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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [fat/] [dir.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/fat/dir.c
3
 *
4
 *  directory handling functions for fat-based filesystems
5
 *
6
 *  Written 1992,1993 by Werner Almesberger
7
 *
8
 *  Hidden files 1995 by Albert Cahalan <albert@ccs.neu.edu> <adc@coe.neu.edu>
9
 *
10
 *  VFAT extensions by Gordon Chaffee <chaffee@plateau.cs.berkeley.edu>
11
 *  Merged with msdos fs by Henrik Storner <storner@osiris.ping.dk>
12
 */
13
 
14
#define ASC_LINUX_VERSION(V, P, S)      (((V) * 65536) + ((P) * 256) + (S))
15
 
16
#include <linux/version.h>
17
#include <linux/fs.h>
18
#include <linux/msdos_fs.h>
19
#include <linux/nls.h>
20
#include <linux/kernel.h>
21
#include <linux/errno.h>
22
#include <linux/stat.h>
23
#include <linux/string.h>
24
#include <linux/ioctl.h>
25
#include <linux/dirent.h>
26
#include <linux/mm.h>
27
 
28
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
29
#include <asm/uaccess.h>
30
#define FAT_GET_USER(len, addr) get_user(len, addr)
31
#define FAT_COPY_TO_USER(uaddr, kaddr, len) copy_to_user(uaddr, kaddr, len)
32
#else
33
#include <asm/segment.h>
34
#define FAT_GET_USER(len, addr) (len) = get_user(addr)
35
#define FAT_COPY_TO_USER(uaddr, kaddr, len) memcpy_tofs(uaddr, kaddr, len)
36
#endif
37
 
38
#include "msbuffer.h"
39
 
40
 
41
#define PRINTK(X)
42
 
43
 
44
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
45
static long fat_dir_read(struct inode * inode,struct file * filp,
46
                         char * buf,unsigned long count)
47
#else
48
static int fat_dir_read(struct inode * inode,struct file * filp, char * buf,int count)
49
#endif
50
{
51
        return -EISDIR;
52
}
53
 
54
struct file_operations fat_dir_operations = {
55
        NULL,                   /* lseek - default */
56
        fat_dir_read,           /* read */
57
        NULL,                   /* write - bad */
58
        fat_readdir,            /* readdir */
59
        NULL,                   /* select v2.0.x/poll v2.1.x - default */
60
        fat_dir_ioctl,          /* ioctl - default */
61
        NULL,                   /* mmap */
62
        NULL,                   /* no special open code */
63
        NULL,                   /* no special release code */
64
        file_fsync              /* fsync */
65
};
66
 
67
/*
68
 * Convert Unicode 16 to UTF8, translated unicode, or ascii.
69
 * If uni_xlate is enabled and we
70
 * can't get a 1:1 conversion, use a colon as an escape character since
71
 * it is normally invalid on the vfat filesystem.  The following three
72
 * characters are a sort of uuencoded 16 bit Unicode value.  This lets
73
 * us do a full dump and restore of Unicode filenames.  We could get
74
 * into some trouble with long Unicode names, but ignore that right now.
75
 */
76
static int
77
uni16_to_x8(unsigned char *ascii, unsigned char *uni, int uni_xlate,
78
            struct nls_table *nls)
79
{
80
        unsigned char *ip, *op;
81
        unsigned char ch, cl;
82
        unsigned char *uni_page;
83
        unsigned short val;
84
 
85
        ip = uni;
86
        op = ascii;
87
 
88
        while (*ip || ip[1]) {
89
                cl = *ip++;
90
                ch = *ip++;
91
 
92
                uni_page = nls->page_uni2charset[ch];
93
                if (uni_page && uni_page[cl]) {
94
                        *op++ = uni_page[cl];
95
                } else {
96
                        if (uni_xlate == 1) {
97
                                *op++ = ':';
98
                                val = (cl << 8) + ch;
99
                                op[2] = fat_uni2esc[val & 0x3f];
100
                                val >>= 6;
101
                                op[1] = fat_uni2esc[val & 0x3f];
102
                                val >>= 6;
103
                                *op = fat_uni2esc[val & 0x3f];
104
                                op += 3;
105
                        } else {
106
                                *op++ = '?';
107
                        }
108
                }
109
        }
110
        *op = 0;
111
        return (op - ascii);
112
}
113
 
114
 
115
int fat_readdirx(
116
        struct inode *inode,
117
        struct file *filp,
118
        void *dirent,
119
        fat_filldir_t fat_filldir,
120
        filldir_t filldir,
121
        int shortnames,
122
        int longnames,
123
        int both)
124
{
125
        struct super_block *sb = inode->i_sb;
126
        int ino,i,i2,last;
127
        char c;
128
        struct buffer_head *bh;
129
        struct msdos_dir_entry *de;
130
        unsigned long oldpos = filp->f_pos;
131
        unsigned long spos;
132
        int is_long;
133
        char longname[275];
134
        unsigned char long_len = 0; /* Make compiler warning go away */
135
        unsigned char alias_checksum = 0; /* Make compiler warning go away */
136
        unsigned char long_slots = 0;
137
        int uni_xlate = MSDOS_SB(sb)->options.unicode_xlate;
138
        int utf8 = MSDOS_SB(sb)->options.utf8;
139
        unsigned char *unicode = NULL;
140
        struct nls_table *nls = MSDOS_SB(sb)->nls_io;
141
 
142
        if (!inode || !S_ISDIR(inode->i_mode))
143
                return -EBADF;
144
/* Fake . and .. for the root directory. */
145
        if (inode->i_ino == MSDOS_ROOT_INO) {
146
                while (oldpos < 2) {
147
                        if (fat_filldir(filldir, dirent, "..", oldpos+1, 0, oldpos, oldpos, 0, MSDOS_ROOT_INO) < 0)
148
                                return 0;
149
                        oldpos++;
150
                        filp->f_pos++;
151
                }
152
                if (oldpos == 2)
153
                        filp->f_pos = 0;
154
        }
155
        if (filp->f_pos & (sizeof(struct msdos_dir_entry)-1))
156
                return -ENOENT;
157
 
158
        bh = NULL;
159
        longname[0] = longname[1] = 0;
160
        is_long = 0;
161
        ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
162
        while (ino > -1) {
163
                /* Check for long filename entry */
164
                if (MSDOS_SB(sb)->options.isvfat && (de->name[0] == (__s8) DELETED_FLAG)) {
165
                        is_long = 0;
166
                        oldpos = filp->f_pos;
167
                } else if (MSDOS_SB(sb)->options.isvfat && de->attr ==  ATTR_EXT) {
168
                        int get_new_entry;
169
                        struct msdos_dir_slot *ds;
170
                        int offset;
171
                        unsigned char id;
172
                        unsigned char slot;
173
                        unsigned char slots = 0;
174
 
175
                        if (!unicode) {
176
                                unicode = (unsigned char *)
177
                                        __get_free_page(GFP_KERNEL);
178
                                if (!unicode)
179
                                        return -ENOMEM;
180
                        }
181
 
182
                        offset = 0;
183
                        ds = (struct msdos_dir_slot *) de;
184
                        id = ds->id;
185
                        if (id & 0x40) {
186
                                slots = id & ~0x40;
187
                                long_slots = slots;
188
                                is_long = 1;
189
                                alias_checksum = ds->alias_checksum;
190
                        }
191
 
192
                        get_new_entry = 1;
193
                        slot = slots;
194
                        while (slot > 0) {
195
                                PRINTK(("1. get_new_entry: %d\n", get_new_entry));
196
                                if (ds->attr !=  ATTR_EXT) {
197
                                        is_long = 0;
198
                                        get_new_entry = 0;
199
                                        break;
200
                                }
201
                                if ((ds->id & ~0x40) != slot) {
202
                                        is_long = 0;
203
                                        break;
204
                                }
205
                                if (ds->alias_checksum != alias_checksum) {
206
                                        is_long = 0;
207
                                        break;
208
                                }
209
                                slot--;
210
                                offset = slot * 26;
211
                                PRINTK(("2. get_new_entry: %d\n", get_new_entry));
212
                                memcpy(&unicode[offset], ds->name0_4, 10);
213
                                offset += 10;
214
                                memcpy(&unicode[offset], ds->name5_10, 12);
215
                                offset += 12;
216
                                memcpy(&unicode[offset], ds->name11_12, 4);
217
                                offset += 4;
218
 
219
                                if (ds->id & 0x40) {
220
                                        unicode[offset] = 0;
221
                                        unicode[offset+1] = 0;
222
                                }
223
                                if (slot > 0) {
224
                                        ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
225
                                        PRINTK(("4. get_new_entry: %d\n", get_new_entry));
226
                                        if (ino == -1) {
227
                                                is_long = 0;
228
                                                get_new_entry = 0;
229
                                                break;
230
                                        }
231
                                        ds = (struct msdos_dir_slot *) de;
232
                                }
233
                                PRINTK(("5. get_new_entry: %d\n", get_new_entry));
234
                        }
235
                } else if (!IS_FREE(de->name) && !(de->attr & ATTR_VOLUME)) {
236
                        char bufname[14];
237
                        char *ptname = bufname;
238
                        int dotoffset = 0;
239
                        int was_long = is_long;
240
 
241
                        if (is_long) {
242
                                unsigned char sum;
243
                                for (sum = 0, i = 0; i < 11; i++) {
244
                                        sum = (((sum&1)<<7)|((sum&0xfe)>>1)) + de->name[i];
245
                                }
246
 
247
                                if (sum != alias_checksum) {
248
                                        PRINTK(("Checksums don't match %d != %d\n", sum, alias_checksum));
249
                                        is_long = 0;
250
                                }
251
                                if (utf8) {
252
                                        long_len = utf8_wcstombs(longname, (__u16 *) unicode, sizeof(longname));
253
                                } else {
254
                                        long_len = uni16_to_x8(longname, unicode, uni_xlate, nls);
255
                                }
256
                        }
257
 
258
                        if ((de->attr & ATTR_HIDDEN) && MSDOS_SB(sb)->options.dotsOK) {
259
                                bufname[0] = '.';
260
                                dotoffset = 1;
261
                                ptname = bufname+1;
262
                        }
263
                        for (i = 0, last = 0; i < 8; i++) {
264
                                if (!(c = de->name[i])) break;
265
                                if (c >= 'A' && c <= 'Z') c += 32;
266
                                /* see namei.c, msdos_format_name */
267
                                if (c == 0x05) c = 0xE5;
268
                                if (c != ' ')
269
                                        last = i+1;
270
                                ptname[i] = c;
271
                        }
272
                        i = last;
273
                        ptname[i] = '.';
274
                        i++;
275
                        for (i2 = 0; i2 < 3; i2++) {
276
                                if (!(c = de->ext[i2])) break;
277
                                if (c >= 'A' && c <= 'Z') c += 32;
278
                                if (c != ' ')
279
                                        last = i+1;
280
                                ptname[i] = c;
281
                                i++;
282
                        }
283
                        if ((i = last) != 0) {
284
                                if (!strcmp(de->name,MSDOS_DOT))
285
                                        ino = inode->i_ino;
286
                                else if (!strcmp(de->name,MSDOS_DOTDOT))
287
                                        ino = fat_parent_ino(inode,0);
288
 
289
                                if (shortnames || !is_long) {
290
                                        dcache_add(inode, bufname, i+dotoffset, ino);
291
                                        if (both) {
292
                                                bufname[i+dotoffset] = '\0';
293
                                        }
294
                                        spos = oldpos;
295
                                        if (was_long) {
296
                                                spos = filp->f_pos - sizeof(struct msdos_dir_entry);
297
                                        } else {
298
                                                long_slots = 0;
299
                                        }
300
                                        if (fat_filldir(filldir, dirent, bufname, i+dotoffset, 0, oldpos, spos, long_slots, ino) < 0) {
301
                                                filp->f_pos = oldpos;
302
                                                break;
303
                                        }
304
                                }
305
                                if (is_long && longnames) {
306
                                        dcache_add(inode, longname, long_len, ino);
307
                                        if (both) {
308
                                                memcpy(&longname[long_len+1], bufname, i+dotoffset);
309
                                                long_len += i+dotoffset;
310
                                        }
311
                                        spos = filp->f_pos - sizeof(struct msdos_dir_entry);
312
                                        if (fat_filldir(filldir, dirent, longname, long_len, 1, oldpos, spos, long_slots, ino) < 0) {
313
                                                filp->f_pos = oldpos;
314
                                                break;
315
                                        }
316
                                }
317
                                oldpos = filp->f_pos;
318
                        }
319
                        is_long = 0;
320
                } else {
321
                        is_long = 0;
322
                        oldpos = filp->f_pos;
323
                }
324
                ino = fat_get_entry(inode,&filp->f_pos,&bh,&de);
325
        }
326
        if (bh)
327
                fat_brelse(sb, bh);
328
        if (unicode) {
329
                free_page((unsigned long) unicode);
330
        }
331
        return 0;
332
}
333
 
334
static int fat_filldir(
335
        filldir_t filldir,
336
        void * buf,
337
        const char * name,
338
        int name_len,
339
        int is_long,
340
        off_t offset,
341
        off_t short_offset,
342
        int long_slots,
343
        ino_t ino)
344
{
345
        return filldir(buf, name, name_len, offset, ino);
346
}
347
 
348
int fat_readdir(
349
        struct inode *inode,
350
        struct file *filp,
351
        void *dirent,
352
        filldir_t filldir)
353
{
354
        return fat_readdirx(inode, filp, dirent, fat_filldir, filldir,
355
                            0, 1, 0);
356
}
357
 
358
static int vfat_ioctl_fill(
359
        filldir_t filldir,
360
        void * buf,
361
        const char * name,
362
        int name_len,
363
        int is_long,
364
        off_t offset,
365
        off_t short_offset,
366
        int long_slots,
367
        ino_t ino)
368
{
369
        struct dirent *d1 = (struct dirent *)buf;
370
        struct dirent *d2 = d1 + 1;
371
        int len, slen;
372
        int dotdir;
373
 
374
        FAT_GET_USER(len, &d1->d_reclen);
375
        if (len != 0) {
376
                return -1;
377
        }
378
 
379
        if ((name_len == 1 && name[0] == '.') ||
380
            (name_len == 2 && name[0] == '.' && name[1] == '.')) {
381
                dotdir = 1;
382
                len = name_len;
383
        } else {
384
                dotdir = 0;
385
                len = strlen(name);
386
        }
387
        if (len != name_len) {
388
                FAT_COPY_TO_USER(d2->d_name, name, len);
389
                put_user(0, d2->d_name + len);
390
                put_user(len, &d2->d_reclen);
391
                put_user(ino, &d2->d_ino);
392
                put_user(offset, &d2->d_off);
393
                slen = name_len - len;
394
                FAT_COPY_TO_USER(d1->d_name, name+len+1, slen);
395
                put_user(0, d1->d_name+slen);
396
                put_user(slen, &d1->d_reclen);
397
        } else {
398
                put_user(0, d2->d_name);
399
                put_user(0, &d2->d_reclen);
400
                FAT_COPY_TO_USER(d1->d_name, name, len);
401
                put_user(0, d1->d_name+len);
402
                put_user(len, &d1->d_reclen);
403
        }
404
        PRINTK(("FAT d1=%p d2=%p len=%d, name_len=%d\n",
405
                d1, d2, len, name_len));
406
 
407
        return 0;
408
}
409
 
410
int fat_dir_ioctl(struct inode * inode, struct file * filp,
411
                  unsigned int cmd, unsigned long arg)
412
{
413
        int err;
414
        /*
415
         * We want to provide an interface for Samba to be able
416
         * to get the short filename for a given long filename.
417
         * Samba should use this ioctl instead of readdir() to
418
         * get the information it needs.
419
         */
420
        switch (cmd) {
421
        case VFAT_IOCTL_READDIR_BOTH: {
422
                struct dirent *d1 = (struct dirent *)arg;
423
                err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
424
                if (err)
425
                        return err;
426
                put_user(0, &d1->d_reclen);
427
                return fat_readdirx(inode,filp,(void *)arg,
428
                                    vfat_ioctl_fill, NULL, 0, 1, 1);
429
        }
430
        case VFAT_IOCTL_READDIR_SHORT: {
431
                struct dirent *d1 = (struct dirent *)arg;
432
                err = verify_area(VERIFY_WRITE, d1, sizeof(struct dirent[2]));
433
                if (err)
434
                        return err;
435
                put_user(0, &d1->d_reclen);
436
                return fat_readdirx(inode,filp,(void *)arg,
437
                                    vfat_ioctl_fill, NULL, 1, 0, 1);
438
        }
439
        default:
440
                return -EINVAL;
441
        }
442
 
443
        return 0;
444
}
445
 
446
/*
447
 * Overrides for Emacs so that we follow Linus's tabbing style.
448
 * Emacs will notice this stuff at the end of the file and automatically
449
 * adjust the settings for this buffer only.  This must remain at the end
450
 * of the file.
451
 * ---------------------------------------------------------------------------
452
 * Local variables:
453
 * c-indent-level: 8
454
 * c-brace-imaginary-offset: 0
455
 * c-brace-offset: -8
456
 * c-argdecl-indent: 8
457
 * c-label-offset: -8
458
 * c-continued-statement-offset: 8
459
 * c-continued-brace-offset: 0
460
 * End:
461
 */

powered by: WebSVN 2.1.0

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