vserver 1.9.3
[linux-2.6.git] / fs / vfat / namei.c
1 /*
2  *  linux/fs/vfat/namei.c
3  *
4  *  Written 1992,1993 by Werner Almesberger
5  *
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.
11  *
12  *  Short name translation 1999, 2001 by Wolfram Pienkoss <wp@bszh.de>
13  *
14  *  Support Multibyte character and cleanup by
15  *                              OGAWA Hirofumi <hirofumi@mail.parknet.co.jp>
16  */
17
18 #include <linux/module.h>
19
20 #include <linux/jiffies.h>
21 #include <linux/msdos_fs.h>
22 #include <linux/ctype.h>
23 #include <linux/slab.h>
24 #include <linux/smp_lock.h>
25 #include <linux/buffer_head.h>
26 #include <linux/namei.h>
27
28 static int vfat_hashi(struct dentry *parent, struct qstr *qstr);
29 static int vfat_hash(struct dentry *parent, struct qstr *qstr);
30 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b);
31 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b);
32 static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd);
33
34 static struct dentry_operations vfat_dentry_ops[4] = {
35         {
36                 .d_hash         = vfat_hashi,
37                 .d_compare      = vfat_cmpi,
38         },
39         {
40                 .d_revalidate   = vfat_revalidate,
41                 .d_hash         = vfat_hashi,
42                 .d_compare      = vfat_cmpi,
43         },
44         {
45                 .d_hash         = vfat_hash,
46                 .d_compare      = vfat_cmp,
47         },
48         {
49                 .d_revalidate   = vfat_revalidate,
50                 .d_hash         = vfat_hash,
51                 .d_compare      = vfat_cmp,
52         }
53 };
54
55 static int vfat_revalidate(struct dentry *dentry, struct nameidata *nd)
56 {
57         int ret = 1;
58
59         if (!dentry->d_inode &&
60             nd && !(nd->flags & LOOKUP_CONTINUE) && (nd->flags & LOOKUP_CREATE))
61                 /*
62                  * negative dentry is dropped, in order to make sure
63                  * to use the name which a user desires if this is
64                  * create path.
65                  */
66                 ret = 0;
67         else {
68                 spin_lock(&dentry->d_lock);
69                 if (dentry->d_time != dentry->d_parent->d_inode->i_version)
70                         ret = 0;
71                 spin_unlock(&dentry->d_lock);
72         }
73         return ret;
74 }
75
76 /* returns the length of a struct qstr, ignoring trailing dots */
77 static unsigned int vfat_striptail_len(struct qstr *qstr)
78 {
79         unsigned int len = qstr->len;
80
81         while (len && qstr->name[len-1] == '.')
82                 len--;
83
84         return len;
85 }
86
87 /*
88  * Compute the hash for the vfat name corresponding to the dentry.
89  * Note: if the name is invalid, we leave the hash code unchanged so
90  * that the existing dentry can be used. The vfat fs routines will
91  * return ENOENT or EINVAL as appropriate.
92  */
93 static int vfat_hash(struct dentry *dentry, struct qstr *qstr)
94 {
95         qstr->hash = full_name_hash(qstr->name, vfat_striptail_len(qstr));
96
97         return 0;
98 }
99
100 /*
101  * Compute the hash for the vfat name corresponding to the dentry.
102  * Note: if the name is invalid, we leave the hash code unchanged so
103  * that the existing dentry can be used. The vfat fs routines will
104  * return ENOENT or EINVAL as appropriate.
105  */
106 static int vfat_hashi(struct dentry *dentry, struct qstr *qstr)
107 {
108         struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
109         const unsigned char *name;
110         unsigned int len;
111         unsigned long hash;
112
113         name = qstr->name;
114         len = vfat_striptail_len(qstr);
115
116         hash = init_name_hash();
117         while (len--)
118                 hash = partial_name_hash(nls_tolower(t, *name++), hash);
119         qstr->hash = end_name_hash(hash);
120
121         return 0;
122 }
123
124 /*
125  * Case insensitive compare of two vfat names.
126  */
127 static int vfat_cmpi(struct dentry *dentry, struct qstr *a, struct qstr *b)
128 {
129         struct nls_table *t = MSDOS_SB(dentry->d_inode->i_sb)->nls_io;
130         unsigned int alen, blen;
131
132         /* A filename cannot end in '.' or we treat it like it has none */
133         alen = vfat_striptail_len(a);
134         blen = vfat_striptail_len(b);
135         if (alen == blen) {
136                 if (nls_strnicmp(t, a->name, b->name, alen) == 0)
137                         return 0;
138         }
139         return 1;
140 }
141
142 /*
143  * Case sensitive compare of two vfat names.
144  */
145 static int vfat_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
146 {
147         unsigned int alen, blen;
148
149         /* A filename cannot end in '.' or we treat it like it has none */
150         alen = vfat_striptail_len(a);
151         blen = vfat_striptail_len(b);
152         if (alen == blen) {
153                 if (strncmp(a->name, b->name, alen) == 0)
154                         return 0;
155         }
156         return 1;
157 }
158
159 /* Characters that are undesirable in an MS-DOS file name */
160
161 static wchar_t bad_chars[] = {
162         /*  `*'     `?'     `<'    `>'      `|'     `"'     `:'     `/' */
163         0x002A, 0x003F, 0x003C, 0x003E, 0x007C, 0x0022, 0x003A, 0x002F,
164         /*  `\' */
165         0x005C, 0,
166 };
167 #define IS_BADCHAR(uni) (vfat_unistrchr(bad_chars, (uni)) != NULL)
168
169 static wchar_t replace_chars[] = {
170         /*  `['     `]'    `;'     `,'     `+'      `=' */
171         0x005B, 0x005D, 0x003B, 0x002C, 0x002B, 0x003D, 0,
172 };
173 #define IS_REPLACECHAR(uni)     (vfat_unistrchr(replace_chars, (uni)) != NULL)
174
175 static wchar_t skip_chars[] = {
176         /*  `.'     ` ' */
177         0x002E, 0x0020, 0,
178 };
179 #define IS_SKIPCHAR(uni) \
180         ((wchar_t)(uni) == skip_chars[0] || (wchar_t)(uni) == skip_chars[1])
181
182 static inline wchar_t *vfat_unistrchr(const wchar_t *s, const wchar_t c)
183 {
184         for(; *s != c; ++s)
185                 if (*s == 0)
186                         return NULL;
187         return (wchar_t *) s;
188 }
189
190 static inline int vfat_is_used_badchars(const wchar_t *s, int len)
191 {
192         int i;
193         
194         for (i = 0; i < len; i++)
195                 if (s[i] < 0x0020 || IS_BADCHAR(s[i]))
196                         return -EINVAL;
197         return 0;
198 }
199
200 static int vfat_valid_longname(const unsigned char *name, unsigned int len)
201 {
202         if (len && name[len-1] == ' ')
203                 return 0;
204         if (len >= 256)
205                 return 0;
206
207         /* MS-DOS "device special files" */
208         if (len == 3 || (len > 3 && name[3] == '.')) {  /* basename == 3 */
209                 if (!strnicmp(name, "aux", 3) ||
210                     !strnicmp(name, "con", 3) ||
211                     !strnicmp(name, "nul", 3) ||
212                     !strnicmp(name, "prn", 3))
213                         return 0;
214         }
215         if (len == 4 || (len > 4 && name[4] == '.')) {  /* basename == 4 */
216                 /* "com1", "com2", ... */
217                 if ('1' <= name[3] && name[3] <= '9') {
218                         if (!strnicmp(name, "com", 3) ||
219                             !strnicmp(name, "lpt", 3))
220                                 return 0;
221                 }
222         }
223
224         return 1;
225 }
226
227 static int vfat_find_form(struct inode *dir, unsigned char *name)
228 {
229         struct msdos_dir_entry *de;
230         struct buffer_head *bh = NULL;
231         loff_t i_pos;
232         int res;
233
234         res = fat_scan(dir, name, &bh, &de, &i_pos);
235         brelse(bh);
236         if (res < 0)
237                 return -ENOENT;
238         return 0;
239 }
240
241 /* 
242  * 1) Valid characters for the 8.3 format alias are any combination of
243  * letters, uppercase alphabets, digits, any of the
244  * following special characters:
245  *     $ % ' ` - @ { } ~ ! # ( ) & _ ^
246  * In this case Longfilename is not stored in disk.
247  *
248  * WinNT's Extension:
249  * File name and extension name is contain uppercase/lowercase
250  * only. And it is expressed by CASE_LOWER_BASE and CASE_LOWER_EXT.
251  *     
252  * 2) File name is 8.3 format, but it contain the uppercase and
253  * lowercase char, muliti bytes char, etc. In this case numtail is not
254  * added, but Longfilename is stored.
255  * 
256  * 3) When the one except for the above, or the following special
257  * character are contained:
258  *        .   [ ] ; , + =
259  * numtail is added, and Longfilename must be stored in disk .
260  */
261 struct shortname_info {
262         unsigned char lower:1,
263                       upper:1,
264                       valid:1;
265 };
266 #define INIT_SHORTNAME_INFO(x)  do {            \
267         (x)->lower = 1;                         \
268         (x)->upper = 1;                         \
269         (x)->valid = 1;                         \
270 } while (0)
271
272 static inline unsigned char
273 shortname_info_to_lcase(struct shortname_info *base,
274                         struct shortname_info *ext)
275 {
276         unsigned char lcase = 0;
277
278         if (base->valid && ext->valid) {
279                 if (!base->upper && base->lower && (ext->lower || ext->upper))
280                         lcase |= CASE_LOWER_BASE;
281                 if (!ext->upper && ext->lower && (base->lower || base->upper))
282                         lcase |= CASE_LOWER_EXT;
283         }
284
285         return lcase;
286 }
287
288 static inline int to_shortname_char(struct nls_table *nls,
289                                     unsigned char *buf, int buf_size, wchar_t *src,
290                                     struct shortname_info *info)
291 {
292         int len;
293
294         if (IS_SKIPCHAR(*src)) {
295                 info->valid = 0;
296                 return 0;
297         }
298         if (IS_REPLACECHAR(*src)) {
299                 info->valid = 0;
300                 buf[0] = '_';
301                 return 1;
302         }
303         
304         len = nls->uni2char(*src, buf, buf_size);
305         if (len <= 0) {
306                 info->valid = 0;
307                 buf[0] = '_';
308                 len = 1;
309         } else if (len == 1) {
310                 unsigned char prev = buf[0];
311
312                 if (buf[0] >= 0x7F) {
313                         info->lower = 0;
314                         info->upper = 0;
315                 }
316
317                 buf[0] = nls_toupper(nls, buf[0]);
318                 if (isalpha(buf[0])) {
319                         if (buf[0] == prev)
320                                 info->lower = 0;
321                         else
322                                 info->upper = 0;
323                 }
324         } else {
325                 info->lower = 0;
326                 info->upper = 0;
327         }
328         
329         return len;
330 }
331
332 /*
333  * Given a valid longname, create a unique shortname.  Make sure the
334  * shortname does not exist
335  * Returns negative number on error, 0 for a normal
336  * return, and 1 for valid shortname
337  */
338 static int vfat_create_shortname(struct inode *dir, struct nls_table *nls,
339                                  wchar_t *uname, int ulen,
340                                  unsigned char *name_res, unsigned char *lcase)
341 {
342         wchar_t *ip, *ext_start, *end, *name_start;
343         unsigned char base[9], ext[4], buf[8], *p;
344         unsigned char charbuf[NLS_MAX_CHARSET_SIZE];
345         int chl, chi;
346         int sz = 0, extlen, baselen, i, numtail_baselen, numtail2_baselen;
347         int is_shortname;
348         struct shortname_info base_info, ext_info;
349         unsigned short opt_shortname = MSDOS_SB(dir->i_sb)->options.shortname;
350
351         is_shortname = 1;
352         INIT_SHORTNAME_INFO(&base_info);
353         INIT_SHORTNAME_INFO(&ext_info);
354
355         /* Now, we need to create a shortname from the long name */
356         ext_start = end = &uname[ulen];
357         while (--ext_start >= uname) {
358                 if (*ext_start == 0x002E) { /* is `.' */
359                         if (ext_start == end - 1) {
360                                 sz = ulen;
361                                 ext_start = NULL;
362                         }
363                         break;
364                 }
365         }
366
367         if (ext_start == uname - 1) {
368                 sz = ulen;
369                 ext_start = NULL;
370         } else if (ext_start) {
371                 /*
372                  * Names which start with a dot could be just
373                  * an extension eg. "...test".  In this case Win95
374                  * uses the extension as the name and sets no extension.
375                  */
376                 name_start = &uname[0];
377                 while (name_start < ext_start) {
378                         if (!IS_SKIPCHAR(*name_start))
379                                 break;
380                         name_start++;
381                 }
382                 if (name_start != ext_start) {
383                         sz = ext_start - uname;
384                         ext_start++;
385                 } else {
386                         sz = ulen;
387                         ext_start=NULL;
388                 }
389         }
390
391         numtail_baselen = 6;
392         numtail2_baselen = 2;
393         for (baselen = i = 0, p = base, ip = uname; i < sz; i++, ip++) {
394                 chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
395                                         ip, &base_info);
396                 if (chl == 0)
397                         continue;
398
399                 if (baselen < 2 && (baselen + chl) > 2)
400                         numtail2_baselen = baselen;
401                 if (baselen < 6 && (baselen + chl) > 6)
402                         numtail_baselen = baselen;
403                 for (chi = 0; chi < chl; chi++){
404                         *p++ = charbuf[chi];
405                         baselen++;
406                         if (baselen >= 8)
407                                 break;
408                 }
409                 if (baselen >= 8) {
410                         if ((chi < chl - 1) || (ip + 1) - uname < sz)
411                                 is_shortname = 0;
412                         break;
413                 }
414         }
415         if (baselen == 0) {
416                 return -EINVAL;
417         }
418
419         extlen = 0;
420         if (ext_start) {
421                 for (p = ext, ip = ext_start; extlen < 3 && ip < end; ip++) {
422                         chl = to_shortname_char(nls, charbuf, sizeof(charbuf),
423                                                 ip, &ext_info);
424                         if (chl == 0)
425                                 continue;
426
427                         if ((extlen + chl) > 3) {
428                                 is_shortname = 0;
429                                 break;
430                         }
431                         for (chi = 0; chi < chl; chi++) {
432                                 *p++ = charbuf[chi];
433                                 extlen++;
434                         }
435                         if (extlen >= 3) {
436                                 if (ip + 1 != end)
437                                         is_shortname = 0;
438                                 break;
439                         }
440                 }
441         }
442         ext[extlen] = '\0';
443         base[baselen] = '\0';
444
445         /* Yes, it can happen. ".\xe5" would do it. */
446         if (base[0] == DELETED_FLAG)
447                 base[0] = 0x05;
448
449         /* OK, at this point we know that base is not longer than 8 symbols,
450          * ext is not longer than 3, base is nonempty, both don't contain
451          * any bad symbols (lowercase transformed to uppercase).
452          */
453
454         memset(name_res, ' ', MSDOS_NAME);
455         memcpy(name_res, base, baselen);
456         memcpy(name_res + 8, ext, extlen);
457         *lcase = 0;
458         if (is_shortname && base_info.valid && ext_info.valid) {
459                 if (vfat_find_form(dir, name_res) == 0)
460                         return -EEXIST;
461
462                 if (opt_shortname & VFAT_SFN_CREATE_WIN95) {
463                         return (base_info.upper && ext_info.upper);
464                 } else if (opt_shortname & VFAT_SFN_CREATE_WINNT) {
465                         if ((base_info.upper || base_info.lower)
466                             && (ext_info.upper || ext_info.lower)) {
467                                 *lcase = shortname_info_to_lcase(&base_info,
468                                                                  &ext_info);
469                                 return 1;
470                         }
471                         return 0;
472                 } else {
473                         BUG();
474                 }
475         }
476         
477         if (MSDOS_SB(dir->i_sb)->options.numtail == 0)
478                 if (vfat_find_form(dir, name_res) < 0)
479                         return 0;
480
481         /*
482          * Try to find a unique extension.  This used to
483          * iterate through all possibilities sequentially,
484          * but that gave extremely bad performance.  Windows
485          * only tries a few cases before using random
486          * values for part of the base.
487          */
488
489         if (baselen>6) {
490                 baselen = numtail_baselen;
491                 name_res[7] = ' ';
492         }
493         name_res[baselen] = '~';
494         for (i = 1; i < 10; i++) {
495                 name_res[baselen+1] = i + '0';
496                 if (vfat_find_form(dir, name_res) < 0)
497                         return 0;
498         }
499
500         i = jiffies & 0xffff;
501         sz = (jiffies >> 16) & 0x7;
502         if (baselen>2) {
503                 baselen = numtail2_baselen;
504                 name_res[7] = ' ';
505         }
506         name_res[baselen+4] = '~';
507         name_res[baselen+5] = '1' + sz;
508         while (1) {
509                 sprintf(buf, "%04X", i);
510                 memcpy(&name_res[baselen], buf, 4);
511                 if (vfat_find_form(dir, name_res) < 0)
512                         break;
513                 i -= 11;
514         }
515         return 0;
516 }
517
518 /* Translate a string, including coded sequences into Unicode */
519 static int
520 xlate_to_uni(const unsigned char *name, int len, unsigned char *outname,
521              int *longlen, int *outlen, int escape, int utf8,
522              struct nls_table *nls)
523 {
524         const unsigned char *ip;
525         unsigned char nc;
526         unsigned char *op;
527         unsigned int ec;
528         int i, k, fill;
529         int charlen;
530
531         if (utf8) {
532                 int name_len = strlen(name);
533
534                 *outlen = utf8_mbstowcs((wchar_t *)outname, name, PAGE_SIZE);
535
536                 /*
537                  * We stripped '.'s before and set len appropriately,
538                  * but utf8_mbstowcs doesn't care about len
539                  */
540                 *outlen -= (name_len-len);
541
542                 op = &outname[*outlen * sizeof(wchar_t)];
543         } else {
544                 if (nls) {
545                         for (i = 0, ip = name, op = outname, *outlen = 0;
546                              i < len && *outlen <= 260; *outlen += 1)
547                         {
548                                 if (escape && (*ip == ':')) {
549                                         if (i > len - 5)
550                                                 return -EINVAL;
551                                         ec = 0;
552                                         for (k = 1; k < 5; k++) {
553                                                 nc = ip[k];
554                                                 ec <<= 4;
555                                                 if (nc >= '0' && nc <= '9') {
556                                                         ec |= nc - '0';
557                                                         continue;
558                                                 }
559                                                 if (nc >= 'a' && nc <= 'f') {
560                                                         ec |= nc - ('a' - 10);
561                                                         continue;
562                                                 }
563                                                 if (nc >= 'A' && nc <= 'F') {
564                                                         ec |= nc - ('A' - 10);
565                                                         continue;
566                                                 }
567                                                 return -EINVAL;
568                                         }
569                                         *op++ = ec & 0xFF;
570                                         *op++ = ec >> 8;
571                                         ip += 5;
572                                         i += 5;
573                                 } else {
574                                         if ((charlen = nls->char2uni(ip, len-i, (wchar_t *)op)) < 0)
575                                                 return -EINVAL;
576                                         ip += charlen;
577                                         i += charlen;
578                                         op += 2;
579                                 }
580                         }
581                 } else {
582                         for (i = 0, ip = name, op = outname, *outlen = 0;
583                              i < len && *outlen <= 260; i++, *outlen += 1)
584                         {
585                                 *op++ = *ip++;
586                                 *op++ = 0;
587                         }
588                 }
589         }
590         if (*outlen > 260)
591                 return -ENAMETOOLONG;
592
593         *longlen = *outlen;
594         if (*outlen % 13) {
595                 *op++ = 0;
596                 *op++ = 0;
597                 *outlen += 1;
598                 if (*outlen % 13) {
599                         fill = 13 - (*outlen % 13);
600                         for (i = 0; i < fill; i++) {
601                                 *op++ = 0xff;
602                                 *op++ = 0xff;
603                         }
604                         *outlen += fill;
605                 }
606         }
607
608         return 0;
609 }
610
611 static int vfat_build_slots(struct inode *dir, const unsigned char *name,
612                             int len, struct msdos_dir_slot *ds,
613                             int *slots, int is_dir)
614 {
615         struct msdos_sb_info *sbi = MSDOS_SB(dir->i_sb);
616         struct fat_mount_options *opts = &sbi->options;
617         struct msdos_dir_slot *ps;
618         struct msdos_dir_entry *de;
619         unsigned long page;
620         unsigned char cksum, lcase;
621         unsigned char msdos_name[MSDOS_NAME];
622         wchar_t *uname;
623         int res, slot, ulen, usize, i;
624         loff_t offset;
625
626         *slots = 0;
627         if (!vfat_valid_longname(name, len))
628                 return -EINVAL;
629
630         if(!(page = __get_free_page(GFP_KERNEL)))
631                 return -ENOMEM;
632
633         uname = (wchar_t *)page;
634         res = xlate_to_uni(name, len, (unsigned char *)uname, &ulen, &usize,
635                            opts->unicode_xlate, opts->utf8, sbi->nls_io);
636         if (res < 0)
637                 goto out_free;
638
639         res = vfat_is_used_badchars(uname, ulen);
640         if (res < 0)
641                 goto out_free;
642
643         res = vfat_create_shortname(dir, sbi->nls_disk, uname, ulen,
644                                     msdos_name, &lcase);
645         if (res < 0)
646                 goto out_free;
647         else if (res == 1) {
648                 de = (struct msdos_dir_entry *)ds;
649                 res = 0;
650                 goto shortname;
651         }
652
653         /* build the entry of long file name */
654         *slots = usize / 13;
655         for (cksum = i = 0; i < 11; i++) {
656                 cksum = (((cksum&1)<<7)|((cksum&0xfe)>>1)) + msdos_name[i];
657         }
658
659         for (ps = ds, slot = *slots; slot > 0; slot--, ps++) {
660                 ps->id = slot;
661                 ps->attr = ATTR_EXT;
662                 ps->reserved = 0;
663                 ps->alias_checksum = cksum;
664                 ps->start = 0;
665                 offset = (slot - 1) * 13;
666                 fatwchar_to16(ps->name0_4, uname + offset, 5);
667                 fatwchar_to16(ps->name5_10, uname + offset + 5, 6);
668                 fatwchar_to16(ps->name11_12, uname + offset + 11, 2);
669         }
670         ds[0].id |= 0x40;
671         de = (struct msdos_dir_entry *) ps;
672
673 shortname:
674         /* build the entry of 8.3 alias name */
675         (*slots)++;
676         memcpy(de->name, msdos_name, MSDOS_NAME);
677         de->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
678         de->lcase = lcase;
679         de->adate = de->cdate = de->date = 0;
680         de->ctime = de->time = 0;
681         de->ctime_ms = 0;
682         de->start = 0;
683         de->starthi = 0;
684         de->size = 0;
685
686 out_free:
687         free_page(page);
688         return res;
689 }
690
691 static int vfat_add_entry(struct inode *dir,struct qstr* qname,
692                           int is_dir, struct vfat_slot_info *sinfo_out,
693                           struct buffer_head **bh, struct msdos_dir_entry **de)
694 {
695         struct msdos_dir_slot *dir_slots;
696         loff_t offset;
697         int res, slots, slot;
698         unsigned int len;
699         struct msdos_dir_entry *dummy_de;
700         struct buffer_head *dummy_bh;
701         loff_t dummy_i_pos;
702
703         len = vfat_striptail_len(qname);
704         if (len == 0)
705                 return -ENOENT;
706
707         dir_slots =
708                kmalloc(sizeof(struct msdos_dir_slot) * MSDOS_SLOTS, GFP_KERNEL);
709         if (dir_slots == NULL)
710                 return -ENOMEM;
711
712         res = vfat_build_slots(dir, qname->name, len,
713                                dir_slots, &slots, is_dir);
714         if (res < 0)
715                 goto cleanup;
716
717         /* build the empty directory entry of number of slots */
718         offset = fat_add_entries(dir, slots, &dummy_bh, &dummy_de, &dummy_i_pos);
719         if (offset < 0) {
720                 res = offset;
721                 goto cleanup;
722         }
723         brelse(dummy_bh);
724
725         /* Now create the new entry */
726         *bh = NULL;
727         for (slot = 0; slot < slots; slot++) {
728                 if (fat_get_entry(dir, &offset, bh, de, &sinfo_out->i_pos) < 0) {
729                         res = -EIO;
730                         goto cleanup;
731                 }
732                 memcpy(*de, dir_slots + slot, sizeof(struct msdos_dir_slot));
733                 mark_buffer_dirty(*bh);
734         }
735
736         res = 0;
737         /* update timestamp */
738         dir->i_ctime = dir->i_mtime = dir->i_atime = CURRENT_TIME;
739         mark_inode_dirty(dir);
740
741         fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
742         (*de)->ctime = (*de)->time;
743         (*de)->adate = (*de)->cdate = (*de)->date;
744
745         mark_buffer_dirty(*bh);
746
747         /* slots can't be less than 1 */
748         sinfo_out->long_slots = slots - 1;
749         sinfo_out->longname_offset =
750                 offset - sizeof(struct msdos_dir_slot) * slots;
751
752 cleanup:
753         kfree(dir_slots);
754         return res;
755 }
756
757 static int vfat_find(struct inode *dir,struct qstr* qname,
758         struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
759         struct msdos_dir_entry **last_de)
760 {
761         struct super_block *sb = dir->i_sb;
762         loff_t offset;
763         unsigned int len;
764         int res;
765
766         len = vfat_striptail_len(qname);
767         if (len == 0)
768                 return -ENOENT;
769
770         res = fat_search_long(dir, qname->name, len,
771                               (MSDOS_SB(sb)->options.name_check != 's'),
772                               &offset, &sinfo->longname_offset);
773         if (res>0) {
774                 sinfo->long_slots = res-1;
775                 if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0)
776                         return 0;
777                 res = -EIO;
778         } 
779         return res ? res : -ENOENT;
780 }
781
782 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
783                 struct nameidata *nd)
784 {
785         int res;
786         struct vfat_slot_info sinfo;
787         struct inode *inode;
788         struct dentry *alias;
789         struct buffer_head *bh = NULL;
790         struct msdos_dir_entry *de;
791         int table;
792         
793         lock_kernel();
794         table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
795         dentry->d_op = &vfat_dentry_ops[table];
796
797         inode = NULL;
798         res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
799         if (res < 0) {
800                 table++;
801                 goto error;
802         }
803         inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
804         brelse(bh);
805         if (res) {
806                 unlock_kernel();
807                 return ERR_PTR(res);
808         }
809         alias = d_find_alias(inode);
810         if (alias) {
811                 if (d_invalidate(alias)==0)
812                         dput(alias);
813                 else {
814                         iput(inode);
815                         unlock_kernel();
816                         return alias;
817                 }
818                 
819         }
820 error:
821         unlock_kernel();
822         dentry->d_op = &vfat_dentry_ops[table];
823         dentry->d_time = dentry->d_parent->d_inode->i_version;
824         dentry = d_splice_alias(inode, dentry);
825         if (dentry) {
826                 dentry->d_op = &vfat_dentry_ops[table];
827                 dentry->d_time = dentry->d_parent->d_inode->i_version;
828         }
829         return dentry;
830 }
831
832 static int vfat_create(struct inode *dir, struct dentry* dentry, int mode,
833                 struct nameidata *nd)
834 {
835         struct super_block *sb = dir->i_sb;
836         struct inode *inode = NULL;
837         struct buffer_head *bh = NULL;
838         struct msdos_dir_entry *de;
839         struct vfat_slot_info sinfo;
840         int res;
841
842         lock_kernel();
843         res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
844         if (res < 0)
845                 goto out;
846         inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
847         brelse(bh);
848         if (!inode)
849                 goto out;
850         res = 0;
851         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
852         mark_inode_dirty(inode);
853         inode->i_version++;
854         dir->i_version++;
855         dentry->d_time = dentry->d_parent->d_inode->i_version;
856         d_instantiate(dentry,inode);
857 out:
858         unlock_kernel();
859         return res;
860 }
861
862 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
863      struct buffer_head *bh, struct msdos_dir_entry *de)
864 {
865         loff_t offset, i_pos;
866         int i;
867
868         /* remove the shortname */
869         dir->i_mtime = dir->i_atime = CURRENT_TIME;
870         dir->i_version++;
871         mark_inode_dirty(dir);
872         de->name[0] = DELETED_FLAG;
873         mark_buffer_dirty(bh);
874         /* remove the longname */
875         offset = sinfo->longname_offset; de = NULL;
876         for (i = sinfo->long_slots; i > 0; --i) {
877                 if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
878                         continue;
879                 de->name[0] = DELETED_FLAG;
880                 de->attr = ATTR_NONE;
881                 mark_buffer_dirty(bh);
882         }
883         brelse(bh);
884 }
885
886 static int vfat_rmdir(struct inode *dir, struct dentry* dentry)
887 {
888         int res;
889         struct vfat_slot_info sinfo;
890         struct buffer_head *bh = NULL;
891         struct msdos_dir_entry *de;
892
893         lock_kernel();
894         res = fat_dir_empty(dentry->d_inode);
895         if (res)
896                 goto out;
897
898         res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de);
899         if (res < 0)
900                 goto out;
901         res = 0;
902         dentry->d_inode->i_nlink = 0;
903         dentry->d_inode->i_mtime = dentry->d_inode->i_atime = CURRENT_TIME;
904         fat_detach(dentry->d_inode);
905         mark_inode_dirty(dentry->d_inode);
906         /* releases bh */
907         vfat_remove_entry(dir,&sinfo,bh,de);
908         dir->i_nlink--;
909 out:
910         unlock_kernel();
911         return res;
912 }
913
914 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
915 {
916         int res;
917         struct vfat_slot_info sinfo;
918         struct buffer_head *bh = NULL;
919         struct msdos_dir_entry *de;
920
921         lock_kernel();
922         res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
923         if (res < 0)
924                 goto out;
925         dentry->d_inode->i_nlink = 0;
926         dentry->d_inode->i_mtime = dentry->d_inode->i_atime = CURRENT_TIME;
927         fat_detach(dentry->d_inode);
928         mark_inode_dirty(dentry->d_inode);
929         /* releases bh */
930         vfat_remove_entry(dir,&sinfo,bh,de);
931 out:
932         unlock_kernel();
933
934         return res;
935 }
936
937 static int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
938 {
939         struct super_block *sb = dir->i_sb;
940         struct inode *inode = NULL;
941         struct vfat_slot_info sinfo;
942         struct buffer_head *bh = NULL;
943         struct msdos_dir_entry *de;
944         int res;
945
946         lock_kernel();
947         res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
948         if (res < 0)
949                 goto out;
950         inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
951         if (!inode)
952                 goto out_brelse;
953         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
954         mark_inode_dirty(inode);
955         inode->i_version++;
956         dir->i_version++;
957         dir->i_nlink++;
958         inode->i_nlink = 2; /* no need to mark them dirty */
959         res = fat_new_dir(inode, dir, 1);
960         if (res < 0)
961                 goto mkdir_failed;
962         dentry->d_time = dentry->d_parent->d_inode->i_version;
963         d_instantiate(dentry,inode);
964 out_brelse:
965         brelse(bh);
966 out:
967         unlock_kernel();
968         return res;
969
970 mkdir_failed:
971         inode->i_nlink = 0;
972         inode->i_mtime = inode->i_atime = CURRENT_TIME;
973         fat_detach(inode);
974         mark_inode_dirty(inode);
975         /* releases bh */
976         vfat_remove_entry(dir,&sinfo,bh,de);
977         iput(inode);
978         dir->i_nlink--;
979         goto out;
980 }
981  
982 static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
983                 struct inode *new_dir, struct dentry *new_dentry)
984 {
985         struct buffer_head *old_bh,*new_bh,*dotdot_bh;
986         struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
987         loff_t dotdot_i_pos;
988         struct inode *old_inode, *new_inode;
989         int res, is_dir;
990         struct vfat_slot_info old_sinfo,sinfo;
991
992         old_bh = new_bh = dotdot_bh = NULL;
993         old_inode = old_dentry->d_inode;
994         new_inode = new_dentry->d_inode;
995         lock_kernel();
996         res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de);
997         if (res < 0)
998                 goto rename_done;
999
1000         is_dir = S_ISDIR(old_inode->i_mode);
1001
1002         if (is_dir) {
1003                 if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
1004                              &dotdot_de, &dotdot_i_pos) < 0) {
1005                         res = -EIO;
1006                         goto rename_done;
1007                 }
1008         }
1009
1010         if (new_dentry->d_inode) {
1011                 res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
1012                                 &new_de);
1013                 if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
1014                         /* WTF??? Cry and fail. */
1015                         printk(KERN_WARNING "vfat_rename: fs corrupted\n");
1016                         goto rename_done;
1017                 }
1018
1019                 if (is_dir) {
1020                         res = fat_dir_empty(new_inode);
1021                         if (res)
1022                                 goto rename_done;
1023                 }
1024                 fat_detach(new_inode);
1025         } else {
1026                 res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,
1027                                         &new_bh,&new_de);
1028                 if (res < 0) goto rename_done;
1029         }
1030
1031         new_dir->i_version++;
1032
1033         /* releases old_bh */
1034         vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
1035         old_bh=NULL;
1036         fat_detach(old_inode);
1037         fat_attach(old_inode, sinfo.i_pos);
1038         mark_inode_dirty(old_inode);
1039
1040         old_dir->i_version++;
1041         old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
1042         mark_inode_dirty(old_dir);
1043         if (new_inode) {
1044                 new_inode->i_nlink--;
1045                 new_inode->i_ctime=CURRENT_TIME;
1046         }
1047
1048         if (is_dir) {
1049                 int start = MSDOS_I(new_dir)->i_logstart;
1050                 dotdot_de->start = cpu_to_le16(start);
1051                 dotdot_de->starthi = cpu_to_le16(start>>16);
1052                 mark_buffer_dirty(dotdot_bh);
1053                 old_dir->i_nlink--;
1054                 if (new_inode) {
1055                         new_inode->i_nlink--;
1056                 } else {
1057                         new_dir->i_nlink++;
1058                         mark_inode_dirty(new_dir);
1059                 }
1060         }
1061
1062 rename_done:
1063         brelse(dotdot_bh);
1064         brelse(old_bh);
1065         brelse(new_bh);
1066         unlock_kernel();
1067         return res;
1068
1069 }
1070
1071 static struct inode_operations vfat_dir_inode_operations = {
1072         .create         = vfat_create,
1073         .lookup         = vfat_lookup,
1074         .unlink         = vfat_unlink,
1075         .mkdir          = vfat_mkdir,
1076         .rmdir          = vfat_rmdir,
1077         .rename         = vfat_rename,
1078         .setattr        = fat_notify_change,
1079 };
1080
1081 static int vfat_fill_super(struct super_block *sb, void *data, int silent)
1082 {
1083         int res;
1084
1085         res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
1086         if (res)
1087                 return res;
1088
1089         if (MSDOS_SB(sb)->options.name_check != 's')
1090                 sb->s_root->d_op = &vfat_dentry_ops[0];
1091         else
1092                 sb->s_root->d_op = &vfat_dentry_ops[2];
1093
1094         return 0;
1095 }
1096
1097 static struct super_block *vfat_get_sb(struct file_system_type *fs_type,
1098         int flags, const char *dev_name, void *data)
1099 {
1100         return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
1101 }
1102
1103 static struct file_system_type vfat_fs_type = {
1104         .owner          = THIS_MODULE,
1105         .name           = "vfat",
1106         .get_sb         = vfat_get_sb,
1107         .kill_sb        = kill_block_super,
1108         .fs_flags       = FS_REQUIRES_DEV,
1109 };
1110
1111 static int __init init_vfat_fs(void)
1112 {
1113         return register_filesystem(&vfat_fs_type);
1114 }
1115
1116 static void __exit exit_vfat_fs(void)
1117 {
1118         unregister_filesystem(&vfat_fs_type);
1119 }
1120
1121 MODULE_LICENSE("GPL");
1122 MODULE_DESCRIPTION("VFAT filesystem support");
1123 MODULE_AUTHOR("Gordon Chaffee");
1124
1125 module_init(init_vfat_fs)
1126 module_exit(exit_vfat_fs)