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