namei.c 34.3 KB
Newer Older
L
Linus Torvalds 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
/*
 * namei.c
 *
 * PURPOSE
 *      Inode name handling routines for the OSTA-UDF(tm) filesystem.
 *
 * COPYRIGHT
 *      This file is distributed under the terms of the GNU General Public
 *      License (GPL). Copies of the GPL can be obtained from:
 *              ftp://prep.ai.mit.edu/pub/gnu/GPL
 *      Each contributing author retains all rights to their own work.
 *
 *  (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>
#include <linux/quotaops.h>
#include <linux/smp_lock.h>
#include <linux/buffer_head.h>
A
Alexey Dobriyan 已提交
33
#include <linux/sched.h>
34
#include <linux/crc-itu-t.h>
R
Rasmus Rohde 已提交
35
#include <linux/exportfs.h>
L
Linus Torvalds 已提交
36

37 38
static inline int udf_match(int len1, const char *name1, int len2,
			    const char *name2)
L
Linus Torvalds 已提交
39 40 41
{
	if (len1 != len2)
		return 0;
42

L
Linus Torvalds 已提交
43 44 45 46
	return !memcmp(name1, name2, len1);
}

int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
47
		 struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
M
Marcin Slusarz 已提交
48
		 uint8_t *impuse, uint8_t *fileident)
L
Linus Torvalds 已提交
49 50 51 52 53 54 55
{
	uint16_t crclen = fibh->eoffset - fibh->soffset - sizeof(tag);
	uint16_t crc;
	int offset;
	uint16_t liu = le16_to_cpu(cfi->lengthOfImpUse);
	uint8_t lfi = cfi->lengthFileIdent;
	int padlen = fibh->eoffset - fibh->soffset - liu - lfi -
56
		sizeof(struct fileIdentDesc);
L
Linus Torvalds 已提交
57 58
	int adinicb = 0;

59
	if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
60 61 62 63
		adinicb = 1;

	offset = fibh->soffset + sizeof(struct fileIdentDesc);

64
	if (impuse) {
65 66 67
		if (adinicb || (offset + liu < 0)) {
			memcpy((uint8_t *)sfi->impUse, impuse, liu);
		} else if (offset >= 0) {
L
Linus Torvalds 已提交
68
			memcpy(fibh->ebh->b_data + offset, impuse, liu);
69 70
		} else {
			memcpy((uint8_t *)sfi->impUse, impuse, -offset);
M
Marcin Slusarz 已提交
71 72
			memcpy(fibh->ebh->b_data, impuse - offset,
				liu + offset);
L
Linus Torvalds 已提交
73 74 75 76 77
		}
	}

	offset += liu;

78
	if (fileident) {
79 80 81
		if (adinicb || (offset + lfi < 0)) {
			memcpy((uint8_t *)sfi->fileIdent + liu, fileident, lfi);
		} else if (offset >= 0) {
L
Linus Torvalds 已提交
82
			memcpy(fibh->ebh->b_data + offset, fileident, lfi);
83
		} else {
M
Marcin Slusarz 已提交
84 85 86 87
			memcpy((uint8_t *)sfi->fileIdent + liu, fileident,
				-offset);
			memcpy(fibh->ebh->b_data, fileident - offset,
				lfi + offset);
L
Linus Torvalds 已提交
88 89 90 91 92
		}
	}

	offset += lfi;

93 94 95
	if (adinicb || (offset + padlen < 0)) {
		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, padlen);
	} else if (offset >= 0) {
L
Linus Torvalds 已提交
96
		memset(fibh->ebh->b_data + offset, 0x00, padlen);
97 98
	} else {
		memset((uint8_t *)sfi->padding + liu + lfi, 0x00, -offset);
L
Linus Torvalds 已提交
99 100 101
		memset(fibh->ebh->b_data, 0x00, padlen + offset);
	}

102 103
	crc = crc_itu_t(0, (uint8_t *)cfi + sizeof(tag),
		      sizeof(struct fileIdentDesc) - sizeof(tag));
104 105

	if (fibh->sbh == fibh->ebh) {
106
		crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
M
Marcin Slusarz 已提交
107
			      crclen + sizeof(tag) -
108
			      sizeof(struct fileIdentDesc));
109
	} else if (sizeof(struct fileIdentDesc) >= -fibh->soffset) {
110
		crc = crc_itu_t(crc, fibh->ebh->b_data +
M
Marcin Slusarz 已提交
111 112 113
					sizeof(struct fileIdentDesc) +
					fibh->soffset,
			      crclen + sizeof(tag) -
114
					sizeof(struct fileIdentDesc));
115
	} else {
116 117 118
		crc = crc_itu_t(crc, (uint8_t *)sfi->impUse,
			      -fibh->soffset - sizeof(struct fileIdentDesc));
		crc = crc_itu_t(crc, fibh->ebh->b_data, fibh->eoffset);
L
Linus Torvalds 已提交
119 120 121 122
	}

	cfi->descTag.descCRC = cpu_to_le16(crc);
	cfi->descTag.descCRCLength = cpu_to_le16(crclen);
123
	cfi->descTag.tagChecksum = udf_tag_checksum(&cfi->descTag);
L
Linus Torvalds 已提交
124

125
	if (adinicb || (sizeof(struct fileIdentDesc) <= -fibh->soffset)) {
M
Marcin Slusarz 已提交
126 127
		memcpy((uint8_t *)sfi, (uint8_t *)cfi,
			sizeof(struct fileIdentDesc));
128 129 130
	} else {
		memcpy((uint8_t *)sfi, (uint8_t *)cfi, -fibh->soffset);
		memcpy(fibh->ebh->b_data, (uint8_t *)cfi - fibh->soffset,
131
		       sizeof(struct fileIdentDesc) + fibh->soffset);
L
Linus Torvalds 已提交
132 133
	}

134
	if (adinicb) {
L
Linus Torvalds 已提交
135
		mark_inode_dirty(inode);
136
	} else {
L
Linus Torvalds 已提交
137 138 139 140 141 142 143
		if (fibh->sbh != fibh->ebh)
			mark_buffer_dirty_inode(fibh->ebh, inode);
		mark_buffer_dirty_inode(fibh->sbh, inode);
	}
	return 0;
}

144 145 146 147
static struct fileIdentDesc *udf_find_entry(struct inode *dir,
					    struct dentry *dentry,
					    struct udf_fileident_bh *fibh,
					    struct fileIdentDesc *cfi)
L
Linus Torvalds 已提交
148
{
149
	struct fileIdentDesc *fi = NULL;
L
Linus Torvalds 已提交
150 151
	loff_t f_pos;
	int block, flen;
152
	char *fname = NULL;
L
Linus Torvalds 已提交
153 154 155
	char *nameptr;
	uint8_t lfi;
	uint16_t liu;
156
	loff_t size;
J
Jan Kara 已提交
157 158
	kernel_lb_addr eloc;
	uint32_t elen;
159
	sector_t offset;
160
	struct extent_position epos = {};
161
	struct udf_inode_info *dinfo = UDF_I(dir);
R
Rasmus Rohde 已提交
162 163
	int isdotdot = dentry->d_name.len == 2 &&
		dentry->d_name.name[0] == '.' && dentry->d_name.name[1] == '.';
L
Linus Torvalds 已提交
164

165 166
	size = udf_ext0_offset(dir) + dir->i_size;
	f_pos = udf_ext0_offset(dir);
L
Linus Torvalds 已提交
167

168
	fibh->sbh = fibh->ebh = NULL;
169
	fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
170 171 172 173
	if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
		if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
		    &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30))
			goto out_err;
L
Linus Torvalds 已提交
174
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
175
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
176
			if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
177
				epos.offset -= sizeof(short_ad);
178
			else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
179
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
180
		} else
L
Linus Torvalds 已提交
181 182
			offset = 0;

M
Marcin Slusarz 已提交
183
		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
184 185
		if (!fibh->sbh)
			goto out_err;
L
Linus Torvalds 已提交
186 187
	}

188 189 190 191
	fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!fname)
		goto out_err;

192
	while (f_pos < size) {
193 194
		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
					&elen, &offset);
195 196
		if (!fi)
			goto out_err;
L
Linus Torvalds 已提交
197 198 199 200

		liu = le16_to_cpu(cfi->lengthOfImpUse);
		lfi = cfi->lengthFileIdent;

201
		if (fibh->sbh == fibh->ebh) {
L
Linus Torvalds 已提交
202
			nameptr = fi->fileIdent + liu;
203
		} else {
L
Linus Torvalds 已提交
204 205
			int poffset;	/* Unpaded ending offset */

