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 static int ext2_dir_read (struct inode * inode, struct file * filp,
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,
36 ext2_dir_read,
37 NULL,
38 ext2_readdir,
39 NULL,
40 ext2_ioctl,
41 NULL,
42 NULL,
43 NULL,
44 file_fsync,
45 NULL,
46 NULL,
47 NULL
48 };
49
50
51
52
53 struct inode_operations ext2_dir_inode_operations = {
54 &ext2_dir_operations,
55 ext2_create,
56 ext2_lookup,
57 ext2_link,
58 ext2_unlink,
59 ext2_symlink,
60 ext2_mkdir,
61 ext2_rmdir,
62 ext2_mknod,
63 ext2_rename,
64 NULL,
65 NULL,
66 NULL,
67 NULL,
68 NULL,
69 ext2_truncate,
70 ext2_permission,
71 NULL
72 };
73
74 int ext2_check_dir_entry (const char * function, struct inode * dir,
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,
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
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
151
152
153
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
159
160
161
162
163
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
180
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
189
190
191
192
193
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 }