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 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
;
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
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
);
88 filp
->f_pos
= (filp
->f_pos
& ~(sb
->s_blocksize
- 1))
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)) +
105 if (!ufs_check_dir_entry ("ufs_readdir", inode
, de
,
107 /* On error, skip the f_pos to the
109 filp
->f_pos
= (filp
->f_pos
|
110 (sb
->s_blocksize
- 1)) +
115 offset
+= SWAB16(de
->d_reclen
);
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
);
135 if (version
!= filp
->f_version
)
139 filp
->f_pos
+= SWAB16(de
->d_reclen
);
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
;
157 flags
= sb
->u
.ufs_sb
.s_flags
;
158 swab
= sb
->u
.ufs_sb
.s_swab
;
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
,