OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [linux/] [linux-2.4/] [fs/] [vfat/] [namei.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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
 
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
 
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
 
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
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
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
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
 */
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
 */
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
 */
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
 */
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
 
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
 
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
 
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
 
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
 
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
 
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
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
 
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
 */
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
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
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
 
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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.