namei.c 15.6 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7
/*
 *  linux/fs/hpfs/namei.c
 *
 *  Mikulas Patocka (mikulas@artax.karlin.mff.cuni.cz), 1998-1999
 *
 *  adding & removing files & directories
 */
A
Alexey Dobriyan 已提交
8
#include <linux/sched.h>
L
Linus Torvalds 已提交
9 10
#include "hpfs_fn.h"

11 12 13 14 15 16 17 18 19 20 21
static void hpfs_update_directory_times(struct inode *dir)
{
	time_t t = get_seconds();
	if (t == dir->i_mtime.tv_sec &&
	    t == dir->i_ctime.tv_sec)
		return;
	dir->i_mtime.tv_sec = dir->i_ctime.tv_sec = t;
	dir->i_mtime.tv_nsec = dir->i_ctime.tv_nsec = 0;
	hpfs_write_inode_nolock(dir);
}

22
static int hpfs_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
L
Linus Torvalds 已提交
23
{
24
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
25 26 27 28 29 30 31 32 33 34 35 36
	unsigned len = dentry->d_name.len;
	struct quad_buffer_head qbh0;
	struct buffer_head *bh;
	struct hpfs_dirent *de;
	struct fnode *fnode;
	struct dnode *dnode;
	struct inode *result;
	fnode_secno fno;
	dnode_secno dno;
	int r;
	struct hpfs_dirent dee;
	int err;
37
	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
A
Arnd Bergmann 已提交
38
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
39 40 41 42
	err = -ENOSPC;
	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
	if (!fnode)
		goto bail;
M
Mikulas Patocka 已提交
43
	dnode = hpfs_alloc_dnode(dir->i_sb, fno, &dno, &qbh0);
L
Linus Torvalds 已提交
44 45 46 47 48 49 50
	if (!dnode)
		goto bail1;
	memset(&dee, 0, sizeof dee);
	dee.directory = 1;
	if (!(mode & 0222)) dee.read_only = 1;
	/*dee.archive = 0;*/
	dee.hidden = name[0] == '.';
51 52
	dee.fnode = cpu_to_le32(fno);
	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
L
Linus Torvalds 已提交
53 54 55 56 57 58 59
	result = new_inode(dir->i_sb);
	if (!result)
		goto bail2;
	hpfs_init_inode(result);
	result->i_ino = fno;
	hpfs_i(result)->i_parent_dir = dir->i_ino;
	hpfs_i(result)->i_dno = dno;
60
	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
L
Linus Torvalds 已提交
61 62 63 64 65 66 67 68 69
	result->i_ctime.tv_nsec = 0; 
	result->i_mtime.tv_nsec = 0; 
	result->i_atime.tv_nsec = 0; 
	hpfs_i(result)->i_ea_size = 0;
	result->i_mode |= S_IFDIR;
	result->i_op = &hpfs_dir_iops;
	result->i_fop = &hpfs_dir_ops;
	result->i_blocks = 4;
	result->i_size = 2048;
M
Miklos Szeredi 已提交
70
	set_nlink(result, 2);
L
Linus Torvalds 已提交
71 72 73
	if (dee.read_only)
		result->i_mode &= ~0222;

M
Mikulas Patocka 已提交
74
	r = hpfs_add_dirent(dir, name, len, &dee);
L
Linus Torvalds 已提交
75 76 77 78 79 80 81 82
	if (r == 1)
		goto bail3;
	if (r == -1) {
		err = -EEXIST;
		goto bail3;
	}
	fnode->len = len;
	memcpy(fnode->name, name, len > 15 ? 15 : len);
83
	fnode->up = cpu_to_le32(dir->i_ino);
84
	fnode->flags |= FNODE_dir;
L
Linus Torvalds 已提交
85 86
	fnode->btree.n_free_nodes = 7;
	fnode->btree.n_used_nodes = 1;
87 88 89
	fnode->btree.first_free = cpu_to_le16(0x14);
	fnode->u.external[0].disk_secno = cpu_to_le32(dno);
	fnode->u.external[0].file_secno = cpu_to_le32(-1);
L
Linus Torvalds 已提交
90
	dnode->root_dnode = 1;
91
	dnode->up = cpu_to_le32(fno);
L
Linus Torvalds 已提交
92
	de = hpfs_add_de(dir->i_sb, dnode, "\001\001", 2, 0);
93
	de->creation_date = de->write_date = de->read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
L
Linus Torvalds 已提交
94 95 96
	if (!(mode & 0222)) de->read_only = 1;
	de->first = de->directory = 1;
	/*de->hidden = de->system = 0;*/
97
	de->fnode = cpu_to_le32(fno);
L
Linus Torvalds 已提交
98 99 100 101
	mark_buffer_dirty(bh);
	brelse(bh);
	hpfs_mark_4buffers_dirty(&qbh0);
	hpfs_brelse4(&qbh0);
102
	inc_nlink(dir);
L
Linus Torvalds 已提交
103 104
	insert_inode_hash(result);

105 106
	if (!uid_eq(result->i_uid, current_fsuid()) ||
	    !gid_eq(result->i_gid, current_fsgid()) ||
L
Linus Torvalds 已提交
107
	    result->i_mode != (mode | S_IFDIR)) {
108 109
		result->i_uid = current_fsuid();
		result->i_gid = current_fsgid();
L
Linus Torvalds 已提交
110 111 112
		result->i_mode = mode | S_IFDIR;
		hpfs_write_inode_nolock(result);
	}
113
	hpfs_update_directory_times(dir);
L
Linus Torvalds 已提交
114
	d_instantiate(dentry, result);
A
Arnd Bergmann 已提交
115
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
116 117 118 119 120 121 122 123 124 125
	return 0;
bail3:
	iput(result);
bail2:
	hpfs_brelse4(&qbh0);
	hpfs_free_dnode(dir->i_sb, dno);
bail1:
	brelse(bh);
	hpfs_free_sectors(dir->i_sb, fno, 1);
bail:
A
Arnd Bergmann 已提交
126
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
127 128 129
	return err;
}

