2005-04-17 02:20:36 +04:00
/*
* dir . c
*
* Copyright ( c ) 1999 Al Smith
*/
# include <linux/buffer_head.h>
2008-02-24 02:23:51 +03:00
# include "efs.h"
2005-04-17 02:20:36 +04:00
2013-05-16 09:41:10 +04:00
static int efs_readdir ( struct file * , struct dir_context * ) ;
2005-04-17 02:20:36 +04:00
2006-03-28 13:56:42 +04:00
const struct file_operations efs_dir_operations = {
2009-06-17 07:35:46 +04:00
. llseek = generic_file_llseek ,
2005-04-17 02:20:36 +04:00
. read = generic_read_dir ,
2013-05-16 09:41:10 +04:00
. iterate = efs_readdir ,
2005-04-17 02:20:36 +04:00
} ;
2007-02-12 11:55:38 +03:00
const struct inode_operations efs_dir_inode_operations = {
2005-04-17 02:20:36 +04:00
. lookup = efs_lookup ,
} ;
2013-05-16 09:41:10 +04:00
static int efs_readdir ( struct file * file , struct dir_context * ctx )
{
struct inode * inode = file_inode ( file ) ;
2005-04-17 02:20:36 +04:00
efs_block_t block ;
2013-05-16 09:41:10 +04:00
int slot ;
2005-04-17 02:20:36 +04:00
if ( inode - > i_size & ( EFS_DIRBSIZE - 1 ) )
2014-06-05 03:12:12 +04:00
pr_warn ( " %s(): directory size not a multiple of EFS_DIRBSIZE \n " ,
__func__ ) ;
2005-04-17 02:20:36 +04:00
/* work out where this entry can be found */
2013-05-16 09:41:10 +04:00
block = ctx - > pos > > EFS_DIRBSIZE_BITS ;
2005-04-17 02:20:36 +04:00
/* each block contains at most 256 slots */
2013-05-16 09:41:10 +04:00
slot = ctx - > pos & 0xff ;
2005-04-17 02:20:36 +04:00
/* look at all blocks */
while ( block < inode - > i_blocks ) {
2013-05-16 09:41:10 +04:00
struct efs_dir * dirblock ;
struct buffer_head * bh ;
2005-04-17 02:20:36 +04:00
/* read the dir block */
bh = sb_bread ( inode - > i_sb , efs_bmap ( inode , block ) ) ;
if ( ! bh ) {
2014-06-05 03:12:12 +04:00
pr_err ( " %s(): failed to read dir block %d \n " ,
__func__ , block ) ;
2005-04-17 02:20:36 +04:00
break ;
}
dirblock = ( struct efs_dir * ) bh - > b_data ;
if ( be16_to_cpu ( dirblock - > magic ) ! = EFS_DIRBLK_MAGIC ) {
2014-06-05 03:12:12 +04:00
pr_err ( " %s(): invalid directory block \n " , __func__ ) ;
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
break ;
}
2013-05-16 09:41:10 +04:00
for ( ; slot < dirblock - > slots ; slot + + ) {
struct efs_dentry * dirslot ;
efs_ino_t inodenum ;
const char * nameptr ;
int namelen ;
if ( dirblock - > space [ slot ] = = 0 )
2005-04-17 02:20:36 +04:00
continue ;
dirslot = ( struct efs_dentry * ) ( ( ( char * ) bh - > b_data ) + EFS_SLOTAT ( dirblock , slot ) ) ;
inodenum = be32_to_cpu ( dirslot - > inode ) ;
namelen = dirslot - > namelen ;
nameptr = dirslot - > name ;
2014-06-05 03:12:13 +04:00
pr_debug ( " %s(): block %d slot %d/%d: inode %u, name \" %s \" , namelen %u \n " ,
__func__ , block , slot , dirblock - > slots - 1 ,
inodenum , nameptr , namelen ) ;
2013-05-16 09:41:10 +04:00
if ( ! namelen )
continue ;
/* found the next entry */
ctx - > pos = ( block < < EFS_DIRBSIZE_BITS ) | slot ;
/* sanity check */
if ( nameptr - ( char * ) dirblock + namelen > EFS_DIRBSIZE ) {
2014-06-05 03:12:12 +04:00
pr_warn ( " directory entry %d exceeds directory block \n " ,
slot ) ;
2013-05-16 09:41:10 +04:00
continue ;
}
/* copy filename and data in dirslot */
if ( ! dir_emit ( ctx , nameptr , namelen , inodenum , DT_UNKNOWN ) ) {
2005-04-17 02:20:36 +04:00
brelse ( bh ) ;
2013-05-16 09:41:10 +04:00
return 0 ;
2005-04-17 02:20:36 +04:00
}
}
brelse ( bh ) ;
slot = 0 ;
block + + ;
}
2013-05-16 09:41:10 +04:00
ctx - > pos = ( block < < EFS_DIRBSIZE_BITS ) | slot ;
2005-04-17 02:20:36 +04:00
return 0 ;
}