/*
 * partition.c
 *
 * PURPOSE
 *      Partition handling routines for the OSTA-UDF(tm) filesystem.
 *
 * 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.
 *
 *  (C) 1998-2001 Ben Fennema
 *
 * HISTORY
 *
 * 12/06/98 blf  Created file. 
 *
 */

#include "udfdecl.h"
#include "udf_sb.h"
#include "udf_i.h"

#include <linux/fs.h>
#include <linux/string.h>
#include <linux/udf_fs.h>
#include <linux/slab.h>
#include <linux/buffer_head.h>

inline uint32_t udf_get_pblock(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
{
	if (partition >= UDF_SB_NUMPARTS(sb))
	{
		udf_debug("block=%d, partition=%d, offset=%d: invalid partition\n",
			block, partition, offset);
		return 0xFFFFFFFF;
	}
	if (UDF_SB_PARTFUNC(sb, partition))
		return UDF_SB_PARTFUNC(sb, partition)(sb, block, partition, offset);
	else
		return UDF_SB_PARTROOT(sb, partition) + block + offset;
}

uint32_t udf_get_pblock_virt15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
{
	struct buffer_head *bh = NULL;
	uint32_t newblock;
	uint32_t index;
	uint32_t loc;

	index = (sb->s_blocksize - UDF_SB_TYPEVIRT(sb,partition).s_start_offset) / sizeof(uint32_t);

	if (block > UDF_SB_TYPEVIRT(sb,partition).s_num_entries)
	{
		udf_debug("Trying to access block beyond end of VAT (%d max %d)\n",
			block, UDF_SB_TYPEVIRT(sb,partition).s_num_entries);
		return 0xFFFFFFFF;
	}

	if (block >= index)
	{
		block -= index;
		newblock = 1 + (block / (sb->s_blocksize / sizeof(uint32_t)));
		index = block % (sb->s_blocksize / sizeof(uint32_t));
	}
	else
	{
		newblock = 0;
		index = UDF_SB_TYPEVIRT(sb,partition).s_start_offset / sizeof(uint32_t) + block;
	}

	loc = udf_block_map(UDF_SB_VAT(sb), newblock);

	if (!(bh = sb_bread(sb, loc)))
	{
		udf_debug("get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d]\n",
			sb, block, partition, loc, index);
		return 0xFFFFFFFF;
	}

	loc = le32_to_cpu(((__le32 *)bh->b_data)[index]);

	udf_release_data(bh);

	if (UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum == partition)
	{
		udf_debug("recursive call to udf_get_pblock!\n");
		return 0xFFFFFFFF;
	}

	return udf_get_pblock(sb, loc, UDF_I_LOCATION(UDF_SB_VAT(sb)).partitionReferenceNum, offset);
}

inline uint32_t udf_get_pblock_virt20(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
{
	return udf_get_pblock_virt15(sb, block, partition, offset);
}

uint32_t udf_get_pblock_spar15(struct super_block *sb, uint32_t block, uint16_t partition, uint32_t offset)
{
	int i;
	struct sparingTable *st = NULL;
	uint32_t packet = (block + offset) & ~(UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1);

	for (i=0; i<4; i++)
	{
		if (UDF_SB_TYPESPAR(sb,partition).s_spar_map[i] != NULL)
		{
			st = (struct sparingTable *)UDF_SB_TYPESPAR(sb,partition).s_spar_map[i]->b_data;
			break;
		}
	}

	if (st)
	{
		for (i=0; i<le16_to_cpu(st->reallocationTableLen); i++)
		{
			if (le32_to_cpu(st->mapEntry[i].origLocation) >= 0xFFFFFFF0)
				break;
			else if (le32_to_cpu(st->mapEntry[i].origLocation) == packet)
			{
				return le32_to_cpu(st->mapEntry[i].mappedLocation) +
					((block + offset) & (UDF_SB_TYPESPAR(sb,partition).s_packet_len - 1));
			}
			else if (le32_to_cpu(st->mapEntry[i].origLocation) > packet)
				break;
		}
	}
	return UDF_SB_PARTROOT(sb,partition) + block + offset;
}

int udf_relocate_blocks(struct super_block *sb, long old_block, long *new_block)
{
	struct udf_sparing_data *sdata;
	struct sparingTable *st = NULL;
	struct sparingEntry mapEntry;
	uint32_t packet;
	int i, j, k, l;

	for (i=0; i<UDF_SB_NUMPARTS(sb); i++)
	{
		if (old_block > UDF_SB_PARTROOT(sb,i) &&
		    old_block < UDF_SB_PARTROOT(sb,i) + UDF_SB_PARTLEN(sb,i))
		{
			sdata = &UDF_SB_TYPESPAR(sb,i);
			packet = (old_block - UDF_SB_PARTROOT(sb,i)) & ~(sdata->s_packet_len - 1);

			for (j=0; j<4; j++)
			{
				if (UDF_SB_TYPESPAR(sb,i).s_spar_map[j] != NULL)
				{
					st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
					break;
				}
			}

			if (!st)
				return 1;

			for (k=0; k<le16_to_cpu(st->reallocationTableLen); k++)
			{
				if (le32_to_cpu(st->mapEntry[k].origLocation) == 0xFFFFFFFF)
				{
					for (; j<4; j++)
					{
						if (sdata->s_spar_map[j])
						{
							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
							st->mapEntry[k].origLocation = cpu_to_le32(packet);
							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
							mark_buffer_dirty(sdata->s_spar_map[j]);
						}
					}
					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
					return 0;
				}
				else if (le32_to_cpu(st->mapEntry[k].origLocation) == packet)
				{
					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
					return 0;
				}
				else if (le32_to_cpu(st->mapEntry[k].origLocation) > packet)
					break;
			}
			for (l=k; l<le16_to_cpu(st->reallocationTableLen); l++)
			{
				if (le32_to_cpu(st->mapEntry[l].origLocation) == 0xFFFFFFFF)
				{
					for (; j<4; j++)
					{
						if (sdata->s_spar_map[j])
						{
							st = (struct sparingTable *)sdata->s_spar_map[j]->b_data;
							mapEntry = st->mapEntry[l];
							mapEntry.origLocation = cpu_to_le32(packet);
							memmove(&st->mapEntry[k+1], &st->mapEntry[k], (l-k)*sizeof(struct sparingEntry));
							st->mapEntry[k] = mapEntry;
							udf_update_tag((char *)st, sizeof(struct sparingTable) + le16_to_cpu(st->reallocationTableLen) * sizeof(struct sparingEntry));
							mark_buffer_dirty(sdata->s_spar_map[j]);
						}
					}
					*new_block = le32_to_cpu(st->mapEntry[k].mappedLocation) +
						((old_block - UDF_SB_PARTROOT(sb,i)) & (sdata->s_packet_len - 1));
					return 0;
				}
			}
			return 1;
		}
	}
	if (i == UDF_SB_NUMPARTS(sb))
	{
		/* outside of partitions */
		/* for now, fail =) */
		return 1;
	}

	return 0;
}
