Import 2.1.118
[davej-history.git] / fs / ufs / dir.c
blob03d95fda57a086eeefd521d3ea4af2654bf7f318
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 <rideau@ens.fr> 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>.
15 * write support by Daniel Pirkl <daniel.pirkl@email.cz> 1998
18 #include <linux/fs.h>
20 #include "swab.h"
21 #include "util.h"
23 #undef UFS_DIR_DEBUG
25 #ifdef UFS_DIR_DEBUG
26 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
27 #else
28 #define UFSD(x)
29 #endif
32 * This is blatantly stolen from ext2fs
34 static int
35 ufs_readdir (struct file * filp, void * dirent, filldir_t filldir)
37 struct inode *inode = filp->f_dentry->d_inode;
38 int error = 0;
39 unsigned long offset, lblk, blk;
40 int i, stored;
41 struct buffer_head * bh;
42 struct ufs_dir_entry * de;
43 struct super_block * sb;
44 int de_reclen;
45 unsigned flags, swab;
48 /* Isn't that already done in the upper layer???
49 * the VFS layer really needs some explicit documentation!
51 if (!inode || !S_ISDIR(inode->i_mode))
52 return -EBADF;
54 sb = inode->i_sb;
55 swab = sb->u.ufs_sb.s_swab;
56 flags = sb->u.ufs_sb.s_flags;
58 UFSD(("ENTER, ino %lu f_pos %lu\n", inode->i_ino, (unsigned long) filp->f_pos))
60 stored = 0;
61 bh = NULL;
62 offset = filp->f_pos & (sb->s_blocksize - 1);
64 while (!error && !stored && filp->f_pos < inode->i_size) {
65 lblk = (filp->f_pos) >> sb->s_blocksize_bits;
66 /* XXX - ufs_bmap() call needs error checking */
67 blk = ufs_bmap(inode, lblk);
68 bh = bread (sb->s_dev, blk, sb->s_blocksize);
69 if (!bh) {
70 /* XXX - error - skip to the next block */
71 printk("ufs_readdir: "
72 "dir inode %lu has a hole at offset %lu\n",
73 inode->i_ino, (unsigned long int)filp->f_pos);
74 filp->f_pos += sb->s_blocksize - offset;
75 continue;
78 revalidate:
79 /* If the dir block has changed since the last call to
80 * readdir(2), then we might be pointing to an invalid
81 * dirent right now. Scan from the start of the block
82 * to make sure. */
83 if (filp->f_version != inode->i_version) {
84 for (i = 0; i < sb->s_blocksize && i < offset; ) {
85 de = (struct ufs_dir_entry *)(bh->b_data + i);
86 /* It's too expensive to do a full
87 * dirent test each time round this
88 * loop, but we do have to test at
89 * least that it is non-zero. A
90 * failure will be detected in the
91 * dirent test below. */
92 de_reclen = SWAB16(de->d_reclen);
93 if (de_reclen < 1)
94 break;
95 i += de_reclen;
97 offset = i;
98 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
99 | offset;
100 filp->f_version = inode->i_version;
103 while (!error && filp->f_pos < inode->i_size
104 && offset < sb->s_blocksize) {
105 de = (struct ufs_dir_entry *) (bh->b_data + offset);
106 /* XXX - put in a real ufs_check_dir_entry() */
107 if ((de->d_reclen == 0) || (ufs_namlen(de) == 0)) {
108 /* SWAB16() was unneeded -- compare to 0 */
109 filp->f_pos = (filp->f_pos &
110 (sb->s_blocksize - 1)) +
111 sb->s_blocksize;
112 brelse(bh);
113 return stored;
115 #if 0 /* XXX */
116 if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
117 /* XXX - beware about de having to be swabped somehow */
118 bh, offset)) {
119 /* On error, skip the f_pos to the
120 next block. */
121 filp->f_pos = (filp->f_pos &
122 (sb->s_blocksize - 1)) +
123 sb->s_blocksize;
124 brelse (bh);
125 return stored;
127 #endif /* XXX */
128 offset += SWAB16(de->d_reclen);
129 if (de->d_ino) {
130 /* SWAB16() was unneeded -- compare to 0 */
131 /* We might block in the next section
132 * if the data destination is
133 * currently swapped out. So, use a
134 * version stamp to detect whether or
135 * not the directory has been modified
136 * during the copy operation. */
137 unsigned long version = inode->i_version;
139 UFSD(("filldir(%s,%u)\n", de->d_name, SWAB32(de->d_ino)))
140 UFSD(("namlen %u\n", ufs_namlen(de)))
141 error = filldir(dirent, de->d_name, ufs_namlen(de),
142 filp->f_pos, SWAB32(de->d_ino));
143 if (error)
144 break;
145 if (version != inode->i_version)
146 goto revalidate;
147 stored ++;
149 filp->f_pos += SWAB16(de->d_reclen);
151 offset = 0;
152 brelse (bh);
154 UPDATE_ATIME(inode);
155 return 0;
158 int ufs_check_dir_entry (const char * function, struct inode * dir,
159 struct ufs_dir_entry * de, struct buffer_head * bh,
160 unsigned long offset)
162 struct super_block * sb;
163 const char * error_msg;
164 unsigned flags, swab;
166 sb = dir->i_sb;
167 flags = sb->u.ufs_sb.s_flags;
168 swab = sb->u.ufs_sb.s_swab;
169 error_msg = NULL;
171 if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(1))
172 error_msg = "reclen is smaller than minimal";
173 else if (SWAB16(de->d_reclen) % 4 != 0)
174 error_msg = "reclen % 4 != 0";
175 else if (SWAB16(de->d_reclen) < UFS_DIR_REC_LEN(ufs_namlen(de)))
176 error_msg = "reclen is too small for namlen";
177 else if (dir && ((char *) de - bh->b_data) + SWAB16(de->d_reclen) >
178 dir->i_sb->s_blocksize)
179 error_msg = "directory entry across blocks";
180 else if (dir && SWAB32(de->d_ino) > (sb->u.ufs_sb.s_uspi->s_ipg * sb->u.ufs_sb.s_uspi->s_ncg))
181 error_msg = "inode out of bounds";
183 if (error_msg != NULL)
184 ufs_error (sb, function, "bad entry in directory #%lu, size %lu: %s - "
185 "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
186 dir->i_ino, dir->i_size, error_msg, offset,
187 (unsigned long) SWAB32(de->d_ino),
188 SWAB16(de->d_reclen), ufs_namlen(de));
190 return (error_msg == NULL ? 1 : 0);
193 static struct file_operations ufs_dir_operations = {
194 NULL, /* lseek */
195 NULL, /* read */
196 NULL, /* write */
197 ufs_readdir, /* readdir */
198 NULL, /* select */
199 NULL, /* ioctl */
200 NULL, /* mmap */
201 NULL, /* open */
202 NULL, /* flush */
203 NULL, /* release */
204 file_fsync, /* fsync */
205 NULL, /* fasync */
206 NULL, /* check_media_change */
207 NULL, /* revalidate */
210 struct inode_operations ufs_dir_inode_operations = {
211 &ufs_dir_operations, /* default directory file operations */
212 ufs_create, /* create */
213 ufs_lookup, /* lookup */
214 ufs_link, /* link */
215 ufs_unlink, /* unlink */
216 ufs_symlink, /* symlink */
217 ufs_mkdir, /* mkdir */
218 ufs_rmdir, /* rmdir */
219 ufs_mknod, /* mknod */
220 ufs_rename, /* rename */
221 NULL, /* readlink */
222 NULL, /* follow_link */
223 NULL, /* readpage */
224 NULL, /* writepage */
225 ufs_bmap, /* bmap */
226 ufs_truncate, /* truncate */
227 ufs_permission, /* permission */
228 NULL, /* smap */