This source file includes following definitions.
- ext2_dir_read
- ext2_check_dir_entry
- ext2_readdir
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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 #define NAME_OFFSET(de) ((int) ((de)->d_name - (char *) (de)))
27 #define ROUND_UP(x) (((x)+3) & ~3)
28
29 static int ext2_dir_read (struct inode * inode, struct file * filp,
30 char * buf, int count)
31 {
32 return -EISDIR;
33 }
34
35 static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
36
37 static struct file_operations ext2_dir_operations = {
38 NULL,
39 ext2_dir_read,
40 NULL,
41 ext2_readdir,
42 NULL,
43 ext2_ioctl,
44 NULL,
45 NULL,
46 NULL,
47 file_fsync,
48 NULL,
49 NULL,
50 NULL
51 };
52
53
54
55
56 struct inode_operations ext2_dir_inode_operations = {
57 &ext2_dir_operations,
58 ext2_create,
59 ext2_lookup,
60 ext2_link,
61 ext2_unlink,
62 ext2_symlink,
63 ext2_mkdir,
64 ext2_rmdir,
65 ext2_mknod,
66 ext2_rename,
67 NULL,
68 NULL,
69 NULL,
70 ext2_truncate,
71 ext2_permission,
72 NULL
73 };
74
75 int ext2_check_dir_entry (char * function, struct inode * dir,
76 struct ext2_dir_entry * de, struct buffer_head * bh,
77 unsigned long offset)
78 {
79 char * error_msg = NULL;
80
81 if (de->rec_len < EXT2_DIR_REC_LEN(1))
82 error_msg = "rec_len is smaller than minimal";
83 else if (de->rec_len % 4 != 0)
84 error_msg = "rec_len % 4 != 0";
85 else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
86 error_msg = "rec_len is too small for name_len";
87 else if (dir && ((char *) de - bh->b_data) + de->rec_len >
88 dir->i_sb->s_blocksize)
89 error_msg = "directory entry across blocks";
90 else if (dir && de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
91 error_msg = "inode out of bounds";
92
93 if (error_msg != NULL)
94 ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
95 "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
96 error_msg, offset, (unsigned long) de->inode, de->rec_len,
97 de->name_len);
98 return error_msg == NULL ? 1 : 0;
99 }
100
101 static int ext2_readdir (struct inode * inode, struct file * filp,
102 struct dirent * dirent, int count)
103 {
104 unsigned long offset, blk;
105 int i, num, stored, dlen;
106 struct buffer_head * bh, * tmp, * bha[16];
107 struct ext2_dir_entry * de;
108 struct super_block * sb;
109 int err, version;
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 (count > 0 && !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 filp->f_pos += sb->s_blocksize - offset;
124 continue;
125 }
126
127
128
129
130 if (!offset) {
131 for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
132 i > 0; i--) {
133 tmp = ext2_getblk (inode, ++blk, 0, &err);
134 if (tmp && !tmp->b_uptodate && !tmp->b_lock)
135 bha[num++] = tmp;
136 else
137 brelse (tmp);
138 }
139 if (num) {
140 ll_rw_block (READA, num, bha);
141 for (i = 0; i < num; i++)
142 brelse (bha[i]);
143 }
144 }
145
146 revalidate:
147
148
149
150
151 if (filp->f_version != inode->i_version) {
152 for (i = 0; i < sb->s_blocksize && i < offset; ) {
153 de = (struct ext2_dir_entry *)
154 (bh->b_data + i);
155
156
157
158
159
160
161 if (de->rec_len < EXT2_DIR_REC_LEN(1))
162 break;
163 i += de->rec_len;
164 }
165 offset = i;
166 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
167 | offset;
168 filp->f_version = inode->i_version;
169 }
170
171 while (count > 0 && filp->f_pos < inode->i_size
172 && offset < sb->s_blocksize) {
173 de = (struct ext2_dir_entry *) (bh->b_data + offset);
174 if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
175 bh, offset)) {
176
177
178 filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
179 + sb->s_blocksize;
180 brelse (bh);
181 return stored;
182 }
183 if (de->inode) {
184 dlen = ROUND_UP(NAME_OFFSET(dirent)
185 + de->name_len + 1);
186
187
188 if (count == 1 && !stored)
189 count = dlen;
190 if (count < dlen) {
191 count = 0;
192 break;
193 }
194
195
196
197
198
199
200
201 version = inode->i_version;
202 i = de->name_len;
203 memcpy_tofs (dirent->d_name, de->name, i);
204 put_fs_long (de->inode, &dirent->d_ino);
205 put_fs_byte (0, dirent->d_name + i);
206 put_fs_word (i, &dirent->d_reclen);
207 put_fs_long (dlen, &dirent->d_off);
208 if (version != inode->i_version)
209 goto revalidate;
210 dcache_add(inode, de->name, de->name_len,
211 de->inode);
212
213 stored += dlen;
214 count -= dlen;
215 ((char *) dirent) += dlen;
216 }
217 offset += de->rec_len;
218 filp->f_pos += de->rec_len;
219 }
220 offset = 0;
221 brelse (bh);
222 }
223 if (!IS_RDONLY(inode)) {
224 inode->i_atime = CURRENT_TIME;
225 inode->i_dirt = 1;
226 }
227 return stored;
228 }