2005-04-17 02:20:36 +04:00
/*
* 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
*
2007-07-21 15:37:18 +04:00
* 12 / 06 / 98 blf Created file .
2005-04-17 02:20:36 +04:00
*
*/
# 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>
2007-07-19 12:47:43 +04:00
inline uint32_t udf_get_pblock ( struct super_block * sb , uint32_t block ,
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
if ( partition > = UDF_SB_NUMPARTS ( sb ) ) {
2007-07-21 15:37:18 +04:00
udf_debug ( " block=%d, partition=%d, offset=%d: invalid partition \n " ,
block , partition , offset ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
if ( UDF_SB_PARTFUNC ( sb , partition ) )
2007-07-21 15:37:18 +04:00
return UDF_SB_PARTFUNC ( sb , partition ) ( sb , block , partition , offset ) ;
2005-04-17 02:20:36 +04:00
else
return UDF_SB_PARTROOT ( sb , partition ) + block + offset ;
}
2007-07-21 15:37:18 +04:00
uint32_t udf_get_pblock_virt15 ( struct super_block * sb , uint32_t block ,
2007-07-19 12:47:43 +04:00
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
struct buffer_head * bh = NULL ;
uint32_t newblock ;
uint32_t index ;
uint32_t loc ;
2007-07-21 15:37:18 +04:00
index = ( sb - > s_blocksize - UDF_SB_TYPEVIRT ( sb , partition ) . s_start_offset ) / sizeof ( uint32_t ) ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
2007-07-19 12:47:43 +04:00
if ( block > = index ) {
2005-04-17 02:20:36 +04:00
block - = index ;
newblock = 1 + ( block / ( sb - > s_blocksize / sizeof ( uint32_t ) ) ) ;
index = block % ( sb - > s_blocksize / sizeof ( uint32_t ) ) ;
2007-07-19 12:47:43 +04:00
} else {
2005-04-17 02:20:36 +04:00
newblock = 0 ;
2007-07-21 15:37:18 +04:00
index = UDF_SB_TYPEVIRT ( sb , partition ) . s_start_offset / sizeof ( uint32_t ) + block ;
2005-04-17 02:20:36 +04:00
}
loc = udf_block_map ( UDF_SB_VAT ( sb ) , newblock ) ;
2007-07-19 12:47:43 +04:00
if ( ! ( bh = sb_bread ( sb , loc ) ) ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " get_pblock(UDF_VIRTUAL_MAP:%p,%d,%d) VAT: %d[%d] \n " ,
2007-07-19 12:47:43 +04:00
sb , block , partition , loc , index ) ;
2005-04-17 02:20:36 +04:00
return 0xFFFFFFFF ;
}
2007-07-21 15:37:18 +04:00
loc = le32_to_cpu ( ( ( __le32 * ) bh - > b_data ) [ index ] ) ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( UDF_I_LOCATION ( UDF_SB_VAT ( sb ) ) . partitionReferenceNum = = partition ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " recursive call to udf_get_pblock! \n " ) ;
return 0xFFFFFFFF ;
}
2007-07-19 12:47:43 +04:00
return udf_get_pblock ( sb , loc ,
2007-07-21 15:37:18 +04:00
UDF_I_LOCATION ( UDF_SB_VAT ( sb ) ) . partitionReferenceNum ,
offset ) ;
2005-04-17 02:20:36 +04:00
}
2007-07-19 12:47:43 +04:00
inline uint32_t udf_get_pblock_virt20 ( struct super_block * sb , uint32_t block ,
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
return udf_get_pblock_virt15 ( sb , block , partition , offset ) ;
}
2007-07-19 12:47:43 +04:00
uint32_t udf_get_pblock_spar15 ( struct super_block * sb , uint32_t block ,
uint16_t partition , uint32_t offset )
2005-04-17 02:20:36 +04:00
{
int i ;
struct sparingTable * st = NULL ;
2007-07-21 15:37:18 +04:00
uint32_t packet = ( block + offset ) & ~ ( UDF_SB_TYPESPAR ( sb , partition ) . s_packet_len - 1 ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < 4 ; i + + ) {
2007-07-21 15:37:18 +04:00
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 ;
2005-04-17 02:20:36 +04:00
break ;
}
}
2007-07-19 12:47:43 +04:00
if ( st ) {
for ( i = 0 ; i < le16_to_cpu ( st - > reallocationTableLen ) ; i + + ) {
2007-07-21 15:37:18 +04:00
if ( le32_to_cpu ( st - > mapEntry [ i ] . origLocation ) > = 0xFFFFFFF0 ) {
2005-04-17 02:20:36 +04:00
break ;
2007-07-21 15:37:18 +04:00
} 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 ) {
2005-04-17 02:20:36 +04:00
break ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
}
}
2007-07-21 15:37:18 +04:00
return UDF_SB_PARTROOT ( sb , partition ) + block + offset ;
2005-04-17 02:20:36 +04:00
}
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 ;
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < UDF_SB_NUMPARTS ( sb ) ; i + + ) {
2007-07-21 15:37:18 +04:00
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 ) ;
2007-07-19 12:47:43 +04:00
for ( j = 0 ; j < 4 ; j + + ) {
2007-07-21 15:37:18 +04:00
if ( UDF_SB_TYPESPAR ( sb , i ) . s_spar_map [ j ] ! = NULL ) {
st = ( struct sparingTable * ) sdata - > s_spar_map [ j ] - > b_data ;
2005-04-17 02:20:36 +04:00
break ;
}
}
if ( ! st )
return 1 ;
2007-07-21 15:37:18 +04:00
for ( k = 0 ; k < le16_to_cpu ( st - > reallocationTableLen ) ; k + + ) {
if ( le32_to_cpu ( st - > mapEntry [ k ] . origLocation ) = = 0xFFFFFFFF ) {
2007-07-19 12:47:43 +04:00
for ( ; j < 4 ; j + + ) {
if ( sdata - > s_spar_map [ j ] ) {
2007-07-21 15:37:18 +04:00
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 ] ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-21 15:37:18 +04:00
* new_block = le32_to_cpu ( st - > mapEntry [ k ] . mappedLocation ) +
( ( old_block - UDF_SB_PARTROOT ( sb , i ) ) & ( sdata - > s_packet_len - 1 ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2007-07-21 15:37:18 +04:00
} 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 ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
2007-07-21 15:37:18 +04:00
} else if ( le32_to_cpu ( st - > mapEntry [ k ] . origLocation ) > packet ) {
2005-04-17 02:20:36 +04:00
break ;
2007-07-21 15:37:18 +04:00
}
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
for ( l = k ; l < le16_to_cpu ( st - > reallocationTableLen ) ; l + + ) {
if ( le32_to_cpu ( st - > mapEntry [ l ] . origLocation ) = = 0xFFFFFFFF ) {
2007-07-19 12:47:43 +04:00
for ( ; j < 4 ; j + + ) {
if ( sdata - > s_spar_map [ j ] ) {
2007-07-21 15:37:18 +04:00
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 ] ) ;
2005-04-17 02:20:36 +04:00
}
}
2007-07-21 15:37:18 +04:00
* new_block = le32_to_cpu ( st - > mapEntry [ k ] . mappedLocation ) +
( ( old_block - UDF_SB_PARTROOT ( sb , i ) ) & ( sdata - > s_packet_len - 1 ) ) ;
2005-04-17 02:20:36 +04:00
return 0 ;
}
}
2007-07-21 15:37:18 +04:00
2005-04-17 02:20:36 +04:00
return 1 ;
2007-07-21 15:37:18 +04:00
} /* if old_block */
2005-04-17 02:20:36 +04:00
}
2007-07-21 15:37:18 +04:00
2007-07-19 12:47:43 +04:00
if ( i = = UDF_SB_NUMPARTS ( sb ) ) {
2005-04-17 02:20:36 +04:00
/* outside of partitions */
/* for now, fail =) */
return 1 ;
}
return 0 ;
}