0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/buffer_head.h>
0009 #include "efs.h"
0010
0011 static int efs_readdir(struct file *, struct dir_context *);
0012
0013 const struct file_operations efs_dir_operations = {
0014 .llseek = generic_file_llseek,
0015 .read = generic_read_dir,
0016 .iterate_shared = efs_readdir,
0017 };
0018
0019 const struct inode_operations efs_dir_inode_operations = {
0020 .lookup = efs_lookup,
0021 };
0022
0023 static int efs_readdir(struct file *file, struct dir_context *ctx)
0024 {
0025 struct inode *inode = file_inode(file);
0026 efs_block_t block;
0027 int slot;
0028
0029 if (inode->i_size & (EFS_DIRBSIZE-1))
0030 pr_warn("%s(): directory size not a multiple of EFS_DIRBSIZE\n",
0031 __func__);
0032
0033
0034 block = ctx->pos >> EFS_DIRBSIZE_BITS;
0035
0036
0037 slot = ctx->pos & 0xff;
0038
0039
0040 while (block < inode->i_blocks) {
0041 struct efs_dir *dirblock;
0042 struct buffer_head *bh;
0043
0044
0045 bh = sb_bread(inode->i_sb, efs_bmap(inode, block));
0046
0047 if (!bh) {
0048 pr_err("%s(): failed to read dir block %d\n",
0049 __func__, block);
0050 break;
0051 }
0052
0053 dirblock = (struct efs_dir *) bh->b_data;
0054
0055 if (be16_to_cpu(dirblock->magic) != EFS_DIRBLK_MAGIC) {
0056 pr_err("%s(): invalid directory block\n", __func__);
0057 brelse(bh);
0058 break;
0059 }
0060
0061 for (; slot < dirblock->slots; slot++) {
0062 struct efs_dentry *dirslot;
0063 efs_ino_t inodenum;
0064 const char *nameptr;
0065 int namelen;
0066
0067 if (dirblock->space[slot] == 0)
0068 continue;
0069
0070 dirslot = (struct efs_dentry *) (((char *) bh->b_data) + EFS_SLOTAT(dirblock, slot));
0071
0072 inodenum = be32_to_cpu(dirslot->inode);
0073 namelen = dirslot->namelen;
0074 nameptr = dirslot->name;
0075 pr_debug("%s(): block %d slot %d/%d: inode %u, name \"%s\", namelen %u\n",
0076 __func__, block, slot, dirblock->slots-1,
0077 inodenum, nameptr, namelen);
0078 if (!namelen)
0079 continue;
0080
0081 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
0082
0083
0084 if (nameptr - (char *) dirblock + namelen > EFS_DIRBSIZE) {
0085 pr_warn("directory entry %d exceeds directory block\n",
0086 slot);
0087 continue;
0088 }
0089
0090
0091 if (!dir_emit(ctx, nameptr, namelen, inodenum, DT_UNKNOWN)) {
0092 brelse(bh);
0093 return 0;
0094 }
0095 }
0096 brelse(bh);
0097
0098 slot = 0;
0099 block++;
0100 }
0101 ctx->pos = (block << EFS_DIRBSIZE_BITS) | slot;
0102 return 0;
0103 }