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

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

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

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

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

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

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

	offset += liu;

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

	offset += lfi;

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

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

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

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

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

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

143 144 145 146
static struct fileIdentDesc *udf_find_entry(struct inode *dir,
					    struct dentry *dentry,
					    struct udf_fileident_bh *fibh,
					    struct fileIdentDesc *cfi)
L
Linus Torvalds 已提交
147
{
148
	struct fileIdentDesc *fi = NULL;
L
Linus Torvalds 已提交
149 150
	loff_t f_pos;
	int block, flen;
151
	char *fname = NULL;
L
Linus Torvalds 已提交
152 153 154
	char *nameptr;
	uint8_t lfi;
	uint16_t liu;
155
	loff_t size;
J
Jan Kara 已提交
156 157
	kernel_lb_addr eloc;
	uint32_t elen;
158
	sector_t offset;
159
	struct extent_position epos = {};
160
	struct udf_inode_info *dinfo = UDF_I(dir);
L
Linus Torvalds 已提交
161

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

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

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

185 186 187 188
	fname = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!fname)
		goto out_err;

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

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

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

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

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

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

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

		if (!lfi)
			continue;

M
Marcin Slusarz 已提交
231 232
		flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi);
		if (flen && udf_match(flen, fname, dentry->d_name.len,
233 234
				      dentry->d_name.name))
			goto out_ok;
L
Linus Torvalds 已提交
235
	}
236

237 238
out_err:
	fi = NULL;
L
Linus Torvalds 已提交
239
	if (fibh->sbh != fibh->ebh)
J
Jan Kara 已提交
240 241
		brelse(fibh->ebh);
	brelse(fibh->sbh);
242
out_ok:
J
Jan Kara 已提交
243
	brelse(epos.bh);
244
	kfree(fname);
245

246
	return fi;
L
Linus Torvalds 已提交
247 248
}

249 250
static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry,
				 struct nameidata *nd)
L
Linus Torvalds 已提交
251 252
{
	struct inode *inode = NULL;
253
	struct fileIdentDesc cfi;
L
Linus Torvalds 已提交
254 255
	struct udf_fileident_bh fibh;

256
	if (dentry->d_name.len > UDF_NAME_LEN - 2)
L
Linus Torvalds 已提交
257 258 259 260 261
		return ERR_PTR(-ENAMETOOLONG);

	lock_kernel();
#ifdef UDF_RECOVERY
	/* temporary shorthand for specifying files by inode number */
262
	if (!strncmp(dentry->d_name.name, ".B=", 3)) {
263 264
		kernel_lb_addr lb = {
			.logicalBlockNum = 0,
M
Marcin Slusarz 已提交
265 266 267
			.partitionReferenceNum =
				simple_strtoul(dentry->d_name.name + 3,
						NULL, 0),
268
		};
L
Linus Torvalds 已提交
269
		inode = udf_iget(dir->i_sb, lb);
270
		if (!inode) {
L
Linus Torvalds 已提交
271 272 273
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
M
Marcin Slusarz 已提交
274
	} else
275
#endif /* UDF_RECOVERY */
L
Linus Torvalds 已提交
276

277
	if (udf_find_entry(dir, dentry, &fibh, &cfi)) {
L
Linus Torvalds 已提交
278
		if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
279 280
			brelse(fibh.ebh);
		brelse(fibh.sbh);
L
Linus Torvalds 已提交
281 282

		inode = udf_iget(dir->i_sb, lelb_to_cpu(cfi.icb.extLocation));
283
		if (!inode) {
L
Linus Torvalds 已提交
284 285 286 287 288 289
			unlock_kernel();
			return ERR_PTR(-EACCES);
		}
	}
	unlock_kernel();
	d_add(dentry, inode);
290

L
Linus Torvalds 已提交
291 292 293
	return NULL;
}

294 295 296 297
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 已提交
298
{
M
Marcin Slusarz 已提交
299
	struct super_block *sb = dir->i_sb;
300
	struct fileIdentDesc *fi = NULL;
301
	char *name = NULL;
L
Linus Torvalds 已提交
302 303
	int namelen;
	loff_t f_pos;
304
	loff_t size = udf_ext0_offset(dir) + dir->i_size;
L
Linus Torvalds 已提交
305 306 307 308
	int nfidlen;
	uint8_t lfi;
	uint16_t liu;
	int block;
J
Jan Kara 已提交
309 310
	kernel_lb_addr eloc;
	uint32_t elen;
311
	sector_t offset;
312
	struct extent_position epos = {};
313
	struct udf_inode_info *dinfo;
L
Linus Torvalds 已提交
314

315 316 317 318 319 320 321
	fibh->sbh = fibh->ebh = NULL;
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!name) {
		*err = -ENOMEM;
		goto out_err;
	}

322 323
	if (dentry) {
		if (!dentry->d_name.len) {
L
Linus Torvalds 已提交
324
			*err = -EINVAL;
325
			goto out_err;
L
Linus Torvalds 已提交
326
		}
M
Marcin Slusarz 已提交
327 328 329
		namelen = udf_put_filename(sb, dentry->d_name.name, name,
						 dentry->d_name.len);
		if (!namelen) {
L
Linus Torvalds 已提交
330
			*err = -ENAMETOOLONG;
331
			goto out_err;
L
Linus Torvalds 已提交
332
		}
333
	} else {
L
Linus Torvalds 已提交
334
		namelen = 0;
335
	}
L
Linus Torvalds 已提交
336 337 338

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

339
	f_pos = udf_ext0_offset(dir);
L
Linus Torvalds 已提交
340

341
	fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
342
	dinfo = UDF_I(dir);
343 344 345 346 347 348 349 350
	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 已提交
351
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
352
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
353
			if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
354
				epos.offset -= sizeof(short_ad);
355
			else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
356
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
357
		} else
