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