namei.c 32.8 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>
L
Linus Torvalds 已提交
34

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

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

int udf_write_fi(struct inode *inode, struct fileIdentDesc *cfi,
45
		 struct fileIdentDesc *sfi, struct udf_fileident_bh *fibh,
M
Marcin Slusarz 已提交
46
		 uint8_t *impuse, uint8_t *fileident)
L
Linus Torvalds 已提交
47 48 49 50 51 52 53
{
	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 -
54
		sizeof(struct fileIdentDesc);
L
Linus Torvalds 已提交
55 56
	int adinicb = 0;

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

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

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

	offset += liu;

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

	offset += lfi;

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

100 101 102 103 104
	crc = udf_crc((uint8_t *)cfi + sizeof(tag),
		      sizeof(struct fileIdentDesc) - sizeof(tag), 0);

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

	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 152 153 154 155
	loff_t f_pos;
	int block, flen;
	char fname[UDF_NAME_LEN];
	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 = {};
L
Linus Torvalds 已提交
161

162
	size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
L
Linus Torvalds 已提交
163 164
	f_pos = (udf_ext0_offset(dir) >> 2);

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

M
Marcin Slusarz 已提交
182 183
		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
		if (!fibh->sbh) {
J
Jan Kara 已提交
184
			brelse(epos.bh);
L
Linus Torvalds 已提交
185 186
			return NULL;
		}
187
	} else {
J
Jan Kara 已提交
188
		brelse(epos.bh);
L
Linus Torvalds 已提交
189 190 191
		return NULL;
	}

192 193 194 195
	while ((f_pos < size)) {
		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
					&elen, &offset);
		if (!fi) {
L
Linus Torvalds 已提交
196
			if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
197 198 199
				brelse(fibh->ebh);
			brelse(fibh->sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
200 201 202 203 204 205
			return NULL;
		}

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

206
		if (fibh->sbh == fibh->ebh) {
L
Linus Torvalds 已提交
207
			nameptr = fi->fileIdent + liu;
208
		} else {
L
Linus Torvalds 已提交
209 210
			int poffset;	/* Unpaded ending offset */

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

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

226 227
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
			if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNDELETE))
L
Linus Torvalds 已提交
228 229
				continue;
		}
230 231 232

		if ((cfi->fileCharacteristics & FID_FILE_CHAR_HIDDEN) != 0) {
			if (!UDF_QUERY_FLAG(dir->i_sb, UDF_FLAG_UNHIDE))
L
Linus Torvalds 已提交
233 234 235 236 237 238
				continue;
		}

		if (!lfi)
			continue;

M
Marcin Slusarz 已提交
239 240 241 242 243
		flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
		if (flen && udf_match(flen, fname, dentry->d_name.len,
				      dentry->d_name.name)) {
			brelse(epos.bh);
			return fi;
L
Linus Torvalds 已提交
244 245
		}
	}
246

L
Linus Torvalds 已提交
247
	if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
248 249 250
		brelse(fibh->ebh);
	brelse(fibh->sbh);
	brelse(epos.bh);
251

L
Linus Torvalds 已提交
252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287
	return NULL;
}

/*
 * udf_lookup
 *
 * PURPOSE
 *	Look-up the inode for a given name.
 *
 * DESCRIPTION
 *	Required - lookup_dentry() will return -ENOTDIR if this routine is not
 *	available for a directory. The filesystem is useless if this routine is
 *	not available for at least the filesystem's root directory.
 *
 *	This routine is passed an incomplete dentry - it must be completed by
 *	calling d_add(dentry, inode). If the name does not exist, then the
 *	specified inode must be set to null. An error should only be returned
 *	when the lookup fails for a reason other than the name not existing.
 *	Note that the directory inode semaphore is held during the call.
 *
 *	Refer to lookup_dentry() in fs/namei.c
 *	lookup_dentry() -> lookup() -> real_lookup() -> .
 *
 * PRE-CONDITIONS
 *	dir			Pointer to inode of parent directory.
 *	dentry			Pointer to dentry to complete.
 *	nd			Pointer to lookup nameidata
 *
 * POST-CONDITIONS
 *	<return>		Zero on success.
 *
 * HISTORY
 *	July 1, 1997 - Andrew E. Mileski
 *	Written, tested, and released.
 */

288 289
static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
				 struct nameidata *nd)
