Import 2.3.7pre9
[davej-history.git] / fs / vfat / namei.c
blobd372ead155368c59e57ad05f605138c4202c39f0
1 /*
2 * linux/fs/vfat/namei.c
4 * Written 1992,1993 by Werner Almesberger
6 * Windows95/Windows NT compatible extended MSDOS filesystem
7 * by Gordon Chaffee Copyright (C) 1995. Send bug reports for the
8 * VFAT filesystem to <chaffee@cs.berkeley.edu>. Specify
9 * what file operation caused you trouble and if you can duplicate
10 * the problem, send a script that demonstrates it.
13 #define __NO_VERSION__
14 #include <linux/module.h>
16 #include <linux/sched.h>
17 #include <linux/msdos_fs.h>
18 #include <linux/nls.h>
19 #include <linux/kernel.h>
20 #include <linux/errno.h>
21 #include <linux/string.h>
22 #include <linux/ctype.h>
23 #include <linux/stat.h>
24 #include <linux/mm.h>
25 #include <linux/malloc.h>
27 #include "../fat/msbuffer.h"
29 #define DEBUG_LEVEL 0
30 #if (DEBUG_LEVEL >= 1)
31 # define PRINTK1(x) printk x
32 #else
33 # define PRINTK1(x)
34 #endif
35 #if (DEBUG_LEVEL >= 2)
36 # define PRINTK2(x) printk x
37 #else
38 # define PRINTK2(x)
39 #endif
40 #if (DEBUG_LEVEL >= 3)
41 # define PRINTK3(x) printk x
42 #else
43 # define PRINTK3(x)
44 #endif
46 #ifndef DEBUG
47 # define CHECK_STACK
48 #else
49 # define CHECK_STACK check_stack(__FILE__, __LINE__)
50 #endif
52 static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
53 static int vfat_hash(struct dentry *parent, struct qstr *qstr);
54 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
55 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
56 static int vfat_revalidate(struct dentry *dentry, int);
58 static struct dentry_operations vfat_dentry_ops[4] = {
60 NULL, /* d_revalidate */
61 vfat_hashi,
62 vfat_cmpi,
63 NULL /* d_delete */
66 vfat_revalidate,
67 vfat_hashi,
68 vfat_cmpi,
69 NULL /* d_delete */
72 NULL, /* d_revalidate */
73 vfat_hash,
74 vfat_cmp,
75 NULL /* d_delete */
78 vfat_revalidate,
79 vfat_hash,
80 vfat_cmp,
81 NULL /* d_delete */
85 static void vfat_put_super_callback(struct super_block *sb)
87 MOD_DEC_USE_COUNT;
90 static int vfat_revalidate(struct dentry *dentry, int flags)
92 PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
93 if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
94 return 1;
96 return 0;
99 static int simple_getbool(char *s, int *setval)
101 if (s) {
102 if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
103 *setval = 1;
104 } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
105 *setval = 0;
106 } else {
107 return 0;
109 } else {
110 *setval = 1;
112 return 1;
115 static int parse_options(char *options, struct fat_mount_options *opts)
117 char *this_char,*value,save,*savep;
118 int ret, val;
120 opts->unicode_xlate = opts->posixfs = 0;
121 opts->numtail = 1;
122 opts->utf8 = 0;
124 if (!options) return 1;
125 save = 0;
126 savep = NULL;
127 ret = 1;
128 for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
129 if ((value = strchr(this_char,'=')) != NULL) {
130 save = *value;
131 savep = value;
132 *value++ = 0;
134 if (!strcmp(this_char,"utf8")) {
135 ret = simple_getbool(value, &val);
136 if (ret) opts->utf8 = val;
137 } else if (!strcmp(this_char,"uni_xlate")) {
138 ret = simple_getbool(value, &val);
139 if (ret) opts->unicode_xlate = val;
140 } else if (!strcmp(this_char,"posix")) {
141 ret = simple_getbool(value, &val);
142 if (ret) opts->posixfs = val;
143 } else if (!strcmp(this_char,"nonumtail")) {
144 ret = simple_getbool(value, &val);
145 if (ret) {
146 opts->numtail = !val;
149 if (this_char != options)
150 *(this_char-1) = ',';
151 if (value) {
152 *savep = save;
154 if (ret == 0) {
155 return 0;
158 if (opts->unicode_xlate) {
159 opts->utf8 = 0;
161 return 1;
165 * Compute the hash for the vfat name corresponding to the dentry.
166 * Note: if the name is invalid, we leave the hash code unchanged so
167 * that the existing dentry can be used. The vfat fs routines will
168 * return ENOENT or EINVAL as appropriate.
170 static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
172 const char *name;
173 int len;
175 len = qstr->len;
176 name = qstr->name;
177 while (len && name[len-1] == '.')
178 len--;
180 qstr->hash = full_name_hash(name, len);
182 return 0;
186 * Compute the hash for the vfat name corresponding to the dentry.
187 * Note: if the name is invalid, we leave the hash code unchanged so
188 * that the existing dentry can be used. The vfat fs routines will
189 * return ENOENT or EINVAL as appropriate.
191 static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
193 const char *name;
194 int len;
195 char c;
196 unsigned long hash;
198 len = qstr->len;
199 name = qstr->name;
200 while (len && name[len-1] == '.')
201 len--;
203 hash = init_name_hash();
204 while (len--) {
205 c = tolower(*name++);
206 hash = partial_name_hash(tolower(c), hash);
208 qstr->hash = end_name_hash(hash);
210 return 0;
214 * Case insensitive compare of two vfat names.
216 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
218 int alen, blen;
220 /* A filename cannot end in '.' or we treat it like it has none */
221 alen = a->len;
222 blen = b->len;
223 while (alen && a->name[alen-1] == '.')
224 alen--;
225 while (blen && b->name[blen-1] == '.')
226 blen--;
227 if (alen == blen) {
228 if (strnicmp(a->name, b->name, alen) == 0)
229 return 0;
231 return 1;
235 * Case sensitive compare of two vfat names.
237 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
239 int alen, blen;
241 /* A filename cannot end in '.' or we treat it like it has none */
242 alen = a->len;
243 blen = b->len;
244 while (alen && a->name[alen-1] == '.')
245 alen--;
246 while (blen && b->name[blen-1] == '.')
247 blen--;
248 if (alen == blen) {
249 if (strncmp(a->name, b->name, alen) == 0)
250 return 0;
252 return 1;
255 #ifdef DEBUG
257 static void
258 check_stack(const char *fname, int lineno)
260 int stack_level;
261 char *pg_dir;
263 stack_level = (long)(&pg_dir)-current->kernel_stack_page;
264 if (stack_level < 0)
265 printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
266 fname, lineno, stack_level);
267 else if (stack_level < 500)
268 printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
269 fname, lineno, stack_level);
270 #if 0
271 else
272 printk("------- vfat kstack ok in %s line %d: SL=%d\n",
273 fname, lineno, stack_level);
274 #endif
275 #if 0
276 if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
277 printk("******* vfat stack corruption detected in %s at line %d\n",
278 fname, lineno);
280 #endif
283 static int debug = 0;
284 static void dump_fat(struct super_block *sb,int start)
286 printk("[");
287 while (start) {
288 printk("%d ",start);
289 start = fat_access(sb,start,-1);
290 if (!start) {
291 printk("ERROR");
292 break;
294 if (start == -1) break;
296 printk("]\n");
299 static void dump_de(struct msdos_dir_entry *de)
301 int i;
302 unsigned char *p = (unsigned char *) de;
303 printk("[");
305 for (i = 0; i < 32; i++, p++) {
306 printk("%02x ", *p);
308 printk("]\n");
311 #endif
313 /* MS-DOS "device special files" */
315 static const char *reserved3_names[] = {
316 "con ", "prn ", "nul ", "aux ", NULL
319 static const char *reserved4_names[] = {
320 "com1 ", "com2 ", "com3 ", "com4 ", "com5 ",
321 "com6 ", "com7 ", "com8 ", "com9 ",
322 "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ",
323 "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ",
324 NULL };
327 /* Characters that are undesirable in an MS-DOS file name */
329 static char bad_chars[] = "*?<>|\":/\\";
330 static char replace_chars[] = "[];,+=";
332 /* Checks the validity of a long MS-DOS filename */
333 /* Returns negative number on error, 0 for a normal
334 * return, and 1 for . or .. */
336 static int vfat_valid_longname(const char *name, int len, int xlate)
338 const char **reserved, *walk;
339 unsigned char c;
340 int i, baselen;
342 if (IS_FREE(name)) return -EINVAL;
344 if (len && name[len-1] == ' ') return -EINVAL;
345 if (len >= 256) return -EINVAL;
346 for (i = 0; i < len; i++) {
347 c = name[i];
348 if (xlate && c == ':') continue;
349 if (strchr(bad_chars,c)) {
350 return -EINVAL;
353 if (len < 3) return 0;
355 for (walk = name; *walk != 0 && *walk != '.'; walk++);
356 baselen = walk - name;
358 if (baselen == 3) {
359 for (reserved = reserved3_names; *reserved; reserved++) {
360 if (!strnicmp(name,*reserved,baselen))
361 return -EINVAL;
363 } else if (baselen == 4) {
364 for (reserved = reserved4_names; *reserved; reserved++) {
365 if (!strnicmp(name,*reserved,baselen))
366 return -EINVAL;
369 return 0;
372 static int vfat_valid_shortname(const char *name,int len,int utf8)
374 const char *walk;
375 unsigned char c;
376 int space;
377 int baselen;
379 space = 1; /* disallow names starting with a dot */
380 c = 0;
381 for (walk = name; len && walk-name < 8;) {
382 c = *walk++;
383 len--;
384 if (utf8 && (c & 0x80)) return -EINVAL;
385 if (strchr(replace_chars,c)) return -EINVAL;
386 if (c >= 'A' && c <= 'Z') return -EINVAL;
387 if (c < ' '|| c==':') return -EINVAL;
388 if (c == '.') break;
389 space = c == ' ';
391 if (space) return -EINVAL;
392 if (len && c != '.') {
393 c = *walk++;
394 len--;
395 if (c != '.') return -EINVAL;
397 baselen = walk - name;
398 if (c == '.') {
399 baselen--;
400 if (len >= 4) return -EINVAL;
401 while (len > 0) {
402 c = *walk++;
403 len--;
404 if (utf8 && (c & 0x80)) return -EINVAL;
405 if (strchr(replace_chars,c))
406 return -EINVAL;
407 if (c < ' ' || c == '.'|| c==':')
408 return -EINVAL;
409 if (c >= 'A' && c <= 'Z') return -EINVAL;
410 space = c == ' ';
412 if (space) return -EINVAL;
415 return 0;
418 static int vfat_find_form(struct inode *dir,char *name)
420 struct msdos_dir_entry *de;
421 struct buffer_head *bh = NULL;
422 int ino,res;
424 res=fat_scan(dir,name,&bh,&de,&ino);
425 fat_brelse(dir->i_sb, bh);
426 if (res<0)
427 return -ENOENT;
428 return 0;
431 static int vfat_format_name(const char *name,int len,char *res,int utf8)
433 char *walk;
434 unsigned char c;
435 int space;
437 space = 1; /* disallow names starting with a dot */
438 for (walk = res; len-- && (c=*name++)!='.' ; walk++) {
439 if (walk-res == 8) return -EINVAL;
440 if (utf8 && (c & 0x80)) return -EINVAL;
441 if (strchr(replace_chars,c)) return -EINVAL;
442 if (c >= 'A' && c <= 'Z') return -EINVAL;
443 if (c < ' '|| c==':') return -EINVAL;
444 space = c == ' ';
445 *walk = c >= 'a' && c <= 'z' ? c-32 : c;
447 if (space) return -EINVAL;
448 if (len >= 0) {
449 while (walk-res < 8) *walk++ = ' ';
450 while (len > 0 && walk-res < MSDOS_NAME) {
451 c = *name++;
452 len--;
453 if (utf8 && (c & 0x80)) return -EINVAL;
454 if (strchr(replace_chars,c))
455 return -EINVAL;
456 if (c < ' ' || c == '.'|| c==':')
457 return -EINVAL;
458 if (c >= 'A' && c <= 'Z') return -EINVAL;
459 space = c == ' ';
460 *walk++ = c >= 'a' && c <= 'z' ? c-32 : c;
462 if (space) return -EINVAL;
463 if (len) return -EINVAL;
465 while (walk-res < MSDOS_NAME) *walk++ = ' ';
467 return 0;
470 static char skip_chars[] = ".:\"?<>| ";
472 /* Given a valid longname, create a unique shortname. Make sure the
473 * shortname does not exist
475 static int vfat_create_shortname(struct inode *dir, const char *name,
476 int len, char *name_res, int utf8)
478 const char *ip, *ext_start, *end;
479 char *p;
480 int sz, extlen, baselen;
481 char msdos_name[13];
482 char base[9], ext[4];
483 int i;
484 char buf[8];
485 const char *name_start;
487 PRINTK2(("Entering vfat_create_shortname: name=%s, len=%d\n", name, len));
488 sz = 0; /* Make compiler happy */
489 if (len && name[len-1]==' ') return -EINVAL;
490 if (len <= 12) {
491 /* Do a case insensitive search if the name would be a valid
492 * shortname if is were all capitalized. However, do not
493 * allow spaces in short names because Win95 scandisk does
494 * not like that */
495 for (i = 0, p = msdos_name, ip = name; ; i++, p++, ip++) {
496 if (i == len) {
497 if (vfat_format_name(msdos_name,
498 len, name_res, utf8) < 0)
499 break;
500 PRINTK3(("vfat_create_shortname 1\n"));
501 if (vfat_find_form(dir, name_res) < 0)
502 return 0;
503 return -EEXIST;
506 if (*ip == ' ')
507 break;
508 if (*ip >= 'A' && *ip <= 'Z') {
509 *p = *ip + 32;
510 } else {
511 *p = *ip;
516 PRINTK3(("vfat_create_shortname 3\n"));
517 /* Now, we need to create a shortname from the long name */
518 ext_start = end = &name[len];
519 while (--ext_start >= name) {
520 if (*ext_start == '.') {
521 if (ext_start == end - 1) {
522 sz = len;
523 ext_start = NULL;
525 break;
528 if (ext_start == name - 1) {
529 sz = len;
530 ext_start = NULL;
531 } else if (ext_start) {
533 * Names which start with a dot could be just
534 * an extension eg. "...test". In this case Win95
535 * uses the extension as the name and sets no extension.
537 name_start = &name[0];
538 while (name_start < ext_start)
540 if (!strchr(skip_chars,*name_start)) break;
541 name_start++;
543 if (name_start != ext_start) {
544 sz = ext_start - name;
545 ext_start++;
546 } else {
547 sz = len;
548 ext_start=NULL;
552 for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++)
554 if (utf8 && (*ip & 0x80)) {
555 *p++ = '_';
556 baselen++;
557 } else if (!strchr(skip_chars, *ip)) {
558 if (*ip >= 'a' && *ip <= 'z') {
559 *p = *ip - 32;
560 } else {
561 *p = *ip;
563 if (strchr(replace_chars, *p)) *p='_';
564 p++; baselen++;
566 ip++;
568 if (baselen == 0) {
569 return -EINVAL;
572 extlen = 0;
573 if (ext_start) {
574 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
575 if (utf8 && (*ip & 0x80)) {
576 *p++ = '_';
577 extlen++;
578 } else if (!strchr(skip_chars, *ip)) {
579 if (*ip >= 'a' && *ip <= 'z') {
580 *p = *ip - 32;
581 } else {
582 *p = *ip;
584 if (strchr(replace_chars, *p)) *p='_';
585 extlen++;
586 p++;
590 ext[extlen] = '\0';
591 base[baselen] = '\0';
593 /* Yes, it can happen. ".\xe5" would do it. */
594 if (IS_FREE(base))
595 base[0]='_';
597 /* OK, at this point we know that base is not longer than 8 symbols,
598 * ext is not longer than 3, base is nonempty, both don't contain
599 * any bad symbols (lowercase transformed to uppercase).
602 memset(name_res, ' ', MSDOS_NAME);
603 memcpy(name_res,base,baselen);
604 memcpy(name_res+8,ext,extlen);
605 if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
606 if (vfat_find_form(dir, name_res) < 0)
607 return 0;
610 * Try to find a unique extension. This used to
611 * iterate through all possibilities sequentially,
612 * but that gave extremely bad performance. Windows
613 * only tries a few cases before using random
614 * values for part of the base.
617 if (baselen>6)
618 baselen = 6;
619 name_res[baselen] = '~';
620 for (i = 1; i < 10; i++) {
621 name_res[baselen+1] = i + '0';
622 if (vfat_find_form(dir, name_res) < 0)
623 return 0;
626 i = jiffies & 0xffff;
627 sz = (jiffies >> 16) & 0x7;
628 if (baselen>2)
629 baselen = 2;
630 name_res[baselen+4] = '~';
631 name_res[baselen+5] = '1' + sz;
632 while (1) {
633 sprintf(buf, "%04X", i);
634 memcpy(&name_res[baselen], buf, 4);
635 if (vfat_find_form(dir, name_res) < 0)
636 break;
637 i -= 11;
639 return 0;
642 /* Translate a string, including coded sequences into Unicode */
643 static int
644 xlate_to_uni(const char *name, int len, char *outname, int *outlen,
645 int escape, int utf8, struct nls_table *nls)
647 int i;
648 const unsigned char *ip;
649 char *op;
650 int fill;
651 unsigned char c1, c2, c3;
653 if (utf8) {
654 *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);
655 if (name[len-1] == '.')
656 *outlen-=2;
657 op = &outname[*outlen * sizeof(__u16)];
658 } else {
659 if (name[len-1] == '.')
660 len--;
661 op = outname;
662 if (nls) {
663 for (i = 0, ip = name, op = outname, *outlen = 0;
664 i < len && *outlen <= 260; i++, *outlen += 1)
666 if (escape && (*ip == ':')) {
667 if (i > len - 4) return -EINVAL;
668 c1 = fat_esc2uni[ip[1]];
669 c2 = fat_esc2uni[ip[2]];
670 c3 = fat_esc2uni[ip[3]];
671 if (c1 == 255 || c2 == 255 || c3 == 255)
672 return -EINVAL;
673 *op++ = (c1 << 4) + (c2 >> 2);
674 *op++ = ((c2 & 0x3) << 6) + c3;
675 ip += 4;
676 } else {
677 *op++ = nls->charset2uni[*ip].uni1;
678 *op++ = nls->charset2uni[*ip].uni2;
679 ip++;
682 } else {
683 for (i = 0, ip = name, op = outname, *outlen = 0;
684 i < len && *outlen <= 260; i++, *outlen += 1)
686 *op++ = *ip++;
687 *op++ = 0;
691 if (*outlen > 260)
692 return -ENAMETOOLONG;
694 if (*outlen % 13) {
695 *op++ = 0;
696 *op++ = 0;
697 *outlen += 1;
698 if (*outlen % 13) {
699 fill = 13 - (*outlen % 13);
700 for (i = 0; i < fill; i++) {
701 *op++ = 0xff;
702 *op++ = 0xff;
704 *outlen += fill;
708 return 0;
711 static int
712 vfat_fill_long_slots(struct msdos_dir_slot *ds, const char *name, int len,
713 char *msdos_name, int *slots,
714 int uni_xlate, int utf8, struct nls_table *nls)
716 struct msdos_dir_slot *ps;
717 struct msdos_dir_entry *de;
718 int res;
719 int slot;
720 unsigned char cksum;
721 char *uniname;
722 const char *ip;
723 unsigned long page;
724 int unilen;
725 int i;
726 loff_t offset;
728 if (name[len-1] == '.') len--;
729 if(!(page = __get_free_page(GFP_KERNEL)))
730 return -ENOMEM;
731 uniname = (char *) page;
732 res = xlate_to_uni(name, len, uniname, &unilen, uni_xlate, utf8, nls);
733 if (res < 0) {
734 free_page(page);
735 return res;
738 *slots = unilen / 13;
739 for (cksum = i = 0; i < 11; i++) {
740 cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
742 PRINTK3(("vfat_fill_long_slots 3: slots=%d\n",*slots));
744 for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
745 ps->id = slot;
746 ps->attr = ATTR_EXT;
747 ps->reserved = 0;
748 ps->alias_checksum = cksum;
749 ps->start = 0;
750 offset = (slot - 1) * 26;
751 ip = &uniname[offset];
752 memcpy(ps->name0_4, ip, 10);
753 memcpy(ps->name5_10, ip+10, 12);
754 memcpy(ps->name11_12, ip+22, 4);
756 ds[0].id |= 0x40;
758 de = (struct msdos_dir_entry *) ps;
759 PRINTK3(("vfat_fill_long_slots 9\n"));
760 strncpy(de->name, msdos_name, MSDOS_NAME);
761 (*slots)++;
763 free_page(page);
764 return 0;
767 /* We can't get "." or ".." here - VFS takes care of those cases */
769 static int vfat_build_slots(struct inode *dir,const char *name,int len,
770 struct msdos_dir_slot *ds, int *slots)
772 struct msdos_dir_entry *de;
773 char msdos_name[MSDOS_NAME];
774 int res, xlate, utf8;
775 struct nls_table *nls;
777 de = (struct msdos_dir_entry *) ds;
778 xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
779 utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
780 nls = MSDOS_SB(dir->i_sb)->nls_io;
782 *slots = 1;
783 res = vfat_valid_longname(name, len, xlate);
784 if (res < 0)
785 return res;
786 if (vfat_valid_shortname(name, len, utf8) >= 0) {
787 vfat_format_name(name, len, de->name, utf8);
788 return 0;
790 res = vfat_create_shortname(dir, name, len, msdos_name, utf8);
791 if (res < 0)
792 return res;
793 return vfat_fill_long_slots(ds, name, len, msdos_name, slots, xlate,
794 utf8, nls);
797 static int vfat_add_entry(struct inode *dir,struct qstr* qname,
798 int is_dir,struct vfat_slot_info *sinfo_out,
799 struct buffer_head **bh, struct msdos_dir_entry **de)
801 struct super_block *sb = dir->i_sb;
802 struct msdos_dir_slot *ps;
803 loff_t offset;
804 struct msdos_dir_slot *ds;
805 int slots, slot;
806 int res;
807 struct msdos_dir_entry *de1;
808 struct buffer_head *bh1;
809 int ino;
810 int len;
811 loff_t dummy;
813 ds = (struct msdos_dir_slot *)
814 kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
815 if (ds == NULL) return -ENOMEM;
817 len = qname->len;
818 while (len && qname->name[len-1] == '.')
819 len--;
820 res = fat_search_long(dir, qname->name, len,
821 (MSDOS_SB(sb)->options.name_check != 's') ||
822 !MSDOS_SB(sb)->options.posixfs,
823 &dummy, &dummy);
824 if (res > 0) /* found */
825 res = -EEXIST;
826 if (res)
827 goto cleanup;
829 res = vfat_build_slots(dir, qname->name, len, ds, &slots);
830 if (res < 0) goto cleanup;
832 offset = fat_add_entries(dir, slots, &bh1, &de1, &ino);
833 if (offset < 0) {
834 res = offset;
835 goto cleanup;
837 fat_brelse(sb, bh1);
839 /* Now create the new entry */
840 *bh = NULL;
841 for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
842 if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) {
843 res = -EIO;
844 goto cleanup;
846 memcpy(*de, ps, sizeof(struct msdos_dir_slot));
847 fat_mark_buffer_dirty(sb, *bh, 1);
850 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
851 mark_inode_dirty(dir);
853 fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
854 (*de)->ctime_ms = 0;
855 (*de)->ctime = (*de)->time;
856 (*de)->adate = (*de)->cdate = (*de)->date;
857 (*de)->start = 0;
858 (*de)->starthi = 0;
859 (*de)->size = 0;
860 (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
861 (*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
864 fat_mark_buffer_dirty(sb, *bh, 1);
866 /* slots can't be less than 1 */
867 sinfo_out->long_slots = slots - 1;
868 sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
869 res = 0;
871 cleanup:
872 kfree(ds);
873 return res;
876 static int vfat_find(struct inode *dir,struct qstr* qname,
877 struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
878 struct msdos_dir_entry **last_de)
880 struct super_block *sb = dir->i_sb;
881 loff_t offset;
882 int res,len;
884 len = qname->len;
885 while (len && qname->name[len-1] == '.')
886 len--;
887 res = fat_search_long(dir, qname->name, len,
888 (MSDOS_SB(sb)->options.name_check != 's'),
889 &offset,&sinfo->longname_offset);
890 if (res>0) {
891 sinfo->long_slots = res-1;
892 if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0)
893 return 0;
894 res = -EIO;
896 return res ? res : -ENOENT;
899 /* Find a hashed dentry for inode; NULL if there are none */
900 static struct dentry *find_alias(struct inode *inode)
902 struct list_head *head, *next, *tmp;
903 struct dentry *alias;
905 head = &inode->i_dentry;
906 next = inode->i_dentry.next;
907 while (next != head) {
908 tmp = next;
909 next = tmp->next;
910 alias = list_entry(tmp, struct dentry, d_alias);
911 if (!list_empty(&alias->d_hash))
912 return dget(alias);
914 return NULL;
917 struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
919 int res;
920 struct vfat_slot_info sinfo;
921 struct inode *inode;
922 struct dentry *alias;
923 struct buffer_head *bh = NULL;
924 struct msdos_dir_entry *de;
925 int table;
927 PRINTK2(("vfat_lookup: name=%s, len=%d\n",
928 dentry->d_name.name, dentry->d_name.len));
930 table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
931 dentry->d_op = &vfat_dentry_ops[table];
933 inode = NULL;
934 res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
935 if (res < 0) {
936 table++;
937 goto error;
939 inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res);
940 fat_brelse(dir->i_sb, bh);
941 if (res)
942 return ERR_PTR(res);
943 alias = find_alias(inode);
944 if (alias) {
945 if (d_invalidate(alias)==0)
946 dput(alias);
947 else {
948 iput(inode);
949 return alias;
953 error:
954 dentry->d_op = &vfat_dentry_ops[table];
955 dentry->d_time = dentry->d_parent->d_inode->i_version;
956 d_add(dentry,inode);
957 return NULL;
960 int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
962 struct super_block *sb = dir->i_sb;
963 struct inode *inode = NULL;
964 struct buffer_head *bh = NULL;
965 struct msdos_dir_entry *de;
966 struct vfat_slot_info sinfo;
967 int res;
969 res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
970 if (res < 0)
971 return res;
972 inode = fat_build_inode(sb, de, sinfo.ino, &res);
973 fat_brelse(sb, bh);
974 if (!inode)
975 return res;
976 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
977 mark_inode_dirty(inode);
978 inode->i_version = ++event;
979 dir->i_version = event;
980 dentry->d_time = dentry->d_parent->d_inode->i_version;
981 d_instantiate(dentry,inode);
982 return 0;
985 static int vfat_create_dotdirs(struct inode *dir, struct inode *parent)
987 struct super_block *sb = dir->i_sb;
988 struct buffer_head *bh;
989 struct msdos_dir_entry *de;
990 __u16 date, time;
992 if ((bh = fat_add_cluster1(dir)) == NULL) return -ENOSPC;
993 /* zeroed out, so... */
994 fat_date_unix2dos(dir->i_mtime,&time,&date);
995 de = (struct msdos_dir_entry*)&bh->b_data[0];
996 memcpy(de[0].name,MSDOS_DOT,MSDOS_NAME);
997 memcpy(de[1].name,MSDOS_DOTDOT,MSDOS_NAME);
998 de[0].attr = de[1].attr = ATTR_DIR;
999 de[0].ctime = de[0].time = de[1].ctime = de[1].time = CT_LE_W(time);
1000 de[0].adate = de[0].cdate = de[0].date = de[1].adate =
1001 de[1].cdate = de[1].date = CT_LE_W(date);
1002 de[0].start = CT_LE_W(MSDOS_I(dir)->i_logstart);
1003 de[0].starthi = CT_LE_W(MSDOS_I(dir)->i_logstart>>16);
1004 de[1].start = CT_LE_W(MSDOS_I(parent)->i_logstart);
1005 de[1].starthi = CT_LE_W(MSDOS_I(parent)->i_logstart>>16);
1006 fat_mark_buffer_dirty(sb, bh, 1);
1007 fat_brelse(sb, bh);
1008 dir->i_atime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
1009 mark_inode_dirty(dir);
1011 return 0;
1014 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
1015 struct buffer_head *bh, struct msdos_dir_entry *de)
1017 struct super_block *sb = dir->i_sb;
1018 loff_t offset;
1019 int i,ino;
1021 /* remove the shortname */
1022 dir->i_mtime = CURRENT_TIME;
1023 dir->i_atime = CURRENT_TIME;
1024 dir->i_version = ++event;
1025 mark_inode_dirty(dir);
1026 de->name[0] = DELETED_FLAG;
1027 fat_mark_buffer_dirty(sb, bh, 1);
1028 /* remove the longname */
1029 offset = sinfo->longname_offset; de = NULL;
1030 for (i = sinfo->long_slots; i > 0; --i) {
1031 if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0)
1032 continue;
1033 de->name[0] = DELETED_FLAG;
1034 de->attr = 0;
1035 fat_mark_buffer_dirty(sb, bh, 1);
1037 if (bh) fat_brelse(sb, bh);
1040 int vfat_rmdir(struct inode *dir,struct dentry* dentry)
1042 int res;
1043 struct vfat_slot_info sinfo;
1044 struct buffer_head *bh = NULL;
1045 struct msdos_dir_entry *de;
1047 if (!list_empty(&dentry->d_hash))
1048 return -EBUSY;
1050 res = fat_dir_empty(dentry->d_inode);
1051 if (res)
1052 return res;
1054 res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de);
1055 if (res<0)
1056 return res;
1057 dentry->d_inode->i_nlink = 0;
1058 dentry->d_inode->i_mtime = CURRENT_TIME;
1059 dentry->d_inode->i_atime = CURRENT_TIME;
1060 fat_detach(dentry->d_inode);
1061 mark_inode_dirty(dentry->d_inode);
1062 /* releases bh */
1063 vfat_remove_entry(dir,&sinfo,bh,de);
1064 dir->i_nlink--;
1065 return 0;
1068 int vfat_unlink(struct inode *dir, struct dentry* dentry)
1070 int res;
1071 struct vfat_slot_info sinfo;
1072 struct buffer_head *bh = NULL;
1073 struct msdos_dir_entry *de;
1075 PRINTK1(("vfat_unlink: %s\n", dentry->d_name.name));
1076 res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
1077 if (res < 0)
1078 return res;
1079 dentry->d_inode->i_nlink = 0;
1080 dentry->d_inode->i_mtime = CURRENT_TIME;
1081 dentry->d_inode->i_atime = CURRENT_TIME;
1082 fat_detach(dentry->d_inode);
1083 mark_inode_dirty(dentry->d_inode);
1084 /* releases bh */
1085 vfat_remove_entry(dir,&sinfo,bh,de);
1086 d_delete(dentry);
1088 return res;
1092 int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
1094 struct super_block *sb = dir->i_sb;
1095 struct inode *inode = NULL;
1096 struct vfat_slot_info sinfo;
1097 struct buffer_head *bh = NULL;
1098 struct msdos_dir_entry *de;
1099 int res;
1101 res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
1102 if (res < 0)
1103 return res;
1104 inode = fat_build_inode(sb, de, sinfo.ino, &res);
1105 if (!inode)
1106 goto out;
1107 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
1108 mark_inode_dirty(inode);
1109 inode->i_version = ++event;
1110 dir->i_version = event;
1111 dir->i_nlink++;
1112 inode->i_nlink = 2; /* no need to mark them dirty */
1114 res = vfat_create_dotdirs(inode, dir);
1115 if (res < 0)
1116 goto mkdir_failed;
1117 dentry->d_time = dentry->d_parent->d_inode->i_version;
1118 d_instantiate(dentry,inode);
1119 out:
1120 fat_brelse(sb, bh);
1121 return res;
1123 mkdir_failed:
1124 inode->i_nlink = 0;
1125 inode->i_mtime = CURRENT_TIME;
1126 inode->i_atime = CURRENT_TIME;
1127 fat_detach(inode);
1128 mark_inode_dirty(inode);
1129 /* releases bh */
1130 vfat_remove_entry(dir,&sinfo,bh,de);
1131 iput(inode);
1132 dir->i_nlink--;
1133 return res;
1136 int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
1137 struct inode *new_dir,struct dentry *new_dentry)
1139 struct super_block *sb = old_dir->i_sb;
1140 struct buffer_head *old_bh,*new_bh,*dotdot_bh;
1141 struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
1142 int dotdot_ino;
1143 struct inode *old_inode, *new_inode;
1144 int res, is_dir;
1145 struct vfat_slot_info old_sinfo,sinfo;
1147 old_bh = new_bh = dotdot_bh = NULL;
1148 old_inode = old_dentry->d_inode;
1149 new_inode = new_dentry->d_inode;
1150 res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de);
1151 PRINTK3(("vfat_rename 2\n"));
1152 if (res < 0) goto rename_done;
1154 is_dir = S_ISDIR(old_inode->i_mode);
1156 if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
1157 &dotdot_de,&dotdot_ino)) < 0)
1158 goto rename_done;
1160 if (new_dentry->d_inode) {
1161 res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
1162 &new_de);
1163 if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) {
1164 /* WTF??? Cry and fail. */
1165 printk(KERN_WARNING "vfat_rename: fs corrupted\n");
1166 goto rename_done;
1169 if (is_dir) {
1170 res = fat_dir_empty(new_inode);
1171 if (res)
1172 goto rename_done;
1174 fat_detach(new_inode);
1175 } else {
1176 res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,
1177 &new_bh,&new_de);
1178 if (res < 0) goto rename_done;
1181 new_dir->i_version = ++event;
1183 /* releases old_bh */
1184 vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
1185 old_bh=NULL;
1186 fat_detach(old_inode);
1187 fat_attach(old_inode, sinfo.ino);
1188 mark_inode_dirty(old_inode);
1190 old_dir->i_version = ++event;
1191 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
1192 mark_inode_dirty(old_dir);
1193 if (new_inode) {
1194 new_inode->i_nlink--;
1195 new_inode->i_ctime=CURRENT_TIME;
1198 if (is_dir) {
1199 int start = MSDOS_I(new_dir)->i_logstart;
1200 dotdot_de->start = CT_LE_W(start);
1201 dotdot_de->starthi = CT_LE_W(start>>16);
1202 fat_mark_buffer_dirty(sb, dotdot_bh, 1);
1203 old_dir->i_nlink--;
1204 if (new_inode) {
1205 new_inode->i_nlink--;
1206 } else {
1207 new_dir->i_nlink++;
1208 mark_inode_dirty(new_dir);
1212 rename_done:
1213 fat_brelse(sb, dotdot_bh);
1214 fat_brelse(sb, old_bh);
1215 fat_brelse(sb, new_bh);
1216 return res;
1221 /* Public inode operations for the VFAT fs */
1222 struct inode_operations vfat_dir_inode_operations = {
1223 &fat_dir_operations, /* default directory file-ops */
1224 vfat_create, /* create */
1225 vfat_lookup, /* lookup */
1226 NULL, /* link */
1227 vfat_unlink, /* unlink */
1228 NULL, /* symlink */
1229 vfat_mkdir, /* mkdir */
1230 vfat_rmdir, /* rmdir */
1231 NULL, /* mknod */
1232 vfat_rename, /* rename */
1233 NULL, /* readlink */
1234 NULL, /* followlink */
1235 NULL, /* readpage */
1236 NULL, /* writepage */
1237 NULL, /* bmap */
1238 NULL, /* truncate */
1239 NULL /* permission */
1242 struct super_block *vfat_read_super(struct super_block *sb,void *data,
1243 int silent)
1245 struct super_block *res;
1247 MOD_INC_USE_COUNT;
1249 MSDOS_SB(sb)->options.isvfat = 1;
1251 res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
1252 if (res == NULL) {
1253 sb->s_dev = 0;
1254 MOD_DEC_USE_COUNT;
1255 return NULL;
1258 if (!parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
1259 MOD_DEC_USE_COUNT;
1260 } else {
1261 MSDOS_SB(sb)->put_super_callback=vfat_put_super_callback;
1262 MSDOS_SB(sb)->options.dotsOK = 0;
1263 if (MSDOS_SB(sb)->options.posixfs) {
1264 MSDOS_SB(sb)->options.name_check = 's';
1266 if (MSDOS_SB(sb)->options.name_check != 's') {
1267 sb->s_root->d_op = &vfat_dentry_ops[0];
1268 } else {
1269 sb->s_root->d_op = &vfat_dentry_ops[2];
1273 return res;
1276 #ifdef MODULE
1277 int init_module(void)
1279 return init_vfat_fs();
1282 void cleanup_module(void)
1284 unregister_filesystem(&vfat_fs_type);
1287 #endif /* ifdef MODULE */