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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
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/slab.h>
19
#include <linux/pagemap.h>
20
 
21
#define UMSDOS_SPECIAL_DIRFPOS  3
22
extern struct dentry *saved_root;
23
extern struct inode *pseudo_root;
24
 
25
/* #define UMSDOS_DEBUG_VERBOSE 1 */
26
 
27
/*
28
 * Dentry operations routines
29
 */
30
 
31
/* nothing for now ... */
32
static int umsdos_dentry_validate(struct dentry *dentry, int flags)
33
{
34
        return 1;
35
}
36
 
37
/* for now, drop everything to force lookups ... */
38
/* ITYM s/everything/& positive/... */
39
static int umsdos_dentry_dput(struct dentry *dentry)
40
{
41
        struct inode *inode = dentry->d_inode;
42
        if (inode) {
43
                return 1;
44
        }
45
        return 0;
46
}
47
 
48
struct dentry_operations umsdos_dentry_operations =
49
{
50
        d_revalidate:   umsdos_dentry_validate,
51
        d_delete:       umsdos_dentry_dput,
52
};
53
 
54
struct UMSDOS_DIR_ONCE {
55
        void *dirbuf;
56
        filldir_t filldir;
57
        int count;
58
        int stop;
59
};
60
 
61
/*
62
 * Record a single entry the first call.
63
 * Return -EINVAL the next one.
64
 * NOTE: filldir DOES NOT use a dentry
65
 */
66
 
67
static int umsdos_dir_once (    void *buf,
68
                                const char *name,
69
                                int len,
70
                                loff_t offset,
71
                                ino_t ino,
72
                                unsigned type)
73
{
74
        int ret = -EINVAL;
75
        struct UMSDOS_DIR_ONCE *d = (struct UMSDOS_DIR_ONCE *) buf;
76
 
77
        if (d->count == 0) {
78
                PRINTK ((KERN_DEBUG "dir_once :%.*s: offset %Ld\n",
79
                        len, name, offset));
80
                ret = d->filldir (d->dirbuf, name, len, offset, ino, DT_UNKNOWN);
81
                d->stop = ret < 0;
82
                d->count = 1;
83
        }
84
        return ret;
85
}
86
 
87
 
88
/*
89
 * Read count directory entries from directory filp
90
 * Return a negative value from linux/errno.h.
91
 * Return > 0 if success (the number of bytes written by filldir).
92
 *
93
 * This function is used by the normal readdir VFS entry point,
94
 * and in order to get the directory entry from a file's dentry.
95
 * See umsdos_dentry_to_entry() below.
96
 */
97
 
98
static int umsdos_readdir_x (struct inode *dir, struct file *filp,
99
                                void *dirbuf, struct umsdos_dirent *u_entry,
100
                                filldir_t filldir)
