Ok. I didn't make 2.4.0 in 2000. Tough. I tried, but we had some
[davej-history.git] / fs / ufs / dir.c
blob755198ded38db087f6127211e04db12186477e0a
1 /*
2 * linux/fs/ufs/ufs_dir.c
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
9 * swab support by Francois-Rene Rideau <fare@tunes.org> 19970406
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>.
16 #include <linux/fs.h>
17 #include <linux/ufs_fs.h>
19 #include "swab.h"
20 #include "util.h"
22 #undef UFS_DIR_DEBUG
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
31 * This is blatantly stolen from ext2fs
33 static int
34 ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
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;
46 sb = inode->i_sb;
47 swab = sb->u.ufs_sb.s_swab;
48 flags = sb->u.ufs_sb.s_flags;
50 UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
52 stored = 0;
53 bh = NULL;
54 offset = filp->f_pos & (sb->s_blocksize - 1);
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;
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;
87 offset = i;
88 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
89 | offset;
90 filp->f_version = inode->i_version;
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;
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)) +
112 brelse (bh);
113 return stored;
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;
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 ++;
139 filp->f_pos += SWAB16(de->d_reclen);
141 offset = 0;
142 brelse (bh);
144 UPDATE_ATIME(inode);
145 return 0;
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)
152 struct super_block * sb;
153 const char * error_msg;
154 unsigned flags, swab;
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;
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";
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));
180 return (error_msg == NULL ? 1 : 0);
183 struct file_operations ufs_dir_operations = {
184 read: generic_read_dir,
185 readdir: ufs_readdir,
186 fsync: file_fsync,