~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

Linux Cross Reference
Linux/fs/affs/dir.c

Version: ~ [ 2.4.0 ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  linux/fs/affs/dir.c
  3  *
  4  *  (c) 1996  Hans-Joachim Widmaier - Rewritten
  5  *
  6  *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
  7  *
  8  *  (C) 1992  Eric Youngdale Modified for ISO 9660 filesystem.
  9  *
 10  *  (C) 1991  Linus Torvalds - minix filesystem
 11  *
 12  *  affs directory handling functions
 13  *
 14  */
 15 
 16 #define DEBUG 0
 17 #include <asm/uaccess.h>
 18 #include <linux/errno.h>
 19 #include <linux/fs.h>
 20 #include <linux/kernel.h>
 21 #include <linux/affs_fs.h>
 22 #include <linux/stat.h>
 23 #include <linux/string.h>
 24 #include <linux/mm.h>
 25 #include <linux/amigaffs.h>
 26 
 27 static int affs_readdir(struct file *, void *, filldir_t);
 28 
 29 struct file_operations affs_dir_operations = {
 30         read:           generic_read_dir,
 31         readdir:        affs_readdir,
 32         fsync:          file_fsync,
 33 };
 34 
 35 /*
 36  * directories can handle most operations...
 37  */
 38 struct inode_operations affs_dir_inode_operations = {
 39         create:         affs_create,
 40         lookup:         affs_lookup,
 41         link:           affs_link,
 42         unlink:         affs_unlink,
 43         symlink:        affs_symlink,
 44         mkdir:          affs_mkdir,
 45         rmdir:          affs_rmdir,
 46         rename:         affs_rename,
 47         setattr:        affs_notify_change,
 48 };
 49 
 50 static int
 51 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
 52 {
 53         int                      j, namelen;
 54         s32                      i;
 55         int                      hash_pos;
 56         int                      chain_pos;
 57         unsigned long            ino;
 58         int                      stored;
 59         unsigned char           *name;
 60         struct buffer_head      *dir_bh;
 61         struct buffer_head      *fh_bh;
 62         struct inode            *dir;
 63         struct inode            *inode = filp->f_dentry->d_inode;
 64 
 65         pr_debug("AFFS: readdir(ino=%lu,f_pos=%lu)\n",inode->i_ino,(unsigned long)filp->f_pos);
 66 
 67         stored = 0;
 68         dir_bh = NULL;
 69         fh_bh  = NULL;
 70         dir    = NULL;
 71         ino    = inode->i_ino;
 72 
 73         if (filp->f_pos == 0) {
 74                 filp->private_data = (void *)0;
 75                 if (filldir(dirent,".",1,filp->f_pos,inode->i_ino,DT_DIR) < 0) {
 76                         return 0;
 77                 }
 78                 ++filp->f_pos;
 79                 stored++;
 80         }
 81         if (filp->f_pos == 1) {
 82                 if (filldir(dirent,"..",2,filp->f_pos,affs_parent_ino(inode),DT_DIR) < 0) {
 83                         return stored;
 84                 }
 85                 filp->f_pos = 2;
 86                 stored++;
 87         }
 88         chain_pos = (filp->f_pos - 2) & 0xffff;
 89         hash_pos  = (filp->f_pos - 2) >> 16;
 90         if (chain_pos == 0xffff) {
 91                 affs_warning(inode->i_sb,"readdir","More than 65535 entries in chain");
 92                 chain_pos = 0;
 93                 hash_pos++;
 94                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
 95         }
 96         if (!(dir_bh = affs_bread(inode->i_dev,inode->i_ino,
 97                                   AFFS_I2BSIZE(inode))))
 98                 goto readdir_done;
 99 
100         while (1) {
101                 while (hash_pos < AFFS_I2HSIZE(inode) &&
102                      !((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos])
103                         hash_pos++;
104                 if (hash_pos >= AFFS_I2HSIZE(inode))
105                         break;
106                 
107                 i = be32_to_cpu(((struct dir_front *)dir_bh->b_data)->hashtable[hash_pos]);
108                 j = chain_pos;
109 
110                 /* If the directory hasn't changed since the last call to readdir(),
111                  * we can jump directly to where we left off.
112                  */
113                 if (filp->private_data && filp->f_version == inode->i_version) {
114                         i = (s32)(unsigned long)filp->private_data;
115                         j = 0;
116                         pr_debug("AFFS: readdir() left off=%d\n",i);
117                 }
118                 filp->f_version = inode->i_version;
119                 pr_debug("AFFS: hash_pos=%d chain_pos=%d\n",hash_pos,chain_pos);
120                 while (i) {
121                         if (!(fh_bh = affs_bread(inode->i_dev,i,AFFS_I2BSIZE(inode)))) {
122                                 affs_error(inode->i_sb,"readdir","Cannot read block %d",i);
123                                 goto readdir_done;
124                         }
125                         ino = i;
126                         i   = be32_to_cpu(FILE_END(fh_bh->b_data,inode)->hash_chain);
127                         if (j == 0)
128                                 break;
129                         affs_brelse(fh_bh);
130                         fh_bh = NULL;
131                         j--;
132                 }
133                 if (fh_bh) {
134                         namelen = affs_get_file_name(AFFS_I2BSIZE(inode),fh_bh->b_data,&name);
135                         pr_debug("AFFS: readdir(): filldir(\"%.*s\",ino=%lu), i=%d\n",
136                                  namelen,name,ino,i);
137                         filp->private_data = (void *)ino;
138                         if (filldir(dirent,name,namelen,filp->f_pos,ino,DT_UNKNOWN) < 0)
139                                 goto readdir_done;
140                         filp->private_data = (void *)(unsigned long)i;
141                         affs_brelse(fh_bh);
142                         fh_bh = NULL;
143                         stored++;
144                 }
145                 if (i == 0) {
146                         hash_pos++;
147                         chain_pos = 0;
148                 } else
149                         chain_pos++;
150                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
151         }
152 
153 readdir_done:
154         affs_brelse(dir_bh);
155         affs_brelse(fh_bh);
156         pr_debug("AFFS: readdir()=%d\n",stored);
157         return stored;
158 }
159 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~ [ freetext search ] ~ [ file search ] ~

This page was automatically generated by the LXR engine.
Visit the LXR main site for more information.