Linux Audio

Check our new training course

Linux BSP development engineering services

Need help to port Linux and bootloaders to your hardware?
Loading...
v6.13.7
  1// SPDX-License-Identifier: GPL-2.0-only
  2/*
  3 * directory.c
  4 *
  5 * PURPOSE
  6 *	Directory related functions
  7 *
 
 
 
 
 
  8 */
  9
 10#include "udfdecl.h"
 11#include "udf_i.h"
 12
 13#include <linux/fs.h>
 14#include <linux/string.h>
 15#include <linux/bio.h>
 16#include <linux/crc-itu-t.h>
 17#include <linux/iversion.h>
 18
 19static int udf_verify_fi(struct udf_fileident_iter *iter)
 
 
 
 
 
 20{
 21	unsigned int len;
 
 
 
 22
 23	if (iter->fi.descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
 24		udf_err(iter->dir->i_sb,
 25			"directory (ino %lu) has entry at pos %llu with incorrect tag %x\n",
 26			iter->dir->i_ino, (unsigned long long)iter->pos,
 27			le16_to_cpu(iter->fi.descTag.tagIdent));
 28		return -EFSCORRUPTED;
 29	}
 30	len = udf_dir_entry_len(&iter->fi);
 31	if (le16_to_cpu(iter->fi.lengthOfImpUse) & 3) {
 32		udf_err(iter->dir->i_sb,
 33			"directory (ino %lu) has entry at pos %llu with unaligned length of impUse field\n",
 34			iter->dir->i_ino, (unsigned long long)iter->pos);
 35		return -EFSCORRUPTED;
 36	}
 37	/*
 38	 * This is in fact allowed by the spec due to long impUse field but
 39	 * we don't support it. If there is real media with this large impUse
 40	 * field, support can be added.
 41	 */
 42	if (len > 1 << iter->dir->i_blkbits) {
 43		udf_err(iter->dir->i_sb,
 44			"directory (ino %lu) has too big (%u) entry at pos %llu\n",
 45			iter->dir->i_ino, len, (unsigned long long)iter->pos);
 46		return -EFSCORRUPTED;
 47	}
 48	if (iter->pos + len > iter->dir->i_size) {
 49		udf_err(iter->dir->i_sb,
 50			"directory (ino %lu) has entry past directory size at pos %llu\n",
 51			iter->dir->i_ino, (unsigned long long)iter->pos);
 52		return -EFSCORRUPTED;
 53	}
 54	if (udf_dir_entry_len(&iter->fi) !=
 55	    sizeof(struct tag) + le16_to_cpu(iter->fi.descTag.descCRCLength)) {
 56		udf_err(iter->dir->i_sb,
 57			"directory (ino %lu) has entry where CRC length (%u) does not match entry length (%u)\n",
 58			iter->dir->i_ino,
 59			(unsigned)le16_to_cpu(iter->fi.descTag.descCRCLength),
 60			(unsigned)(udf_dir_entry_len(&iter->fi) -
 61							sizeof(struct tag)));
 62		return -EFSCORRUPTED;
 63	}
 64	return 0;
 65}
 66
 67static int udf_copy_fi(struct udf_fileident_iter *iter)
 68{
 69	struct udf_inode_info *iinfo = UDF_I(iter->dir);
 70	u32 blksize = 1 << iter->dir->i_blkbits;
 71	u32 off, len, nameoff;
 72	int err;
 73
 74	/* Skip copying when we are at EOF */
 75	if (iter->pos >= iter->dir->i_size) {
 76		iter->name = NULL;
 77		return 0;
 78	}
 79	if (iter->dir->i_size < iter->pos + sizeof(struct fileIdentDesc)) {
 80		udf_err(iter->dir->i_sb,
 81			"directory (ino %lu) has entry straddling EOF\n",
 82			iter->dir->i_ino);
 83		return -EFSCORRUPTED;
 84	}
 85	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
 86		memcpy(&iter->fi, iinfo->i_data + iinfo->i_lenEAttr + iter->pos,
 87		       sizeof(struct fileIdentDesc));
 88		err = udf_verify_fi(iter);
 89		if (err < 0)
 90			return err;
 91		iter->name = iinfo->i_data + iinfo->i_lenEAttr + iter->pos +
 92			sizeof(struct fileIdentDesc) +
 93			le16_to_cpu(iter->fi.lengthOfImpUse);
 94		return 0;
 95	}
 96
 97	off = iter->pos & (blksize - 1);
 98	len = min_t(u32, sizeof(struct fileIdentDesc), blksize - off);
 99	memcpy(&iter->fi, iter->bh[0]->b_data + off, len);