101
{
102
        struct dentry *demd;
103
        off_t start_fpos;
104
        int ret = 0;
105
        loff_t pos;
106
 
107
        umsdos_startlookup (dir);
108
 
109
        if (filp->f_pos == UMSDOS_SPECIAL_DIRFPOS && dir == pseudo_root) {
110
 
111
                /*
112
                 * We don't need to simulate this pseudo directory
113
                 * when umsdos_readdir_x is called for internal operation
114
                 * of umsdos. This is why dirent_in_fs is tested
115
                 */
116
                /* #Specification: pseudo root / directory /DOS
117
                 * When umsdos operates in pseudo root mode (C:\linux is the
118
                 * linux root), it simulate a directory /DOS which points to
119
                 * the real root of the file system.
120
                 */
121
 
122
                Printk ((KERN_WARNING "umsdos_readdir_x: pseudo_root thing UMSDOS_SPECIAL_DIRFPOS\n"));
123
                if (filldir (dirbuf, "DOS", 3,
124
                                UMSDOS_SPECIAL_DIRFPOS, UMSDOS_ROOT_INO, DT_DIR) == 0) {
125
                        filp->f_pos++;
126
                }
127
                goto out_end;
128
        }
129
 
130
        if (filp->f_pos < 2 ||
131
            (dir->i_ino != UMSDOS_ROOT_INO && filp->f_pos == 32)) {
132
 
133
                int last_f_pos = filp->f_pos;
134
                struct UMSDOS_DIR_ONCE bufk;
135
 
136
                Printk (("umsdos_readdir_x: . or .. /mn/?\n"));
137
 
138
                bufk.dirbuf = dirbuf;
139
                bufk.filldir = filldir;
140
                bufk.count = 0;
141
 
142
                ret = fat_readdir (filp, &bufk, umsdos_dir_once);
143
                if (last_f_pos > 0 && filp->f_pos > last_f_pos)
144
                        filp->f_pos = UMSDOS_SPECIAL_DIRFPOS;
145
                if (u_entry != NULL)
146
                        u_entry->flags = 0;
147
                goto out_end;
148
        }
149
 
150
        Printk (("umsdos_readdir_x: normal file /mn/?\n"));
151
 
152
        /* get the EMD dentry */
153
        demd = umsdos_get_emd_dentry(filp->f_dentry);
154
        ret = PTR_ERR(demd);
155
        if (IS_ERR(demd))
156
                goto out_end;
157
        ret = -EIO;
158
        if (!demd->d_inode) {
159
                printk(KERN_WARNING
160
                        "umsdos_readir_x: EMD file %s/%s not found\n",
161
                        demd->d_parent->d_name.name, demd->d_name.name);
162
                goto out_dput;
163
        }
164
 
165
        pos = filp->f_pos;
166
        start_fpos = filp->f_pos;
167
 
168
        if (pos <= UMSDOS_SPECIAL_DIRFPOS + 1)
169
                pos = 0;
170
        ret = 0;
171
        while (pos < demd->d_inode->i_size) {
172
                off_t cur_f_pos = pos;
173
                struct dentry *dret;
174
                struct inode *inode;
175
                struct umsdos_dirent entry;
176
                struct umsdos_info info;
177
 
178
                ret = -EIO;
179
                if (umsdos_emd_dir_readentry (demd, &pos, &entry) != 0)
180
                        break;
181
                if (entry.name_len == 0)
182
                        continue;
183
#ifdef UMSDOS_DEBUG_VERBOSE
184
if (entry.flags & UMSDOS_HLINK)
185
printk("umsdos_readdir_x: %s/%s is hardlink\n",
186
filp->f_dentry->d_name.name, entry.name);
187
#endif
188
 
189
                umsdos_parse (entry.name, entry.name_len, &info);
190
                info.f_pos = cur_f_pos;
191
                umsdos_manglename (&info);
192
                /*
193
                 * Do a real lookup on the short name.
194
                 */
195
                dret = umsdos_covered(filp->f_dentry, info.fake.fname,
196
                                                 info.fake.len);
197
                ret = PTR_ERR(dret);
198
                if (IS_ERR(dret))
199
                        break;
200
                /*
201
                 * If the file wasn't found, remove it from the EMD.
202
                 */
203
                inode = dret->d_inode;
204
                if (!inode)
205
                        goto remove_name;
206
#ifdef UMSDOS_DEBUG_VERBOSE
207
if (inode->u.umsdos_i.i_is_hlink)
208
printk("umsdos_readdir_x: %s/%s already resolved, ino=%ld\n",
209
dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino);
210
#endif
211
 
212
Printk (("Found %s/%s, ino=%ld, flags=%x\n",
213
dret->d_parent->d_name.name, info.fake.fname, dret->d_inode->i_ino,
214
entry.flags));
215
                /* check whether to resolve a hard-link */
216
                if ((entry.flags & UMSDOS_HLINK) &&
217
                    !inode->u.umsdos_i.i_is_hlink) {
218
                        dret = umsdos_solve_hlink (dret);
219
                        ret = PTR_ERR(dret);
220
                        if (IS_ERR(dret))
221
                                break;
222
                        inode = dret->d_inode;
223
                        if (!inode) {
224
printk("umsdos_readdir_x: %s/%s negative after link\n",
225
dret->d_parent->d_name.name, dret->d_name.name);
226
                                goto clean_up;
227
                        }
228
                }
229
 
230
                /* #Specification:  pseudo root / reading real root
231
                 * The pseudo root (/linux) is logically
232
                 * erased from the real root.  This means that
233
                 * ls /DOS, won't show "linux". This avoids
234
                 * infinite recursion (/DOS/linux/DOS/linux/...) while
235
                 * walking the file system.
236
                 */
237
                if (inode != pseudo_root && !(entry.flags & UMSDOS_HIDDEN)) {
238
                        if (filldir (dirbuf, entry.name, entry.name_len,
239
                                 cur_f_pos, inode->i_ino, DT_UNKNOWN) < 0) {
240
                                pos = cur_f_pos;
241
                        }
242
Printk(("umsdos_readdir_x: got %s/%s, ino=%ld\n",
243
dret->d_parent->d_name.name, dret->d_name.name, inode->i_ino));
244
                        if (u_entry != NULL)
245
                                *u_entry = entry;
246
                        dput(dret);
247
                        ret = 0;
248
                        break;
249
                }
250
        clean_up:
251
                dput(dret);
252
                continue;
253
 
254
        remove_name:
255
                /* #Specification:  umsdos / readdir / not in MSDOS
256
                 * During a readdir operation, if the file is not
257
                 * in the MS-DOS directory any more, the entry is
258
                 * removed from the EMD file silently.
259
                 */
260
#ifdef UMSDOS_PARANOIA
261
printk("umsdos_readdir_x: %s/%s out of sync, erasing\n",
262
filp->f_dentry->d_name.name, info.entry.name);
263
#endif
264
                ret = umsdos_delentry(filp->f_dentry, &info,
265
                                        S_ISDIR(info.entry.mode));
266
                if (ret)
267
                        printk(KERN_WARNING
268
                                "umsdos_readdir_x: delentry %s, err=%d\n",
269
                                info.entry.name, ret);
270
                goto clean_up;
271
        }
272
        /*
273
         * If the fillbuf has failed, f_pos is back to 0.
274
         * To avoid getting back into the . and .. state
275
         * (see comments at the beginning), we put back
276
         * the special offset.
277
         */
278
        filp->f_pos = pos;
279
        if (filp->f_pos == 0)
280
                filp->f_pos = start_fpos;
281
out_dput:
282
        dput(demd);
283
 
284
out_end:
285
        umsdos_endlookup (dir);
286
 
287
        Printk ((KERN_DEBUG "read dir %p pos %Ld ret %d\n",
288
                dir, filp->f_pos, ret));
289
        return ret;
290
}
291
 
