home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / ext2 / dir.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-01-09  |  4.4 KB  |  171 lines

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