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