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 ext2_truncate,
68 ext2_permission,
69 NULL
70 };
71
72 int ext2_check_dir_entry (const char * function, struct inode * dir,
73 struct ext2_dir_entry * de, struct buffer_head * bh,
74 unsigned long offset)
75 {
76 const char * error_msg = NULL;
77
78 if (de->rec_len < EXT2_DIR_REC_LEN(1))
79 error_msg = "rec_len is smaller than minimal";
80 else if (de->rec_len % 4 != 0)
81 error_msg = "rec_len % 4 != 0";
82 else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
83 error_msg = "rec_len is too small for name_len";
84 else if (dir && ((char *) de - bh->b_data) + de->rec_len >
85 dir->i_sb->s_blocksize)
86 error_msg = "directory entry across blocks";
87 else if (dir && de->inode > dir->i_sb->u.ext2_sb.s_es->s_inodes_count)
88 error_msg = "inode out of bounds";
89
90 if (error_msg != NULL)
91 ext2_error (dir->i_sb, function, "bad entry in directory #%lu: %s - "
92 "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
93 dir->i_ino, error_msg, offset, (unsigned long) de->inode,
94 de->rec_len, de->name_len);
95 return error_msg == NULL ? 1 : 0;
96 }
97
98 static int ext2_readdir (struct inode * inode, struct file * filp,
99 void * dirent, filldir_t filldir)
100 {
101 int error = 0;
102 unsigned long offset, blk;
103 int i, num, stored;
104 struct buffer_head * bh, * tmp, * bha[16];
105 struct ext2_dir_entry * de;
106 struct super_block * sb;
107 int err, version;
108
109 if (!inode || !S_ISDIR(inode->i_mode))
110 return -EBADF;
111 sb = inode->i_sb;
112
113 stored = 0;
114 bh = NULL;
115 offset = filp->f_pos & (sb->s_blocksize - 1);
116
117 while (!error && !stored && filp->f_pos < inode->i_size) {
118 blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
119 bh = ext2_bread (inode, blk, 0, &err);
120 if (!bh) {
121 ext2_error (sb, "ext2_readdir",
122 "directory #%lu contains a hole at offset %lu",
123 inode->i_ino, (unsigned long)filp->f_pos);
124 filp->f_pos += sb->s_blocksize - offset;
125 continue;
126 }
127
128
129
130
131 if (!offset) {
132 for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
133 i > 0; i--) {
134 tmp = ext2_getblk (inode, ++blk, 0, &err);
135 if (tmp && !tmp->b_uptodate && !tmp->b_lock)
136 bha[num++] = tmp;
137 else
138 brelse (tmp);
139 }
140 if (num) {
141 ll_rw_block (READA, num, bha);
142 for (i = 0; i < num; i++)
143 brelse (bha[i]);
144 }
145 }
146
147 revalidate:
148
149
150
151
152 if (filp->f_version != inode->i_version) {
153 for (i = 0; i < sb->s_blocksize && i < offset; ) {
154 de = (struct ext2_dir_entry *)
155 (bh->b_data + i);
156
157
158
159
160
161
162 if (de->rec_len < EXT2_DIR_REC_LEN(1))
163 break;
164 i += de->rec_len;
165 }
166 offset = i;
167 filp->f_pos = (filp->f_pos & ~(sb->s_blocksize - 1))
168 | offset;
169 filp->f_version = inode->i_version;
170 }
171
172 while (!error && filp->f_pos < inode->i_size
173 && offset < sb->s_blocksize) {
174 de = (struct ext2_dir_entry *) (bh->b_data + offset);
175 if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
176 bh, offset)) {
177
178
179 filp->f_pos = (filp->f_pos & (sb->s_blocksize - 1))
180 + sb->s_blocksize;
181 brelse (bh);
182 return stored;
183 }
184 offset += de->rec_len;
185 if (de->inode) {
186
187
188
189
190
191
192 version = inode->i_version;
193 error = filldir(dirent, de->name, de->name_len, filp->f_pos, de->inode);
194 if (error)
195 break;
196 if (version != inode->i_version)
197 goto revalidate;
198 stored ++;
199 }
200 filp->f_pos += de->rec_len;
201 }
202 offset = 0;
203 brelse (bh);
204 }
205 if (!IS_RDONLY(inode)) {
206 inode->i_atime = CURRENT_TIME;
207 inode->i_dirt = 1;
208 }
209 return 0;
210 }