namei.c 16.2 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 335 336 337
	result->i_size = strlen(symlink);
	result->i_op = &page_symlink_inode_operations;
	result->i_data.a_ops = &hpfs_symlink_aops;

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

	insert_inode_hash(result);

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

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

A
Arnd Bergmann 已提交
381
	hpfs_lock(dir->i_sb);
382
	hpfs_adjust_length(name, &len);
L
Linus Torvalds 已提交
383 384
again:
	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 403 404 405 406 407 408
	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;
	case 2:		/* no space for deleting, try to truncate file */

		err = -ENOSPC;
		if (rep++)
			break;

409 410
		dentry_unhash(dentry);
		if (!d_unhashed(dentry)) {
A
Arnd Bergmann 已提交
411
			hpfs_unlock(dir->i_sb);
412 413
			return -ENOSPC;
		}
414
		if (generic_permission(inode, MAY_WRITE) ||
L
Linus Torvalds 已提交
415 416 417 418 419
		    !S_ISREG(inode->i_mode) ||
		    get_write_access(inode)) {
			d_rehash(dentry);
		} else {
			struct iattr newattrs;
420
			/*pr_info("truncating file before delete.\n");*/
L
Linus Torvalds 已提交
421 422
			newattrs.ia_size = 0;
			newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME;
423
			err = notify_change(dentry, &newattrs, NULL);
L
Linus Torvalds 已提交
424 425 426 427
			put_write_access(inode);
			if (!err)
				goto again;
		}
A
Arnd Bergmann 已提交
428
		hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
429 430
		return -ENOSPC;
	default:
431
		drop_nlink(inode);
L
Linus Torvalds 已提交
432 433 434 435 436 437 438
		err = 0;
	}
	goto out;

out1:
	hpfs_brelse4(&qbh);
out:
439 440
	if (!err)
		hpfs_update_directory_times(dir);
A
Arnd Bergmann 已提交
441
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
442 443 444 445 446
	return err;
}

static int hpfs_rmdir(struct inode *dir, struct dentry *dentry)
{
447
	const unsigned char *name = dentry->d_name.name;
L
Linus Torvalds 已提交
448 449 450
	unsigned len = dentry->d_name.len;
	struct quad_buffer_head qbh;
	struct hpfs_dirent *de;
451
	struct inode *inode = d_inode(dentry);
L
Linus Torvalds 已提交
452 453 454 455 456
	dnode_secno dno;
	int n_items = 0;
	int err;
	int r;

457
	hpfs_adjust_length(name, &len);
A
Arnd Bergmann 已提交
458
	hpfs_lock(dir->i_sb);
L
Linus Torvalds 已提交
459
	err = -ENOENT;
460
	de = map_dirent(dir, hpfs_i(dir)->i_dno, name, len, &dno, &qbh);
L
Linus Torvalds 已提交
461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486
	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:
487
		drop_nlink(dir);
488
		clear_nlink(inode);
L
Linus Torvalds 已提交
489 490 491 492 493 494
		err = 0;
	}
	goto out;
out1:
	hpfs_brelse4(&qbh);
out:
495 496
	if (!err)
		hpfs_update_directory_times(dir);
A
Arnd Bergmann 已提交
497
	hpfs_unlock(dir->i_sb);
L
Linus Torvalds 已提交
498 499 500 501 502 503 504 505 506 507 508 509
	return err;
}

static int hpfs_symlink_readpage(struct file *file, struct page *page)
{
	char *link = kmap(page);
	struct inode *i = page->mapping->host;
	struct fnode *fnode;
	struct buffer_head *bh;
	int err;

	err = -EIO;
A
Arnd Bergmann 已提交
510
	hpfs_lock(i->i_sb);
L
Linus Torvalds 已提交
511 512 513 514 515 516
	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 已提交
517
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
518 519 520 521 522 523
	SetPageUptodate(page);
	kunmap(page);
	unlock_page(page);
	return 0;

fail:
A
Arnd Bergmann 已提交
524
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
525 526 527 528 529 530
	SetPageError(page);
	kunmap(page);
	unlock_page(page);
	return err;
}

531
const struct address_space_operations hpfs_symlink_aops = {
L
Linus Torvalds 已提交
532 533 534 535 536 537
	.readpage	= hpfs_symlink_readpage
};
	
static int hpfs_rename(struct inode *old_dir, struct dentry *old_dentry,
		struct inode *new_dir, struct dentry *new_dentry)
{
538 539 540 541
	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;
542 543
	struct inode *i = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);
L
Linus Torvalds 已提交
544 545 546 547 548 549 550 551
	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;
552

553
	if ((err = hpfs_chk_name(new_name, &new_len))) return err;
L
Linus Torvalds 已提交
554
	err = 0;
555
	hpfs_adjust_length(old_name, &old_len);
L
Linus Torvalds 已提交
556

A
Arnd Bergmann 已提交
557
	hpfs_lock(i->i_sb);
L
Linus Torvalds 已提交
558 559 560 561 562 563 564 565
	/* 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;
	}

566
	if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
L
Linus Torvalds 已提交
567 568 569 570 571 572 573 574 575 576
		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) {
577
			if ((nde = map_dirent(new_dir, hpfs_i(new_dir)->i_dno, new_name, new_len, NULL, &qbh1))) {
578
				clear_nlink(new_inode);
L
Linus Torvalds 已提交
579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594
				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 已提交
595
	if ((r = hpfs_add_dirent(new_dir, new_name, new_len, &de))) {
L
Linus Torvalds 已提交
596 597 598 599 600 601 602
		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)
603
		if (!(dep = map_dirent(old_dir, hpfs_i(old_dir)->i_dno, old_name, old_len, &dno, &qbh))) {
L
Linus Torvalds 已提交
604 605 606 607 608 609 610 611 612 613
			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 已提交
614

615
end:
L
Linus Torvalds 已提交
616 617
	hpfs_i(i)->i_parent_dir = new_dir->i_ino;
	if (S_ISDIR(i->i_mode)) {
618
		inc_nlink(new_dir);
619
		drop_nlink(old_dir);
L
Linus Torvalds 已提交
620 621
	}
	if ((fnode = hpfs_map_fnode(i->i_sb, i->i_ino, &bh))) {
622
		fnode->up = cpu_to_le32(new_dir->i_ino);
L
Linus Torvalds 已提交
623 624 625 626 627 628 629
		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:
630 631 632 633
	if (!err) {
		hpfs_update_directory_times(old_dir);
		hpfs_update_directory_times(new_dir);
	}
A
Arnd Bergmann 已提交
634
	hpfs_unlock(i->i_sb);
L
Linus Torvalds 已提交
635 636 637
	return err;
}

638
const struct inode_operations hpfs_dir_iops =
L
Linus Torvalds 已提交
639 640 641 642 643 644 645 646 647
{
	.create		= hpfs_create,
	.lookup		= hpfs_lookup,
	.unlink		= hpfs_unlink,
	.symlink	= hpfs_symlink,
	.mkdir		= hpfs_mkdir,
	.rmdir		= hpfs_rmdir,
	.mknod		= hpfs_mknod,
	.rename		= hpfs_rename,
648
	.setattr	= hpfs_setattr,
L
Linus Torvalds 已提交
649
};