xref: /openbmc/linux/fs/udf/directory.c (revision 3bf25cb40d899eeb5a471f497e56ddfe2c96c019)
11da177e4SLinus Torvalds /*
21da177e4SLinus Torvalds  * directory.c
31da177e4SLinus Torvalds  *
41da177e4SLinus Torvalds  * PURPOSE
51da177e4SLinus Torvalds  *	Directory related functions
61da177e4SLinus Torvalds  *
71da177e4SLinus Torvalds  * COPYRIGHT
81da177e4SLinus Torvalds  *	This file is distributed under the terms of the GNU General Public
91da177e4SLinus Torvalds  *	License (GPL). Copies of the GPL can be obtained from:
101da177e4SLinus Torvalds  *		ftp://prep.ai.mit.edu/pub/gnu/GPL
111da177e4SLinus Torvalds  *	Each contributing author retains all rights to their own work.
121da177e4SLinus Torvalds  */
131da177e4SLinus Torvalds 
141da177e4SLinus Torvalds #include "udfdecl.h"
151da177e4SLinus Torvalds #include "udf_i.h"
161da177e4SLinus Torvalds 
171da177e4SLinus Torvalds #include <linux/fs.h>
181da177e4SLinus Torvalds #include <linux/string.h>
191da177e4SLinus Torvalds #include <linux/buffer_head.h>
201da177e4SLinus Torvalds 
211da177e4SLinus Torvalds #if 0
221da177e4SLinus Torvalds static uint8_t *
231da177e4SLinus Torvalds udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
241da177e4SLinus Torvalds 		kernel_lb_addr fe_loc, int *pos, int *offset,
251da177e4SLinus Torvalds 		struct buffer_head **bh, int *error)
261da177e4SLinus Torvalds {
271da177e4SLinus Torvalds 	int loffset = *offset;
281da177e4SLinus Torvalds 	int block;
291da177e4SLinus Torvalds 	uint8_t *ad;
301da177e4SLinus Torvalds 	int remainder;
311da177e4SLinus Torvalds 
321da177e4SLinus Torvalds 	*error = 0;
331da177e4SLinus Torvalds 
341da177e4SLinus Torvalds 	ad = (uint8_t *)(*bh)->b_data + *offset;
351da177e4SLinus Torvalds 	*offset += ad_size;
361da177e4SLinus Torvalds 
371da177e4SLinus Torvalds 	if (!ad)
381da177e4SLinus Torvalds 	{
39*3bf25cb4SJan Kara 		brelse(*bh);
401da177e4SLinus Torvalds 		*error = 1;
411da177e4SLinus Torvalds 		return NULL;
421da177e4SLinus Torvalds 	}
431da177e4SLinus Torvalds 
441da177e4SLinus Torvalds 	if (*offset == dir->i_sb->s_blocksize)
451da177e4SLinus Torvalds 	{
46*3bf25cb4SJan Kara 		brelse(*bh);
471da177e4SLinus Torvalds 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
481da177e4SLinus Torvalds 		if (!block)
491da177e4SLinus Torvalds 			return NULL;
501da177e4SLinus Torvalds 		if (!(*bh = udf_tread(dir->i_sb, block)))
511da177e4SLinus Torvalds 			return NULL;
521da177e4SLinus Torvalds 	}
531da177e4SLinus Torvalds 	else if (*offset > dir->i_sb->s_blocksize)
541da177e4SLinus Torvalds 	{
551da177e4SLinus Torvalds 		ad = tmpad;
561da177e4SLinus Torvalds 
571da177e4SLinus Torvalds 		remainder = dir->i_sb->s_blocksize - loffset;
581da177e4SLinus Torvalds 		memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
591da177e4SLinus Torvalds 
60*3bf25cb4SJan Kara 		brelse(*bh);
611da177e4SLinus Torvalds 		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
621da177e4SLinus Torvalds 		if (!block)
631da177e4SLinus Torvalds 			return NULL;
641da177e4SLinus Torvalds 		if (!((*bh) = udf_tread(dir->i_sb, block)))
651da177e4SLinus Torvalds 			return NULL;
661da177e4SLinus Torvalds 
671da177e4SLinus Torvalds 		memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
681da177e4SLinus Torvalds 		*offset = ad_size - remainder;
691da177e4SLinus Torvalds 	}
701da177e4SLinus Torvalds 	return ad;
711da177e4SLinus Torvalds }
721da177e4SLinus Torvalds #endif
731da177e4SLinus Torvalds 
741da177e4SLinus Torvalds struct fileIdentDesc *
751da177e4SLinus Torvalds udf_fileident_read(struct inode *dir, loff_t *nf_pos,
761da177e4SLinus Torvalds 	struct udf_fileident_bh *fibh,
771da177e4SLinus Torvalds 	struct fileIdentDesc *cfi,
78ff116fc8SJan Kara 	struct extent_position *epos,
791da177e4SLinus Torvalds 	kernel_lb_addr *eloc, uint32_t *elen,
80ff116fc8SJan Kara 	sector_t *offset)
811da177e4SLinus Torvalds {
821da177e4SLinus Torvalds 	struct fileIdentDesc *fi;
831da177e4SLinus Torvalds 	int i, num, block;
841da177e4SLinus Torvalds 	struct buffer_head * tmp, * bha[16];
851da177e4SLinus Torvalds 
861da177e4SLinus Torvalds 	fibh->soffset = fibh->eoffset;
871da177e4SLinus Torvalds 
881da177e4SLinus Torvalds 	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
891da177e4SLinus Torvalds 	{
901da177e4SLinus Torvalds 		fi = udf_get_fileident(UDF_I_DATA(dir) -
911da177e4SLinus Torvalds 			(UDF_I_EFE(dir) ?
921da177e4SLinus Torvalds 				sizeof(struct extendedFileEntry) :
931da177e4SLinus Torvalds 				sizeof(struct fileEntry)),
941da177e4SLinus Torvalds 			dir->i_sb->s_blocksize, &(fibh->eoffset));
951da177e4SLinus Torvalds 
961da177e4SLinus Torvalds 		if (!fi)
971da177e4SLinus Torvalds 			return NULL;
981da177e4SLinus Torvalds 
991da177e4SLinus Torvalds 		*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
1001da177e4SLinus Torvalds 
1011da177e4SLinus Torvalds 		memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
1021da177e4SLinus Torvalds 
1031da177e4SLinus Torvalds 		return fi;
1041da177e4SLinus Torvalds 	}
1051da177e4SLinus Torvalds 
1061da177e4SLinus Torvalds 	if (fibh->eoffset == dir->i_sb->s_blocksize)
1071da177e4SLinus Torvalds 	{
108ff116fc8SJan Kara 		int lextoffset = epos->offset;
1091da177e4SLinus Torvalds 
110ff116fc8SJan Kara 		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
1111da177e4SLinus Torvalds 			(EXT_RECORDED_ALLOCATED >> 30))
1121da177e4SLinus Torvalds 			return NULL;
1131da177e4SLinus Torvalds 
1141da177e4SLinus Torvalds 		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
1151da177e4SLinus Torvalds 
1161da177e4SLinus Torvalds 		(*offset) ++;
1171da177e4SLinus Torvalds 
1181da177e4SLinus Torvalds 		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
1191da177e4SLinus Torvalds 			*offset = 0;
1201da177e4SLinus Torvalds 		else
121ff116fc8SJan Kara 			epos->offset = lextoffset;
1221da177e4SLinus Torvalds 
123*3bf25cb4SJan Kara 		brelse(fibh->sbh);
1241da177e4SLinus Torvalds 		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
1251da177e4SLinus Torvalds 			return NULL;
1261da177e4SLinus Torvalds 		fibh->soffset = fibh->eoffset = 0;
1271da177e4SLinus Torvalds 
1281da177e4SLinus Torvalds 		if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
1291da177e4SLinus Torvalds 		{
1301da177e4SLinus Torvalds 			i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
1311da177e4SLinus Torvalds 			if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
1321da177e4SLinus Torvalds 				i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
1331da177e4SLinus Torvalds 			for (num=0; i>0; i--)
1341da177e4SLinus Torvalds 			{
1351da177e4SLinus Torvalds 				block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
1361da177e4SLinus Torvalds 				tmp = udf_tgetblk(dir->i_sb, block);
1371da177e4SLinus Torvalds 				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
1381da177e4SLinus Torvalds 					bha[num++] = tmp;
1391da177e4SLinus Torvalds 				else
1401da177e4SLinus Torvalds 					brelse(tmp);
1411da177e4SLinus Torvalds 			}
1421da177e4SLinus Torvalds 			if (num)
1431da177e4SLinus Torvalds 			{
1441da177e4SLinus Torvalds 				ll_rw_block(READA, num, bha);
1451da177e4SLinus Torvalds 				for (i=0; i<num; i++)
1461da177e4SLinus Torvalds 					brelse(bha[i]);
1471da177e4SLinus Torvalds 			}
1481da177e4SLinus Torvalds 		}
1491da177e4SLinus Torvalds 	}
1501da177e4SLinus Torvalds 	else if (fibh->sbh != fibh->ebh)
1511da177e4SLinus Torvalds 	{
152*3bf25cb4SJan Kara 		brelse(fibh->sbh);
1531da177e4SLinus Torvalds 		fibh->sbh = fibh->ebh;
1541da177e4SLinus Torvalds 	}
1551da177e4SLinus Torvalds 
1561da177e4SLinus Torvalds 	fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
1571da177e4SLinus Torvalds 		&(fibh->eoffset));
1581da177e4SLinus Torvalds 
1591da177e4SLinus Torvalds 	if (!fi)
1601da177e4SLinus Torvalds 		return NULL;
1611da177e4SLinus Torvalds 
1621da177e4SLinus Torvalds 	*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
1631da177e4SLinus Torvalds 
1641da177e4SLinus Torvalds 	if (fibh->eoffset <= dir->i_sb->s_blocksize)
1651da177e4SLinus Torvalds 	{
1661da177e4SLinus Torvalds 		memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
1671da177e4SLinus Torvalds 	}
1681da177e4SLinus Torvalds 	else if (fibh->eoffset > dir->i_sb->s_blocksize)
1691da177e4SLinus Torvalds 	{
170ff116fc8SJan Kara 		int lextoffset = epos->offset;
1711da177e4SLinus Torvalds 
172ff116fc8SJan Kara 		if (udf_next_aext(dir, epos, eloc, elen, 1) !=
1731da177e4SLinus Torvalds 			(EXT_RECORDED_ALLOCATED >> 30))
1741da177e4SLinus Torvalds 			return NULL;
1751da177e4SLinus Torvalds 
1761da177e4SLinus Torvalds 		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
1771da177e4SLinus Torvalds 
1781da177e4SLinus Torvalds 		(*offset) ++;
1791da177e4SLinus Torvalds 
1801da177e4SLinus Torvalds 		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
1811da177e4SLinus Torvalds 			*offset = 0;
1821da177e4SLinus Torvalds 		else
183ff116fc8SJan Kara 			epos->offset = lextoffset;
1841da177e4SLinus Torvalds 
1851da177e4SLinus Torvalds 		fibh->soffset -= dir->i_sb->s_blocksize;
1861da177e4SLinus Torvalds 		fibh->eoffset -= dir->i_sb->s_blocksize;
1871da177e4SLinus Torvalds 
1881da177e4SLinus Torvalds 		if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
1891da177e4SLinus Torvalds 			return NULL;
1901da177e4SLinus Torvalds 
1911da177e4SLinus Torvalds 		if (sizeof(struct fileIdentDesc) > - fibh->soffset)
1921da177e4SLinus Torvalds 		{
1931da177e4SLinus Torvalds 			int fi_len;
1941da177e4SLinus Torvalds 
1951da177e4SLinus Torvalds 			memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
1961da177e4SLinus Torvalds 			memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
1971da177e4SLinus Torvalds 				sizeof(struct fileIdentDesc) + fibh->soffset);
1981da177e4SLinus Torvalds 
1991da177e4SLinus Torvalds 			fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
2001da177e4SLinus Torvalds 				le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
2011da177e4SLinus Torvalds 
2021da177e4SLinus Torvalds 			*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
2031da177e4SLinus Torvalds 			fibh->eoffset = fibh->soffset + fi_len;
2041da177e4SLinus Torvalds 		}
2051da177e4SLinus Torvalds 		else
2061da177e4SLinus Torvalds 		{
2071da177e4SLinus Torvalds 			memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
2081da177e4SLinus Torvalds 		}
2091da177e4SLinus Torvalds 	}
2101da177e4SLinus Torvalds 	return fi;
2111da177e4SLinus Torvalds }
2121da177e4SLinus Torvalds 
2131da177e4SLinus Torvalds struct fileIdentDesc *
2141da177e4SLinus Torvalds udf_get_fileident(void * buffer, int bufsize, int * offset)
2151da177e4SLinus Torvalds {
2161da177e4SLinus Torvalds 	struct fileIdentDesc *fi;
2171da177e4SLinus Torvalds 	int lengthThisIdent;
2181da177e4SLinus Torvalds 	uint8_t * ptr;
2191da177e4SLinus Torvalds 	int padlen;
2201da177e4SLinus Torvalds 
2211da177e4SLinus Torvalds 	if ( (!buffer) || (!offset) ) {
2221da177e4SLinus Torvalds 		udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
2231da177e4SLinus Torvalds 		return NULL;
2241da177e4SLinus Torvalds 	}
2251da177e4SLinus Torvalds 
2261da177e4SLinus Torvalds 	ptr = buffer;
2271da177e4SLinus Torvalds 
2281da177e4SLinus Torvalds 	if ( (*offset > 0) && (*offset < bufsize) ) {
2291da177e4SLinus Torvalds 		ptr += *offset;
2301da177e4SLinus Torvalds 	}
2311da177e4SLinus Torvalds 	fi=(struct fileIdentDesc *)ptr;
2321da177e4SLinus Torvalds 	if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
2331da177e4SLinus Torvalds 	{
2341da177e4SLinus Torvalds 		udf_debug("0x%x != TAG_IDENT_FID\n",
2351da177e4SLinus Torvalds 			le16_to_cpu(fi->descTag.tagIdent));
2361da177e4SLinus Torvalds 		udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
2371da177e4SLinus Torvalds 			*offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
2381da177e4SLinus Torvalds 		return NULL;
2391da177e4SLinus Torvalds 	}
2401da177e4SLinus Torvalds 	if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
2411da177e4SLinus Torvalds 	{
2421da177e4SLinus Torvalds 		lengthThisIdent = sizeof(struct fileIdentDesc);
2431da177e4SLinus Torvalds 	}
2441da177e4SLinus Torvalds 	else
2451da177e4SLinus Torvalds 		lengthThisIdent = sizeof(struct fileIdentDesc) +
2461da177e4SLinus Torvalds 			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
2471da177e4SLinus Torvalds 
2481da177e4SLinus Torvalds 	/* we need to figure padding, too! */
2491da177e4SLinus Torvalds 	padlen = lengthThisIdent % UDF_NAME_PAD;
2501da177e4SLinus Torvalds 	if (padlen)
2511da177e4SLinus Torvalds 		lengthThisIdent += (UDF_NAME_PAD - padlen);
2521da177e4SLinus Torvalds 	*offset = *offset + lengthThisIdent;
2531da177e4SLinus Torvalds 
2541da177e4SLinus Torvalds 	return fi;
2551da177e4SLinus Torvalds }
2561da177e4SLinus Torvalds 
2571da177e4SLinus Torvalds #if 0
2581da177e4SLinus Torvalds static extent_ad *
2591da177e4SLinus Torvalds udf_get_fileextent(void * buffer, int bufsize, int * offset)
2601da177e4SLinus Torvalds {
2611da177e4SLinus Torvalds 	extent_ad * ext;
2621da177e4SLinus Torvalds 	struct fileEntry *fe;
2631da177e4SLinus Torvalds 	uint8_t * ptr;
2641da177e4SLinus Torvalds 
2651da177e4SLinus Torvalds 	if ( (!buffer) || (!offset) )
2661da177e4SLinus Torvalds 	{
2671da177e4SLinus Torvalds 		printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
2681da177e4SLinus Torvalds 		return NULL;
2691da177e4SLinus Torvalds 	}
2701da177e4SLinus Torvalds 
2711da177e4SLinus Torvalds 	fe = (struct fileEntry *)buffer;
2721da177e4SLinus Torvalds 
2731da177e4SLinus Torvalds 	if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
2741da177e4SLinus Torvalds 	{
2751da177e4SLinus Torvalds 		udf_debug("0x%x != TAG_IDENT_FE\n",
2761da177e4SLinus Torvalds 			le16_to_cpu(fe->descTag.tagIdent));
2771da177e4SLinus Torvalds 		return NULL;
2781da177e4SLinus Torvalds 	}
2791da177e4SLinus Torvalds 
2801da177e4SLinus Torvalds 	ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
2811da177e4SLinus Torvalds 
2821da177e4SLinus Torvalds 	if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
2831da177e4SLinus Torvalds 	{
2841da177e4SLinus Torvalds 		ptr += *offset;
2851da177e4SLinus Torvalds 	}
2861da177e4SLinus Torvalds 
2871da177e4SLinus Torvalds 	ext = (extent_ad *)ptr;
2881da177e4SLinus Torvalds 
2891da177e4SLinus Torvalds 	*offset = *offset + sizeof(extent_ad);
2901da177e4SLinus Torvalds 	return ext;
2911da177e4SLinus Torvalds }
2921da177e4SLinus Torvalds #endif
2931da177e4SLinus Torvalds 
2941da177e4SLinus Torvalds short_ad *
2951da177e4SLinus Torvalds udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
2961da177e4SLinus Torvalds {
2971da177e4SLinus Torvalds 	short_ad *sa;
2981da177e4SLinus Torvalds 
2991da177e4SLinus Torvalds 	if ( (!ptr) || (!offset) )
3001da177e4SLinus Torvalds 	{
3011da177e4SLinus Torvalds 		printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
3021da177e4SLinus Torvalds 		return NULL;
3031da177e4SLinus Torvalds 	}
3041da177e4SLinus Torvalds 
3051da177e4SLinus Torvalds 	if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
3061da177e4SLinus Torvalds 		return NULL;
3071da177e4SLinus Torvalds 	else if ((sa = (short_ad *)ptr)->extLength == 0)
3081da177e4SLinus Torvalds 		return NULL;
3091da177e4SLinus Torvalds 
3101da177e4SLinus Torvalds 	if (inc)
3111da177e4SLinus Torvalds 		*offset += sizeof(short_ad);
3121da177e4SLinus Torvalds 	return sa;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds 
3151da177e4SLinus Torvalds long_ad *
3161da177e4SLinus Torvalds udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
3171da177e4SLinus Torvalds {
3181da177e4SLinus Torvalds 	long_ad *la;
3191da177e4SLinus Torvalds 
3201da177e4SLinus Torvalds 	if ( (!ptr) || (!offset) )
3211da177e4SLinus Torvalds 	{
3221da177e4SLinus Torvalds 		printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
3231da177e4SLinus Torvalds 		return NULL;
3241da177e4SLinus Torvalds 	}
3251da177e4SLinus Torvalds 
3261da177e4SLinus Torvalds 	if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
3271da177e4SLinus Torvalds 		return NULL;
3281da177e4SLinus Torvalds 	else if ((la = (long_ad *)ptr)->extLength == 0)
3291da177e4SLinus Torvalds 		return NULL;
3301da177e4SLinus Torvalds 
3311da177e4SLinus Torvalds 	if (inc)
3321da177e4SLinus Torvalds 		*offset += sizeof(long_ad);
3331da177e4SLinus Torvalds 	return la;
3341da177e4SLinus Torvalds }
335