A
Al Viro 已提交
130
static int hpfs_create(struct inode *dir, struct dentry *dentry, umode_t mode, bool excl)
L
Linus Torvalds 已提交
131
{
132
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
133 134 135 136 137 138 139 140
	unsigned len = dentry->d_name.len;
	struct inode *result = NULL;
	struct buffer_head *bh;
	struct fnode *fnode;
	fnode_secno fno;
	int r;
	struct hpfs_dirent dee;
	int err;
141
	if ((err = hpfs_chk_name(name, &len)))
L
Linus Torvalds 已提交
142
		return err==-ENOENT ? -EINVAL : err;
A
Arnd Bergmann 已提交
143
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
144 145 146 147 148 149 150 151
	err = -ENOSPC;
	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
	if (!fnode)
		goto bail;
	memset(&dee, 0, sizeof dee);
	if (!(mode & 0222)) dee.read_only = 1;
	dee.archive = 1;
	dee.hidden = name[0] == '.';
152 153
	dee.fnode = cpu_to_le32(fno);
	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
L
Linus Torvalds 已提交
154 155 156 157 158 159 160 161 162 163 164

	result = new_inode(dir->i_sb);
	if (!result)
		goto bail1;
	
	hpfs_init_inode(result);
	result->i_ino = fno;
	result->i_mode |= S_IFREG;
	result->i_mode &= ~0111;
	result->i_op = &hpfs_file_iops;
	result->i_fop = &hpfs_file_ops;
M
Miklos Szeredi 已提交
165
	set_nlink(result, 1);
L
Linus Torvalds 已提交
166
	hpfs_i(result)->i_parent_dir = dir->i_ino;
167
	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
L
Linus Torvalds 已提交
168 169 170 171 172 173 174 175 176 177 178
	result->i_ctime.tv_nsec = 0;
	result->i_mtime.tv_nsec = 0;
	result->i_atime.tv_nsec = 0;
	hpfs_i(result)->i_ea_size = 0;
	if (dee.read_only)
		result->i_mode &= ~0222;
	result->i_blocks = 1;
	result->i_size = 0;
	result->i_data.a_ops = &hpfs_aops;
	hpfs_i(result)->mmu_private = 0;

M
Mikulas Patocka 已提交
179
	r = hpfs_add_dirent(dir, name, len, &dee);
L
Linus Torvalds 已提交
180 181 182 183 184 185 186 187
	if (r == 1)
		goto bail2;
	if (r == -1) {
		err = -EEXIST;
		goto bail2;
	}
	fnode->len = len;
	memcpy(fnode->name, name, len > 15 ? 15 : len);
188
	fnode->up = cpu_to_le32(dir->i_ino);
L
Linus Torvalds 已提交
189 190 191 192 193
	mark_buffer_dirty(bh);
	brelse(bh);

	insert_inode_hash(result);

194 195
	if (!uid_eq(result->i_uid, current_fsuid()) ||
	    !gid_eq(result->i_gid, current_fsgid()) ||
L
Linus Torvalds 已提交
196
	    result->i_mode != (mode | S_IFREG)) {
197 198
		result->i_uid = current_fsuid();
		result->i_gid = current_fsgid();
L
Linus Torvalds 已提交
199 200 201
		result->i_mode = mode | S_IFREG;
		hpfs_write_inode_nolock(result);
	}
202
	hpfs_update_directory_times(dir);
L
Linus Torvalds 已提交
203
	d_instantiate(dentry, result);
A
Arnd Bergmann 已提交
204
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
205 206 207 208 209 210 211 212
	return 0;

bail2:
	iput(result);
bail1:
	brelse(bh);
	hpfs_free_sectors(dir->i_sb, fno, 1);
bail:
A
Arnd Bergmann 已提交
213
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
214 215 216
	return err;
}

