/*
 * directory.c
 *
 * PURPOSE
 *	Directory related functions
 *
 * 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) {
		brelse(*bh);
		*error = 1;
		return NULL;
	}

	if (*offset == dir->i_sb->s_blocksize) {
		brelse(*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);

		brelse(*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,
					 struct extent_position *epos,
					 kernel_lb_addr * eloc, uint32_t * elen,
					 sector_t * offset)
{
	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 = epos->offset;

		if (udf_next_aext(dir, epos, eloc, elen, 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
			epos->offset = lextoffset;

		brelse(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) {
		brelse(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 = epos->offset;

		if (udf_next_aext(dir, epos, eloc, elen, 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
			epos->offset = 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;
}