M
Marcin Slusarz 已提交
206 207
			poffset = fibh->soffset + sizeof(struct fileIdentDesc) +
					liu + lfi;
L
Linus Torvalds 已提交
208

M
Marcin Slusarz 已提交
209 210 211 212
			if (poffset >= lfi)
				nameptr = (uint8_t *)(fibh->ebh->b_data +
						      poffset - lfi);
			else {
L
Linus Torvalds 已提交
213
				nameptr = fname;
M
Marcin Slusarz 已提交
214 215 216 217
				memcpy(nameptr, fi->fileIdent + liu,
					lfi - poffset);
				memcpy(nameptr + lfi - poffset,
					fibh->ebh->b_data, poffset);
L
Linus Torvalds 已提交
218 219 220
			}
		}

221 222
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
			if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
L
Linus Torvalds 已提交
223 224
				continue;
		}
225 226 227

		if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
			if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
L
Linus Torvalds 已提交
228 229 230
				continue;
		}

R
Rasmus Rohde 已提交
231 232 233 234 235 236
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_PARENT) &&
		    isdotdot) {
			brelse(epos.bh);
			return fi;
		}

L
Linus Torvalds 已提交
237 238 239
		if (!lfi)
			continue;

M
Marcin Slusarz 已提交
240 241
		flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
		if (flen && udf_match(flen, fname, dentry->d_name.len,
242 243
				      dentry->d_name.name))
			goto out_ok;
L
Linus Torvalds 已提交
244
	}
245

246 247
out_err:
	fi = NULL;
L
Linus Torvalds 已提交
248
	if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
249 250
		brelse(fibh->ebh);
	brelse(fibh->sbh);
251
out_ok:
J
Jan Kara 已提交
252
	brelse(epos.bh);
253
	kfree(fname);
254

255
	return fi;
L
Linus Torvalds 已提交
256 257
}

258 259
static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
				 struct nameidata *nd)
L
Linus Torvalds 已提交
260 261
{
	struct inode *inode = NULL;
262
	struct fileIdentDesc cfi;
L
Linus Torvalds 已提交
263 264
	struct udf_fileident_bh fibh;

265
	if (dentry->d_name.len > UDF_NAME_LEN - 2)
L
Linus Torvalds 已提交
266 267 268 269 270
		return ERR_PTR(-ENAMETOOLONG);

	lock_kernel();
#ifdef UDF_RECOVERY
	/* temporary shorthand for specifying files by inode number */
271
	if (!strncmp(dentry->d_name.name, ".B=", 3)) {
272 273
		kernel_lb_addr lb = {
			.logicalBlockNum = 0,
M
Marcin Slusarz 已提交
274 275 276
			.partitionReferenceNum =
				simple_strtoul(dentry->d_name.name + 3,
						NULL, 0),
277
		};
L
Linus Torvalds 已提交
278
		inode = udf_iget(dir->i_sb, lb);
279
		if (!inode) {
L
Linus Torvalds 已提交
280 281 282
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
M
Marcin Slusarz 已提交
283
	} else
284
#endif /* UDF_RECOVERY */
L
Linus Torvalds 已提交
285

286
	if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
L
Linus Torvalds 已提交
287
		if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
288 289
			brelse(fibh.ebh);
		brelse(fibh.sbh);
L
Linus Torvalds 已提交
290 291

		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
292
		if (!inode) {
L
Linus Torvalds 已提交
293 294 295 296 297
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
	}
	unlock_kernel();
298

R
Rasmus Rohde 已提交
299
	return d_splice_alias(inode, dentry);
L
Linus Torvalds 已提交
300 301
}

302 303 304 305
static struct fileIdentDesc *udf_add_entry(struct inode *dir,
					   struct dentry *dentry,
					   struct udf_fileident_bh *fibh,
					   struct fileIdentDesc *cfi, int *err)
L
Linus Torvalds 已提交
306
{
M
Marcin Slusarz 已提交
307
	struct super_block *sb = dir->i_sb;
308
	struct fileIdentDesc *fi = NULL;
309
	char *name = NULL;
L
Linus Torvalds 已提交
310 311
	int namelen;
	loff_t f_pos;
312
	loff_t size = udf_ext0_offset(dir) + dir->i_size;
L
Linus Torvalds 已提交
313 314 315 316
	int nfidlen;
	uint8_t lfi;
	uint16_t liu;
	int block;
J
Jan Kara 已提交
317
	kernel_lb_addr eloc;
318
	uint32_t elen = 0;
319
	sector_t offset;
320
	struct extent_position epos = {};
321
	struct udf_inode_info *dinfo;
L
Linus Torvalds 已提交
322

323 324 325 326 327 328 329
	fibh->sbh = fibh->ebh = NULL;
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!name) {
		*err = -ENOMEM;
		goto out_err;
	}

330 331
	if (dentry) {
		if (!dentry->d_name.len) {
L
Linus Torvalds 已提交
332
			*err = -EINVAL;
333
			goto out_err;
L
Linus Torvalds 已提交
334
		}
M
Marcin Slusarz 已提交
335 336 337
		namelen = udf_put_filename(sb, dentry->d_name.name, name,
						 dentry->d_name.len);
		if (!namelen) {
L
Linus Torvalds 已提交
338
			*err = -ENAMETOOLONG;
339
			goto out_err;
L
Linus Torvalds 已提交
340
		}
341
	} else {
L
Linus Torvalds 已提交
342
		namelen = 0;
343
	}
L
Linus Torvalds 已提交
344 345 346

	nfidlen = (sizeof(struct fileIdentDesc) + namelen + 3) & ~3;

347
	f_pos = udf_ext0_offset(dir);
L
Linus Torvalds 已提交
348

349
	fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
350
	dinfo = UDF_I(dir);
351 352 353 354 355 356 357 358
	if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
		if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos,
		    &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) {
			block = udf_get_lb_pblock(dir->i_sb,
					dinfo->i_location, 0);
			fibh->soffset = fibh->eoffset = sb->s_blocksize;
			goto add;
		}
