root/fs/affs/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. affs_dir_read
  2. affs_readdir
  3. affs_dir_truncate

   1 /*
   2  *  linux/fs/affs/dir.c
   3  *
   4  *  (c) 1996  Hans-Joachim Widmaier - Modifications for larger blocks
   5  *              and hard links.
   6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
   7  *
   8  *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
   9  *
  10  *  (C) 1991  Linus Torvalds - minix filesystem
  11  *
  12  *  affs directory handling functions
  13  *
  14  */
  15 
  16 #include <asm/segment.h>
  17 #include <linux/errno.h>
  18 #include <linux/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/mm.h>
  24 #include <linux/amigaffs.h>
  25 
  26 static int affs_readdir(struct inode *, struct file *, void *, filldir_t);
  27 static int affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count);
  28 
  29 static struct file_operations affs_dir_operations = {
  30         NULL,                   /* lseek - default */
  31         affs_dir_read,          /* read */
  32         NULL,                   /* write - bad */
  33         affs_readdir,           /* readdir */
  34         NULL,                   /* select - default */
  35         NULL,                   /* ioctl - default */
  36         NULL,                   /* mmap */
  37         NULL,                   /* no special open code */
  38         NULL,                   /* no special release code */
  39         file_fsync              /* default fsync */
  40 };
  41 
  42 /*
  43  * directories can handle most operations...
  44  */
  45 struct inode_operations affs_dir_inode_operations = {
  46         &affs_dir_operations,   /* default directory file-ops */
  47         affs_create,            /* create */
  48         affs_lookup,            /* lookup */
  49         affs_link,              /* link */
  50         affs_unlink,            /* unlink */
  51         affs_symlink,           /* symlink */
  52         affs_mkdir,             /* mkdir */
  53         affs_rmdir,             /* rmdir */
  54         NULL,                   /* mknod */
  55         affs_rename,            /* rename */
  56         NULL,                   /* readlink */
  57         NULL,                   /* follow_link */
  58         NULL,                   /* readpage */
  59         NULL,                   /* writepage */
  60         NULL,                   /* bmap */
  61         affs_dir_truncate,      /* truncate */
  62         NULL                    /* permissions */
  63 };
  64 
  65 static int
  66 affs_dir_read(struct inode * inode, struct file * filp, char * buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
  67 {
  68         return -EISDIR;
  69 }
  70 
  71 static int
  72 affs_readdir(struct inode *inode, struct file *filp, void *dirent, filldir_t filldir)
     /* [previous][next][first][last][top][bottom][index][help] */
  73 {
  74         int                      j, namelen;
  75         LONG                     i;
  76         ULONG                    hash_pos;
  77         ULONG                    chain_pos;
  78         unsigned long            ino;
  79         unsigned long                    old;
  80         int stored;
  81         char *name;
  82         struct buffer_head *dir_bh;
  83         struct buffer_head *fh_bh;
  84         struct inode       *dir;
  85 
  86         pr_debug("AFFS: readdir(ino=%ld,f_pos=%lu)\n",inode->i_ino,filp->f_pos);
  87         
  88 
  89         if (!inode || !S_ISDIR(inode->i_mode))
  90                 return -EBADF;
  91 
  92         stored = 0;
  93         dir_bh = NULL;
  94         fh_bh  = NULL;
  95         dir    = NULL;
  96         old    = filp->f_pos & 0x80000000;
  97         filp->f_pos &= 0x7FFFFFFF;
  98 
  99         if (filp->f_pos == 0) {
 100                 filp->private_data = (void *)0;
 101                 if (filldir(dirent,".",1,filp->f_pos,inode->i_ino) < 0) {
 102                         return 0;
 103                 }
 104                 ++filp->f_pos;
 105                 stored++;
 106         }
 107         if (filp->f_pos == 1) {
 108                 if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode)) < 0) {
 109                         filp->f_pos |= 0x80000000;
 110                         return stored;
 111                 }
 112                 filp->f_pos = 2;
 113                 stored++;
 114         }
 115 
 116         /* Read original if this is a link */
 117         ino = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
 118         if (!(dir = iget(inode->i_sb,ino)))
 119                 return stored;
 120         
 121         chain_pos = (filp->f_pos - 2) & 0xffff;
 122         hash_pos  = (filp->f_pos - 2) >> 16;
 123         if (chain_pos == 0xffff) {
 124                 printk("AFFS: more than 65535 entries in chain\n");
 125                 chain_pos = 0;
 126                 hash_pos++;
 127                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 128         }
 129         if (!(dir_bh = affs_bread(inode->i_dev,ino,AFFS_I2BSIZE(inode))))
 130                 goto readdir_done;
 131 
 132         while (!stored || !old) {
 133                 while (hash_pos < AFFS_I2HSIZE(inode) &&
 134                      !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
 135                         hash_pos++;
 136                 if (hash_pos >= AFFS_I2HSIZE(inode))
 137                         goto readdir_done;
 138                 
 139                 i = htonl(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
 140                 j = chain_pos;
 141                 /* If the directory hasn't changed since the last call to readdir(),
 142                  * we can jump directly to where we left off.
 143                  */
 144                 if (filp->private_data && filp->f_version == dir->i_version) {
 145                         i = (ULONG)filp->private_data;
 146                         j = 0;
 147                         pd_debug("AFFS: readdir() left off=%lu\n",i);
 148                 }
 149                 filp->f_version = dir->i_version;
 150                 pd_debug("AFFS: hash_pos=%lu chain_pos=%lu\n", hash_pos, chain_pos);
 151                 while (i) {
 152                         if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
 153                                 printk("AFFS: readdir: Can't get block %d\n",i);
 154                                 goto readdir_done;
 155                         }
 156                         ino = i;
 157                         i   = htonl(FILE_END(fh_bh->b_data,inode)->hash_chain);
 158                         if (j == 0)
 159                                 break;
 160                         affs_brelse(fh_bh);
 161                         fh_bh = NULL;
 162                         j--;
 163                 }
 164                 if (fh_bh) {
 165                         namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
 166                         pr_debug("AFFS: readdir(): filldir(..,\"%.*s\",ino=%lu), i=%lu\n",namelen,name,ino,i);
 167                         filp->private_data = (void *)ino;
 168                         if (filldir(dirent,name,namelen,filp->f_pos,ino) < 0)
 169                                 goto readdir_done;
 170                         filp->private_data = (void *)i;
 171                         affs_brelse(fh_bh);
 172                         fh_bh = NULL;
 173                         stored++;
 174                 }
 175                 if (i == 0) {
 176                         hash_pos++;
 177                         chain_pos = 0;
 178                 } else
 179                         chain_pos++;
 180                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 181         }
 182 
 183 readdir_done:
 184         filp->f_pos |= old;
 185         affs_brelse(dir_bh);
 186         affs_brelse(fh_bh);
 187         iput(dir);
 188         pr_debug("AFFS: readdir()=%d\n",stored);
 189         return stored;
 190 }
 191 
 192 void
 193 affs_dir_truncate(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 194 {
 195         printk("AFFS: dir_truncate()\n");
 196 }

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