L
Linus Torvalds 已提交
290 291
{
	struct inode *inode = NULL;
292
	struct fileIdentDesc cfi;
L
Linus Torvalds 已提交
293 294
	struct udf_fileident_bh fibh;

295
	if (dentry->d_name.len > UDF_NAME_LEN - 2)
L
Linus Torvalds 已提交
296 297 298 299 300
		return ERR_PTR(-ENAMETOOLONG);

	lock_kernel();
#ifdef UDF_RECOVERY
	/* temporary shorthand for specifying files by inode number */
301
	if (!strncmp(dentry->d_name.name, ".B=", 3)) {
302 303
		kernel_lb_addr lb = {
			.logicalBlockNum = 0,
M
Marcin Slusarz 已提交
304 305 306
			.partitionReferenceNum =
				simple_strtoul(dentry->d_name.name + 3,
						NULL, 0),
307
		};
L
Linus Torvalds 已提交
308
		inode = udf_iget(dir->i_sb, lb);
309
		if (!inode) {
L
Linus Torvalds 已提交
310 311 312
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
M
Marcin Slusarz 已提交
313
	} else
314
#endif /* UDF_RECOVERY */
L
Linus Torvalds 已提交
315

316
	if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
L
Linus Torvalds 已提交
317
		if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
318 319
			brelse(fibh.ebh);
		brelse(fibh.sbh);
L
Linus Torvalds 已提交
320 321

		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
322
		if (!inode) {
L
Linus Torvalds 已提交
323 324 325 326 327 328
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
	}
	unlock_kernel();
	d_add(dentry, inode);
329

L
Linus Torvalds 已提交
330 331 332
	return NULL;
}

333 334 335 336
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 已提交
337
{
M
Marcin Slusarz 已提交
338
	struct super_block *sb = dir->i_sb;
339
	struct fileIdentDesc *fi = NULL;
L
Linus Torvalds 已提交
340 341 342 343 344 345 346 347 348 349
	char name[UDF_NAME_LEN], fname[UDF_NAME_LEN];
	int namelen;
	loff_t f_pos;
	int flen;
	char *nameptr;
	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
	int nfidlen;
	uint8_t lfi;
	uint16_t liu;
	int block;
J
Jan Kara 已提交
350 351
	kernel_lb_addr eloc;
	uint32_t elen;
352
	sector_t offset;
353
	struct extent_position epos = {};
L
Linus Torvalds 已提交
354

355 356
	if (dentry) {
		if (!dentry->d_name.len) {
L
Linus Torvalds 已提交
357 358 359
			*err = -EINVAL;
			return NULL;
		}
M
Marcin Slusarz 已提交
360 361 362
		namelen = udf_put_filename(sb, dentry->d_name.name, name,
						 dentry->d_name.len);
		if (!namelen) {
L
Linus Torvalds 已提交
363 364 365
			*err = -ENAMETOOLONG;
			return NULL;
		}
366
	} else {
L
Linus Torvalds 已提交
367
		namelen = 0;
368
	}
L
Linus Torvalds 已提交
369 370 371 372 373

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

	f_pos = (udf_ext0_offset(dir) >> 2);

M
Marcin Slusarz 已提交
374 375
	fibh->soffset = fibh->eoffset =
			(f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
376
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
377
		fibh->sbh = fibh->ebh = NULL;
M
Marcin Slusarz 已提交
378 379 380
	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
			      &epos, &eloc, &elen, &offset) ==
					(EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
381
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
382
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
383
			if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
384
				epos.offset -= sizeof(short_ad);
385 386
			else if (UDF_I(dir)->i_alloc_type ==
							ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
387
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
388
		} else
L
Linus Torvalds 已提交
389 390
			offset = 0;

M
Marcin Slusarz 已提交
391 392
		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
		if (!fibh->sbh) {
J
Jan Kara 已提交
393
			brelse(epos.bh);
L
Linus Torvalds 已提交
394 395 396 397
			*err = -EIO;
			return NULL;
		}

398
		block = UDF_I(dir)->i_location.logicalBlockNum;
L
Linus Torvalds 已提交
399

400
	} else {
401
		block = udf_get_lb_pblock(dir->i_sb, UDF_I(dir)->i_location, 0);
L
Linus Torvalds 已提交
402 403 404 405 406
		fibh->sbh = fibh->ebh = NULL;
		fibh->soffset = fibh->eoffset = sb->s_blocksize;
		goto add;
	}

407 408 409
	while ((f_pos < size)) {
		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
					&elen, &offset);
L
Linus Torvalds 已提交
410

411
		if (!fi) {
L
Linus Torvalds 已提交
412
			if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
413 414 415
				brelse(fibh->ebh);
			brelse(fibh->sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
416 417 418 419 420 421 422
			*err = -EIO;
			return NULL;
		}

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

M
Marcin Slusarz 已提交
423
		if (fibh->sbh == fibh->ebh)
L
Linus Torvalds 已提交
424
			nameptr = fi->fileIdent + liu;
M
Marcin Slusarz 已提交
425
		else {
L
Linus Torvalds 已提交
426 427
			int poffset;	/* Unpaded ending offset */

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

M
Marcin Slusarz 已提交
431 432 433 434
			if (poffset >= lfi)
				nameptr = (char *)(fibh->ebh->b_data +
						   poffset - lfi);
			else {
L
Linus Torvalds 已提交
435
				nameptr = fname;
M
Marcin Slusarz 已提交
436 437 438 439
				memcpy(nameptr, fi->fileIdent + liu,
					lfi - poffset);
				memcpy(nameptr + lfi - poffset,
					fibh->ebh->b_data, poffset);
L
Linus Torvalds 已提交
440 441 442
			}
		}

443
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
M
Marcin Slusarz 已提交
444 445
			if (((sizeof(struct fileIdentDesc) +
					liu + lfi + 3) & ~3) == nfidlen) {
J
Jan Kara 已提交
446
				brelse(epos.bh);
L
Linus Torvalds 已提交
447 448 449 450 451
				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 已提交
452 453
				if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
						  name))
L
Linus Torvalds 已提交
454
					return fi;
M
Marcin Slusarz 已提交
455
				else {
L
Linus Torvalds 已提交
456 457 458 459 460 461 462 463 464
					*err = -EIO;
					return NULL;
				}
			}
		}

		if (!lfi || !dentry)
			continue;