292
 
293
/*
294
 * Read count directory entries from directory filp.
295
 * Return a negative value from linux/errno.h.
296
 * Return 0 or positive if successful.
297
 */
298
 
299
static int UMSDOS_readdir (struct file *filp, void *dirbuf, filldir_t filldir)
300
{
301
        struct inode *dir = filp->f_dentry->d_inode;
302
        int ret = 0, count = 0;
303
        struct UMSDOS_DIR_ONCE bufk;
304
 
305
        bufk.dirbuf = dirbuf;
306
        bufk.filldir = filldir;
307
        bufk.stop = 0;
308
 
309
        Printk (("UMSDOS_readdir in\n"));
310
        while (ret == 0 && bufk.stop == 0) {
311
                struct umsdos_dirent entry;
312
 
313
                bufk.count = 0;
314
                ret = umsdos_readdir_x (dir, filp, &bufk, &entry,
315
                                        umsdos_dir_once);
316
                if (bufk.count == 0)
317
                        break;
318
                count += bufk.count;
319
        }
320
        Printk (("UMSDOS_readdir out %d count %d pos %Ld\n",
321
                ret, count, filp->f_pos));
322
        return count ? : ret;
323
}
324
 
325
 
326
/*
327
 * Complete the inode content with info from the EMD file.
328
 *
329
 * This function modifies the state of a dir inode.  It decides
330
 * whether the dir is a UMSDOS or DOS directory.  This is done
331
 * deeper in umsdos_patch_inode() called at the end of this function.
332
 *
333
 * Because it is does disk access, umsdos_patch_inode() may block.
334
 * At the same time, another process may get here to initialise
335
 * the same directory inode. There are three cases.
336
 *
337
 * 1) The inode is already initialised.  We do nothing.
338
 * 2) The inode is not initialised.  We lock access and do it.
339
 * 3) Like 2 but another process has locked the inode, so we try
340
 * to lock it and check right afterward check whether
341
 * initialisation is still needed.
342
 *
343
 *
344
 * Thanks to the "mem" option of the kernel command line, it was
345
 * possible to consistently reproduce this problem by limiting
346
 * my memory to 4 MB and running X.
347
 *
348
 * Do this only if the inode is freshly read, because we will lose
349
 * the current (updated) content.
350
 *
351
 * A lookup of a mount point directory yield the inode into
352
 * the other fs, so we don't care about initialising it. iget()
353
 * does this automatically.
354
 */