L
Linus Torvalds 已提交
358 359
			offset = 0;

M
Marcin Slusarz 已提交
360 361
		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
		if (!fibh->sbh) {
L
Linus Torvalds 已提交
362
			*err = -EIO;
363
			goto out_err;
L
Linus Torvalds 已提交
364 365
		}

366
		block = dinfo->i_location.logicalBlockNum;
L
Linus Torvalds 已提交
367 368
	}

369
	while (f_pos < size) {
370 371
		fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc,
					&elen, &offset);
L
Linus Torvalds 已提交
372

373
		if (!fi) {
L
Linus Torvalds 已提交
374
			*err = -EIO;
375
			goto out_err;
L
Linus Torvalds 已提交
376 377 378 379 380
		}

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

381
		if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) {
M
Marcin Slusarz 已提交
382 383
			if (((sizeof(struct fileIdentDesc) +
					liu + lfi + 3) & ~3) == nfidlen) {
L
Linus Torvalds 已提交
384 385 386 387 388
				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 已提交
389 390
				if (!udf_write_fi(dir, cfi, fi, fibh, NULL,
						  name))
391
					goto out_ok;
M
Marcin Slusarz 已提交
392
				else {
L
Linus Torvalds 已提交
393
					*err = -EIO;
394
					goto out_err;
L
Linus Torvalds 已提交
395 396 397 398 399
				}
			}
		}
	}

400
add:
J
Jan Kara 已提交
401 402 403 404 405 406 407 408
	if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
		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 已提交
409 410
	f_pos += nfidlen;

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

431
	if (sb->s_blocksize - fibh->eoffset >= nfidlen) {
L
Linus Torvalds 已提交
432 433
		fibh->soffset = fibh->eoffset;
		fibh->eoffset += nfidlen;
434
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
435
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
436 437 438
			fibh->sbh = fibh->ebh;
		}

439 440
		if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
			block = dinfo->i_location.logicalBlockNum;
M
Marcin Slusarz 已提交
441
			fi = (struct fileIdentDesc *)
442
					(dinfo->i_ext.i_data +
443
					 fibh->soffset -
M
Marcin Slusarz 已提交
444
					 udf_ext0_offset(dir) +
445
					 dinfo->i_lenEAttr);
446
		} else {
M
Marcin Slusarz 已提交
447 448 449 450 451
			block = eloc.logicalBlockNum +
					((elen - 1) >>
						dir->i_sb->s_blocksize_bits);
			fi = (struct fileIdentDesc *)
				(fibh->sbh->b_data + fibh->soffset);
L
Linus Torvalds 已提交
452
		}