M
Marcin Slusarz 已提交
465 466 467
		flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
		if (flen && udf_match(flen, fname, dentry->d_name.len,
				      dentry->d_name.name)) {
L
Linus Torvalds 已提交
468
			if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
469 470 471
				brelse(fibh->ebh);
			brelse(fibh->sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
472 473 474 475 476
			*err = -EEXIST;
			return NULL;
		}
	}

477
add:
L
Linus Torvalds 已提交
478 479
	f_pos += nfidlen;

480
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB &&
481
	    sb->s_blocksize - fibh->eoffset < nfidlen) {
J
Jan Kara 已提交
482
		brelse(epos.bh);
J
Jan Kara 已提交
483
		epos.bh = NULL;
L
Linus Torvalds 已提交
484 485 486 487
		fibh->soffset -= udf_ext0_offset(dir);
		fibh->eoffset -= udf_ext0_offset(dir);
		f_pos -= (udf_ext0_offset(dir) >> 2);
		if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
488 489
			brelse(fibh->ebh);
		brelse(fibh->sbh);
M
Marcin Slusarz 已提交
490 491 492
		fibh->sbh = fibh->ebh =
				udf_expand_dir_adinicb(dir, &block, err);
		if (!fibh->sbh)
L
Linus Torvalds 已提交
493
			return NULL;
494
		epos.block = UDF_I(dir)->i_location;
L
Linus Torvalds 已提交
495
		eloc.logicalBlockNum = block;
M
Marcin Slusarz 已提交
496
		eloc.partitionReferenceNum =
497
				UDF_I(dir)->i_location.partitionReferenceNum;
L
Linus Torvalds 已提交
498
		elen = dir->i_sb->s_blocksize;
J
Jan Kara 已提交
499
		epos.offset = udf_file_entry_alloc_offset(dir);
500
		if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
501
			epos.offset += sizeof(short_ad);
502
		else if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
503
			epos.offset += sizeof(long_ad);
L
Linus Torvalds 已提交
504 505
	}

506
	if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
L
Linus Torvalds 已提交
507 508
		fibh->soffset = fibh->eoffset;
		fibh->eoffset += nfidlen;
509
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
510
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
511 512 513
			fibh->sbh = fibh->ebh;
		}

514 515
		if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			block = UDF_I(dir)->i_location.logicalBlockNum;
M
Marcin Slusarz 已提交
516
			fi = (struct fileIdentDesc *)
517 518
					(UDF_I(dir)->i_ext.i_data +
					 fibh->soffset -
M
Marcin Slusarz 已提交
519
					 udf_ext0_offset(dir) +
520
					 UDF_I(dir)->i_lenEAttr);
521
		} else {
M
Marcin Slusarz 已提交
522 523 524 525 526
			block = eloc.logicalBlockNum +
					((elen - 1) >>
						dir->i_sb->s_blocksize_bits);
			fi = (struct fileIdentDesc *)
				(fibh->sbh->b_data + fibh->soffset);
L
Linus Torvalds 已提交
527
		}
