2005-04-17 02:20:36 +04:00
/*
* namei . c
*
* Copyright ( c ) 1999 Al Smith
*
* Portions derived from work ( c ) 1995 , 1996 Christian Vogelgsang .
*/
# include <linux/buffer_head.h>
# include <linux/string.h>
2007-10-22 03:42:09 +04:00
# include <linux/exportfs.h>
2008-02-24 02:23:51 +03:00
# include "efs.h"
2007-10-22 03:42:09 +04:00
2005-04-17 02:20:36 +04:00
static efs_ino_t efs_find_entry ( struct inode * inode , const char * name , int len ) {
struct buffer_head * bh ;
int slot , namelen ;
char * nameptr ;
struct efs_dir * dirblock ;
struct efs_dentry * dirslot ;
efs_ino_t inodenum ;
efs_block_t block ;
if ( inode - > i_size & ( EFS_DIRBSIZE - 1 ) )
printk ( KERN_WARNING " EFS: WARNING: find_entry(): directory size not a multiple of EFS_DIRBSIZE \n " ) ;
for ( block = 0 ; block < inode - > i_blocks ; block + + ) {
bh = sb_bread ( inode - > i_sb , efs_bmap ( inode , block ) ) ;
if ( ! bh ) {
printk ( KERN_ERR " EFS: find_entry(): failed to read dir block %d \n " , block ) ;
return 0 ;
}
dirblock = ( struct efs_dir * ) bh - > b_data ;
if ( be16_to_cpu ( dirblock - > magic ) ! = EFS_DIRBLK_MAGIC ) {
printk ( KERN_ERR " EFS: find_entry(): invalid directory block \n " ) ;
brelse ( bh ) ;
return ( 0 ) ;
}
for ( slot = 0 ; slot < dirblock - > slots ; slot + + ) {
dirslot = ( struct efs_dentry * ) ( ( ( char * ) bh - > b_data ) + EFS_SLOTAT ( dirblock , slot ) ) ;
namelen = dirslot - > namelen ;
nameptr = dirslot - > name ;
if ( ( namelen = = len ) & & ( ! memcmp ( name , nameptr , len ) ) ) {
inodenum = be32_to_cpu ( dirslot - > inode ) ;
brelse ( bh ) ;
return ( inodenum ) ;
}
}
brelse ( bh ) ;
}
return ( 0 ) ;
}
struct dentry * efs_lookup ( struct inode * dir , struct dentry * dentry , struct nameidata * nd ) {
efs_ino_t inodenum ;
2011-07-09 05:20:11 +04:00
struct inode * inode = NULL ;
2005-04-17 02:20:36 +04:00
inodenum = efs_find_entry ( dir , dentry - > d_name . name , dentry - > d_name . len ) ;
2011-07-09 05:20:11 +04:00
if ( inodenum )
2008-02-07 11:15:34 +03:00
inode = efs_iget ( dir - > i_sb , inodenum ) ;
2005-04-17 02:20:36 +04:00
2008-08-11 19:33:57 +04:00
return d_splice_alias ( inode , dentry ) ;
2005-04-17 02:20:36 +04:00
}
2007-10-22 03:42:09 +04:00
static struct inode * efs_nfs_get_inode ( struct super_block * sb , u64 ino ,
u32 generation )
2007-07-17 15:04:29 +04:00
{
struct inode * inode ;
if ( ino = = 0 )
return ERR_PTR ( - ESTALE ) ;
2008-02-07 11:15:34 +03:00
inode = efs_iget ( sb , ino ) ;
if ( IS_ERR ( inode ) )
return ERR_CAST ( inode ) ;
2007-07-17 15:04:29 +04:00
2008-02-07 11:15:34 +03:00
if ( generation & & inode - > i_generation ! = generation ) {
2007-10-22 03:42:09 +04:00
iput ( inode ) ;
return ERR_PTR ( - ESTALE ) ;
2007-07-17 15:04:29 +04:00
}
2007-10-22 03:42:09 +04:00
return inode ;
}
2007-07-17 15:04:29 +04:00
2007-10-22 03:42:09 +04:00
struct dentry * efs_fh_to_dentry ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_dentry ( sb , fid , fh_len , fh_type ,
efs_nfs_get_inode ) ;
}
struct dentry * efs_fh_to_parent ( struct super_block * sb , struct fid * fid ,
int fh_len , int fh_type )
{
return generic_fh_to_parent ( sb , fid , fh_len , fh_type ,
efs_nfs_get_inode ) ;
2007-07-17 15:04:29 +04:00
}
2005-04-17 02:20:36 +04:00
struct dentry * efs_get_parent ( struct dentry * child )
{
2008-08-11 17:49:04 +04:00
struct dentry * parent = ERR_PTR ( - ENOENT ) ;
2005-04-17 02:20:36 +04:00
efs_ino_t ino ;
ino = efs_find_entry ( child - > d_inode , " .. " , 2 ) ;
2008-08-11 17:49:04 +04:00
if ( ino )
parent = d_obtain_alias ( efs_iget ( child - > d_inode - > i_sb , ino ) ) ;
2005-04-17 02:20:36 +04:00
2008-08-11 17:49:04 +04:00
return parent ;
2005-04-17 02:20:36 +04:00
}