100	if (len < sizeof(struct fileIdentDesc))
101		memcpy((char *)(&iter->fi) + len, iter->bh[1]->b_data,
102		       sizeof(struct fileIdentDesc) - len);
103	err = udf_verify_fi(iter);
104	if (err < 0)
105		return err;
106
107	/* Handle directory entry name */
108	nameoff = off + sizeof(struct fileIdentDesc) +
109				le16_to_cpu(iter->fi.lengthOfImpUse);
110	if (off + udf_dir_entry_len(&iter->fi) <= blksize) {
111		iter->name = iter->bh[0]->b_data + nameoff;
112	} else if (nameoff >= blksize) {
113		iter->name = iter->bh[1]->b_data + (nameoff - blksize);
114	} else {
115		iter->name = iter->namebuf;
116		len = blksize - nameoff;
117		memcpy(iter->name, iter->bh[0]->b_data + nameoff, len);
118		memcpy(iter->name + len, iter->bh[1]->b_data,
119		       iter->fi.lengthFileIdent - len);
120	}
121	return 0;
122}
123
124/* Readahead 8k once we are at 8k boundary */
125static void udf_readahead_dir(struct udf_fileident_iter *iter)
126{
127	unsigned int ralen = 16 >> (iter->dir->i_blkbits - 9);
128	struct buffer_head *tmp, *bha[16];
129	int i, num;
130	udf_pblk_t blk;
131
132	if (iter->loffset & (ralen - 1))
133		return;
134
135	if (iter->loffset + ralen > (iter->elen >> iter->dir->i_blkbits))
136		ralen = (iter->elen >> iter->dir->i_blkbits) - iter->loffset;
137	num = 0;
138	for (i = 0; i < ralen; i++) {
139		blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc,
140					iter->loffset + i);
141		tmp = sb_getblk(iter->dir->i_sb, blk);
142		if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
143			bha[num++] = tmp;
144		else
145			brelse(tmp);
146	}
147	if (num) {
148		bh_readahead_batch(num, bha, REQ_RAHEAD);
149		for (i = 0; i < num; i++)
150			brelse(bha[i]);
151	}
152}
153
154static struct buffer_head *udf_fiiter_bread_blk(struct udf_fileident_iter *iter)
155{
156	udf_pblk_t blk;
157
158	udf_readahead_dir(iter);
159	blk = udf_get_lb_pblock(iter->dir->i_sb, &iter->eloc, iter->loffset);
160	return sb_bread(iter->dir->i_sb, blk);
161}
162
163/*
164 * Updates loffset to point to next directory block; eloc, elen & epos are
165 * updated if we need to traverse to the next extent as well.
166 */
167static int udf_fiiter_advance_blk(struct udf_fileident_iter *iter)
168{
169	int8_t etype = -1;
170	int err = 0;
171
172	iter->loffset++;
173	if (iter->loffset < DIV_ROUND_UP(iter->elen, 1<<iter->dir->i_blkbits))
174		return 0;
175
176	iter->loffset = 0;
177	err = udf_next_aext(iter->dir, &iter->epos, &iter->eloc,
178			    &iter->elen, &etype, 1);
179	if (err < 0)
180		return err;
181	else if (err == 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
182		if (iter->pos == iter->dir->i_size) {
183			iter->elen = 0;
184			return 0;
185		}
186		udf_err(iter->dir->i_sb,
187			"extent after position %llu not allocated in directory (ino %lu)\n",
188			(unsigned long long)iter->pos, iter->dir->i_ino);
189		return -EFSCORRUPTED;
190	}
191	return 0;
192}
193
194static int udf_fiiter_load_bhs(struct udf_fileident_iter *iter)
195{
196	int blksize = 1 << iter->dir->i_blkbits;
197	int off = iter->pos & (blksize - 1);
198	int err;
199	struct fileIdentDesc *fi;
200
201	/* Is there any further extent we can map from? */
202	if (!iter->bh[0] && iter->elen) {
203		iter->bh[0] = udf_fiiter_bread_blk(iter);
204		if (!iter->bh[0]) {
205			err = -ENOMEM;
206			goto out_brelse;
207		}
208		if (!buffer_uptodate(iter->bh[0])) {
209			err = -EIO;
210			goto out_brelse;
211		}
212	}
213	/* There's no next block so we are done */
214	if (iter->pos >= iter->dir->i_size)
215		return 0;
216	/* Need to fetch next block as well? */
217	if (off + sizeof(struct fileIdentDesc) > blksize)
218		goto fetch_next;
219	fi = (struct fileIdentDesc *)(iter->bh[0]->b_data + off);
220	/* Need to fetch next block to get name? */
221	if (off + udf_dir_entry_len(fi) > blksize) {
222fetch_next:
223		err = udf_fiiter_advance_blk(iter);
224		if (err)
225			goto out_brelse;
226		iter->bh[1] = udf_fiiter_bread_blk(iter);
227		if (!iter->bh[1]) {
228			err = -ENOMEM;
229			goto out_brelse;
230		}
231		if (!buffer_uptodate(iter->bh[1])) {
232			err = -EIO;
233			goto out_brelse;
234		}
 
 
 
235	}
236	return 0;
237out_brelse:
238	brelse(iter->bh[0]);
239	brelse(iter->bh[1]);
240	iter->bh[0] = iter->bh[1] = NULL;
241	return err;
242}
243
244int udf_fiiter_init(struct udf_fileident_iter *iter, struct inode *dir,
245		    loff_t pos)
246{
247	struct udf_inode_info *iinfo = UDF_I(dir);
248	int err = 0;
249	int8_t etype;
250
251	iter->dir = dir;
252	iter->bh[0] = iter->bh[1] = NULL;
253	iter->pos = pos;
254	iter->elen = 0;
255	iter->epos.bh = NULL;
256	iter->name = NULL;
257	/*
258	 * When directory is verified, we don't expect directory iteration to
259	 * fail and it can be difficult to undo without corrupting filesystem.
260	 * So just do not allow memory allocation failures here.
261	 */
262	iter->namebuf = kmalloc(UDF_NAME_LEN_CS0, GFP_KERNEL | __GFP_NOFAIL);
263
264	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
265		err = udf_copy_fi(iter);
266		goto out;
267	}
268
269	err = inode_bmap(dir, iter->pos >> dir->i_blkbits, &iter->epos,
270			 &iter->eloc, &iter->elen, &iter->loffset, &etype);
271	if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
272		if (pos == dir->i_size)
273			return 0;
274		udf_err(dir->i_sb,
275			"position %llu not allocated in directory (ino %lu)\n",
276			(unsigned long long)pos, dir->i_ino);
277		err = -EFSCORRUPTED;
278		goto out;
279	}
280	err = udf_fiiter_load_bhs(iter);
281	if (err < 0)
282		goto out;
283	err = udf_copy_fi(iter);
284out:
285	if (err < 0)
286		udf_fiiter_release(iter);
287	return err;
288}
289
290int udf_fiiter_advance(struct udf_fileident_iter *iter)
291{
292	unsigned int oldoff, len;
293	int blksize = 1 << iter->dir->i_blkbits;
294	int err;
295
296	oldoff = iter->pos & (blksize - 1);
297	len = udf_dir_entry_len(&iter->fi);
298	iter->pos += len;
299	if (UDF_I(iter->dir)->i_alloc_type != ICBTAG_FLAG_AD_IN_ICB) {
300		if (oldoff + len >= blksize) {
301			brelse(iter->bh[0]);
302			iter->bh[0] = NULL;
303			/* Next block already loaded? */
304			if (iter->bh[1]) {
305				iter->bh[0] = iter->bh[1];
306				iter->bh[1] = NULL;
307			} else {
308				err = udf_fiiter_advance_blk(iter);
309				if (err < 0)
310					return err;
311			}
312		}
313		err = udf_fiiter_load_bhs(iter);
314		if (err < 0)
315			return err;
316	}
317	return udf_copy_fi(iter);
318}
319
320void udf_fiiter_release(struct udf_fileident_iter *iter)
321{
322	iter->dir = NULL;
323	brelse(iter->bh[0]);
324	brelse(iter->bh[1]);
325	iter->bh[0] = iter->bh[1] = NULL;
326	kfree(iter->namebuf);
327	iter->namebuf = NULL;
328}
329
330static void udf_copy_to_bufs(void *buf1, int len1, void *buf2, int len2,
331			     int off, void *src, int len)
332{
333	int copy;
334
335	if (off >= len1) {
336		off -= len1;
337	} else {
338		copy = min(off + len, len1) - off;
339		memcpy(buf1 + off, src, copy);
340		src += copy;
341		len -= copy;
342		off = 0;
343	}
344	if (len > 0) {
345		if (WARN_ON_ONCE(off + len > len2 || !buf2))
346			return;
347		memcpy(buf2 + off, src, len);
348	}
349}
350
351static uint16_t udf_crc_fi_bufs(void *buf1, int len1, void *buf2, int len2,
352				int off, int len)
353{
354	int copy;
355	uint16_t crc = 0;
356
357	if (off >= len1) {
358		off -= len1;
359	} else {
360		copy = min(off + len, len1) - off;
361		crc = crc_itu_t(crc, buf1 + off, copy);
362		len -= copy;
363		off = 0;
364	}
365	if (len > 0) {
366		if (WARN_ON_ONCE(off + len > len2 || !buf2))
367			return 0;
368		crc = crc_itu_t(crc, buf2 + off, len);
369	}
370	return crc;
371}
372
373static void udf_copy_fi_to_bufs(char *buf1, int len1, char *buf2, int len2,
374				int off, struct fileIdentDesc *fi,
375				uint8_t *impuse, uint8_t *name)
376{
377	uint16_t crc;
378	int fioff = off;
379	int crcoff = off + sizeof(struct tag);
380	unsigned int crclen = udf_dir_entry_len(fi) - sizeof(struct tag);
381	char zeros[UDF_NAME_PAD] = {};
382	int endoff = off + udf_dir_entry_len(fi);
383
384	udf_copy_to_bufs(buf1, len1, buf2, len2, off, fi,
385			 sizeof(struct fileIdentDesc));
386	off += sizeof(struct fileIdentDesc);
387	if (impuse)
388		udf_copy_to_bufs(buf1, len1, buf2, len2, off, impuse,
389				 le16_to_cpu(fi->lengthOfImpUse));
390	off += le16_to_cpu(fi->lengthOfImpUse);
391	if (name) {
392		udf_copy_to_bufs(buf1, len1, buf2, len2, off, name,
393				 fi->lengthFileIdent);
394		off += fi->lengthFileIdent;
395		udf_copy_to_bufs(buf1, len1, buf2, len2, off, zeros,
396				 endoff - off);
397	}
398
399	crc = udf_crc_fi_bufs(buf1, len1, buf2, len2, crcoff, crclen);
400	fi->descTag.descCRC = cpu_to_le16(crc);
401	fi->descTag.descCRCLength = cpu_to_le16(crclen);
402	fi->descTag.tagChecksum = udf_tag_checksum(&fi->descTag);
403
404	udf_copy_to_bufs(buf1, len1, buf2, len2, fioff, fi, sizeof(struct tag));
405}
 
 
406
407void udf_fiiter_write_fi(struct udf_fileident_iter *iter, uint8_t *impuse)
408{
409	struct udf_inode_info *iinfo = UDF_I(iter->dir);
410	void *buf1, *buf2 = NULL;
411	int len1, len2 = 0, off;
412	int blksize = 1 << iter->dir->i_blkbits;
413
414	off = iter->pos & (blksize - 1);
415	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
416		buf1 = iinfo->i_data + iinfo->i_lenEAttr;
417		len1 = iter->dir->i_size;
418	} else {
419		buf1 = iter->bh[0]->b_data;
420		len1 = blksize;
421		if (iter->bh[1]) {
422			buf2 = iter->bh[1]->b_data;
423			len2 = blksize;
424		}
425	}
426
427	udf_copy_fi_to_bufs(buf1, len1, buf2, len2, off, &iter->fi, impuse,
428			    iter->name == iter->namebuf ? iter->name : NULL);
429
430	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
431		mark_inode_dirty(iter->dir);
432	} else {
433		mark_buffer_dirty_inode(iter->bh[0], iter->dir);
434		if (iter->bh[1])
435			mark_buffer_dirty_inode(iter->bh[1], iter->dir);
436	}
437	inode_inc_iversion(iter->dir);
438}
439
440void udf_fiiter_update_elen(struct udf_fileident_iter *iter, uint32_t new_elen)
441{
442	struct udf_inode_info *iinfo = UDF_I(iter->dir);
443	int diff = new_elen - iter->elen;
444
445	/* Skip update when we already went past the last extent */
446	if (!iter->elen)
447		return;
448	iter->elen = new_elen;
449	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_SHORT)
450		iter->epos.offset -= sizeof(struct short_ad);
451	else if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_LONG)
452		iter->epos.offset -= sizeof(struct long_ad);
453	udf_write_aext(iter->dir, &iter->epos, &iter->eloc, iter->elen, 1);
454	iinfo->i_lenExtents += diff;
455	mark_inode_dirty(iter->dir);
456}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
457
458/* Append new block to directory. @iter is expected to point at EOF */
459int udf_fiiter_append_blk(struct udf_fileident_iter *iter)
460{
461	struct udf_inode_info *iinfo = UDF_I(iter->dir);
462	int blksize = 1 << iter->dir->i_blkbits;
463	struct buffer_head *bh;
464	sector_t block;
465	uint32_t old_elen = iter->elen;
466	int err;
467	int8_t etype;
468
469	if (WARN_ON_ONCE(iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB))
470		return -EINVAL;
471
472	/* Round up last extent in the file */
473	udf_fiiter_update_elen(iter, ALIGN(iter->elen, blksize));
474
475	/* Allocate new block and refresh mapping information */
476	block = iinfo->i_lenExtents >> iter->dir->i_blkbits;
477	bh = udf_bread(iter->dir, block, 1, &err);
478	if (!bh) {
479		udf_fiiter_update_elen(iter, old_elen);
480		return err;
481	}
482	err = inode_bmap(iter->dir, block, &iter->epos, &iter->eloc, &iter->elen,
483		   &iter->loffset, &etype);
484	if (err <= 0 || etype != (EXT_RECORDED_ALLOCATED >> 30)) {
485		udf_err(iter->dir->i_sb,
486			"block %llu not allocated in directory (ino %lu)\n",
487			(unsigned long long)block, iter->dir->i_ino);
488		return -EFSCORRUPTED;
489	}
490	if (!(iter->pos & (blksize - 1))) {
491		brelse(iter->bh[0]);
492		iter->bh[0] = bh;
493	} else {
494		iter->bh[1] = bh;
495	}
496	return 0;
497}
498
499struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
500			      int inc)
501{
502	struct short_ad *sa;
503
504	if ((!ptr) || (!offset)) {
505		pr_err("%s: invalidparms\n", __func__);
506		return NULL;
507	}
508
509	if ((*offset + sizeof(struct short_ad)) > maxoffset)
510		return NULL;
511	else {
512		sa = (struct short_ad *)ptr;
513		if (sa->extLength == 0)
514			return NULL;
515	}
516
517	if (inc)
518		*offset += sizeof(struct short_ad);
519	return sa;
520}
521
522struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
523{
524	struct long_ad *la;
525
526	if ((!ptr) || (!offset)) {
527		pr_err("%s: invalidparms\n", __func__);
528		return NULL;
529	}
530
531	if ((*offset + sizeof(struct long_ad)) > maxoffset)
532		return NULL;
533	else {
534		la = (struct long_ad *)ptr;
535		if (la->extLength == 0)
536			return NULL;
537	}
538
539	if (inc)
540		*offset += sizeof(struct long_ad);
541	return la;
542}
v4.6
 
  1/*
  2 * directory.c
  3 *
  4 * PURPOSE
  5 *	Directory related functions
  6 *
  7 * COPYRIGHT
  8 *	This file is distributed under the terms of the GNU General Public
  9 *	License (GPL). Copies of the GPL can be obtained from:
 10 *		ftp://prep.ai.mit.edu/pub/gnu/GPL
 11 *	Each contributing author retains all rights to their own work.
 12 */
 13
 14#include "udfdecl.h"
 15#include "udf_i.h"
 16
 17#include <linux/fs.h>
 18#include <linux/string.h>
 
 
 
 19
 20struct fileIdentDesc *udf_fileident_read(struct inode *dir, loff_t *nf_pos,
 21					 struct udf_fileident_bh *fibh,
 22					 struct fileIdentDesc *cfi,
 23					 struct extent_position *epos,
 24					 struct kernel_lb_addr *eloc, uint32_t *elen,
 25					 sector_t *offset)
 26{
 27	struct fileIdentDesc *fi;
 28	int i, num, block;
 29	struct buffer_head *tmp, *bha[16];
 30	struct udf_inode_info *iinfo = UDF_I(dir);
 31
 32	fibh->soffset = fibh->eoffset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 33
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 34	if (iinfo->i_alloc_type == ICBTAG_FLAG_AD_IN_ICB) {
 35		fi = udf_get_fileident(iinfo->i_ext.i_data -
 36				       (iinfo->i_efe ?
 37					sizeof(struct extendedFileEntry) :
 38					sizeof(struct fileEntry)),
 39				       dir->i_sb->s_blocksize,
 40				       &(fibh->eoffset));
 41		if (!fi)
 42			return NULL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 43
 44		*nf_pos += fibh->eoffset - fibh->soffset;
 
 
 
 
 
 
 45
 46		memcpy((uint8_t *)cfi, (uint8_t *)fi,
 47		       sizeof(struct fileIdentDesc));
 48
 49		return fi;
 
 
 
 
 
 
 
 
 
 
 50	}
 
 
 
 
 
 
 51
 52	if (fibh->eoffset == dir->i_sb->s_blocksize) {
 53		int lextoffset = epos->offset;
 54		unsigned char blocksize_bits = dir->i_sb->s_blocksize_bits;
 55
 56		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
 57		    (EXT_RECORDED_ALLOCATED >> 30))
 58			return NULL;
 
 59
 60		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
 
 
 
 
 
 
 
 61
 62		(*offset)++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 63
 64		if ((*offset << blocksize_bits) >= *elen)
 65			*offset = 0;
 66		else
 67			epos->offset = lextoffset;
 
 
 68
 69		brelse(fibh->sbh);
 70		fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block);
 71		if (!fibh->sbh)
 72			return NULL;
 73		fibh->soffset = fibh->eoffset = 0;
 74
 75		if (!(*offset & ((16 >> (blocksize_bits - 9)) - 1))) {
 76			i = 16 >> (blocksize_bits - 9);
 77			if (i + *offset > (*elen >> blocksize_bits))
 78				i = (*elen >> blocksize_bits)-*offset;
 79			for (num = 0; i > 0; i--) {
 80				block = udf_get_lb_pblock(dir->i_sb, eloc,
 81							  *offset + i);
 82				tmp = udf_tgetblk(dir->i_sb, block);
 83				if (tmp && !buffer_uptodate(tmp) &&
 84						!buffer_locked(tmp))
 85					bha[num++] = tmp;
 86				else
 87					brelse(tmp);
 88			}
 89			if (num) {
 90				ll_rw_block(READA, num, bha);
 91				for (i = 0; i < num; i++)
 92					brelse(bha[i]);
 93			}
 
 
 
 
 
 
 
 
 94		}
 95	} else if (fibh->sbh != fibh->ebh) {
 96		brelse(fibh->sbh);
 97		fibh->sbh = fibh->ebh;
 98	}
 
 
 
 
 
 
 
 99
