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

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

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

  1 /*
  2  *  linux/fs/ufs/ufs_dir.c
  3  *
  4  * Copyright (C) 1996
  5  * Adrian Rodriguez (adrian@franklins-tower.rutgers.edu)
  6  * Laboratory for Computer Science Research Computing Facility
  7  * Rutgers, The State University of New Jersey
  8  *
  9  * swab support by Francois-Rene Rideau <fare@tunes.org> 19970406
 10  *
 11  * 4.4BSD (FreeBSD) support added on February 1st 1998 by
 12  * Niels Kristian Bech Jensen <nkbj@image.dk> partially based
 13  * on code by Martin von Loewis <martin@mira.isdn.cs.tu-berlin.de>.
 14  */
 15 
 16 #include <linux/fs.h>
 17 #include <linux/ufs_fs.h>
 18 
 19 #include "swab.h"
 20 #include "util.h"
 21 
 22 #undef UFS_DIR_DEBUG
 23 
 24 #ifdef UFS_DIR_DEBUG
 25 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
 26 #else
 27 #define UFSD(x)
 28 #endif
 29 
 30 /*
 31  * This is blatantly stolen from ext2fs
 32  */
 33 static int
 34 ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
 35 {
 36         struct inode *inode = filp->f_dentry->d_inode;
 37         int error = 0;
 38         unsigned long offset, lblk, blk;
 39         int i, stored;
 40         struct buffer_head * bh;
 41         struct ufs_dir_entry * de;
 42         struct super_block * sb;
 43         int de_reclen;
 44         unsigned flags, swab;
 45 
 46         sb = inode->i_sb;
 47         swab = sb->u.ufs_sb.s_swab;
 48         flags = sb->u.ufs_sb.s_flags;
 49 
 50         UFSD(("ENTER, ino %lu  f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
 51 
 52         stored = 0;
 53         bh = NULL;
 54         offset = filp->f_pos & (sb->s_blocksize - 1);
 55 
 56         while (!error && !stored && filp->f_pos < inode->i_size) {
 57                 lblk = (filp->f_pos) >> sb->s_blocksize_bits;
 58                 blk = ufs_frag_map(inode, lblk);
 59                 if (!blk || !(bh = bread (sb->s_dev, blk, sb->s_blocksize))) {
 60                         /* XXX - error - skip to the next block */
 61                         printk("ufs_readdir: "
 62                                "dir inode %lu has a hole at offset %lu\n",
 63                                inode->i_ino, (unsigned long int)filp->f_pos);
 64                         filp->f_pos += sb->s_blocksize - offset;
 65                         continue;
 66                 }
 67 
 68 revalidate:
 69                 /* If the dir block has changed since the last call to
 70                  * readdir(2), then we might be pointing to an invalid
 71                  * dirent right now.  Scan from the start of the block
 72                  * to make sure. */
 73                 if (filp->f_version != inode->i_version) {
 74                         for (i = 0; i < sb->s_blocksize && i < offset; ) {
 75                                 de = (struct ufs_dir_entry *)(bh->b_data + i);
 76                                 /* It's too expensive to do a full
 77                                  * dirent test each time round this
 78                                  * loop, but we do have to test at
 79                                  * least that it is non-zero.  A
 80                                  * failure will be detected in the
 81                                  * dirent test below. */
 82                                 de_reclen = SWAB16(de->d_reclen);
 83                                 if (de_reclen < 1)
 84                                         break;
 85                                 i += de_reclen;
 86                         }
 87                         offset = i;
 88                         filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
 89                                 | offset;
 90                         filp->f_version = inode->i_version;
 91                 }
 92 
 93                 while (!error && filp->f_pos < inode->i_size
 94                        && offset < sb->s_blocksize) {
 95                         de = (struct ufs_dir_entry *) (bh->b_data + offset);
 96                         /* XXX - put in a real ufs_check_dir_entry() */
 97                         if ((de->d_reclen == 0) || (ufs_get_de_namlen(de) == 0)) {
 98                         /* SWAB16() was unneeded -- compare to 0 */
 99                                 filp->f_pos = (filp->f_pos &
100                                               (sb->s_blocksize - 1)) +
101                                                sb->s_blocksize;
102                                 brelse(bh);
103                                 return stored;
104                         }
105                         if (!ufs_check_dir_entry ("ufs_readdir", inode, de,
106                                                    bh, offset)) {
107                                 /* On error, skip the f_pos to the
108                                    next block. */
109                                 filp->f_pos = (filp->f_pos |
110                                               (sb->s_blocksize - 1)) +
111                                                1;
112                                 brelse (bh);
113                                 return stored;
114                         }
115                         offset += SWAB16(de->d_reclen);
116                         if (de->d_ino) {
117                         /* SWAB16() was unneeded -- compare to 0 */
118                                 /* We might block in the next section
119                                  * if the data destination is
120                                  * currently swapped out.  So, use a
121                                  * version stamp to detect whether or
122                                  * not the directory has been modified
123                                  * during the copy operation. */
124                                 unsigned long version = filp->f_version;
125                                 unsigned char d_type = DT_UNKNOWN;
126 
127                                 UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
128                                 UFSD(("namlen %u\n", ufs_get_de_namlen(de)))
129                                 if ((flags & UFS_DE_MASK) == UFS_DE_44BSD)
130                                         d_type = de->d_u.d_44.d_type;
131                                 error = filldir(dirent, de->d_name, ufs_get_de_namlen(de),
132                                                 filp->f_pos, SWAB32(de->d_ino), d_type);
133                                 if (error)
134                                         break;
135                                 if (version != filp->f_version)
136                                         goto revalidate;
137                                 stored ++;
138                         }
139                         filp->f_pos += SWAB16(de->d_reclen);
140                 }
141                 offset = 0;
142                 brelse (bh);
143         }
144         UPDATE_ATIME(inode);
145         return 0;
146 }
147 
148 int ufs_check_dir_entry (const char * function, struct inode * dir,
149         struct ufs_dir_entry * de, struct buffer_head * bh, 
150         unsigned long offset)
151 {
152         struct super_block * sb;
153         const char * error_msg;
154         unsigned flags, swab;
155         
156         sb = dir->i_sb;
157         flags = sb->u.ufs_sb.s_flags;
158         swab = sb->u.ufs_sb.s_swab;
159         error_msg = NULL;
160                         
161         if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
162                 error_msg = "reclen is smaller than minimal";
163         else if (SWAB16(de->d_reclen) % 4 != 0)
164                 error_msg = "reclen % 4 != 0";
165         else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_get_de_namlen(de)))
166                 error_msg = "reclen is too small for namlen";
167         else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
168                  dir->i_sb->s_blocksize)
169                 error_msg = "directory entry across blocks";
170         else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
171                 error_msg = "inode out of bounds";
172 
173         if (error_msg != NULL)
174                 ufs_error (sb, function, "bad entry in directory #%lu, size %Lu: %s - "
175                             "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
176                             dir->i_ino, dir->i_size, error_msg, offset,
177                             (unsigned long) SWAB32(de->d_ino),
178                             SWAB16(de->d_reclen), ufs_get_de_namlen(de));
179         
180         return (error_msg == NULL ? 1 : 0);
181 }
182 
183 struct file_operations ufs_dir_operations = {
184         read:           generic_read_dir,
185         readdir:        ufs_readdir,
186         fsync:          file_fsync,
187 };
188 

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