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 pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n", 30 __func__); 31 32 /* work out where this entry can be found */ 33 block = ctx->pos >> EFS_DIRBSIZE_BITS; 34 35 /* each block contains at most 256 slots */ 36 slot = ctx->pos & 0xff; 37 38 /* look at all blocks */ 39 while (block < inode->i_blocks) { 40 struct efs_dir *dirblock; 41 struct buffer_head *bh; 42 43 /* read the dir block */ 44 bh = sb_bread(inode->i_sb, efs_bmap(inode, block)); 45 46 if (!bh) { 47 pr_err("%s(): failed to read dir block %d\n", 48 __func__, block); 49 break; 50 } 51 52 dirblock = (struct efs_dir *) bh->b_data; 53 54 if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) { 55 pr_err("%s(): invalid directory block\n", __func__); 56 brelse(bh); 57 break; 58 } 59 60 for (; slot < dirblock->slots; slot++) { 61 struct efs_dentry *dirslot; 62 efs_ino_t inodenum; 63 const char *nameptr; 64 int namelen; 65 66 if (dirblock->space[slot] == 0) 67 continue; 68 69 dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot)); 70 71 inodenum = be32_to_cpu(dirslot->inode); 72 namelen = dirslot->namelen; 73 nameptr = dirslot->name; 74 pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n", 75 __func__, block, slot, dirblock->slots-1, 76 inodenum, nameptr, namelen); 77 if (!namelen) 78 continue; 79 /* found the next entry */ 80 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 81 82 /* sanity check */ 83 if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) { 84 pr_warn("directory entry %d exceeds directory block\n", 85 slot); 86 continue; 87 } 88 89 /* copy filename and data in dirslot */ 90 if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) { 91 brelse(bh); 92 return 0; 93 } 94 } 95 brelse(bh); 96 97 slot = 0; 98 block++; 99 } 100 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot; 101 return 0; 102 } 103 104