summary refs log tree commit diff
path: root/fs/udf/directory.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
committerLinus Torvalds <torvalds@ppc970.osdl.org>2005-04-16 15:20:36 -0700
commit1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch)
tree0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/udf/directory.c
downloadlinux-1da177e4c3f41524e886b7f1b8a0c1fc7321cac2.tar.gz
Linux-2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.

Let it rip!
Diffstat (limited to 'fs/udf/directory.c')
-rw-r--r--fs/udf/directory.c343
1 files changed, 343 insertions, 0 deletions
diff --git a/fs/udf/directory.c b/fs/udf/directory.c
new file mode 100644
index 000000000000..9a61ecc5451b
--- /dev/null
+++ b/fs/udf/directory.c
@@ -0,0 +1,343 @@
+/*
+ * directory.c
+ *
+ * PURPOSE
+ *	Directory related functions
+ *
+ * CONTACTS
+ *	E-mail regarding any portion of the Linux UDF file system should be
+ *	directed to the development team mailing list (run by majordomo):
+ *		linux_udf@hpesjro.fc.hp.com
+ *
+ * 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.
+ */
+
+#include "udfdecl.h"
+#include "udf_i.h"
+
+#include <linux/fs.h>
+#include <linux/string.h>
+#include <linux/buffer_head.h>
+
+#if 0
+static uint8_t *
+udf_filead_read(struct inode *dir, uint8_t *tmpad, uint8_t ad_size,
+		kernel_lb_addr fe_loc, int *pos, int *offset,
+		struct buffer_head **bh, int *error)
+{
+	int loffset = *offset;
+	int block;
+	uint8_t *ad;
+	int remainder;
+
+	*error = 0;
+
+	ad = (uint8_t *)(*bh)->b_data + *offset;
+	*offset += ad_size;
+
+	if (!ad)
+	{
+		udf_release_data(*bh);
+		*error = 1;
+		return NULL;
+	}
+
+	if (*offset == dir->i_sb->s_blocksize)
+	{
+		udf_release_data(*bh);
+		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+		if (!block)
+			return NULL;
+		if (!(*bh = udf_tread(dir->i_sb, block)))
+			return NULL;
+	}
+	else if (*offset > dir->i_sb->s_blocksize)
+	{
+		ad = tmpad;
+
+		remainder = dir->i_sb->s_blocksize - loffset;
+		memcpy((uint8_t *)ad, (*bh)->b_data + loffset, remainder);
+
+		udf_release_data(*bh);
+		block = udf_get_lb_pblock(dir->i_sb, fe_loc, ++*pos);
+		if (!block)
+			return NULL;
+		if (!((*bh) = udf_tread(dir->i_sb, block)))
+			return NULL;
+
+		memcpy((uint8_t *)ad + remainder, (*bh)->b_data, ad_size - remainder);
+		*offset = ad_size - remainder;
+	}
+	return ad;
+}
+#endif
+
+struct fileIdentDesc *
+udf_fileident_read(struct inode *dir, loff_t *nf_pos,
+	struct udf_fileident_bh *fibh,
+	struct fileIdentDesc *cfi,
+	kernel_lb_addr *bloc, uint32_t *extoffset, 
+	kernel_lb_addr *eloc, uint32_t *elen,
+	uint32_t *offset, struct buffer_head **bh)
+{
+	struct fileIdentDesc *fi;
+	int i, num, block;
+	struct buffer_head * tmp, * bha[16];
+
+	fibh->soffset = fibh->eoffset;
+
+	if (UDF_I_ALLOCTYPE(dir) == ICBTAG_FLAG_AD_IN_ICB)
+	{
+		fi = udf_get_fileident(UDF_I_DATA(dir) -
+			(UDF_I_EFE(dir) ?
+				sizeof(struct extendedFileEntry) :
+				sizeof(struct fileEntry)),
+			dir->i_sb->s_blocksize, &(fibh->eoffset));
+
+		if (!fi)
+			return NULL;
+
+		*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+
+		memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+
+		return fi;
+	}
+
+	if (fibh->eoffset == dir->i_sb->s_blocksize)
+	{
+		int lextoffset = *extoffset;
+
+		if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+			(EXT_RECORDED_ALLOCATED >> 30))
+		{
+			return NULL;
+		}
+
+		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+
+		(*offset) ++;
+
+		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
+			*offset = 0;
+		else
+			*extoffset = lextoffset;
+
+		udf_release_data(fibh->sbh);
+		if (!(fibh->sbh = fibh->ebh = udf_tread(dir->i_sb, block)))
+			return NULL;
+		fibh->soffset = fibh->eoffset = 0;
+
+		if (!(*offset & ((16 >> (dir->i_sb->s_blocksize_bits - 9))-1)))
+		{
+			i = 16 >> (dir->i_sb->s_blocksize_bits - 9);
+			if (i+*offset > (*elen >> dir->i_sb->s_blocksize_bits))
+				i = (*elen >> dir->i_sb->s_blocksize_bits)-*offset;
+			for (num=0; i>0; i--)
+			{
+				block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset+i);
+				tmp = udf_tgetblk(dir->i_sb, block);
+				if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
+					bha[num++] = tmp;
+				else
+					brelse(tmp);
+			}
+			if (num)
+			{
+				ll_rw_block(READA, num, bha);
+				for (i=0; i<num; i++)
+					brelse(bha[i]);
+			}
+		}
+	}
+	else if (fibh->sbh != fibh->ebh)
+	{
+		udf_release_data(fibh->sbh);
+		fibh->sbh = fibh->ebh;
+	}
+
+	fi = udf_get_fileident(fibh->sbh->b_data, dir->i_sb->s_blocksize,
+		&(fibh->eoffset));
+
+	if (!fi)
+		return NULL;
+
+	*nf_pos += ((fibh->eoffset - fibh->soffset) >> 2);
+
+	if (fibh->eoffset <= dir->i_sb->s_blocksize)
+	{
+		memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+	}
+	else if (fibh->eoffset > dir->i_sb->s_blocksize)
+	{
+		int lextoffset = *extoffset;
+
+		if (udf_next_aext(dir, bloc, extoffset, eloc, elen, bh, 1) !=
+			(EXT_RECORDED_ALLOCATED >> 30))
+		{
+			return NULL;
+		}
+
+		block = udf_get_lb_pblock(dir->i_sb, *eloc, *offset);
+
+		(*offset) ++;
+
+		if ((*offset << dir->i_sb->s_blocksize_bits) >= *elen)
+			*offset = 0;
+		else
+			*extoffset = lextoffset;
+
+		fibh->soffset -= dir->i_sb->s_blocksize;
+		fibh->eoffset -= dir->i_sb->s_blocksize;
+
+		if (!(fibh->ebh = udf_tread(dir->i_sb, block)))
+			return NULL;
+
+		if (sizeof(struct fileIdentDesc) > - fibh->soffset)
+		{
+			int fi_len;
+
+			memcpy((uint8_t *)cfi, (uint8_t *)fi, - fibh->soffset);
+			memcpy((uint8_t *)cfi - fibh->soffset, fibh->ebh->b_data,
+				sizeof(struct fileIdentDesc) + fibh->soffset);
+
+			fi_len = (sizeof(struct fileIdentDesc) + cfi->lengthFileIdent +
+				le16_to_cpu(cfi->lengthOfImpUse) + 3) & ~3;
+
+			*nf_pos += ((fi_len - (fibh->eoffset - fibh->soffset)) >> 2);
+			fibh->eoffset = fibh->soffset + fi_len;
+		}
+		else
+		{
+			memcpy((uint8_t *)cfi, (uint8_t *)fi, sizeof(struct fileIdentDesc));
+		}
+	}
+	return fi;
+}
+
+struct fileIdentDesc * 
+udf_get_fileident(void * buffer, int bufsize, int * offset)
+{
+	struct fileIdentDesc *fi;
+	int lengthThisIdent;
+	uint8_t * ptr;
+	int padlen;
+
+	if ( (!buffer) || (!offset) ) {
+		udf_debug("invalidparms\n, buffer=%p, offset=%p\n", buffer, offset);
+		return NULL;
+	}
+
+	ptr = buffer;
+
+	if ( (*offset > 0) && (*offset < bufsize) ) {
+		ptr += *offset;
+	}
+	fi=(struct fileIdentDesc *)ptr;
+	if (le16_to_cpu(fi->descTag.tagIdent) != TAG_IDENT_FID)
+	{
+		udf_debug("0x%x != TAG_IDENT_FID\n",
+			le16_to_cpu(fi->descTag.tagIdent));
+		udf_debug("offset: %u sizeof: %lu bufsize: %u\n",
+			*offset, (unsigned long)sizeof(struct fileIdentDesc), bufsize);
+		return NULL;
+	}
+	if ( (*offset + sizeof(struct fileIdentDesc)) > bufsize )
+	{
+		lengthThisIdent = sizeof(struct fileIdentDesc);
+	}
+	else
+		lengthThisIdent = sizeof(struct fileIdentDesc) +
+			fi->lengthFileIdent + le16_to_cpu(fi->lengthOfImpUse);
+
+	/* we need to figure padding, too! */
+	padlen = lengthThisIdent % UDF_NAME_PAD;
+	if (padlen)
+		lengthThisIdent += (UDF_NAME_PAD - padlen);
+	*offset = *offset + lengthThisIdent;
+
+	return fi;
+}
+
+#if 0
+static extent_ad *
+udf_get_fileextent(void * buffer, int bufsize, int * offset)
+{
+	extent_ad * ext;
+	struct fileEntry *fe;
+	uint8_t * ptr;
+
+	if ( (!buffer) || (!offset) )
+	{
+		printk(KERN_ERR "udf: udf_get_fileextent() invalidparms\n");
+		return NULL;
+	}
+
+	fe = (struct fileEntry *)buffer;
+
+	if ( le16_to_cpu(fe->descTag.tagIdent) != TAG_IDENT_FE )
+	{
+		udf_debug("0x%x != TAG_IDENT_FE\n",
+			le16_to_cpu(fe->descTag.tagIdent));
+		return NULL;
+	}
+
+	ptr=(uint8_t *)(fe->extendedAttr) + le32_to_cpu(fe->lengthExtendedAttr);
+
+	if ( (*offset > 0) && (*offset < le32_to_cpu(fe->lengthAllocDescs)) )
+	{
+		ptr += *offset;
+	}
+
+	ext = (extent_ad *)ptr;
+
+	*offset = *offset + sizeof(extent_ad);
+	return ext;
+}
+#endif
+
+short_ad *
+udf_get_fileshortad(uint8_t *ptr, int maxoffset, int *offset, int inc)
+{
+	short_ad *sa;
+
+	if ( (!ptr) || (!offset) )
+	{
+		printk(KERN_ERR "udf: udf_get_fileshortad() invalidparms\n");
+		return NULL;
+	}
+
+	if ( (*offset < 0) || ((*offset + sizeof(short_ad)) > maxoffset) )
+		return NULL;
+	else if ((sa = (short_ad *)ptr)->extLength == 0)
+		return NULL;
+
+	if (inc)
+		*offset += sizeof(short_ad);
+	return sa;
+}
+
+long_ad *
+udf_get_filelongad(uint8_t *ptr, int maxoffset, int * offset, int inc)
+{
+	long_ad *la;
+
+	if ( (!ptr) || (!offset) ) 
+	{
+		printk(KERN_ERR "udf: udf_get_filelongad() invalidparms\n");
+		return NULL;
+	}
+
+	if ( (*offset < 0) || ((*offset + sizeof(long_ad)) > maxoffset) )
+		return NULL;
+	else if ((la = (long_ad *)ptr)->extLength == 0)
+		return NULL;
+
+	if (inc)
+		*offset += sizeof(long_ad);
+	return la;
+}