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/ext3/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/ext3/dir.c
    3  *
    4  * Copyright (C) 1992, 1993, 1994, 1995
    5  * Remy Card (card@masi.ibp.fr)
    6  * Laboratoire MASI - Institut Blaise Pascal
    7  * Universite Pierre et Marie Curie (Paris VI)
    8  *
    9  *  from
   10  *
   11  *  linux/fs/minix/dir.c
   12  *
   13  *  Copyright (C) 1991, 1992  Linus Torvalds
   14  *
   15  *  ext3 directory handling functions
   16  *
   17  *  Big-endian to little-endian byte-swapping/bitmaps by
   18  *        David S. Miller (davem@caip.rutgers.edu), 1995
   19  */
   20 
   21 #include <linux/fs.h>
   22 #include <linux/jbd.h>
   23 #include <linux/ext3_fs.h>
   24 
   25 static unsigned char ext3_filetype_table[] = {
   26         DT_UNKNOWN, DT_REG, DT_DIR, DT_CHR, DT_BLK, DT_FIFO, DT_SOCK, DT_LNK
   27 };
   28 
   29 static int ext3_readdir(struct file *, void *, filldir_t);
   30 
   31 struct file_operations ext3_dir_operations = {
   32         read:           generic_read_dir,
   33         readdir:        ext3_readdir,           /* BKL held */
   34         ioctl:          ext3_ioctl,             /* BKL held */
   35         fsync:          ext3_sync_file,         /* BKL held */
   36 };
   37 
   38 int ext3_check_dir_entry (const char * function, struct inode * dir,
   39                           struct ext3_dir_entry_2 * de,
   40                           struct buffer_head * bh,
   41                           unsigned long offset)
   42 {
   43         const char * error_msg = NULL;
   44         const int rlen = le16_to_cpu(de->rec_len);
   45 
   46         if (rlen < EXT3_DIR_REC_LEN(1))
   47                 error_msg = "rec_len is smaller than minimal";
   48         else if (rlen % 4 != 0)
   49                 error_msg = "rec_len % 4 != 0";
   50         else if (rlen < EXT3_DIR_REC_LEN(de->name_len))
   51                 error_msg = "rec_len is too small for name_len";
   52         else if (((char *) de - bh->b_data) + rlen > dir->i_sb->s_blocksize)
   53                 error_msg = "directory entry across blocks";
   54         else if (le32_to_cpu(de->inode) >
   55                         le32_to_cpu(dir->i_sb->u.ext3_sb.s_es->s_inodes_count))
   56                 error_msg = "inode out of bounds";
   57 
   58         if (error_msg != NULL)
   59                 ext3_error (dir->i_sb, function,
   60                         "bad entry in directory #%lu: %s - "
   61                         "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
   62                         dir->i_ino, error_msg, offset,
   63                         (unsigned long) le32_to_cpu(de->inode),
   64                         rlen, de->name_len);
   65         return error_msg == NULL ? 1 : 0;
   66 }
   67 
   68 static int ext3_readdir(struct file * filp,
   69                          void * dirent, filldir_t filldir)
   70 {
   71         int error = 0;
   72         unsigned long offset, blk;
   73         int i, num, stored;
   74         struct buffer_head * bh, * tmp, * bha[16];
   75         struct ext3_dir_entry_2 * de;
   76         struct super_block * sb;
   77         int err;
   78         struct inode *inode = filp->f_dentry->d_inode;
   79 
   80         sb = inode->i_sb;
   81 
   82         stored = 0;
   83         bh = NULL;
   84         offset = filp->f_pos & (sb->s_blocksize - 1);
   85 
   86         while (!error && !stored && filp->f_pos < inode->i_size) {
   87                 blk = (filp->f_pos) >> EXT3_BLOCK_SIZE_BITS(sb);
   88                 bh = ext3_bread (0, inode, blk, 0, &err);
   89                 if (!bh) {
   90                         ext3_error (sb, "ext3_readdir",
   91                                 "directory #%lu contains a hole at offset %lu",
   92                                 inode->i_ino, (unsigned long)filp->f_pos);
   93                         filp->f_pos += sb->s_blocksize - offset;
   94                         continue;
   95                 }
   96 
   97                 /*
   98                  * Do the readahead
   99                  */
  100                 if (!offset) {
  101                         for (i = 16 >> (EXT3_BLOCK_SIZE_BITS(sb) - 9), num = 0;
  102                              i > 0; i--) {
  103                                 tmp = ext3_getblk (NULL, inode, ++blk, 0, &err);
  104                                 if (tmp && !buffer_uptodate(tmp) &&
  105                                                 !buffer_locked(tmp))
  106                                         bha[num++] = tmp;
  107                                 else
  108                                         brelse (tmp);
  109                         }
  110                         if (num) {
  111                                 ll_rw_block (READA, num, bha);
  112                                 for (i = 0; i < num; i++)
  113                                         brelse (bha[i]);
  114                         }
  115                 }
  116                 
  117 revalidate:
  118                 /* If the dir block has changed since the last call to
  119                  * readdir(2), then we might be pointing to an invalid
  120                  * dirent right now.  Scan from the start of the block
  121                  * to make sure. */
  122                 if (filp->f_version != inode->i_version) {
  123                         for (i = 0; i < sb->s_blocksize && i < offset; ) {
  124                                 de = (struct ext3_dir_entry_2 *) 
  125                                         (bh->b_data + i);
  126                                 /* It's too expensive to do a full
  127                                  * dirent test each time round this
  128                                  * loop, but we do have to test at
  129                                  * least that it is non-zero.  A
  130                                  * failure will be detected in the
  131                                  * dirent test below. */
  132                                 if (le16_to_cpu(de->rec_len) <
  133                                                 EXT3_DIR_REC_LEN(1))
  134                                         break;
  135                                 i += le16_to_cpu(de->rec_len);
  136                         }
  137                         offset = i;
  138                         filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
  139                                 | offset;
  140                         filp->f_version = inode->i_version;
  141                 }
  142                 
  143                 while (!error && filp->f_pos < inode->i_size 
  144                        && offset < sb->s_blocksize) {
  145                         de = (struct ext3_dir_entry_2 *) (bh->b_data + offset);
  146                         if (!ext3_check_dir_entry ("ext3_readdir", inode, de,
  147                                                    bh, offset)) {
  148                                 /* On error, skip the f_pos to the
  149                                    next block. */
  150                                 filp->f_pos = (filp->f_pos |
  151                                                 (sb->s_blocksize - 1)) + 1;
  152                                 brelse (bh);
  153                                 return stored;
  154                         }
  155                         offset += le16_to_cpu(de->rec_len);
  156                         if (le32_to_cpu(de->inode)) {
  157                                 /* We might block in the next section
  158                                  * if the data destination is
  159                                  * currently swapped out.  So, use a
  160                                  * version stamp to detect whether or
  161                                  * not the directory has been modified
  162                                  * during the copy operation.
  163                                  */
  164                                 unsigned long version = filp->f_version;
  165                                 unsigned char d_type = DT_UNKNOWN;
  166 
  167                                 if (EXT3_HAS_INCOMPAT_FEATURE(sb,
  168                                                 EXT3_FEATURE_INCOMPAT_FILETYPE)
  169                                                 && de->file_type < EXT3_FT_MAX)
  170                                         d_type =
  171                                           ext3_filetype_table[de->file_type];
  172                                 error = filldir(dirent, de->name,
  173                                                 de->name_len,
  174                                                 filp->f_pos,
  175                                                 le32_to_cpu(de->inode),
  176                                                 d_type);
  177                                 if (error)
  178                                         break;
  179                                 if (version != filp->f_version)
  180                                         goto revalidate;
  181                                 stored ++;
  182                         }
  183                         filp->f_pos += le16_to_cpu(de->rec_len);
  184                 }
  185                 offset = 0;
  186                 brelse (bh);
  187         }
  188         UPDATE_ATIME(inode);
  189         return 0;
  190 }

Cache object: 06fc35ff0c678c8292dbfcd01baa6140


[ 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.