1 /* 2 * dir.c 3 * 4 * Copyright (c) 1999 Al Smith 5 */ 6 7 #include <linux/buffer_head.h> 8 #include "efs.h" 9 10 static int efs_readdir(struct file *, struct dir_context *); 11 12 const struct file_operations efs_dir_operations = { 13 .llseek = generic_file_llseek, 14 .read = generic_read_dir, 15 .iterate = efs_readdir, 16 }; 17 18 const struct inode_operations efs_dir_inode_operations = { 19 .lookup = efs_lookup, 20 }; 21 22 static int efs_readdir(struct file *file, struct dir_context *ctx) 23 { 24 struct inode *inode = file_inode(file); 25 efs_block_t block; 26 int slot; 27 28 if (inode->i_size & (EFS_DIRBSIZE-1)) 29 printk(KERN_WARNING "EFS: WARNING: readdir(): directory size not a multiple of EFS_DIRBSIZE\n"); 30 31 /* work out where this entry can be found */ 32 block = ctx->pos >> EFS_DIRBSIZE_BITS; 33 34 /* each block contains at most 256 slots */ 35 slot = ctx->pos & 0xff; 36 37 /* look at all blocks */ 38 while (block < inode->i_blocks) { 39 struct efs_dir *dirblock; 40 struct buffer_head *bh; 41 42 /* read the dir block */ 43 bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 44 45 if (!bh) { 46 printk(KERN_ERR "EFS: readdir(): failed to read dir block %d\n", block); 47 break; 48 } 49 50 dirblock = (struct efs_dir *) bh->b_data; 51 52 if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 53 printk(KERN_ERR "EFS: readdir(): invalid directory block\n"); 54 brelse(bh); 55 break; 56 } 57 58 for (; slot < dirblock->slots; slot++) { 59 struct efs_dentry *dirslot; 60 efs_ino_t inodenum; 61 const char *nameptr; 62 int namelen; 63 64 if (dirblock->space[slot] == 0) 65 continue; 66 67 dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 68 69 inodenum = be32_to_cpu(dirslot->inode); 70 namelen = dirslot->namelen; 71 nameptr = dirslot->name; 72 73 #ifdef DEBUG 74 printk(KERN_DEBUG "EFS: readdir(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", block, slot, dirblock->slots-1, inodenum, nameptr, namelen); 75 #endif 76 if (!namelen) 77 continue; 78 /* found the next entry */ 79 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 80 81 /* sanity check */ 82 if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 83 printk(KERN_WARNING "EFS: directory entry %d exceeds directory block\n", slot); 84 continue; 85 } 86 87 /* copy filename and data in dirslot */ 88 if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) { 89 brelse(bh); 90 return 0; 91 } 92 } 93 brelse(bh); 94 95 slot = 0; 96 block++; 97 } 98 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 99 return 0; 100 } 101 102