L
Linus Torvalds 已提交
359
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
360
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
361
			if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
362
				epos.offset -= sizeof(short_ad);
363
			else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
364
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
365
		} else
L
Linus Torvalds 已提交
366 367
			offset = 0;

M
Marcin Slusarz 已提交
368 369
		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
		if (!fibh->sbh) {
L
Linus Torvalds 已提交
370
			*err = -EIO;
371
			goto out_err;
L
Linus Torvalds 已提交
372 373
		}

374
		block = dinfo->i_location.logicalBlockNum;
L
Linus Torvalds 已提交
375 376
	}

377
	while (f_pos < size) {
378 379
		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
					&elen, &offset);
L
Linus Torvalds 已提交
380

381
		if (!fi) {
L
Linus Torvalds 已提交
382
			*err = -EIO;
383
			goto out_err;
L
Linus Torvalds 已提交
384 385 386 387 388
		}

		liu = le16_to_cpu(cfi->lengthOfImpUse);
		lfi = cfi->lengthFileIdent;

389
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
M
Marcin Slusarz 已提交
390 391
			if (((sizeof(struct fileIdentDesc) +
					liu + lfi + 3) & ~3) == nfidlen) {
L
Linus Torvalds 已提交
392 393 394 395 396
				cfi->descTag.tagSerialNum = cpu_to_le16(1);
				cfi->fileVersionNum = cpu_to_le16(1);
				cfi->fileCharacteristics = 0;
				cfi->lengthFileIdent = namelen;
				cfi->lengthOfImpUse = cpu_to_le16(0);
M
Marcin Slusarz 已提交
397 398
				if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
						  name))
399
					goto out_ok;
M
Marcin Slusarz 已提交
400
				else {
L
Linus Torvalds 已提交
401
					*err = -EIO;
402
					goto out_err;
L
Linus Torvalds 已提交
403 404 405 406 407
				}
			}
		}
	}

408
add:
409 410
	/* Is there any extent whose size we need to round up? */
	if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB && elen) {
J
Jan Kara 已提交
411 412 413 414 415 416 417
		elen = (elen + sb->s_blocksize - 1) & ~(sb->s_blocksize - 1);
		if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
			epos.offset -= sizeof(short_ad);
		else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
			epos.offset -= sizeof(long_ad);
		udf_write_aext(dir, &epos, eloc, elen, 1);
	}
L
Linus Torvalds 已提交
418 419
	f_pos += nfidlen;

420
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
421
	    sb->s_blocksize - fibh->eoffset < nfidlen) {
J
Jan Kara 已提交
422
		brelse(epos.bh);
J
Jan Kara 已提交
423
		epos.bh = NULL;
L
Linus Torvalds 已提交
424 425
		fibh->soffset -= udf_ext0_offset(dir);
		fibh->eoffset -= udf_ext0_offset(dir);
426
		f_pos -= udf_ext0_offset(dir);
L
Linus Torvalds 已提交
427
		if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
428 429
			brelse(fibh->ebh);
		brelse(fibh->sbh);
M
Marcin Slusarz 已提交
430 431 432
		fibh->sbh = fibh->ebh =
				udf_expand_dir_adinicb(dir, &block, err);
		if (!fibh->sbh)
433
			goto out_err;
434
		epos.block = dinfo->i_location;
J
Jan Kara 已提交
435
		epos.offset = udf_file_entry_alloc_offset(dir);
J
Jan Kara 已提交
436 437
		/* Load extent udf_expand_dir_adinicb() has created */
		udf_current_aext(dir, &epos, &eloc, &elen, 1);
L
Linus Torvalds 已提交
438 439
	}

440
	if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
L
Linus Torvalds 已提交
441 442
		fibh->soffset = fibh->eoffset;
		fibh->eoffset += nfidlen;
443
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
444
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
445 446 447
			fibh->sbh = fibh->ebh;
		}

448 449
		if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			block = dinfo->i_location.logicalBlockNum;
M
Marcin Slusarz 已提交
450
			fi = (struct fileIdentDesc *)
451
					(dinfo->i_ext.i_data +
452
					 fibh->soffset -
M
Marcin Slusarz 已提交
453
					 udf_ext0_offset(dir) +
454
					 dinfo->i_lenEAttr);
