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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/msdos/namei.c
3
 *
4
 *  Written 1992,1993 by Werner Almesberger
5
 *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
6
 *  Rewritten for constant inumbers 1999 by Al Viro
7
 */
8
 
9
 
10
#define __NO_VERSION__
11
#include <linux/module.h>
12
 
13
#include <linux/sched.h>
14
#include <linux/msdos_fs.h>
15
#include <linux/errno.h>
16
#include <linux/string.h>
17
 
18
#include <asm/uaccess.h>
19
 
20
#define MSDOS_DEBUG 0
21
#define PRINTK(x)
22
 
23
/* MS-DOS "device special files" */
24
 
25
static const char *reserved_names[] = {
26
    "CON     ","PRN     ","NUL     ","AUX     ",
27
    "LPT1    ","LPT2    ","LPT3    ","LPT4    ",
28
    "COM1    ","COM2    ","COM3    ","COM4    ",
29
    NULL };
30
 
31
 
32
/* Characters that are undesirable in an MS-DOS file name */
33
 
34
static char bad_chars[] = "*?<>|\"";
35
static char bad_if_strict_pc[] = "+=,; ";
36
static char bad_if_strict_atari[] = " "; /* GEMDOS is less restrictive */
37
#define bad_if_strict(opts) ((opts)->atari ? bad_if_strict_atari : bad_if_strict_pc)
38
 
39
/* Must die */
40
void msdos_put_super(struct super_block *sb)
41
{
42
        fat_put_super(sb);
43
}
44
 
45
/***** Formats an MS-DOS file name. Rejects invalid names. */
46
static int msdos_format_name(const char *name,int len,
47
        char *res,struct fat_mount_options *opts)
48
        /* name is the proposed name, len is its length, res is
49
         * the resulting name, opts->name_check is either (r)elaxed,
50
         * (n)ormal or (s)trict, opts->dotsOK allows dots at the
51
         * beginning of name (for hidden files)
52
         */
53
{
54
        char *walk;
55
        const char **reserved;
56
        unsigned char c;
57
        int space;
58
 
59
        if (name[0] == '.') {  /* dotfile because . and .. already done */
60
                if (opts->dotsOK) {
61
                        /* Get rid of dot - test for it elsewhere */
62
                        name++; len--;
63
                }
64
                else if (!opts->atari) return -EINVAL;
65
        }
66
        /* disallow names that _really_ start with a dot for MS-DOS, GEMDOS does
67
         * not care */
68
        space = !opts->atari;
69
        c = 0;
70
        for (walk = res; len && walk-res < 8; walk++) {
71
                c = *name++;
72
                len--;
73
                if (opts->name_check != 'r' && strchr(bad_chars,c))
74
                        return -EINVAL;
75
                if (opts->name_check == 's' && strchr(bad_if_strict(opts),c))
76
                        return -EINVAL;
77
                if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
78
                        return -EINVAL;
79
                if (c < ' ' || c == ':' || c == '\\') return -EINVAL;
80
/*  0xE5 is legal as a first character, but we must substitute 0x05     */
81
/*  because 0xE5 marks deleted files.  Yes, DOS really does this.       */
82
/*  It seems that Microsoft hacked DOS to support non-US characters     */
83
/*  after the 0xE5 character was already in use to mark deleted files.  */
84
                if((res==walk) && (c==0xE5)) c=0x05;
85
                if (c == '.') break;
86
                space = (c == ' ');
87
                *walk = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
88
        }
89
        if (space) return -EINVAL;
90
        if (opts->name_check == 's' && len && c != '.') {
91
                c = *name++;
92
                len--;
93
                if (c != '.') return -EINVAL;
94
        }
95
        while (c != '.' && len--) c = *name++;
96
        if (c == '.') {
97
                while (walk-res < 8) *walk++ = ' ';
98
                while (len > 0 && walk-res < MSDOS_NAME) {
99
                        c = *name++;
100
                        len--;
101
                        if (opts->name_check != 'r' && strchr(bad_chars,c))
102
                                return -EINVAL;
103
                        if (opts->name_check == 's' &&
104
                            strchr(bad_if_strict(opts),c))
105
                                return -EINVAL;
106
                        if (c < ' ' || c == ':' || c == '\\')
107
                                return -EINVAL;
108
                        if (c == '.') {
109
                                if (opts->name_check == 's')
110
                                        return -EINVAL;
111
                                break;
112
                        }
113
                        if (c >= 'A' && c <= 'Z' && opts->name_check == 's')
114
                                return -EINVAL;
115
                        space = c == ' ';
116
                        *walk++ = (!opts->nocase && c >= 'a' && c <= 'z') ? c-32 : c;
117
                }
118
                if (space) return -EINVAL;
119
                if (opts->name_check == 's' && len) return -EINVAL;
120
        }
121
        while (walk-res < MSDOS_NAME) *walk++ = ' ';
122
        if (!opts->atari)
123
                /* GEMDOS is less stupid and has no reserved names */
124
                for (reserved = reserved_names; *reserved; reserved++)
125
                        if (!strncmp(res,*reserved,8)) return -EINVAL;
126
        return 0;
127
}
128
 
