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 * $Id: ufs_dir.c,v 1.10 1997/06/05 01:29:06 davem Exp $
14 #include <linux/ufs_fs.h>
17 * This is blatantly stolen from ext2fs
20 ufs_readdir (struct file
* filp
, void * dirent
, filldir_t filldir
)
22 struct inode
*inode
= filp
->f_dentry
->d_inode
;
24 unsigned long offset
, lblk
, blk
;
26 struct buffer_head
* bh
;
27 struct ufs_direct
* de
;
28 struct super_block
* sb
;
30 if (!inode
|| !S_ISDIR(inode
->i_mode
))
34 if (inode
->i_sb
->u
.ufs_sb
.s_flags
& UFS_DEBUG
) {
35 printk("ufs_readdir: ino %lu f_pos %lu\n",
36 inode
->i_ino
, (unsigned long) filp
->f_pos
);
37 ufs_print_inode(inode
);
42 offset
= filp
->f_pos
& (sb
->s_blocksize
- 1);
44 while (!error
&& !stored
&& filp
->f_pos
< inode
->i_size
) {
45 lblk
= (filp
->f_pos
) >> sb
->s_blocksize_bits
;
46 /* XXX - ufs_bmap() call needs error checking */
47 blk
= ufs_bmap(inode
, lblk
);
48 bh
= bread (sb
->s_dev
, blk
, sb
->s_blocksize
);
50 /* XXX - error - skip to the next block */
51 printk("ufs_readdir: dir inode %lu has a hole at offset %lu\n",
52 inode
->i_ino
, (unsigned long int)filp
->f_pos
);
53 filp
->f_pos
+= sb
->s_blocksize
- offset
;
58 /* If the dir block has changed since the last call to
59 * readdir(2), then we might be pointing to an invalid
60 * dirent right now. Scan from the start of the block
62 if (filp
->f_version
!= inode
->i_version
) {
63 for (i
= 0; i
< sb
->s_blocksize
&& i
< offset
; ) {
64 de
= (struct ufs_direct
*)
66 /* It's too expensive to do a full
67 * dirent test each time round this
68 * loop, but we do have to test at
69 * least that it is non-zero. A
70 * failure will be detected in the
71 * dirent test below. */
72 if (ufs_swab16(de
->d_reclen
) < 1)
74 i
+= ufs_swab16(de
->d_reclen
);
77 filp
->f_pos
= (filp
->f_pos
& ~(sb
->s_blocksize
- 1))
79 filp
->f_version
= inode
->i_version
;
82 while (!error
&& filp
->f_pos
< inode
->i_size
83 && offset
< sb
->s_blocksize
) {
84 de
= (struct ufs_direct
*) (bh
->b_data
+ offset
);
85 /* XXX - put in a real ufs_check_dir_entry() */
86 if ((ufs_swab16(de
->d_reclen
) == 0)
87 || (ufs_swab16(de
->d_namlen
) == 0)) {
88 filp
->f_pos
= (filp
->f_pos
& (sb
->s_blocksize
- 1)) + sb
->s_blocksize
;
93 if (!ext2_check_dir_entry ("ext2_readdir", inode
, de
,
95 /* On error, skip the f_pos to the
97 filp
->f_pos
= (filp
->f_pos
& (sb
->s_blocksize
- 1))
103 offset
+= ufs_swab16(de
->d_reclen
);
104 if (ufs_swab32(de
->d_ino
)) {
105 /* We might block in the next section
106 * if the data destination is
107 * currently swapped out. So, use a
108 * version stamp to detect whether or
109 * not the directory has been modified
110 * during the copy operation. */
111 unsigned long version
= inode
->i_version
;
113 if (inode
->i_sb
->u
.ufs_sb
.s_flags
& UFS_DEBUG
) {
114 printk("ufs_readdir: filldir(%s,%u)\n",
115 de
->d_name
, ufs_swab32(de
->d_ino
));
117 error
= filldir(dirent
, de
->d_name
, ufs_swab16(de
->d_namlen
), filp
->f_pos
, ufs_swab32(de
->d_ino
));
120 if (version
!= inode
->i_version
)
124 filp
->f_pos
+= ufs_swab16(de
->d_reclen
);
130 if (!IS_RDONLY(inode
)) {
131 inode
->i_atime
= CURRENT_TIME
;
138 static struct file_operations ufs_dir_operations
= {
142 ufs_readdir
, /* readdir */
148 file_fsync
, /* fsync */
150 NULL
, /* check_media_change */
151 NULL
, /* revalidate */
154 struct inode_operations ufs_dir_inode_operations
= {
155 &ufs_dir_operations
, /* default directory file operations */
157 ufs_lookup
, /* lookup */
167 NULL
, /* writepage */
170 NULL
, /* permission */