root/fs/ext2/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. ext2_dir_read
  2. ext2_check_dir_entry
  3. ext2_readdir

   1 /*
   2  *  linux/fs/ext2/dir.c
   3  *
   4  *  Copyright (C) 1992, 1993, 1994  Remy Card (card@masi.ibp.fr)
   5  *                                  Laboratoire MASI - Institut Blaise Pascal
   6  *                                  Universite Pierre et Marie Curie (Paris VI)
   7  *
   8  *  from
   9  *
  10  *  linux/fs/minix/dir.c
  11  *
  12  *  Copyright (C) 1991, 1992  Linus Torvalds
  13  *
  14  *  ext2 directory handling functions
  15  */
  16 
  17 #include <asm/segment.h>
  18 
  19 #include <linux/autoconf.h>
  20 #include <linux/errno.h>
  21 #include <linux/fs.h>
  22 #include <linux/ext2_fs.h>
  23 #include <linux/sched.h>
  24 #include <linux/stat.h>
  25 
  26 #ifndef CONFIG_EXT2_FS_DIR_READ
  27 static int ext2_dir_read (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
  28                             char * buf, int count)
  29 {
  30         return -EISDIR;
  31 }
  32 #else
  33 int ext2_file_read (struct inode *, struct file *, char *, int);
  34 #endif
  35 
  36 static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
  37 
  38 static struct file_operations ext2_dir_operations = {
  39         NULL,                   /* lseek - default */
  40 #ifdef CONFIG_EXT2_FS_DIR_READ
  41         ext2_file_read,         /* read */
  42 #else
  43         ext2_dir_read,          /* read */
  44 #endif
  45         NULL,                   /* write - bad */
  46         ext2_readdir,           /* readdir */
  47         NULL,                   /* select - default */
  48         ext2_ioctl,             /* ioctl */
  49         NULL,                   /* mmap */
  50         NULL,                   /* no special open code */
  51         NULL,                   /* no special release code */
  52         file_fsync              /* fsync */
  53 };
  54 
  55 /*
  56  * directories can handle most operations...
  57  */
  58 struct inode_operations ext2_dir_inode_operations = {
  59         &ext2_dir_operations,   /* default directory file-ops */
  60         ext2_create,            /* create */
  61         ext2_lookup,            /* lookup */
  62         ext2_link,              /* link */
  63         ext2_unlink,            /* unlink */
  64         ext2_symlink,           /* symlink */
  65         ext2_mkdir,             /* mkdir */
  66         ext2_rmdir,             /* rmdir */
  67         ext2_mknod,             /* mknod */
  68         ext2_rename,            /* rename */
  69         NULL,                   /* readlink */
  70         NULL,                   /* follow_link */
  71         NULL,                   /* bmap */
  72         ext2_truncate,          /* truncate */
  73         ext2_permission         /* permission */
  74 };
  75 
  76 int ext2_check_dir_entry (char * function, struct inode * dir,
     /* [previous][next][first][last][top][bottom][index][help] */
  77                           struct ext2_dir_entry * de, struct buffer_head * bh,
  78                           unsigned long offset)
  79 {
  80         char * error_msg = NULL;
  81 
  82         if (de->rec_len < EXT2_DIR_REC_LEN(1))
  83                 error_msg = "rec_len is smaller than minimal";
  84         else if (de->rec_len % 4 != 0)
  85                 error_msg = "rec_len % 4 != 0";
  86         else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
  87                 error_msg = "rec_len is too small for name_len";
  88         else if (dir && ((char *) de - bh->b_data) + de->rec_len >
  89                  dir->i_sb->s_blocksize)
  90                 error_msg = "directory entry across blocks";
  91 
  92         if (error_msg != NULL)
  93                 ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
  94                             "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
  95                             error_msg, offset, de->inode, de->rec_len,
  96                             de->name_len);
  97         return error_msg == NULL ? 1 : 0;
  98 }
  99 
 100 static int ext2_readdir (struct inode * inode, struct file * filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 101                          struct dirent * dirent, int count)
 102 {
 103         unsigned long offset, blk;
 104         int i, num;
 105         struct buffer_head * bh, * tmp, * bha[16];
 106         struct ext2_dir_entry * de;
 107         struct super_block * sb;
 108         int err;
 109         
 110         if (!inode || !S_ISDIR(inode->i_mode))
 111                 return -EBADF;
 112         sb = inode->i_sb;
 113         while (filp->f_pos < inode->i_size) {
 114                 offset = filp->f_pos & (sb->s_blocksize - 1);
 115                 blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
 116                 bh = ext2_bread (inode, blk, 0, &err);
 117                 if (!bh) {
 118                         filp->f_pos += sb->s_blocksize - offset;
 119                         continue;
 120                 }
 121 
 122                 /*
 123                  * Do the readahead
 124                  */
 125                 if (!offset) {
 126                         for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
 127                              i > 0; i--) {
 128                                 tmp = ext2_getblk (inode, ++blk, 0, &err);
 129                                 if (tmp && !tmp->b_uptodate && !tmp->b_lock)
 130                                         bha[num++] = tmp;
 131                                 else
 132                                         brelse (tmp);
 133                         }
 134                         if (num) {
 135                                 ll_rw_block (READA, num, bha);
 136                                 for (i = 0; i < num; i++)
 137                                         brelse (bha[i]);
 138                         }
 139                 }
 140                 
 141                 de = (struct ext2_dir_entry *) (offset + bh->b_data);
 142                 while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
 143                         if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
 144                                                    bh, offset)) {
 145                                 brelse (bh);
 146                                 return 0;
 147                         }
 148                         offset += de->rec_len;
 149                         filp->f_pos += de->rec_len;
 150                         if (de->inode) {
 151                                 memcpy_tofs (dirent->d_name, de->name,
 152                                              de->name_len);
 153                                 put_fs_long (de->inode, &dirent->d_ino);
 154                                 put_fs_byte (0, de->name_len + dirent->d_name);
 155                                 put_fs_word (de->name_len, &dirent->d_reclen);
 156 #ifndef DONT_USE_DCACHE
 157                                 ext2_dcache_add (inode->i_dev, inode->i_ino,
 158                                                  de->name, de->name_len,
 159                                                  de->inode);
 160 #endif
 161                                 i = de->name_len;
 162                                 brelse (bh);
 163                                 if (!IS_RDONLY(inode)) {
 164                                         inode->i_atime = CURRENT_TIME;
 165                                         inode->i_dirt = 1;
 166                                 }
 167                                 return i;
 168                         }
 169                         de = (struct ext2_dir_entry *) ((char *) de +
 170                                                         de->rec_len);
 171                 }
 172                 brelse (bh);
 173         }
 174         if (!IS_RDONLY(inode)) {
 175                 inode->i_atime = CURRENT_TIME;
 176                 inode->i_dirt = 1;
 177         }
 178         return 0;
 179 }

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