129
/***** Locates a directory entry.  Uses unformatted name. */
130
static int msdos_find(struct inode *dir, const char *name, int len,
131
                      struct buffer_head **bh, struct msdos_dir_entry **de,
132
                      loff_t *i_pos)
133
{
134
        int res;
135
        char dotsOK;
136
        char msdos_name[MSDOS_NAME];
137
 
138
        dotsOK = MSDOS_SB(dir->i_sb)->options.dotsOK;
139
        res = msdos_format_name(name,len, msdos_name,&MSDOS_SB(dir->i_sb)->options);
140
        if (res < 0)
141
                return -ENOENT;
142
        res = fat_scan(dir, msdos_name, bh, de, i_pos);
143
        if (!res && dotsOK) {
144
                if (name[0]=='.') {
145
                        if (!((*de)->attr & ATTR_HIDDEN))
146
                                res = -ENOENT;
147
                } else {
148
                        if ((*de)->attr & ATTR_HIDDEN)
149
                                res = -ENOENT;
150
                }
151
        }
152
        return res;
153
}
154
 
155
/*
156
 * Compute the hash for the msdos name corresponding to the dentry.
157
 * Note: if the name is invalid, we leave the hash code unchanged so
158
 * that the existing dentry can be used. The msdos fs routines will
159
 * return ENOENT or EINVAL as appropriate.
160
 */
161
static int msdos_hash(struct dentry *dentry, struct qstr *qstr)
162
{
163
        struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
164
        int error;
165
        char msdos_name[MSDOS_NAME];
166
 
167
        error = msdos_format_name(qstr->name, qstr->len, msdos_name, options);
168
        if (!error)
169
                qstr->hash = full_name_hash(msdos_name, MSDOS_NAME);
170
        return 0;
171
}
172
 
173
/*
174
 * Compare two msdos names. If either of the names are invalid,
175
 * we fall back to doing the standard name comparison.
176
 */
177
static int msdos_cmp(struct dentry *dentry, struct qstr *a, struct qstr *b)
178
{
179
        struct fat_mount_options *options = & (MSDOS_SB(dentry->d_sb)->options);
180
        int error;
181
        char a_msdos_name[MSDOS_NAME], b_msdos_name[MSDOS_NAME];
182
 
183
        error = msdos_format_name(a->name, a->len, a_msdos_name, options);
184
        if (error)
185
                goto old_compare;
186
        error = msdos_format_name(b->name, b->len, b_msdos_name, options);
187
        if (error)
188
                goto old_compare;
189
        error = memcmp(a_msdos_name, b_msdos_name, MSDOS_NAME);
190
out:
191
        return error;
192
 
193
old_compare:
194
        error = 1;
195
        if (a->len == b->len)
196
                error = memcmp(a->name, b->name, a->len);
197
        goto out;
198
}
199
 
200
 
201
static struct dentry_operations msdos_dentry_operations = {
202
        d_hash:         msdos_hash,
203
        d_compare:      msdos_cmp,
204
};
205
 
206
/*
207
 * AV. Wrappers for FAT sb operations. Is it wise?
208
 */
209
 
210
/***** Get inode using directory and name */
211
struct dentry *msdos_lookup(struct inode *dir,struct dentry *dentry)
212
{
213
        struct super_block *sb = dir->i_sb;
214
        struct inode *inode = NULL;
215
        struct msdos_dir_entry *de;
216
        struct buffer_head *bh = NULL;
217
        loff_t i_pos;
218
        int res;
219
 
220
        PRINTK (("msdos_lookup\n"));
221
 
222
        dentry->d_op = &msdos_dentry_operations;
223
 
224
        res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len, &bh,
225
                         &de, &i_pos);
226
        if (res == -ENOENT)
227
                goto add;
228
        if (res < 0)
229
                goto out;
230
        inode = fat_build_inode(sb, de, i_pos, &res);
231
        if (res)
232
                goto out;
233
add:
234
        d_add(dentry, inode);
235
        res = 0;
236
out:
237
        if (bh)
238
                fat_brelse(sb, bh);
239
        return ERR_PTR(res);
240
}
241
 