455
		} else {
M
Marcin Slusarz 已提交
456 457 458 459 460
			block = eloc.logicalBlockNum +
					((elen - 1) >>
						dir->i_sb->s_blocksize_bits);
			fi = (struct fileIdentDesc *)
				(fibh->sbh->b_data + fibh->soffset);
L
Linus Torvalds 已提交
461
		}
462
	} else {
L
Linus Torvalds 已提交
463 464
		fibh->soffset = fibh->eoffset - sb->s_blocksize;
		fibh->eoffset += nfidlen - sb->s_blocksize;
465
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
466
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
467 468 469 470
			fibh->sbh = fibh->ebh;
		}

		block = eloc.logicalBlockNum + ((elen - 1) >>
471
						dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
472
		fibh->ebh = udf_bread(dir,
473
				f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
474 475
		if (!fibh->ebh)
			goto out_err;
L
Linus Torvalds 已提交
476

477
		if (!fibh->soffset) {
J
Jan Kara 已提交
478
			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
479
			    (EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
480
				block = eloc.logicalBlockNum + ((elen - 1) >>
481
					dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
482
			} else
483
				block++;
L
Linus Torvalds 已提交
484

J
Jan Kara 已提交
485
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
486 487
			fibh->sbh = fibh->ebh;
			fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
488
		} else {
L
Linus Torvalds 已提交
489
			fi = (struct fileIdentDesc *)
M
Marcin Slusarz 已提交
490 491
				(fibh->sbh->b_data + sb->s_blocksize +
					fibh->soffset);
L
Linus Torvalds 已提交
492 493 494 495
		}
	}

	memset(cfi, 0, sizeof(struct fileIdentDesc));
M
Marcin Slusarz 已提交
496
	if (UDF_SB(sb)->s_udfrev >= 0x0200)
M
Marcin Slusarz 已提交
497 498
		udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
			    sizeof(tag));
L
Linus Torvalds 已提交
499
	else
M
Marcin Slusarz 已提交
500 501
		udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
			    sizeof(tag));
L
Linus Torvalds 已提交
502 503 504
	cfi->fileVersionNum = cpu_to_le16(1);
	cfi->lengthFileIdent = namelen;
	cfi->lengthOfImpUse = cpu_to_le16(0);
505
	if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
L
Linus Torvalds 已提交
506
		dir->i_size += nfidlen;
507 508
		if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
			dinfo->i_lenAlloc += nfidlen;
L
Linus Torvalds 已提交
509
		mark_inode_dirty(dir);
510
		goto out_ok;
511
	} else {
L
Linus Torvalds 已提交
512
		*err = -EIO;
513
		goto out_err;
L
Linus Torvalds 已提交
514
	}
515 516 517 518 519 520 521 522 523 524

out_err:
	fi = NULL;
	if (fibh->sbh != fibh->ebh)
		brelse(fibh->ebh);
	brelse(fibh->sbh);
out_ok:
	brelse(epos.bh);
	kfree(name);
	return fi;
L
Linus Torvalds 已提交
525 526 527
}

static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
528 529
			    struct udf_fileident_bh *fibh,
			    struct fileIdentDesc *cfi)
L
Linus Torvalds 已提交
530 531
{
	cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
532

L
Linus Torvalds 已提交
533 534
	if (UDF_QUERY_FLAG(inode->i_sb, UDF_FLAG_STRICT))
		memset(&(cfi->icb), 0x00, sizeof(long_ad));
535

L
Linus Torvalds 已提交
536 537 538
	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}

539 540
static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
		      struct nameidata *nd)
L
Linus Torvalds 已提交
541 542 543 544 545
{
	struct udf_fileident_bh fibh;
	struct inode *inode;
	struct fileIdentDesc cfi, *fi;
	int err;
546
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
547 548 549

	lock_kernel();
	inode = udf_new_inode(dir, mode, &err);
550
	if (!inode) {
L
Linus Torvalds 已提交
551 552 553 554
		unlock_kernel();
		return err;
	}

555 556
	iinfo = UDF_I(inode);
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
557 558 559 560 561 562 563 564
		inode->i_data.a_ops = &udf_adinicb_aops;
	else
		inode->i_data.a_ops = &udf_aops;
	inode->i_op = &udf_file_inode_operations;
	inode->i_fop = &udf_file_operations;
	inode->i_mode = mode;
	mark_inode_dirty(inode);

M
Marcin Slusarz 已提交
565 566
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
567
		inode->i_nlink--;
L
Linus Torvalds 已提交
568 569 570 571 572 573
		mark_inode_dirty(inode);
		iput(inode);
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
574
	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
575
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
576
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
577
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
578
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
579 580
		mark_inode_dirty(dir);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
581 582
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
583 584
	unlock_kernel();
	d_instantiate(dentry, inode);
585

L
Linus Torvalds 已提交
586 587 588
	return 0;
}

589 590
static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
		     dev_t rdev)
L
Linus Torvalds 已提交
591
{
592
	struct inode *inode;
L
Linus Torvalds 已提交
593 594 595
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
596
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
597 598 599 600 601 602 603 604 605 606

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

	lock_kernel();
	err = -EIO;
	inode = udf_new_inode(dir, mode, &err);
	if (!inode)
		goto out;

607
	iinfo = UDF_I(inode);
L
Linus Torvalds 已提交
608 609
	inode->i_uid = current->fsuid;
	init_special_inode(inode, mode, rdev);
M
Marcin Slusarz 已提交
610 611
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
612
		inode->i_nlink--;
L
Linus Torvalds 已提交
613 614 615 616 617 618
		mark_inode_dirty(inode);
		iput(inode);
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
619
	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
620
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
621
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
622
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
623
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
624 625 626 627
		mark_inode_dirty(dir);
	mark_inode_dirty(inode);

	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
628 629
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
630 631
	d_instantiate(dentry, inode);
	err = 0;
632 633

out:
L
Linus Torvalds 已提交
634 635 636 637
	unlock_kernel();
	return err;
}

638
static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
L
Linus Torvalds 已提交
639
{
640
	struct inode *inode;
L
Linus Torvalds 已提交
641 642 643
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
644 645
	struct udf_inode_info *dinfo = UDF_I(dir);
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
646 647 648

	lock_kernel();
	err = -EMLINK;
649
	if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
650 651 652 653 654 655 656
		goto out;

	err = -EIO;
	inode = udf_new_inode(dir, S_IFDIR, &err);
	if (!inode)
		goto out;

657
	iinfo = UDF_I(inode);
L
Linus Torvalds 已提交
658 659
	inode->i_op = &udf_dir_inode_operations;
	inode->i_fop = &udf_dir_operations;
M
Marcin Slusarz 已提交
660 661
	fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
662 663 664 665 666 667 668
		inode->i_nlink--;
		mark_inode_dirty(inode);
		iput(inode);
		goto out;
	}
	inode->i_nlink = 2;
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
669
	cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