453
	} else {
L
Linus Torvalds 已提交
454 455
		fibh->soffset = fibh->eoffset - sb->s_blocksize;
		fibh->eoffset += nfidlen - sb->s_blocksize;
456
		if (fibh->sbh != fibh->ebh) {
J
Jan Kara 已提交
457
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
458 459 460 461
			fibh->sbh = fibh->ebh;
		}

		block = eloc.logicalBlockNum + ((elen - 1) >>
462
						dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
463
		fibh->ebh = udf_bread(dir,
464
				f_pos >> dir->i_sb->s_blocksize_bits, 1, err);
465 466
		if (!fibh->ebh)
			goto out_err;
L
Linus Torvalds 已提交
467

468
		if (!fibh->soffset) {
J
Jan Kara 已提交
469
			if (udf_next_aext(dir, &epos, &eloc, &elen, 1) ==
470
			    (EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
471
				block = eloc.logicalBlockNum + ((elen - 1) >>
472
					dir->i_sb->s_blocksize_bits);
M
Marcin Slusarz 已提交
473
			} else
474
				block++;
L
Linus Torvalds 已提交
475

J
Jan Kara 已提交
476
			brelse(fibh->sbh);
L
Linus Torvalds 已提交
477 478
			fibh->sbh = fibh->ebh;
			fi = (struct fileIdentDesc *)(fibh->sbh->b_data);
479
		} else {
L
Linus Torvalds 已提交
480
			fi = (struct fileIdentDesc *)
M
Marcin Slusarz 已提交
481 482
				(fibh->sbh->b_data + sb->s_blocksize +
					fibh->soffset);
L
Linus Torvalds 已提交
483 484 485 486
		}
	}

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

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 已提交
516 517 518
}

static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi,
519 520
			    struct udf_fileident_bh *fibh,
			    struct fileIdentDesc *cfi)
L
Linus Torvalds 已提交
521 522
{
	cfi->fileCharacteristics |= FID_FILE_CHAR_DELETED;
523

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

L
Linus Torvalds 已提交
527 528 529
	return udf_write_fi(inode, cfi, fi, fibh, NULL, NULL);
}

530 531
static int udf_create(struct inode *dir, struct dentry *dentry, int mode,
		      struct nameidata *nd)