242
/***** Creates a directory entry (name is already formatted). */
243
static int msdos_add_entry(struct inode *dir, const char *name,
244
                           struct buffer_head **bh,
245
                           struct msdos_dir_entry **de,
246
                           loff_t *i_pos, int is_dir, int is_hid)
247
{
248
        struct super_block *sb = dir->i_sb;
249
        int res;
250
 
251
        res = fat_add_entries(dir, 1, bh, de, i_pos);
252
        if (res < 0)
253
                return res;
254
        /*
255
         * XXX all times should be set by caller upon successful completion.
256
         */
257
        dir->i_ctime = dir->i_mtime = CURRENT_TIME;
258
        mark_inode_dirty(dir);
259
        memcpy((*de)->name,name,MSDOS_NAME);
260
        (*de)->attr = is_dir ? ATTR_DIR : ATTR_ARCH;
261
        if (is_hid)
262
                (*de)->attr |= ATTR_HIDDEN;
263
        (*de)->start = 0;
264
        (*de)->starthi = 0;
265
        fat_date_unix2dos(dir->i_mtime,&(*de)->time,&(*de)->date);
266
        (*de)->size = 0;
267
        fat_mark_buffer_dirty(sb, *bh);
268
        return 0;
269
}
270
 
271
/*
272
 * AV. Huh??? It's exported. Oughtta check usage.
273
 */
274
 
275
/***** Create a file */
276
int msdos_create(struct inode *dir,struct dentry *dentry,int mode)
277
{
278
        struct super_block *sb = dir->i_sb;
279
        struct buffer_head *bh;
280
        struct msdos_dir_entry *de;
281
        struct inode *inode;
282
        loff_t i_pos;
283
        int res, is_hid;
284
        char msdos_name[MSDOS_NAME];
285
 
286
        res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
287
                                msdos_name, &MSDOS_SB(sb)->options);
288
        if (res < 0)
289
                return res;
290
        is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
291
        /* Have to do it due to foo vs. .foo conflicts */
292
        if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0) {
293
                fat_brelse(sb, bh);
294
                return -EINVAL;
295
        }
296
        inode = NULL;
297
        res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 0, is_hid);
298
        if (res)
299
                return res;
300
        inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
301
        fat_brelse(sb, bh);
302
        if (!inode)
303
                return res;
304
        inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME;
305
        mark_inode_dirty(inode);
306
        d_instantiate(dentry, inode);
307
        return 0;
308
}
309
 
310
/***** Remove a directory */
311
int msdos_rmdir(struct inode *dir, struct dentry *dentry)
312
{
313
        struct super_block *sb = dir->i_sb;
314
        struct inode *inode = dentry->d_inode;
315
        loff_t i_pos;
316
        int res;
317
        struct buffer_head *bh;
318
        struct msdos_dir_entry *de;
319
 
320
        bh = NULL;
321
        res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
322
                         &bh, &de, &i_pos);
323
        if (res < 0)
324
                goto rmdir_done;
325
        /*
326
         * Check whether the directory is not in use, then check
327
         * whether it is empty.
328
         */
329
        res = fat_dir_empty(inode);
330
        if (res)
331
                goto rmdir_done;
332
 
333
        de->name[0] = DELETED_FLAG;
334
        fat_mark_buffer_dirty(sb, bh);
335
        fat_detach(inode);
336
        inode->i_nlink = 0;
337
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
338
        dir->i_nlink--;
339
        mark_inode_dirty(inode);
340
        mark_inode_dirty(dir);
341
        res = 0;
342
 
343
rmdir_done:
344
        fat_brelse(sb, bh);
345
        return res;
346
}
347
 