355
 
356
void umsdos_lookup_patch_new(struct dentry *dentry, struct umsdos_info *info)
357
{
358
        struct inode *inode = dentry->d_inode;
359
        struct umsdos_dirent *entry = &info->entry;
360
 
361
        /*
362
         * This part of the initialization depends only on i_patched.
363
         */
364
        if (inode->u.umsdos_i.i_patched)
365
                goto out;
366
        inode->u.umsdos_i.i_patched = 1;
367
        if (S_ISREG (entry->mode))
368
                entry->mtime = inode->i_mtime;
369
        inode->i_mode = entry->mode;
370
        inode->i_rdev = to_kdev_t (entry->rdev);
371
        inode->i_atime = entry->atime;
372
        inode->i_ctime = entry->ctime;
373
        inode->i_mtime = entry->mtime;
374
        inode->i_uid = entry->uid;
375
        inode->i_gid = entry->gid;
376
 
377
        /* #Specification: umsdos / i_nlink
378
         * The nlink field of an inode is maintained by the MSDOS file system
379
         * for directory and by UMSDOS for other files.  The logic is that
380
         * MSDOS is already figuring out what to do for directories and
381
         * does nothing for other files.  For MSDOS, there are no hard links
382
         * so all file carry nlink==1.  UMSDOS use some info in the
383
         * EMD file to plug the correct value.
384
         */
385
        if (!S_ISDIR (entry->mode)) {
386
                if (entry->nlink > 0) {
387
                        inode->i_nlink = entry->nlink;
388
                } else {
389
                        printk (KERN_ERR
390
                                "UMSDOS:  lookup_patch entry->nlink < 1 ???\n");
391
                }
392
        }
393
        /*
394
         * The mode may have changed, so patch the inode again.
395
         */
396
        umsdos_patch_dentry_inode(dentry, info->f_pos);
397
        umsdos_set_dirinfo_new(dentry, info->f_pos);
398
 
399
out:
400
        return;
401
}
402
 
403
 
404
/*
405
 * Return != 0 if an entry is the pseudo DOS entry in the pseudo root.
406
 */
407
 
408
int umsdos_is_pseudodos (struct inode *dir, struct dentry *dentry)
409
{
410
        /* #Specification: pseudo root / DOS hard coded
411
         * The pseudo sub-directory DOS in the pseudo root is hard coded.
412
         * The name is DOS. This is done this way to help standardised
413
         * the umsdos layout. The idea is that from now on /DOS is
414
         * a reserved path and nobody will think of using such a path
415
         * for a package.
416
         */
417
        return dir == pseudo_root
418
            && dentry->d_name.len == 3
419
            && dentry->d_name.name[0] == 'D'
420
            && dentry->d_name.name[1] == 'O'
421
            && dentry->d_name.name[2] == 'S';
422
}
423
 
424
 
425
/*
426
 * Check whether a file exists in the current directory.
427
 * Return 0 if OK, negative error code if not (ex: -ENOENT).
428
 *
429
 * fills dentry->d_inode with found inode, and increments its count.
430
 * if not found, return -ENOENT.
431
 */
432
/* #Specification: umsdos / lookup
433
 * A lookup for a file is done in two steps.  First, we
434
 * locate the file in the EMD file.  If not present, we
435
 * return an error code (-ENOENT).  If it is there, we
436
 * repeat the operation on the msdos file system. If
437
 * this fails, it means that the file system is not in
438
 * sync with the EMD file.   We silently remove this
439
 * entry from the EMD file, and return ENOENT.
440
 */
441
 
442
struct dentry *umsdos_lookup_x (struct inode *dir, struct dentry *dentry, int nopseudo)
443
{
444
        struct dentry *dret = NULL;
445
        struct inode *inode;
446
        int ret = -ENOENT;
447
        struct umsdos_info info;
448
 
449
#ifdef UMSDOS_DEBUG_VERBOSE
450
printk("umsdos_lookup_x: looking for %s/%s\n",
451
dentry->d_parent->d_name.name, dentry->d_name.name);
452
#endif
453
 
454
        umsdos_startlookup (dir);
455
        if (umsdos_is_pseudodos (dir, dentry)) {
456
                /* #Specification: pseudo root / lookup(DOS)
457
                 * A lookup of DOS in the pseudo root will always succeed
458
                 * and return the inode of the real root.
459
                 */
460
                Printk ((KERN_DEBUG "umsdos_lookup_x: following /DOS\n"));
461
                inode = saved_root->d_inode;
462
                goto out_add;
463
        }
464
 
465
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
466
        if (ret) {
467
printk("umsdos_lookup_x: %s/%s parse failed, ret=%d\n",
468
dentry->d_parent->d_name.name, dentry->d_name.name, ret);
469
                goto out;
470
        }
471
 
472
        ret = umsdos_findentry (dentry->d_parent, &info, 0);
473
        if (ret) {
474
if (ret != -ENOENT)
475
printk("umsdos_lookup_x: %s/%s findentry failed, ret=%d\n",
476
dentry->d_parent->d_name.name, dentry->d_name.name, ret);
477
                goto out;
478
        }
479
Printk (("lookup %.*s pos %lu ret %d len %d ",
480
info.fake.len, info.fake.fname, info.f_pos, ret, info.fake.len));
481
 
482
        /* do a real lookup to get the short name ... */
483
        dret = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
484
        ret = PTR_ERR(dret);
485
        if (IS_ERR(dret)) {
486
printk("umsdos_lookup_x: %s/%s real lookup failed, ret=%d\n",
487
dentry->d_parent->d_name.name, dentry->d_name.name, ret);
488
                goto out;
489
        }
490
        inode = dret->d_inode;
491
        if (!inode)
492
                goto out_remove;
493
        umsdos_lookup_patch_new(dret, &info);
494
#ifdef UMSDOS_DEBUG_VERBOSE
495
printk("umsdos_lookup_x: found %s/%s, ino=%ld\n",
496
dret->d_parent->d_name.name, dret->d_name.name, dret->d_inode->i_ino);
497
#endif
498
 
499
        /* Check for a hard link */
500
        if ((info.entry.flags & UMSDOS_HLINK) &&
501
            !inode->u.umsdos_i.i_is_hlink) {
502
                dret = umsdos_solve_hlink (dret);
503
                ret = PTR_ERR(dret);
504
                if (IS_ERR(dret))
505
                        goto out;
506
                ret = -ENOENT;
507
                inode = dret->d_inode;
508
                if (!inode) {
509
printk("umsdos_lookup_x: %s/%s negative after link\n",
510
dret->d_parent->d_name.name, dret->d_name.name);
511
                        goto out_dput;
512
                }
513
        }
514
 
515
        if (inode == pseudo_root && !nopseudo) {
516
                /* #Specification: pseudo root / dir lookup
517
                 * For the same reason as readdir, a lookup in /DOS for
518
                 * the pseudo root directory (linux) will fail.
519
                 */
520
                /*
521
                 * This has to be allowed for resolving hard links
522
                 * which are recorded independently of the pseudo-root
523
                 * mode.
524
                 */
525
printk("umsdos_lookup_x: skipping DOS/linux\n");
526
                ret = -ENOENT;
527
                goto out_dput;
528
        }
529
 
530
        /*
531
         * We've found it OK.  Now hash the dentry with the inode.
532
         */
533
out_add:
534
        atomic_inc(&inode->i_count);
535
        d_add (dentry, inode);
536
        dentry->d_op = &umsdos_dentry_operations;
537
        ret = 0;
538
 
539
out_dput:
540
        if (dret && dret != dentry)
541
                d_drop(dret);
542
        dput(dret);
543
out:
544
        umsdos_endlookup (dir);
545
        return ERR_PTR(ret);
546
 
547
out_remove:
548
        printk(KERN_WARNING "UMSDOS:  entry %s/%s out of sync, erased\n",
549
                dentry->d_parent->d_name.name, dentry->d_name.name);
550
        umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
551
        ret = -ENOENT;
552
        goto out_dput;
553
}
554
 
555
 
556
/*
557
 * Check whether a file exists in the current directory.
558
 * Return 0 if OK, negative error code if not (ex: -ENOENT).
559
 *
560
 * Called by VFS; should fill dentry->d_inode via d_add.
561
 */
562
 
563
struct dentry *UMSDOS_lookup (struct inode *dir, struct dentry *dentry)
564
{
565
        struct dentry *ret;
566
 
567
        ret = umsdos_lookup_x (dir, dentry, 0);
568
 
569
        /* Create negative dentry if not found. */
570
        if (ret == ERR_PTR(-ENOENT)) {
571
                Printk ((KERN_DEBUG
572
                        "UMSDOS_lookup: converting -ENOENT to negative\n"));
573
                d_add (dentry, NULL);
574
                dentry->d_op = &umsdos_dentry_operations;
575
                ret = NULL;
576
        }
577
        return ret;
578
}
579
 
580
struct dentry *umsdos_covered(struct dentry *parent, char *name, int len)
581
{
582
        struct dentry *result, *dentry;
583
        struct qstr qstr;
584
 
585
        qstr.name = name;
586
        qstr.len  = len;
587
        qstr.hash = full_name_hash(name, len);
588
        result = ERR_PTR(-ENOMEM);
589
        dentry = d_alloc(parent, &qstr);
590
        if (dentry) {
591
                /* XXXXXXXXXXXXXXXXXXX Race alert! */
592
                result = UMSDOS_rlookup(parent->d_inode, dentry);
593
                d_drop(dentry);
594
                if (result)
595
                        goto out_fail;
596
                return dentry;
597
        }
598
out:
599
        return result;
600
 
601
out_fail:
602
        dput(dentry);
603
        goto out;
604
}
605
 
606
/*
607
 * Lookup or create a dentry from within the filesystem.
608
 *
609
 * We need to use this instead of lookup_dentry, as the
610
 * directory semaphore lock is already held.
611
 */
612
struct dentry *umsdos_lookup_dentry(struct dentry *parent, char *name, int len,
613
                                        int real)
614
{
615
        struct dentry *result, *dentry;
616
        struct qstr qstr;
617
 
618
        qstr.name = name;
619
        qstr.len  = len;
620
        qstr.hash = full_name_hash(name, len);
621
        result = d_lookup(parent, &qstr);
622
        if (!result) {
623
                result = ERR_PTR(-ENOMEM);
624
                dentry = d_alloc(parent, &qstr);
625
                if (dentry) {
626
                        result = real ?
627
                                UMSDOS_rlookup(parent->d_inode, dentry) :
628
                                UMSDOS_lookup(parent->d_inode, dentry);
629
                        if (result)
630
                                goto out_fail;
631
                        return dentry;
632
                }
633
        }
634
out:
635
        return result;
636
 
637
out_fail:
638
        dput(dentry);
639
        goto out;
640
}
641
 
642
/*
643
 * Return a path relative to our root.
644
 */
645
char * umsdos_d_path(struct dentry *dentry, char * buffer, int len)
646
{
647
        struct dentry * old_root;
648
        char * path;
649
 
650
        read_lock(&current->fs->lock);
651
        old_root = dget(current->fs->root);
652
        read_unlock(&current->fs->lock);
653
        spin_lock(&dcache_lock);
654
        path = __d_path(dentry, current->fs->rootmnt, dentry->d_sb->s_root, current->fs->rootmnt, buffer, len); /* FIXME: current->fs->rootmnt */
655
        spin_unlock(&dcache_lock);
656
 
657
        if (IS_ERR(path))
658
                return path;
659
 
660
        if (*path == '/')
661
                path++; /* skip leading '/' */
662
 
663
        if (current->fs->root->d_inode == pseudo_root)
664
        {
665
                *(path-1) = '/';
666
                path -= (UMSDOS_PSDROOT_LEN+1);
667
                memcpy(path, UMSDOS_PSDROOT_NAME, UMSDOS_PSDROOT_LEN);
668
        }
669
        dput(old_root);
670
 
671
        return path;
672
}
673
 
674
/*
675
 * Return the dentry which points to a pseudo-hardlink.
676
 *
677
 * it should try to find file it points to
678
 * if file is found, return new dentry/inode
679
 * The resolved inode will have i_is_hlink set.
680
 *
681
 * Note: the original dentry is always dput(), even if an error occurs.
682
 */
683
 