670
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
671
		cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
M
Marcin Slusarz 已提交
672 673
	cfi.fileCharacteristics =
			FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
L
Linus Torvalds 已提交
674
	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
J
Jan Kara 已提交
675
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
676 677 678 679 680
	inode->i_mode = S_IFDIR | mode;
	if (dir->i_mode & S_ISGID)
		inode->i_mode |= S_ISGID;
	mark_inode_dirty(inode);

M
Marcin Slusarz 已提交
681 682
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
683 684 685 686 687 688
		inode->i_nlink = 0;
		mark_inode_dirty(inode);
		iput(inode);
		goto out;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
689
	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
690
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
691
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
692 693
	cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
694
	inc_nlink(dir);
L
Linus Torvalds 已提交
695 696 697
	mark_inode_dirty(dir);
	d_instantiate(dentry, inode);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
698 699
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
700
	err = 0;
701 702

out:
L
Linus Torvalds 已提交
703 704 705 706 707 708 709 710 711
	unlock_kernel();
	return err;
}

static int empty_dir(struct inode *dir)
{
	struct fileIdentDesc *fi, cfi;
	struct udf_fileident_bh fibh;
	loff_t f_pos;
712
	loff_t size = udf_ext0_offset(dir) + dir->i_size;
L
Linus Torvalds 已提交
713
	int block;
J
Jan Kara 已提交
714 715
	kernel_lb_addr eloc;
	uint32_t elen;
716
	sector_t offset;
717
	struct extent_position epos = {};
718
	struct udf_inode_info *dinfo = UDF_I(dir);
L
Linus Torvalds 已提交
719

720 721
	f_pos = udf_ext0_offset(dir);
	fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
L
Linus Torvalds 已提交
722

723
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
724
		fibh.sbh = fibh.ebh = NULL;
725
	else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
M
Marcin Slusarz 已提交
726 727
			      &epos, &eloc, &elen, &offset) ==
					(EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
728
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
729
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
730
			if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
731
				epos.offset -= sizeof(short_ad);
732
			else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
733
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
734
		} else
L
Linus Torvalds 已提交
735 736
			offset = 0;

M
Marcin Slusarz 已提交
737 738
		fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
		if (!fibh.sbh) {
J
Jan Kara 已提交
739
			brelse(epos.bh);
L
Linus Torvalds 已提交
740 741
			return 0;
		}
742
	} else {
J
Jan Kara 已提交
743
		brelse(epos.bh);
L
Linus Torvalds 已提交
744 745 746
		return 0;
	}