348
/***** Make a directory */
349
int msdos_mkdir(struct inode *dir,struct dentry *dentry,int mode)
350
{
351
        struct super_block *sb = dir->i_sb;
352
        struct buffer_head *bh;
353
        struct msdos_dir_entry *de;
354
        struct inode *inode;
355
        int res,is_hid;
356
        char msdos_name[MSDOS_NAME];
357
        loff_t i_pos;
358
 
359
        res = msdos_format_name(dentry->d_name.name,dentry->d_name.len,
360
                                msdos_name, &MSDOS_SB(sb)->options);
361
        if (res < 0)
362
                return res;
363
        is_hid = (dentry->d_name.name[0]=='.') && (msdos_name[0]!='.');
364
        /* foo vs .foo situation */
365
        if (fat_scan(dir, msdos_name, &bh, &de, &i_pos) >= 0)
366
                goto out_exist;
367
 
368
        res = msdos_add_entry(dir, msdos_name, &bh, &de, &i_pos, 1, is_hid);
369
        if (res)
370
                goto out_unlock;
371
        inode = fat_build_inode(dir->i_sb, de, i_pos, &res);
372
        if (!inode) {
373
                fat_brelse(sb, bh);
374
                goto out_unlock;
375
        }
376
        res = 0;
377
 
378
        dir->i_nlink++;
379
        inode->i_nlink = 2; /* no need to mark them dirty */
380
 
381
        res = fat_new_dir(inode, dir, 0);
382
        if (res)
383
                goto mkdir_error;
384
 
385
        fat_brelse(sb, bh);
386
        d_instantiate(dentry, inode);
387
        res = 0;
388
 
389
out_unlock:
390
        return res;
391
 
392
mkdir_error:
393
        printk(KERN_WARNING "msdos_mkdir: error=%d, attempting cleanup\n", res);
394
        inode->i_nlink = 0;
395
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
396
        dir->i_nlink--;
397
        mark_inode_dirty(inode);
398
        mark_inode_dirty(dir);
399
        de->name[0] = DELETED_FLAG;
400
        fat_mark_buffer_dirty(sb, bh);
401
        fat_brelse(sb, bh);
402
        fat_detach(inode);
403
        iput(inode);
404
        goto out_unlock;
405
 
406
out_exist:
407
        fat_brelse(sb, bh);
408
        res = -EINVAL;
409
        goto out_unlock;
410
}
411
 
412
/***** Unlink a file */
413
int msdos_unlink( struct inode *dir, struct dentry *dentry)
414
{
415
        struct super_block *sb = dir->i_sb;
416
        struct inode *inode = dentry->d_inode;
417
        loff_t i_pos;
418
        int res;
419
        struct buffer_head *bh;
420
        struct msdos_dir_entry *de;
421
 
422
        bh = NULL;
423
        res = msdos_find(dir, dentry->d_name.name, dentry->d_name.len,
424
                         &bh, &de, &i_pos);
425
        if (res < 0)
426
                goto unlink_done;
427
 
428
        de->name[0] = DELETED_FLAG;
429
        fat_mark_buffer_dirty(sb, bh);
430
        fat_detach(inode);
431
        fat_brelse(sb, bh);
432
        inode->i_nlink = 0;
433
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
434
        mark_inode_dirty(inode);
435
        mark_inode_dirty(dir);
436
        res = 0;
437
unlink_done:
438
        return res;
439
}
440
 
441
static int do_msdos_rename(struct inode *old_dir, char *old_name,
442
    struct dentry *old_dentry,
443
    struct inode *new_dir,char *new_name, struct dentry *new_dentry,
444
    struct buffer_head *old_bh,
445
    struct msdos_dir_entry *old_de, loff_t old_i_pos, int is_hid)
446
{
447
        struct super_block *sb = old_dir->i_sb;
448
        struct buffer_head *new_bh=NULL,*dotdot_bh=NULL;
449
        struct msdos_dir_entry *new_de,*dotdot_de;
450
        struct inode *old_inode,*new_inode;
451
        loff_t new_i_pos, dotdot_i_pos;
452
        int error;
453
        int is_dir;
454
 
455
        old_inode = old_dentry->d_inode;
456
        new_inode = new_dentry->d_inode;
457
        is_dir = S_ISDIR(old_inode->i_mode);
458
 
459
        if (fat_scan(new_dir, new_name, &new_bh, &new_de, &new_i_pos) >= 0
460
            && !new_inode)
461
                goto degenerate_case;
462
        if (is_dir) {
463
                if (new_inode) {
464
                        error = fat_dir_empty(new_inode);
465
                        if (error)
466
                                goto out;
467
                }
468
                error = fat_scan(old_inode, MSDOS_DOTDOT, &dotdot_bh,
469
                                &dotdot_de, &dotdot_i_pos);
470
                if (error < 0) {
471
                        printk(KERN_WARNING
472
                                "MSDOS: %s/%s, get dotdot failed, ret=%d\n",
473
                                old_dentry->d_parent->d_name.name,
474
                                old_dentry->d_name.name, error);
475
                        goto out;
476
                }
477
        }
478
        if (!new_bh) {
479
                error = msdos_add_entry(new_dir, new_name, &new_bh, &new_de,
480
                                        &new_i_pos, is_dir, is_hid);
481
                if (error)
482
                        goto out;
483
        }
484
        new_dir->i_version = ++event;
485
 
486
        /* There we go */
487
 
488
        if (new_inode)
489
                fat_detach(new_inode);
490
        old_de->name[0] = DELETED_FLAG;
491
        fat_mark_buffer_dirty(sb, old_bh);
492
        fat_detach(old_inode);
493
        fat_attach(old_inode, new_i_pos);
494
        if (is_hid)
495
                MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
496
        else
497
                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
498
        mark_inode_dirty(old_inode);
499
        old_dir->i_version = ++event;
500
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
501
        mark_inode_dirty(old_dir);
502
        if (new_inode) {
503
                new_inode->i_nlink--;
504
                new_inode->i_ctime = CURRENT_TIME;
505
                mark_inode_dirty(new_inode);
506
        }
507
        if (dotdot_bh) {
508
                dotdot_de->start = CT_LE_W(MSDOS_I(new_dir)->i_logstart);
509
                dotdot_de->starthi = CT_LE_W((MSDOS_I(new_dir)->i_logstart) >> 16);
510
                fat_mark_buffer_dirty(sb, dotdot_bh);
511
                old_dir->i_nlink--;
512
                mark_inode_dirty(old_dir);
513
                if (new_inode) {
514
                        new_inode->i_nlink--;
515
                        mark_inode_dirty(new_inode);
516
                } else {
517
                        new_dir->i_nlink++;
518
                        mark_inode_dirty(new_dir);
519
                }
520
        }
521
        error = 0;
522
out:
523
        fat_brelse(sb, new_bh);
524
        fat_brelse(sb, dotdot_bh);
525
        return error;
526
 
527
degenerate_case:
528
        error = -EINVAL;
529
        if (new_de!=old_de)
530
                goto out;
531
        if (is_hid)
532
                MSDOS_I(old_inode)->i_attrs |= ATTR_HIDDEN;
533
        else
534
                MSDOS_I(old_inode)->i_attrs &= ~ATTR_HIDDEN;
535
        mark_inode_dirty(old_inode);
536
        old_dir->i_version = ++event;
537
        old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
538
        mark_inode_dirty(old_dir);
539
        return 0;
540
}
541
 
