namei.c 25.6 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds's avatar
Linus Torvalds committed
2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
/*
 * namei.c
 *
 * PURPOSE
 *      Inode name handling routines for the OSTA-UDF(tm) filesystem.
 *
 * COPYRIGHT
 *  (C) 1998-2004 Ben Fennema
 *  (C) 1999-2000 Stelias Computing Inc
 *
 * HISTORY
 *
 *  12/12/98 blf  Created. Split out the lookup code from dir.c
 *  04/19/99 blf  link, mknod, symlink support
 */

#include "udfdecl.h"

#include "udf_i.h"
#include "udf_sb.h"
#include <linux/string.h>
#include <linux/errno.h>
#include <linux/mm.h>
#include <linux/slab.h>
Alexey Dobriyan's avatar
Alexey Dobriyan committed
26
#include <linux/sched.h>
27
#include <linux/crc-itu-t.h>
Rasmus Rohde's avatar
Rasmus Rohde committed
28
#include <linux/exportfs.h>
Jan Kara's avatar
Jan Kara committed
29
#include <linux/iversion.h>
Linus Torvalds's avatar
Linus Torvalds committed
30

Al Viro's avatar
Al Viro committed
31 32
static inline int udf_match(int len1, const unsigned char *name1, int len2,
			    const unsigned char *name2)
Linus Torvalds's avatar
Linus Torvalds committed
33 34 35
{
	if (len1 != len2)
		return 0;
36

Linus Torvalds's avatar
Linus Torvalds committed
37 38 39
	return !memcmp(name1, name2, len1);
}

40
/**
41
 * udf_fiiter_find_entry - find entry in given directory.
42 43 44
 *
 * @dir:	directory inode to search in
 * @child:	qstr of the name
45
 * @iter:	iter to use for searching
46 47
 *
 * This function searches in the directory @dir for a file name @child. When
48
 * found, @iter points to the position in the directory with given entry.
49
 *
50
 * Returns 0 on success, < 0 on error (including -ENOENT).
51
 */
52 53
static int udf_fiiter_find_entry(struct inode *dir, const struct qstr *child,
				 struct udf_fileident_iter *iter)
Linus Torvalds's avatar
Linus Torvalds committed
54
{
55
	int flen;
56 57
	unsigned char *fname = NULL;
	struct super_block *sb = dir->i_sb;
58 59
	int isdotdot = child->len == 2 &&
		child->name[0] == '.' && child->name[1] == '.';
60
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
61

62
	fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
63 64
	if (!fname)
		return -ENOMEM;
Linus Torvalds's avatar
Linus Torvalds committed
65

66 67 68 69
	for (ret = udf_fiiter_init(iter, dir, 0);
	     !ret && iter->pos < dir->i_size;
	     ret = udf_fiiter_advance(iter)) {
		if (iter->fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
Jan Kara's avatar
Jan Kara committed
70
			if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNDELETE))
Linus Torvalds's avatar
Linus Torvalds committed
71 72
				continue;
		}
73

74
		if (iter->fi.fileCharacteristics & FID_FILE_CHAR_HIDDEN) {
Jan Kara's avatar
Jan Kara committed
75
			if (!UDF_QUERY_FLAG(sb, UDF_FLAG_UNHIDE))
Linus Torvalds's avatar
Linus Torvalds committed
76 77 78
				continue;
		}

79
		if ((iter->fi.fileCharacteristics & FID_FILE_CHAR_PARENT) &&
80 81
		    isdotdot)
			goto out_ok;
Rasmus Rohde's avatar
Rasmus Rohde committed
82

83
		if (!iter->fi.lengthFileIdent)
Linus Torvalds's avatar
Linus Torvalds committed
84 85
			continue;

86 87
		flen = udf_get_filename(sb, iter->name,
				iter->fi.lengthFileIdent, fname, UDF_NAME_LEN);
88
		if (flen < 0) {
89
			ret = flen;
90 91 92 93
			goto out_err;
		}

		if (udf_match(flen, fname, child->len, child->name))
94
			goto out_ok;
Linus Torvalds's avatar
Linus Torvalds committed
95
	}
96 97
	if (!ret)
		ret = -ENOENT;
98

99
out_err:
100
	udf_fiiter_release(iter);
101 102
out_ok:
	kfree(fname);
103

104
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
105 106
}

107
static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
108
				 unsigned int flags)
Linus Torvalds's avatar
Linus Torvalds committed
109 110
{
	struct inode *inode = NULL;
111 112
	struct udf_fileident_iter iter;
	int err;
Linus Torvalds's avatar
Linus Torvalds committed
113

114
	if (dentry->d_name.len > UDF_NAME_LEN)
Linus Torvalds's avatar
Linus Torvalds committed
115 116
		return ERR_PTR(-ENAMETOOLONG);

117 118 119
	err = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
	if (err < 0 && err != -ENOENT)
		return ERR_PTR(err);
120

121
	if (err == 0) {
122 123
		struct kernel_lb_addr loc;

124 125
		loc = lelb_to_cpu(iter.fi.icb.extLocation);
		udf_fiiter_release(&iter);
Linus Torvalds's avatar
Linus Torvalds committed
126

127
		inode = udf_iget(dir->i_sb, &loc);
128 129
		if (IS_ERR(inode))
			return ERR_CAST(inode);
Linus Torvalds's avatar
Linus Torvalds committed
130
	}
131

Rasmus Rohde's avatar
Rasmus Rohde committed
132
	return d_splice_alias(inode, dentry);
Linus Torvalds's avatar
Linus Torvalds committed
133 134
}

135
static int udf_expand_dir_adinicb(struct inode *inode, udf_pblk_t *block)
Linus Torvalds's avatar
Linus Torvalds committed
136
{
137 138
	udf_pblk_t newblock;
	struct buffer_head *dbh = NULL;
139
	struct kernel_lb_addr eloc;
140 141 142 143 144 145
	struct extent_position epos;
	uint8_t alloctype;
	struct udf_inode_info *iinfo = UDF_I(inode);
	struct udf_fileident_iter iter;
	uint8_t *impuse;
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
146

147 148 149 150
	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_USE_SHORT_AD))
		alloctype = ICBTAG_FLAG_AD_SHORT;
	else
		alloctype = ICBTAG_FLAG_AD_LONG;
