2005-04-17 02:20:36 +04:00
/*
* symlink . c
*
* PURPOSE
* Symlink 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
2007-07-21 15:37:18 +04:00
* ( C ) 1999 Stelias Computing Inc
2005-04-17 02:20:36 +04:00
*
* HISTORY
*
* 04 / 16 / 99 blf Created .
*
*/
# include "udfdecl.h"
# include <asm/uaccess.h>
# include <linux/errno.h>
# include <linux/fs.h>
# include <linux/udf_fs.h>
# include <linux/time.h>
# include <linux/mm.h>
# include <linux/stat.h>
# include <linux/slab.h>
# include <linux/pagemap.h>
# include <linux/smp_lock.h>
# include <linux/buffer_head.h>
# include "udf_i.h"
2007-07-21 15:37:18 +04:00
static void udf_pc_to_char ( struct super_block * sb , char * from , int fromlen , char * to )
2005-04-17 02:20:36 +04:00
{
struct pathComponent * pc ;
int elen = 0 ;
char * p = to ;
2007-07-19 12:47:43 +04:00
while ( elen < fromlen ) {
2005-04-17 02:20:36 +04:00
pc = ( struct pathComponent * ) ( from + elen ) ;
2007-07-19 12:47:43 +04:00
switch ( pc - > componentType ) {
case 1 :
if ( pc - > lengthComponentIdent = = 0 ) {
p = to ;
2005-04-17 02:20:36 +04:00
* p + + = ' / ' ;
2007-07-19 12:47:43 +04:00
}
break ;
case 3 :
memcpy ( p , " ../ " , 3 ) ;
p + = 3 ;
break ;
case 4 :
memcpy ( p , " ./ " , 2 ) ;
p + = 2 ;
/* that would be . - just ignore */
break ;
case 5 :
p + = udf_get_filename ( sb , pc - > componentIdent , p ,
pc - > lengthComponentIdent ) ;
* p + + = ' / ' ;
break ;
2005-04-17 02:20:36 +04:00
}
elen + = sizeof ( struct pathComponent ) + pc - > lengthComponentIdent ;
}
2007-07-19 12:47:43 +04:00
if ( p > to + 1 )
2005-04-17 02:20:36 +04:00
p [ - 1 ] = ' \0 ' ;
else
p [ 0 ] = ' \0 ' ;
}
static int udf_symlink_filler ( struct file * file , struct page * page )
{
struct inode * inode = page - > mapping - > host ;
struct buffer_head * bh = NULL ;
char * symlink ;
int err = - EIO ;
char * p = kmap ( page ) ;
lock_kernel ( ) ;
2007-07-21 15:37:18 +04:00
if ( UDF_I_ALLOCTYPE ( inode ) = = ICBTAG_FLAG_AD_IN_ICB ) {
2005-04-17 02:20:36 +04:00
symlink = UDF_I_DATA ( inode ) + UDF_I_LENEATTR ( inode ) ;
2007-07-21 15:37:18 +04:00
} else {
2005-04-17 02:20:36 +04:00
bh = sb_bread ( inode - > i_sb , udf_block_map ( inode , 0 ) ) ;
if ( ! bh )
goto out ;
symlink = bh - > b_data ;
}
udf_pc_to_char ( inode - > i_sb , symlink , inode - > i_size , p ) ;
2007-05-08 11:35:16 +04:00
brelse ( bh ) ;
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
SetPageUptodate ( page ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
return 0 ;
2007-07-21 15:37:18 +04:00
out :
2005-04-17 02:20:36 +04:00
unlock_kernel ( ) ;
SetPageError ( page ) ;
kunmap ( page ) ;
unlock_page ( page ) ;
return err ;
}
/*
* symlinks can ' t do much . . .
*/
2006-06-28 15:26:44 +04:00
const struct address_space_operations udf_symlink_aops = {
2007-07-21 15:37:18 +04:00
. readpage = udf_symlink_filler ,
2005-04-17 02:20:36 +04:00
} ;