747
	while (f_pos < size) {
748 749 750
		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
					&elen, &offset);
		if (!fi) {
L
Linus Torvalds 已提交
751
			if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
752 753 754
				brelse(fibh.ebh);
			brelse(fibh.sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
755 756 757
			return 0;
		}

758 759
		if (cfi.lengthFileIdent &&
		    (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
L
Linus Torvalds 已提交
760
			if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
761 762 763
				brelse(fibh.ebh);
			brelse(fibh.sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
764 765 766
			return 0;
		}
	}
767

L
Linus Torvalds 已提交
768
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
769 770 771
		brelse(fibh.ebh);
	brelse(fibh.sbh);
	brelse(epos.bh);
772

L
Linus Torvalds 已提交
773 774 775
	return 1;
}

776
static int udf_rmdir(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
777 778
{
	int retval;
779
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801
	struct udf_fileident_bh fibh;
	struct fileIdentDesc *fi, cfi;
	kernel_lb_addr tloc;

	retval = -ENOENT;
	lock_kernel();
	fi = udf_find_entry(dir, dentry, &fibh, &cfi);
	if (!fi)
		goto out;

	retval = -EIO;
	tloc = lelb_to_cpu(cfi.icb.extLocation);
	if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
		goto end_rmdir;
	retval = -ENOTEMPTY;
	if (!empty_dir(inode))
		goto end_rmdir;
	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
	if (retval)
		goto end_rmdir;
	if (inode->i_nlink != 2)
		udf_warning(inode->i_sb, "udf_rmdir",
802 803
			    "empty directory has nlink != 2 (%d)",
			    inode->i_nlink);
804
	clear_nlink(inode);
L
Linus Torvalds 已提交
805
	inode->i_size = 0;
806
	inode_dec_link_count(dir);
M
Marcin Slusarz 已提交
807 808
	inode->i_ctime = dir->i_ctime = dir->i_mtime =
						current_fs_time(dir->i_sb);
L
Linus Torvalds 已提交
809 810
	mark_inode_dirty(dir);

811
end_rmdir:
L
Linus Torvalds 已提交
812
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
813 814
		brelse(fibh.ebh);
	brelse(fibh.sbh);
815 816

out:
L
Linus Torvalds 已提交
817 818 819 820
	unlock_kernel();
	return retval;
}

821
static int udf_unlink(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
822 823
{
	int retval;
824
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
	struct udf_fileident_bh fibh;
	struct fileIdentDesc *fi;
	struct fileIdentDesc cfi;
	kernel_lb_addr tloc;

	retval = -ENOENT;
	lock_kernel();
	fi = udf_find_entry(dir, dentry, &fibh, &cfi);
	if (!fi)
		goto out;

	retval = -EIO;
	tloc = lelb_to_cpu(cfi.icb.extLocation);
	if (udf_get_lb_pblock(dir->i_sb, tloc, 0) != inode->i_ino)
		goto end_unlink;

841
	if (!inode->i_nlink) {
L
Linus Torvalds 已提交
842
		udf_debug("Deleting nonexistent file (%lu), %d\n",
843
			  inode->i_ino, inode->i_nlink);
L
Linus Torvalds 已提交
844 845 846 847 848 849 850
		inode->i_nlink = 1;
	}
	retval = udf_delete_entry(dir, fi, &fibh, &cfi);
	if (retval)
		goto end_unlink;
	dir->i_ctime = dir->i_mtime = current_fs_time(dir->i_sb);
	mark_inode_dirty(dir);
851
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
852 853 854
	inode->i_ctime = dir->i_ctime;
	retval = 0;

855
end_unlink:
L
Linus Torvalds 已提交
856
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
857 858
		brelse(fibh.ebh);
	brelse(fibh.sbh);
859 860

out:
L
Linus Torvalds 已提交
861 862 863 864
	unlock_kernel();
	return retval;
}

865 866
static int udf_symlink(struct inode *dir, struct dentry *dentry,
		       const char *symname)
L
Linus Torvalds 已提交
867
{
868
	struct inode *inode;
L
Linus Torvalds 已提交
869 870 871
	struct pathComponent *pc;
	char *compstart;
	struct udf_fileident_bh fibh;
872
	struct extent_position epos = {};
L
Linus Torvalds 已提交
873 874 875 876 877 878
	int eoffset, elen = 0;
	struct fileIdentDesc *fi;
	struct fileIdentDesc cfi;
	char *ea;
	int err;
	int block;
879
	char *name = NULL;
L
Linus Torvalds 已提交
880
	int namelen;
M
Marcin Slusarz 已提交
881
	struct buffer_head *bh;
882
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
883 884

	lock_kernel();
M
Marcin Slusarz 已提交
885 886
	inode = udf_new_inode(dir, S_IFLNK, &err);
	if (!inode)
L
Linus Torvalds 已提交
887 888
		goto out;

889 890 891 892 893 894
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!name) {
		err = -ENOMEM;
		goto out_no_entry;
	}

895
	iinfo = UDF_I(inode);
L
Linus Torvalds 已提交
896 897 898 899
	inode->i_mode = S_IFLNK | S_IRWXUGO;
	inode->i_data.a_ops = &udf_symlink_aops;
	inode->i_op = &page_symlink_inode_operations;

900
	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
J
Jan Kara 已提交
901
		kernel_lb_addr eloc;
902
		uint32_t bsize;
L
Linus Torvalds 已提交
903 904

		block = udf_new_block(inode->i_sb, inode,
905 906
				iinfo->i_location.partitionReferenceNum,
				iinfo->i_location.logicalBlockNum, &err);
L
Linus Torvalds 已提交
907 908
		if (!block)
			goto out_no_entry;
909
		epos.block = iinfo->i_location;
J
Jan Kara 已提交
910 911
		epos.offset = udf_file_entry_alloc_offset(inode);
		epos.bh = NULL;
L
Linus Torvalds 已提交
912
		eloc.logicalBlockNum = block;
M
Marcin Slusarz 已提交
913
		eloc.partitionReferenceNum =
914
				iinfo->i_location.partitionReferenceNum;
915 916 917
		bsize = inode->i_sb->s_blocksize;
		iinfo->i_lenExtents = bsize;
		udf_add_aext(inode, &epos, eloc, bsize, 0);
J
Jan Kara 已提交
918
		brelse(epos.bh);
L
Linus Torvalds 已提交
919 920

		block = udf_get_pblock(inode->i_sb, block,
921
				iinfo->i_location.partitionReferenceNum,
M
Marcin Slusarz 已提交
922
				0);
J
Jan Kara 已提交
923 924 925 926 927 928 929
		epos.bh = udf_tread(inode->i_sb, block);
		lock_buffer(epos.bh);
		memset(epos.bh->b_data, 0x00, inode->i_sb->s_blocksize);
		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);
930 931
	} else
		ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
L
Linus Torvalds 已提交
932 933 934 935

	eoffset = inode->i_sb->s_blocksize - udf_ext0_offset(inode);
	pc = (struct pathComponent *)ea;

936 937
	if (*symname == '/') {
		do {
L
Linus Torvalds 已提交
938 939 940 941 942 943 944 945 946 947 948 949
			symname++;
		} while (*symname == '/');

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

	err = -ENAMETOOLONG;

950
	while (*symname) {
L
Linus Torvalds 已提交
951 952 953 954 955 956 957
		if (elen + sizeof(struct pathComponent) > eoffset)
			goto out_no_entry;

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

		compstart = (char *)symname;

958
		do {
L
Linus Torvalds 已提交
959 960 961 962 963 964
			symname++;
		} while (*symname && *symname != '/');

		pc->componentType = 5;
		pc->lengthComponentIdent = 0;
		pc->componentFileVersionNum = 0;
965 966
		if (compstart[0] == '.') {
			if ((symname - compstart) == 1)
L
Linus Torvalds 已提交
967
				pc->componentType = 4;
M
Marcin Slusarz 已提交
968 969
			else if ((symname - compstart) == 2 &&
					compstart[1] == '.')
L
Linus Torvalds 已提交
970 971 972
				pc->componentType = 3;
		}

973
		if (pc->componentType == 5) {
974 975 976
			namelen = udf_put_filename(inode->i_sb, compstart, name,
						   symname - compstart);
			if (!namelen)
L
Linus Torvalds 已提交
977 978
				goto out_no_entry;

M
Marcin Slusarz 已提交
979 980
			if (elen + sizeof(struct pathComponent) + namelen >
					eoffset)
L
Linus Torvalds 已提交
981 982 983 984 985 986 987 988 989
				goto out_no_entry;
			else
				pc->lengthComponentIdent = namelen;

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

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

990 991
		if (*symname) {
			do {
L
Linus Torvalds 已提交
992 993 994 995 996
				symname++;
			} while (*symname == '/');
		}
	}

J
Jan Kara 已提交
997
	brelse(epos.bh);
L
Linus Torvalds 已提交
998
	inode->i_size = elen;
999 1000
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		iinfo->i_lenAlloc = inode->i_size;
L
Linus Torvalds 已提交
1001 1002
	mark_inode_dirty(inode);

M
Marcin Slusarz 已提交
1003 1004
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi)
L
Linus Torvalds 已提交
1005 1006
		goto out_no_entry;
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
1007
	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
M
Marcin Slusarz 已提交
1008 1009
	bh = UDF_SB(inode->i_sb)->s_lvid_bh;
	if (bh) {
M
Marcin Slusarz 已提交
1010 1011
		struct logicalVolIntegrityDesc *lvid =
				(struct logicalVolIntegrityDesc *)bh->b_data;
L
Linus Torvalds 已提交
1012 1013
		struct logicalVolHeaderDesc *lvhd;
		uint64_t uniqueID;
M
Marcin Slusarz 已提交
1014 1015
		lvhd = (struct logicalVolHeaderDesc *)
				lvid->logicalVolContentsUse;
L
Linus Torvalds 已提交
1016
		uniqueID = le64_to_cpu(lvhd->uniqueID);
1017 1018
		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
1019 1020 1021
		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
			uniqueID += 16;
		lvhd->uniqueID = cpu_to_le64(uniqueID);
M
Marcin Slusarz 已提交
1022
		mark_buffer_dirty(bh);
L
Linus Torvalds 已提交
1023 1024
	}
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
1025
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1026 1027
		mark_inode_dirty(dir);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
1028 1029
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
1030 1031 1032
	d_instantiate(dentry, inode);
	err = 0;

1033
out:
1034
	kfree(name);
L
Linus Torvalds 已提交
1035 1036 1037
	unlock_kernel();
	return err;

1038
out_no_entry:
1039
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
1040 1041 1042 1043
	iput(inode);
	goto out;
}

1044 1045
static int udf_link(struct dentry *old_dentry, struct inode *dir,
		    struct dentry *dentry)
L
Linus Torvalds 已提交
1046 1047 1048 1049 1050
{
	struct inode *inode = old_dentry->d_inode;
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
M
Marcin Slusarz 已提交
1051
	struct buffer_head *bh;
L
Linus Torvalds 已提交
1052 1053

	lock_kernel();
1054
	if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
L
Linus Torvalds 已提交
1055 1056 1057 1058
		unlock_kernel();
		return -EMLINK;
	}

M
Marcin Slusarz 已提交
1059 1060
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
1061 1062 1063 1064
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
1065
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
M
Marcin Slusarz 已提交
1066 1067
	bh = UDF_SB(inode->i_sb)->s_lvid_bh;
	if (bh) {
M
Marcin Slusarz 已提交
1068 1069
		struct logicalVolIntegrityDesc *lvid =
				(struct logicalVolIntegrityDesc *)bh->b_data;
L
Linus Torvalds 已提交
1070 1071
		struct logicalVolHeaderDesc *lvhd;
		uint64_t uniqueID;
M
Marcin Slusarz 已提交
1072 1073
		lvhd = (struct logicalVolHeaderDesc *)
				(lvid->logicalVolContentsUse);
L
Linus Torvalds 已提交
1074
		uniqueID = le64_to_cpu(lvhd->uniqueID);
1075 1076
		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
1077 1078 1079
		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
			uniqueID += 16;
		lvhd->uniqueID = cpu_to_le64(uniqueID);
M
Marcin Slusarz 已提交
1080
		mark_buffer_dirty(bh);
L
Linus Torvalds 已提交
1081 1082
	}
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
1083
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1084
		mark_inode_dirty(dir);
1085

L
Linus Torvalds 已提交
1086
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
1087 1088
		brelse(fibh.ebh);
	brelse(fibh.sbh);
1089
	inc_nlink(inode);
L
Linus Torvalds 已提交
1090 1091 1092 1093 1094
	inode->i_ctime = current_fs_time(inode->i_sb);
	mark_inode_dirty(inode);
	atomic_inc(&inode->i_count);
	d_instantiate(dentry, inode);
	unlock_kernel();
1095

L
Linus Torvalds 已提交
1096 1097 1098 1099 1100 1101
	return 0;
}

/* Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
1102 1103
static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry)
L
Linus Torvalds 已提交
1104
{
1105 1106
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
L
Linus Torvalds 已提交
1107
	struct udf_fileident_bh ofibh, nfibh;
M
Marcin Slusarz 已提交
1108 1109
	struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL;
	struct fileIdentDesc ocfi, ncfi;
L
Linus Torvalds 已提交
1110 1111 1112
	struct buffer_head *dir_bh = NULL;
	int retval = -ENOENT;
	kernel_lb_addr tloc;
1113
	struct udf_inode_info *old_iinfo = UDF_I(old_inode);
L
Linus Torvalds 已提交
1114 1115

	lock_kernel();
M
Marcin Slusarz 已提交
1116 1117
	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
	if (ofi) {
L
Linus Torvalds 已提交
1118
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1119 1120
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1121 1122 1123
	}
	tloc = lelb_to_cpu(ocfi.icb.extLocation);
	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
1124
	    != old_inode->i_ino)
L
Linus Torvalds 已提交
1125 1126 1127
		goto end_rename;

	nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
1128 1129
	if (nfi) {
		if (!new_inode) {
L
Linus Torvalds 已提交
1130
			if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1131 1132
				brelse(nfibh.ebh);
			brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1133 1134 1135
			nfi = NULL;
		}
	}
1136
	if (S_ISDIR(old_inode->i_mode)) {
M
Marcin Slusarz 已提交
1137
		int offset = udf_ext0_offset(old_inode);
L
Linus Torvalds 已提交
1138

1139
		if (new_inode) {
L
Linus Torvalds 已提交
1140 1141 1142 1143 1144
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
		}
		retval = -EIO;
1145
		if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
M
Marcin Slusarz 已提交
1146
			dir_fi = udf_get_fileident(
1147 1148
					old_iinfo->i_ext.i_data -
					  (old_iinfo->i_efe ?
M
Marcin Slusarz 已提交
1149 1150 1151
					   sizeof(struct extendedFileEntry) :
					   sizeof(struct fileEntry)),
					old_inode->i_sb->s_blocksize, &offset);
1152
		} else {
L
Linus Torvalds 已提交
1153 1154 1155
			dir_bh = udf_bread(old_inode, 0, 0, &retval);
			if (!dir_bh)
				goto end_rename;
M
Marcin Slusarz 已提交
1156 1157
			dir_fi = udf_get_fileident(dir_bh->b_data,
					old_inode->i_sb->s_blocksize, &offset);
L
Linus Torvalds 已提交
1158 1159 1160 1161
		}
		if (!dir_fi)
			goto end_rename;
		tloc = lelb_to_cpu(dir_fi->icb.extLocation);
M
Marcin Slusarz 已提交
1162 1163
		if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) !=
				old_dir->i_ino)
L
Linus Torvalds 已提交
1164 1165 1166
			goto end_rename;

		retval = -EMLINK;
M
Marcin Slusarz 已提交
1167 1168 1169
		if (!new_inode &&
			new_dir->i_nlink >=
				(256 << sizeof(new_dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
1170 1171
			goto end_rename;
	}
1172
	if (!nfi) {
M
Marcin Slusarz 已提交
1173 1174
		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
				    &retval);
L
Linus Torvalds 已提交
1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
		if (!nfi)
			goto end_rename;
	}

	/*
	 * Like most other Unix systems, set the ctime for inodes on a
	 * rename.
	 */
	old_inode->i_ctime = current_fs_time(old_inode->i_sb);
	mark_inode_dirty(old_inode);

	/*
	 * ok, that's it
	 */
	ncfi.fileVersionNum = ocfi.fileVersionNum;
	ncfi.fileCharacteristics = ocfi.fileCharacteristics;
	memcpy(&(ncfi.icb), &(ocfi.icb), sizeof(long_ad));
	udf_write_fi(new_dir, &ncfi, nfi, &nfibh, NULL, NULL);

	/* The old fid may have moved - find it again */
	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
	udf_delete_entry(old_dir, ofi, &ofibh, &ocfi);