542
/***** Rename, a wrapper for rename_same_dir & rename_diff_dir */
543
int msdos_rename(struct inode *old_dir,struct dentry *old_dentry,
544
                 struct inode *new_dir,struct dentry *new_dentry)
545
{
546
        struct super_block *sb = old_dir->i_sb;
547
        struct buffer_head *old_bh;
548
        struct msdos_dir_entry *old_de;
549
        loff_t old_i_pos;
550
        int error, is_hid, old_hid; /* if new file and old file are hidden */
551
        char old_msdos_name[MSDOS_NAME], new_msdos_name[MSDOS_NAME];
552
 
553
        error = msdos_format_name(old_dentry->d_name.name,
554
                                  old_dentry->d_name.len,old_msdos_name,
555
                                  &MSDOS_SB(old_dir->i_sb)->options);
556
        if (error < 0)
557
                goto rename_done;
558
        error = msdos_format_name(new_dentry->d_name.name,
559
                                  new_dentry->d_name.len,new_msdos_name,
560
                                  &MSDOS_SB(new_dir->i_sb)->options);
561
        if (error < 0)
562
                goto rename_done;
563
 
564
        is_hid  = (new_dentry->d_name.name[0]=='.') && (new_msdos_name[0]!='.');
565
        old_hid = (old_dentry->d_name.name[0]=='.') && (old_msdos_name[0]!='.');
566
        error = fat_scan(old_dir, old_msdos_name, &old_bh, &old_de, &old_i_pos);
567
        if (error < 0)
568
                goto rename_done;
569
 
570
        error = do_msdos_rename(old_dir, old_msdos_name, old_dentry,
571
                                new_dir, new_msdos_name, new_dentry,
572
                                old_bh, old_de, old_i_pos, is_hid);
573
        fat_brelse(sb, old_bh);
574
 
575
rename_done:
576
        return error;
577
}
578
 
579
 
580
/* The public inode operations for the msdos fs */
581
struct inode_operations msdos_dir_inode_operations = {
582
        create:         msdos_create,
583
        lookup:         msdos_lookup,
584
        unlink:         msdos_unlink,
585
        mkdir:          msdos_mkdir,
586
        rmdir:          msdos_rmdir,
587
        rename:         msdos_rename,
588
        setattr:        fat_notify_change,
589
};
590
 
591
struct super_block *msdos_read_super(struct super_block *sb,void *data, int silent)
592
{
593
        struct super_block *res;
594
 
595
        MSDOS_SB(sb)->options.isvfat = 0;
596
        res = fat_read_super(sb, data, silent, &msdos_dir_inode_operations);
597
        if (res)
598
                sb->s_root->d_op = &msdos_dentry_operations;
599
        return res;
600
}

powered by: WebSVN 2.1.0

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