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>
2008-02-08 15:20:36 +03:00
struct fileIdentDesc * udf_fileident_read ( struct inode * dir , loff_t * nf_pos ,
2007-07-19 12:47:43 +04:00
struct udf_fileident_bh * fibh ,
struct fileIdentDesc * cfi ,
struct extent_position * epos ,
2008-10-15 14:28:03 +04:00
struct kernel_lb_addr * eloc , uint32_t * elen ,
2008-02-08 15:20:36 +03:00
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 ] ;
2008-02-08 15:20:44 +03:00
struct udf_inode_info * iinfo = UDF_I ( dir ) ;
2005-04-17 02:20:36 +04:00
fibh - > soffset = fibh - > eoffset ;
2008-02-08 15:20:44 +03:00
if ( iinfo - > i_alloc_type = = ICBTAG_FLAG_AD_IN_ICB ) {
fi = udf_get_fileident ( iinfo - > i_ext . i_data -
( iinfo - > i_efe ?
2007-07-19 12:47:43 +04:00
sizeof ( struct extendedFileEntry ) :
sizeof ( struct fileEntry ) ) ,
2008-02-08 15:20:36 +03:00
dir - > i_sb - > s_blocksize ,
& ( fibh - > eoffset ) ) ;
2005-04-17 02:20:36 +04:00
if ( ! fi )
return NULL ;
2008-02-08 15:20:50 +03:00
* nf_pos + = fibh - > eoffset - fibh - > soffset ;
2005-04-17 02:20:36 +04:00
2007-07-21 15:37:18 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi ,
2007-07-19 12:47:43 +04:00
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 ;
2008-02-08 15:20:36 +03:00
unsigned char blocksize_bits = dir - > i_sb - > s_blocksize_bits ;
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 ;
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , eloc , * offset ) ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
( * offset ) + + ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
if ( ( * offset < < blocksize_bits ) > = * elen )
2005-04-17 02:20:36 +04:00
* 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 ) ;
2008-02-08 15:20:36 +03:00
fibh - > sbh = fibh - > ebh = udf_tread ( dir - > i_sb , block ) ;
if ( ! fibh - > sbh )
2005-04-17 02:20:36 +04:00
return NULL ;
fibh - > soffset = fibh - > eoffset = 0 ;
2008-02-08 15:20:36 +03:00
if ( ! ( * offset & ( ( 16 > > ( blocksize_bits - 9 ) ) - 1 ) ) ) {
i = 16 > > ( blocksize_bits - 9 ) ;
if ( i + * offset > ( * elen > > blocksize_bits ) )
i = ( * elen > > blocksize_bits ) - * offset ;
2007-07-19 12:47:43 +04:00
for ( num = 0 ; i > 0 ; i - - ) {
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , eloc ,
2008-02-08 15:20:36 +03:00
* offset + i ) ;
2005-04-17 02:20:36 +04:00
tmp = udf_tgetblk ( dir - > i_sb , block ) ;
2008-02-08 15:20:36 +03: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 ;
2008-02-08 15:20:50 +03:00
* nf_pos + = fibh - > eoffset - fibh - > soffset ;
2005-04-17 02:20:36 +04:00
2007-07-19 12:47:43 +04:00
if ( fibh - > eoffset < = dir - > i_sb - > s_blocksize ) {
2007-07-21 15:37:18 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi ,
2007-07-19 12:47:43 +04:00
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 ;
2008-10-15 14:29:03 +04:00
block = udf_get_lb_pblock ( dir - > i_sb , eloc , * offset ) ;
2005-04-17 02:20:36 +04:00
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 ;
2008-02-08 15:20:36 +03:00
fibh - > ebh = udf_tread ( dir - > i_sb , block ) ;
if ( ! fibh - > ebh )
2005-04-17 02:20:36 +04:00
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-21 15:37:18 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi , - fibh - > soffset ) ;
2008-02-08 15:20:36 +03:00
memcpy ( ( uint8_t * ) cfi - fibh - > soffset ,
fibh - > ebh - > b_data ,
2007-07-19 12:47:43 +04:00
sizeof ( struct fileIdentDesc ) + fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:36 +03:00
fi_len = ( sizeof ( struct fileIdentDesc ) +
cfi - > lengthFileIdent +
2007-07-21 15:37:18 +04:00
le16_to_cpu ( cfi - > lengthOfImpUse ) + 3 ) & ~ 3 ;
2005-04-17 02:20:36 +04:00
2008-02-08 15:20:50 +03:00
* nf_pos + = fi_len - ( fibh - > eoffset - fibh - > soffset ) ;
2005-04-17 02:20:36 +04:00
fibh - > eoffset = fibh - > soffset + fi_len ;
2007-07-19 12:47:43 +04:00
} else {
2007-07-21 15:37:18 +04:00
memcpy ( ( uint8_t * ) cfi , ( uint8_t * ) fi ,
2007-07-19 12:47:43 +04:00
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 ;
2008-02-08 15:20:36 +03: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 ;
2008-02-08 15:20:41 +03:00
if ( fi - > descTag . tagIdent ! = cpu_to_le16 ( 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 ;
}
2008-02-08 15:20:36 +03:00
if ( ( * offset + sizeof ( struct fileIdentDesc ) ) > bufsize )
2005-04-17 02:20:36 +04:00
lengthThisIdent = sizeof ( struct fileIdentDesc ) ;
2008-02-08 15:20:36 +03:00
else
2005-04-17 02:20:36 +04:00
lengthThisIdent = sizeof ( struct fileIdentDesc ) +
2007-07-21 15:37:18 +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 ;
}
2008-10-15 14:28:03 +04:00
struct short_ad * udf_get_fileshortad ( uint8_t * ptr , int maxoffset , uint32_t * offset ,
2007-07-19 12:47:43 +04:00
int inc )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:28:03 +04:00
struct short_ad * sa ;
2005-04-17 02:20:36 +04:00
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 ;
}
2008-10-15 14:28:03 +04:00
if ( ( * offset + sizeof ( struct short_ad ) ) > maxoffset )
2005-04-17 02:20:36 +04:00
return NULL ;
2008-02-08 15:20:36 +03:00
else {
2008-10-15 14:28:03 +04:00
sa = ( struct short_ad * ) ptr ;
2008-02-08 15:20:36 +03:00
if ( sa - > extLength = = 0 )
return NULL ;
}
2005-04-17 02:20:36 +04:00
if ( inc )
2008-10-15 14:28:03 +04:00
* offset + = sizeof ( struct short_ad ) ;
2005-04-17 02:20:36 +04:00
return sa ;
}
2008-10-15 14:28:03 +04:00
struct long_ad * udf_get_filelongad ( uint8_t * ptr , int maxoffset , uint32_t * offset , int inc )
2005-04-17 02:20:36 +04:00
{
2008-10-15 14:28:03 +04:00
struct long_ad * la ;
2005-04-17 02:20:36 +04:00
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 ;
}
2008-10-15 14:28:03 +04:00
if ( ( * offset + sizeof ( struct long_ad ) ) > maxoffset )
2005-04-17 02:20:36 +04:00
return NULL ;
2008-02-08 15:20:36 +03:00
else {
2008-10-15 14:28:03 +04:00
la = ( struct long_ad * ) ptr ;
2008-02-08 15:20:36 +03:00
if ( la - > extLength = = 0 )
return NULL ;
}
2005-04-17 02:20:36 +04:00
if ( inc )
2008-10-15 14:28:03 +04:00
* offset + = sizeof ( struct long_ad ) ;
2005-04-17 02:20:36 +04:00
return la ;
}