This source file includes following definitions.
- fat_dir_read
- fat_readdirx
- fat_readdir
- vfat_ioctl_fill
- fat_dir_ioctl
1
2
3
4
5
6
7
8
9
10
11
12
13 #include <linux/fs.h>
14 #include <linux/msdos_fs.h>
15 #include <linux/kernel.h>
16 #include <linux/errno.h>
17 #include <linux/stat.h>
18 #include <linux/string.h>
19 #include <linux/ioctl.h>
20 #include <linux/dirent.h>
21
22 #include <asm/segment.h>
23
24 #include "msbuffer.h"
25 #include "tables.h"
26
27
28 #define PRINTK(X)
29
30 static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
31 {
32 return -EISDIR;
33 }
34
35 struct file_operations fat_dir_operations = {
36 NULL,
37 fat_dir_read,
38 NULL,
39 fat_readdir,
40 NULL,
41 fat_dir_ioctl,
42 NULL,
43 NULL,
44 NULL,
45 file_fsync
46 };
47
48 int fat_readdirx(
49 struct inode *inode,
50 struct file *filp,
51 void *dirent,
52 filldir_t filldir,
53 int both)
54 {
55 struct super_block *sb = inode->i_sb;
56 int ino,i,i2,last;
57 char c;
58 struct buffer_head *bh;
59 struct msdos_dir_entry *de;
60 unsigned long oldpos = filp->f_pos;
61 int is_long;
62 char longname[275];
63 unsigned char long_len = 0;
64 unsigned char alias_checksum = 0;
65
66
67 if (!inode || !S_ISDIR(inode->i_mode))
68 return -EBADF;
69
70 if (inode->i_ino == MSDOS_ROOT_INO) {
71 while (oldpos < 2) {
72 if (filldir(dirent, "..", oldpos+1, oldpos, MSDOS_ROOT_INO) < 0)
73 return 0;
74 oldpos++;
75 filp->f_pos++;
76 }
77 if (oldpos == 2)
78 filp->f_pos = 0;
79 }
80 if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1))
81 return -ENOENT;
82
83 bh = NULL;
84 longname[0] = '\0';
85 is_long = 0;
86 ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
87 while (ino > -1) {
88
89
90
91
92 if (!MSDOS_SB(sb)->vfat &&
93 !MSDOS_SB(sb)->umsdos &&
94 !IS_RDONLY(inode) &&
95 (de->attr == ATTR_EXT) &&
96 !MSDOS_SB(sb)->quiet) {
97 printk("MSDOS-fs warning: vfat directory entry found on fs mounted non-vfat (device %s)\n",
98 kdevname(sb->s_dev));
99 }
100
101
102 if (MSDOS_SB(sb)->vfat && (de->name[0] == (__s8) DELETED_FLAG)) {
103 is_long = 0;
104 oldpos = filp->f_pos;
105 } else if (MSDOS_SB(sb)->vfat && de->attr == ATTR_EXT) {
106 int get_new_entry;
107 struct msdos_dir_slot *ds;
108 unsigned char page, pg_off, ascii;
109 unsigned char *uni_page;
110 unsigned char offset;
111 unsigned char id;
112 unsigned char slot;
113 unsigned char slots = 0;
114 int i;
115
116 offset = 0;
117 ds = (struct msdos_dir_slot *) de;
118 id = ds->id;
119 if (id & 0x40) {
120 slots = id & ~0x40;
121 is_long = 1;
122 alias_checksum = ds->alias_checksum;
123 }
124
125 get_new_entry = 1;
126 slot = slots;
127 while (slot > 0) {
128 PRINTK(("1. get_new_entry: %d\n", get_new_entry));
129 if (ds->attr != ATTR_EXT) {
130 is_long = 0;
131 get_new_entry = 0;
132 break;
133 }
134 if ((ds->id & ~0x40) != slot) {
135 is_long = 0;
136 break;
137 }
138 if (ds->alias_checksum != alias_checksum) {
139 is_long = 0;
140 break;
141 }
142 slot--;
143 offset = slot * 13;
144 PRINTK(("2. get_new_entry: %d\n", get_new_entry));
145 for (i = 0; i < 10; i += 2) {
146 pg_off = ds->name0_4[i];
147 page = ds->name0_4[i+1];
148 if (pg_off == 0 && page == 0) {
149 goto found_end;
150 }
151 uni_page = fat_uni2asc_pg[page];
152 ascii = uni_page[pg_off];
153 longname[offset++] = ascii ? ascii : '?';
154 }
155 for (i = 0; i < 12; i += 2) {
156 pg_off = ds->name5_10[i];
157 page = ds->name5_10[i+1];
158 if (pg_off == 0 && page == 0) {
159 goto found_end;
160 }
161 uni_page = fat_uni2asc_pg[page];
162 ascii = uni_page[pg_off];
163 longname[offset++] = ascii ? ascii : '?';
164 }
165 for (i = 0; i < 4; i += 2) {
166 pg_off = ds->name11_12[i];
167 page = ds->name11_12[i+1];
168 if (pg_off == 0 && page == 0) {
169 goto found_end;
170 }
171 uni_page = fat_uni2asc_pg[page];
172 ascii = uni_page[pg_off];
173 longname[offset++] = ascii ? ascii : '?';
174 }
175 found_end:
176 PRINTK(("3. get_new_entry: %d\n", get_new_entry));
177 if (ds->id & 0x40) {
178 longname[offset] = '\0';
179 long_len = offset;
180 }
181 if (slot > 0) {
182 ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
183 PRINTK(("4. get_new_entry: %d\n", get_new_entry));
184 if (ino == -1) {
185 is_long = 0;
186 get_new_entry = 0;
187 break;
188 }
189 ds = (struct msdos_dir_slot *) de;
190 }
191 PRINTK(("5. get_new_entry: %d\n", get_new_entry));
192 }
193 PRINTK(("Long filename: %s, get_new_entry: %d\n", longname, get_new_entry));
194 } else if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
195 char bufname[14];
196 char *ptname = bufname;
197 int dotoffset = 0;
198
199 if (is_long) {
200 unsigned char sum;
201
202 for (sum = i = 0; i < 11; i++) {
203 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
204 }
205
206 if (sum != alias_checksum) {
207 PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
208 is_long = 0;
209 }
210 }
211
212 if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->dotsOK) {
213 bufname[0] = '.';
214 dotoffset = 1;
215 ptname = bufname+1;
216 }
217 for (i = last = 0; i < 8; i++) {
218 if (!(c = de->name[i])) break;
219 if (c >= 'A' && c <= 'Z') c += 32;
220
221 if (c == 0x05) c = 0xE5;
222 if (c != ' ')
223 last = i+1;
224 ptname[i] = c;
225 }
226 i = last;
227 ptname[i] = '.';
228 i++;
229 for (i2 = 0; i2 < 3; i2++) {
230 if (!(c = de->ext[i2])) break;
231 if (c >= 'A' && c <= 'Z') c += 32;
232 if (c != ' ')
233 last = i+1;
234 ptname[i] = c;
235 i++;
236 }
237 if ((i = last) != 0) {
238 if (!strcmp(de->name,MSDOS_DOT))
239 ino = inode->i_ino;
240 else if (!strcmp(de->name,MSDOS_DOTDOT))
241 ino = fat_parent_ino(inode,0);
242
243 if (!is_long) {
244 dcache_add(inode, bufname, i+dotoffset, ino);
245 if (both) {
246 bufname[i+dotoffset] = '\0';
247 }
248 if (filldir(dirent, bufname, i+dotoffset, oldpos, ino) < 0) {
249 filp->f_pos = oldpos;
250 break;
251 }
252 } else {
253 dcache_add(inode, longname, long_len, ino);
254 if (both) {
255 memcpy(&longname[long_len+1], bufname, i+dotoffset);
256 long_len += i+dotoffset;
257 }
258 if (filldir(dirent, longname, long_len, oldpos, ino) < 0) {
259 filp->f_pos = oldpos;
260 break;
261 }
262 }
263 oldpos = filp->f_pos;
264 }
265 is_long = 0;
266 } else {
267 is_long = 0;
268 oldpos = filp->f_pos;
269 }
270 ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
271 }
272 if (bh) brelse(bh);
273 return 0;
274 }
275
276 int fat_readdir(
277 struct inode *inode,
278 struct file *filp,
279 void *dirent,
280 filldir_t filldir)
281 {
282 return fat_readdirx(inode, filp, dirent, filldir, 0);
283 }
284 static int vfat_ioctl_fill(
285 void * buf,
286 const char * name,
287 int name_len,
288 off_t offset,
289 ino_t ino)
290 {
291 struct dirent *d1 = (struct dirent *)buf;
292 struct dirent *d2 = d1 + 1;
293 int len, slen;
294 int dotdir;
295
296 if (get_user(&d1->d_reclen) != 0) {
297 return -1;
298 }
299
300 if ((name_len == 1 && name[0] == '.') ||
301 (name_len == 2 && name[0] == '.' && name[1] == '.')) {
302 dotdir = 1;
303 len = name_len;
304 } else {
305 dotdir = 0;
306 len = strlen(name);
307 }
308 if (len != name_len) {
309 memcpy_tofs(d2->d_name, name, len);
310 put_user(0, d2->d_name + len);
311 put_user(len, &d2->d_reclen);
312 put_user(ino, &d2->d_ino);
313 put_user(offset, &d2->d_off);
314 slen = name_len - len;
315 memcpy_tofs(d1->d_name, name+len+1, slen);
316 put_user(0, d1->d_name+slen);
317 put_user(slen, &d1->d_reclen);
318 } else {
319 put_user(0, d2->d_name);
320 put_user(0, &d2->d_reclen);
321 memcpy_tofs(d1->d_name, name, len);
322 put_user(0, d1->d_name+len);
323 put_user(len, &d1->d_reclen);
324 }
325 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
326 d1, d2, len, name_len));
327
328 return 0;
329 }
330
331 int fat_dir_ioctl(struct inode * inode, struct file * filp,
332 unsigned int cmd, unsigned long arg)
333 {
334
335
336
337
338
339
340 switch (cmd) {
341 case VFAT_IOCTL_READDIR_BOTH: {
342 struct dirent *d1 = (struct dirent *)arg;
343 put_user(0, &d1->d_reclen);
344 return fat_readdirx(inode,filp,(void *)arg,vfat_ioctl_fill,1);
345 }
346 default:
347 return -EINVAL;
348 }
349
350 return 0;
351 }