528
	} else {
L
Linus Torvalds 已提交
529 530
		fibh->soffset = fibh->eoffset - sb->s_blocksize;
		fibh->eoffset += nfidlen - sb->s_blocksize;
531
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
532
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
533 534 535 536
			fibh->sbh = fibh->ebh;
		}

		block = eloc.logicalBlockNum + ((elen - 1) >>
537
						dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
538 539 540
		fibh->ebh = udf_bread(dir,
				f_pos >> (dir->i_sb->s_blocksize_bits - 2),
				1, err);
541
		if (!fibh->ebh) {
J
Jan Kara 已提交
542 543
			brelse(epos.bh);
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
544 545 546
			return NULL;
		}

547
		if (!fibh->soffset) {
J
Jan Kara 已提交
548
			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
549
			    (EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
550
				block = eloc.logicalBlockNum + ((elen - 1) >>
551
					dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
552
			} else
553
				block++;
L
Linus Torvalds 已提交
554

J
Jan Kara 已提交
555
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
556 557
			fibh->sbh = fibh->ebh;
			fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
558
		} else {
L
Linus Torvalds 已提交
559
			fi = (struct fileIdentDesc *)
M
Marcin Slusarz 已提交
560 561
				(fibh->sbh->b_data + sb->s_blocksize +
					fibh->soffset);
L
Linus Torvalds 已提交
562 563 564 565
		}
	}

	memset(cfi, 0, sizeof(struct fileIdentDesc));
M
Marcin Slusarz 已提交
566
	if (UDF_SB(sb)->s_udfrev >= 0x0200)
M
Marcin Slusarz 已提交
567 568
		udf_new_tag((char *)cfi, TAG_IDENT_FID, 3, 1, block,
			    sizeof(tag));
L
Linus Torvalds 已提交
569
	else
M
Marcin Slusarz 已提交
570 571
		udf_new_tag((char *)cfi, TAG_IDENT_FID, 2, 1, block,
			    sizeof(tag));
L
Linus Torvalds 已提交
572 573 574
	cfi->fileVersionNum = cpu_to_le16(1);
	cfi->lengthFileIdent = namelen;
	cfi->lengthOfImpUse = cpu_to_le16(0);
575
	if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) {
J
Jan Kara 已提交
576
		brelse(epos.bh);
L
Linus Torvalds 已提交
577
		dir->i_size += nfidlen;
578 579
		if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
			UDF_I(dir)->i_lenAlloc += nfidlen;
L
Linus Torvalds 已提交
580 581
		mark_inode_dirty(dir);
		return fi;
582
	} else {
J
Jan Kara 已提交
583
		brelse(epos.bh);
L
Linus Torvalds 已提交
584
		if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
585 586
			brelse(fibh->ebh);
		brelse(fibh->sbh);
L
Linus Torvalds 已提交
587 588 589 590 591 592
		*err = -EIO;
		return NULL;
	}
}

static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
593 594
			    struct udf_fileident_bh *fibh,
			    struct fileIdentDesc *cfi)
L
Linus Torvalds 已提交
595 596
{
	cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
597

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

L
Linus Torvalds 已提交
601 602 603
	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}

604 605
static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
		      struct nameidata *nd)
L
Linus Torvalds 已提交
606 607 608 609 610 611 612 613
{
	struct udf_fileident_bh fibh;
	struct inode *inode;
	struct fileIdentDesc cfi, *fi;
	int err;

	lock_kernel();
	inode = udf_new_inode(dir, mode, &err);
614
	if (!inode) {
L
Linus Torvalds 已提交
615 616 617 618
		unlock_kernel();
		return err;
	}

619
	if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
620 621 622 623 624 625 626 627
		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 已提交
628 629
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
630
		inode->i_nlink--;
L
Linus Torvalds 已提交
631 632 633 634 635 636
		mark_inode_dirty(inode);
		iput(inode);
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
637
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
638
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
639
		cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
640
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
641
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
642 643
		mark_inode_dirty(dir);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
644 645
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
646 647
	unlock_kernel();
	d_instantiate(dentry, inode);
648

L
Linus Torvalds 已提交
649 650 651
	return 0;
}

652 653
static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
		     dev_t rdev)
L
Linus Torvalds 已提交
654
{
655
	struct inode *inode;
L
Linus Torvalds 已提交
656 657 658 659 660 661 662 663 664 665 666 667 668 669 670
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;

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

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

	inode->i_uid = current->fsuid;
	init_special_inode(inode, mode, rdev);
M
Marcin Slusarz 已提交
671 672
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
673
		inode->i_nlink--;
L
Linus Torvalds 已提交
674 675 676 677 678 679
		mark_inode_dirty(inode);
		iput(inode);
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
680
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
681
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
682
		cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
683
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
684
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
685 686 687 688
		mark_inode_dirty(dir);
	mark_inode_dirty(inode);

	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
689 690
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
691 692
	d_instantiate(dentry, inode);
	err = 0;
693 694

out:
L
Linus Torvalds 已提交
695 696 697 698
	unlock_kernel();
	return err;
}

699
static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
L
Linus Torvalds 已提交
700
{
701
	struct inode *inode;
L
Linus Torvalds 已提交
702 703 704 705 706 707
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;

	lock_kernel();
	err = -EMLINK;
708
	if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
709 710 711 712 713 714 715 716 717
		goto out;

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

	inode->i_op = &udf_dir_inode_operations;
	inode->i_fop = &udf_dir_operations;
M
Marcin Slusarz 已提交
718 719
	fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
720 721 722 723 724 725 726
		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);
