2 * linux/fs/ufs/ufs_dir.c
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>.
24 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
30 * This is blatantly stolen from ext2fs
33 ufs_readdir (struct file
* filp
, void * dirent
, filldir_t filldir
)
35 struct inode
*inode
= filp
->f_dentry
->d_inode
;
37 unsigned long offset
, lblk
, blk
;
39 struct buffer_head
* bh
;
40 struct ufs_dir_entry
* de
;
41 struct super_block
* sb
;
46 /* Isn't that already done in the upper layer???
47 * the VFS layer really needs some explicit documentation!
49 if (!inode
|| !S_ISDIR(inode
->i_mode
))
53 swab
= sb
->u
.ufs_sb
.s_swab
;
54 flags
= sb
->u
.ufs_sb
.s_flags
;
56 UFSD(("ENTER, ino %lu f_pos %lu\n", inode
->i_ino
, (unsigned long) filp
->f_pos
))
60 offset
= filp
->f_pos
& (sb
->s_blocksize
- 1);
62 while (!error
&& !stored
&& filp
->f_pos
< inode
->i_size
) {
63 lblk
= (filp
->f_pos
) >> sb
->s_blocksize_bits
;
64 /* XXX - ufs_bmap() call needs error checking */
65 blk
= ufs_bmap(inode
, lblk
);
66 bh
= bread (sb
->s_dev
, blk
, sb
->s_blocksize
);
68 /* XXX - error - skip to the next block */
69 printk("ufs_readdir: "
70 "dir inode %lu has a hole at offset %lu\n",
71 inode
->i_ino
, (unsigned long int)filp
->f_pos
);
72 filp
->f_pos
+= sb
->s_blocksize
- offset
;
77 /* If the dir block has changed since the last call to
78 * readdir(2), then we might be pointing to an invalid
79 * dirent right now. Scan from the start of the block
81 if (filp
->f_version
!= inode
->i_version
) {
82 for (i
= 0; i
< sb
->s_blocksize
&& i
< offset
; ) {
83 de
= (struct ufs_dir_entry
*)(bh
->b_data
+ i
);
84 /* It's too expensive to do a full
85 * dirent test each time round this
86 * loop, but we do have to test at
87 * least that it is non-zero. A
88 * failure will be detected in the
89 * dirent test below. */
90 de_reclen
= SWAB16(de
->d_reclen
);
96 filp
->f_pos
= (filp
->f_pos
& ~(sb
->s_blocksize
- 1))
98 filp
->f_version
= inode
->i_version
;
101 while (!error
&& filp
->f_pos
< inode
->i_size
102 && offset
< sb
->s_blocksize
) {
103 de
= (struct ufs_dir_entry
*) (bh
->b_data
+ offset
);
104 /* XXX - put in a real ufs_check_dir_entry() */
105 if ((de
->d_reclen
== 0) || (ufs_get_de_namlen(de
) == 0)) {
106 /* SWAB16() was unneeded -- compare to 0 */
107 filp
->f_pos
= (filp
->f_pos
&
108 (sb
->s_blocksize
- 1)) +
113 if (!ufs_check_dir_entry ("ufs_readdir", inode
, de
,
115 /* On error, skip the f_pos to the
117 filp
->f_pos
= (filp
->f_pos
&
118 (sb
->s_blocksize
- 1)) +
123 offset
+= SWAB16(de
->d_reclen
);
125 /* SWAB16() was unneeded -- compare to 0 */
126 /* We might block in the next section
127 * if the data destination is
128 * currently swapped out. So, use a
129 * version stamp to detect whether or
130 * not the directory has been modified
131 * during the copy operation. */
132 unsigned long version
= inode
->i_version
;
134 UFSD(("filldir(%s,%u)\n", de
->d_name
, SWAB32(de
->d_ino
)))
135 UFSD(("namlen %u\n", ufs_get_de_namlen(de
)))
136 error
= filldir(dirent
, de
->d_name
, ufs_get_de_namlen(de
),
137 filp
->f_pos
, SWAB32(de
->d_ino
));
140 if (version
!= inode
->i_version
)
144 filp
->f_pos
+= SWAB16(de
->d_reclen
);
153 int ufs_check_dir_entry (const char * function
, struct inode
* dir
,
154 struct ufs_dir_entry
* de
, struct buffer_head
* bh
,
155 unsigned long offset
)
157 struct super_block
* sb
;
158 const char * error_msg
;
159 unsigned flags
, swab
;
162 flags
= sb
->u
.ufs_sb
.s_flags
;
163 swab
= sb
->u
.ufs_sb
.s_swab
;
166 if (SWAB16(de
->d_reclen
) < UFS_DIR_REC_LEN(1))
167 error_msg
= "reclen is smaller than minimal";
168 else if (SWAB16(de
->d_reclen
) % 4 != 0)
169 error_msg
= "reclen % 4 != 0";
170 else if (SWAB16(de
->d_reclen
) < UFS_DIR_REC_LEN(ufs_get_de_namlen(de
)))
171 error_msg
= "reclen is too small for namlen";
172 else if (dir
&& ((char *) de
- bh
->b_data
) + SWAB16(de
->d_reclen
) >
173 dir
->i_sb
->s_blocksize
)
174 error_msg
= "directory entry across blocks";
175 else if (dir
&& SWAB32(de
->d_ino
) > (sb
->u
.ufs_sb
.s_uspi
->s_ipg
* sb
->u
.ufs_sb
.s_uspi
->s_ncg
))
176 error_msg
= "inode out of bounds";
178 if (error_msg
!= NULL
)
179 ufs_error (sb
, function
, "bad entry in directory #%lu, size %lu: %s - "
180 "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
181 dir
->i_ino
, dir
->i_size
, error_msg
, offset
,
182 (unsigned long) SWAB32(de
->d_ino
),
183 SWAB16(de
->d_reclen
), ufs_get_de_namlen(de
));
185 return (error_msg
== NULL
? 1 : 0);
188 static struct file_operations ufs_dir_operations
= {
192 ufs_readdir
, /* readdir */
199 file_fsync
, /* fsync */
201 NULL
, /* check_media_change */
202 NULL
, /* revalidate */
205 struct inode_operations ufs_dir_inode_operations
= {
206 &ufs_dir_operations
, /* default directory file operations */
207 ufs_create
, /* create */
208 ufs_lookup
, /* lookup */
210 ufs_unlink
, /* unlink */
211 ufs_symlink
, /* symlink */
212 ufs_mkdir
, /* mkdir */
213 ufs_rmdir
, /* rmdir */
214 ufs_mknod
, /* mknod */
215 ufs_rename
, /* rename */
217 NULL
, /* follow_link */
219 NULL
, /* writepage */
222 ufs_permission
, /* permission */