root/fs/affs/dir.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. affs_readdir

   1 /*
   2  *  linux/fs/affs/dir.c
   3  *
   4  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   5  *
   6  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   7  *
   8  *  (C) 1991  Linus Torvalds - minix filesystem
   9  *
  10  *  affs directory handling functions
  11  */
  12 
  13 #include <linux/errno.h>
  14 
  15 #include <asm/segment.h>
  16 
  17 #include <linux/fs.h>
  18 #include <linux/affs_fs.h>
  19 #include <linux/kernel.h>
  20 #include <linux/affs_fs.h>
  21 #include <linux/stat.h>
  22 #include <linux/string.h>
  23 #include <linux/sched.h>
  24 
  25 static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
  26 
  27 struct file_operations affs_dir_operations = {
  28         NULL,                   /* lseek - default */
  29         NULL,                   /* read */
  30         NULL,                   /* write - bad */
  31         affs_readdir,           /* readdir */
  32         NULL,                   /* select - default */
  33         NULL,                   /* ioctl - default */
  34         NULL,                   /* mmap */
  35         NULL,                   /* no special open code */
  36         NULL,                   /* no special release code */
  37         NULL                    /* fsync */
  38 };
  39 
  40 /*
  41  * directories can handle most operations...
  42  */
  43 struct inode_operations affs_dir_inode_operations = {
  44         &affs_dir_operations,   /* default directory file-ops */
  45         NULL,                   /* create */
  46         affs_lookup,            /* lookup */
  47         NULL,                   /* link */
  48         NULL,                   /* unlink */
  49         NULL,                   /* symlink */
  50         NULL,                   /* mkdir */
  51         NULL,                   /* rmdir */
  52         NULL,                   /* mknod */
  53         NULL,                   /* rename */
  54         NULL,                   /* readlink */
  55         NULL,                   /* follow_link */
  56         NULL,                   /* bmap */
  57         NULL,                   /* truncate */
  58         NULL                    /* permission */
  59 };
  60 
  61 /* This is used to speed up lookup.  Without this we would need to
  62 make a linear search of the directory to find the file that the
  63 directory read just returned.  This is a single element cache. */
  64 
  65 /* struct lookup_cache cache = {0,}; */
  66 
  67 static int affs_readdir(struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  68         void * dirent, filldir_t filldir)
  69 {
  70         int i, j, chain_pos, hash_pos, reclen, ino;
  71         char *name;
  72         struct buffer_head *dir_bh;
  73         struct buffer_head *fh_bh;
  74         void *dir_data;
  75         void *fh_data;
  76 
  77 #ifdef DEBUG
  78         printk ("AFFS: readdir: inode=%d f_pos=%d\n",
  79                 inode->i_ino, filp->f_pos);
  80 #endif
  81         
  82         if (!inode || !S_ISDIR(inode->i_mode))
  83                 return -EBADF;
  84 
  85         while ((unsigned long)filp->f_pos < 2) {
  86                 if (filp->f_pos == 0) {
  87                         if (filldir (dirent, ".", 1, filp->f_pos, inode->i_ino) < 0)
  88                                 return 0;
  89                 } else {
  90                         i = affs_parent_ino (inode);
  91                         if (filldir (dirent, "..", 2, filp->f_pos, i) < 0)
  92                                 return 0;
  93                 }
  94                 filp->f_pos++;
  95         }
  96         /* No caching here.  I've got 16 megs why should I care?  :-) */
  97         chain_pos = (filp->f_pos - 2) & 0xffff;
  98         if (chain_pos == 0xffff)
  99                 return 0;
 100         hash_pos = (filp->f_pos - 2) >> 16;
 101 #ifdef DEBUG
 102         printk ("AFFS: hash_pos=%d chain_pos=%d\n", hash_pos, chain_pos);
 103 #endif
 104         if (!(dir_bh = affs_pread(inode, inode->i_ino, &dir_data)))
 105                 return 0;
 106         /* HASH_POS should already be on a used entry unless it is
 107            the first read of the directory.  Will this break the
 108            dirtell thing somehow? */
 109         i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode), dir_data,
 110                                        &hash_pos);
 111         j = chain_pos;
 112         for (;;) {
 113                 if (i <= 0) {
 114 #ifdef DEBUG
 115                         printk ("AFFS: bad f_pos in readdir\n");
 116 #endif
 117                         brelse (dir_bh);
 118                         return 0;
 119                 }
 120                 ino = i;
 121                 if (!(fh_bh = affs_pread (inode, i, &fh_data))) {
 122                         brelse (dir_bh);
 123                         return 0;
 124                 }
 125                 i = affs_get_fh_hash_link (AFFS_I2BSIZE (inode), fh_data);
 126                 if (j == 0) {
 127                         j = 1;
 128                         if (i <= 0) {
 129                                 hash_pos++;
 130                                 i = affs_find_next_hash_entry (AFFS_I2BSIZE (inode),
 131                                                                dir_data, &hash_pos);
 132                                 if (i <= 0)
 133                                         chain_pos = 0xffff;
 134                                 else
 135                                         chain_pos = 0;
 136                         } else
 137                                 chain_pos++;
 138                         reclen = affs_get_file_name (AFFS_I2BSIZE (inode),
 139                                                      fh_data, &name);
 140                         if (filldir (dirent, name, reclen, filp->f_pos, ino) < 0) {
 141                                 brelse (fh_bh);
 142                                 brelse (dir_bh);
 143                                 return 0;
 144                         }
 145                         filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 146                 }
 147                 brelse (fh_bh);
 148                 j--;
 149         }
 150 }

/* [previous][next][first][last][top][bottom][index][help] */