151

152 153 154
	if (!inode->i_size) {
		iinfo->i_alloc_type = alloctype;
		mark_inode_dirty(inode);
155
		return 0;
156
	}
Linus Torvalds's avatar
Linus Torvalds committed
157

158 159 160
	/* alloc block, and copy data to it */
	*block = udf_new_block(inode->i_sb, inode,
			       iinfo->i_location.partitionReferenceNum,
161
			       iinfo->i_location.logicalBlockNum, &ret);
162
	if (!(*block))
163
		return ret;
164 165 166
	newblock = udf_get_pblock(inode->i_sb, *block,
				  iinfo->i_location.partitionReferenceNum,
				0);
167 168
	if (newblock == 0xffffffff)
		return -EFSCORRUPTED;
Jan Kara's avatar
Jan Kara committed
169
	dbh = sb_getblk(inode->i_sb, newblock);
170
	if (!dbh)
171
		return -ENOMEM;
172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189
	lock_buffer(dbh);
	memcpy(dbh->b_data, iinfo->i_data, inode->i_size);
	memset(dbh->b_data + inode->i_size, 0,
	       inode->i_sb->s_blocksize - inode->i_size);
	set_buffer_uptodate(dbh);
	unlock_buffer(dbh);

	/* Drop inline data, add block instead */
	iinfo->i_alloc_type = alloctype;
	memset(iinfo->i_data + iinfo->i_lenEAttr, 0, iinfo->i_lenAlloc);
	iinfo->i_lenAlloc = 0;
	eloc.logicalBlockNum = *block;
	eloc.partitionReferenceNum =
				iinfo->i_location.partitionReferenceNum;
	iinfo->i_lenExtents = inode->i_size;
	epos.bh = NULL;
	epos.block = iinfo->i_location;
	epos.offset = udf_file_entry_alloc_offset(inode);
190
	ret = udf_add_aext(inode, &epos, &eloc, inode->i_size, 0);
191
	brelse(epos.bh);
192
	if (ret < 0) {
193
		brelse(dbh);
194
		udf_free_blocks(inode->i_sb, inode, &eloc, 0, 1);
195
		return ret;
196
	}
197
	mark_inode_dirty(inode);
Linus Torvalds's avatar
Linus Torvalds committed
198

199 200 201 202 203 204 205 206 207 208 209
	/* Now fixup tags in moved directory entries */
	for (ret = udf_fiiter_init(&iter, inode, 0);
	     !ret && iter.pos < inode->i_size;
	     ret = udf_fiiter_advance(&iter)) {
		iter.fi.descTag.tagLocation = cpu_to_le32(*block);
		if (iter.fi.lengthOfImpUse != cpu_to_le16(0))
			impuse = dbh->b_data + iter.pos +
						sizeof(struct fileIdentDesc);
		else
			impuse = NULL;
		udf_fiiter_write_fi(&iter, impuse);
Linus Torvalds's avatar
Linus Torvalds committed
210
	}
211
	brelse(dbh);
212 213 214 215 216 217
	/*
	 * We don't expect the iteration to fail as the directory has been
	 * already verified to be correct
	 */
	WARN_ON_ONCE(ret);
	udf_fiiter_release(&iter);
Linus Torvalds's avatar
Linus Torvalds committed
218

219
	return 0;
220
}
Linus Torvalds's avatar
Linus Torvalds committed
221

222 223 224 225 226 227 228 229 230
static int udf_fiiter_add_entry(struct inode *dir, struct dentry *dentry,
				struct udf_fileident_iter *iter)
{
	struct udf_inode_info *dinfo = UDF_I(dir);
	int nfidlen, namelen = 0;
	int ret;
	int off, blksize = 1 << dir->i_blkbits;
	udf_pblk_t block;
	char name[UDF_NAME_LEN_CS0];
Linus Torvalds's avatar
Linus Torvalds committed
231

232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255
	if (dentry) {
		if (!dentry->d_name.len)
			return -EINVAL;
		namelen = udf_put_filename(dir->i_sb, dentry->d_name.name,
					   dentry->d_name.len,
					   name, UDF_NAME_LEN_CS0);
		if (!namelen)
			return -ENAMETOOLONG;
	}
	nfidlen = ALIGN(sizeof(struct fileIdentDesc) + namelen, UDF_NAME_PAD);

	for (ret = udf_fiiter_init(iter, dir, 0);
	     !ret && iter->pos < dir->i_size;
	     ret = udf_fiiter_advance(iter)) {
		if (iter->fi.fileCharacteristics & FID_FILE_CHAR_DELETED) {
			if (udf_dir_entry_len(&iter->fi) == nfidlen) {
				iter->fi.descTag.tagSerialNum = cpu_to_le16(1);
				iter->fi.fileVersionNum = cpu_to_le16(1);
				iter->fi.fileCharacteristics = 0;
				iter->fi.lengthFileIdent = namelen;
				iter->fi.lengthOfImpUse = cpu_to_le16(0);
				memcpy(iter->namebuf, name, namelen);
				iter->name = iter->namebuf;
				return 0;
Linus Torvalds's avatar
Linus Torvalds committed
256 257 258
			}
		}
	}
259 260 261
	if (ret) {
		udf_fiiter_release(iter);
		return ret;
Linus Torvalds's avatar
Linus Torvalds committed
262
	}
263 264 265
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
	    blksize - udf_ext0_offset(dir) - iter->pos < nfidlen) {
		udf_fiiter_release(iter);
266 267
		ret = udf_expand_dir_adinicb(dir, &block);
		if (ret)
268 269 270 271 272 273 274 275 276
			return ret;
		ret = udf_fiiter_init(iter, dir, dir->i_size);
		if (ret < 0)
			return ret;
	}

	/* Get blocknumber to use for entry tag */
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
		block = dinfo->i_location.logicalBlockNum;
