- patches.fixes/patch-2.6.11-rc1: 2.6.11-rc1.
[linux-flexiantxendom0-3.2.10.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_SEC;
739         mark_inode_dirty(dir);
740
741         fat_date_unix2dos(dir->i_mtime.tv_sec, &(*de)->time, &(*de)->date);
742         dir->i_mtime.tv_nsec = 0;
743         (*de)->ctime = (*de)->time;
744         (*de)->adate = (*de)->cdate = (*de)->date;
745
746         mark_buffer_dirty(*bh);
747
748         /* slots can't be less than 1 */
749         sinfo_out->long_slots = slots - 1;
750         sinfo_out->longname_offset =
751                 offset - sizeof(struct msdos_dir_slot) * slots;
752
753 cleanup:
754         kfree(dir_slots);
755         return res;
756 }
757
758 static int vfat_find(struct inode *dir,struct qstr* qname,
759         struct vfat_slot_info *sinfo, struct buffer_head **last_bh,
760         struct msdos_dir_entry **last_de)
761 {
762         struct super_block *sb = dir->i_sb;
763         loff_t offset;
764         unsigned int len;
765         int res;
766
767         len = vfat_striptail_len(qname);
768         if (len == 0)
769                 return -ENOENT;
770
771         res = fat_search_long(dir, qname->name, len,
772                               (MSDOS_SB(sb)->options.name_check != 's'),
773                               &offset, &sinfo->longname_offset);
774         if (res>0) {
775                 sinfo->long_slots = res-1;
776                 if (fat_get_entry(dir,&offset,last_bh,last_de,&sinfo->i_pos)>=0)
777                         return 0;
778                 res = -EIO;
779         } 
780         return res ? res : -ENOENT;
781 }
782
783 static struct dentry *vfat_lookup(struct inode *dir, struct dentry *dentry,
784                 struct nameidata *nd)
785 {
786         int res;
787         struct vfat_slot_info sinfo;
788         struct inode *inode;
789         struct dentry *alias;
790         struct buffer_head *bh = NULL;
791         struct msdos_dir_entry *de;
792         int table;
793         
794         lock_kernel();
795         table = (MSDOS_SB(dir->i_sb)->options.name_check == 's') ? 2 : 0;
796         dentry->d_op = &vfat_dentry_ops[table];
797
798         inode = NULL;
799         res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
800         if (res < 0) {
801                 table++;
802                 goto error;
803         }
804         inode = fat_build_inode(dir->i_sb, de, sinfo.i_pos, &res);
805         brelse(bh);
806         if (res) {
807                 unlock_kernel();
808                 return ERR_PTR(res);
809         }
810         alias = d_find_alias(inode);
811         if (alias) {
812                 if (d_invalidate(alias)==0)
813                         dput(alias);
814                 else {
815                         iput(inode);
816                         unlock_kernel();
817                         return alias;
818                 }
819                 
820         }
821 error:
822         unlock_kernel();
823         dentry->d_op = &vfat_dentry_ops[table];
824         dentry->d_time = dentry->d_parent->d_inode->i_version;
825         dentry = d_splice_alias(inode, dentry);
826         if (dentry) {
827                 dentry->d_op = &vfat_dentry_ops[table];
828                 dentry->d_time = dentry->d_parent->d_inode->i_version;
829         }
830         return dentry;
831 }
832
833 static int vfat_create(struct inode *dir, struct dentry* dentry, int mode,
834                 struct nameidata *nd)
835 {
836         struct super_block *sb = dir->i_sb;
837         struct inode *inode = NULL;
838         struct buffer_head *bh = NULL;
839         struct msdos_dir_entry *de;
840         struct vfat_slot_info sinfo;
841         int res;
842
843         lock_kernel();
844         res = vfat_add_entry(dir, &dentry->d_name, 0, &sinfo, &bh, &de);
845         if (res < 0)
846                 goto out;
847         inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
848         brelse(bh);
849         if (!inode)
850                 goto out;
851         res = 0;
852         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
853         mark_inode_dirty(inode);
854         inode->i_version++;
855         dir->i_version++;
856         dentry->d_time = dentry->d_parent->d_inode->i_version;
857         d_instantiate(dentry,inode);
858 out:
859         unlock_kernel();
860         return res;
861 }
862
863 static void vfat_remove_entry(struct inode *dir,struct vfat_slot_info *sinfo,
864      struct buffer_head *bh, struct msdos_dir_entry *de)
865 {
866         loff_t offset, i_pos;
867         int i;
868
869         /* remove the shortname */
870         dir->i_mtime = dir->i_atime = CURRENT_TIME_SEC;
871         dir->i_version++;
872         mark_inode_dirty(dir);
873         de->name[0] = DELETED_FLAG;
874         mark_buffer_dirty(bh);
875         /* remove the longname */
876         offset = sinfo->longname_offset; de = NULL;
877         for (i = sinfo->long_slots; i > 0; --i) {
878                 if (fat_get_entry(dir, &offset, &bh, &de, &i_pos) < 0)
879                         continue;
880                 de->name[0] = DELETED_FLAG;
881                 de->attr = ATTR_NONE;
882                 mark_buffer_dirty(bh);
883         }
884         brelse(bh);
885 }
886
887 static int vfat_rmdir(struct inode *dir, struct dentry* dentry)
888 {
889         int res;
890         struct vfat_slot_info sinfo;
891         struct buffer_head *bh = NULL;
892         struct msdos_dir_entry *de;
893
894         lock_kernel();
895         res = fat_dir_empty(dentry->d_inode);
896         if (res)
897                 goto out;
898
899         res = vfat_find(dir,&dentry->d_name,&sinfo, &bh, &de);
900         if (res < 0)
901                 goto out;
902         res = 0;
903         dentry->d_inode->i_nlink = 0;
904         dentry->d_inode->i_mtime = dentry->d_inode->i_atime = CURRENT_TIME_SEC;
905         fat_detach(dentry->d_inode);
906         mark_inode_dirty(dentry->d_inode);
907         /* releases bh */
908         vfat_remove_entry(dir,&sinfo,bh,de);
909         dir->i_nlink--;
910 out:
911         unlock_kernel();
912         return res;
913 }
914
915 static int vfat_unlink(struct inode *dir, struct dentry *dentry)
916 {
917         int res;
918         struct vfat_slot_info sinfo;
919         struct buffer_head *bh = NULL;
920         struct msdos_dir_entry *de;
921
922         lock_kernel();
923         res = vfat_find(dir,&dentry->d_name,&sinfo,&bh,&de);
924         if (res < 0)
925                 goto out;
926         dentry->d_inode->i_nlink = 0;
927         dentry->d_inode->i_mtime = dentry->d_inode->i_atime = CURRENT_TIME_SEC;
928         fat_detach(dentry->d_inode);
929         mark_inode_dirty(dentry->d_inode);
930         /* releases bh */
931         vfat_remove_entry(dir,&sinfo,bh,de);
932 out:
933         unlock_kernel();
934
935         return res;
936 }
937
938 static int vfat_mkdir(struct inode *dir,struct dentry* dentry,int mode)
939 {
940         struct super_block *sb = dir->i_sb;
941         struct inode *inode = NULL;
942         struct vfat_slot_info sinfo;
943         struct buffer_head *bh = NULL;
944         struct msdos_dir_entry *de;
945         int res;
946
947         lock_kernel();
948         res = vfat_add_entry(dir, &dentry->d_name, 1, &sinfo, &bh, &de);
949         if (res < 0)
950                 goto out;
951         inode = fat_build_inode(sb, de, sinfo.i_pos, &res);
952         if (!inode)
953                 goto out_brelse;
954         inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC;
955         mark_inode_dirty(inode);
956         inode->i_version++;
957         dir->i_version++;
958         dir->i_nlink++;
959         inode->i_nlink = 2; /* no need to mark them dirty */
960         res = fat_new_dir(inode, dir, 1);
961         if (res < 0)
962                 goto mkdir_failed;
963         dentry->d_time = dentry->d_parent->d_inode->i_version;
964         d_instantiate(dentry,inode);
965 out_brelse:
966         brelse(bh);
967 out:
968         unlock_kernel();
969         return res;
970
971 mkdir_failed:
972         inode->i_nlink = 0;
973         inode->i_mtime = inode->i_atime = CURRENT_TIME_SEC;
974         fat_detach(inode);
975         mark_inode_dirty(inode);
976         /* releases bh */
977         vfat_remove_entry(dir,&sinfo,bh,de);
978         iput(inode);
979         dir->i_nlink--;
980         goto out;
981 }
982  
983 static int vfat_rename(struct inode *old_dir, struct dentry *old_dentry,
984                 struct inode *new_dir, struct dentry *new_dentry)
985 {
986         struct buffer_head *old_bh,*new_bh,*dotdot_bh;
987         struct msdos_dir_entry *old_de,*new_de,*dotdot_de;
988         loff_t dotdot_i_pos;
989         struct inode *old_inode, *new_inode;
990         int res, is_dir;
991         struct vfat_slot_info old_sinfo,sinfo;
992
993         old_bh = new_bh = dotdot_bh = NULL;
994         old_inode = old_dentry->d_inode;
995         new_inode = new_dentry->d_inode;
996         lock_kernel();
997         res = vfat_find(old_dir,&old_dentry->d_name,&old_sinfo,&old_bh,&old_de);
998         if (res < 0)
999                 goto rename_done;
1000
1001         is_dir = S_ISDIR(old_inode->i_mode);
1002
1003         if (is_dir) {
1004                 if (fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
1005                              &dotdot_de, &dotdot_i_pos) < 0) {
1006                         res = -EIO;
1007                         goto rename_done;
1008                 }
1009         }
1010
1011         if (new_dentry->d_inode) {
1012                 res = vfat_find(new_dir,&new_dentry->d_name,&sinfo,&new_bh,
1013                                 &new_de);
1014                 if (res < 0 || MSDOS_I(new_inode)->i_pos != sinfo.i_pos) {
1015                         /* WTF??? Cry and fail. */
1016                         printk(KERN_WARNING "vfat_rename: fs corrupted\n");
1017                         goto rename_done;
1018                 }
1019
1020                 if (is_dir) {
1021                         res = fat_dir_empty(new_inode);
1022                         if (res)
1023                                 goto rename_done;
1024                 }
1025                 fat_detach(new_inode);
1026         } else {
1027                 res = vfat_add_entry(new_dir,&new_dentry->d_name,is_dir,&sinfo,
1028                                         &new_bh,&new_de);
1029                 if (res < 0) goto rename_done;
1030         }
1031
1032         new_dir->i_version++;
1033
1034         /* releases old_bh */
1035         vfat_remove_entry(old_dir,&old_sinfo,old_bh,old_de);
1036         old_bh=NULL;
1037         fat_detach(old_inode);
1038         fat_attach(old_inode, sinfo.i_pos);
1039         mark_inode_dirty(old_inode);
1040
1041         old_dir->i_version++;
1042         old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME_SEC;
1043         mark_inode_dirty(old_dir);
1044         if (new_inode) {
1045                 new_inode->i_nlink--;
1046                 new_inode->i_ctime = CURRENT_TIME_SEC;
1047         }
1048
1049         if (is_dir) {
1050                 int start = MSDOS_I(new_dir)->i_logstart;
1051                 dotdot_de->start = cpu_to_le16(start);
1052                 dotdot_de->starthi = cpu_to_le16(start>>16);
1053                 mark_buffer_dirty(dotdot_bh);
1054                 old_dir->i_nlink--;
1055                 if (new_inode) {
1056                         new_inode->i_nlink--;
1057                 } else {
1058                         new_dir->i_nlink++;
1059                         mark_inode_dirty(new_dir);
1060                 }
1061         }
1062
1063 rename_done:
1064         brelse(dotdot_bh);
1065         brelse(old_bh);
1066         brelse(new_bh);
1067         unlock_kernel();
1068         return res;
1069
1070 }
1071
1072 static struct inode_operations vfat_dir_inode_operations = {
1073         .create         = vfat_create,
1074         .lookup         = vfat_lookup,
1075         .unlink         = vfat_unlink,
1076         .mkdir          = vfat_mkdir,
1077         .rmdir          = vfat_rmdir,
1078         .rename         = vfat_rename,
1079         .setattr        = fat_notify_change,
1080 };
1081
1082 static int vfat_fill_super(struct super_block *sb, void *data, int silent)
1083 {
1084         int res;
1085
1086         res = fat_fill_super(sb, data, silent, &vfat_dir_inode_operations, 1);
1087         if (res)
1088                 return res;
1089
1090         if (MSDOS_SB(sb)->options.name_check != 's')
1091                 sb->s_root->d_op = &vfat_dentry_ops[0];
1092         else
1093                 sb->s_root->d_op = &vfat_dentry_ops[2];
1094
1095         return 0;
1096 }
1097
1098 static struct super_block *vfat_get_sb(struct file_system_type *fs_type,
1099         int flags, const char *dev_name, void *data)
1100 {
1101         return get_sb_bdev(fs_type, flags, dev_name, data, vfat_fill_super);
1102 }
1103
1104 static struct file_system_type vfat_fs_type = {
1105         .owner          = THIS_MODULE,
1106         .name           = "vfat",
1107         .get_sb         = vfat_get_sb,
1108         .kill_sb        = kill_block_super,
1109         .fs_flags       = FS_REQUIRES_DEV,
1110 };
1111
1112 static int __init init_vfat_fs(void)
1113 {
1114         return register_filesystem(&vfat_fs_type);
1115 }
1116
1117 static void __exit exit_vfat_fs(void)
1118 {
1119         unregister_filesystem(&vfat_fs_type);
1120 }
1121
1122 MODULE_LICENSE("GPL");
1123 MODULE_DESCRIPTION("VFAT filesystem support");
1124 MODULE_AUTHOR("Gordon Chaffee");
1125
1126 module_init(init_vfat_fs)
1127 module_exit(exit_vfat_fs)