A
Al Viro 已提交
217
static int hpfs_mknod(struct inode *dir, struct dentry *dentry, umode_t mode, dev_t rdev)
L
Linus Torvalds 已提交
218
{
219
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
220 221 222 223 224 225 226 227
	unsigned len = dentry->d_name.len;
	struct buffer_head *bh;
	struct fnode *fnode;
	fnode_secno fno;
	int r;
	struct hpfs_dirent dee;
	struct inode *result = NULL;
	int err;
228
	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
L
Linus Torvalds 已提交
229
	if (hpfs_sb(dir->i_sb)->sb_eas < 2) return -EPERM;
A
Arnd Bergmann 已提交
230
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
231 232 233 234 235 236 237 238
	err = -ENOSPC;
	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
	if (!fnode)
		goto bail;
	memset(&dee, 0, sizeof dee);
	if (!(mode & 0222)) dee.read_only = 1;
	dee.archive = 1;
	dee.hidden = name[0] == '.';
239 240
	dee.fnode = cpu_to_le32(fno);
	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
L
Linus Torvalds 已提交
241 242 243 244 245 246 247 248

	result = new_inode(dir->i_sb);
	if (!result)
		goto bail1;

	hpfs_init_inode(result);
	result->i_ino = fno;
	hpfs_i(result)->i_parent_dir = dir->i_ino;
249
	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
L
Linus Torvalds 已提交
250 251 252 253
	result->i_ctime.tv_nsec = 0;
	result->i_mtime.tv_nsec = 0;
	result->i_atime.tv_nsec = 0;
	hpfs_i(result)->i_ea_size = 0;
254 255
	result->i_uid = current_fsuid();
	result->i_gid = current_fsgid();
M
Miklos Szeredi 已提交
256
	set_nlink(result, 1);
L
Linus Torvalds 已提交
257 258 259 260
	result->i_size = 0;
	result->i_blocks = 1;
	init_special_inode(result, mode, rdev);

M
Mikulas Patocka 已提交
261
	r = hpfs_add_dirent(dir, name, len, &dee);
L
Linus Torvalds 已提交
262 263 264 265 266 267 268 269
	if (r == 1)
		goto bail2;
	if (r == -1) {
		err = -EEXIST;
		goto bail2;
	}
	fnode->len = len;
	memcpy(fnode->name, name, len > 15 ? 15 : len);
270
	fnode->up = cpu_to_le32(dir->i_ino);
L
Linus Torvalds 已提交
271 272 273 274 275
	mark_buffer_dirty(bh);

	insert_inode_hash(result);

	hpfs_write_inode_nolock(result);
276
	hpfs_update_directory_times(dir);
L
Linus Torvalds 已提交
277 278
	d_instantiate(dentry, result);
	brelse(bh);
A
Arnd Bergmann 已提交
279
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
280 281 282 283 284 285 286
	return 0;
bail2:
	iput(result);
bail1:
	brelse(bh);
	hpfs_free_sectors(dir->i_sb, fno, 1);
bail:
A
Arnd Bergmann 已提交
287
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
288 289 290 291 292
	return err;
}

