diff options
Diffstat (limited to 'fs/udf/namei.c')
-rw-r--r-- | fs/udf/namei.c | 128 |
1 files changed, 66 insertions, 62 deletions
diff --git a/fs/udf/namei.c b/fs/udf/namei.c index e9f587201e17..68686b79650a 100644 --- a/fs/udf/namei.c +++ b/fs/udf/namei.c | |||
@@ -149,7 +149,7 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
149 | struct fileIdentDesc *fi = NULL; | 149 | struct fileIdentDesc *fi = NULL; |
150 | loff_t f_pos; | 150 | loff_t f_pos; |
151 | int block, flen; | 151 | int block, flen; |
152 | char fname[UDF_NAME_LEN]; | 152 | char *fname = NULL; |
153 | char *nameptr; | 153 | char *nameptr; |
154 | uint8_t lfi; | 154 | uint8_t lfi; |
155 | uint16_t liu; | 155 | uint16_t liu; |
@@ -163,12 +163,12 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
163 | size = udf_ext0_offset(dir) + dir->i_size; | 163 | size = udf_ext0_offset(dir) + dir->i_size; |
164 | f_pos = udf_ext0_offset(dir); | 164 | f_pos = udf_ext0_offset(dir); |
165 | 165 | ||
166 | fibh->sbh = fibh->ebh = NULL; | ||
166 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); | 167 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); |
167 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 168 | if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
168 | fibh->sbh = fibh->ebh = NULL; | 169 | if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, |
169 | else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, | 170 | &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) |
170 | &epos, &eloc, &elen, &offset) == | 171 | goto out_err; |
171 | (EXT_RECORDED_ALLOCATED >> 30)) { | ||
172 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | 172 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); |
173 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { | 173 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { |
174 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 174 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
@@ -179,25 +179,19 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
179 | offset = 0; | 179 | offset = 0; |
180 | 180 | ||
181 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); | 181 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); |
182 | if (!fibh->sbh) { | 182 | if (!fibh->sbh) |
183 | brelse(epos.bh); | 183 | goto out_err; |
184 | return NULL; | ||
185 | } | ||
186 | } else { | ||
187 | brelse(epos.bh); | ||
188 | return NULL; | ||
189 | } | 184 | } |
190 | 185 | ||
186 | fname = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
187 | if (!fname) | ||
188 | goto out_err; | ||
189 | |||
191 | while (f_pos < size) { | 190 | while (f_pos < size) { |
192 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, | 191 | fi = udf_fileident_read(dir, &f_pos, fibh, cfi, &epos, &eloc, |
193 | &elen, &offset); | 192 | &elen, &offset); |
194 | if (!fi) { | 193 | if (!fi) |
195 | if (fibh->sbh != fibh->ebh) | 194 | goto out_err; |
196 | brelse(fibh->ebh); | ||
197 | brelse(fibh->sbh); | ||
198 | brelse(epos.bh); | ||
199 | return NULL; | ||
200 | } | ||
201 | 195 | ||
202 | liu = le16_to_cpu(cfi->lengthOfImpUse); | 196 | liu = le16_to_cpu(cfi->lengthOfImpUse); |
203 | lfi = cfi->lengthFileIdent; | 197 | lfi = cfi->lengthFileIdent; |
@@ -237,18 +231,20 @@ static struct fileIdentDesc *udf_find_entry(struct inode *dir, | |||
237 | 231 | ||
238 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); | 232 | flen = udf_get_filename(dir->i_sb, nameptr, fname, lfi); |
239 | if (flen && udf_match(flen, fname, dentry->d_name.len, | 233 | if (flen && udf_match(flen, fname, dentry->d_name.len, |
240 | dentry->d_name.name)) { | 234 | dentry->d_name.name)) |
241 | brelse(epos.bh); | 235 | goto out_ok; |
242 | return fi; | ||
243 | } | ||
244 | } | 236 | } |
245 | 237 | ||
238 | out_err: | ||
239 | fi = NULL; | ||
246 | if (fibh->sbh != fibh->ebh) | 240 | if (fibh->sbh != fibh->ebh) |
247 | brelse(fibh->ebh); | 241 | brelse(fibh->ebh); |
248 | brelse(fibh->sbh); | 242 | brelse(fibh->sbh); |
243 | out_ok: | ||
249 | brelse(epos.bh); | 244 | brelse(epos.bh); |
245 | kfree(fname); | ||
250 | 246 | ||
251 | return NULL; | 247 | return fi; |
252 | } | 248 | } |
253 | 249 | ||
254 | static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, | 250 | static struct dentry *udf_lookup(struct inode *dir, struct dentry *dentry, |
@@ -303,7 +299,7 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
303 | { | 299 | { |
304 | struct super_block *sb = dir->i_sb; | 300 | struct super_block *sb = dir->i_sb; |
305 | struct fileIdentDesc *fi = NULL; | 301 | struct fileIdentDesc *fi = NULL; |
306 | char name[UDF_NAME_LEN]; | 302 | char *name = NULL; |
307 | int namelen; | 303 | int namelen; |
308 | loff_t f_pos; | 304 | loff_t f_pos; |
309 | loff_t size = udf_ext0_offset(dir) + dir->i_size; | 305 | loff_t size = udf_ext0_offset(dir) + dir->i_size; |
@@ -317,16 +313,23 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
317 | struct extent_position epos = {}; | 313 | struct extent_position epos = {}; |
318 | struct udf_inode_info *dinfo; | 314 | struct udf_inode_info *dinfo; |
319 | 315 | ||
316 | fibh->sbh = fibh->ebh = NULL; | ||
317 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
318 | if (!name) { | ||
319 | *err = -ENOMEM; | ||
320 | goto out_err; | ||
321 | } | ||
322 | |||
320 | if (dentry) { | 323 | if (dentry) { |
321 | if (!dentry->d_name.len) { | 324 | if (!dentry->d_name.len) { |
322 | *err = -EINVAL; | 325 | *err = -EINVAL; |
323 | return NULL; | 326 | goto out_err; |
324 | } | 327 | } |
325 | namelen = udf_put_filename(sb, dentry->d_name.name, name, | 328 | namelen = udf_put_filename(sb, dentry->d_name.name, name, |
326 | dentry->d_name.len); | 329 | dentry->d_name.len); |
327 | if (!namelen) { | 330 | if (!namelen) { |
328 | *err = -ENAMETOOLONG; | 331 | *err = -ENAMETOOLONG; |
329 | return NULL; | 332 | goto out_err; |
330 | } | 333 | } |
331 | } else { | 334 | } else { |
332 | namelen = 0; | 335 | namelen = 0; |
@@ -338,11 +341,14 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
338 | 341 | ||
339 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); | 342 | fibh->soffset = fibh->eoffset = f_pos & (dir->i_sb->s_blocksize - 1); |
340 | dinfo = UDF_I(dir); | 343 | dinfo = UDF_I(dir); |
341 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 344 | if (dinfo->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) { |
342 | fibh->sbh = fibh->ebh = NULL; | 345 | if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, &epos, |
343 | else if (inode_bmap(dir, f_pos >> dir->i_sb->s_blocksize_bits, | 346 | &eloc, &elen, &offset) != (EXT_RECORDED_ALLOCATED >> 30)) { |
344 | &epos, &eloc, &elen, &offset) == | 347 | block = udf_get_lb_pblock(dir->i_sb, |
345 | (EXT_RECORDED_ALLOCATED >> 30)) { | 348 | dinfo->i_location, 0); |
349 | fibh->soffset = fibh->eoffset = sb->s_blocksize; | ||
350 | goto add; | ||
351 | } | ||
346 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); | 352 | block = udf_get_lb_pblock(dir->i_sb, eloc, offset); |
347 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { | 353 | if ((++offset << dir->i_sb->s_blocksize_bits) < elen) { |
348 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) | 354 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT) |
@@ -354,17 +360,11 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
354 | 360 | ||
355 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); | 361 | fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block); |
356 | if (!fibh->sbh) { | 362 | if (!fibh->sbh) { |
357 | brelse(epos.bh); | ||
358 | *err = -EIO; | 363 | *err = -EIO; |
359 | return NULL; | 364 | goto out_err; |
360 | } | 365 | } |
361 | 366 | ||
362 | block = dinfo->i_location.logicalBlockNum; | 367 | block = dinfo->i_location.logicalBlockNum; |
363 | } else { | ||
364 | block = udf_get_lb_pblock(dir->i_sb, dinfo->i_location, 0); | ||
365 | fibh->sbh = fibh->ebh = NULL; | ||
366 | fibh->soffset = fibh->eoffset = sb->s_blocksize; | ||
367 | goto add; | ||
368 | } | 368 | } |
369 | 369 | ||
370 | while (f_pos < size) { | 370 | while (f_pos < size) { |
@@ -372,12 +372,8 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
372 | &elen, &offset); | 372 | &elen, &offset); |
373 | 373 | ||
374 | if (!fi) { | 374 | if (!fi) { |
375 | if (fibh->sbh != fibh->ebh) | ||
376 | brelse(fibh->ebh); | ||
377 | brelse(fibh->sbh); | ||
378 | brelse(epos.bh); | ||
379 | *err = -EIO; | 375 | *err = -EIO; |
380 | return NULL; | 376 | goto out_err; |
381 | } | 377 | } |
382 | 378 | ||
383 | liu = le16_to_cpu(cfi->lengthOfImpUse); | 379 | liu = le16_to_cpu(cfi->lengthOfImpUse); |
@@ -386,7 +382,6 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
386 | if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { | 382 | if ((cfi->fileCharacteristics & FID_FILE_CHAR_DELETED) != 0) { |
387 | if (((sizeof(struct fileIdentDesc) + | 383 | if (((sizeof(struct fileIdentDesc) + |
388 | liu + lfi + 3) & ~3) == nfidlen) { | 384 | liu + lfi + 3) & ~3) == nfidlen) { |
389 | brelse(epos.bh); | ||
390 | cfi->descTag.tagSerialNum = cpu_to_le16(1); | 385 | cfi->descTag.tagSerialNum = cpu_to_le16(1); |
391 | cfi->fileVersionNum = cpu_to_le16(1); | 386 | cfi->fileVersionNum = cpu_to_le16(1); |
392 | cfi->fileCharacteristics = 0; | 387 | cfi->fileCharacteristics = 0; |
@@ -394,10 +389,10 @@ static struct fileIdentDesc *udf_add_entry(struct inode *dir, | |||
394 | cfi->lengthOfImpUse = cpu_to_le16(0); | 389 | cfi->lengthOfImpUse = cpu_to_le16(0); |
395 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, | 390 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, |
396 | name)) | 391 | name)) |
397 | return fi; | 392 | goto out_ok; |
398 | else { | 393 | else { |
399 | *err = -EIO; | 394 | *err = -EIO; |
400 | return NULL; | 395 | goto out_err; |
401 | } | 396 | } |
402 | } | 397 | } |
403 | } | 398 | } |
@@ -427,7 +422,7 @@ add: | |||
427 | fibh->sbh = fibh->ebh = | 422 | fibh->sbh = fibh->ebh = |
428 | udf_expand_dir_adinicb(dir, &block, err); | 423 | udf_expand_dir_adinicb(dir, &block, err); |
429 | if (!fibh->sbh) | 424 | if (!fibh->sbh) |
430 | return NULL; | 425 | goto out_err; |
431 | epos.block = dinfo->i_location; | 426 | epos.block = dinfo->i_location; |
432 | epos.offset = udf_file_entry_alloc_offset(dir); | 427 | epos.offset = udf_file_entry_alloc_offset(dir); |
433 | /* Load extent udf_expand_dir_adinicb() has created */ | 428 | /* Load extent udf_expand_dir_adinicb() has created */ |
@@ -468,11 +463,8 @@ add: | |||
468 | dir->i_sb->s_blocksize_bits); | 463 | dir->i_sb->s_blocksize_bits); |
469 | fibh->ebh = udf_bread(dir, | 464 | fibh->ebh = udf_bread(dir, |
470 | f_pos >> dir->i_sb->s_blocksize_bits, 1, err); | 465 | f_pos >> dir->i_sb->s_blocksize_bits, 1, err); |
471 | if (!fibh->ebh) { | 466 | if (!fibh->ebh) |
472 | brelse(epos.bh); | 467 | goto out_err; |
473 | brelse(fibh->sbh); | ||
474 | return NULL; | ||
475 | } | ||
476 | 468 | ||
477 | if (!fibh->soffset) { | 469 | if (!fibh->soffset) { |
478 | if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == | 470 | if (udf_next_aext(dir, &epos, &eloc, &elen, 1) == |
@@ -503,20 +495,25 @@ add: | |||
503 | cfi->lengthFileIdent = namelen; | 495 | cfi->lengthFileIdent = namelen; |
504 | cfi->lengthOfImpUse = cpu_to_le16(0); | 496 | cfi->lengthOfImpUse = cpu_to_le16(0); |
505 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { | 497 | if (!udf_write_fi(dir, cfi, fi, fibh, NULL, name)) { |
506 | brelse(epos.bh); | ||
507 | dir->i_size += nfidlen; | 498 | dir->i_size += nfidlen; |
508 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) | 499 | if (dinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) |
509 | dinfo->i_lenAlloc += nfidlen; | 500 | dinfo->i_lenAlloc += nfidlen; |
510 | mark_inode_dirty(dir); | 501 | mark_inode_dirty(dir); |
511 | return fi; | 502 | goto out_ok; |
512 | } else { | 503 | } else { |
513 | brelse(epos.bh); | ||
514 | if (fibh->sbh != fibh->ebh) | ||
515 | brelse(fibh->ebh); | ||
516 | brelse(fibh->sbh); | ||
517 | *err = -EIO; | 504 | *err = -EIO; |
518 | return NULL; | 505 | goto out_err; |
519 | } | 506 | } |
507 | |||
508 | out_err: | ||
509 | fi = NULL; | ||
510 | if (fibh->sbh != fibh->ebh) | ||
511 | brelse(fibh->ebh); | ||
512 | brelse(fibh->sbh); | ||
513 | out_ok: | ||
514 | brelse(epos.bh); | ||
515 | kfree(name); | ||
516 | return fi; | ||
520 | } | 517 | } |
521 | 518 | ||
522 | static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, | 519 | static int udf_delete_entry(struct inode *inode, struct fileIdentDesc *fi, |
@@ -871,7 +868,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
871 | char *ea; | 868 | char *ea; |
872 | int err; | 869 | int err; |
873 | int block; | 870 | int block; |
874 | char name[UDF_NAME_LEN]; | 871 | char *name = NULL; |
875 | int namelen; | 872 | int namelen; |
876 | struct buffer_head *bh; | 873 | struct buffer_head *bh; |
877 | struct udf_inode_info *iinfo; | 874 | struct udf_inode_info *iinfo; |
@@ -881,6 +878,12 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
881 | if (!inode) | 878 | if (!inode) |
882 | goto out; | 879 | goto out; |
883 | 880 | ||
881 | name = kmalloc(UDF_NAME_LEN, GFP_NOFS); | ||
882 | if (!name) { | ||
883 | err = -ENOMEM; | ||
884 | goto out_no_entry; | ||
885 | } | ||
886 | |||
884 | iinfo = UDF_I(inode); | 887 | iinfo = UDF_I(inode); |
885 | inode->i_mode = S_IFLNK | S_IRWXUGO; | 888 | inode->i_mode = S_IFLNK | S_IRWXUGO; |
886 | inode->i_data.a_ops = &udf_symlink_aops; | 889 | inode->i_data.a_ops = &udf_symlink_aops; |
@@ -1020,6 +1023,7 @@ static int udf_symlink(struct inode *dir, struct dentry *dentry, | |||
1020 | err = 0; | 1023 | err = 0; |
1021 | 1024 | ||
1022 | out: | 1025 | out: |
1026 | kfree(name); | ||
1023 | unlock_kernel(); | 1027 | unlock_kernel(); |
1024 | return err; | 1028 | return err; |
1025 | 1029 | ||