2005-04-17 02:20:36 +04:00
/*
* 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
2007-07-19 12:47:43 +04:00
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 )
2005-04-17 02:20:36 +04:00
{
int loffset = * offset ;
int block ;
uint8_t * ad ;
int remainder ;
* error = 0 ;
2007-07-19 12:47:43 +04:00
ad = ( uint8_t * ) ( * bh ) - > b_data + * offset ;
2005-04-17 02:20:36 +04:00
* offset + = ad_size ;
2007-07-19 12:47:43 +04:00
if ( ! ad ) {
2007-05-08 11:35:16 +04:00
brelse ( * bh ) ;
2005-04-17 02:20:36 +04:00
* error = 1 ;
return NULL ;
}
2007-07-19 12:47:43 +04:00
if ( * offset = = dir - > i_sb - > s_blocksize ) {
2007-05-08 11:35:16 +04:00
brelse ( * bh ) ;
2005-04-17 02:20:36 +04:00
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 ;
2007-07-19 12:47:43 +04:00
} else if ( * offset > dir - > i_sb - > s_blocksize ) {
2005-04-17 02:20:36 +04:00
ad = tmpad ;
remainder = dir - > i_sb - > s_blocksize - loffset ;
2007-07-19 12:47:43 +04:00
memcpy ( ( uint8_t * ) ad , ( * bh ) - > b_data + loffset , remainder ) ;
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
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 ;
2007-07-19 12:47:43 +04:00
memcpy ( ( uint8_t * ) ad + remainder , ( * bh ) - > b_data ,
ad_size - remainder ) ;
2005-04-17 02:20:36 +04:00
* offset = ad_size - remainder ;
}
return ad ;
}
# endif
2007-07-19 12:47:43 +04:00
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 )
2005-04-17 02:20:36 +04:00
{
struct fileIdentDesc * fi ;
int i , num , block ;
2007-07-19 12:47:43 +04:00
struct buffer_head * tmp , * bha [ 16 ] ;
2005-04-17 02:20:36 +04:00
fibh - > soffset = fibh - > eoffset ;
2007-07-19 12:47:43 +04:00
if ( UDF_I_ALLOCTYPE ( dir ) = = ICBTAG_FLAG_AD_IN_ICB ) {
2005-04-17 02:20:36 +04:00
fi = udf_get_fileident ( UDF_I_DATA ( dir ) -
2007-07-19 12:47:43 +04:00
( UDF_I_EFE ( dir ) ?
sizeof ( struct extendedFileEntry ) :
sizeof ( struct fileEntry ) ) ,
dir - > i_sb - > s_blocksize ,
& ( fibh - > eoffset ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! fi )
return NULL ;
* nf_pos + = ( ( fibh - > eoffset - fibh - > soffset ) > > 2 ) ;
2007-07-19 12:47:43 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi ,
sizeof ( struct fileIdentDesc ) ) ;
2005-04-17 02:20:36 +04:00
return fi ;
}
2007-07-19 12:47:43 +04:00
if ( fibh - > eoffset = = dir - > i_sb - > s_blocksize ) {
2007-05-08 11:35:14 +04:00
int lextoffset = epos - > offset ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
if ( udf_next_aext ( dir , epos , eloc , elen , 1 ) ! =
2007-07-19 12:47:43 +04:00
( EXT_RECORDED_ALLOCATED > > 30 ) )
2005-04-17 02:20:36 +04:00
return NULL ;
block = udf_get_lb_pblock ( dir - > i_sb , * eloc , * offset ) ;
2007-07-19 12:47:43 +04:00
( * offset ) + + ;
2005-04-17 02:20:36 +04:00
if ( ( * offset < < dir - > i_sb - > s_blocksize_bits ) > = * elen )
* offset = 0 ;
else
2007-05-08 11:35:14 +04:00
epos - > offset = lextoffset ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:16 +04:00
brelse ( fibh - > sbh ) ;
2005-04-17 02:20:36 +04:00
if ( ! ( fibh - > sbh = fibh - > ebh = udf_tread ( dir - > i_sb , block ) ) )
return NULL ;
fibh - > soffset = fibh - > eoffset = 0 ;
2007-07-19 12:47:43 +04:00
if ( !
( * offset & ( ( 16 > > ( dir - > i_sb - > s_blocksize_bits - 9 ) ) - 1 ) ) )
2005-04-17 02:20:36 +04:00
{
i = 16 > > ( dir - > i_sb - > s_blocksize_bits - 9 ) ;
2007-07-19 12:47:43 +04:00
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 ) ;
2005-04-17 02:20:36 +04:00
tmp = udf_tgetblk ( dir - > i_sb , block ) ;
2007-07-19 12:47:43 +04:00
if ( tmp & & ! buffer_uptodate ( tmp )
& & ! buffer_locked ( tmp ) )
2005-04-17 02:20:36 +04:00
bha [ num + + ] = tmp ;
else
brelse ( tmp ) ;
}
2007-07-19 12:47:43 +04:00
if ( num ) {
2005-04-17 02:20:36 +04:00
ll_rw_block ( READA , num , bha ) ;
2007-07-19 12:47:43 +04:00
for ( i = 0 ; i < num ; i + + )
2005-04-17 02:20:36 +04:00
brelse ( bha [ i ] ) ;
}
}
2007-07-19 12:47:43 +04:00
} else if ( fibh - > sbh ! = fibh - > ebh ) {
2007-05-08 11:35:16 +04:00
brelse ( fibh - > sbh ) ;
2005-04-17 02:20:36 +04:00
fibh - > sbh = fibh - > ebh ;
}
fi = udf_get_fileident ( fibh - > sbh - > b_data , dir - > i_sb - > s_blocksize ,
2007-07-19 12:47:43 +04:00
& ( fibh - > eoffset ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! fi )
return NULL ;
* nf_pos + = ( ( fibh - > eoffset - fibh - > soffset ) > > 2 ) ;
2007-07-19 12:47:43 +04:00
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 ) {
2007-05-08 11:35:14 +04:00
int lextoffset = epos - > offset ;
2005-04-17 02:20:36 +04:00
2007-05-08 11:35:14 +04:00
if ( udf_next_aext ( dir , epos , eloc , elen , 1 ) ! =
2007-07-19 12:47:43 +04:00
( EXT_RECORDED_ALLOCATED > > 30 ) )
2005-04-17 02:20:36 +04:00
return NULL ;
block = udf_get_lb_pblock ( dir - > i_sb , * eloc , * offset ) ;
2007-07-19 12:47:43 +04:00
( * offset ) + + ;
2005-04-17 02:20:36 +04:00
if ( ( * offset < < dir - > i_sb - > s_blocksize_bits ) > = * elen )
* offset = 0 ;
else
2007-05-08 11:35:14 +04:00
epos - > offset = lextoffset ;
2005-04-17 02:20:36 +04:00
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 ;
2007-07-19 12:47:43 +04:00
if ( sizeof ( struct fileIdentDesc ) > - fibh - > soffset ) {
2005-04-17 02:20:36 +04:00
int fi_len ;
2007-07-19 12:47:43 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi , - fibh - > soffset ) ;
memcpy ( ( uint8_t * ) cfi - fibh - > soffset ,
fibh - > ebh - > b_data ,
sizeof ( struct fileIdentDesc ) + fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
fi_len =
( sizeof ( struct fileIdentDesc ) +
cfi - > lengthFileIdent +
le16_to_cpu ( cfi - > lengthOfImpUse ) + 3 ) & ~ 3 ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
* nf_pos + =
( ( fi_len - ( fibh - > eoffset - fibh - > soffset ) ) > > 2 ) ;
2005-04-17 02:20:36 +04:00
fibh - > eoffset = fibh - > soffset + fi_len ;
2007-07-19 12:47:43 +04:00
} else {
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi ,
sizeof ( struct fileIdentDesc ) ) ;
2005-04-17 02:20:36 +04:00
}
}
return fi ;
}
2007-07-19 12:47:43 +04:00
struct fileIdentDesc * udf_get_fileident ( void * buffer , int bufsize , int * offset )
2005-04-17 02:20:36 +04:00
{
struct fileIdentDesc * fi ;
int lengthThisIdent ;
2007-07-19 12:47:43 +04:00
uint8_t * ptr ;
2005-04-17 02:20:36 +04:00
int padlen ;
2007-07-19 12:47:43 +04:00
if ( ( ! buffer ) | | ( ! offset ) ) {
udf_debug ( " invalidparms \n , buffer=%p, offset=%p \n " , buffer ,
offset ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
ptr = buffer ;
2007-07-19 12:47:43 +04:00
if ( ( * offset > 0 ) & & ( * offset < bufsize ) ) {
2005-04-17 02:20:36 +04:00
ptr + = * offset ;
}
2007-07-19 12:47:43 +04:00
fi = ( struct fileIdentDesc * ) ptr ;
if ( le16_to_cpu ( fi - > descTag . tagIdent ) ! = TAG_IDENT_FID ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " 0x%x != TAG_IDENT_FID \n " ,
2007-07-19 12:47:43 +04:00
le16_to_cpu ( fi - > descTag . tagIdent ) ) ;
2005-04-17 02:20:36 +04:00
udf_debug ( " offset: %u sizeof: %lu bufsize: %u \n " ,
2007-07-19 12:47:43 +04:00
* offset , ( unsigned long ) sizeof ( struct fileIdentDesc ) ,
bufsize ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2007-07-19 12:47:43 +04:00
if ( ( * offset + sizeof ( struct fileIdentDesc ) ) > bufsize ) {
2005-04-17 02:20:36 +04:00
lengthThisIdent = sizeof ( struct fileIdentDesc ) ;
2007-07-19 12:47:43 +04:00
} else
2005-04-17 02:20:36 +04:00
lengthThisIdent = sizeof ( struct fileIdentDesc ) +
2007-07-19 12:47:43 +04:00
fi - > lengthFileIdent + le16_to_cpu ( fi - > lengthOfImpUse ) ;
2005-04-17 02:20:36 +04:00
/* 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
2007-07-19 12:47:43 +04:00
static extent_ad * udf_get_fileextent ( void * buffer , int bufsize , int * offset )
2005-04-17 02:20:36 +04:00
{
2007-07-19 12:47:43 +04:00
extent_ad * ext ;
2005-04-17 02:20:36 +04:00
struct fileEntry * fe ;
2007-07-19 12:47:43 +04:00
uint8_t * ptr ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ( ! buffer ) | | ( ! offset ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: udf_get_fileextent() invalidparms \n " ) ;
return NULL ;
}
fe = ( struct fileEntry * ) buffer ;
2007-07-19 12:47:43 +04:00
if ( le16_to_cpu ( fe - > descTag . tagIdent ) ! = TAG_IDENT_FE ) {
2005-04-17 02:20:36 +04:00
udf_debug ( " 0x%x != TAG_IDENT_FE \n " ,
2007-07-19 12:47:43 +04:00
le16_to_cpu ( fe - > descTag . tagIdent ) ) ;
2005-04-17 02:20:36 +04:00
return NULL ;
}
2007-07-19 12:47:43 +04:00
ptr =
( uint8_t * ) ( fe - > extendedAttr ) +
le32_to_cpu ( fe - > lengthExtendedAttr ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( ( * offset > 0 ) & & ( * offset < le32_to_cpu ( fe - > lengthAllocDescs ) ) ) {
2005-04-17 02:20:36 +04:00
ptr + = * offset ;
}
2007-07-19 12:47:43 +04:00
ext = ( extent_ad * ) ptr ;
2005-04-17 02:20:36 +04:00
* offset = * offset + sizeof ( extent_ad ) ;
return ext ;
}
# endif
2007-07-19 12:47:43 +04:00
short_ad * udf_get_fileshortad ( uint8_t * ptr , int maxoffset , int * offset ,
int inc )
2005-04-17 02:20:36 +04:00
{
short_ad * sa ;
2007-07-19 12:47:43 +04:00
if ( ( ! ptr ) | | ( ! offset ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: udf_get_fileshortad() invalidparms \n " ) ;
return NULL ;
}
2007-07-19 12:47:43 +04:00
if ( ( * offset < 0 ) | | ( ( * offset + sizeof ( short_ad ) ) > maxoffset ) )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-07-19 12:47:43 +04:00
else if ( ( sa = ( short_ad * ) ptr ) - > extLength = = 0 )
2005-04-17 02:20:36 +04:00
return NULL ;
if ( inc )
* offset + = sizeof ( short_ad ) ;
return sa ;
}
2007-07-19 12:47:43 +04:00
long_ad * udf_get_filelongad ( uint8_t * ptr , int maxoffset , int * offset , int inc )
2005-04-17 02:20:36 +04:00
{
long_ad * la ;
2007-07-19 12:47:43 +04:00
if ( ( ! ptr ) | | ( ! offset ) ) {
2005-04-17 02:20:36 +04:00
printk ( KERN_ERR " udf: udf_get_filelongad() invalidparms \n " ) ;
return NULL ;
}
2007-07-19 12:47:43 +04:00
if ( ( * offset < 0 ) | | ( ( * offset + sizeof ( long_ad ) ) > maxoffset ) )
2005-04-17 02:20:36 +04:00
return NULL ;
2007-07-19 12:47:43 +04:00
else if ( ( la = ( long_ad * ) ptr ) - > extLength = = 0 )
2005-04-17 02:20:36 +04:00
return NULL ;
if ( inc )
* offset + = sizeof ( long_ad ) ;
return la ;
}