static int hpfs_symlink(struct inode *dir, struct dentry *dentry, const char *symlink)
{
293
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
294 295 296 297 298 299 300 301
	unsigned len = dentry->d_name.len;
	struct buffer_head *bh;
	struct fnode *fnode;
	fnode_secno fno;
	int r;
	struct hpfs_dirent dee;
	struct inode *result;
	int err;
302
	if ((err = hpfs_chk_name(name, &len))) return err==-ENOENT ? -EINVAL : err;
A
Arnd Bergmann 已提交
303
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
304
	if (hpfs_sb(dir->i_sb)->sb_eas < 2) {
A
Arnd Bergmann 已提交
305
		hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
306 307 308 309 310 311 312 313 314
		return -EPERM;
	}
	err = -ENOSPC;
	fnode = hpfs_alloc_fnode(dir->i_sb, hpfs_i(dir)->i_dno, &fno, &bh);
	if (!fnode)
		goto bail;
	memset(&dee, 0, sizeof dee);
	dee.archive = 1;
	dee.hidden = name[0] == '.';
315 316
	dee.fnode = cpu_to_le32(fno);
	dee.creation_date = dee.write_date = dee.read_date = cpu_to_le32(gmt_to_local(dir->i_sb, get_seconds()));
L
Linus Torvalds 已提交
317 318 319 320 321 322 323

	result = new_inode(dir->i_sb);
	if (!result)
		goto bail1;
	result->i_ino = fno;
	hpfs_init_inode(result);
	hpfs_i(result)->i_parent_dir = dir->i_ino;
324
	result->i_ctime.tv_sec = result->i_mtime.tv_sec = result->i_atime.tv_sec = local_to_gmt(dir->i_sb, le32_to_cpu(dee.creation_date));
L
Linus Torvalds 已提交
325 326 327 328 329
	result->i_ctime.tv_nsec = 0;
	result->i_mtime.tv_nsec = 0;
	result->i_atime.tv_nsec = 0;
	hpfs_i(result)->i_ea_size = 0;
	result->i_mode = S_IFLNK | 0777;
330 331
	result->i_uid = current_fsuid();
	result->i_gid = current_fsgid();
L
Linus Torvalds 已提交
332
	result->i_blocks = 1;
M
Miklos Szeredi 已提交
333
	set_nlink(result, 1);
L
Linus Torvalds 已提交
334
	result->i_size = strlen(symlink);
335
	inode_nohighmem(result);
L
Linus Torvalds 已提交
336 337 338
	result->i_op = &page_symlink_inode_operations;
	result->i_data.a_ops = &hpfs_symlink_aops;

M
Mikulas Patocka 已提交
339
	r = hpfs_add_dirent(dir, name, len, &dee);
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347
	if (r == 1)
		goto bail2;
	if (r == -1) {
		err = -EEXIST;
		goto bail2;
	}
	fnode->len = len;
	memcpy(fnode->name, name, len > 15 ? 15 : len);
348
	fnode->up = cpu_to_le32(dir->i_ino);
349
	hpfs_set_ea(result, fnode, "SYMLINK", symlink, strlen(symlink));
L
Linus Torvalds 已提交
350 351 352 353 354 355
	mark_buffer_dirty(bh);
	brelse(bh);

	insert_inode_hash(result);

	hpfs_write_inode_nolock(result);
356
	hpfs_update_directory_times(dir);
L
Linus Torvalds 已提交
357
	d_instantiate(dentry, result);
A
Arnd Bergmann 已提交
358
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
359 360 361 362 363 364 365
	return 0;
bail2:
	iput(result);
bail1:
	brelse(bh);
	hpfs_free_sectors(dir->i_sb, fno, 1);
bail:
A
Arnd Bergmann 已提交
366
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
367 368 369 370 371
	return err;
}

