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 #include <asm/segment.h>
18
19 #include <linux/autoconf.h>
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 #ifndef CONFIG_EXT2_FS_DIR_READ
27 static int ext2_dir_read (struct inode * inode, struct file * filp,
28 char * buf, int count)
29 {
30 return -EISDIR;
31 }
32 #else
33 int ext2_file_read (struct inode *, struct file *, char *, int);
34 #endif
35
36 static int ext2_readdir (struct inode *, struct file *, struct dirent *, int);
37
38 static struct file_operations ext2_dir_operations = {
39 NULL,
40 #ifdef CONFIG_EXT2_FS_DIR_READ
41 ext2_file_read,
42 #else
43 ext2_dir_read,
44 #endif
45 NULL,
46 ext2_readdir,
47 NULL,
48 ext2_ioctl,
49 NULL,
50 NULL,
51 NULL,
52 file_fsync
53 };
54
55
56
57
58 struct inode_operations ext2_dir_inode_operations = {
59 &ext2_dir_operations,
60 ext2_create,
61 ext2_lookup,
62 ext2_link,
63 ext2_unlink,
64 ext2_symlink,
65 ext2_mkdir,
66 ext2_rmdir,
67 ext2_mknod,
68 ext2_rename,
69 NULL,
70 NULL,
71 NULL,
72 ext2_truncate,
73 ext2_permission
74 };
75
76 int ext2_check_dir_entry (char * function, struct inode * dir,
77 struct ext2_dir_entry * de, struct buffer_head * bh,
78 unsigned long offset)
79 {
80 char * error_msg = NULL;
81
82 if (de->rec_len < EXT2_DIR_REC_LEN(1))
83 error_msg = "rec_len is smaller than minimal";
84 else if (de->rec_len % 4 != 0)
85 error_msg = "rec_len % 4 != 0";
86 else if (de->rec_len < EXT2_DIR_REC_LEN(de->name_len))
87 error_msg = "rec_len is too small for name_len";
88 else if (dir && ((char *) de - bh->b_data) + de->rec_len >
89 dir->i_sb->s_blocksize)
90 error_msg = "directory entry across blocks";
91
92 if (error_msg != NULL)
93 ext2_error (dir->i_sb, function, "bad directory entry: %s\n"
94 "offset=%lu, inode=%lu, rec_len=%d, name_len=%d",
95 error_msg, offset, de->inode, de->rec_len,
96 de->name_len);
97 return error_msg == NULL ? 1 : 0;
98 }
99
100 static int ext2_readdir (struct inode * inode, struct file * filp,
101 struct dirent * dirent, int count)
102 {
103 unsigned long offset, blk;
104 int i, num;
105 struct buffer_head * bh, * tmp, * bha[16];
106 struct ext2_dir_entry * de;
107 struct super_block * sb;
108 int err;
109
110 if (!inode || !S_ISDIR(inode->i_mode))
111 return -EBADF;
112 sb = inode->i_sb;
113 while (filp->f_pos < inode->i_size) {
114 offset = filp->f_pos & (sb->s_blocksize - 1);
115 blk = (filp->f_pos) >> EXT2_BLOCK_SIZE_BITS(sb);
116 bh = ext2_bread (inode, blk, 0, &err);
117 if (!bh) {
118 filp->f_pos += sb->s_blocksize - offset;
119 continue;
120 }
121
122
123
124
125 if (!offset) {
126 for (i = 16 >> (EXT2_BLOCK_SIZE_BITS(sb) - 9), num = 0;
127 i > 0; i--) {
128 tmp = ext2_getblk (inode, ++blk, 0, &err);
129 if (tmp && !tmp->b_uptodate && !tmp->b_lock)
130 bha[num++] = tmp;
131 else
132 brelse (tmp);
133 }
134 if (num) {
135 ll_rw_block (READA, num, bha);
136 for (i = 0; i < num; i++)
137 brelse (bha[i]);
138 }
139 }
140
141 de = (struct ext2_dir_entry *) (offset + bh->b_data);
142 while (offset < sb->s_blocksize && filp->f_pos < inode->i_size) {
143 if (!ext2_check_dir_entry ("ext2_readdir", inode, de,
144 bh, offset)) {
145 brelse (bh);
146 return 0;
147 }
148 offset += de->rec_len;
149 filp->f_pos += de->rec_len;
150 if (de->inode) {
151 memcpy_tofs (dirent->d_name, de->name,
152 de->name_len);
153 put_fs_long (de->inode, &dirent->d_ino);
154 put_fs_byte (0, de->name_len + dirent->d_name);
155 put_fs_word (de->name_len, &dirent->d_reclen);
156 #ifndef DONT_USE_DCACHE
157 ext2_dcache_add (inode->i_dev, inode->i_ino,
158 de->name, de->name_len,
159 de->inode);
160 #endif
161 i = de->name_len;
162 brelse (bh);
163 if (!IS_RDONLY(inode)) {
164 inode->i_atime = CURRENT_TIME;
165 inode->i_dirt = 1;
166 }
167 return i;
168 }
169 de = (struct ext2_dir_entry *) ((char *) de +
170 de->rec_len);
171 }
172 brelse (bh);
173 }
174 if (!IS_RDONLY(inode)) {
175 inode->i_atime = CURRENT_TIME;
176 inode->i_dirt = 1;
177 }
178 return 0;
179 }