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