static int hpfs_unlink(struct inode *dir, struct dentry *dentry)
{
372
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
373 374 375
	unsigned len = dentry->d_name.len;
	struct quad_buffer_head qbh;
	struct hpfs_dirent *de;
376
	struct inode *inode = d_inode(dentry);
L
Linus Torvalds 已提交
377 378 379 380
	dnode_secno dno;
	int r;
	int err;

A
Arnd Bergmann 已提交
381
	hpfs_lock(dir->i_sb);
382
	hpfs_adjust_length(name, &len);
383

L
Linus Torvalds 已提交
384
	err = -ENOENT;
385
	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
L
Linus Torvalds 已提交
386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402
	if (!de)
		goto out;

	err = -EPERM;
	if (de->first)
		goto out1;

	err = -EISDIR;
	if (de->directory)
		goto out1;

	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
	switch (r) {
	case 1:
		hpfs_error(dir->i_sb, "there was error when removing dirent");
		err = -EFSERROR;
		break;
403
	case 2:		/* no space for deleting */
L
Linus Torvalds 已提交
404
		err = -ENOSPC;
405
		break;
L
Linus Torvalds 已提交
406
	default:
407
		drop_nlink(inode);
L
Linus Torvalds 已提交
408 409 410 411 412 413 414
		err = 0;
	}
	goto out;

out1:
	hpfs_brelse4(&qbh);
out:
415 416
	if (!err)
		hpfs_update_directory_times(dir);
A
Arnd Bergmann 已提交
417
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
418 419 420 421 422
	return err;
}

static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
{
423
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
424 425 426
	unsigned len = dentry->d_name.len;
	struct quad_buffer_head qbh;
	struct hpfs_dirent *de;
427
	struct inode *inode = d_inode(dentry);
L
Linus Torvalds 已提交
428 429 430 431 432
	dnode_secno dno;
	int n_items = 0;
	int err;
	int r;

433
	hpfs_adjust_length(name, &len);
A
Arnd Bergmann 已提交
434
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
435
	err = -ENOENT;
436
	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
L
Linus Torvalds 已提交
437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462
	if (!de)
		goto out;

	err = -EPERM;
	if (de->first)
		goto out1;

	err = -ENOTDIR;
	if (!de->directory)
		goto out1;

	hpfs_count_dnodes(dir->i_sb, hpfs_i(inode)->i_dno, NULL, NULL, &n_items);
	err = -ENOTEMPTY;
	if (n_items)
		goto out1;

	r = hpfs_remove_dirent(dir, dno, de, &qbh, 1);
	switch (r) {
	case 1:
		hpfs_error(dir->i_sb, "there was error when removing dirent");
		err = -EFSERROR;
		break;
	case 2:
		err = -ENOSPC;
		break;
	default:
463
		drop_nlink(dir);
464
		clear_nlink(inode);
L
Linus Torvalds 已提交
465 466 467 468 469 470
		err = 0;
	}
	goto out;
out1:
	hpfs_brelse4(&qbh);
out:
471 472
	if (!err)
		hpfs_update_directory_times(dir);
A
Arnd Bergmann 已提交
473
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
474 475 476 477 478
	return err;
}

static int hpfs_symlink_readpage(struct file *file, struct page *page)
{
479
	char *link = page_address(page);
L
Linus Torvalds 已提交
480 481 482 483 484 485
	struct inode *i = page->mapping->host;
	struct fnode *fnode;
	struct buffer_head *bh;
	int err;

	err = -EIO;
A
Arnd Bergmann 已提交
486
	hpfs_lock(i->i_sb);
L
Linus Torvalds 已提交
487 488 489 490 491 492
	if (!(fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh)))
		goto fail;
	err = hpfs_read_ea(i->i_sb, fnode, "SYMLINK", link, PAGE_SIZE);
	brelse(bh);
	if (err)
		goto fail;
A
Arnd Bergmann 已提交
493
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
494 495 496 497 498
	SetPageUptodate(page);
	unlock_page(page);
	return 0;

fail:
A
Arnd Bergmann 已提交
499
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
500 501 502 503 504
	SetPageError(page);
	unlock_page(page);
	return err;
}

505
const struct address_space_operations hpfs_symlink_aops = {
L
Linus Torvalds 已提交
506 507 508 509 510 511
	.readpage	= hpfs_symlink_readpage
};
	
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
512 513 514 515
	const unsigned char *old_name = old_dentry->d_name.name;
	unsigned old_len = old_dentry->d_name.len;
	const unsigned char *new_name = new_dentry->d_name.name;
	unsigned new_len = new_dentry->d_name.len;
516 517
	struct inode *i = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);
L
Linus Torvalds 已提交
518 519 520 521 522 523 524 525
	struct quad_buffer_head qbh, qbh1;
	struct hpfs_dirent *dep, *nde;
	struct hpfs_dirent de;
	dnode_secno dno;
	int r;
	struct buffer_head *bh;
	struct fnode *fnode;
	int err;