100	fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
101			       &(fibh->eoffset));
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
102
103	if (!fi)
104		return NULL;
 
 
105
106	*nf_pos += fibh->eoffset - fibh->soffset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
108	if (fibh->eoffset <= dir->i_sb->s_blocksize) {
109		memcpy((uint8_t *)cfi, (uint8_t *)fi,
110		       sizeof(struct fileIdentDesc));
111	} else if (fibh->eoffset > dir->i_sb->s_blocksize) {
112		int lextoffset = epos->offset;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
113
114		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
115		    (EXT_RECORDED_ALLOCATED >> 30))
116			return NULL;
 
 
 
 
 
 
117
118		block = udf_get_lb_pblock(dir->i_sb, eloc, *offset);
 
 
 
119
120		(*offset)++;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
121
122		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
123			*offset = 0;
124		else
125			epos->offset = lextoffset;
 
126
127		fibh->soffset -= dir->i_sb->s_blocksize;
128		fibh->eoffset -= dir->i_sb->s_blocksize;
 
 
 
 
 
 
 
 
 
 
 
 
 
129
130		fibh->ebh = udf_tread(dir->i_sb, block);
131		if (!fibh->ebh)
132			return NULL;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
133
134		if (sizeof(struct fileIdentDesc) > -fibh->soffset) {
135			int fi_len;
 
 
136
137			memcpy((uint8_t *)cfi, (uint8_t *)fi, -fibh->soffset);
138			memcpy((uint8_t *)cfi - fibh->soffset,
139			       fibh->ebh->b_data,
140			       sizeof(struct fileIdentDesc) + fibh->soffset);
141
142			fi_len = (sizeof(struct fileIdentDesc) +
143				  cfi->lengthFileIdent +
144				  le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
 
 
 
145
146			*nf_pos += fi_len - (fibh->eoffset - fibh->soffset);
147			fibh->eoffset = fibh->soffset + fi_len;
148		} else {
149			memcpy((uint8_t *)cfi, (uint8_t *)fi,
150			       sizeof(struct fileIdentDesc));
 
 
 
 
 
151		}
152	}
153	return fi;
 
 
 
 
 
 
 
 
 
 
 