684
struct dentry *umsdos_solve_hlink (struct dentry *hlink)
685
{
686
        /* root is our root for resolving pseudo-hardlink */
687
        struct dentry *base = hlink->d_sb->s_root;
688
        struct dentry *dentry_dst;
689
        char *path, *pt;
690
        int len;
691
        struct address_space *mapping = hlink->d_inode->i_mapping;
692
        struct page *page;
693
 
694
        page=read_cache_page(mapping,0,(filler_t *)mapping->a_ops->readpage,NULL);
695
        dentry_dst=(struct dentry *)page;
696
        if (IS_ERR(page))
697
                goto out;
698
        wait_on_page(page);
699
        if (!Page_Uptodate(page))
700
                goto async_fail;
701
 
702
        dentry_dst = ERR_PTR(-ENOMEM);
703
        path = (char *) kmalloc (PATH_MAX, GFP_KERNEL);
704
        if (path == NULL)
705
                goto out_release;
706
        memcpy(path, kmap(page), hlink->d_inode->i_size);
707
        kunmap(page);
708
        page_cache_release(page);
709
 
710
        len = hlink->d_inode->i_size;
711
 
712
        /* start at root dentry */
713
        dentry_dst = dget(base);
714
        path[len] = '\0';
715
 
716
        pt = path;
717
        if (*path == '/')
718
                pt++; /* skip leading '/' */
719
 
720
        if (base->d_inode == pseudo_root)
721
                pt += (UMSDOS_PSDROOT_LEN + 1);
722
 
723
        while (1) {
724
                struct dentry *dir = dentry_dst, *demd;
725
                char *start = pt;
726
                int real;
727
 
728
                while (*pt != '\0' && *pt != '/') pt++;
729
                len = (int) (pt - start);
730
                if (*pt == '/') *pt++ = '\0';
731
 
732
                real = 1;
733
                demd = umsdos_get_emd_dentry(dir);
734
                if (!IS_ERR(demd)) {
735
                        if (demd->d_inode)
736
                                real = 0;
737
                        dput(demd);
738
                }
739
 
740
#ifdef UMSDOS_DEBUG_VERBOSE
741
printk ("umsdos_solve_hlink: dir %s/%s, name=%s, real=%d\n",
742
dir->d_parent->d_name.name, dir->d_name.name, start, real);
743
#endif
744
                dentry_dst = umsdos_lookup_dentry(dir, start, len, real);
745
/* XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX */
746
                if (real)
747
                        d_drop(dir);
748
                dput (dir);
749
                if (IS_ERR(dentry_dst))
750
                        break;
751
                /* not found? stop search ... */
752
                if (!dentry_dst->d_inode) {
753
                        break;
754
                }
755
                if (*pt == '\0')        /* we're finished! */
756
                        break;
757
        } /* end while */
758
 
759
        if (!IS_ERR(dentry_dst)) {
760
                struct inode *inode = dentry_dst->d_inode;
761
                if (inode) {
762
                        inode->u.umsdos_i.i_is_hlink = 1;
763
#ifdef UMSDOS_DEBUG_VERBOSE
764
printk ("umsdos_solve_hlink: resolved link %s/%s, ino=%ld\n",
765
dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name, inode->i_ino);
766
#endif
767
                } else {
768
#ifdef UMSDOS_DEBUG_VERBOSE
769
printk ("umsdos_solve_hlink: resolved link %s/%s negative!\n",
770
dentry_dst->d_parent->d_name.name, dentry_dst->d_name.name);
771
#endif
772
                }
773
        } else
774
                printk(KERN_WARNING
775
                        "umsdos_solve_hlink: err=%ld\n", PTR_ERR(dentry_dst));
776
        kfree (path);
777
 
778
out:
779
        dput(hlink);    /* original hlink no longer needed */
780
        return dentry_dst;
781
 
782
async_fail:
783
        dentry_dst = ERR_PTR(-EIO);
784
out_release:
785
        page_cache_release(page);
786
        goto out;
787
}
788
 
789
 
790
struct file_operations umsdos_dir_operations =
791
{
792
        read:           generic_read_dir,
793
        readdir:        UMSDOS_readdir,
794
        ioctl:          UMSDOS_ioctl_dir,
795
};
796
 
797
struct inode_operations umsdos_dir_inode_operations =
798
{
799
        create:         UMSDOS_create,
800
        lookup:         UMSDOS_lookup,
801
        link:           UMSDOS_link,
802
        unlink:         UMSDOS_unlink,
803
        symlink:        UMSDOS_symlink,
804
        mkdir:          UMSDOS_mkdir,
805
        rmdir:          UMSDOS_rmdir,
806
        mknod:          UMSDOS_mknod,
807
        rename:         UMSDOS_rename,
808
        setattr:        UMSDOS_notify_change,
809
};

powered by: WebSVN 2.1.0

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