526

527
	if ((err = hpfs_chk_name(new_name, &new_len))) return err;
L
Linus Torvalds 已提交
528
	err = 0;
529
	hpfs_adjust_length(old_name, &old_len);
L
Linus Torvalds 已提交
530

A
Arnd Bergmann 已提交
531
	hpfs_lock(i->i_sb);
L
Linus Torvalds 已提交
532 533 534 535 536 537 538 539
	/* order doesn't matter, due to VFS exclusion */
	
	/* Erm? Moving over the empty non-busy directory is perfectly legal */
	if (new_inode && S_ISDIR(new_inode->i_mode)) {
		err = -EINVAL;
		goto end1;
	}

540
	if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
L
Linus Torvalds 已提交
541 542 543 544 545 546 547 548 549 550
		hpfs_error(i->i_sb, "lookup succeeded but map dirent failed");
		err = -ENOENT;
		goto end1;
	}
	copy_de(&de, dep);
	de.hidden = new_name[0] == '.';

	if (new_inode) {
		int r;
		if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 1)) != 2) {
551
			if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) {
552
				clear_nlink(new_inode);
L
Linus Torvalds 已提交
553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568
				copy_de(nde, &de);
				memcpy(nde->name, new_name, new_len);
				hpfs_mark_4buffers_dirty(&qbh1);
				hpfs_brelse4(&qbh1);
				goto end;
			}
			hpfs_error(new_dir->i_sb, "hpfs_rename: could not find dirent");
			err = -EFSERROR;
			goto end1;
		}
		err = r == 2 ? -ENOSPC : r == 1 ? -EFSERROR : 0;
		goto end1;
	}

	if (new_dir == old_dir) hpfs_brelse4(&qbh);

M
Mikulas Patocka 已提交
569
	if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) {
L
Linus Torvalds 已提交
570 571 572 573 574 575 576
		if (r == -1) hpfs_error(new_dir->i_sb, "hpfs_rename: dirent already exists!");
		err = r == 1 ? -ENOSPC : -EFSERROR;
		if (new_dir != old_dir) hpfs_brelse4(&qbh);
		goto end1;
	}
	
	if (new_dir == old_dir)
577
		if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
L
Linus Torvalds 已提交
578 579 580 581 582 583 584 585 586 587
			hpfs_error(i->i_sb, "lookup succeeded but map dirent failed at #2");
			err = -ENOENT;
			goto end1;
		}

	if ((r = hpfs_remove_dirent(old_dir, dno, dep, &qbh, 0))) {
		hpfs_error(i->i_sb, "hpfs_rename: could not remove dirent");
		err = r == 2 ? -ENOSPC : -EFSERROR;
		goto end1;
	}
M
Mikulas Patocka 已提交
588

589
end:
L
Linus Torvalds 已提交
590 591
	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
	if (S_ISDIR(i->i_mode)) {
592
		inc_nlink(new_dir);
593
		drop_nlink(old_dir);
L
Linus Torvalds 已提交
594 595
	}
	if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
596
		fnode->up = cpu_to_le32(new_dir->i_ino);
L
Linus Torvalds 已提交
597 598 599 600 601 602 603
		fnode->len = new_len;
		memcpy(fnode->name, new_name, new_len>15?15:new_len);
		if (new_len < 15) memset(&fnode->name[new_len], 0, 15 - new_len);
		mark_buffer_dirty(bh);
		brelse(bh);
	}
end1:
604 605 606 607
	if (!err) {
		hpfs_update_directory_times(old_dir);
		hpfs_update_directory_times(new_dir);
	}
A
Arnd Bergmann 已提交
608
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
609 610 611
	return err;
}

612
const struct inode_operations hpfs_dir_iops =
L
Linus Torvalds 已提交
613 614 615 616 617 618 619 620 621
{
	.create		= hpfs_create,
	.lookup		= hpfs_lookup,
	.unlink		= hpfs_unlink,
	.symlink	= hpfs_symlink,
	.mkdir		= hpfs_mkdir,
	.rmdir		= hpfs_rmdir,
	.mknod		= hpfs_mknod,
	.rename		= hpfs_rename,
622
	.setattr	= hpfs_setattr,
L
Linus Torvalds 已提交
623
};