Import 2.3.26pre2
[davej-history.git] / fs / fat / dir.c
blob628c0bb9c0ef1b99e70ca1397787609108015b9d
1 /*
2 * linux/fs/fat/dir.c
4 * directory handling functions for fat-based filesystems
6 * Written 1992,1993 by Werner Almesberger
8 * Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
10 * VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
11 * Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
12 * Rewritten for constant inumbers. Plugged buffer overrun in readdir(). AV
15 #define ASC_LINUX_VERSION(V, P, S) (((V) * 65536) + ((P) * 256) + (S))
17 #include <linux/version.h>
18 #include <linux/fs.h>
19 #include <linux/msdos_fs.h>
20 #include <linux/nls.h>
21 #include <linux/kernel.h>
22 #include <linux/errno.h>
23 #include <linux/stat.h>
24 #include <linux/string.h>
25 #include <linux/ioctl.h>
26 #include <linux/dirent.h>
27 #include <linux/mm.h>
28 #include <linux/ctype.h>
30 #include <asm/uaccess.h>
32 #include "msbuffer.h"
34 #define PRINTK(X)
36 static ssize_t fat_dir_read(struct file * filp, char * buf,
37 size_t count, loff_t *ppos)
39 return -EISDIR;
42 struct file_operations fat_dir_operations = {
43 NULL, /* lseek - default */
44 fat_dir_read, /* read */
45 NULL, /* write - bad */
46 fat_readdir, /* readdir */
47 NULL, /* select v2.0.x/poll v2.1.x - default */
48 fat_dir_ioctl, /* ioctl - default */
49 NULL, /* mmap */
50 NULL, /* no special open code */
51 NULL, /* flush */
52 NULL, /* no special release code */
53 file_fsync /* fsync */
57 * Convert Unicode 16 to UTF8, translated Unicode, or ASCII.
58 * If uni_xlate is enabled and we
59 * can't get a 1:1 conversion, use a colon as an escape character since
60 * it is normally invalid on the vfat filesystem. The following three
61 * characters are a sort of uuencoded 16 bit Unicode value. This lets
62 * us do a full dump and restore of Unicode filenames. We could get
63 * into some trouble with long Unicode names, but ignore that right now.
64 * Ahem... Stack smashing in ring 0 isn't fun. Fixed.
66 static int
67 uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
68 struct nls_table *nls)
70 unsigned char *ip, *op;
71 unsigned char ch, cl;
72 unsigned char *uni_page;
73 unsigned short val;
75 ip = uni;
76 op = ascii;
78 while (*ip || ip[1]) {
79 cl = *ip++;
80 ch = *ip++;
82 uni_page = nls->page_uni2charset[ch];
83 if (uni_page && uni_page[cl]) {
84 *op++ = uni_page[cl];
85 } else {
86 if (uni_xlate == 1) {
87 *op++ = ':';
88 val = (cl << 8) + ch;
89 op[2] = fat_uni2esc[val & 0x3f];
90 val >>= 6;
91 op[1] = fat_uni2esc[val & 0x3f];
92 val >>= 6;
93 *op = fat_uni2esc[val & 0x3f];
94 op += 3;
95 } else {
96 *op++ = '?';
99 /* We have some slack there, so it's OK */
100 if (op>ascii+256) {
101 op = ascii + 256;
102 break;
105 *op = 0;
106 return (op - ascii);
109 #if 0
110 static void dump_de(struct msdos_dir_entry *de)
112 int i;
113 unsigned char *p = (unsigned char *) de;
114 printk("[");
116 for (i = 0; i < 32; i++, p++) {
117 printk("%02x ", *p);
119 printk("]\n");
121 #endif
122 static int memicmp(const char *s1, const char *s2, int len) {
123 while(len--) if (tolower(*s1++)!=tolower(*s2++)) return 1;
124 return 0;
128 * Return values: negative -> error, 0 -> not found, positive -> found,
129 * value is the total amount of slots, including the shortname entry.
131 int fat_search_long(
132 struct inode *inode, const char *name, int name_len, int anycase,
133 loff_t *spos, loff_t *lpos)
135 struct super_block *sb = inode->i_sb;
136 int ino,i,i2,last;
137 char c;
138 struct buffer_head *bh = NULL;
139 struct msdos_dir_entry *de;
140 loff_t cpos = 0;
141 char bufname[14];
142 unsigned char long_slots;
143 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
144 int utf8 = MSDOS_SB(sb)->options.utf8;
145 unsigned char *unicode = NULL;
146 struct nls_table *nls = MSDOS_SB(sb)->nls_io;
147 int res = 0;
149 while(1) {
150 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
151 goto EODir;
152 parse_record:
153 long_slots = 0;
154 if (de->name[0] == (__s8) DELETED_FLAG)
155 continue;
156 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
157 continue;
158 if (de->attr != ATTR_EXT && IS_FREE(de->name))
159 continue;
160 if (de->attr == ATTR_EXT) {
161 struct msdos_dir_slot *ds;
162 int offset;
163 unsigned char id;
164 unsigned char slot;
165 unsigned char slots;
166 unsigned char sum;
167 unsigned char alias_checksum;
169 if (!unicode) {
170 unicode = (unsigned char *)
171 __get_free_page(GFP_KERNEL);
172 if (!unicode) {
173 fat_brelse(sb, bh);
174 return -ENOMEM;
177 parse_long:
178 slots = 0;
179 offset = 0;
180 ds = (struct msdos_dir_slot *) de;
181 id = ds->id;
182 if (!(id & 0x40))
183 continue;
184 slots = id & ~0x40;
185 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
186 continue;
187 long_slots = slots;
188 alias_checksum = ds->alias_checksum;
190 slot = slots;
191 while (1) {
192 slot--;
193 offset = slot * 26;
194 memcpy(&unicode[offset], ds->name0_4, 10);
195 memcpy(&unicode[offset+10], ds->name5_10, 12);
196 memcpy(&unicode[offset+22], ds->name11_12, 4);
197 offset += 26;
199 if (ds->id & 0x40) {
200 unicode[offset] = 0;
201 unicode[offset+1] = 0;
203 if (fat_get_entry(inode,&cpos,&bh,&de,&ino)<0)
204 goto EODir;
205 if (slot == 0)
206 break;
207 ds = (struct msdos_dir_slot *) de;
208 if (ds->attr != ATTR_EXT)
209 goto parse_record;
210 if ((ds->id & ~0x40) != slot)
211 goto parse_long;
212 if (ds->alias_checksum != alias_checksum)
213 goto parse_long;
215 if (de->name[0] == (__s8) DELETED_FLAG)
216 continue;
217 if (de->attr == ATTR_EXT)
218 goto parse_long;
219 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
220 continue;
221 for (sum = 0, i = 0; i < 11; i++)
222 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
223 if (sum != alias_checksum)
224 long_slots = 0;
227 for (i = 0, last = 0; i < 8;) {
228 if (!(c = de->name[i])) break;
229 if (c >= 'A' && c <= 'Z') c += 32;
230 if (c == 0x05) c = 0xE5;
231 if ((bufname[i++] = c) != ' ')
232 last = i;
234 i = last;
235 bufname[i++] = '.';
236 for (i2 = 0; i2 < 3; i2++) {
237 if (!(c = de->ext[i2])) break;
238 if (c >= 'A' && c <= 'Z') c += 32;
239 if ((bufname[i++] = c) != ' ')
240 last = i;
242 if (!last)
243 continue;
245 if (last==name_len)
246 if ((!anycase && !memcmp(name, bufname, last)) ||
247 (anycase && !memicmp(name, bufname, last)))
248 goto Found;
249 if (long_slots) {
250 char longname[260]; /* 256 + 4 */
251 unsigned char long_len;
252 long_len = utf8
253 ?utf8_wcstombs(longname, (__u16 *) unicode, 260)
254 :uni16_to_x8(longname, unicode, uni_xlate, nls);
255 if (long_len != name_len)
256 continue;
257 if ((!anycase && !memcmp(name, longname, long_len)) ||
258 (anycase && !memicmp(name, longname, long_len)))
259 goto Found;
263 Found:
264 fat_brelse(sb, bh);
265 res = long_slots + 1;
266 *spos = cpos - sizeof(struct msdos_dir_entry);
267 *lpos = cpos - res*sizeof(struct msdos_dir_entry);
268 EODir:
269 if (unicode) {
270 free_page((unsigned long) unicode);
272 return res;
275 static int fat_readdirx(
276 struct inode *inode,
277 struct file *filp,
278 void *dirent,
279 filldir_t filldir,
280 int shortnames,
281 int both)
283 struct super_block *sb = inode->i_sb;
284 int ino,inum,i,i2,last;
285 char c;
286 struct buffer_head *bh;
287 struct msdos_dir_entry *de;
288 unsigned long lpos;
289 loff_t cpos;
290 unsigned char long_slots;
291 int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
292 int utf8 = MSDOS_SB(sb)->options.utf8;
293 unsigned char *unicode = NULL;
294 struct nls_table *nls = MSDOS_SB(sb)->nls_io;
295 char bufname[14];
296 char *ptname = bufname;
297 int dotoffset = 0;
298 unsigned long *furrfu = &lpos;
299 unsigned long dummy;
301 cpos = filp->f_pos;
302 /* Fake . and .. for the root directory. */
303 if (inode->i_ino == MSDOS_ROOT_INO) {
304 while (cpos < 2) {
305 if (filldir(dirent, "..", cpos+1, cpos, MSDOS_ROOT_INO) < 0)
306 return 0;
307 cpos++;
308 filp->f_pos++;
310 if (cpos == 2) {
311 dummy = 2;
312 furrfu = &dummy;
313 cpos = 0;
316 if (cpos & (sizeof(struct msdos_dir_entry)-1))
317 return -ENOENT;
319 bh = NULL;
320 GetNew:
321 long_slots = 0;
322 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
323 goto EODir;
324 /* Check for long filename entry */
325 if (MSDOS_SB(sb)->options.isvfat) {
326 if (de->name[0] == (__s8) DELETED_FLAG)
327 goto RecEnd;
328 if (de->attr != ATTR_EXT && (de->attr & ATTR_VOLUME))
329 goto RecEnd;
330 if (de->attr != ATTR_EXT && IS_FREE(de->name))
331 goto RecEnd;
332 } else {
333 if ((de->attr & ATTR_VOLUME) || IS_FREE(de->name))
334 goto RecEnd;
337 if (MSDOS_SB(sb)->options.isvfat && de->attr == ATTR_EXT) {
338 struct msdos_dir_slot *ds;
339 int offset;
340 unsigned char id;
341 unsigned char slot;
342 unsigned char slots;
343 unsigned char sum;
344 unsigned char alias_checksum;
346 if (!unicode) {
347 unicode = (unsigned char *)
348 __get_free_page(GFP_KERNEL);
349 if (!unicode) {
350 filp->f_pos = cpos;
351 fat_brelse(sb, bh);
352 return -ENOMEM;
355 ParseLong:
356 slots = 0;
357 offset = 0;
358 ds = (struct msdos_dir_slot *) de;
359 id = ds->id;
360 if (!(id & 0x40))
361 goto RecEnd;
362 slots = id & ~0x40;
363 if (slots > 20 || !slots) /* ceil(256 * 2 / 26) */
364 goto RecEnd;
365 long_slots = slots;
366 alias_checksum = ds->alias_checksum;
368 slot = slots;
369 while (1) {
370 slot--;
371 offset = slot * 26;
372 memcpy(&unicode[offset], ds->name0_4, 10);
373 memcpy(&unicode[offset+10], ds->name5_10, 12);
374 memcpy(&unicode[offset+22], ds->name11_12, 4);
375 offset += 26;
377 if (ds->id & 0x40) {
378 unicode[offset] = 0;
379 unicode[offset+1] = 0;
381 if (fat_get_entry(inode,&cpos,&bh,&de,&ino) == -1)
382 goto EODir;
383 if (slot == 0)
384 break;
385 ds = (struct msdos_dir_slot *) de;
386 if (ds->attr != ATTR_EXT)
387 goto RecEnd; /* XXX */
388 if ((ds->id & ~0x40) != slot)
389 goto ParseLong;
390 if (ds->alias_checksum != alias_checksum)
391 goto ParseLong;
393 if (de->name[0] == (__s8) DELETED_FLAG)
394 goto RecEnd;
395 if (de->attr == ATTR_EXT)
396 goto ParseLong;
397 if (IS_FREE(de->name) || (de->attr & ATTR_VOLUME))
398 goto RecEnd;
399 for (sum = 0, i = 0; i < 11; i++)
400 sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
401 if (sum != alias_checksum)
402 long_slots = 0;
405 if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
406 *ptname++ = '.';
407 dotoffset = 1;
409 for (i = 0, last = 0; i < 8;) {
410 if (!(c = de->name[i])) break;
411 if (c >= 'A' && c <= 'Z') c += 32;
412 /* see namei.c, msdos_format_name */
413 if (c == 0x05) c = 0xE5;
414 if ((ptname[i++] = c) != ' ')
415 last = i;
417 i = last;
418 ptname[i++] = '.';
419 for (i2 = 0; i2 < 3; i2++) {
420 if (!(c = de->ext[i2])) break;
421 if (c >= 'A' && c <= 'Z') c += 32;
422 if ((ptname[i++] = c) != ' ')
423 last = i;
425 if (!last)
426 goto RecEnd;
428 i = last + dotoffset;
430 lpos = cpos - (long_slots+1)*sizeof(struct msdos_dir_entry);
431 if (!memcmp(de->name,MSDOS_DOT,11))
432 inum = inode->i_ino;
433 else if (!memcmp(de->name,MSDOS_DOTDOT,11)) {
434 /* inum = fat_parent_ino(inode,0); */
435 inum = filp->f_dentry->d_parent->d_inode->i_ino;
436 } else {
437 struct inode *tmp = fat_iget(sb, ino);
438 if (tmp) {
439 inum = tmp->i_ino;
440 iput(tmp);
441 } else
442 inum = iunique(sb, MSDOS_ROOT_INO);
445 if (!long_slots||shortnames) {
446 if (both)
447 bufname[i] = '\0';
448 if (filldir(dirent, bufname, i, *furrfu, inum) < 0)
449 goto FillFailed;
450 } else {
451 char longname[275];
452 unsigned char long_len = utf8
453 ? utf8_wcstombs(longname, (__u16 *) unicode, 275)
454 : uni16_to_x8(longname, unicode, uni_xlate, nls);
455 if (both) {
456 memcpy(&longname[long_len+1], bufname, i);
457 long_len += i;
459 if (filldir(dirent, longname, long_len, *furrfu, inum) < 0)
460 goto FillFailed;
463 RecEnd:
464 furrfu = &lpos;
465 filp->f_pos = cpos;
466 goto GetNew;
467 EODir:
468 filp->f_pos = cpos;
469 FillFailed:
470 if (bh)
471 fat_brelse(sb, bh);
472 if (unicode) {
473 free_page((unsigned long) unicode);
475 return 0;
478 int fat_readdir(struct file *filp, void *dirent, filldir_t filldir)
480 struct inode *inode = filp->f_dentry->d_inode;
481 return fat_readdirx(inode, filp, dirent, filldir, 0, 0);
484 static int vfat_ioctl_fill(
485 void * buf,
486 const char * name,
487 int name_len,
488 off_t offset,
489 ino_t ino)
491 struct dirent *d1 = (struct dirent *)buf;
492 struct dirent *d2 = d1 + 1;
493 int len, slen;
494 int dotdir;
496 get_user(len, &d1->d_reclen);
497 if (len != 0) {
498 return -1;
501 if ((name_len == 1 && name[0] == '.') ||
502 (name_len == 2 && name[0] == '.' && name[1] == '.')) {
503 dotdir = 1;
504 len = name_len;
505 } else {
506 dotdir = 0;
507 len = strlen(name);
509 if (len != name_len) {
510 copy_to_user(d2->d_name, name, len);
511 put_user(0, d2->d_name + len);
512 put_user(len, &d2->d_reclen);
513 put_user(ino, &d2->d_ino);
514 put_user(offset, &d2->d_off);
515 slen = name_len - len;
516 copy_to_user(d1->d_name, name+len+1, slen);
517 put_user(0, d1->d_name+slen);
518 put_user(slen, &d1->d_reclen);
519 } else {
520 put_user(0, d2->d_name);
521 put_user(0, &d2->d_reclen);
522 copy_to_user(d1->d_name, name, len);
523 put_user(0, d1->d_name+len);
524 put_user(len, &d1->d_reclen);
526 PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
527 d1, d2, len, name_len));
529 return 0;
532 int fat_dir_ioctl(struct inode * inode, struct file * filp,
533 unsigned int cmd, unsigned long arg)
535 int err;
537 * We want to provide an interface for Samba to be able
538 * to get the short filename for a given long filename.
539 * Samba should use this ioctl instead of readdir() to
540 * get the information it needs.
542 switch (cmd) {
543 case VFAT_IOCTL_READDIR_BOTH: {
544 struct dirent *d1 = (struct dirent *)arg;
545 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
546 if (err)
547 return err;
548 put_user(0, &d1->d_reclen);
549 return fat_readdirx(inode,filp,(void *)arg,
550 vfat_ioctl_fill, 0, 1);
552 case VFAT_IOCTL_READDIR_SHORT: {
553 struct dirent *d1 = (struct dirent *)arg;
554 put_user(0, &d1->d_reclen);
555 err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
556 if (err)
557 return err;
558 return fat_readdirx(inode,filp,(void *)arg,
559 vfat_ioctl_fill, 1, 1);
561 default:
562 /* forward ioctl to CVF extension */
563 if (MSDOS_SB(inode->i_sb)->cvf_format &&
564 MSDOS_SB(inode->i_sb)->cvf_format->cvf_dir_ioctl)
565 return MSDOS_SB(inode->i_sb)->cvf_format
566 ->cvf_dir_ioctl(inode,filp,cmd,arg);
567 return -EINVAL;
570 return 0;
573 /***** See if directory is empty */
574 int fat_dir_empty(struct inode *dir)
576 loff_t pos;
577 struct buffer_head *bh;
578 struct msdos_dir_entry *de;
579 int ino,result = 0;
581 pos = 0;
582 bh = NULL;
583 while (fat_get_entry(dir,&pos,&bh,&de,&ino) > -1) {
584 /* Ignore vfat longname entries */
585 if (de->attr == ATTR_EXT)
586 continue;
587 if (!IS_FREE(de->name) &&
588 strncmp(de->name,MSDOS_DOT , MSDOS_NAME) &&
589 strncmp(de->name,MSDOS_DOTDOT, MSDOS_NAME)) {
590 result = -ENOTEMPTY;
591 break;
594 if (bh)
595 fat_brelse(dir->i_sb, bh);
597 return result;
600 /* This assumes that size of cluster is above the 32*slots */
602 int fat_add_entries(struct inode *dir,int slots, struct buffer_head **bh,
603 struct msdos_dir_entry **de, int *ino)
605 struct super_block *sb = dir->i_sb;
606 loff_t offset, curr;
607 int row;
608 struct buffer_head *new_bh;
610 offset = curr = 0;
611 *bh = NULL;
612 row = 0;
613 while (fat_get_entry(dir,&curr,bh,de,ino) > -1) {
614 if (IS_FREE((*de)->name)) {
615 if (++row == slots)
616 return offset;
617 } else {
618 row = 0;
619 offset = curr;
622 if ((dir->i_ino == MSDOS_ROOT_INO) && (MSDOS_SB(sb)->fat_bits != 32))
623 return -ENOSPC;
624 new_bh = fat_extend_dir(dir);
625 if (!new_bh)
626 return -ENOSPC;
627 fat_brelse(sb, new_bh);
628 do fat_get_entry(dir,&curr,bh,de,ino); while (++row<slots);
629 return offset;
632 int fat_new_dir(struct inode *dir, struct inode *parent, int is_vfat)
634 struct super_block *sb = dir->i_sb;
635 struct buffer_head *bh;
636 struct msdos_dir_entry *de;
637 __u16 date, time;
639 if ((bh = fat_extend_dir(dir)) == NULL) return -ENOSPC;
640 /* zeroed out, so... */
641 fat_date_unix2dos(dir->i_mtime,&time,&date);
642 de = (struct msdos_dir_entry*)&bh->b_data[0];
643 memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
644 memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
645 de[0].attr = de[1].attr = ATTR_DIR;
646 de[0].time = de[1].time = CT_LE_W(time);
647 de[0].date = de[1].date = CT_LE_W(date);
648 if (is_vfat) { /* extra timestamps */
649 de[0].ctime = de[1].ctime = CT_LE_W(time);
650 de[0].adate = de[0].cdate =
651 de[1].adate = de[1].cdate = CT_LE_W(date);
653 de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
654 de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
655 de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
656 de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
657 fat_mark_buffer_dirty(sb, bh, 1);
658 fat_brelse(sb, bh);
659 dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
660 mark_inode_dirty(dir);
662 return 0;
666 * Overrides for Emacs so that we follow Linus's tabbing style.
667 * Emacs will notice this stuff at the end of the file and automatically
668 * adjust the settings for this buffer only. This must remain at the end
669 * of the file.
670 * ---------------------------------------------------------------------------
671 * Local variables:
672 * c-indent-level: 8
673 * c-brace-imaginary-offset: 0
674 * c-brace-offset: -8
675 * c-argdecl-indent: 8
676 * c-label-offset: -8
677 * c-continued-statement-offset: 8
678 * c-continued-brace-offset: 0
679 * End: