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

Subversion Repositories or1k

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

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/umsdos/dir.c
3
 *
4
 *  Written 1993 by Jacques Gelinas
5
 *      Inspired from linux/fs/msdos/... : Werner Almesberger
6
 *
7
 *  Extended MS-DOS directory handling functions
8
 */
9
 
10
#include <linux/sched.h>
11
#include <linux/string.h>
12
#include <linux/fs.h>
13
#include <linux/msdos_fs.h>
14
#include <linux/errno.h>
15
#include <linux/stat.h>
16
#include <linux/limits.h>
17
#include <linux/umsdos_fs.h>
18
#include <linux/malloc.h>
19
 
20
#include <asm/segment.h>
21
 
22
#define PRINTK(x)
23
#define Printk(x) printk x
24
 
25
#define UMSDOS_SPECIAL_DIRFPOS  3
26
extern struct inode *pseudo_root;
27
/*
28
        So  grep *  doesn't complain in the presence of directories.
29
*/
30
int UMSDOS_dir_read(struct inode *inode,struct file *filp,char *buf,
31
    int count)
32
{
33
        return -EISDIR;
34
}
35
 
36
struct UMSDOS_DIR_ONCE {
37
        void *dirbuf;
38
        filldir_t filldir;
39
        int count;
40
        int stop;
41
};
42
 
43
/*
44
        Record a single entry the first call.
45
        Return -EINVAL the next one.
46
*/
47
static int umsdos_dir_once(
48
        void * buf,
49
        const char * name,
50
        int name_len,
51
        off_t offset,
52
        ino_t ino)
53
{
54
        int ret = -EINVAL;
55
        struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *)buf;
56
        if (d->count == 0){
57
                #if 0
58
                        char zname[100];
59
                        memcpy (zname,name,name_len);
60
                        zname[name_len] = '\0';
61
                        Printk (("dir_once :%s: offset %Ld\n",zname,offset));
62
                #endif
63
                ret = d->filldir (d->dirbuf,name,name_len,offset,ino);
64
                d->stop = ret < 0;
65
                d->count = 1;
66
        }
67
        return ret;
68
}
69
 
70
/*
71
        Read count directory entries from directory filp
72
        Return a negative value from linux/errno.h.
73
        Return > 0 if success (The amount of byte written by filldir).
74
 
75
        This function is used by the normal readdir VFS entry point and by
76
        some function who try to find out info on a file from a pure MSDOS
77
        inode. See umsdos_locate_ancestor() below.
78
*/
79
static int umsdos_readdir_x(
80
        struct inode *dir,              /* Point to a description of the super block */
81
        struct file *filp,              /* Point to a directory which is read */
82
    void *dirbuf,                       /* Will hold count directory entry */
83
                                                        /* but filled by the filldir function */
84
        int internal_read,              /* Called for internal purpose */
85
        struct umsdos_dirent *u_entry,  /* Optional umsdos entry */
86
        int follow_hlink,
87
        filldir_t filldir)
88
{
89
        int ret = 0;
90
 
91
        umsdos_startlookup(dir);
92
        if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS
93
                && dir == pseudo_root
94
                && !internal_read){
95
                /*
96
                        We don't need to simulate this pseudo directory
97
                        when umsdos_readdir_x is called for internal operation
98
                        of umsdos. This is why dirent_in_fs is tested
99
                */
100
                /* #Specification: pseudo root / directory /DOS
101
                        When umsdos operates in pseudo root mode (C:\linux is the
102
                        linux root), it simulate a directory /DOS which points to
103
                        the real root of the file system.
104
                */
105
                if (filldir (dirbuf,"DOS",3,UMSDOS_SPECIAL_DIRFPOS
106
                        ,dir->i_sb->s_mounted->i_ino) == 0){
107
                        filp->f_pos++;
108
                }
109
        }else if (filp->f_pos < 2
110
                || (dir != dir->i_sb->s_mounted && filp->f_pos == 32)){
111
                /* #Specification: readdir / . and ..
112
                        The msdos filesystem manage the . and .. entry properly
113
                        so the EMD file won't hold any info about it.
114
 
115
                        In readdir, we assume that for the root directory
116
                        the read position will be 0 for ".", 1 for "..". For
117
                        a non root directory, the read position will be 0 for "."
118
                        and 32 for "..".
119
                */
120
                /*
121
                        This is a trick used by the msdos file system (fs/msdos/dir.c)
122
                        to manage . and .. for the root directory of a file system.
123
                        Since there is no such entry in the root, fs/msdos/dir.c
124
                        use the following:
125
 
126
                        if f_pos == 0, return ".".
127
                        if f_pos == 1, return "..".
128
 
129
                        So let msdos handle it
130
 
131
                        Since umsdos entries are much larger, we share the same f_pos.
132
                        if f_pos is 0 or 1 or 32, we are clearly looking at . and
133
                        ..
134
 
135
                        As soon as we get f_pos == 2 or f_pos == 64, then back to
136
                        0, but this time we are reading the EMD file.
137
 
138
                        Well, not so true. The problem, is that UMSDOS_REC_SIZE is
139
                        also 64, so as soon as we read the first record in the
140
                        EMD, we are back at offset 64. So we set the offset
141
                        to UMSDOS_SPECIAL_DIRFPOS(3) as soon as we have read the
142
                        .. entry from msdos.
143
 
144
                        Now (linux 1.3), umsdos_readdir can read more than one
145
                        entry even if we limit (umsdos_dir_once) to only one:
146
                        It skips over hidden file. So we switch to
147
                        UMSDOS_SPECIAL_DIRFPOS as soon as we have read successfully
148
                        the .. entry.
149
                */
150
                int last_f_pos = filp->f_pos;
151
                struct UMSDOS_DIR_ONCE bufk;
152
                bufk.dirbuf = dirbuf;
153
                bufk.filldir = filldir;
154
                bufk.count = 0;
155
                ret = fat_readdir(dir,filp,&bufk,umsdos_dir_once);
156
                if (last_f_pos > 0 && filp->f_pos > last_f_pos) filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
157
                if (u_entry != NULL) u_entry->flags = 0;
158
        }else{
159
                struct inode *emd_dir = umsdos_emd_dir_lookup(dir,0);
160
                if (emd_dir != NULL){
161
                        off_t start_fpos = filp->f_pos;
162
                        if (filp->f_pos <= UMSDOS_SPECIAL_DIRFPOS+1) filp->f_pos = 0;
163
                        PRINTK (("f_pos %lu i_size %ld\n",filp->f_pos,emd_dir->i_size));
164
                        ret = 0;
165
                        while (filp->f_pos < emd_dir->i_size){
166
                                struct umsdos_dirent entry;
167
                                off_t cur_f_pos = filp->f_pos;
168
                                if (umsdos_emd_dir_readentry (emd_dir,filp,&entry)!=0){
169
                                        ret = -EIO;
170
                                        break;
171
                                }else if (entry.name_len != 0){
172
                                        /* #Specification: umsdos / readdir
173
                                                umsdos_readdir() should fill a struct dirent with
174
                                                an inode number. The cheap way to get it is to
175
                                                do a lookup in the MSDOS directory for each
176
                                                entry processed by the readdir() function.
177
                                                This is not very efficient, but very simple. The
178
                                                other way around is to maintain a copy of the inode
179
                                                number in the EMD file. This is a problem because
180
                                                this has to be maintained in sync using tricks.
181
                                                Remember that MSDOS (the OS) does not update the
182
                                                modification time (mtime) of a directory. There is
183
                                                no easy way to tell that a directory was modified
184
                                                during a DOS session and synchronise the EMD file.
185
 
186
                                                Suggestion welcome.
187
 
188
                                                So the easy way is used!
189
                                        */
190
                                        struct umsdos_info info;
191
                                        struct inode *inode;
192
                                        int lret;
193
                                        umsdos_parse (entry.name,entry.name_len,&info);
194
                                        info.f_pos = cur_f_pos;
195
                                        umsdos_manglename (&info);
196
                                        lret = umsdos_real_lookup (dir,info.fake.fname
197
                                                ,info.fake.len,&inode);
198
                                        PRINTK (("Cherche inode de %s lret %d flags %d\n"
199
                                                ,info.fake.fname,lret,entry.flags));
200
                                        if (lret == 0
201
                                                && (entry.flags & UMSDOS_HLINK)
202
                                                && follow_hlink){
203
                                                struct inode *rinode;
204
                                                lret = umsdos_hlink2inode (inode,&rinode);
205
                                                inode = rinode;
206
                                        }
207
                                        if (lret == 0){
208
                                                /* #Specification: pseudo root / reading real root
209
                                                        The pseudo root (/linux) is logically
210
                                                        erased from the real root. This mean that
211
                                                        ls /DOS, won't show "linux". This avoids
212
                                                        infinite recursion /DOS/linux/DOS/linux while
213
                                                        walking the file system.
214
                                                */
215
                                                if (inode != pseudo_root
216
                                                        && (internal_read
217
                                                                || !(entry.flags & UMSDOS_HIDDEN))){
218
                                                        if (filldir (dirbuf
219
                                                                ,entry.name,entry.name_len
220
                                                                ,cur_f_pos, inode->i_ino) < 0){
221
                                                                filp->f_pos = cur_f_pos;
222
                                                        }
223
                                                        PRINTK (("Trouve ino %ld ",inode->i_ino));
224
                                                        if (u_entry != NULL) *u_entry = entry;
225
                                                        iput (inode);
226
                                                        break;
227
                                                }
228
                                                iput (inode);
229
                                        }else{
230
                                                /* #Specification: umsdos / readdir / not in MSDOS
231
                                                        During a readdir operation, if the file is not
232
                                                        in the MSDOS directory anymore, the entry is
233
                                                        removed from the EMD file silently.
234
                                                */
235
                                                ret = umsdos_writeentry (dir,emd_dir,&info,1);
236
                                                if (ret != 0){
237
                                                        break;
238
                                                }
239
                                        }
240
                                }
241
                        }
242
                        /*
243
                                If the fillbuf has failed, f_pos is back to 0.
244
                                To avoid getting back into the . and .. state
245
                                (see comments at the beginning), we put back
246
                                the special offset.
247
                        */
248
                        if (filp->f_pos == 0) filp->f_pos = start_fpos;
249
                        iput(emd_dir);
250
                }
251
        }
252
        umsdos_endlookup(dir);
253
        PRINTK (("read dir %p pos %Ld ret %d\n",dir,filp->f_pos,ret));
254
        return ret;
255
}
256
/*
257
        Read count directory entries from directory filp
258
        Return a negative value from linux/errno.h.
259
        Return 0 or positive if successful
260
*/
261
static int UMSDOS_readdir(
262
        struct inode *dir,              /* Point to a description of the super block */
263
        struct file *filp,              /* Point to a directory which is read */
264
        void *dirbuf,                   /* Will hold directory entries  */
265
        filldir_t filldir)
266
{
267
        int ret = 0;
268
        int count = 0;
269
        struct UMSDOS_DIR_ONCE bufk;
270
        bufk.dirbuf = dirbuf;
271
        bufk.filldir = filldir;
272
        bufk.stop = 0;
273
        PRINTK (("UMSDOS_readdir in\n"));
274
        while (ret == 0 && bufk.stop == 0){
275
                struct umsdos_dirent entry;
276
                bufk.count = 0;
277
                ret = umsdos_readdir_x (dir,filp,&bufk,0,&entry,1,umsdos_dir_once);
278
                if (bufk.count == 0) break;
279
                count += bufk.count;
280
        }
281
        PRINTK (("UMSDOS_readdir out %d count %d pos %Ld\n",ret,count
282
                ,filp->f_pos));
283
        return count?:ret;
284
}
285
/*
286
        Complete the inode content with info from the EMD file
287
*/
288
void umsdos_lookup_patch (
289
        struct inode *dir,
290
        struct inode *inode,
291
        struct umsdos_dirent *entry,
292
        off_t  emd_pos)
293
{
294
        /*
295
                This function modify the state of a dir inode. It decides
296
                if the dir is a umsdos dir or a dos dir. This is done
297
                deeper in umsdos_patch_inode() called at the end of this function.
298
 
299
                umsdos_patch_inode() may block because it is doing disk access.
300
                At the same time, another process may get here to initialise
301
                the same dir inode. There is 3 cases.
302
 
303
                1-The inode is already initialised. We do nothing.
304
                2-The inode is not initialised. We lock access and do it.
305
                3-Like 2 but another process has lock the inode, so we try
306
                  to lock it and right after check if initialisation is still
307
                  needed.
308
 
309
 
310
                Thanks to the mem option of the kernel command line, it was
311
                possible to consistently reproduce this problem by limiting
312
                my mem to 4 meg and running X.
313
        */
314
        /*
315
                Do this only if the inode is freshly read, because we will lose
316
                the current (updated) content.
317
        */
318
        /*
319
                A lookup of a mount point directory yield the inode into
320
                the other fs, so we don't care about initialising it. iget()
321
                does this automatically.
322
        */
323
        if (inode->i_sb == dir->i_sb && !umsdos_isinit(inode)){
324
                if (S_ISDIR(inode->i_mode)) umsdos_lockcreate(inode);
325
                if (!umsdos_isinit(inode)){
326
                        /* #Specification: umsdos / lookup / inode info
327
                                After successfully reading an inode from the MSDOS
328
                                filesystem, we use the EMD file to complete it.
329
                                We update the following field.
330
 
331
                                uid, gid, atime, ctime, mtime, mode.
332
 
333
                                We rely on MSDOS for mtime. If the file
334
                                was modified during an MSDOS session, at least
335
                                mtime will be meaningful. We do this only for regular
336
                                file.
337
 
338
                                We don't rely on MSDOS for mtime for directory because
339
                                the MSDOS directory date is creation time (strange
340
                                MSDOS behavior) which fit nowhere in the three UNIX
341
                                time stamp.
342
                        */
343
                        if (S_ISREG(entry->mode)) entry->mtime = inode->i_mtime;
344
                        inode->i_mode  = entry->mode;
345
                        inode->i_rdev  = to_kdev_t(entry->rdev);
346
                        inode->i_atime = entry->atime;
347
                        inode->i_ctime = entry->ctime;
348
                        inode->i_mtime = entry->mtime;
349
                        inode->i_uid   = entry->uid;
350
                        inode->i_gid   = entry->gid;
351
                        /* #Specification: umsdos / conversion mode
352
                                The msdos fs can do some inline conversion
353
                                of the data of a file. It can translate
354
                                silently from MsDOS text file format to Unix
355
                                one (crlf -> lf) while reading, and the reverse
356
                                while writing. This is activated using the mount
357
                                option conv=....
358
 
359
                                This is not useful for Linux file in promoted
360
                                directory. It can even be harmful. For this
361
                                reason, the binary (no conversion) mode is
362
                                always activated.
363
                        */
364
                        /* #Specification: umsdos / conversion mode / todo
365
                                A flag could be added to file and directories
366
                                forcing an automatic conversion mode (as
367
                                done with the msdos fs).
368
 
369
                                This flag could be setup on a directory basis
370
                                (instead of file) and all file in it would
371
                                logically inherited. If the conversion mode
372
                                is active (conv=) then the i_binary flag would
373
                                be left untouched in those directories.
374
 
375
                                It was proposed that the sticky bit was used
376
                                to set this. The problem is that new file would
377
                                be written incorrectly. The other problem is that
378
                                the sticky bit has a meaning for directories. So
379
                                another bit should be used (there is some space
380
                                in the EMD file for it) and a special utilities
381
                                would be used to assign the flag to a directory).
382
                                I don't think it is useful to assign this flag
383
                                on a single file.
384
                        */
385
 
386
                        MSDOS_I(inode)->i_binary = 1;
387
                        /* #Specification: umsdos / i_nlink
388
                                The nlink field of an inode is maintain by the MSDOS file system
389
                                for directory and by UMSDOS for other file. The logic is that
390
                                MSDOS is already figuring out what to do for directories and
391
                                does nothing for other files. For MSDOS, there are no hard link
392
                                so all file carry nlink==1. UMSDOS use some info in the
393
                                EMD file to plug the correct value.
394
                        */
395
                        if (!S_ISDIR(entry->mode)){
396
                                if (entry->nlink > 0){
397
                                        inode->i_nlink = entry->nlink;
398
                                }else{
399
                                        printk ("UMSDOS: lookup_patch entry->nlink < 1 ???\n");
400
                                }
401
                        }
402
                        umsdos_patch_inode(inode,dir,emd_pos);
403
                }
404
                if (S_ISDIR(inode->i_mode)) umsdos_unlockcreate(inode);
405
if (inode->u.umsdos_i.i_emd_owner==0) printk ("emd_owner still 0 ???\n");
406
        }
407
}
408
struct UMSDOS_DIRENT_K{
409
        off_t f_pos; /* will hold the offset of the entry in EMD */
410
        ino_t ino;
411
};
412
 
413
/*
414
        Just to record the offset of one entry.
415
*/
416
static int umsdos_filldir_k(
417
        void * buf,
418
        const char * name,
419
        int name_len,
420
        off_t offset,
421
        ino_t ino)
422
{
423
        struct UMSDOS_DIRENT_K *d = (struct UMSDOS_DIRENT_K *)buf;
424
        d->f_pos = offset;
425
        d->ino = ino;
426
        return 0;
427
}
428
 
429
struct UMSDOS_DIR_SEARCH{
430
        struct umsdos_dirent *entry;
431
        int found;
432
        ino_t search_ino;
433
};
434
 
435
static int umsdos_dir_search (
436
        void * buf,
437
        const char * name,
438
        int name_len,
439
        off_t offset,
440
        ino_t ino)
441
{
442
        int ret = 0;
443
        struct UMSDOS_DIR_SEARCH *d = (struct UMSDOS_DIR_SEARCH *)buf;
444
        if (d->search_ino == ino){
445
                d->found = 1;
446
                memcpy (d->entry->name,name,name_len);
447
                d->entry->name[name_len] = '\0';
448
                d->entry->name_len = name_len;
449
                ret = 1;        /* So fat_readdir will terminate */
450
        }
451
        return ret;
452
}
453
 
454
 
455
/*
456
        Locate entry of an inode in a directory.
457
        Return 0 or a negative error code.
458
 
459
        Normally, this function must succeed. It means a strange corruption
460
        in the file system if not.
461
*/
462
int umsdos_inode2entry (
463
        struct inode *dir,
464
        struct inode *inode,
465
        struct umsdos_dirent *entry)    /* Will hold the entry */
466
{
467
        int ret = -ENOENT;
468
        if (inode == pseudo_root){
469
                /*
470
                        Quick way to find the name.
471
                        Also umsdos_readdir_x won't show /linux anyway
472
                */
473
                memcpy (entry->name,UMSDOS_PSDROOT_NAME,UMSDOS_PSDROOT_LEN+1);
474
                entry->name_len = UMSDOS_PSDROOT_LEN;
475
                ret = 0;
476
        }else{
477
                struct inode *emddir = umsdos_emd_dir_lookup(dir,0);
478
                iput (emddir);
479
                if (emddir == NULL){
480
                        /* This is a DOS directory */
481
                        struct UMSDOS_DIR_SEARCH bufk;
482
                        struct file filp;
483
                        filp.f_reada = 1;
484
                        filp.f_pos = 0;
485
                        bufk.entry = entry;
486
                        bufk.search_ino = inode->i_ino;
487
                        fat_readdir (dir,&filp,&bufk,umsdos_dir_search);
488
                        if (bufk.found){
489
                                ret = 0;
490
                                inode->u.umsdos_i.i_dir_owner = dir->i_ino;
491
                                inode->u.umsdos_i.i_emd_owner = 0;
492
                                umsdos_setup_dir_inode(inode);
493
                        }
494
                }else{
495
                        /* skip . and .. see umsdos_readdir_x() */
496
                        struct file filp;
497
                        filp.f_reada = 1;
498
                        filp.f_pos = UMSDOS_SPECIAL_DIRFPOS;
499
                        while (1){
500
                                struct UMSDOS_DIRENT_K bufk;
501
                                if (umsdos_readdir_x(dir,&filp,&bufk
502
                                        ,1,entry,0,umsdos_filldir_k) < 0){
503
                                        printk ("UMSDOS: can't locate inode %ld in EMD file???\n"
504
                                                ,inode->i_ino);
505
                                        break;
506
                                }else if (bufk.ino == inode->i_ino){
507
                                        ret = 0;
508
                                        umsdos_lookup_patch (dir,inode,entry,bufk.f_pos);
509
                                        break;
510
                                }
511
                        }
512
                }
513
        }
514
        return ret;
515
}
516
/*
517
        Locate the parent of a directory and the info on that directory
518
        Return 0 or a negative error code.
519
*/
520
static int umsdos_locate_ancestor (
521
        struct inode *dir,
522
        struct inode **result,
523
        struct umsdos_dirent *entry)