277
	} else {
278 279
		block = iter->eloc.logicalBlockNum +
				((iter->elen - 1) >> dir->i_blkbits);
Linus Torvalds's avatar
Linus Torvalds committed
280
	}
281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301
	off = iter->pos & (blksize - 1);
	if (!off)
		off = blksize;
	/* Entry fits into current block? */
	if (blksize - udf_ext0_offset(dir) - off >= nfidlen)
		goto store_fi;

	ret = udf_fiiter_append_blk(iter);
	if (ret) {
		udf_fiiter_release(iter);
		return ret;
	}

	/* Entry will be completely in the new block? Update tag location... */
	if (!(iter->pos & (blksize - 1)))
		block = iter->eloc.logicalBlockNum +
				((iter->elen - 1) >> dir->i_blkbits);
store_fi:
	memset(&iter->fi, 0, sizeof(struct fileIdentDesc));
	if (UDF_SB(dir->i_sb)->s_udfrev >= 0x0200)
		udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 3, 1, block,
302
			    sizeof(struct tag));
Linus Torvalds's avatar
Linus Torvalds committed
303
	else
304
		udf_new_tag((char *)(&iter->fi), TAG_IDENT_FID, 2, 1, block,
305
			    sizeof(struct tag));
306 307 308 309 310 311 312 313 314
	iter->fi.fileVersionNum = cpu_to_le16(1);
	iter->fi.lengthFileIdent = namelen;
	iter->fi.lengthOfImpUse = cpu_to_le16(0);
	memcpy(iter->namebuf, name, namelen);
	iter->name = iter->namebuf;

	dir->i_size += nfidlen;
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
		dinfo->i_lenAlloc += nfidlen;
315
	} else {
316 317 318
		/* Truncate last extent to proper size */
		udf_fiiter_update_elen(iter, iter->elen -
					(dinfo->i_lenExtents - dir->i_size));
Linus Torvalds's avatar
Linus Torvalds committed
319
	}
320
	mark_inode_dirty(dir);
321

322
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
323 324
}

325
static void udf_fiiter_delete_entry(struct udf_fileident_iter *iter)
Linus Torvalds's avatar
Linus Torvalds committed
326
{
327 328 329 330
	iter->fi.fileCharacteristics |= FID_FILE_CHAR_DELETED;

	if (UDF_QUERY_FLAG(iter->dir->i_sb, UDF_FLAG_STRICT))
		memset(&iter->fi.icb, 0x00, sizeof(struct long_ad));
331

332 333 334
	udf_fiiter_write_fi(iter, NULL);
}

Jan Kara's avatar
Jan Kara committed
335 336 337
static void udf_add_fid_counter(struct super_block *sb, bool dir, int val)
{
	struct logicalVolIntegrityDescImpUse *lvidiu = udf_sb_lvidiu(sb);
338

Jan Kara's avatar
Jan Kara committed
339 340 341 342 343 344 345 346 347
	if (!lvidiu)
		return;
	mutex_lock(&UDF_SB(sb)->s_alloc_mutex);
	if (dir)
		le32_add_cpu(&lvidiu->numDirs, val);
	else
		le32_add_cpu(&lvidiu->numFiles, val);
	udf_updated_lvid(sb);
	mutex_unlock(&UDF_SB(sb)->s_alloc_mutex);
Linus Torvalds's avatar
Linus Torvalds committed
348 349
}

