The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/fs/affs/dir.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    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 #include <asm/uaccess.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 file *, void *, filldir_t);
   27 
   28 struct file_operations affs_dir_operations = {
   29         read:           generic_read_dir,
   30         readdir:        affs_readdir,
   31         fsync:          file_fsync,
   32 };
   33 
   34 /*
   35  * directories can handle most operations...
   36  */
   37 struct inode_operations affs_dir_inode_operations = {
   38         create:         affs_create,
   39         lookup:         affs_lookup,
   40         link:           affs_link,
   41         unlink:         affs_unlink,
   42         symlink:        affs_symlink,
   43         mkdir:          affs_mkdir,
   44         rmdir:          affs_rmdir,
   45         rename:         affs_rename,
   46         setattr:        affs_notify_change,
   47 };
   48 
   49 static int
   50 affs_readdir(struct file *filp, void *dirent, filldir_t filldir)
   51 {
   52         struct inode            *inode = filp->f_dentry->d_inode;
   53         struct super_block      *sb = inode->i_sb;
   54         struct buffer_head      *dir_bh;
   55         struct buffer_head      *fh_bh;
   56         unsigned char           *name;
   57         int                      namelen;
   58         u32                      i;
   59         int                      hash_pos;
   60         int                      chain_pos;
   61         u32                      f_pos;
   62         u32                      ino;
   63         int                      stored;
   64         int                      res;
   65 
   66         pr_debug("AFFS: readdir(ino=%lu,f_pos=%lx)\n",inode->i_ino,(unsigned long)filp->f_pos);
   67 
   68         stored = 0;
   69         res    = -EIO;
   70         dir_bh = NULL;
   71         fh_bh  = NULL;
   72         f_pos  = filp->f_pos;
   73 
   74         if (f_pos == 0) {
   75                 filp->private_data = (void *)0;
   76                 if (filldir(dirent, ".", 1, f_pos, inode->i_ino, DT_DIR) < 0)
   77                         return 0;
   78                 filp->f_pos = f_pos = 1;
   79                 stored++;
   80         }
   81         if (f_pos == 1) {
   82                 if (filldir(dirent, "..", 2, f_pos, filp->f_dentry->d_parent->d_inode->i_ino, DT_DIR) < 0)
   83                         return stored;
   84                 filp->f_pos = f_pos = 2;
   85                 stored++;
   86         }
   87 
   88         affs_lock_dir(inode);
   89         chain_pos = (f_pos - 2) & 0xffff;
   90         hash_pos  = (f_pos - 2) >> 16;
   91         if (chain_pos == 0xffff) {
   92                 affs_warning(sb, "readdir", "More than 65535 entries in chain");
   93                 chain_pos = 0;
   94                 hash_pos++;
   95                 filp->f_pos = ((hash_pos << 16) | chain_pos) + 2;
   96         }
   97         dir_bh = affs_bread(sb, inode->i_ino);
   98         if (!dir_bh)
   99                 goto readdir_out;
  100 
  101         /* If the directory hasn't changed since the last call to readdir(),
  102          * we can jump directly to where we left off.
  103          */
  104         ino = (u32)(long)filp->private_data;
  105         if (ino && filp->f_version == inode->i_version) {
  106                 pr_debug("AFFS: readdir() left off=%d\n", ino);
  107                 goto inside;
  108         }
  109 
  110         ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
  111         for (i = 0; ino && i < chain_pos; i++) {
  112                 fh_bh = affs_bread(sb, ino);
  113                 if (!fh_bh) {
  114                         affs_error(sb, "readdir","Cannot read block %d", i);
  115                         goto readdir_out;
  116                 }
  117                 ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
  118                 affs_brelse(fh_bh);
  119                 fh_bh = NULL;
  120         }
  121         if (ino)
  122                 goto inside;
  123         hash_pos++;
  124 
  125         for (; hash_pos < AFFS_SB->s_hashsize; hash_pos++) {
  126                 ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[hash_pos]);
  127                 if (!ino)
  128                         continue;
  129                 f_pos = (hash_pos << 16) + 2;
  130 inside:
  131                 do {
  132                         fh_bh = affs_bread(sb, ino);
  133                         if (!fh_bh) {
  134                                 affs_error(sb, "readdir","Cannot read block %d", ino);
  135                                 goto readdir_done;
  136                         }
  137 
  138                         namelen = min(AFFS_TAIL(sb, fh_bh)->name[0], (u8)30);
  139                         name = AFFS_TAIL(sb, fh_bh)->name + 1;
  140                         pr_debug("AFFS: readdir(): filldir(\"%.*s\", ino=%u), hash=%d, f_pos=%x\n",
  141                                  namelen, name, ino, hash_pos, f_pos);
  142                         if (filldir(dirent, name, namelen, f_pos, ino, DT_UNKNOWN) < 0)
  143                                 goto readdir_done;
  144                         stored++;
  145                         f_pos++;
  146                         ino = be32_to_cpu(AFFS_TAIL(sb, fh_bh)->hash_chain);
  147                         affs_brelse(fh_bh);
  148                         fh_bh = NULL;
  149                 } while (ino);
  150         }
  151 readdir_done:
  152         filp->f_pos = f_pos;
  153         filp->f_version = inode->i_version;
  154         filp->private_data = (void *)(long)ino;
  155         res = stored;
  156 
  157 readdir_out:
  158         affs_brelse(dir_bh);
  159         affs_brelse(fh_bh);
  160         affs_unlock_dir(inode);
  161         pr_debug("AFFS: readdir()=%d\n", stored);
  162         return res;
  163 }

Cache object: 88f80362906068fb6e9f10de9c8be5c4


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.