L
Linus Torvalds 已提交
532 533 534 535 536
{
	struct udf_fileident_bh fibh;
	struct inode *inode;
	struct fileIdentDesc cfi, *fi;
	int err;
537
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
538 539 540

	lock_kernel();
	inode = udf_new_inode(dir, mode, &err);
541
	if (!inode) {
L
Linus Torvalds 已提交
542 543 544 545
		unlock_kernel();
		return err;
	}

546 547
	iinfo = UDF_I(inode);
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
548 549 550 551 552 553 554 555
		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 已提交
556 557
	fi = udf_add_entry(dir, dentry, &fibh, &cfi, &err);
	if (!fi) {
558
		inode->i_nlink--;
L
Linus Torvalds 已提交
559 560 561 562 563 564
		mark_inode_dirty(inode);
		iput(inode);
		unlock_kernel();
		return err;
	}
	cfi.icb.extLength = cpu_to_le32(inode->i_sb->s_blocksize);
565
	cfi.icb.extLocation = cpu_to_lelb(iinfo->i_location);
566
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
567
		cpu_to_le32(iinfo->i_unique & 0x00000000FFFFFFFFUL);
L
Linus Torvalds 已提交
568
	udf_write_fi(dir, &cfi, fi, &fibh, NULL, NULL);
569
	if (UDF_I(dir)->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
570 571
		mark_inode_dirty(dir);
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
572 573
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
574 575
	unlock_kernel();
	d_instantiate(dentry, inode);
576

L
Linus Torvalds 已提交
577 578 579
	return 0;
}

580 581
static int udf_mknod(struct inode *dir, struct dentry *dentry, int mode,
		     dev_t rdev)
L
Linus Torvalds 已提交
582
{
583
	struct inode *inode;
L
Linus Torvalds 已提交
584 585 586
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
587
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
588 589 590 591 592 593 594 595 596 597

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

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

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

	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
619 620
		brelse(fibh.ebh);
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
621 622
	d_instantiate(dentry, inode);
	err = 0;
623 624

out:
L
Linus Torvalds 已提交
625 626 627 628
	unlock_kernel();
	return err;
}

629
static int udf_mkdir(struct inode *dir, struct dentry *dentry, int mode)
L
Linus Torvalds 已提交
630
{
631
	struct inode *inode;
L
Linus Torvalds 已提交
632 633 634
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
635 636
	struct udf_inode_info *dinfo = UDF_I(dir);
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
637 638 639

	lock_kernel();
	err = -EMLINK;
640
	if (dir->i_nlink >= (256 << sizeof(dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
641 642 643 644 645 646 647
		goto out;

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

648
	iinfo = UDF_I(inode);
L
Linus Torvalds 已提交
649 650
	inode->i_op = &udf_dir_inode_operations;
	inode->i_fop = &udf_dir_operations;
M
Marcin Slusarz 已提交
651 652
	fi = udf_add_entry(inode, NULL, &fibh, &cfi, &err);
	if (!fi) {
L
Linus Torvalds 已提交
653 654 655 656 657 658 659
		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);
660
	cfi.icb.extLocation = cpu_to_lelb(dinfo->i_location);
661
	*(__le32 *)((struct allocDescImpUse *)cfi.icb.impUse)->impUse =
662
		cpu_to_le32(dinfo->i_unique & 0x00000000FFFFFFFFUL);
M
Marcin Slusarz 已提交
663 664
	cfi.fileCharacteristics =
			FID_FILE_CHAR_DIRECTORY | FID_FILE_CHAR_PARENT;
L
Linus Torvalds 已提交
665
	udf_write_fi(inode, &cfi, fi, &fibh, NULL, NULL);
J
Jan Kara 已提交
666
	brelse(fibh.sbh);
L
Linus Torvalds 已提交
667 668 669 670 671
	inode->i_mode = S_IFDIR | mode;
	if (dir->i_mode & S_ISGID)
		inode->i_mode |= S_ISGID;
	mark_inode_dirty(inode);

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

out:
L
Linus Torvalds 已提交
694 695 696 697 698 699 700 701 702
	unlock_kernel();
	return err;
}

static int empty_dir(struct inode *dir)
{
	struct fileIdentDesc *fi, cfi;
	struct udf_fileident_bh fibh;
	loff_t f_pos;
703
	loff_t size = udf_ext0_offset(dir) + dir->i_size;
L
Linus Torvalds 已提交
704
	int block;
J
Jan Kara 已提交
705 706
	kernel_lb_addr eloc;
	uint32_t elen;
707
	sector_t offset;
708
	struct extent_position epos = {};
709
	struct udf_inode_info *dinfo = UDF_I(dir);
L
Linus Torvalds 已提交
710

711 712
	f_pos = udf_ext0_offset(dir);
	fibh.soffset = fibh.eoffset = f_pos & (dir->i_sb->s_blocksize - 1);
L
Linus Torvalds 已提交
713

714
	if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
715
		fibh.sbh = fibh.ebh = NULL;
716
	else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits,
M
Marcin Slusarz 已提交
717 718
			      &epos, &eloc, &elen, &offset) ==
					(EXT_RECORDED_ALLOCATED >> 30)) {
L
Linus Torvalds 已提交
719
		block = udf_get_lb_pblock(dir->i_sb, eloc, offset);
720
		if ((++offset << dir->i_sb->s_blocksize_bits) < elen) {
721
			if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
J
Jan Kara 已提交
722
				epos.offset -= sizeof(short_ad);
723
			else if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
J
Jan Kara 已提交
724
				epos.offset -= sizeof(long_ad);
M
Marcin Slusarz 已提交
725
		} else
L
Linus Torvalds 已提交
726 727
			offset = 0;

M
Marcin Slusarz 已提交
728 729
		fibh.sbh = fibh.ebh = udf_tread(dir->i_sb, block);
		if (!fibh.sbh) {
J
Jan Kara 已提交
730
			brelse(epos.bh);
L
Linus Torvalds 已提交
731 732
			return 0;
		}
733
	} else {
J
Jan Kara 已提交
734
		brelse(epos.bh);
L
Linus Torvalds 已提交
735 736 737
		return 0;
	}

738
	while (f_pos < size) {
739 740 741
		fi = udf_fileident_read(dir, &f_pos, &fibh, &cfi, &epos, &eloc,
					&elen, &offset);
		if (!fi) {
L
Linus Torvalds 已提交
742
			if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
743 744 745
				brelse(fibh.ebh);
			brelse(fibh.sbh);
			brelse(epos.bh);
L
Linus Torvalds 已提交
746 747 748
			return 0;
		}

749 750
		if (cfi.lengthFileIdent &&
		    (cfi.fileCharacteristics & FID_FILE_CHAR_DELETED) == 0) {
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

L
Linus Torvalds 已提交
759
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
760 761 762
		brelse(fibh.ebh);
	brelse(fibh.sbh);
	brelse(epos.bh);
763

L
Linus Torvalds 已提交
764 765 766
	return 1;
}

767
static int udf_rmdir(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
768 769
{
	int retval;
770
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792
	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",
793 794
			    "empty directory has nlink != 2 (%d)",
			    inode->i_nlink);
795
	clear_nlink(inode);
L
Linus Torvalds 已提交
796
	inode->i_size = 0;
797
	inode_dec_link_count(dir);
M
Marcin Slusarz 已提交
798 799
	inode->i_ctime = dir->i_ctime = dir->i_mtime =
						current_fs_time(dir->i_sb);
L
Linus Torvalds 已提交
800 801
	mark_inode_dirty(dir);

802
end_rmdir:
L
Linus Torvalds 已提交
803
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
804 805
		brelse(fibh.ebh);
	brelse(fibh.sbh);
806 807

out:
L
Linus Torvalds 已提交
808 809 810 811
	unlock_kernel();
	return retval;
}

812
static int udf_unlink(struct inode *dir, struct dentry *dentry)
L
Linus Torvalds 已提交
813 814
{
	int retval;
815
	struct inode *inode = dentry->d_inode;
L
Linus Torvalds 已提交
816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831
	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;

832
	if (!inode->i_nlink) {
L
Linus Torvalds 已提交
833
		udf_debug("Deleting nonexistent file (%lu), %d\n",
834
			  inode->i_ino, inode->i_nlink);
L
Linus Torvalds 已提交
835 836 837 838 839 840 841
		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);
842
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
843 844 845
	inode->i_ctime = dir->i_ctime;
	retval = 0;

846
end_unlink:
L
Linus Torvalds 已提交
847
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
848 849
		brelse(fibh.ebh);
	brelse(fibh.sbh);
850 851

out:
L
Linus Torvalds 已提交
852 853 854 855
	unlock_kernel();
	return retval;
}

856 857
static int udf_symlink(struct inode *dir, struct dentry *dentry,
		       const char *symname)
L
Linus Torvalds 已提交
858
{
859
	struct inode *inode;
L
Linus Torvalds 已提交
860 861 862
	struct pathComponent *pc;
	char *compstart;
	struct udf_fileident_bh fibh;
863
	struct extent_position epos = {};
L
Linus Torvalds 已提交
864 865 866 867 868 869
	int eoffset, elen = 0;
	struct fileIdentDesc *fi;
	struct fileIdentDesc cfi;
	char *ea;
	int err;
	int block;
870
	char *name = NULL;
L
Linus Torvalds 已提交
871
	int namelen;
M
Marcin Slusarz 已提交
872
	struct buffer_head *bh;
873
	struct udf_inode_info *iinfo;
L
Linus Torvalds 已提交
874 875

	lock_kernel();
M
Marcin Slusarz 已提交
876 877
	inode = udf_new_inode(dir, S_IFLNK, &err);
	if (!inode)
L
Linus Torvalds 已提交
878 879
		goto out;

880 881 882 883 884 885
	name = kmalloc(UDF_NAME_LEN, GFP_NOFS);
	if (!name) {
		err = -ENOMEM;
		goto out_no_entry;
	}

886
	iinfo = UDF_I(inode);
L
Linus Torvalds 已提交
887 888 889 890
	inode->i_mode = S_IFLNK | S_IRWXUGO;
	inode->i_data.a_ops = &udf_symlink_aops;
	inode->i_op = &page_symlink_inode_operations;

891
	if (iinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
J
Jan Kara 已提交
892 893
		kernel_lb_addr eloc;
		uint32_t elen;
L
Linus Torvalds 已提交
894 895

		block = udf_new_block(inode->i_sb, inode,
896 897
				iinfo->i_location.partitionReferenceNum,
				iinfo->i_location.logicalBlockNum, &err);
L
Linus Torvalds 已提交
898 899
		if (!block)
			goto out_no_entry;
900
		epos.block = iinfo->i_location;
J
Jan Kara 已提交
901 902
		epos.offset = udf_file_entry_alloc_offset(inode);
		epos.bh = NULL;
L
Linus Torvalds 已提交
903
		eloc.logicalBlockNum = block;
M
Marcin Slusarz 已提交
904
		eloc.partitionReferenceNum =
905
				iinfo->i_location.partitionReferenceNum;
L
Linus Torvalds 已提交
906
		elen = inode->i_sb->s_blocksize;
907
		iinfo->i_lenExtents = elen;
J
Jan Kara 已提交
908
		udf_add_aext(inode, &epos, eloc, elen, 0);
J
Jan Kara 已提交
909
		brelse(epos.bh);
L
Linus Torvalds 已提交
910 911

		block = udf_get_pblock(inode->i_sb, block,
912
				iinfo->i_location.partitionReferenceNum,
M
Marcin Slusarz 已提交
913
				0);
J
Jan Kara 已提交
914 915 916 917 918 919 920
		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);
921 922
	} else
		ea = iinfo->i_ext.i_data + iinfo->i_lenEAttr;
L
Linus Torvalds 已提交
923 924 925 926

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

927 928
	if (*symname == '/') {
		do {
L
Linus Torvalds 已提交
929 930 931 932 933 934 935 936 937 938 939 940
			symname++;
		} while (*symname == '/');

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

	err = -ENAMETOOLONG;

941
	while (*symname) {
L
Linus Torvalds 已提交
942 943 944 945 946 947 948
		if (elen + sizeof(struct pathComponent) > eoffset)
			goto out_no_entry;

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

		compstart = (char *)symname;

949
		do {
L
Linus Torvalds 已提交
950 951 952 953 954 955
			symname++;
		} while (*symname && *symname != '/');

		pc->componentType = 5;
		pc->lengthComponentIdent = 0;
		pc->componentFileVersionNum = 0;
956 957
		if (compstart[0] == '.') {
			if ((symname - compstart) == 1)
L
Linus Torvalds 已提交
958
				pc->componentType = 4;
M
Marcin Slusarz 已提交
959 960
			else if ((symname - compstart) == 2 &&
					compstart[1] == '.')
L
Linus Torvalds 已提交
961 962 963
				pc->componentType = 3;
		}

964
		if (pc->componentType == 5) {
965 966 967
			namelen = udf_put_filename(inode->i_sb, compstart, name,
						   symname - compstart);
			if (!namelen)
L
Linus Torvalds 已提交
968 969
				goto out_no_entry;

M
Marcin Slusarz 已提交
970 971
			if (elen + sizeof(struct pathComponent) + namelen >
					eoffset)
L
Linus Torvalds 已提交
972 973 974 975 976 977 978 979 980
				goto out_no_entry;
			else
				pc->lengthComponentIdent = namelen;

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

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

981 982
		if (*symname) {
			do {
L
Linus Torvalds 已提交
983 984 985 986 987
				symname++;
			} while (*symname == '/');
		}
	}

J
Jan Kara 已提交
988
	brelse(epos.bh);
L
Linus Torvalds 已提交
989
	inode->i_size = elen;
990 991
	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
		iinfo->i_lenAlloc = inode->i_size;
L
Linus Torvalds 已提交
992 993
	mark_inode_dirty(inode);

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

1024
out:
1025
	kfree(name);
L
Linus Torvalds 已提交
1026 1027 1028
	unlock_kernel();
	return err;

1029
out_no_entry:
1030
	inode_dec_link_count(inode);
L
Linus Torvalds 已提交
1031 1032 1033 1034
	iput(inode);
	goto out;
}

1035 1036
static int udf_link(struct dentry *old_dentry, struct inode *dir,
		    struct dentry *dentry)
L
Linus Torvalds 已提交
1037 1038 1039 1040 1041
{
	struct inode *inode = old_dentry->d_inode;
	struct udf_fileident_bh fibh;
	struct fileIdentDesc cfi, *fi;
	int err;
M
Marcin Slusarz 已提交
1042
	struct buffer_head *bh;
L
Linus Torvalds 已提交
1043 1044

	lock_kernel();
1045
	if (inode->i_nlink >= (256 << sizeof(inode->i_nlink)) - 1) {
L
Linus Torvalds 已提交
1046 1047 1048 1049
		unlock_kernel();
		return -EMLINK;
	}

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

L
Linus Torvalds 已提交
1077
	if (fibh.sbh != fibh.ebh)
J
Jan Kara 已提交
1078 1079
		brelse(fibh.ebh);
	brelse(fibh.sbh);
1080
	inc_nlink(inode);
L
Linus Torvalds 已提交
1081 1082 1083 1084 1085
	inode->i_ctime = current_fs_time(inode->i_sb);
	mark_inode_dirty(inode);
	atomic_inc(&inode->i_count);
	d_instantiate(dentry, inode);
	unlock_kernel();
1086

L
Linus Torvalds 已提交
1087 1088 1089 1090 1091 1092
	return 0;
}

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

	lock_kernel();
M
Marcin Slusarz 已提交
1107 1108
	ofi = udf_find_entry(old_dir, old_dentry, &ofibh, &ocfi);
	if (ofi) {
L
Linus Torvalds 已提交
1109
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1110 1111
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1112 1113 1114
	}
	tloc = lelb_to_cpu(ocfi.icb.extLocation);
	if (!ofi || udf_get_lb_pblock(old_dir->i_sb, tloc, 0)
1115
	    != old_inode->i_ino)
L
Linus Torvalds 已提交
1116 1117 1118
		goto end_rename;

	nfi = udf_find_entry(new_dir, new_dentry, &nfibh, &ncfi);
1119 1120
	if (nfi) {
		if (!new_inode) {
L
Linus Torvalds 已提交
1121
			if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1122 1123
				brelse(nfibh.ebh);
			brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1124 1125 1126
			nfi = NULL;
		}
	}
1127
	if (S_ISDIR(old_inode->i_mode)) {
M
Marcin Slusarz 已提交
1128
		int offset = udf_ext0_offset(old_inode);
L
Linus Torvalds 已提交
1129

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

		retval = -EMLINK;
M
Marcin Slusarz 已提交
1158 1159 1160
		if (!new_inode &&
			new_dir->i_nlink >=
				(256 << sizeof(new_dir->i_nlink)) - 1)
L
Linus Torvalds 已提交
1161 1162
			goto end_rename;
	}
1163
	if (!nfi) {
M
Marcin Slusarz 已提交
1164 1165
		nfi = udf_add_entry(new_dir, new_dentry, &nfibh, &ncfi,
				    &retval);
L
Linus Torvalds 已提交
1166 1167 1168 1169 1170 1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188
		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);

1189
	if (new_inode) {
L
Linus Torvalds 已提交
1190
		new_inode->i_ctime = current_fs_time(new_inode->i_sb);
1191
		inode_dec_link_count(new_inode);
L
Linus Torvalds 已提交
1192 1193 1194 1195
	}
	old_dir->i_ctime = old_dir->i_mtime = current_fs_time(old_dir->i_sb);
	mark_inode_dirty(old_dir);

1196
	if (dir_fi) {
1197
		dir_fi->icb.extLocation = cpu_to_lelb(UDF_I(new_dir)->i_location);
M
Marcin Slusarz 已提交
1198 1199 1200
		udf_update_tag((char *)dir_fi,
				(sizeof(struct fileIdentDesc) +
				le16_to_cpu(dir_fi->lengthOfImpUse) + 3) & ~3);
1201
		if (old_iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB)
L
Linus Torvalds 已提交
1202
			mark_inode_dirty(old_inode);
M
Marcin Slusarz 已提交
1203
		else
L
Linus Torvalds 已提交
1204
			mark_buffer_dirty_inode(dir_bh, old_inode);
M
Marcin Slusarz 已提交
1205

1206
		inode_dec_link_count(old_dir);
M
Marcin Slusarz 已提交
1207
		if (new_inode)
1208
			inode_dec_link_count(new_inode);
M
Marcin Slusarz 已提交
1209
		else {
1210
			inc_nlink(new_dir);
L
Linus Torvalds 已提交
1211 1212 1213 1214
			mark_inode_dirty(new_dir);
		}
	}

1215
	if (ofi) {
L
Linus Torvalds 已提交
1216
		if (ofibh.sbh != ofibh.ebh)
J
Jan Kara 已提交
1217 1218
			brelse(ofibh.ebh);
		brelse(ofibh.sbh);
L
Linus Torvalds 已提交
1219 1220 1221 1222
	}

	retval = 0;

1223
end_rename:
J
Jan Kara 已提交
1224
	brelse(dir_bh);
1225
	if (nfi) {
L
Linus Torvalds 已提交
1226
		if (nfibh.sbh != nfibh.ebh)
J
Jan Kara 已提交
1227 1228
			brelse(nfibh.ebh);
		brelse(nfibh.sbh);
L
Linus Torvalds 已提交
1229 1230
	}
	unlock_kernel();
1231

L
Linus Torvalds 已提交
1232 1233 1234
	return retval;
}

1235
const struct inode_operations udf_dir_inode_operations = {
1236 1237 1238 1239 1240 1241 1242 1243 1244
	.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 已提交
1245
};