154}
155
156struct fileIdentDesc *udf_get_fileident(void *buffer, int bufsize, int *offset)
157{
158	struct fileIdentDesc *fi;
159	int lengthThisIdent;
160	uint8_t *ptr;
161	int padlen;
162
163	if ((!buffer) || (!offset)) {
164		udf_debug("invalidparms, buffer=%p, offset=%p\n",
165			  buffer, offset);
166		return NULL;
167	}
168
169	ptr = buffer;
170
171	if ((*offset > 0) && (*offset < bufsize))
172		ptr += *offset;
173	fi = (struct fileIdentDesc *)ptr;
174	if (fi->descTag.tagIdent != cpu_to_le16(TAG_IDENT_FID)) {
175		udf_debug("0x%x != TAG_IDENT_FID\n",
176			  le16_to_cpu(fi->descTag.tagIdent));
177		udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
178			  *offset, (unsigned long)sizeof(struct fileIdentDesc),
179			  bufsize);
180		return NULL;
181	}
182	if ((*offset + sizeof(struct fileIdentDesc)) > bufsize)
183		lengthThisIdent = sizeof(struct fileIdentDesc);
184	else
185		lengthThisIdent = sizeof(struct fileIdentDesc) +
186			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
187
188	/* we need to figure padding, too! */
189	padlen = lengthThisIdent % UDF_NAME_PAD;
190	if (padlen)
191		lengthThisIdent += (UDF_NAME_PAD - padlen);
192	*offset = *offset + lengthThisIdent;
193
194	return fi;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
195}
196
197struct short_ad *udf_get_fileshortad(uint8_t *ptr, int maxoffset, uint32_t *offset,
198			      int inc)
199{
200	struct short_ad *sa;
201
202	if ((!ptr) || (!offset)) {
203		pr_err("%s: invalidparms\n", __func__);
204		return NULL;
205	}
206
207	if ((*offset + sizeof(struct short_ad)) > maxoffset)
208		return NULL;
209	else {
210		sa = (struct short_ad *)ptr;
211		if (sa->extLength == 0)
212			return NULL;
213	}
214
215	if (inc)
216		*offset += sizeof(struct short_ad);
217	return sa;
218}
219
220struct long_ad *udf_get_filelongad(uint8_t *ptr, int maxoffset, uint32_t *offset, int inc)
221{
222	struct long_ad *la;
223
224	if ((!ptr) || (!offset)) {
225		pr_err("%s: invalidparms\n", __func__);
226		return NULL;
227	}
228
229	if ((*offset + sizeof(struct long_ad)) > maxoffset)
230		return NULL;
231	else {
232		la = (struct long_ad *)ptr;
233		if (la->extLength == 0)
234			return NULL;
235	}
236
237	if (inc)
238		*offset += sizeof(struct long_ad);
239	return la;
240}