Merge with Linux 2.4.0-test5-pre3.
[linux-2.6/linux-mips.git] / fs / vfat / namei.c
blob9c38896a305acd1570024d9f0195397bff6804d4
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.
12 * Short name translation 1999 by Wolfram Pienkoss <wp@bsz.shk.th.schule.de>
15 #define __NO_VERSION__
16 #include <linux/module.h>
18 #include <linux/sched.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/string.h>
24 #include <linux/ctype.h>
25 #include <linux/stat.h>
26 #include <linux/mm.h>
27 #include <linux/malloc.h>
29 #include "../fat/msbuffer.h"
31 #define DEBUG_LEVEL 0
32 #if (DEBUG_LEVEL >= 1)
33 # define PRINTK1(x) printk x
34 #else
35 # define PRINTK1(x)
36 #endif
37 #if (DEBUG_LEVEL >= 2)
38 # define PRINTK2(x) printk x
39 #else
40 # define PRINTK2(x)
41 #endif
42 #if (DEBUG_LEVEL >= 3)
43 # define PRINTK3(x) printk x
44 #else
45 # define PRINTK3(x)
46 #endif
48 #ifndef DEBUG
49 # define CHECK_STACK
50 #else
51 # define CHECK_STACK check_stack(__FILE__, __LINE__)
52 #endif
54 static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
55 static int vfat_hash(struct dentry *parent, struct qstr *qstr);
56 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
57 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
58 static int vfat_revalidate(struct dentry *dentry, int);
60 static struct dentry_operations vfat_dentry_ops[4] = {
62 d_hash: vfat_hashi,
63 d_compare: vfat_cmpi,
66 d_revalidate: vfat_revalidate,
67 d_hash: vfat_hashi,
68 d_compare: vfat_cmpi,
71 d_hash: vfat_hash,
72 d_compare: vfat_cmp,
75 d_revalidate: vfat_revalidate,
76 d_hash: vfat_hash,
77 d_compare: vfat_cmp,
81 static int vfat_revalidate(struct dentry *dentry, int flags)
83 PRINTK1(("vfat_revalidate: %s\n", dentry->d_name.name));
84 spin_lock(&dcache_lock);
85 if (dentry->d_time == dentry->d_parent->d_inode->i_version) {
86 spin_unlock(&dcache_lock);
87 return 1;
89 spin_unlock(&dcache_lock);
90 return 0;
93 static int simple_getbool(char *s, int *setval)
95 if (s) {
96 if (!strcmp(s,"1") || !strcmp(s,"yes") || !strcmp(s,"true")) {
97 *setval = 1;
98 } else if (!strcmp(s,"0") || !strcmp(s,"no") || !strcmp(s,"false")) {
99 *setval = 0;
100 } else {
101 return 0;
103 } else {
104 *setval = 1;
106 return 1;
109 static int parse_options(char *options, struct fat_mount_options *opts)
111 char *this_char,*value,save,*savep;
112 int ret, val;
114 opts->unicode_xlate = opts->posixfs = 0;
115 opts->numtail = 1;
116 opts->utf8 = 0;
118 if (!options) return 1;
119 save = 0;
120 savep = NULL;
121 ret = 1;
122 for (this_char = strtok(options,","); this_char; this_char = strtok(NULL,",")) {
123 if ((value = strchr(this_char,'=')) != NULL) {
124 save = *value;
125 savep = value;
126 *value++ = 0;
128 if (!strcmp(this_char,"utf8")) {
129 ret = simple_getbool(value, &val);
130 if (ret) opts->utf8 = val;
131 } else if (!strcmp(this_char,"uni_xlate")) {
132 ret = simple_getbool(value, &val);
133 if (ret) opts->unicode_xlate = val;
134 } else if (!strcmp(this_char,"posix")) {
135 ret = simple_getbool(value, &val);
136 if (ret) opts->posixfs = val;
137 } else if (!strcmp(this_char,"nonumtail")) {
138 ret = simple_getbool(value, &val);
139 if (ret) {
140 opts->numtail = !val;
143 if (this_char != options)
144 *(this_char-1) = ',';
145 if (value) {
146 *savep = save;
148 if (ret == 0) {
149 return 0;
152 if (opts->unicode_xlate) {
153 opts->utf8 = 0;
155 return 1;
158 static inline unsigned char
159 vfat_getlower(struct nls_table *t, unsigned char c)
161 return t->charset2lower[c];
164 static inline unsigned char
165 vfat_tolower(struct nls_table *t, unsigned char c)
167 unsigned char nc = t->charset2lower[c];
169 return nc ? nc : c;
172 static inline unsigned char
173 vfat_getupper(struct nls_table *t, unsigned char c)
175 return t->charset2upper[c];
178 static inline unsigned char
179 vfat_toupper(struct nls_table *t, unsigned char c)
181 unsigned char nc = t->charset2upper[c];
183 return nc ? nc : c;
186 static int
187 vfat_strnicmp(struct nls_table *t, const unsigned char *s1,
188 const unsigned char *s2, int len)
190 while(len--)
191 if (vfat_tolower(t, *s1++) != vfat_tolower(t, *s2++))
192 return 1;
194 return 0;
197 static inline int
198 vfat_uni2short(struct nls_table *t, wchar_t uc, unsigned char *op, int bound)
200 int charlen;
202 if ( (charlen = t->uni2char(uc, op, bound)) < 0)
203 charlen = 0;
205 return charlen;
208 static inline int
209 vfat_uni2upper_short(struct nls_table *t, wchar_t uc, char *op, int bound)
211 int chi, chl;
213 if ( (chl = t->uni2char(uc, op, bound)) < 0)
214 chl = 0;
216 for (chi = 0; chi < chl; chi++)
217 op[chi] = vfat_toupper(t, op[chi]);
219 return chl;
223 * Compute the hash for the vfat name corresponding to the dentry.
224 * Note: if the name is invalid, we leave the hash code unchanged so
225 * that the existing dentry can be used. The vfat fs routines will
226 * return ENOENT or EINVAL as appropriate.
228 static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
230 const char *name;
231 int len;
233 len = qstr->len;
234 name = qstr->name;
235 while (len && name[len-1] == '.')
236 len--;
238 qstr->hash = full_name_hash(name, len);
240 return 0;
244 * Compute the hash for the vfat name corresponding to the dentry.
245 * Note: if the name is invalid, we leave the hash code unchanged so
246 * that the existing dentry can be used. The vfat fs routines will
247 * return ENOENT or EINVAL as appropriate.
249 static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
251 struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
252 const char *name;
253 int len;
254 unsigned long hash;
256 len = qstr->len;
257 name = qstr->name;
258 while (len && name[len-1] == '.')
259 len--;
261 hash = init_name_hash();
262 while (len--)
263 hash = partial_name_hash(vfat_tolower(t, *name++), hash);
264 qstr->hash = end_name_hash(hash);
266 return 0;
270 * Case insensitive compare of two vfat names.
272 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
274 struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
275 int alen, blen;
277 /* A filename cannot end in '.' or we treat it like it has none */
278 alen = a->len;
279 blen = b->len;
280 while (alen && a->name[alen-1] == '.')
281 alen--;
282 while (blen && b->name[blen-1] == '.')
283 blen--;
284 if (alen == blen) {
285 if (vfat_strnicmp(t, a->name, b->name, alen) == 0)
286 return 0;
288 return 1;
292 * Case sensitive compare of two vfat names.
294 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
296 int alen, blen;
298 /* A filename cannot end in '.' or we treat it like it has none */
299 alen = a->len;
300 blen = b->len;
301 while (alen && a->name[alen-1] == '.')
302 alen--;
303 while (blen && b->name[blen-1] == '.')
304 blen--;
305 if (alen == blen) {
306 if (strncmp(a->name, b->name, alen) == 0)
307 return 0;
309 return 1;
312 #ifdef DEBUG
314 static void
315 check_stack(const char *fname, int lineno)
317 int stack_level;
318 char *pg_dir;
320 stack_level = (long)(&pg_dir)-current->kernel_stack_page;
321 if (stack_level < 0)
322 printk("*-*-*-* vfat kstack overflow in %s line %d: SL=%d\n",
323 fname, lineno, stack_level);
324 else if (stack_level < 500)
325 printk("*-*-*-* vfat kstack low in %s line %d: SL=%d\n",
326 fname, lineno, stack_level);
327 #if 0
328 else
329 printk("------- vfat kstack ok in %s line %d: SL=%d\n",
330 fname, lineno, stack_level);
331 #endif
332 #if 0
333 if (*(unsigned long *) current->kernel_stack_page != STACK_MAGIC) {
334 printk("******* vfat stack corruption detected in %s at line %d\n",
335 fname, lineno);
337 #endif
340 static int debug = 0;
341 static void dump_fat(struct super_block *sb,int start)
343 printk("[");
344 while (start) {
345 printk("%d ",start);
346 start = fat_access(sb,start,-1);
347 if (!start) {
348 printk("ERROR");
349 break;
351 if (start == -1) break;
353 printk("]\n");
356 static void dump_de(struct msdos_dir_entry *de)
358 int i;
359 unsigned char *p = (unsigned char *) de;
360 printk("[");
362 for (i = 0; i < 32; i++, p++) {
363 printk("%02x ", *p);
365 printk("]\n");
368 #endif
370 /* MS-DOS "device special files" */
372 static const char *reserved3_names[] = {
373 "con ", "prn ", "nul ", "aux ", NULL
376 static const char *reserved4_names[] = {
377 "com1 ", "com2 ", "com3 ", "com4 ", "com5 ",
378 "com6 ", "com7 ", "com8 ", "com9 ",
379 "lpt1 ", "lpt2 ", "lpt3 ", "lpt4 ", "lpt5 ",
380 "lpt6 ", "lpt7 ", "lpt8 ", "lpt9 ",
381 NULL };
384 /* Characters that are undesirable in an MS-DOS file name */
386 static char bad_chars[] = "*?<>|\":/\\";
387 static char replace_chars[] = "[];,+=";
389 /* Checks the validity of a long MS-DOS filename */
390 /* Returns negative number on error, 0 for a normal
391 * return, and 1 for . or .. */
393 static int vfat_valid_longname(const char *name, int len, int xlate)
395 const char **reserved, *walk;
396 unsigned char c;
397 int i, baselen;
399 if (len && name[len-1] == ' ') return -EINVAL;
400 if (len >= 256) return -EINVAL;
401 for (i = 0; i < len; i++) {
402 c = name[i];
403 if (xlate && c == ':') continue;
404 if (strchr(bad_chars,c)) {
405 return -EINVAL;
408 if (len < 3) return 0;
410 for (walk = name; *walk != 0 && *walk != '.'; walk++);
411 baselen = walk - name;
413 if (baselen == 3) {
414 for (reserved = reserved3_names; *reserved; reserved++) {
415 if (!strnicmp(name,*reserved,baselen))
416 return -EINVAL;
418 } else if (baselen == 4) {
419 for (reserved = reserved4_names; *reserved; reserved++) {
420 if (!strnicmp(name,*reserved,baselen))
421 return -EINVAL;
424 return 0;
427 static int vfat_valid_shortname(struct nls_table *nls, wchar_t *name, int len)
429 wchar_t *walk;
430 unsigned char c, charbuf[NLS_MAX_CHARSET_SIZE];
431 int chl, chi;
432 int space;
434 if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
435 return -EINVAL;
437 if (IS_FREE(charbuf))
438 return -EINVAL;
440 chl = 0;
441 c = 0;
442 space = 1; /* disallow names starting with a dot */
443 for (walk = name; len && walk-name < 8;) {
444 len--;
445 if ( (chl = nls->uni2char(*walk, charbuf, NLS_MAX_CHARSET_SIZE)) < 0) {
446 walk++;
447 return -EINVAL;
450 for (chi = 0; chi < chl; chi++) {
451 c = vfat_getupper(nls, charbuf[chi]);
452 if (!c) return -EINVAL;
453 if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
454 if (strchr(replace_chars,c)) return -EINVAL;
455 if (c < ' '|| c==':') return -EINVAL;
456 if (c == '.') break;
457 space = c == ' ';
460 if (space) return -EINVAL;
461 if (len && c != '.') {
462 len--;
463 if (vfat_uni2upper_short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE) == 1) {
464 if (charbuf[0] != '.') return -EINVAL;
465 } else
466 return -EINVAL;
468 if (c == '.') {
469 if (len >= 4) return -EINVAL;
470 while (len > 0) {
471 len--;
472 chl = vfat_uni2short(nls, *walk++, charbuf, NLS_MAX_CHARSET_SIZE);
473 if (chl < 0)
474 return -EINVAL;
475 for (chi = 0; chi < chl; chi++) {
476 c = vfat_getupper(nls, charbuf[chi]);
477 if (!c) return -EINVAL;
478 if (charbuf[chi] != vfat_tolower(nls, c)) return -EINVAL;
479 if (strchr(replace_chars,c))
480 return -EINVAL;
481 if (c < ' ' || c == '.'|| c==':')
482 return -EINVAL;
483 space = c == ' ';
486 if (space) return -EINVAL;
489 return 0;
492 static int vfat_find_form(struct inode *dir,char *name)
494 struct msdos_dir_entry *de;
495 struct buffer_head *bh = NULL;
496 int ino,res;
498 res=fat_scan(dir,name,&bh,&de,&ino);
499 fat_brelse(dir->i_sb, bh);
500 if (res<0)
501 return -ENOENT;
502 return 0;
505 static int vfat_format_name(struct nls_table *nls, wchar_t *name,
506 int len, char *res)
508 char *walk;
509 unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
510 int chi, chl;
511 int space;
513 if (vfat_uni2upper_short(nls, *name, charbuf, NLS_MAX_CHARSET_SIZE) == 0)
514 return -EINVAL;
516 if (IS_FREE(charbuf))
517 return -EINVAL;
519 space = 1; /* disallow names starting with a dot */
520 for (walk = res; len--; ) {
521 chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
522 if (chl == 0)
523 return -EINVAL;
524 for (chi = 0; chi < chl; chi++){
525 if (charbuf[chi] == '.') break;
526 if (!charbuf[chi]) return -EINVAL;
527 if (walk-res == 8) return -EINVAL;
528 if (strchr(replace_chars,charbuf[chi])) return -EINVAL;
529 if (charbuf[chi] < ' '|| charbuf[chi]==':') return -EINVAL;
530 space = charbuf[chi] == ' ';
531 *walk = charbuf[chi];
532 walk++;
535 if (space) return -EINVAL;
536 if (len >= 0) {
537 while (walk-res < 8) *walk++ = ' ';
538 while (len > 0 && walk-res < MSDOS_NAME) {
539 chl = vfat_uni2upper_short(nls, *name++, charbuf, NLS_MAX_CHARSET_SIZE);
540 if (len < chl)
541 chl = len;
542 len -= chl;
543 for (chi = 0; chi < chl; chi++){
544 if (!charbuf[chi]) return -EINVAL;
545 if (strchr(replace_chars,charbuf[chi]))
546 return -EINVAL;
547 if (charbuf[chi] < ' ' || charbuf[chi] == '.'|| charbuf[chi]==':')
548 return -EINVAL;
549 space = charbuf[chi] == ' ';
550 *walk++ = charbuf[chi];
553 if (space) return -EINVAL;
554 if (len) return -EINVAL;
556 while (walk-res < MSDOS_NAME) *walk++ = ' ';
558 return 0;
561 static char skip_chars[] = ".:\"?<>| ";
563 /* Given a valid longname, create a unique shortname. Make sure the
564 * shortname does not exist
566 static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
567 wchar_t *name, int len,
568 char *name_res)
570 wchar_t *ip, *op, *ext_start, *end, *name_start;
571 wchar_t msdos_name[13];
572 char base[9], ext[4], buf[8], *p;
573 unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
574 int chl, chi;
575 int sz, extlen, baselen, i;
577 PRINTK2(("Entering vfat_create_shortname\n"));
578 chl = 0;
579 sz = 0; /* Make compiler happy */
580 if (len <= 12) {
581 /* Do a case insensitive search if the name would be a valid
582 * shortname if is were all capitalized. However, do not
583 * allow spaces in short names because Win95 scandisk does
584 * not like that */
585 for (i = 0, op = &msdos_name[0], ip = name; ; i++, ip++, op++) {
586 if (i == len) {
587 if (vfat_format_name(nls, &msdos_name[0], len,
588 name_res) < 0)
589 break;
590 PRINTK3(("vfat_create_shortname 1\n"));
591 if (vfat_find_form(dir, name_res) < 0)
592 return 0;
593 return -EEXIST;
595 chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
596 for (chi = 0; chi < chl; chi++){
597 if (charbuf[chi] == ' ')
598 break;
600 if (chi < chl)
601 break;
603 *op = *ip;
607 PRINTK3(("vfat_create_shortname 3\n"));
608 /* Now, we need to create a shortname from the long name */
609 ext_start = end = &name[len];
610 while (--ext_start >= name) {
611 chl = vfat_uni2upper_short(nls, *ext_start, charbuf, NLS_MAX_CHARSET_SIZE);
612 for (chi = 0; chi < chl; chi++) {
613 if (charbuf[chi] == '.') {
614 if (ext_start == end - 1) {
615 sz = len;
616 ext_start = NULL;
618 break;
621 if (charbuf[chi] == '.')
622 break;
624 if (ext_start == name - 1) {
625 sz = len;
626 ext_start = NULL;
627 } else if (ext_start) {
629 * Names which start with a dot could be just
630 * an extension eg. "...test". In this case Win95
631 * uses the extension as the name and sets no extension.
633 name_start = &name[0];
634 while (name_start < ext_start)
636 chl = vfat_uni2upper_short(nls, *name_start, charbuf, NLS_MAX_CHARSET_SIZE);
637 if (chl == 0)
638 break;
639 for (chi = 0; chi < chl; chi++)
640 if (!strchr(skip_chars, charbuf[chi]))
641 break;
642 name_start++;
644 if (name_start != ext_start) {
645 sz = ext_start - name;
646 ext_start++;
647 } else {
648 sz = len;
649 ext_start=NULL;
653 for (baselen = i = 0, p = base, ip = name; i < sz && baselen < 8; i++, ip++)
655 chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
656 if (chl == 0){
657 *p++ = '_';
658 baselen++;
659 continue;
662 for (chi = 0; chi < chl; chi++){
663 if (!strchr(skip_chars, charbuf[chi])){
664 if (strchr(replace_chars, charbuf[chi]))
665 *p = '_';
666 else
667 *p = charbuf[chi];
668 p++; baselen++;
672 if (baselen == 0) {
673 return -EINVAL;
676 extlen = 0;
677 if (ext_start) {
678 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
679 chl = vfat_uni2upper_short(nls, *ip, charbuf, NLS_MAX_CHARSET_SIZE);
680 if (chl == 0) {
681 *p++ = '_';
682 extlen++;
683 continue;
686 for (chi = 0; chi < chl; chi++) {
687 if (!strchr(skip_chars, charbuf[chi])) {
688 if (strchr(replace_chars, charbuf[chi]))
689 *p = '_';
690 else
691 *p = charbuf[chi];
692 p++; extlen++;
697 ext[extlen] = '\0';
698 base[baselen] = '\0';
700 /* Yes, it can happen. ".\xe5" would do it. */
701 if (IS_FREE(base))
702 base[0]='_';
704 /* OK, at this point we know that base is not longer than 8 symbols,
705 * ext is not longer than 3, base is nonempty, both don't contain
706 * any bad symbols (lowercase transformed to uppercase).
709 memset(name_res, ' ', MSDOS_NAME);
710 memcpy(name_res,base,baselen);
711 memcpy(name_res+8,ext,extlen);
712 if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
713 if (vfat_find_form(dir, name_res) < 0)
714 return 0;
717 * Try to find a unique extension. This used to
718 * iterate through all possibilities sequentially,
719 * but that gave extremely bad performance. Windows
720 * only tries a few cases before using random
721 * values for part of the base.
724 if (baselen>6)
725 baselen = 6;
726 name_res[baselen] = '~';
727 for (i = 1; i < 10; i++) {
728 name_res[baselen+1] = i + '0';
729 if (vfat_find_form(dir, name_res) < 0)
730 return 0;
733 i = jiffies & 0xffff;
734 sz = (jiffies >> 16) & 0x7;
735 if (baselen>2)
736 baselen = 2;
737 name_res[baselen+4] = '~';
738 name_res[baselen+5] = '1' + sz;
739 while (1) {
740 sprintf(buf, "%04X", i);
741 memcpy(&name_res[baselen], buf, 4);
742 if (vfat_find_form(dir, name_res) < 0)
743 break;
744 i -= 11;
746 return 0;
749 /* Translate a string, including coded sequences into Unicode */
750 static int
751 xlate_to_uni(const char *name, int len, char *outname, int *longlen, int *outlen,
752 int escape, int utf8, struct nls_table *nls)
754 const unsigned char *ip;
755 unsigned char nc;
756 char *op;
757 unsigned int ec;
758 int i, k, fill;
759 int charlen;
761 if (utf8) {
762 *outlen = utf8_mbstowcs((__u16 *) outname, name, PAGE_SIZE);
763 if (name[len-1] == '.')
764 *outlen-=2;
765 op = &outname[*outlen * sizeof(__u16)];
766 } else {
767 if (name[len-1] == '.')
768 len--;
769 if (nls) {
770 for (i = 0, ip = name, op = outname, *outlen = 0;
771 i < len && *outlen <= 260; *outlen += 1)
773 if (escape && (*ip == ':')) {
774 if (i > len - 5)
775 return -EINVAL;
776 ec = 0;
777 for (k = 1; k < 5; k++) {
778 nc = ip[k];
779 ec <<= 4;
780 if (nc >= '0' && nc <= '9') {
781 ec |= nc - '0';
782 continue;
784 if (nc >= 'a' && nc <= 'f') {
785 ec |= nc - ('a' - 10);
786 continue;
788 if (nc >= 'A' && nc <= 'F') {
789 ec |= nc - ('A' - 10);
790 continue;
792 return -EINVAL;
794 *op++ = ec & 0xFF;
795 *op++ = ec >> 8;
796 ip += 5;
797 i += 5;
798 } else {
799 if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0)
800 return -EINVAL;
802 ip += charlen;
803 i += charlen;
804 op += 2;
807 } else {
808 for (i = 0, ip = name, op = outname, *outlen = 0;
809 i < len && *outlen <= 260; i++, *outlen += 1)
811 *op++ = *ip++;
812 *op++ = 0;
816 if (*outlen > 260)
817 return -ENAMETOOLONG;
819 *longlen = *outlen;
820 if (*outlen % 13) {
821 *op++ = 0;
822 *op++ = 0;
823 *outlen += 1;
824 if (*outlen % 13) {
825 fill = 13 - (*outlen % 13);
826 for (i = 0; i < fill; i++) {
827 *op++ = 0xff;
828 *op++ = 0xff;
830 *outlen += fill;
834 return 0;
837 static int
838 vfat_fill_slots(struct inode *dir, struct msdos_dir_slot *ds, const char *name,
839 int len, int *slots, int uni_xlate)
841 struct nls_table *nls_io, *nls_disk;
842 wchar_t *uname;
843 struct msdos_dir_slot *ps;
844 struct msdos_dir_entry *de;
845 unsigned long page;
846 unsigned char cksum;
847 const char *ip;
848 char *uniname, msdos_name[MSDOS_NAME];
849 int res, utf8, slot, ulen, unilen, i;
850 loff_t offset;
852 de = (struct msdos_dir_entry *) ds;
853 utf8 = MSDOS_SB(dir->i_sb)->options.utf8;
854 nls_io = MSDOS_SB(dir->i_sb)->nls_io;
855 nls_disk = MSDOS_SB(dir->i_sb)->nls_disk;
857 if (name[len-1] == '.') len--;
858 if(!(page = __get_free_page(GFP_KERNEL)))
859 return -ENOMEM;
860 uniname = (char *) page;
862 res = xlate_to_uni(name, len, uniname, &ulen, &unilen, uni_xlate,
863 utf8, nls_io);
864 if (res < 0)
865 goto out_free;
867 uname = (wchar_t *) page;
868 if (vfat_valid_shortname(nls_disk, uname, ulen) >= 0) {
869 res = vfat_format_name(nls_disk, uname, ulen, de->name);
870 if (!res)
871 goto out_free;
874 res = vfat_create_shortname(dir, nls_disk, uname, ulen, msdos_name);
875 if (res)
876 goto out_free;
878 *slots = unilen / 13;
879 for (cksum = i = 0; i < 11; i++) {
880 cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
882 PRINTK3(("vfat_fill_slots 3: slots=%d\n",*slots));
884 for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
885 ps->id = slot;
886 ps->attr = ATTR_EXT;
887 ps->reserved = 0;
888 ps->alias_checksum = cksum;
889 ps->start = 0;
890 offset = (slot - 1) * 26;
891 ip = &uniname[offset];
892 memcpy(ps->name0_4, ip, 10);
893 memcpy(ps->name5_10, ip+10, 12);
894 memcpy(ps->name11_12, ip+22, 4);
896 ds[0].id |= 0x40;
898 de = (struct msdos_dir_entry *) ps;
899 PRINTK3(("vfat_fill_slots 9\n"));
900 strncpy(de->name, msdos_name, MSDOS_NAME);
901 (*slots)++;
903 out_free:
904 free_page(page);
905 return res;
908 /* We can't get "." or ".." here - VFS takes care of those cases */
910 static int vfat_build_slots(struct inode *dir,const char *name,int len,
911 struct msdos_dir_slot *ds, int *slots)
913 int res, xlate;
915 xlate = MSDOS_SB(dir->i_sb)->options.unicode_xlate;
916 *slots = 1;
917 res = vfat_valid_longname(name, len, xlate);
918 if (res < 0)
919 return res;
920 return vfat_fill_slots(dir, ds, name, len, slots, xlate);
923 static int vfat_add_entry(struct inode *dir,struct qstr* qname,
924 int is_dir,struct vfat_slot_info *sinfo_out,
925 struct buffer_head **bh, struct msdos_dir_entry **de)
927 struct super_block *sb = dir->i_sb;
928 struct msdos_dir_slot *ps;
929 loff_t offset;
930 struct msdos_dir_slot *ds;
931 int slots, slot;
932 int res;
933 struct msdos_dir_entry *de1;
934 struct buffer_head *bh1;
935 int ino;
936 int len;
937 loff_t dummy;
939 ds = (struct msdos_dir_slot *)
940 kmalloc(sizeof(struct msdos_dir_slot)*MSDOS_SLOTS, GFP_KERNEL);
941 if (ds == NULL) return -ENOMEM;
943 len = qname->len;
944 while (len && qname->name[len-1] == '.')
945 len--;
946 res = fat_search_long(dir, qname->name, len,
947 (MSDOS_SB(sb)->options.name_check != 's') ||
948 !MSDOS_SB(sb)->options.posixfs,
949 &dummy, &dummy);
950 if (res > 0) /* found */
951 res = -EEXIST;
952 if (res)
953 goto cleanup;
955 res = vfat_build_slots(dir, qname->name, len, ds, &slots);
956 if (res < 0) goto cleanup;
958 offset = fat_add_entries(dir, slots, &bh1, &de1, &ino);
959 if (offset < 0) {
960 res = offset;
961 goto cleanup;
963 fat_brelse(sb, bh1);
965 /* Now create the new entry */
966 *bh = NULL;
967 for (slot = 0, ps = ds; slot < slots; slot++, ps++) {
968 if (fat_get_entry(dir,&offset,bh,de, &sinfo_out->ino) < 0) {
969 res = -EIO;
970 goto cleanup;
972 memcpy(*de, ps, sizeof(struct msdos_dir_slot));
973 fat_mark_buffer_dirty(sb, *bh, 1);
976 dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
977 mark_inode_dirty(dir);
979 fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
980 (*de)->ctime_ms = 0;
981 (*de)->ctime = (*de)->time;
982 (*de)->adate = (*de)->cdate = (*de)->date;
983 (*de)->start = 0;
984 (*de)->starthi = 0;
985 (*de)->size = 0;
986 (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
987 (*de)->lcase = CASE_LOWER_BASE | CASE_LOWER_EXT;
990 fat_mark_buffer_dirty(sb, *bh, 1);
992 /* slots can't be less than 1 */
993 sinfo_out->long_slots = slots - 1;
994 sinfo_out->longname_offset = offset - sizeof(struct msdos_dir_slot) * slots;
995 res = 0;
997 cleanup:
998 kfree(ds);
999 return res;
1002 static int vfat_find(struct inode *dir,struct qstr* qname,
1003 struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
1004 struct msdos_dir_entry **last_de)
1006 struct super_block *sb = dir->i_sb;
1007 loff_t offset;
1008 int res,len;
1010 len = qname->len;
1011 while (len && qname->name[len-1] == '.')
1012 len--;
1013 res = fat_search_long(dir, qname->name, len,
1014 (MSDOS_SB(sb)->options.name_check != 's'),
1015 &offset,&sinfo->longname_offset);
1016 if (res>0) {
1017 sinfo->long_slots = res-1;
1018 if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->ino)>=0)
1019 return 0;
1020 res = -EIO;
1022 return res ? res : -ENOENT;
1025 struct dentry *vfat_lookup(struct inode *dir,struct dentry *dentry)
1027 int res;
1028 struct vfat_slot_info sinfo;
1029 struct inode *inode;
1030 struct dentry *alias;
1031 struct buffer_head *bh = NULL;
1032 struct msdos_dir_entry *de;
1033 int table;
1035 PRINTK2(("vfat_lookup: name=%s, len=%d\n",
1036 dentry->d_name.name, dentry->d_name.len));
1038 table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
1039 dentry->d_op = &vfat_dentry_ops[table];
1041 inode = NULL;
1042 res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
1043 if (res < 0) {
1044 table++;
1045 goto error;
1047 inode = fat_build_inode(dir->i_sb, de, sinfo.ino, &res);
1048 fat_brelse(dir->i_sb, bh);
1049 if (res)
1050 return ERR_PTR(res);
1051 alias = d_find_alias(inode);
1052 if (alias) {
1053 if (d_invalidate(alias)==0)
1054 dput(alias);
1055 else {
1056 iput(inode);
1057 return alias;
1061 error:
1062 dentry->d_op = &vfat_dentry_ops[table];
1063 dentry->d_time = dentry->d_parent->d_inode->i_version;
1064 d_add(dentry,inode);
1065 return NULL;
1068 int vfat_create(struct inode *dir,struct dentry* dentry,int mode)
1070 struct super_block *sb = dir->i_sb;
1071 struct inode *inode = NULL;
1072 struct buffer_head *bh = NULL;
1073 struct msdos_dir_entry *de;
1074 struct vfat_slot_info sinfo;
1075 int res;
1077 res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
1078 if (res < 0)
1079 return res;
1080 inode = fat_build_inode(sb, de, sinfo.ino, &res);
1081 fat_brelse(sb, bh);
1082 if (!inode)
1083 return res;
1084 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
1085 mark_inode_dirty(inode);
1086 inode->i_version = ++event;
1087 dir->i_version = event;
1088 dentry->d_time = dentry->d_parent->d_inode->i_version;
1089 d_instantiate(dentry,inode);
1090 return 0;
1093 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
1094 struct buffer_head *bh, struct msdos_dir_entry *de)
1096 struct super_block *sb = dir->i_sb;
1097 loff_t offset;
1098 int i,ino;
1100 /* remove the shortname */
1101 dir->i_mtime = CURRENT_TIME;
1102 dir->i_atime = CURRENT_TIME;
1103 dir->i_version = ++event;
1104 mark_inode_dirty(dir);
1105 de->name[0] = DELETED_FLAG;
1106 fat_mark_buffer_dirty(sb, bh, 1);
1107 /* remove the longname */
1108 offset = sinfo->longname_offset; de = NULL;
1109 for (i = sinfo->long_slots; i > 0; --i) {
1110 if (fat_get_entry(dir, &offset, &bh, &de, &ino) < 0)
1111 continue;
1112 de->name[0] = DELETED_FLAG;
1113 de->attr = 0;
1114 fat_mark_buffer_dirty(sb, bh, 1);
1116 if (bh) fat_brelse(sb, bh);
1119 int vfat_rmdir(struct inode *dir,struct dentry* dentry)
1121 int res;
1122 struct vfat_slot_info sinfo;
1123 struct buffer_head *bh = NULL;
1124 struct msdos_dir_entry *de;
1126 res = fat_dir_empty(dentry->d_inode);
1127 if (res)
1128 return res;
1130 res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de);
1131 if (res<0)
1132 return res;
1133 dentry->d_inode->i_nlink = 0;
1134 dentry->d_inode->i_mtime = CURRENT_TIME;
1135 dentry->d_inode->i_atime = CURRENT_TIME;
1136 fat_detach(dentry->d_inode);
1137 mark_inode_dirty(dentry->d_inode);
1138 /* releases bh */
1139 vfat_remove_entry(dir,&sinfo,bh,de);
1140 dir->i_nlink--;
1141 return 0;
1144 int vfat_unlink(struct inode *dir, struct dentry* dentry)
1146 int res;
1147 struct vfat_slot_info sinfo;
1148 struct buffer_head *bh = NULL;
1149 struct msdos_dir_entry *de;
1151 PRINTK1(("vfat_unlink: %s\n", dentry->d_name.name));
1152 res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
1153 if (res < 0)
1154 return res;
1155 dentry->d_inode->i_nlink = 0;
1156 dentry->d_inode->i_mtime = CURRENT_TIME;
1157 dentry->d_inode->i_atime = CURRENT_TIME;
1158 fat_detach(dentry->d_inode);
1159 mark_inode_dirty(dentry->d_inode);
1160 /* releases bh */
1161 vfat_remove_entry(dir,&sinfo,bh,de);
1163 return res;
1167 int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
1169 struct super_block *sb = dir->i_sb;
1170 struct inode *inode = NULL;
1171 struct vfat_slot_info sinfo;
1172 struct buffer_head *bh = NULL;
1173 struct msdos_dir_entry *de;
1174 int res;
1176 res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
1177 if (res < 0)
1178 return res;
1179 inode = fat_build_inode(sb, de, sinfo.ino, &res);
1180 if (!inode)
1181 goto out;
1182 inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
1183 mark_inode_dirty(inode);
1184 inode->i_version = ++event;
1185 dir->i_version = event;
1186 dir->i_nlink++;
1187 inode->i_nlink = 2; /* no need to mark them dirty */
1188 res = fat_new_dir(inode, dir, 1);
1189 if (res < 0)
1190 goto mkdir_failed;
1191 dentry->d_time = dentry->d_parent->d_inode->i_version;
1192 d_instantiate(dentry,inode);
1193 out:
1194 fat_brelse(sb, bh);
1195 return res;
1197 mkdir_failed:
1198 inode->i_nlink = 0;
1199 inode->i_mtime = CURRENT_TIME;
1200 inode->i_atime = CURRENT_TIME;
1201 fat_detach(inode);
1202 mark_inode_dirty(inode);
1203 /* releases bh */
1204 vfat_remove_entry(dir,&sinfo,bh,de);
1205 iput(inode);
1206 dir->i_nlink--;
1207 return res;
1210 int vfat_rename(struct inode *old_dir,struct dentry *old_dentry,
1211 struct inode *new_dir,struct dentry *new_dentry)
1213 struct super_block *sb = old_dir->i_sb;
1214 struct buffer_head *old_bh,*new_bh,*dotdot_bh;
1215 struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
1216 int dotdot_ino;
1217 struct inode *old_inode, *new_inode;
1218 int res, is_dir;
1219 struct vfat_slot_info old_sinfo,sinfo;
1221 old_bh = new_bh = dotdot_bh = NULL;
1222 old_inode = old_dentry->d_inode;
1223 new_inode = new_dentry->d_inode;
1224 res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de);
1225 PRINTK3(("vfat_rename 2\n"));
1226 if (res < 0) goto rename_done;
1228 is_dir = S_ISDIR(old_inode->i_mode);
1230 if (is_dir && (res = fat_scan(old_inode,MSDOS_DOTDOT,&dotdot_bh,
1231 &dotdot_de,&dotdot_ino)) < 0)
1232 goto rename_done;
1234 if (new_dentry->d_inode) {
1235 res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
1236 &new_de);
1237 if (res < 0 || MSDOS_I(new_inode)->i_location != sinfo.ino) {
1238 /* WTF??? Cry and fail. */
1239 printk(KERN_WARNING "vfat_rename: fs corrupted\n");
1240 goto rename_done;
1243 if (is_dir) {
1244 res = fat_dir_empty(new_inode);
1245 if (res)
1246 goto rename_done;
1248 fat_detach(new_inode);
1249 } else {
1250 res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,
1251 &new_bh,&new_de);
1252 if (res < 0) goto rename_done;
1255 new_dir->i_version = ++event;
1257 /* releases old_bh */
1258 vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
1259 old_bh=NULL;
1260 fat_detach(old_inode);
1261 fat_attach(old_inode, sinfo.ino);
1262 mark_inode_dirty(old_inode);
1264 old_dir->i_version = ++event;
1265 old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
1266 mark_inode_dirty(old_dir);
1267 if (new_inode) {
1268 new_inode->i_nlink--;
1269 new_inode->i_ctime=CURRENT_TIME;
1272 if (is_dir) {
1273 int start = MSDOS_I(new_dir)->i_logstart;
1274 dotdot_de->start = CT_LE_W(start);
1275 dotdot_de->starthi = CT_LE_W(start>>16);
1276 fat_mark_buffer_dirty(sb, dotdot_bh, 1);
1277 old_dir->i_nlink--;
1278 if (new_inode) {
1279 new_inode->i_nlink--;
1280 } else {
1281 new_dir->i_nlink++;
1282 mark_inode_dirty(new_dir);
1286 rename_done:
1287 fat_brelse(sb, dotdot_bh);
1288 fat_brelse(sb, old_bh);
1289 fat_brelse(sb, new_bh);
1290 return res;
1295 /* Public inode operations for the VFAT fs */
1296 struct inode_operations vfat_dir_inode_operations = {
1297 create: vfat_create,
1298 lookup: vfat_lookup,
1299 unlink: vfat_unlink,
1300 mkdir: vfat_mkdir,
1301 rmdir: vfat_rmdir,
1302 rename: vfat_rename,
1303 setattr: fat_notify_change,
1306 struct super_block *vfat_read_super(struct super_block *sb,void *data,
1307 int silent)
1309 struct super_block *res;
1311 MSDOS_SB(sb)->options.isvfat = 1;
1313 res = fat_read_super(sb, data, silent, &vfat_dir_inode_operations);
1314 if (res == NULL)
1315 return NULL;
1317 if (parse_options((char *) data, &(MSDOS_SB(sb)->options))) {
1318 MSDOS_SB(sb)->options.dotsOK = 0;
1319 if (MSDOS_SB(sb)->options.posixfs) {
1320 MSDOS_SB(sb)->options.name_check = 's';
1322 if (MSDOS_SB(sb)->options.name_check != 's') {
1323 sb->s_root->d_op = &vfat_dentry_ops[0];
1324 } else {
1325 sb->s_root->d_op = &vfat_dentry_ops[2];
1329 return res;