727
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(dir)->i_location);
728
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
729
		cpu_to_le32(UDF_I(dir)->i_unique & 0x00000000FFFFFFFFUL);
M
Marcin Slusarz 已提交
730 731
	cfi.fileCharacteristics =
			FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
L
Linus Torvalds 已提交
732
	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
J
Jan Kara 已提交
733
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
734 735 736 737 738
	inode->i_mode = S_IFDIR | mode;
	if (dir->i_mode & S_ISGID)
		inode->i_mode |= S_ISGID;
	mark_inode_dirty(inode);

M
Marcin Slusarz 已提交
739 740
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
741 742 743 744 745 746
		inode->i_nlink = 0;
		mark_inode_dirty(inode);
		iput(inode);
		goto out;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
747
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
748
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
749
		cpu_to_le32(UDF_I(inode)->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
750 751
	cfi.fileCharacteristics |= FID_FILE_CHAR_DIRECTORY;
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
752
	inc_nlink(dir);
L
Linus Torvalds 已提交
753 754 755
	mark_inode_dirty(dir);
	d_instantiate(dentry, inode);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
756 757
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
758
	err = 0;
759 760

out:
L
Linus Torvalds 已提交
761 762 763 764 765 766 767 768 769 770 771
	unlock_kernel();
	return err;
}

static int empty_dir(struct inode *dir)
{
	struct fileIdentDesc *fi, cfi;
	struct udf_fileident_bh fibh;
	loff_t f_pos;
	loff_t size = (udf_ext0_offset(dir) + dir->i_size) >> 2;
	int block;
J
Jan Kara 已提交
772 773
	kernel_lb_addr eloc;
	uint32_t elen;
774
	sector_t offset;
775
	struct extent_position epos = {};
L
Linus Torvalds 已提交
776 777 778

	f_pos = (udf_ext0_offset(dir) >> 2);

M
Marcin Slusarz 已提交
779 780
	fibh.soffset = fibh.eoffset =
			(f_pos & ((dir->i_sb->s_blocksize - 1) >> 2)) << 2;
L
Linus Torvalds 已提交
781

782
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
783
		fibh.sbh = fibh.ebh = NULL;
M
Marcin Slusarz 已提交
784 785 786
	else if (inode_bmap(dir, f_pos >> (dir->i_sb->s_blocksize_bits - 2),
			      &epos, &eloc, &elen, &offset) ==
					(EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
787
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
788
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
789
			if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
790
				epos.offset -= sizeof(short_ad);
791 792
			else if (UDF_I(dir)->i_alloc_type ==
							ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
793
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
794
		} else
L
Linus Torvalds 已提交
795 796
			offset = 0;

M
Marcin Slusarz 已提交
797 798
		fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
		if (!fibh.sbh) {
J
Jan Kara 已提交
799
			brelse(epos.bh);
L
Linus Torvalds 已提交
800 801
			return 0;
		}
802
	} else {
J
Jan Kara 已提交
803
		brelse(epos.bh);
L
Linus Torvalds 已提交
804 805 806
		return 0;
	}

807 808 809 810
	while ((f_pos < size)) {
		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
					&elen, &offset);
		if (!fi) {
L
Linus Torvalds 已提交
811
			if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
812 813 814
				brelse(fibh.ebh);
			brelse(fibh.sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
815 816 817
			return 0;
		}

818 819
		if (cfi.lengthFileIdent &&
		    (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
L
Linus Torvalds 已提交
820
			if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
821 822 823
				brelse(fibh.ebh);
			brelse(fibh.sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
824 825 826
			return 0;
		}
	}
827

L
Linus Torvalds 已提交
828
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
829 830 831
		brelse(fibh.ebh);
	brelse(fibh.sbh);
	brelse(epos.bh);
832

L
Linus Torvalds 已提交
833 834 835
	return 1;
}

836
static int udf_rmdir(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
837 838
{
	int retval;
839
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861
	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",
862 863
			    "empty directory has nlink != 2 (%d)",
			    inode->i_nlink);
864
	clear_nlink(inode);
L
Linus Torvalds 已提交
865
	inode->i_size = 0;
866
	inode_dec_link_count(dir);
M
Marcin Slusarz 已提交
867 868
	inode->i_ctime = dir->i_ctime = dir->i_mtime =
						current_fs_time(dir->i_sb);
L
Linus Torvalds 已提交
869 870
	mark_inode_dirty(dir);

871
end_rmdir:
L
Linus Torvalds 已提交
872
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
873 874
		brelse(fibh.ebh);
	brelse(fibh.sbh);
875 876

out:
L
Linus Torvalds 已提交
877 878 879 880
	unlock_kernel();
	return retval;
}

881
static int udf_unlink(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
882 883
{
	int retval;
884
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900
	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;

901
	if (!inode->i_nlink) {
L
Linus Torvalds 已提交
902
		udf_debug("Deleting nonexistent file (%lu), %d\n",
903
			  inode->i_ino, inode->i_nlink);
L
Linus Torvalds 已提交
904 905 906 907 908 909 910
		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);
911
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
912 913 914
	inode->i_ctime = dir->i_ctime;
	retval = 0;

915
end_unlink:
L
Linus Torvalds 已提交
916
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
917 918
		brelse(fibh.ebh);
	brelse(fibh.sbh);
919 920

out:
L
Linus Torvalds 已提交
921 922 923 924
	unlock_kernel();
	return retval;
}

925 926
static int udf_symlink(struct inode *dir, struct dentry *dentry,
		       const char *symname)
L
Linus Torvalds 已提交
927
{
928
	struct inode *inode;
L
Linus Torvalds 已提交
929 930 931
	struct pathComponent *pc;
	char *compstart;
	struct udf_fileident_bh fibh;
932
	struct extent_position epos = {};
L
Linus Torvalds 已提交
933 934 935 936 937 938 939 940
	int eoffset, elen = 0;
	struct fileIdentDesc *fi;
	struct fileIdentDesc cfi;
	char *ea;
	int err;
	int block;
	char name[UDF_NAME_LEN];
	int namelen;
M
Marcin Slusarz 已提交
941
	struct buffer_head *bh;
L
Linus Torvalds 已提交
942 943

	lock_kernel();
M
Marcin Slusarz 已提交
944 945
	inode = udf_new_inode(dir, S_IFLNK, &err);
	if (!inode)
L
Linus Torvalds 已提交
946 947 948 949 950 951
		goto out;

	inode->i_mode = S_IFLNK | S_IRWXUGO;
	inode->i_data.a_ops = &udf_symlink_aops;
	inode->i_op = &page_symlink_inode_operations;

952
	if (UDF_I(inode)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
J
Jan Kara 已提交
953 954
		kernel_lb_addr eloc;
		uint32_t elen;
L
Linus Torvalds 已提交
955 956

		block = udf_new_block(inode->i_sb, inode,
957 958
				UDF_I(inode)->i_location.partitionReferenceNum,
				UDF_I(inode)->i_location.logicalBlockNum, &err);
L
Linus Torvalds 已提交
959 960
		if (!block)
			goto out_no_entry;
961
		epos.block = UDF_I(inode)->i_location;
J
Jan Kara 已提交
962 963
		epos.offset = udf_file_entry_alloc_offset(inode);
		epos.bh = NULL;
L
Linus Torvalds 已提交
964
		eloc.logicalBlockNum = block;
M
Marcin Slusarz 已提交
965
		eloc.partitionReferenceNum =
966
				UDF_I(inode)->i_location.partitionReferenceNum;
L
Linus Torvalds 已提交
967
		elen = inode->i_sb->s_blocksize;
968
		UDF_I(inode)->i_lenExtents = elen;
J
Jan Kara 已提交
969
		udf_add_aext(inode, &epos, eloc, elen, 0);
J
Jan Kara 已提交
970
		brelse(epos.bh);
L
Linus Torvalds 已提交
971 972

		block = udf_get_pblock(inode->i_sb, block,
973
				UDF_I(inode)->i_location.partitionReferenceNum,
M
Marcin Slusarz 已提交
974
				0);
J
Jan Kara 已提交
975 976 977 978 979 980 981
		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);
982
	} else {
983
		ea = UDF_I(inode)->i_ext.i_data + UDF_I(inode)->i_lenEAttr;
984
	}
L
Linus Torvalds 已提交
985 986 987 988

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

989 990
	if (*symname == '/') {
		do {
L
Linus Torvalds 已提交
991 992 993 994 995 996 997 998 999 1000 1001 1002
			symname++;
		} while (*symname == '/');

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

	err = -ENAMETOOLONG;

1003
	while (*symname) {
L
Linus Torvalds 已提交
1004 1005 1006 1007 1008 1009 1010
		if (elen + sizeof(struct pathComponent) > eoffset)
			goto out_no_entry;

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

		compstart = (char *)symname;

1011
		do {
L
Linus Torvalds 已提交
1012 1013 1014 1015 1016 1017
			symname++;
		} while (*symname && *symname != '/');

		pc->componentType = 5;
		pc->lengthComponentIdent = 0;
		pc->componentFileVersionNum = 0;
1018 1019
		if (compstart[0] == '.') {
			if ((symname - compstart) == 1)
L
Linus Torvalds 已提交
1020
				pc->componentType = 4;
M
Marcin Slusarz 已提交
1021 1022
			else if ((symname - compstart) == 2 &&
					compstart[1] == '.')
L
Linus Torvalds 已提交
1023 1024 1025
				pc->componentType = 3;
		}

1026
		if (pc->componentType == 5) {
1027 1028 1029
			namelen = udf_put_filename(inode->i_sb, compstart, name,
						   symname - compstart);
			if (!namelen)
L
Linus Torvalds 已提交
1030 1031
				goto out_no_entry;

M
Marcin Slusarz 已提交
1032 1033
			if (elen + sizeof(struct pathComponent) + namelen >
					eoffset)
L
Linus Torvalds 已提交
1034 1035 1036 1037 1038 1039 1040 1041 1042
				goto out_no_entry;
			else
				pc->lengthComponentIdent = namelen;

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

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

1043 1044
		if (*symname) {
			do {
L
Linus Torvalds 已提交
1045 1046 1047 1048 1049
				symname++;
			} while (*symname == '/');
		}
	}

J
Jan Kara 已提交
1050
	brelse(epos.bh);
L
Linus Torvalds 已提交
1051
	inode->i_size = elen;
1052 1053
	if (UDF_I(inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		UDF_I(inode)->i_lenAlloc = inode->i_size;
L
Linus Torvalds 已提交
1054 1055
	mark_inode_dirty(inode);

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

1086
out:
L
Linus Torvalds 已提交
1087 1088 1089
	unlock_kernel();
	return err;

1090
out_no_entry:
1091
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
1092 1093 1094 1095
	iput(inode);
	goto out;
}

1096 1097
static int udf_link(struct dentry *old_dentry, struct inode *dir,
		    struct dentry *dentry)
L
Linus Torvalds 已提交
1098 1099 1100 1101 1102
{
	struct inode *inode = old_dentry->d_inode;
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
M
Marcin Slusarz 已提交
1103
	struct buffer_head *bh;
L
Linus Torvalds 已提交
1104 1105

	lock_kernel();
1106
	if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
L
Linus Torvalds 已提交
1107 1108 1109 1110
		unlock_kernel();
		return -EMLINK;
	}

M
Marcin Slusarz 已提交
1111 1112
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
1113 1114 1115 1116
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
1117
	cfi.icb.extLocation = cpu_to_lelb(UDF_I(inode)->i_location);
M
Marcin Slusarz 已提交
1118 1119
	bh = UDF_SB(inode->i_sb)->s_lvid_bh;
	if (bh) {
M
Marcin Slusarz 已提交
1120 1121
		struct logicalVolIntegrityDesc *lvid =
				(struct logicalVolIntegrityDesc *)bh->b_data;
L
Linus Torvalds 已提交
1122 1123
		struct logicalVolHeaderDesc *lvhd;
		uint64_t uniqueID;
M
Marcin Slusarz 已提交
1124 1125
		lvhd = (struct logicalVolHeaderDesc *)
				(lvid->logicalVolContentsUse);
L
Linus Torvalds 已提交
1126
		uniqueID = le64_to_cpu(lvhd->uniqueID);
1127 1128
		*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
			cpu_to_le32(uniqueID & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
1129 1130 1131
		if (!(++uniqueID & 0x00000000FFFFFFFFUL))
			uniqueID += 16;
		lvhd->uniqueID = cpu_to_le64(uniqueID);
M
Marcin Slusarz 已提交
1132
		mark_buffer_dirty(bh);
L
Linus Torvalds 已提交
1133 1134
	}
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
1135
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1136
		mark_inode_dirty(dir);
1137

L
Linus Torvalds 已提交
1138
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
1139 1140
		brelse(fibh.ebh);
	brelse(fibh.sbh);
1141
	inc_nlink(inode);
L
Linus Torvalds 已提交
1142 1143 1144 1145 1146
	inode->i_ctime = current_fs_time(inode->i_sb);
	mark_inode_dirty(inode);
	atomic_inc(&inode->i_count);
	d_instantiate(dentry, inode);
	unlock_kernel();
1147

L
Linus Torvalds 已提交
1148 1149 1150 1151 1152 1153
	return 0;
}

/* Anybody can rename anything with this: the permission checks are left to the
 * higher-level routines.
 */
1154 1155
static int udf_rename(struct inode *old_dir, struct dentry *old_dentry,
		      struct inode *new_dir, struct dentry *new_dentry)
L
Linus Torvalds 已提交
1156
{
1157 1158
	struct inode *old_inode = old_dentry->d_inode;
	struct inode *new_inode = new_dentry->d_inode;
L
Linus Torvalds 已提交
1159
	struct udf_fileident_bh ofibh, nfibh;
M
Marcin Slusarz 已提交
1160 1161
	struct fileIdentDesc *ofi = NULL, *nfi = NULL, *dir_fi = NULL;
	struct fileIdentDesc ocfi, ncfi;
L
Linus Torvalds 已提交
1162 1163 1164 1165 1166
	struct buffer_head *dir_bh = NULL;
	int retval = -ENOENT;
	kernel_lb_addr tloc;

	lock_kernel();
M
Marcin Slusarz 已提交
1167 1168
	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
	if (ofi) {
L
Linus Torvalds 已提交
1169
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1170 1171
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1172 1173 1174
	}
	tloc = lelb_to_cpu(ocfi.icb.extLocation);
	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
1175
	    != old_inode->i_ino)
L
Linus Torvalds 已提交
1176 1177 1178
		goto end_rename;

	nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
1179 1180
	if (nfi) {
		if (!new_inode) {
L
Linus Torvalds 已提交
1181
			if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1182 1183
				brelse(nfibh.ebh);
			brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1184 1185 1186
			nfi = NULL;
		}
	}
1187
	if (S_ISDIR(old_inode->i_mode)) {
L
Linus Torvalds 已提交
1188 1189
		uint32_t offset = udf_ext0_offset(old_inode);

1190
		if (new_inode) {
L
Linus Torvalds 已提交
1191 1192 1193 1194 1195
			retval = -ENOTEMPTY;
			if (!empty_dir(new_inode))
				goto end_rename;
		}
		retval = -EIO;
1196
		if (UDF_I(old_inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
M
Marcin Slusarz 已提交
1197
			dir_fi = udf_get_fileident(
1198 1199
					UDF_I(old_inode)->i_ext.i_data -
					  (UDF_I(old_inode)->i_efe ?
M
Marcin Slusarz 已提交
1200 1201 1202
					   sizeof(struct extendedFileEntry) :
					   sizeof(struct fileEntry)),
					old_inode->i_sb->s_blocksize, &offset);
1203
		} else {
L
Linus Torvalds 已提交
1204 1205 1206
			dir_bh = udf_bread(old_inode, 0, 0, &retval);
			if (!dir_bh)
				goto end_rename;
M
Marcin Slusarz 已提交
1207 1208
			dir_fi = udf_get_fileident(dir_bh->b_data,
					old_inode->i_sb->s_blocksize, &offset);
L
Linus Torvalds 已提交
1209 1210 1211 1212
		}
		if (!dir_fi)
			goto end_rename;
		tloc = lelb_to_cpu(dir_fi->icb.extLocation);
M
Marcin Slusarz 已提交
1213 1214
		if (udf_get_lb_pblock(old_inode->i_sb, tloc, 0) !=
				old_dir->i_ino)
L
Linus Torvalds 已提交
1215 1216 1217
			goto end_rename;

		retval = -EMLINK;
M
Marcin Slusarz 已提交
1218 1219 1220
		if (!new_inode &&
			new_dir->i_nlink >=
				(256 << sizeof(new_dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
1221 1222
			goto end_rename;
	}
1223
	if (!nfi) {
M
Marcin Slusarz 已提交
1224 1225
		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
				    &retval);
L
Linus Torvalds 已提交
1226 1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248
		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);

1249
	if (new_inode) {
L
Linus Torvalds 已提交
1250
		new_inode->i_ctime = current_fs_time(new_inode->i_sb);
1251
		inode_dec_link_count(new_inode);
L
Linus Torvalds 已提交
1252 1253 1254 1255
	}
	old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
	mark_inode_dirty(old_dir);

1256
	if (dir_fi) {
1257
		dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
M
Marcin Slusarz 已提交
1258 1259 1260
		udf_update_tag((char *)dir_fi,
				(sizeof(struct fileIdentDesc) +
				le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
1261
		if (UDF_I(old_inode)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1262
			mark_inode_dirty(old_inode);
M
Marcin Slusarz 已提交
1263
		else
L
Linus Torvalds 已提交
1264
			mark_buffer_dirty_inode(dir_bh, old_inode);
M
Marcin Slusarz 已提交
1265

1266
		inode_dec_link_count(old_dir);
M
Marcin Slusarz 已提交
1267
		if (new_inode)
1268
			inode_dec_link_count(new_inode);
M
Marcin Slusarz 已提交
1269
		else {
1270
			inc_nlink(new_dir);
L
Linus Torvalds 已提交
1271 1272 1273 1274
			mark_inode_dirty(new_dir);
		}
	}

1275
	if (ofi) {
L
Linus Torvalds 已提交
1276
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1277 1278
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1279 1280 1281 1282
	}

	retval = 0;

1283
end_rename:
J
Jan Kara 已提交
1284
	brelse(dir_bh);
1285
	if (nfi) {
L
Linus Torvalds 已提交
1286
		if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1287 1288
			brelse(nfibh.ebh);
		brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1289 1290
	}
	unlock_kernel();
1291

L
Linus Torvalds 已提交
1292 1293 1294
	return retval;
}

1295
const struct inode_operations udf_dir_inode_operations = {
1296 1297 1298 1299 1300 1301 1302 1303 1304
	.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 已提交
1305
};