1 /*
2 * linux/fs/ext2/dir.c
3 *
4 * Copyright (C) 1992, 1993, 1994, 1995
5 * Remy Card (card@masi.ibp.fr)
6 * Laboratoire MASI - Institut Blaise Pascal
7 * Universite Pierre et Marie Curie (Paris VI)
8 *
9 * from
10 *
11 * linux/fs/minix/dir.c
12 *
13 * Copyright (C) 1991, 1992 Linus Torvalds
14 *
15 * ext2 directory handling functions
16 */
17
18 #include <asm/segment.h>
19
20 #include <linux/errno.h>
21 #include <linux/fs.h>
22 #include <linux/ext2_fs.h>
23 #include <linux/sched.h>
24 #include <linux/stat.h>
25
26 static int ext2_dir_read (struct inode * inode, struct file * filp,
/* ![[previous]](../icons/n_left.png)
![[next]](../icons/right.png)
![[first]](../icons/n_first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
27 char * buf, int count)
28 {
29 return -EISDIR;
30 }
31
32 static int ext2_readdir (struct inode *, struct file *, void *, filldir_t);
33
34 static struct file_operations ext2_dir_operations = {
35 NULL, /* lseek - default */
36 ext2_dir_read, /* read */
37 NULL, /* write - bad */
38 ext2_readdir, /* readdir */
39 NULL, /* select - default */
40 ext2_ioctl, /* ioctl */
41 NULL, /* mmap */
42 NULL, /* no special open code */
43 NULL, /* no special release code */
44 file_fsync, /* fsync */
45 NULL, /* fasync */
46 NULL, /* check_media_change */
47 NULL /* revalidate */
48 };
49
50 /*
51 * directories can handle most operations...
52 */
53 struct inode_operations ext2_dir_inode_operations = {
54 &ext2_dir_operations, /* default directory file-ops */
55 ext2_create, /* create */
56 ext2_lookup, /* lookup */
57 ext2_link, /* link */
58 ext2_unlink, /* unlink */
59 ext2_symlink, /* symlink */
60 ext2_mkdir, /* mkdir */
61 ext2_rmdir, /* rmdir */
62 ext2_mknod, /* mknod */
63 ext2_rename, /* rename */
64 NULL, /* readlink */
65 NULL, /* follow_link */
66 NULL, /* readpage */
67 NULL, /* writepage */
68 NULL, /* bmap */
69 ext2_truncate, /* truncate */
70 ext2_permission, /* permission */
71 NULL /* smap */
72 };
73
74 int ext2_check_dir_entry (const char * function, struct inode * dir,
/* ![[previous]](../icons/left.png)
![[next]](../icons/right.png)
![[first]](../icons/first.png)
![[last]](../icons/last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
75 struct ext2_dir_entry * de, struct buffer_head * bh,
76 unsigned long offset)
77 {
78 const char * error_msg = NULL;
79
80 if (de->rec_len < EXT2_DIR_REC_LEN(1))
81 error_msg = "rec_len is smaller than minimal";
82 else if (de->rec_len % 4 != 0)
83 error_msg = "rec_len % 4 != 0";
84 else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
85 error_msg = "rec_len is too small for name_len";
86 else if (dir && ((char *) de - bh->b_data) + de->rec_len >
87 dir->i_sb->s_blocksize)
88 error_msg = "directory entry across blocks";
89 else if (dir && de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
90 error_msg = "inode out of bounds";
91
92 if (error_msg != NULL)
93 ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
94 "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
95 dir->i_ino, error_msg, offset, (unsigned long) de->inode,
96 de->rec_len, de->name_len);
97 return error_msg == NULL ? 1 : 0;
98 }
99
100 static int ext2_readdir (struct inode * inode, struct file * filp,
/* ![[previous]](../icons/left.png)
![[next]](../icons/n_right.png)
![[first]](../icons/first.png)
![[last]](../icons/n_last.png)
![[top]](../icons/top.png)
![[bottom]](../icons/bottom.png)
![[index]](../icons/index.png)
*/
101 void * dirent, filldir_t filldir)
102 {
103 int error = 0;
104 unsigned long offset, blk;
105 int i, num, stored;
106 struct buffer_head * bh, * tmp, * bha[16];
107 struct ext2_dir_entry * de;
108 struct super_block * sb;
109 int err;
110
111 if (!inode || !S_ISDIR(inode->i_mode))
112 return -EBADF;
113 sb = inode->i_sb;
114
115 stored = 0;
116 bh = NULL;
117 offset = filp->f_pos & (sb->s_blocksize - 1);
118
119 while (!error && !stored && filp->f_pos < inode->i_size) {
120 blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
121 bh = ext2_bread (inode, blk, 0, &err);
122 if (!bh) {
123 ext2_error (sb, "ext2_readdir",
124 "directory #%lu contains a hole at offset %lu",
125 inode->i_ino, (unsigned long)filp->f_pos);
126 filp->f_pos += sb->s_blocksize - offset;
127 continue;
128 }
129
130 /*
131 * Do the readahead
132 */
133 if (!offset) {
134 for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
135 i > 0; i--) {
136 tmp = ext2_getblk (inode, ++blk, 0, &err);
137 if (tmp && !buffer_uptodate(tmp) && !buffer_locked(tmp))
138 bha[num++] = tmp;
139 else
140 brelse (tmp);
141 }
142 if (num) {
143 ll_rw_block (READA, num, bha);
144 for (i = 0; i < num; i++)
145 brelse (bha[i]);
146 }
147 }
148
149 revalidate:
150 /* If the dir block has changed since the last call to
151 * readdir(2), then we might be pointing to an invalid
152 * dirent right now. Scan from the start of the block
153 * to make sure. */
154 if (filp->f_version != inode->i_version) {
155 for (i = 0; i < sb->s_blocksize && i < offset; ) {
156 de = (struct ext2_dir_entry *)
157 (bh->b_data + i);
158 /* It's too expensive to do a full
159 * dirent test each time round this
160 * loop, but we do have to test at
161 * least that it is non-zero. A
162 * failure will be detected in the
163 * dirent test below. */
164 if (de->rec_len < EXT2_DIR_REC_LEN(1))
165 break;
166 i += de->rec_len;
167 }
168 offset = i;
169 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
170 | offset;
171 filp->f_version = inode->i_version;
172 }
173
174 while (!error && filp->f_pos < inode->i_size
175 && offset < sb->s_blocksize) {
176 de = (struct ext2_dir_entry *) (bh->b_data + offset);
177 if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
178 bh, offset)) {
179 /* On error, skip the f_pos to the
180 next block. */
181 filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
182 + sb->s_blocksize;
183 brelse (bh);
184 return stored;
185 }
186 offset += de->rec_len;
187 if (de->inode) {
188 /* We might block in the next section
189 * if the data destination is
190 * currently swapped out. So, use a
191 * version stamp to detect whether or
192 * not the directory has been modified
193 * during the copy operation. */
194 unsigned long version;
195 dcache_add(inode, de->name, de->name_len, de->inode);
196 version = inode->i_version;
197 error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
198 if (error)
199 break;
200 if (version != inode->i_version)
201 goto revalidate;
202 stored ++;
203 }
204 filp->f_pos += de->rec_len;
205 }
206 offset = 0;
207 brelse (bh);
208 }
209 if (!IS_RDONLY(inode)) {
210 inode->i_atime = CURRENT_TIME;
211 inode->i_dirt = 1;
212 }
213 return 0;
214 }