524
{
525
        int ret;
526
        umsdos_patch_inode (dir,NULL,0);
527
        ret = umsdos_real_lookup (dir,"..",2,result);
528
        PRINTK (("result %d %p ",ret,*result));
529
        if (ret == 0){
530
                struct inode *adir = *result;
531
                ret = umsdos_inode2entry (adir,dir,entry);
532
        }
533
        PRINTK (("\n"));
534
        return ret;
535
}
536
/*
537
        Build the path name of an inode (relative to the file system.
538
        This function is need to set (pseudo) hard link.
539
 
540
        It uses the same strategy as the standard getcwd().
541
*/
542
int umsdos_locate_path (
543
        struct inode *inode,
544
        char *path)
545
{
546
        int ret = 0;
547
        struct inode *dir = inode;
548
        char *bpath = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
549
        if (bpath == NULL){
550
                ret = -ENOMEM;
551
        }else{
552
                struct umsdos_dirent entry;
553
                char *ptbpath = bpath+PATH_MAX-1;
554
                *ptbpath = '\0';
555
                PRINTK (("locate_path mode %x ",inode->i_mode));
556
                if (!S_ISDIR(inode->i_mode)){
557
                        ret = umsdos_get_dirowner (inode,&dir);
558
                        PRINTK (("locate_path ret %d ",ret));
559
                        if (ret == 0){
560
                                ret = umsdos_inode2entry (dir,inode,&entry);
561
                                if (ret == 0){
562
                                        ptbpath -= entry.name_len;
563
                                        memcpy (ptbpath,entry.name,entry.name_len);
564
                                        PRINTK (("ptbpath :%s: ",ptbpath));
565
                                }
566
                        }
567
                }else{
568
                        dir->i_count++;
569
                }
570
                if (ret == 0){
571
                        while (dir != dir->i_sb->s_mounted){
572
                                struct inode *adir;
573
                                ret = umsdos_locate_ancestor (dir,&adir,&entry);
574
                                iput (dir);
575
                                dir = NULL;
576
                                PRINTK (("ancestor %d ",ret));
577
                                if (ret == 0){
578
                                        *--ptbpath = '/';
579
                                        ptbpath -= entry.name_len;
580
                                        memcpy (ptbpath,entry.name,entry.name_len);
581
                                        dir = adir;
582
                                        PRINTK (("ptbpath :%s: ",ptbpath));
583
                                }else{
584
                                        break;
585
                                }
586
                        }
587
                }
588
                strcpy (path,ptbpath);
589
                kfree (bpath);
590
        }
591
        PRINTK (("\n"));
592
        iput (dir);
593
        return ret;
594
}
595
 
596
/*
597
        Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
598
*/
599
int umsdos_is_pseudodos (
600
        struct inode *dir,
601
        const char *name,
602
        int len)
603
{
604
        /* #Specification: pseudo root / DOS hard coded
605
                The pseudo sub-directory DOS in the pseudo root is hard coded.
606
                The name is DOS. This is done this way to help standardised
607
                the umsdos layout. The idea is that from now on /DOS is
608
                a reserved path and nobody will think of using such a path
609
                for a package.
610
        */
611
        return dir == pseudo_root
612
                && len == 3
613
                && name[0] == 'D' && name[1] == 'O' && name[2] == 'S';
614
}
615
/*
616
        Check if a file exist in the current directory.
617
        Return 0 if ok, negative error code if not (ex: -ENOENT).
618
*/
619
static int umsdos_lookup_x (
620
        struct inode *dir,
621
        const char *name,
622
        int len,
623
        struct inode **result,  /* Will hold inode of the file, if successful */
624
        int nopseudo)                   /* Don't care about pseudo root mode */