350
static int udf_add_nondir(struct dentry *dentry, struct inode *inode)
Linus Torvalds's avatar
Linus Torvalds committed
351
{
352
	struct udf_inode_info *iinfo = UDF_I(inode);
353
	struct inode *dir = d_inode(dentry->d_parent);
354
	struct udf_fileident_iter iter;
Linus Torvalds's avatar
Linus Torvalds committed
355 356
	int err;

357 358
	err = udf_fiiter_add_entry(dir, dentry, &iter);
	if (err) {
359
		inode_dec_link_count(inode);
360
		discard_new_inode(inode);
Linus Torvalds's avatar
Linus Torvalds committed
361 362
		return err;
	}
363 364 365
	iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
	iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
	*(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
366
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
367
	udf_fiiter_write_fi(&iter, NULL);
368
	dir->i_mtime = inode_set_ctime_current(dir);
369
	mark_inode_dirty(dir);
370
	udf_fiiter_release(&iter);
Jan Kara's avatar
Jan Kara committed
371
	udf_add_fid_counter(dir->i_sb, false, 1);
372
	d_instantiate_new(dentry, inode);
373

Linus Torvalds's avatar
Linus Torvalds committed
374 375 376
	return 0;
}

377
static int udf_create(struct mnt_idmap *idmap, struct inode *dir,
378
		      struct dentry *dentry, umode_t mode, bool excl)
379
{
380
	struct inode *inode = udf_new_inode(dir, mode);
381

382 383
	if (IS_ERR(inode))
		return PTR_ERR(inode);
384

385
	inode->i_data.a_ops = &udf_aops;
386 387 388 389 390 391 392
	inode->i_op = &udf_file_inode_operations;
	inode->i_fop = &udf_file_operations;
	mark_inode_dirty(inode);

	return udf_add_nondir(dentry, inode);
}

393
static int udf_tmpfile(struct mnt_idmap *idmap, struct inode *dir,
394
		       struct file *file, umode_t mode)
Al Viro's avatar
Al Viro committed
395
{
396
	struct inode *inode = udf_new_inode(dir, mode);
Al Viro's avatar
Al Viro committed
397

398 399
	if (IS_ERR(inode))
		return PTR_ERR(inode);
Al Viro's avatar
Al Viro committed
400

401
	inode->i_data.a_ops = &udf_aops;
Al Viro's avatar
Al Viro committed
402 403 404
	inode->i_op = &udf_file_inode_operations;
	inode->i_fop = &udf_file_operations;
	mark_inode_dirty(inode);
405
	d_tmpfile(file, inode);
406
	unlock_new_inode(inode);
407
	return finish_open_simple(file, 0);
Al Viro's avatar
Al Viro committed
408 409
}

410
static int udf_mknod(struct mnt_idmap *idmap, struct inode *dir,
411
		     struct dentry *dentry, umode_t mode, dev_t rdev)
Linus Torvalds's avatar
Linus Torvalds committed
412
{
413
	struct inode *inode;
Linus Torvalds's avatar
Linus Torvalds committed
414 415 416 417

	if (!old_valid_dev(rdev))
		return -EINVAL;

418 419 420
	inode = udf_new_inode(dir, mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);
421

422 423
	init_special_inode(inode, mode, rdev);
	return udf_add_nondir(dentry, inode);
Linus Torvalds's avatar
Linus Torvalds committed
424 425
}

426
static int udf_mkdir(struct mnt_idmap *idmap, struct inode *dir,
427
		     struct dentry *dentry, umode_t mode)
Linus Torvalds's avatar
Linus Torvalds committed
428
{
429
	struct inode *inode;
430
	struct udf_fileident_iter iter;
Linus Torvalds's avatar
Linus Torvalds committed
431
	int err;
432 433
	struct udf_inode_info *dinfo = UDF_I(dir);
	struct udf_inode_info *iinfo;
Linus Torvalds's avatar
Linus Torvalds committed
434

435 436 437
	inode = udf_new_inode(dir, S_IFDIR | mode);
	if (IS_ERR(inode))
		return PTR_ERR(inode);
Linus Torvalds's avatar
Linus Torvalds committed
438

439
	iinfo = UDF_I(inode);
Linus Torvalds's avatar
Linus Torvalds committed
440 441
	inode->i_op = &udf_dir_inode_operations;
	inode->i_fop = &udf_dir_operations;
442 443 444
	err = udf_fiiter_add_entry(inode, NULL, &iter);
	if (err) {
		clear_nlink(inode);
445
		discard_new_inode(inode);
446
		return err;
Linus Torvalds's avatar
Linus Torvalds committed
447
	}
448
	set_nlink(inode, 2);
449 450 451
	iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
	iter.fi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
	*(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
452
		cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
453
	iter.fi.fileCharacteristics =
Marcin Slusarz's avatar
Marcin Slusarz committed
454
			FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
455 456
	udf_fiiter_write_fi(&iter, NULL);
	udf_fiiter_release(&iter);
Linus Torvalds's avatar
Linus Torvalds committed
457 458
	mark_inode_dirty(inode);

459 460
	err = udf_fiiter_add_entry(dir, dentry, &iter);
	if (err) {
461
		clear_nlink(inode);
462
		discard_new_inode(inode);
463
		return err;
Linus Torvalds's avatar
Linus Torvalds committed
464
	}
465 466 467
	iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
	iter.fi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
	*(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
468
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
469 470 471
	iter.fi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
	udf_fiiter_write_fi(&iter, NULL);
	udf_fiiter_release(&iter);
Jan Kara's avatar
Jan Kara committed
472
	udf_add_fid_counter(dir->i_sb, true, 1);
473
	inc_nlink(dir);
474
	dir->i_mtime = inode_set_ctime_current(dir);
Linus Torvalds's avatar
Linus Torvalds committed
475
	mark_inode_dirty(dir);
476
	d_instantiate_new(dentry, inode);
477

478
	return 0;
Linus Torvalds's avatar
Linus Torvalds committed
479 480 481 482
}

static int empty_dir(struct inode *dir)
{
483 484
	struct udf_fileident_iter iter;
	int ret;
Linus Torvalds's avatar
Linus Torvalds committed
485

486 487 488 489 490 491
	for (ret = udf_fiiter_init(&iter, dir, 0);
	     !ret && iter.pos < dir->i_size;
	     ret = udf_fiiter_advance(&iter)) {
		if (iter.fi.lengthFileIdent &&
		    !(iter.fi.fileCharacteristics & FID_FILE_CHAR_DELETED)) {
			udf_fiiter_release(&iter);
Linus Torvalds's avatar
Linus Torvalds committed
492 493 494
			return 0;
		}
	}
495
	udf_fiiter_release(&iter);
496

Linus Torvalds's avatar
Linus Torvalds committed
497 498 499
	return 1;
}

500
static int udf_rmdir(struct inode *dir, struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
501
{
502
	int ret;
503
	struct inode *inode = d_inode(dentry);
504
	struct udf_fileident_iter iter;
505
	struct kernel_lb_addr tloc;
Linus Torvalds's avatar
Linus Torvalds committed
506

507 508
	ret = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
	if (ret)
Linus Torvalds's avatar
Linus Torvalds committed
509 510
		goto out;

511 512
	ret = -EFSCORRUPTED;
	tloc = lelb_to_cpu(iter.fi.icb.extLocation);
513
	if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
Linus Torvalds's avatar
Linus Torvalds committed
514
		goto end_rmdir;
515
	ret = -ENOTEMPTY;
Linus Torvalds's avatar
Linus Torvalds committed
516 517
	if (!empty_dir(inode))
		goto end_rmdir;
518
	udf_fiiter_delete_entry(&iter);
Linus Torvalds's avatar
Linus Torvalds committed
519
	if (inode->i_nlink != 2)
520
		udf_warn(inode->i_sb, "empty directory has nlink != 2 (%u)\n",
521
			 inode->i_nlink);
522
	clear_nlink(inode);
Linus Torvalds's avatar
Linus Torvalds committed
523
	inode->i_size = 0;
524
	inode_dec_link_count(dir);
Jan Kara's avatar
Jan Kara committed
525
	udf_add_fid_counter(dir->i_sb, true, -1);
526 527
	dir->i_mtime = inode_set_ctime_to_ts(dir,
					     inode_set_ctime_current(inode));
Linus Torvalds's avatar
Linus Torvalds committed
528
	mark_inode_dirty(dir);
529
	ret = 0;
530
end_rmdir:
531
	udf_fiiter_release(&iter);
532
out:
533
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
534 535
}

536
static int udf_unlink(struct inode *dir, struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
537
{
538
	int ret;
539
	struct inode *inode = d_inode(dentry);
540
	struct udf_fileident_iter iter;
541
	struct kernel_lb_addr tloc;
Linus Torvalds's avatar
Linus Torvalds committed
542

543 544
	ret = udf_fiiter_find_entry(dir, &dentry->d_name, &iter);
	if (ret)
Linus Torvalds's avatar
Linus Torvalds committed
545 546
		goto out;

547 548
	ret = -EFSCORRUPTED;
	tloc = lelb_to_cpu(iter.fi.icb.extLocation);
549
	if (udf_get_lb_pblock(dir->i_sb, &tloc, 0) != inode->i_ino)
Linus Torvalds's avatar
Linus Torvalds committed
550 551
		goto end_unlink;

552
	if (!inode->i_nlink) {
553
		udf_debug("Deleting nonexistent file (%lu), %u\n",
554
			  inode->i_ino, inode->i_nlink);
555
		set_nlink(inode, 1);
Linus Torvalds's avatar
Linus Torvalds committed
556
	}
557
	udf_fiiter_delete_entry(&iter);
558
	dir->i_mtime = inode_set_ctime_current(dir);
Linus Torvalds's avatar
Linus Torvalds committed
559
	mark_inode_dirty(dir);
560
	inode_dec_link_count(inode);
Jan Kara's avatar
Jan Kara committed
561
	udf_add_fid_counter(dir->i_sb, false, -1);
562
	inode_set_ctime_to_ts(inode, inode_get_ctime(dir));
563
	ret = 0;
564
end_unlink:
565
	udf_fiiter_release(&iter);
566
out:
567
	return ret;
Linus Torvalds's avatar
Linus Torvalds committed
568 569
}

570
static int udf_symlink(struct mnt_idmap *idmap, struct inode *dir,
571
		       struct dentry *dentry, const char *symname)
Linus Torvalds's avatar
Linus Torvalds committed
572
{
573
	struct inode *inode = udf_new_inode(dir, S_IFLNK | 0777);
Linus Torvalds's avatar
Linus Torvalds committed
574
	struct pathComponent *pc;
Al Viro's avatar
Al Viro committed
575
	const char *compstart;
576
	struct extent_position epos = {};
Linus Torvalds's avatar
Linus Torvalds committed
577
	int eoffset, elen = 0;
Al Viro's avatar
Al Viro committed
578
	uint8_t *ea;
Linus Torvalds's avatar
Linus Torvalds committed
579
	int err;
580
	udf_pblk_t block;
Al Viro's avatar
Al Viro committed
581
	unsigned char *name = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
582
	int namelen;
583
	struct udf_inode_info *iinfo;
584
	struct super_block *sb = dir->i_sb;
Linus Torvalds's avatar
Linus Torvalds committed
585

586 587
	if (IS_ERR(inode))
		return PTR_ERR(inode);
Linus Torvalds's avatar
Linus Torvalds committed
588

589 590
	iinfo = UDF_I(inode);
	down_write(&iinfo->i_data_sem);
591
	name = kmalloc(UDF_NAME_LEN_CS0, GFP_NOFS);
592 593 594 595 596
	if (!name) {
		err = -ENOMEM;
		goto out_no_entry;
	}

Linus Torvalds's avatar
Linus Torvalds committed
597
	inode->i_data.a_ops = &udf_symlink_aops;
598
	inode->i_op = &udf_symlink_inode_operations;
599
	inode_nohighmem(inode);
Linus Torvalds's avatar
Linus Torvalds committed
600

601
	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
602
		struct kernel_lb_addr eloc;
603
		uint32_t bsize;
Linus Torvalds's avatar
Linus Torvalds committed
604

605
		block = udf_new_block(sb, inode,
606 607
				iinfo->i_location.partitionReferenceNum,
				iinfo->i_location.logicalBlockNum, &err);
Linus Torvalds's avatar
Linus Torvalds committed
608 609
		if (!block)
			goto out_no_entry;
610
		epos.block = iinfo->i_location;
611 612
		epos.offset = udf_file_entry_alloc_offset(inode);
		epos.bh = NULL;
Linus Torvalds's avatar
Linus Torvalds committed
613
		eloc.logicalBlockNum = block;
Marcin Slusarz's avatar
Marcin Slusarz committed
614
		eloc.partitionReferenceNum =
615
				iinfo->i_location.partitionReferenceNum;
616
		bsize = sb->s_blocksize;
617
		iinfo->i_lenExtents = bsize;
618
		err = udf_add_aext(inode, &epos, &eloc, bsize, 0);
Jan Kara's avatar
Jan Kara committed
619
		brelse(epos.bh);
620 621 622 623
		if (err < 0) {
			udf_free_blocks(sb, inode, &eloc, 0, 1);
			goto out_no_entry;
		}
Linus Torvalds's avatar
Linus Torvalds committed
624

625
		block = udf_get_pblock(sb, block,
626
				iinfo->i_location.partitionReferenceNum,
Marcin Slusarz's avatar
Marcin Slusarz committed
627
				0);
Jan Kara's avatar
Jan Kara committed
628
		epos.bh = sb_getblk(sb, block);
629 630
		if (unlikely(!epos.bh)) {
			err = -ENOMEM;
631
			udf_free_blocks(sb, inode, &eloc, 0, 1);
632 633
			goto out_no_entry;
		}
634
		lock_buffer(epos.bh);
635
		memset(epos.bh->b_data, 0x00, bsize);
636 637 638 639
		set_buffer_uptodate(epos.bh);
		unlock_buffer(epos.bh);
		mark_buffer_dirty_inode(epos.bh, inode);
		ea = epos.bh->b_data + udf_ext0_offset(inode);
640
	} else
641
		ea = iinfo->i_data + iinfo->i_lenEAttr;
Linus Torvalds's avatar
Linus Torvalds committed
642

643
	eoffset = sb->s_blocksize - udf_ext0_offset(inode);
Linus Torvalds's avatar
Linus Torvalds committed
644 645
	pc = (struct pathComponent *)ea;

646 647
	if (*symname == '/') {
		do {
Linus Torvalds's avatar
Linus Torvalds committed
648 649 650 651 652 653 654 655 656 657 658
			symname++;
		} while (*symname == '/');

		pc->componentType = 1;
		pc->lengthComponentIdent = 0;
		pc->componentFileVersionNum = 0;
		elen += sizeof(struct pathComponent);
	}

	err = -ENAMETOOLONG;

659
	while (*symname) {
Linus Torvalds's avatar
Linus Torvalds committed
660 661 662 663 664
		if (elen + sizeof(struct pathComponent) > eoffset)
			goto out_no_entry;

		pc = (struct pathComponent *)(ea + elen);

Al Viro's avatar
Al Viro committed
665
		compstart = symname;
Linus Torvalds's avatar
Linus Torvalds committed
666

667
		do {
Linus Torvalds's avatar
Linus Torvalds committed
668 669 670 671 672 673
			symname++;
		} while (*symname && *symname != '/');

		pc->componentType = 5;
		pc->lengthComponentIdent = 0;
		pc->componentFileVersionNum = 0;
674 675
		if (compstart[0] == '.') {
			if ((symname - compstart) == 1)
Linus Torvalds's avatar
Linus Torvalds committed
676
				pc->componentType = 4;
Marcin Slusarz's avatar
Marcin Slusarz committed
677 678
			else if ((symname - compstart) == 2 &&
					compstart[1] == '.')
Linus Torvalds's avatar
Linus Torvalds committed
679 680 681
				pc->componentType = 3;
		}

682
		if (pc->componentType == 5) {
683 684
			namelen = udf_put_filename(sb, compstart,
						   symname - compstart,
685
						   name, UDF_NAME_LEN_CS0);
686
			if (!namelen)
Linus Torvalds's avatar
Linus Torvalds committed
687 688
				goto out_no_entry;

Marcin Slusarz's avatar
Marcin Slusarz committed
689 690
			if (elen + sizeof(struct pathComponent) + namelen >
					eoffset)
Linus Torvalds's avatar
Linus Torvalds committed
691 692 693 694 695 696 697 698 699
				goto out_no_entry;
			else
				pc->lengthComponentIdent = namelen;

			memcpy(pc->componentIdent, name, namelen);
		}

		elen += sizeof(struct pathComponent) + pc->lengthComponentIdent;

700 701
		if (*symname) {
			do {
Linus Torvalds's avatar
Linus Torvalds committed
702 703 704 705 706
				symname++;
			} while (*symname == '/');
		}
	}

Jan Kara's avatar
Jan Kara committed
707
	brelse(epos.bh);
Linus Torvalds's avatar
Linus Torvalds committed
708
	inode->i_size = elen;
709 710
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		iinfo->i_lenAlloc = inode->i_size;
Jan Kara's avatar
Jan Kara committed
711 712
	else
		udf_truncate_tail_extent(inode);
Linus Torvalds's avatar
Linus Torvalds committed
713
	mark_inode_dirty(inode);
714
	up_write(&iinfo->i_data_sem);
Linus Torvalds's avatar
Linus Torvalds committed
715

716
	err = udf_add_nondir(dentry, inode);
717
out:
718
	kfree(name);
Linus Torvalds's avatar
Linus Torvalds committed
719 720
	return err;

721
out_no_entry:
722
	up_write(&iinfo->i_data_sem);
723
	inode_dec_link_count(inode);
724
	discard_new_inode(inode);
Linus Torvalds's avatar
Linus Torvalds committed
725 726 727
	goto out;
}

728 729
static int udf_link(struct dentry *old_dentry, struct inode *dir,
		    struct dentry *dentry)
Linus Torvalds's avatar
Linus Torvalds committed
730
{
731
	struct inode *inode = d_inode(old_dentry);
732
	struct udf_fileident_iter iter;
Linus Torvalds's avatar
Linus Torvalds committed
733 734
	int err;

735 736
	err = udf_fiiter_add_entry(dir, dentry, &iter);
	if (err)
Linus Torvalds's avatar
Linus Torvalds committed
737
		return err;
738 739
	iter.fi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
	iter.fi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
740
	if (UDF_SB(inode->i_sb)->s_lvid_bh) {
741
		*(__le32 *)((struct allocDescImpUse *)iter.fi.icb.impUse)->impUse =
742
			cpu_to_le32(lvid_get_unique_id(inode->i_sb));
Linus Torvalds's avatar
Linus Torvalds committed
743
	}
744 745
	udf_fiiter_write_fi(&iter, NULL);
	udf_fiiter_release(&iter);
746

747
	inc_nlink(inode);
Jan Kara's avatar
Jan Kara committed
748
	udf_add_fid_counter(dir->i_sb, false, 1);
749
	inode_set_ctime_current(inode);
Linus Torvalds's avatar
Linus Torvalds committed
750
	mark_inode_dirty(inode);
751
	dir->i_mtime = inode_set_ctime_current(dir);
752
	mark_inode_dirty(dir);
Al Viro's avatar
Al Viro committed
753
	ihold(inode);
Linus Torvalds's avatar
Linus Torvalds committed
754
	d_instantiate(dentry, inode);
755

Linus Torvalds's avatar
Linus Torvalds committed
756 757 758 759 760 761
	return 0;
}

/* Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
762
static int udf_rename(struct mnt_idmap *idmap, struct inode *old_dir,
763 764
		      struct dentry *old_dentry, struct inode *new_dir,
		      struct dentry *new_dentry, unsigned int flags)
Linus Torvalds's avatar
Linus Torvalds committed
765
{
766 767
	struct inode *old_inode = d_inode(old_dentry);
	struct inode *new_inode = d_inode(new_dentry);
768 769 770
	struct udf_fileident_iter oiter, niter, diriter;
	bool has_diriter = false;
	int retval;
771
	struct kernel_lb_addr tloc;
Linus Torvalds's avatar
Linus Torvalds committed
772

773 774 775
	if (flags & ~RENAME_NOREPLACE)
		return -EINVAL;

776 777 778
	retval = udf_fiiter_find_entry(old_dir, &old_dentry->d_name, &oiter);
	if (retval)
		return retval;
Linus Torvalds's avatar
Linus Torvalds committed
779

780 781 782 783
	tloc = lelb_to_cpu(oiter.fi.icb.extLocation);
	if (udf_get_lb_pblock(old_dir->i_sb, &tloc, 0) != old_inode->i_ino) {
		retval = -ENOENT;
		goto out_oiter;
Linus Torvalds's avatar
Linus Torvalds committed
784 785
	}

786
	if (S_ISDIR(old_inode->i_mode)) {
787
		if (new_inode) {
Linus Torvalds's avatar
Linus Torvalds committed
788 789
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
790
				goto out_oiter;
Linus Torvalds's avatar
Linus Torvalds committed
791
		}
792 793 794 795 796 797 798
		retval = udf_fiiter_find_entry(old_inode, &dotdot_name,
					       &diriter);
		if (retval == -ENOENT) {
			udf_err(old_inode->i_sb,
				"directory (ino %lu) has no '..' entry\n",
				old_inode->i_ino);
			retval = -EFSCORRUPTED;
Linus Torvalds's avatar
Linus Torvalds committed
799
		}
800
		if (retval)
801 802 803
			goto out_oiter;
		has_diriter = true;
		tloc = lelb_to_cpu(diriter.fi.icb.extLocation);
804
		if (udf_get_lb_pblock(old_inode->i_sb, &tloc, 0) !=
805 806 807 808 809 810 811 812
				old_dir->i_ino) {
			retval = -EFSCORRUPTED;
			udf_err(old_inode->i_sb,
				"directory (ino %lu) has parent entry pointing to another inode (%lu != %u)\n",
				old_inode->i_ino, old_dir->i_ino,
				udf_get_lb_pblock(old_inode->i_sb, &tloc, 0));
			goto out_oiter;
		}
Linus Torvalds's avatar
Linus Torvalds committed
813
	}
814 815 816 817 818 819 820 821 822

	retval = udf_fiiter_find_entry(new_dir, &new_dentry->d_name, &niter);
	if (retval && retval != -ENOENT)
		goto out_oiter;
	/* Entry found but not passed by VFS? */
	if (!retval && !new_inode) {
		retval = -EFSCORRUPTED;
		udf_fiiter_release(&niter);
		goto out_oiter;
Linus Torvalds's avatar
Linus Torvalds committed
823
	}
824 825 826 827 828 829
	/* Entry not found? Need to add one... */
	if (retval) {
		udf_fiiter_release(&niter);
		retval = udf_fiiter_add_entry(new_dir, new_dentry, &niter);
		if (retval)
			goto out_oiter;
Linus Torvalds's avatar
Linus Torvalds committed
830 831 832 833 834 835
	}

	/*
	 * Like most other Unix systems, set the ctime for inodes on a
	 * rename.
	 */
836
	inode_set_ctime_current(old_inode);
Linus Torvalds's avatar
Linus Torvalds committed
837 838 839 840 841
	mark_inode_dirty(old_inode);

	/*
	 * ok, that's it
	 */
842 843 844 845 846
	niter.fi.fileVersionNum = oiter.fi.fileVersionNum;
	niter.fi.fileCharacteristics = oiter.fi.fileCharacteristics;
	memcpy(&(niter.fi.icb), &(oiter.fi.icb), sizeof(oiter.fi.icb));
	udf_fiiter_write_fi(&niter, NULL);
	udf_fiiter_release(&niter);
Linus Torvalds's avatar
Linus Torvalds committed
847

848 849 850 851 852 853 854 855 856 857 858 859 860 861
	/*
	 * The old entry may have moved due to new entry allocation. Find it
	 * again.
	 */
	udf_fiiter_release(&oiter);
	retval = udf_fiiter_find_entry(old_dir, &old_dentry->d_name, &oiter);
	if (retval) {
		udf_err(old_dir->i_sb,
			"failed to find renamed entry again in directory (ino %lu)\n",
			old_dir->i_ino);
	} else {
		udf_fiiter_delete_entry(&oiter);
		udf_fiiter_release(&oiter);
	}
Linus Torvalds's avatar
Linus Torvalds committed
862

863
	if (new_inode) {
864
		inode_set_ctime_current(new_inode);
865
		inode_dec_link_count(new_inode);
Jan Kara's avatar
Jan Kara committed
866 867
		udf_add_fid_counter(old_dir->i_sb, S_ISDIR(new_inode->i_mode),
				    -1);
Linus Torvalds's avatar
Linus Torvalds committed
868
	}
869 870
	old_dir->i_mtime = inode_set_ctime_current(old_dir);
	new_dir->i_mtime = inode_set_ctime_current(new_dir);
Linus Torvalds's avatar
Linus Torvalds committed
871
	mark_inode_dirty(old_dir);
872
	mark_inode_dirty(new_dir);
Linus Torvalds's avatar
Linus Torvalds committed
873

874 875 876 877 878 879 880
	if (has_diriter) {
		diriter.fi.icb.extLocation =
					cpu_to_lelb(UDF_I(new_dir)->i_location);
		udf_update_tag((char *)&diriter.fi,
			       udf_dir_entry_len(&diriter.fi));
		udf_fiiter_write_fi(&diriter, NULL);
		udf_fiiter_release(&diriter);
Marcin Slusarz's avatar
Marcin Slusarz committed
881

882
		inode_dec_link_count(old_dir);
Marcin Slusarz's avatar
Marcin Slusarz committed
883
		if (new_inode)
884
			inode_dec_link_count(new_inode);
Marcin Slusarz's avatar
Marcin Slusarz committed
885
		else {
886
			inc_nlink(new_dir);
Linus Torvalds's avatar
Linus Torvalds committed
887 888 889
			mark_inode_dirty(new_dir);
		}
	}
890 891
	return 0;
out_oiter:
892
	if (has_diriter)
893 894
		udf_fiiter_release(&diriter);
	udf_fiiter_release(&oiter);
895

Linus Torvalds's avatar
Linus Torvalds committed
896 897 898
	return retval;
}

Rasmus Rohde's avatar
Rasmus Rohde committed
899 900
static struct dentry *udf_get_parent(struct dentry *child)
{
901
	struct kernel_lb_addr tloc;
Rasmus Rohde's avatar
Rasmus Rohde committed
902
	struct inode *inode = NULL;
903 904
	struct udf_fileident_iter iter;
	int err;
Rasmus Rohde's avatar
Rasmus Rohde committed
905

906 907 908
	err = udf_fiiter_find_entry(d_inode(child), &dotdot_name, &iter);
	if (err)
		return ERR_PTR(err);
Rasmus Rohde's avatar
Rasmus Rohde committed
909

910 911
	tloc = lelb_to_cpu(iter.fi.icb.extLocation);
	udf_fiiter_release(&iter);
912
	inode = udf_iget(child->d_sb, &tloc);
913 914
	if (IS_ERR(inode))
		return ERR_CAST(inode);
Rasmus Rohde's avatar
Rasmus Rohde committed
915

916
	return d_obtain_alias(inode);
Rasmus Rohde's avatar
Rasmus Rohde committed
917 918 919 920 921 922 923
}


static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
					u16 partref, __u32 generation)
{
	struct inode *inode;
924
	struct kernel_lb_addr loc;
Rasmus Rohde's avatar
Rasmus Rohde committed
925 926 927 928 929 930

	if (block == 0)
		return ERR_PTR(-ESTALE);

	loc.logicalBlockNum = block;
	loc.partitionReferenceNum = partref;
931
	inode = udf_iget(sb, &loc);
Rasmus Rohde's avatar
Rasmus Rohde committed
932

933 934
	if (IS_ERR(inode))
		return ERR_CAST(inode);
Rasmus Rohde's avatar
Rasmus Rohde committed
935 936 937 938 939

	if (generation && inode->i_generation != generation) {
		iput(inode);
		return ERR_PTR(-ESTALE);
	}
940
	return d_obtain_alias(inode);
Rasmus Rohde's avatar
Rasmus Rohde committed
941 942 943 944 945
}

static struct dentry *udf_fh_to_dentry(struct super_block *sb,
				       struct fid *fid, int fh_len, int fh_type)
{
NeilBrown's avatar
NeilBrown committed
946
	if (fh_len < 3 ||
Rasmus Rohde's avatar
Rasmus Rohde committed
947 948 949 950 951 952 953 954 955 956 957
	    (fh_type != FILEID_UDF_WITH_PARENT &&
	     fh_type != FILEID_UDF_WITHOUT_PARENT))
		return NULL;

	return udf_nfs_get_inode(sb, fid->udf.block, fid->udf.partref,
			fid->udf.generation);
}

static struct dentry *udf_fh_to_parent(struct super_block *sb,
				       struct fid *fid, int fh_len, int fh_type)
{
NeilBrown's avatar
NeilBrown committed
958
	if (fh_len < 5 || fh_type != FILEID_UDF_WITH_PARENT)
Rasmus Rohde's avatar
Rasmus Rohde committed
959 960 961 962 963 964
		return NULL;

	return udf_nfs_get_inode(sb, fid->udf.parent_block,
				 fid->udf.parent_partref,
				 fid->udf.parent_generation);
}
Al Viro's avatar
Al Viro committed
965 966
static int udf_encode_fh(struct inode *inode, __u32 *fh, int *lenp,
			 struct inode *parent)
Rasmus Rohde's avatar
Rasmus Rohde committed
967 968
{
	int len = *lenp;
969
	struct kernel_lb_addr location = UDF_I(inode)->i_location;
Rasmus Rohde's avatar
Rasmus Rohde committed
970 971 972
	struct fid *fid = (struct fid *)fh;
	int type = FILEID_UDF_WITHOUT_PARENT;

Al Viro's avatar
Al Viro committed
973
	if (parent && (len < 5)) {
974
		*lenp = 5;
975
		return FILEID_INVALID;
976 977
	} else if (len < 3) {
		*lenp = 3;
978
		return FILEID_INVALID;
979
	}
Rasmus Rohde's avatar
Rasmus Rohde committed
980 981 982 983

	*lenp = 3;
	fid->udf.block = location.logicalBlockNum;
	fid->udf.partref = location.partitionReferenceNum;
984
	fid->udf.parent_partref = 0;
Rasmus Rohde's avatar
Rasmus Rohde committed
985 986
	fid->udf.generation = inode->i_generation;

Al Viro's avatar
Al Viro committed
987 988
	if (parent) {
		location = UDF_I(parent)->i_location;
Rasmus Rohde's avatar
Rasmus Rohde committed
989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005
		fid->udf.parent_block = location.logicalBlockNum;
		fid->udf.parent_partref = location.partitionReferenceNum;
		fid->udf.parent_generation = inode->i_generation;
		*lenp = 5;
		type = FILEID_UDF_WITH_PARENT;
	}

	return type;
}

const struct export_operations udf_export_ops = {
	.encode_fh	= udf_encode_fh,
	.fh_to_dentry   = udf_fh_to_dentry,
	.fh_to_parent   = udf_fh_to_parent,
	.get_parent     = udf_get_parent,
};

1006
const struct inode_operations udf_dir_inode_operations = {
1007 1008 1009 1010 1011 1012 1013 1014 1015
	.lookup				= udf_lookup,
	.create				= udf_create,
	.link				= udf_link,
	.unlink				= udf_unlink,
	.symlink			= udf_symlink,
	.mkdir				= udf_mkdir,
	.rmdir				= udf_rmdir,
	.mknod				= udf_mknod,
	.rename				= udf_rename,
Al Viro's avatar
Al Viro committed
1016
	.tmpfile			= udf_tmpfile,
Linus Torvalds's avatar
Linus Torvalds committed
1017
};