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>.
17 #include <linux/ufs_fs.h>
25 #define UFSD(x) printk("(%s, %d), %s: ", __FILE__, __LINE__, __FUNCTION__); printk x;
31 * This is blatantly stolen from ext2fs
34 ufs_readdir (struct file
* filp
, void * dirent
, filldir_t filldir
)
36 struct inode
*inode
= filp
->f_dentry
->d_inode
;
38 unsigned long offset
, lblk
, blk
;
40 struct buffer_head
* bh
;
41 struct ufs_dir_entry
* de
;
42 struct super_block
* 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
))
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 /* XXX - ufs_bmap() call needs error checking */
59 blk
= ufs_bmap(inode
, lblk
);
60 bh
= bread (sb
->s_dev
, blk
, sb
->s_blocksize
);
62 /* XXX - error - skip to the next block */
63 printk("ufs_readdir: "
64 "dir inode %lu has a hole at offset %lu\n",
65 inode
->i_ino
, (unsigned long int)filp
->f_pos
);
66 filp
->f_pos
+= sb
->s_blocksize
- offset
;
71 /* If the dir block has changed since the last call to
72 * readdir(2), then we might be pointing to an invalid
73 * dirent right now. Scan from the start of the block
75 if (filp
->f_version
!= inode
->i_version
) {
76 for (i
= 0; i
< sb
->s_blocksize
&& i
< offset
; ) {
77 de
= (struct ufs_dir_entry
*)(bh
->b_data
+ i
);
78 /* It's too expensive to do a full
79 * dirent test each time round this
80 * loop, but we do have to test at
81 * least that it is non-zero. A
82 * failure will be detected in the
83 * dirent test below. */
84 de_reclen
= SWAB16(de
->d_reclen
);
90 filp
->f_pos
= (filp
->f_pos
& ~(sb
->s_blocksize
- 1))
92 filp
->f_version
= inode
->i_version
;
95 while (!error
&& filp
->f_pos
< inode
->i_size
96 && offset
< sb
->s_blocksize
) {
97 de
= (struct ufs_dir_entry
*) (bh
->b_data
+ offset
);
98 /* XXX - put in a real ufs_check_dir_entry() */
99 if ((de
->d_reclen
== 0) || (ufs_get_de_namlen(de
) == 0)) {
100 /* SWAB16() was unneeded -- compare to 0 */
101 filp
->f_pos
= (filp
->f_pos
&
102 (sb
->s_blocksize
- 1)) +
107 if (!ufs_check_dir_entry ("ufs_readdir", inode
, de
,
109 /* On error, skip the f_pos to the
111 filp
->f_pos
= (filp
->f_pos
&
112 (sb
->s_blocksize
- 1)) +
117 offset
+= SWAB16(de
->d_reclen
);
119 /* SWAB16() was unneeded -- compare to 0 */
120 /* We might block in the next section
121 * if the data destination is
122 * currently swapped out. So, use a
123 * version stamp to detect whether or
124 * not the directory has been modified
125 * during the copy operation. */
126 unsigned long version
= inode
->i_version
;
128 UFSD(("filldir(%s,%u)\n", de
->d_name
, SWAB32(de
->d_ino
)))
129 UFSD(("namlen %u\n", ufs_get_de_namlen(de
)))
130 error
= filldir(dirent
, de
->d_name
, ufs_get_de_namlen(de
),
131 filp
->f_pos
, SWAB32(de
->d_ino
));
134 if (version
!= inode
->i_version
)
138 filp
->f_pos
+= SWAB16(de
->d_reclen
);
147 int ufs_check_dir_entry (const char * function
, struct inode
* dir
,
148 struct ufs_dir_entry
* de
, struct buffer_head
* bh
,
149 unsigned long offset
)
151 struct super_block
* sb
;
152 const char * error_msg
;
153 unsigned flags
, swab
;
156 flags
= sb
->u
.ufs_sb
.s_flags
;
157 swab
= sb
->u
.ufs_sb
.s_swab
;
160 if (SWAB16(de
->d_reclen
) < UFS_DIR_REC_LEN(1))
161 error_msg
= "reclen is smaller than minimal";
162 else if (SWAB16(de
->d_reclen
) % 4 != 0)
163 error_msg
= "reclen % 4 != 0";
164 else if (SWAB16(de
->d_reclen
) < UFS_DIR_REC_LEN(ufs_get_de_namlen(de
)))
165 error_msg
= "reclen is too small for namlen";
166 else if (dir
&& ((char *) de
- bh
->b_data
) + SWAB16(de
->d_reclen
) >
167 dir
->i_sb
->s_blocksize
)
168 error_msg
= "directory entry across blocks";
169 else if (dir
&& SWAB32(de
->d_ino
) > (sb
->u
.ufs_sb
.s_uspi
->s_ipg
* sb
->u
.ufs_sb
.s_uspi
->s_ncg
))
170 error_msg
= "inode out of bounds";
172 if (error_msg
!= NULL
)
173 ufs_error (sb
, function
, "bad entry in directory #%lu, size %lu: %s - "
174 "offset=%lu, inode=%lu, reclen=%d, namlen=%d",
175 dir
->i_ino
, dir
->i_size
, error_msg
, offset
,
176 (unsigned long) SWAB32(de
->d_ino
),
177 SWAB16(de
->d_reclen
), ufs_get_de_namlen(de
));
179 return (error_msg
== NULL
? 1 : 0);
182 static struct file_operations ufs_dir_operations
= {
186 ufs_readdir
, /* readdir */
193 file_fsync
, /* fsync */
195 NULL
, /* check_media_change */
196 NULL
, /* revalidate */
199 struct inode_operations ufs_dir_inode_operations
= {
200 &ufs_dir_operations
, /* default directory file operations */
201 ufs_create
, /* create */
202 ufs_lookup
, /* lookup */
204 ufs_unlink
, /* unlink */
205 ufs_symlink
, /* symlink */
206 ufs_mkdir
, /* mkdir */
207 ufs_rmdir
, /* rmdir */
208 ufs_mknod
, /* mknod */
209 ufs_rename
, /* rename */
211 NULL
, /* follow_link */
213 NULL
, /* writepage */
216 ufs_permission
, /* permission */