625
{
626
        int ret = -ENOENT;
627
        *result = NULL;
628
        umsdos_startlookup(dir);
629
        if (len == 1 && name[0] == '.'){
630
                *result = dir;
631
                dir->i_count++;
632
                ret = 0;
633
        }else if (len == 2 && name[0] == '.' && name[1] == '.'){
634
                if (pseudo_root != NULL && dir == pseudo_root->i_sb->s_mounted){
635
                        /* #Specification: pseudo root / .. in real root
636
                                Whenever a lookup is those in the real root for
637
                                the directory .., and pseudo root is active, the
638
                                pseudo root is returned.
639
                        */
640
                        ret = 0;
641
                        *result = pseudo_root;
642
                        pseudo_root->i_count++;
643
                }else{
644
                        /* #Specification: locating .. / strategy
645
                                We use the msdos filesystem to locate the parent directory.
646
                                But it is more complicated than that.
647
 
648
                                We have to step back even further to
649
                                get the parent of the parent, so we can get the EMD
650
                                of the parent of the parent. Using the EMD file, we can
651
                                locate all the info on the parent, such a permissions
652
                                and owner.
653
                        */
654
                        ret = umsdos_real_lookup (dir,"..",2,result);
655
                        PRINTK (("ancestor ret %d dir %p *result %p ",ret,dir,*result));
656
                        if (ret == 0
657
                                && *result != dir->i_sb->s_mounted
658
                                && *result != pseudo_root){
659
                                struct inode *aadir;
660
                                struct umsdos_dirent entry;
661
                                ret = umsdos_locate_ancestor (*result,&aadir,&entry);
662
                                iput (aadir);
663
                        }
664
                }
665
        }else if (umsdos_is_pseudodos(dir,name,len)){
666
                /* #Specification: pseudo root / lookup(DOS)
667
                        A lookup of DOS in the pseudo root will always succeed
668
                        and return the inode of the real root.
669
                */
670
                *result = dir->i_sb->s_mounted;
671
                (*result)->i_count++;
672
                ret = 0;
673
        }else{
674
                struct umsdos_info info;
675
                ret = umsdos_parse (name,len,&info);
676
                if (ret == 0) ret = umsdos_findentry (dir,&info,0);
677
                PRINTK (("lookup %s pos %lu ret %d len %d ",info.fake.fname,info.f_pos,ret
678
                        ,info.fake.len));
679
                if (ret == 0){
680
                        /* #Specification: umsdos / lookup
681
                                A lookup for a file is done in two step. First, we locate
682
                                the file in the EMD file. If not present, we return
683
                                an error code (-ENOENT). If it is there, we repeat the
684
                                operation on the msdos file system. If this fails, it means
685
                                that the file system is not in sync with the emd file.
686
                                We silently remove this entry from the emd file,
687
                                and return ENOENT.
688
                        */
689
                        struct inode *inode;
690
                        ret = umsdos_real_lookup (dir,info.fake.fname,info.fake.len,result);
691
                        inode = *result;
692
                        if (inode == NULL){
693
                                printk ("UMSDOS: Erase entry %s, out of sync with MsDOS\n"
694
                                        ,info.fake.fname);
695
                                umsdos_delentry (dir,&info,S_ISDIR(info.entry.mode));
696
                        }else{
697
                                umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
698
                                PRINTK (("lookup ino %ld flags %d\n",inode->i_ino
699
                                        ,info.entry.flags));
700
                                if (info.entry.flags & UMSDOS_HLINK){
701
                                        ret = umsdos_hlink2inode (inode,result);
702
                                }
703
                                if (*result == pseudo_root && !nopseudo){
704
                                        /* #Specification: pseudo root / dir lookup
705
                                                For the same reason as readdir, a lookup in /DOS for
706
                                                the pseudo root directory (linux) will fail.
707
                                        */
708
                                        /*
709
                                                This has to be allowed for resolving hard link
710
                                                which are recorded independently of the pseudo-root
711
                                                mode.
712
                                        */
713
                                        iput (pseudo_root);
714
                                        *result = NULL;
715
                                        ret = -ENOENT;
716
                                }
717
                        }
718
                }
719
        }
720
        umsdos_endlookup(dir);
721
        iput (dir);
722
        return ret;
723
}
724
/*
725
        Check if a file exist in the current directory.
726
        Return 0 if ok, negative error code if not (ex: -ENOENT).
727
*/
728
int UMSDOS_lookup (
729
        struct inode *dir,
730
        const char *name,
731
        int len,
732
        struct inode **result)  /* Will hold inode of the file, if successful */