1198
	if (new_inode) {
L
Linus Torvalds 已提交
1199
		new_inode->i_ctime = current_fs_time(new_inode->i_sb);
1200
		inode_dec_link_count(new_inode);
L
Linus Torvalds 已提交
1201 1202 1203 1204
	}
	old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
	mark_inode_dirty(old_dir);

1205
	if (dir_fi) {
1206
		dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
M
Marcin Slusarz 已提交
1207 1208 1209
		udf_update_tag((char *)dir_fi,
				(sizeof(struct fileIdentDesc) +
				le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
1210
		if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1211
			mark_inode_dirty(old_inode);
M
Marcin Slusarz 已提交
1212
		else
L
Linus Torvalds 已提交
1213
			mark_buffer_dirty_inode(dir_bh, old_inode);
M
Marcin Slusarz 已提交
1214

1215
		inode_dec_link_count(old_dir);
M
Marcin Slusarz 已提交
1216
		if (new_inode)
1217
			inode_dec_link_count(new_inode);
M
Marcin Slusarz 已提交
1218
		else {
1219
			inc_nlink(new_dir);
L
Linus Torvalds 已提交
1220 1221 1222 1223
			mark_inode_dirty(new_dir);
		}
	}

1224
	if (ofi) {
L
Linus Torvalds 已提交
1225
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1226 1227
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1228 1229 1230 1231
	}

	retval = 0;

1232
end_rename:
J
Jan Kara 已提交
1233
	brelse(dir_bh);
1234
	if (nfi) {
L
Linus Torvalds 已提交
1235
		if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1236 1237
			brelse(nfibh.ebh);
		brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1238 1239
	}
	unlock_kernel();
1240

L
Linus Torvalds 已提交
1241 1242 1243
	return retval;
}

R
Rasmus Rohde 已提交
1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255 1256 1257 1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305 1306 1307 1308 1309 1310 1311 1312 1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371
static struct dentry *udf_get_parent(struct dentry *child)
{
	struct dentry *parent;
	struct inode *inode = NULL;
	struct dentry dotdot;
	struct fileIdentDesc cfi;
	struct udf_fileident_bh fibh;

	dotdot.d_name.name = "..";
	dotdot.d_name.len = 2;

	lock_kernel();
	if (!udf_find_entry(child->d_inode, &dotdot, &fibh, &cfi))
		goto out_unlock;

	if (fibh.sbh != fibh.ebh)
		brelse(fibh.ebh);
	brelse(fibh.sbh);

	inode = udf_iget(child->d_inode->i_sb,
			 lelb_to_cpu(cfi.icb.extLocation));
	if (!inode)
		goto out_unlock;
	unlock_kernel();

	parent = d_alloc_anon(inode);
	if (!parent) {
		iput(inode);
		parent = ERR_PTR(-ENOMEM);
	}

	return parent;
out_unlock:
	unlock_kernel();
	return ERR_PTR(-EACCES);
}


static struct dentry *udf_nfs_get_inode(struct super_block *sb, u32 block,
					u16 partref, __u32 generation)
{
	struct inode *inode;
	struct dentry *result;
	kernel_lb_addr loc;

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

	loc.logicalBlockNum = block;
	loc.partitionReferenceNum = partref;
	inode = udf_iget(sb, loc);

	if (inode == NULL)
		return ERR_PTR(-ENOMEM);

	if (generation && inode->i_generation != generation) {
		iput(inode);
		return ERR_PTR(-ESTALE);
	}
	result = d_alloc_anon(inode);
	if (!result) {
		iput(inode);
		return ERR_PTR(-ENOMEM);
	}
	return result;
}

static struct dentry *udf_fh_to_dentry(struct super_block *sb,
				       struct fid *fid, int fh_len, int fh_type)
{
	if ((fh_len != 3 && fh_len != 5) ||
	    (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)
{
	if (fh_len != 5 || fh_type != FILEID_UDF_WITH_PARENT)
		return NULL;

	return udf_nfs_get_inode(sb, fid->udf.parent_block,
				 fid->udf.parent_partref,
				 fid->udf.parent_generation);
}
static int udf_encode_fh(struct dentry *de, __u32 *fh, int *lenp,
			 int connectable)
{
	int len = *lenp;
	struct inode *inode =  de->d_inode;
	kernel_lb_addr location = UDF_I(inode)->i_location;
	struct fid *fid = (struct fid *)fh;
	int type = FILEID_UDF_WITHOUT_PARENT;

	if (len < 3 || (connectable && len < 5))
		return 255;

	*lenp = 3;
	fid->udf.block = location.logicalBlockNum;
	fid->udf.partref = location.partitionReferenceNum;
	fid->udf.generation = inode->i_generation;

	if (connectable && !S_ISDIR(inode->i_mode)) {
		spin_lock(&de->d_lock);
		inode = de->d_parent->d_inode;
		location = UDF_I(inode)->i_location;
		fid->udf.parent_block = location.logicalBlockNum;
		fid->udf.parent_partref = location.partitionReferenceNum;
		fid->udf.parent_generation = inode->i_generation;
		spin_unlock(&de->d_lock);
		*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,
};

1372
const struct inode_operations udf_dir_inode_operations = {
1373 1374 1375 1376 1377 1378 1379 1380 1381
	.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,
L
Linus Torvalds 已提交
1382
};