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