733
{
734
        return umsdos_lookup_x(dir,name,len,result,0);
735
}
736
/*
737
        Locate the inode pointed by a (pseudo) hard link
738
        Return 0 if ok, a negative error code if not.
739
*/
740
int umsdos_hlink2inode (struct inode *hlink, struct inode **result)
741
{
742
        int ret = -EIO;
743
        char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
744
        *result = NULL;
745
        if (path == NULL){
746
                ret = -ENOMEM;
747
                iput (hlink);
748
        }else{
749
                struct file filp;
750
                filp.f_reada = 1;
751
                filp.f_pos = 0;
752
                PRINTK (("hlink2inode "));
753
                if (umsdos_file_read_kmem (hlink,&filp,path,hlink->i_size)
754
                        ==hlink->i_size){
755
                        struct inode *dir;
756
                        char *pt = path;
757
                        dir = hlink->i_sb->s_mounted;
758
                        path[hlink->i_size] = '\0';
759
                        iput (hlink);
760
                        dir->i_count++;
761
                        while (1){
762
                                char *start = pt;
763
                                int len;
764
                                while (*pt != '\0' && *pt != '/') pt++;
765
                                len = (int)(pt - start);
766
                                if (*pt == '/') *pt++ = '\0';
767
                                if (dir->u.umsdos_i.i_emd_dir == 0){
768
                                        /* This is a DOS directory */
769
                                        ret = umsdos_rlookup_x(dir,start,len,result,1);
770
                                }else{
771
                                        ret = umsdos_lookup_x(dir,start,len,result,1);
772
                                }
773
                                PRINTK (("h2n lookup :%s: -> %d ",start,ret));
774
                                if (ret == 0 && *pt != '\0'){
775
                                        dir = *result;
776
                                }else{
777
                                        break;
778
                                }
779
                        }
780
                }else{
781
                        iput (hlink);
782
                }
783
                PRINTK (("hlink2inode ret = %d %p -> %p\n",ret,hlink,*result));
784
                kfree (path);
785
        }
786
        return ret;
787
}
788
 
789
static struct file_operations umsdos_dir_operations = {
790
        NULL,                           /* lseek - default */
791
        UMSDOS_dir_read,        /* read */
792
        NULL,                           /* write - bad */
793
        UMSDOS_readdir,         /* readdir */
794
        NULL,                           /* select - default */
795
        UMSDOS_ioctl_dir,       /* ioctl - default */
796
        NULL,                           /* mmap */
797
        NULL,                           /* no special open code */
798
        NULL,                           /* no special release code */
799
        NULL                            /* fsync */
800
};
801
 
802
struct inode_operations umsdos_dir_inode_operations = {
803
        &umsdos_dir_operations, /* default directory file-ops */
804
        UMSDOS_create,          /* create */
805
        UMSDOS_lookup,          /* lookup */
806
        UMSDOS_link,            /* link */
807
        UMSDOS_unlink,          /* unlink */
808
        UMSDOS_symlink,         /* symlink */
809
        UMSDOS_mkdir,           /* mkdir */
810
        UMSDOS_rmdir,           /* rmdir */
811
        UMSDOS_mknod,           /* mknod */
812
        UMSDOS_rename,          /* rename */
813
        NULL,                   /* readlink */
814
        NULL,                   /* follow_link */
815
        NULL,                   /* readpage */
816
        NULL,                   /* writepage */
817
        NULL,                   /* bmap */
818
        NULL,                   /* truncate */
819
        NULL                    /* permission */
820
};
821
 
822
 
823
 
824
 
825
 
826
 
827
 
828
 
829
 
830
 

powered by: WebSVN 2.1.0

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