2005-04-17 02:20:36 +04:00
/*
* linux / fs / isofs / rock . c
*
* ( C ) 1992 , 1993 Eric Youngdale
*
* Rock Ridge Extensions to iso9660
*/
# include <linux/slab.h>
# include <linux/pagemap.h>
# include <linux/smp_lock.h>
2005-04-26 05:32:12 +04:00
# include "isofs.h"
2005-04-17 02:20:36 +04:00
# include "rock.h"
2005-06-22 04:16:47 +04:00
/*
* These functions are designed to read the system areas of a directory record
2005-04-17 02:20:36 +04:00
* and extract relevant information . There are different functions provided
* depending upon what information we need at the time . One function fills
* out an inode structure , a second one extracts a filename , a third one
* returns a symbolic link name , and a fourth one returns the extent number
2005-06-22 04:16:47 +04:00
* for the file .
*/
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:42 +04:00
# define SIG(A,B) ((A) | ((B) << 8)) /* isonum_721() */
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:46 +04:00
struct rock_state {
void * buffer ;
unsigned char * chr ;
int len ;
int cont_size ;
int cont_extent ;
int cont_offset ;
struct inode * inode ;
} ;
2005-06-22 04:16:44 +04:00
/*
* This is a way of ensuring that we have something in the system
2005-06-22 04:16:47 +04:00
* use fields that is compatible with Rock Ridge . Return zero on success .
2005-06-22 04:16:44 +04:00
*/
static int check_sp ( struct rock_ridge * rr , struct inode * inode )
{
if ( rr - > u . SP . magic [ 0 ] ! = 0xbe )
return - 1 ;
if ( rr - > u . SP . magic [ 1 ] ! = 0xef )
return - 1 ;
ISOFS_SB ( inode - > i_sb ) - > s_rock_offset = rr - > u . SP . skip ;
return 0 ;
}
2005-06-22 04:16:46 +04:00
static void setup_rock_ridge ( struct iso_directory_record * de ,
2005-06-22 04:16:46 +04:00
struct inode * inode , struct rock_state * rs )
2005-06-22 04:16:46 +04:00
{
2005-06-22 04:16:46 +04:00
rs - > len = sizeof ( struct iso_directory_record ) + de - > name_len [ 0 ] ;
if ( rs - > len & 1 )
( rs - > len ) + + ;
rs - > chr = ( unsigned char * ) de + rs - > len ;
rs - > len = * ( ( unsigned char * ) de ) - rs - > len ;
if ( rs - > len < 0 )
rs - > len = 0 ;
2005-06-22 04:16:46 +04:00
if ( ISOFS_SB ( inode - > i_sb ) - > s_rock_offset ! = - 1 ) {
2005-06-22 04:16:46 +04:00
rs - > len - = ISOFS_SB ( inode - > i_sb ) - > s_rock_offset ;
rs - > chr + = ISOFS_SB ( inode - > i_sb ) - > s_rock_offset ;
if ( rs - > len < 0 )
rs - > len = 0 ;
2005-06-22 04:16:46 +04:00
}
2005-06-22 04:16:42 +04:00
}
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:46 +04:00
static void init_rock_state ( struct rock_state * rs , struct inode * inode )
{
memset ( rs , 0 , sizeof ( * rs ) ) ;
rs - > inode = inode ;
}
/*
* Returns 0 if the caller should continue scanning , 1 if the scan must end
* and - ve on error .
*/
static int rock_continue ( struct rock_state * rs )
{
int ret = 1 ;
2005-06-22 04:16:50 +04:00
int blocksize = 1 < < rs - > inode - > i_blkbits ;
const int min_de_size = offsetof ( struct rock_ridge , u ) ;
2005-06-22 04:16:46 +04:00
kfree ( rs - > buffer ) ;
rs - > buffer = NULL ;
2005-06-22 04:16:50 +04:00
if ( ( unsigned ) rs - > cont_offset > blocksize - min_de_size | |
( unsigned ) rs - > cont_size > blocksize | |
( unsigned ) ( rs - > cont_offset + rs - > cont_size ) > blocksize ) {
printk ( KERN_NOTICE " rock: corrupted directory entry. "
" extent=%d, offset=%d, size=%d \n " ,
rs - > cont_extent , rs - > cont_offset , rs - > cont_size ) ;
ret = - EIO ;
goto out ;
}
2005-06-22 04:16:46 +04:00
if ( rs - > cont_extent ) {
struct buffer_head * bh ;
rs - > buffer = kmalloc ( rs - > cont_size , GFP_KERNEL ) ;
if ( ! rs - > buffer ) {
ret = - ENOMEM ;
goto out ;
}
ret = - EIO ;
bh = sb_bread ( rs - > inode - > i_sb , rs - > cont_extent ) ;
if ( bh ) {
memcpy ( rs - > buffer , bh - > b_data + rs - > cont_offset ,
rs - > cont_size ) ;
put_bh ( bh ) ;
rs - > chr = rs - > buffer ;
rs - > len = rs - > cont_size ;
rs - > cont_extent = 0 ;
rs - > cont_size = 0 ;
rs - > cont_offset = 0 ;
return 0 ;
}
printk ( " Unable to read rock-ridge attributes \n " ) ;
}
out :
kfree ( rs - > buffer ) ;
rs - > buffer = NULL ;
return ret ;
}
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:51 +04:00
/*
* We think there ' s a record of type ` sig ' at rs - > chr . Parse the signature
* and make sure that there ' s really room for a record of that type .
*/
static int rock_check_overflow ( struct rock_state * rs , int sig )
{
int len ;
switch ( sig ) {
case SIG ( ' S ' , ' P ' ) :
len = sizeof ( struct SU_SP_s ) ;
break ;
case SIG ( ' C ' , ' E ' ) :
len = sizeof ( struct SU_CE_s ) ;
break ;
case SIG ( ' E ' , ' R ' ) :
len = sizeof ( struct SU_ER_s ) ;
break ;
case SIG ( ' R ' , ' R ' ) :
len = sizeof ( struct RR_RR_s ) ;
break ;
case SIG ( ' P ' , ' X ' ) :
len = sizeof ( struct RR_PX_s ) ;
break ;
case SIG ( ' P ' , ' N ' ) :
len = sizeof ( struct RR_PN_s ) ;
break ;
case SIG ( ' S ' , ' L ' ) :
len = sizeof ( struct RR_SL_s ) ;
break ;
case SIG ( ' N ' , ' M ' ) :
len = sizeof ( struct RR_NM_s ) ;
break ;
case SIG ( ' C ' , ' L ' ) :
len = sizeof ( struct RR_CL_s ) ;
break ;
case SIG ( ' P ' , ' L ' ) :
len = sizeof ( struct RR_PL_s ) ;
break ;
case SIG ( ' T ' , ' F ' ) :
len = sizeof ( struct RR_TF_s ) ;
break ;
case SIG ( ' Z ' , ' F ' ) :
len = sizeof ( struct RR_ZF_s ) ;
break ;
default :
len = 0 ;
break ;
}
len + = offsetof ( struct rock_ridge , u ) ;
if ( len > rs - > len ) {
printk ( KERN_NOTICE " rock: directory entry would overflow "
" storage \n " ) ;
printk ( KERN_NOTICE " rock: sig=0x%02x, size=%d, remaining=%d \n " ,
sig , len , rs - > len ) ;
return - EIO ;
}
return 0 ;
}
2005-06-22 04:16:47 +04:00
/*
* return length of name field ; 0 : not found , - 1 : to be ignored
*/
2005-06-22 04:16:42 +04:00
int get_rock_ridge_filename ( struct iso_directory_record * de ,
char * retname , struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2005-06-22 04:16:46 +04:00
struct rock_state rs ;
2005-06-22 04:16:43 +04:00
struct rock_ridge * rr ;
int sig ;
int retnamlen = 0 ;
int truncate = 0 ;
2005-06-22 04:16:46 +04:00
int ret = 0 ;
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:42 +04:00
if ( ! ISOFS_SB ( inode - > i_sb ) - > s_rock )
return 0 ;
* retname = 0 ;
2005-06-22 04:16:46 +04:00
init_rock_state ( & rs , inode ) ;
setup_rock_ridge ( de , inode , & rs ) ;
2005-06-22 04:16:43 +04:00
repeat :
2005-06-22 04:16:46 +04:00
while ( rs . len > 2 ) { /* There may be one byte for padding somewhere */
rr = ( struct rock_ridge * ) rs . chr ;
2008-07-25 12:46:32 +04:00
/*
* Ignore rock ridge info if rr - > len is out of range , but
* don ' t return - EIO because that would make the file
* invisible .
*/
2005-06-22 04:16:43 +04:00
if ( rr - > len < 3 )
goto out ; /* Something got screwed up here */
2005-06-22 04:16:46 +04:00
sig = isonum_721 ( rs . chr ) ;
2005-06-22 04:16:51 +04:00
if ( rock_check_overflow ( & rs , sig ) )
goto eio ;
2005-06-22 04:16:46 +04:00
rs . chr + = rr - > len ;
rs . len - = rr - > len ;
2008-07-25 12:46:32 +04:00
/*
* As above , just ignore the rock ridge info if rr - > len
* is bogus .
*/
2005-06-22 04:16:46 +04:00
if ( rs . len < 0 )
2008-07-25 12:46:32 +04:00
goto out ; /* Something got screwed up here */
2005-06-22 04:16:43 +04:00
switch ( sig ) {
case SIG ( ' R ' , ' R ' ) :
if ( ( rr - > u . RR . flags [ 0 ] & RR_NM ) = = 0 )
goto out ;
break ;
case SIG ( ' S ' , ' P ' ) :
2005-06-22 04:16:44 +04:00
if ( check_sp ( rr , inode ) )
goto out ;
2005-06-22 04:16:43 +04:00
break ;
case SIG ( ' C ' , ' E ' ) :
2005-06-22 04:16:46 +04:00
rs . cont_extent = isonum_733 ( rr - > u . CE . extent ) ;
rs . cont_offset = isonum_733 ( rr - > u . CE . offset ) ;
rs . cont_size = isonum_733 ( rr - > u . CE . size ) ;
2005-06-22 04:16:43 +04:00
break ;
case SIG ( ' N ' , ' M ' ) :
if ( truncate )
2005-06-22 04:16:42 +04:00
break ;
2005-06-22 04:16:43 +04:00
if ( rr - > len < 5 )
2005-06-22 04:16:42 +04:00
break ;
2005-06-22 04:16:43 +04:00
/*
* If the flags are 2 or 4 , this indicates ' . ' or ' . . ' .
* We don ' t want to do anything with this , because it
* screws up the code that calls us . We don ' t really
* care anyways , since we can just use the non - RR
* name .
*/
if ( rr - > u . NM . flags & 6 )
2005-06-22 04:16:42 +04:00
break ;
2005-06-22 04:16:43 +04:00
if ( rr - > u . NM . flags & ~ 1 ) {
printk ( " Unsupported NM flag settings (%d) \n " ,
rr - > u . NM . flags ) ;
2005-06-22 04:16:42 +04:00
break ;
2005-06-22 04:16:43 +04:00
}
if ( ( strlen ( retname ) + rr - > len - 5 ) > = 254 ) {
truncate = 1 ;
2005-06-22 04:16:42 +04:00
break ;
}
2005-06-22 04:16:43 +04:00
strncat ( retname , rr - > u . NM . name , rr - > len - 5 ) ;
retnamlen + = rr - > len - 5 ;
break ;
case SIG ( ' R ' , ' E ' ) :
2005-06-22 04:16:46 +04:00
kfree ( rs . buffer ) ;
2005-06-22 04:16:43 +04:00
return - 1 ;
default :
break ;
2005-06-22 04:16:42 +04:00
}
2005-04-17 02:20:36 +04:00
}
2005-06-22 04:16:46 +04:00
ret = rock_continue ( & rs ) ;
if ( ret = = 0 )
goto repeat ;
if ( ret = = 1 )
return retnamlen ; /* If 0, this file did not have a NM field */
2005-06-22 04:16:43 +04:00
out :
2005-06-22 04:16:46 +04:00
kfree ( rs . buffer ) ;
return ret ;
2005-06-22 04:16:51 +04:00
eio :
ret = - EIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
static int
parse_rock_ridge_inode_internal ( struct iso_directory_record * de ,
struct inode * inode , int regard_xa )
{
2005-06-22 04:16:42 +04:00
int symlink_len = 0 ;
2005-06-22 04:16:43 +04:00
int cnt , sig ;
struct inode * reloc ;
struct rock_ridge * rr ;
int rootflag ;
2005-06-22 04:16:46 +04:00
struct rock_state rs ;
int ret = 0 ;
2005-06-22 04:16:42 +04:00
if ( ! ISOFS_SB ( inode - > i_sb ) - > s_rock )
return 0 ;
2005-06-22 04:16:46 +04:00
init_rock_state ( & rs , inode ) ;
setup_rock_ridge ( de , inode , & rs ) ;
2005-06-22 04:16:42 +04:00
if ( regard_xa ) {
2005-06-22 04:16:46 +04:00
rs . chr + = 14 ;
rs . len - = 14 ;
if ( rs . len < 0 )
rs . len = 0 ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
repeat :
2005-06-22 04:16:46 +04:00
while ( rs . len > 2 ) { /* There may be one byte for padding somewhere */
rr = ( struct rock_ridge * ) rs . chr ;
2008-07-25 12:46:32 +04:00
/*
* Ignore rock ridge info if rr - > len is out of range , but
* don ' t return - EIO because that would make the file
* invisible .
*/
2005-06-22 04:16:43 +04:00
if ( rr - > len < 3 )
goto out ; /* Something got screwed up here */
2005-06-22 04:16:46 +04:00
sig = isonum_721 ( rs . chr ) ;
2005-06-22 04:16:51 +04:00
if ( rock_check_overflow ( & rs , sig ) )
goto eio ;
2005-06-22 04:16:46 +04:00
rs . chr + = rr - > len ;
rs . len - = rr - > len ;
2008-07-25 12:46:32 +04:00
/*
* As above , just ignore the rock ridge info if rr - > len
* is bogus .
*/
2005-06-22 04:16:46 +04:00
if ( rs . len < 0 )
2008-07-25 12:46:32 +04:00
goto out ; /* Something got screwed up here */
2005-06-22 04:16:43 +04:00
switch ( sig ) {
2005-04-17 02:20:36 +04:00
# ifndef CONFIG_ZISOFS /* No flag for SF or ZF */
2005-06-22 04:16:43 +04:00
case SIG ( ' R ' , ' R ' ) :
if ( ( rr - > u . RR . flags [ 0 ] &
( RR_PX | RR_TF | RR_SL | RR_CL ) ) = = 0 )
goto out ;
break ;
2005-04-17 02:20:36 +04:00
# endif
2005-06-22 04:16:43 +04:00
case SIG ( ' S ' , ' P ' ) :
2005-06-22 04:16:44 +04:00
if ( check_sp ( rr , inode ) )
goto out ;
2005-06-22 04:16:43 +04:00
break ;
case SIG ( ' C ' , ' E ' ) :
2005-06-22 04:16:46 +04:00
rs . cont_extent = isonum_733 ( rr - > u . CE . extent ) ;
rs . cont_offset = isonum_733 ( rr - > u . CE . offset ) ;
rs . cont_size = isonum_733 ( rr - > u . CE . size ) ;
2005-06-22 04:16:43 +04:00
break ;
case SIG ( ' E ' , ' R ' ) :
ISOFS_SB ( inode - > i_sb ) - > s_rock = 1 ;
printk ( KERN_DEBUG " ISO 9660 Extensions: " ) ;
{
int p ;
for ( p = 0 ; p < rr - > u . ER . len_id ; p + + )
printk ( " %c " , rr - > u . ER . data [ p ] ) ;
}
printk ( " \n " ) ;
break ;
case SIG ( ' P ' , ' X ' ) :
inode - > i_mode = isonum_733 ( rr - > u . PX . mode ) ;
inode - > i_nlink = isonum_733 ( rr - > u . PX . n_links ) ;
inode - > i_uid = isonum_733 ( rr - > u . PX . uid ) ;
inode - > i_gid = isonum_733 ( rr - > u . PX . gid ) ;
break ;
case SIG ( ' P ' , ' N ' ) :
{
int high , low ;
high = isonum_733 ( rr - > u . PN . dev_high ) ;
low = isonum_733 ( rr - > u . PN . dev_low ) ;
/*
* The Rock Ridge standard specifies that if
* sizeof ( dev_t ) < = 4 , then the high field is
* unused , and the device number is completely
* stored in the low field . Some writers may
* ignore this subtlety ,
* and as a result we test to see if the entire
* device number is
* stored in the low field , and use that .
*/
if ( ( low & ~ 0xff ) & & high = = 0 ) {
inode - > i_rdev =
MKDEV ( low > > 8 , low & 0xff ) ;
} else {
inode - > i_rdev =
MKDEV ( high , low ) ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
}
break ;
case SIG ( ' T ' , ' F ' ) :
/*
* Some RRIP writers incorrectly place ctime in the
* TF_CREATE field . Try to handle this correctly for
* either case .
*/
/* Rock ridge never appears on a High Sierra disk */
cnt = 0 ;
if ( rr - > u . TF . flags & TF_CREATE ) {
inode - > i_ctime . tv_sec =
iso_date ( rr - > u . TF . times [ cnt + + ] . time ,
0 ) ;
inode - > i_ctime . tv_nsec = 0 ;
}
if ( rr - > u . TF . flags & TF_MODIFY ) {
inode - > i_mtime . tv_sec =
iso_date ( rr - > u . TF . times [ cnt + + ] . time ,
0 ) ;
inode - > i_mtime . tv_nsec = 0 ;
}
if ( rr - > u . TF . flags & TF_ACCESS ) {
inode - > i_atime . tv_sec =
iso_date ( rr - > u . TF . times [ cnt + + ] . time ,
0 ) ;
inode - > i_atime . tv_nsec = 0 ;
}
if ( rr - > u . TF . flags & TF_ATTRIBUTES ) {
inode - > i_ctime . tv_sec =
iso_date ( rr - > u . TF . times [ cnt + + ] . time ,
0 ) ;
inode - > i_ctime . tv_nsec = 0 ;
}
break ;
case SIG ( ' S ' , ' L ' ) :
{
int slen ;
struct SL_component * slp ;
struct SL_component * oldslp ;
slen = rr - > len - 5 ;
slp = & rr - > u . SL . link ;
inode - > i_size = symlink_len ;
while ( slen > 1 ) {
rootflag = 0 ;
switch ( slp - > flags & ~ 1 ) {
case 0 :
inode - > i_size + =
slp - > len ;
break ;
case 2 :
inode - > i_size + = 1 ;
break ;
case 4 :
inode - > i_size + = 2 ;
break ;
case 8 :
rootflag = 1 ;
inode - > i_size + = 1 ;
break ;
default :
printk ( " Symlink component flag "
" not implemented \n " ) ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
slen - = slp - > len + 2 ;
oldslp = slp ;
slp = ( struct SL_component * )
( ( ( char * ) slp ) + slp - > len + 2 ) ;
if ( slen < 2 ) {
if ( ( ( rr - > u . SL .
flags & 1 ) ! = 0 )
& &
( ( oldslp - >
flags & 1 ) = = 0 ) )
2005-06-22 04:16:42 +04:00
inode - > i_size + =
2005-06-22 04:16:43 +04:00
1 ;
break ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
/*
* If this component record isn ' t
* continued , then append a ' / ' .
*/
if ( ! rootflag
& & ( oldslp - > flags & 1 ) = = 0 )
inode - > i_size + = 1 ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
}
symlink_len = inode - > i_size ;
break ;
case SIG ( ' R ' , ' E ' ) :
printk ( KERN_WARNING " Attempt to read inode for "
" relocated directory \n " ) ;
goto out ;
case SIG ( ' C ' , ' L ' ) :
ISOFS_I ( inode ) - > i_first_extent =
isonum_733 ( rr - > u . CL . location ) ;
reloc =
isofs_iget ( inode - > i_sb ,
ISOFS_I ( inode ) - > i_first_extent ,
0 ) ;
2008-02-07 11:15:41 +03:00
if ( IS_ERR ( reloc ) ) {
ret = PTR_ERR ( reloc ) ;
2005-06-22 04:16:42 +04:00
goto out ;
2008-02-07 11:15:41 +03:00
}
2005-06-22 04:16:43 +04:00
inode - > i_mode = reloc - > i_mode ;
inode - > i_nlink = reloc - > i_nlink ;
inode - > i_uid = reloc - > i_uid ;
inode - > i_gid = reloc - > i_gid ;
inode - > i_rdev = reloc - > i_rdev ;
inode - > i_size = reloc - > i_size ;
inode - > i_blocks = reloc - > i_blocks ;
inode - > i_atime = reloc - > i_atime ;
inode - > i_ctime = reloc - > i_ctime ;
inode - > i_mtime = reloc - > i_mtime ;
iput ( reloc ) ;
break ;
2005-04-17 02:20:36 +04:00
# ifdef CONFIG_ZISOFS
2005-06-22 04:16:43 +04:00
case SIG ( ' Z ' , ' F ' ) : {
int algo ;
if ( ISOFS_SB ( inode - > i_sb ) - > s_nocompress )
2005-06-22 04:16:42 +04:00
break ;
2005-06-22 04:16:43 +04:00
algo = isonum_721 ( rr - > u . ZF . algorithm ) ;
if ( algo = = SIG ( ' p ' , ' z ' ) ) {
int block_shift =
isonum_711 ( & rr - > u . ZF . parms [ 1 ] ) ;
2009-09-23 16:44:56 +04:00
if ( block_shift > 17 ) {
2005-06-22 04:16:43 +04:00
printk ( KERN_WARNING " isofs: "
" Can't handle ZF block "
" size of 2^%d \n " ,
block_shift ) ;
} else {
/*
* Note : we don ' t change
* i_blocks here
*/
ISOFS_I ( inode ) - > i_file_format =
isofs_file_compressed ;
/*
* Parameters to compression
* algorithm ( header size ,
* block size )
*/
ISOFS_I ( inode ) - > i_format_parm [ 0 ] =
isonum_711 ( & rr - > u . ZF . parms [ 0 ] ) ;
ISOFS_I ( inode ) - > i_format_parm [ 1 ] =
isonum_711 ( & rr - > u . ZF . parms [ 1 ] ) ;
inode - > i_size =
isonum_733 ( rr - > u . ZF .
real_size ) ;
}
} else {
printk ( KERN_WARNING
" isofs: Unknown ZF compression "
" algorithm: %c%c \n " ,
rr - > u . ZF . algorithm [ 0 ] ,
rr - > u . ZF . algorithm [ 1 ] ) ;
2005-06-22 04:16:42 +04:00
}
2005-06-22 04:16:43 +04:00
break ;
}
# endif
default :
break ;
2005-06-22 04:16:42 +04:00
}
}
2005-06-22 04:16:46 +04:00
ret = rock_continue ( & rs ) ;
if ( ret = = 0 )
goto repeat ;
if ( ret = = 1 )
ret = 0 ;
2005-06-22 04:16:43 +04:00
out :
2005-06-22 04:16:46 +04:00
kfree ( rs . buffer ) ;
return ret ;
2005-06-22 04:16:51 +04:00
eio :
ret = - EIO ;
goto out ;
2005-04-17 02:20:36 +04:00
}
static char * get_symlink_chunk ( char * rpnt , struct rock_ridge * rr , char * plimit )
{
int slen ;
int rootflag ;
struct SL_component * oldslp ;
struct SL_component * slp ;
slen = rr - > len - 5 ;
slp = & rr - > u . SL . link ;
while ( slen > 1 ) {
rootflag = 0 ;
switch ( slp - > flags & ~ 1 ) {
case 0 :
if ( slp - > len > plimit - rpnt )
return NULL ;
memcpy ( rpnt , slp - > text , slp - > len ) ;
2005-06-22 04:16:42 +04:00
rpnt + = slp - > len ;
2005-04-17 02:20:36 +04:00
break ;
case 2 :
if ( rpnt > = plimit )
return NULL ;
2005-06-22 04:16:42 +04:00
* rpnt + + = ' . ' ;
2005-04-17 02:20:36 +04:00
break ;
case 4 :
if ( 2 > plimit - rpnt )
return NULL ;
2005-06-22 04:16:42 +04:00
* rpnt + + = ' . ' ;
* rpnt + + = ' . ' ;
2005-04-17 02:20:36 +04:00
break ;
case 8 :
if ( rpnt > = plimit )
return NULL ;
rootflag = 1 ;
2005-06-22 04:16:42 +04:00
* rpnt + + = ' / ' ;
2005-04-17 02:20:36 +04:00
break ;
default :
printk ( " Symlink component flag not implemented (%d) \n " ,
2005-06-22 04:16:42 +04:00
slp - > flags ) ;
2005-04-17 02:20:36 +04:00
}
slen - = slp - > len + 2 ;
oldslp = slp ;
2005-06-22 04:16:42 +04:00
slp = ( struct SL_component * ) ( ( char * ) slp + slp - > len + 2 ) ;
2005-04-17 02:20:36 +04:00
if ( slen < 2 ) {
/*
* If there is another SL record , and this component
* record isn ' t continued , then add a slash .
*/
if ( ( ! rootflag ) & & ( rr - > u . SL . flags & 1 ) & &
! ( oldslp - > flags & 1 ) ) {
if ( rpnt > = plimit )
return NULL ;
2005-06-22 04:16:42 +04:00
* rpnt + + = ' / ' ;
2005-04-17 02:20:36 +04:00
}
break ;
}
/*
* If this component record isn ' t continued , then append a ' / ' .
*/
if ( ! rootflag & & ! ( oldslp - > flags & 1 ) ) {
if ( rpnt > = plimit )
return NULL ;
2005-06-22 04:16:42 +04:00
* rpnt + + = ' / ' ;
2005-04-17 02:20:36 +04:00
}
}
return rpnt ;
}
2005-06-22 04:16:42 +04:00
int parse_rock_ridge_inode ( struct iso_directory_record * de , struct inode * inode )
2005-04-17 02:20:36 +04:00
{
2005-06-22 04:16:42 +04:00
int result = parse_rock_ridge_inode_internal ( de , inode , 0 ) ;
2005-06-22 04:16:47 +04:00
/*
* if rockridge flag was reset and we didn ' t look for attributes
* behind eventual XA attributes , have a look there
*/
2005-06-22 04:16:42 +04:00
if ( ( ISOFS_SB ( inode - > i_sb ) - > s_rock_offset = = - 1 )
& & ( ISOFS_SB ( inode - > i_sb ) - > s_rock = = 2 ) ) {
result = parse_rock_ridge_inode_internal ( de , inode , 14 ) ;
}
return result ;
2005-04-17 02:20:36 +04:00
}
2005-06-22 04:16:47 +04:00
/*
* readpage ( ) for symlinks : reads symlink contents into the page and either
* makes it uptodate and returns 0 or returns error ( - EIO )
*/
2005-04-17 02:20:36 +04:00
static int rock_ridge_symlink_readpage ( struct file * file , struct page * page )
{
struct inode * inode = page - > mapping - > host ;
2005-06-22 04:16:42 +04:00
struct iso_inode_info * ei = ISOFS_I ( inode ) ;
2005-04-17 02:20:36 +04:00
char * link = kmap ( page ) ;
unsigned long bufsize = ISOFS_BUFFER_SIZE ( inode ) ;
struct buffer_head * bh ;
char * rpnt = link ;
unsigned char * pnt ;
2005-06-22 04:16:46 +04:00
struct iso_directory_record * raw_de ;
2005-04-17 02:20:36 +04:00
unsigned long block , offset ;
int sig ;
struct rock_ridge * rr ;
2005-06-22 04:16:46 +04:00
struct rock_state rs ;
int ret ;
2005-04-17 02:20:36 +04:00
if ( ! ISOFS_SB ( inode - > i_sb ) - > s_rock )
goto error ;
2005-06-22 04:16:46 +04:00
init_rock_state ( & rs , inode ) ;
2005-04-17 02:20:36 +04:00
block = ei - > i_iget5_block ;
lock_kernel ( ) ;
bh = sb_bread ( inode - > i_sb , block ) ;
if ( ! bh )
goto out_noread ;
2005-06-22 04:16:42 +04:00
offset = ei - > i_iget5_offset ;
pnt = ( unsigned char * ) bh - > b_data + offset ;
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:46 +04:00
raw_de = ( struct iso_directory_record * ) pnt ;
2005-04-17 02:20:36 +04:00
/*
* If we go past the end of the buffer , there is some sort of error .
*/
if ( offset + * pnt > bufsize )
goto out_bad_span ;
2005-06-22 04:16:47 +04:00
/*
* Now test for possible Rock Ridge extensions which will override
* some of these numbers in the inode structure .
*/
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:46 +04:00
setup_rock_ridge ( raw_de , inode , & rs ) ;
2005-04-17 02:20:36 +04:00
2005-06-22 04:16:43 +04:00
repeat :
2005-06-22 04:16:46 +04:00
while ( rs . len > 2 ) { /* There may be one byte for padding somewhere */
rr = ( struct rock_ridge * ) rs . chr ;
2005-04-17 02:20:36 +04:00
if ( rr - > len < 3 )
goto out ; /* Something got screwed up here */
2005-06-22 04:16:46 +04:00
sig = isonum_721 ( rs . chr ) ;
2005-06-22 04:16:51 +04:00
if ( rock_check_overflow ( & rs , sig ) )
goto out ;
2005-06-22 04:16:46 +04:00
rs . chr + = rr - > len ;
rs . len - = rr - > len ;
if ( rs . len < 0 )
2005-04-17 02:20:36 +04:00
goto out ; /* corrupted isofs */
switch ( sig ) {
case SIG ( ' R ' , ' R ' ) :
if ( ( rr - > u . RR . flags [ 0 ] & RR_SL ) = = 0 )
goto out ;
break ;
case SIG ( ' S ' , ' P ' ) :
2005-06-22 04:16:44 +04:00
if ( check_sp ( rr , inode ) )
goto out ;
2005-04-17 02:20:36 +04:00
break ;
case SIG ( ' S ' , ' L ' ) :
rpnt = get_symlink_chunk ( rpnt , rr ,
link + ( PAGE_SIZE - 1 ) ) ;
if ( rpnt = = NULL )
goto out ;
break ;
case SIG ( ' C ' , ' E ' ) :
/* This tells is if there is a continuation record */
2005-06-22 04:16:46 +04:00
rs . cont_extent = isonum_733 ( rr - > u . CE . extent ) ;
rs . cont_offset = isonum_733 ( rr - > u . CE . offset ) ;
rs . cont_size = isonum_733 ( rr - > u . CE . size ) ;
2005-04-17 02:20:36 +04:00
default :
break ;
}
}
2005-06-22 04:16:46 +04:00
ret = rock_continue ( & rs ) ;
if ( ret = = 0 )
goto repeat ;
if ( ret < 0 )
goto fail ;
2005-04-17 02:20:36 +04:00
if ( rpnt = = link )
goto fail ;
brelse ( bh ) ;
* rpnt = ' \0 ' ;
unlock_kernel ( ) ;
SetPageUptodate ( page ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
return 0 ;
/* error exit from macro */
2005-06-22 04:16:43 +04:00
out :
2005-06-22 04:16:46 +04:00
kfree ( rs . buffer ) ;
2005-04-17 02:20:36 +04:00
goto fail ;
2005-06-22 04:16:43 +04:00
out_noread :
2005-04-17 02:20:36 +04:00
printk ( " unable to read i-node block " ) ;
goto fail ;
2005-06-22 04:16:43 +04:00
out_bad_span :
2005-04-17 02:20:36 +04:00
printk ( " symlink spans iso9660 blocks \n " ) ;
2005-06-22 04:16:43 +04:00
fail :
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
unlock_kernel ( ) ;
2005-06-22 04:16:43 +04:00
error :
2005-04-17 02:20:36 +04:00
SetPageError ( page ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
return - EIO ;
}
2006-06-28 15:26:44 +04:00
const struct address_space_operations isofs_symlink_aops = {
2005-06-22 04:16:42 +04:00
. readpage = rock_ridge_symlink_readpage
2005-04-17 02:20:36 +04:00
} ;