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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1275 phoenix
/*
2
 *  linux/fs/umsdos/namei.c
3
 *
4
 *      Written 1993 by Jacques Gelinas
5
 *      Inspired from linux/fs/msdos/... by Werner Almesberger
6
 *
7
 * Maintain and access the --linux alternate directory file.
8
 */
9
 /*
10
  * You are in the maze of twisted functions - half of them shouldn't
11
  * be here...
12
  */
13
 
14
#include <linux/errno.h>
15
#include <linux/kernel.h>
16
#include <linux/sched.h>
17
#include <linux/types.h>
18
#include <linux/fcntl.h>
19
#include <linux/stat.h>
20
#include <linux/string.h>
21
#include <linux/msdos_fs.h>
22
#include <linux/umsdos_fs.h>
23
#include <linux/slab.h>
24
 
25
#define UMSDOS_DIR_LOCK
26
 
27
#ifdef UMSDOS_DIR_LOCK
28
 
29
static inline void u_sleep_on (struct inode *dir)
30
{
31
        sleep_on (&dir->u.umsdos_i.dir_info.p);
32
}
33
 
34
static inline void u_wake_up (struct inode *dir)
35
{
36
        wake_up (&dir->u.umsdos_i.dir_info.p);
37
}
38
 
39
/*
40
 * Wait for creation exclusivity.
41
 * Return 0 if the dir was already available.
42
 * Return 1 if a wait was necessary.
43
 * When 1 is return, it means a wait was done. It does not
44
 * mean the directory is available.
45
 */
46
static int umsdos_waitcreate (struct inode *dir)
47
{
48
        int ret = 0;
49
 
50
        if (dir->u.umsdos_i.dir_info.creating
51
            && dir->u.umsdos_i.dir_info.pid != current->pid) {
52
                PRINTK (("creating && dir_info.pid=%lu, current->pid=%u\n", dir->u.umsdos_i.dir_info.pid, current->pid));
53
                u_sleep_on (dir);
54
                ret = 1;
55
        }
56
        return ret;
57
}
58
 
59
/*
60
 * Wait for any lookup process to finish
61
 */
62
static void umsdos_waitlookup (struct inode *dir)
63
{
64
        while (dir->u.umsdos_i.dir_info.looking) {
65
                u_sleep_on (dir);
66
        }
67
}
68
 
69
/*
70
 * Lock all other process out of this directory.
71
 */
72
/* #Specification: file creation / not atomic
73
 * File creation is a two step process. First we create (allocate)
74
 * an entry in the EMD file and then (using the entry offset) we
75
 * build a unique name for MSDOS. We create this name in the msdos
76
 * space.
77
 *
78
 * We have to use semaphore (sleep_on/wake_up) to prevent lookup
79
 * into a directory when we create a file or directory and to
80
 * prevent creation while a lookup is going on. Since many lookup
81
 * may happen at the same time, the semaphore is a counter.
82
 *
83
 * Only one creation is allowed at the same time. This protection
84
 * may not be necessary. The problem arise mainly when a lookup
85
 * or a readdir is done while a file is partially created. The
86
 * lookup process see that as a "normal" problem and silently
87
 * erase the file from the EMD file. Normal because a file
88
 * may be erased during a MSDOS session, but not removed from
89
 * the EMD file.
90
 *
91
 * The locking is done on a directory per directory basis. Each
92
 * directory inode has its wait_queue.
93
 *
94
 * For some operation like hard link, things even get worse. Many
95
 * creation must occur at once (atomic). To simplify the design
96
 * a process is allowed to recursively lock the directory for
97
 * creation. The pid of the locking process is kept along with
98
 * a counter so a second level of locking is granted or not.
99
 */
100
void umsdos_lockcreate (struct inode *dir)
101
{
102
        /*
103
         * Wait for any creation process to finish except
104
         * if we (the process) own the lock
105
         */
106
        while (umsdos_waitcreate (dir) != 0);
107
        dir->u.umsdos_i.dir_info.creating++;
108
        dir->u.umsdos_i.dir_info.pid = current->pid;
109
        umsdos_waitlookup (dir);
110
}
111
 
112
/*
113
 * Lock all other process out of those two directories.
114
 */
115
static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
116
{
117
        /*
118
         * We must check that both directory are available before
119
         * locking anyone of them. This is to avoid some deadlock.
120
         * Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
121
         * this to me.
122
         */
123
        while (1) {
124
                if (umsdos_waitcreate (dir1) == 0
125
                    && umsdos_waitcreate (dir2) == 0) {
126
                        /* We own both now */
127
                        dir1->u.umsdos_i.dir_info.creating++;
128
                        dir1->u.umsdos_i.dir_info.pid = current->pid;
129
                        dir2->u.umsdos_i.dir_info.creating++;
130
                        dir2->u.umsdos_i.dir_info.pid = current->pid;
131
                        break;
132
                }
133
        }
134
        umsdos_waitlookup (dir1);
135
        umsdos_waitlookup (dir2);
136
}
137
 
138
/*
139
 * Wait until creation is finish in this directory.
140
 */
141
void umsdos_startlookup (struct inode *dir)
142
{
143
        while (umsdos_waitcreate (dir) != 0);
144
        dir->u.umsdos_i.dir_info.looking++;
145
}
146
 
147
/*
148
 * Unlock the directory.
149
 */
150
void umsdos_unlockcreate (struct inode *dir)
151
{
152
        dir->u.umsdos_i.dir_info.creating--;
153
        if (dir->u.umsdos_i.dir_info.creating < 0) {
154
                printk ("UMSDOS: dir->u.umsdos_i.dir_info.creating < 0: %d"
155
                        ,dir->u.umsdos_i.dir_info.creating);
156
        }
157
        u_wake_up (dir);
158
}
159
 
160
/*
161
 * Tell directory lookup is over.
162
 */
163
void umsdos_endlookup (struct inode *dir)
164
{
165
        dir->u.umsdos_i.dir_info.looking--;
166
        if (dir->u.umsdos_i.dir_info.looking < 0) {
167
                printk ("UMSDOS: dir->u.umsdos_i.dir_info.looking < 0: %d"
168
                        ,dir->u.umsdos_i.dir_info.looking);
169
        }
170
        u_wake_up (dir);
171
}
172
 
173
#else
174
static void umsdos_lockcreate (struct inode *dir)
175
{
176
}
177
static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
178
{
179
}
180
void umsdos_startlookup (struct inode *dir)
181
{
182
}
183
static void umsdos_unlockcreate (struct inode *dir)
184
{
185
}
186
void umsdos_endlookup (struct inode *dir)
187
{
188
}
189
 
190
#endif
191
 
192
static int umsdos_nevercreat (struct inode *dir, struct dentry *dentry,
193
                                int errcod)
194
{
195
        int ret = 0;
196
 
197
        if (umsdos_is_pseudodos (dir, dentry)) {
198
                /* #Specification: pseudo root / any file creation /DOS
199
                 * The pseudo sub-directory /DOS can't be created!
200
                 * EEXIST is returned.
201
                 *
202
                 * The pseudo sub-directory /DOS can't be removed!
203
                 * EPERM is returned.
204
                 */
205
                ret = errcod;
206
        }
207
        return ret;
208
}
209
 
210
/*
211
 * Add a new file (ordinary or special) into the alternate directory.
212
 * The file is added to the real MSDOS directory. If successful, it
213
 * is then added to the EMD file.
214
 *
215
 * Return the status of the operation. 0 mean success.
216
 *
217
 * #Specification: create / file exists in DOS
218
 * Here is a situation: we are trying to create a file with
219
 * UMSDOS. The file is unknown to UMSDOS but already
220
 * exists in the DOS directory.
221
 *
222
 * Here is what we are NOT doing:
223
 *
224
 * We could silently assume that everything is fine
225
 * and allows the creation to succeed.
226
 *
227
 * It is possible not all files in the partition
228
 * are meant to be visible from linux. By trying to create
229
 * those file in some directory, one user may get access
230
 * to those file without proper permissions. Looks like
231
 * a security hole to me. Off course sharing a file system
232
 * with DOS is some kind of security hole :-)
233
 *
234
 * So ?
235
 *
236
 * We return EEXIST in this case.
237
 * The same is true for directory creation.
238
 */
239
static int umsdos_create_any (struct inode *dir, struct dentry *dentry,
240
                                int mode, int rdev, char flags)
241
{
242
        struct dentry *fake;
243
        struct inode *inode;
244
        int ret;
245
        struct umsdos_info info;
246
 
247
        ret = umsdos_nevercreat (dir, dentry, -EEXIST);
248
        if (ret)
249
                goto out;
250
 
251
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
252
        if (ret)
253
                goto out;
254
 
255
        info.entry.mode = mode;
256
        info.entry.rdev = rdev;
257
        info.entry.flags = flags;
258
        info.entry.uid = current->fsuid;
259
        info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
260
        info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
261
        info.entry.nlink = 1;
262
        ret = umsdos_newentry (dentry->d_parent, &info);
263
        if (ret)
264
                goto out;
265
 
266
        /* do a real lookup to get the short name dentry */
267
        fake = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
268
        ret = PTR_ERR(fake);
269
        if (IS_ERR(fake))
270
                goto out_remove;
271
 
272
        /* should not exist yet ... */
273
        ret = -EEXIST;
274
        if (fake->d_inode)
275
                goto out_remove_dput;
276
 
277
        ret = msdos_create (dir, fake, S_IFREG | 0777);
278
        if (ret)
279
                goto out_remove_dput;
280
 
281
        inode = fake->d_inode;
282
        atomic_inc(&inode->i_count);
283
        d_instantiate (dentry, inode);
284
        dput(fake);
285
        if (atomic_read(&inode->i_count) > 1) {
286
                printk(KERN_WARNING
287
                        "umsdos_create_any: %s/%s, ino=%ld, icount=%d??\n",
288
                        dentry->d_parent->d_name.name, dentry->d_name.name,
289
                        inode->i_ino, atomic_read(&inode->i_count));
290
        }
291
        umsdos_lookup_patch_new(dentry, &info);
292
 
293
out:
294
        return ret;
295
 
296
        /* Creation failed ... remove the EMD entry */
297
out_remove_dput:
298
        dput(fake);
299
out_remove:
300
        if (ret == -EEXIST)
301
                printk(KERN_WARNING "UMSDOS: out of sync, deleting %s/%s\n",
302
                        dentry->d_parent->d_name.name, info.fake.fname);
303
        umsdos_delentry (dentry->d_parent, &info, S_ISDIR (info.entry.mode));
304
        goto out;
305
}
306
 
307
/*
308
 * Add a new file into the alternate directory.
309
 * The file is added to the real MSDOS directory. If successful, it
310
 * is then added to the EMD file.
311
 *
312
 * Return the status of the operation. 0 mean success.
313
 */
314
int UMSDOS_create (struct inode *dir, struct dentry *dentry, int mode)
315
{
316
        return umsdos_create_any (dir, dentry, mode, 0, 0);
317
}
318
 
319
 
320
/*
321
 * Initialise the new_entry from the old for a rename operation.
322
 * (Only useful for umsdos_rename_f() below).
323
 */
324
static void umsdos_ren_init (struct umsdos_info *new_info,
325
                             struct umsdos_info *old_info)
326
{
327
        new_info->entry.mode = old_info->entry.mode;
328
        new_info->entry.rdev = old_info->entry.rdev;
329
        new_info->entry.uid = old_info->entry.uid;
330
        new_info->entry.gid = old_info->entry.gid;
331
        new_info->entry.ctime = old_info->entry.ctime;
332
        new_info->entry.atime = old_info->entry.atime;
333
        new_info->entry.mtime = old_info->entry.mtime;
334
        new_info->entry.flags = old_info->entry.flags;
335
        new_info->entry.nlink = old_info->entry.nlink;
336
}
337
 
338
/*
339
 * Rename a file (move) in the file system.
340
 */
341
 
342
static int umsdos_rename_f (struct inode *old_dir, struct dentry *old_dentry,
343
                            struct inode *new_dir, struct dentry *new_dentry,
344
                            int flags)
345
{
346
        struct inode *old_inode = old_dentry->d_inode;
347
        struct dentry *old, *new, *old_emd;
348
        int err, ret;
349
        struct umsdos_info old_info;
350
        struct umsdos_info new_info;
351
 
352
        ret = -EPERM;
353
        err = umsdos_parse (old_dentry->d_name.name,
354
                                old_dentry->d_name.len, &old_info);
355
        if (err)
356
                goto out;
357
        err = umsdos_parse (new_dentry->d_name.name,
358
                                new_dentry->d_name.len, &new_info);
359
        if (err)
360
                goto out;
361
 
362
        /* Get the EMD dentry for the old parent */
363
        old_emd = umsdos_get_emd_dentry(old_dentry->d_parent);
364
        ret = PTR_ERR(old_emd);
365
        if (IS_ERR(old_emd))
366
                goto out;
367
 
368
        umsdos_lockcreate2 (old_dir, new_dir);
369
 
370
        ret = umsdos_findentry(old_emd->d_parent, &old_info, 0);
371
        if (ret)
372
                goto out_unlock;
373
 
374
        err = umsdos_findentry(new_dentry->d_parent, &new_info, 0);
375
        if (err == 0) {
376
                /* check whether it _really_ exists ... */
377
                ret = -EEXIST;
378
                if (new_dentry->d_inode)
379
                        goto out_unlock;
380
 
381
                /* bogus lookup? complain and fix up the EMD ... */
382
                printk(KERN_WARNING
383
                        "umsdos_rename_f: entry %s/%s exists, inode NULL??\n",
384
                        new_dentry->d_parent->d_name.name, new_info.entry.name);
385
                err = umsdos_delentry(new_dentry->d_parent, &new_info,
386
                                        S_ISDIR(new_info.entry.mode));
387
        }
388
 
389
        umsdos_ren_init (&new_info, &old_info);
390
        if (flags)
391
                new_info.entry.flags = flags;
392
        ret = umsdos_newentry (new_dentry->d_parent, &new_info);
393
        if (ret)
394
                goto out_unlock;
395
 
396
        /* If we're moving a hardlink, drop it first */
397
        if (old_info.entry.flags & UMSDOS_HLINK) {
398
                d_drop(old_dentry);
399
        }
400
 
401
        old = umsdos_covered(old_dentry->d_parent, old_info.fake.fname,
402
                                        old_info.fake.len);
403
        ret = PTR_ERR(old);
404
        if (IS_ERR(old))
405
                goto out_unlock;
406
        /* make sure it's the same inode! */
407
        ret = -ENOENT;
408
        /*
409
         * note: for hardlinks they will be different!
410
         *  old_inode will contain inode of .LINKxxx file containing data, and
411
         *  old->d_inode will contain inode of file containing path to .LINKxxx file
412
         */
413
        if (!(old_info.entry.flags & UMSDOS_HLINK)) {
414
                if (old->d_inode != old_inode)
415
                        goto out_dput;
416
        }
417
 
418
        new = umsdos_covered(new_dentry->d_parent, new_info.fake.fname,
419
                                        new_info.fake.len);
420
        ret = PTR_ERR(new);
421
        if (IS_ERR(new))
422
                goto out_dput;
423
 
424
        /* Do the msdos-level rename */
425
        ret = msdos_rename (old_dir, old, new_dir, new);
426
 
427
        dput(new);
428
 
429
        /* If the rename failed, remove the new EMD entry */
430
        if (ret != 0) {
431
                umsdos_delentry (new_dentry->d_parent, &new_info,
432
                                 S_ISDIR (new_info.entry.mode));
433
                goto out_dput;
434
        }
435
 
436
        /*
437
         * Rename successful ... remove the old name from the EMD.
438
         * Note that we use the EMD parent here, as the old dentry
439
         * may have moved to a new parent ...
440
         */
441
        err = umsdos_delentry (old_emd->d_parent, &old_info,
442
                                S_ISDIR (old_info.entry.mode));
443
        if (err) {
444
                /* Failed? Complain a bit, but don't fail the operation */
445
                printk(KERN_WARNING
446
                        "umsdos_rename_f: delentry %s/%s failed, error=%d\n",
447
                        old_emd->d_parent->d_name.name, old_info.entry.name,
448
                        err);
449
        }
450
 
451
        /*
452
         * Update f_pos so notify_change will succeed
453
         * if the file was already in use.
454
         */
455
        umsdos_set_dirinfo_new(old_dentry, new_info.f_pos);
456
 
457
        /* dput() the dentry if we haven't already */
458
out_dput:
459
        dput(old);
460
 
461
out_unlock:
462
        dput(old_emd);
463
        umsdos_unlockcreate (old_dir);
464
        umsdos_unlockcreate (new_dir);
465
 
466
out:
467
        Printk ((" _ret=%d\n", ret));
468
        return ret;
469
}
470
 
471
/*
472
 * Setup a Symbolic link or a (pseudo) hard link
473
 * Return a negative error code or 0 if OK.
474
 */
475
/* #Specification: symbolic links / strategy
476
 * A symbolic link is simply a file which holds a path. It is
477
 * implemented as a normal MSDOS file (not very space efficient :-()
478
 *
479
 * I see two different ways to do this: One is to place the link data
480
 * in unused entries of the EMD file; the other is to have a separate
481
 * file dedicated to hold all symbolic links data.
482
 *
483
 * Let's go for simplicity...
484
 */
485
 
486
/*
487
 * AV. Should be called with dir->i_sem down.
488
 */
489
static int umsdos_symlink_x (struct inode *dir, struct dentry *dentry,
490
                        const char *symname, int mode, char flags)
491
{
492
        int ret, len;
493
 
494
        ret = umsdos_create_any (dir, dentry, mode, 0, flags);
495
        if (ret) {
496
                printk(KERN_WARNING
497
                        "umsdos_symlink: create failed, ret=%d\n", ret);
498
                goto out;
499
        }
500
 
501
        len = strlen (symname) + 1;
502
        ret = block_symlink(dentry->d_inode, symname, len);
503
        if (ret < 0)
504
                goto out_unlink;
505
out:
506
        return ret;
507
 
508
out_unlink:
509
        printk(KERN_WARNING "umsdos_symlink: write failed, unlinking\n");
510
        UMSDOS_unlink (dir, dentry);
511
        d_drop(dentry);
512
        goto out;
513
}
514
 
515
/*
516
 * Setup a Symbolic link.
517
 * Return a negative error code or 0 if OK.
518
 */
519
int UMSDOS_symlink ( struct inode *dir, struct dentry *dentry,
520
                 const char *symname)
521
{
522
        return umsdos_symlink_x (dir, dentry, symname, S_IFLNK | 0777, 0);
523
}
524
 
525
/*
526
 * Add a link to an inode in a directory
527
 */
528
int UMSDOS_link (struct dentry *olddentry, struct inode *dir,
529
                 struct dentry *dentry)
530
{
531
        struct inode *oldinode = olddentry->d_inode;
532
        struct inode *olddir = olddentry->d_parent->d_inode;
533
        struct dentry *temp;
534
        char *path;
535
        unsigned long buffer;
536
        int ret;
537
        struct umsdos_info old_info;
538
        struct umsdos_info hid_info;
539
 
540
#ifdef UMSDOS_DEBUG_VERBOSE
541
printk("umsdos_link: new %s/%s -> %s/%s\n",
542
dentry->d_parent->d_name.name, dentry->d_name.name,
543
olddentry->d_parent->d_name.name, olddentry->d_name.name);
544
#endif
545
 
546
        ret = -EPERM;
547
        if (S_ISDIR (oldinode->i_mode))
548
                goto out;
549
 
550
        ret = umsdos_nevercreat (dir, dentry, -EPERM);
551
        if (ret)
552
                goto out;
553
 
554
        ret = -ENOMEM;
555
        buffer = get_free_page(GFP_KERNEL);
556
        if (!buffer)
557
                goto out;
558
 
559
        /*
560
         * Lock the link parent if it's not the same directory.
561
         */
562
        ret = -EDEADLOCK;
563
        if (olddir != dir) {
564
                if (atomic_read(&olddir->i_sem.count) < 1)
565
                        goto out_free;
566
                down(&olddir->i_sem);
567
        }
568
 
569
        /*
570
         * Parse the name and get the visible directory entry.
571
         */
572
        ret = umsdos_parse (olddentry->d_name.name, olddentry->d_name.len,
573
                                &old_info);
574
        if (ret)
575
                goto out_unlock;
576
        ret = umsdos_findentry (olddentry->d_parent, &old_info, 1);
577
        if (ret) {
578
printk("UMSDOS_link: %s/%s not in EMD, ret=%d\n",
579
olddentry->d_parent->d_name.name, olddentry->d_name.name, ret);
580
                goto out_unlock;
581
        }
582
 
583
        /*
584
         * If the visible dentry is a pseudo-hardlink, the original
585
         * file must be already hidden.
586
         */
587
        if (!(old_info.entry.flags & UMSDOS_HLINK)) {
588
                int err;
589
 
590
                /* create a hidden link name */
591
                ret = umsdos_newhidden (olddentry->d_parent, &hid_info);
592
                if (ret) {
593
printk("umsdos_link: can't make hidden %s/%s, ret=%d\n",
594
olddentry->d_parent->d_name.name, hid_info.entry.name, ret);
595
                        goto out_unlock;
596
                }
597
 
598
                /*
599
                 * Make a dentry and rename the original file ...
600
                 */
601
                temp = umsdos_lookup_dentry(olddentry->d_parent,
602
                                                hid_info.entry.name,
603
                                                hid_info.entry.name_len, 0);
604
                ret = PTR_ERR(temp);
605
                if (IS_ERR(temp)) {
606
printk("umsdos_link: lookup %s/%s failed, ret=%d\n",
607
dentry->d_parent->d_name.name, hid_info.entry.name, ret);
608
                        goto cleanup;
609
                }
610
                /* rename the link to the hidden location ... */
611
                ret = umsdos_rename_f(olddir, olddentry, olddir, temp,
612
                                        UMSDOS_HIDDEN);
613
                d_move(olddentry, temp);
614
                dput(temp);
615
                if (ret) {
616
printk("umsdos_link: rename to %s/%s failed, ret=%d\n",
617
temp->d_parent->d_name.name, temp->d_name.name, ret);
618
                        goto cleanup;
619
                }
620
                /*
621
                 * Capture the path to the hidden link.
622
                 */
623
                path = umsdos_d_path(olddentry, (char *) buffer, PAGE_SIZE);
624
                if (IS_ERR(path)) {
625
                        ret = PTR_ERR(path);
626
                        goto cleanup;
627
                }
628
Printk(("umsdos_link: hidden link path=%s\n", path));
629
 
630
                /* mark the inode as a hardlink */
631
                oldinode->u.umsdos_i.i_is_hlink = 1;
632
 
633
                /*
634
                 * Recreate a dentry for the original name and symlink it,
635
                 * then symlink the new dentry. Don't give up if one fails,
636
                 * or we'll lose the file completely!
637
                 *
638
                 * Note: this counts as the "original" reference, so we
639
                 * don't increment i_nlink for this one.
640
                 */
641
                temp = umsdos_lookup_dentry(olddentry->d_parent,
642
                                                old_info.entry.name,
643
                                                old_info.entry.name_len, 0);
644
                ret = PTR_ERR(temp);
645
                if (!IS_ERR(temp)) {
646
                        ret = umsdos_symlink_x (olddir, temp, path,
647
                                                S_IFREG | 0777, UMSDOS_HLINK);
648
                        dput(temp);
649
                }
650
 
651
                /* This symlink increments i_nlink (see below.) */
652
                err = umsdos_symlink_x (dir, dentry, path,
653
                                        S_IFREG | 0777, UMSDOS_HLINK);
654
                /* fold the two errors */
655
                if (!ret)
656
                        ret = err;
657
                goto out_unlock;
658
 
659
                /* creation failed ... remove the link entry */
660
        cleanup:
661
printk("umsdos_link: link failed, ret=%d, removing %s/%s\n",
662
ret, olddentry->d_parent->d_name.name, hid_info.entry.name);
663
                err = umsdos_delentry(olddentry->d_parent, &hid_info, 0);
664
                goto out_unlock;
665
        }
666
 
667
Printk(("UMSDOS_link: %s/%s already hidden\n",
668
olddentry->d_parent->d_name.name, olddentry->d_name.name));
669
        /*
670
         * The original file is already hidden, and we need to get
671
         * the dentry for its real name, not the visible name.
672
         * N.B. make sure it's the hidden inode ...
673
         */
674
        if (!oldinode->u.umsdos_i.i_is_hlink)
675
                printk("UMSDOS_link: %s/%s hidden, ino=%ld not hlink??\n",
676
                        olddentry->d_parent->d_name.name,
677
                        olddentry->d_name.name, oldinode->i_ino);
678
 
679
        /*
680
         * In order to get the correct (real) inode, we just drop
681
         * the original dentry.
682
         */
683
        d_drop(olddentry);
684
Printk(("UMSDOS_link: hard link %s/%s, fake=%s\n",
685
olddentry->d_parent->d_name.name, olddentry->d_name.name, old_info.fake.fname));
686
 
687
        /* Do a real lookup to get the short name dentry */
688
        temp = umsdos_covered(olddentry->d_parent, old_info.fake.fname,
689
                                        old_info.fake.len);
690
        ret = PTR_ERR(temp);
691
        if (IS_ERR(temp))
692
                goto out_unlock;
693
 
694
        /* now resolve the link ... */
695
        temp = umsdos_solve_hlink(temp);
696
        ret = PTR_ERR(temp);
697
        if (IS_ERR(temp))
698
                goto out_unlock;
699
        path = umsdos_d_path(temp, (char *) buffer, PAGE_SIZE);
700
        dput(temp);
701
        if (IS_ERR(path))
702
                goto out_unlock;
703
Printk(("umsdos_link: %s/%s already hidden, path=%s\n",
704
olddentry->d_parent->d_name.name, olddentry->d_name.name, path));
705
 
706
        /* finally we can symlink it ... */
707
        ret = umsdos_symlink_x (dir, dentry, path, S_IFREG | 0777,UMSDOS_HLINK);
708
 
709
out_unlock:
710
        /* remain locked for the call to notify_change ... */
711
        if (ret == 0) {
712
                struct iattr newattrs;
713
 
714
                /* Do a real lookup to get the short name dentry */
715
                temp = umsdos_covered(olddentry->d_parent,
716
                                        old_info.fake.fname,
717
                                        old_info.fake.len);
718
                ret = PTR_ERR(temp);
719
                if (IS_ERR(temp))
720
                        goto out_unlock2;
721
 
722
                /* now resolve the link ... */
723
                temp = umsdos_solve_hlink(temp);
724
                ret = PTR_ERR(temp);
725
                if (IS_ERR(temp))
726
                        goto out_unlock2;
727
 
728
 
729
#ifdef UMSDOS_PARANOIA
730
if (!oldinode->u.umsdos_i.i_is_hlink)
731
printk("UMSDOS_link: %s/%s, ino=%ld, not marked as hlink!\n",
732
olddentry->d_parent->d_name.name, olddentry->d_name.name, oldinode->i_ino);
733
#endif
734
                temp->d_inode->i_nlink++;
735
Printk(("UMSDOS_link: linked %s/%s, ino=%ld, nlink=%d\n",
736
olddentry->d_parent->d_name.name, olddentry->d_name.name,
737
oldinode->i_ino, oldinode->i_nlink));
738
                newattrs.ia_valid = 0;
739
                ret = umsdos_notify_change_locked(temp, &newattrs);
740
                if (ret == 0)
741
                        mark_inode_dirty(temp->d_inode);
742
                dput(temp);
743
out_unlock2:
744
                if (ret == 0)
745
                        mark_inode_dirty(olddentry->d_inode);
746
        }
747
        if (olddir != dir)
748
                up(&olddir->i_sem);
749
 
750
out_free:
751
        free_page(buffer);
752
out:
753
        Printk (("umsdos_link %d\n", ret));
754
        return ret;
755
}
756
 
757
 
758
/*
759
 * Add a sub-directory in a directory
760
 */
761
/* #Specification: mkdir / Directory already exist in DOS
762
 * We do the same thing as for file creation.
763
 * For all user it is an error.
764
 */
765
/* #Specification: mkdir / umsdos directory / create EMD
766
 * When we created a new sub-directory in a UMSDOS
767
 * directory (one with full UMSDOS semantics), we
768
 * create immediately an EMD file in the new
769
 * sub-directory so it inherits UMSDOS semantics.
770
 */
771
int UMSDOS_mkdir (struct inode *dir, struct dentry *dentry, int mode)
772
{
773
        struct dentry *temp;
774
        struct inode *inode;
775
        int ret, err;
776
        struct umsdos_info info;
777
 
778
        ret = umsdos_nevercreat (dir, dentry, -EEXIST);
779
        if (ret)
780
                goto out;
781
 
782
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
783
        if (ret)
784
                goto out;
785
 
786
        info.entry.mode = mode | S_IFDIR;
787
        info.entry.rdev = 0;
788
        info.entry.uid = current->fsuid;
789
        info.entry.gid = (dir->i_mode & S_ISGID) ? dir->i_gid : current->fsgid;
790
        info.entry.ctime = info.entry.atime = info.entry.mtime = CURRENT_TIME;
791
        info.entry.flags = 0;
792
        info.entry.nlink = 1;
793
        ret = umsdos_newentry (dentry->d_parent, &info);
794
        if (ret)
795
                goto out;
796
 
797
        /* lookup the short name dentry */
798
        temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
799
        ret = PTR_ERR(temp);
800
        if (IS_ERR(temp))
801
                goto out_remove;
802
 
803
        /* Make sure the short name doesn't exist */
804
        ret = -EEXIST;
805
        if (temp->d_inode) {
806
printk("umsdos_mkdir: short name %s/%s exists\n",
807
dentry->d_parent->d_name.name, info.fake.fname);
808
                goto out_remove_dput;
809
        }
810
 
811
        ret = msdos_mkdir (dir, temp, mode);
812
        if (ret)
813
                goto out_remove_dput;
814
 
815
        /*
816
         * Lock the inode to protect the EMD creation ...
817
         */
818
        inode = temp->d_inode;
819
        down(&inode->i_sem);
820
 
821
        atomic_inc(&inode->i_count);
822
        d_instantiate(dentry, inode);
823
 
824
        /* N.B. this should have an option to create the EMD ... */
825
        umsdos_lookup_patch_new(dentry, &info);
826
 
827
        /*
828
         * Create the EMD file, and set up the dir so it is
829
         * promoted to EMD with the EMD file invisible.
830
         *
831
         * N.B. error return if EMD fails?
832
         */
833
        err = umsdos_make_emd(dentry);
834
        umsdos_setup_dir(dentry);
835
 
836
        up(&inode->i_sem);
837
        dput(temp);
838
 
839
out:
840
        Printk(("umsdos_mkdir: %s/%s, ret=%d\n",
841
                dentry->d_parent->d_name.name, dentry->d_name.name, ret));
842
        return ret;
843
 
844
        /* an error occurred ... remove EMD entry. */
845
out_remove_dput:
846
        dput(temp);
847
out_remove:
848
        umsdos_delentry (dentry->d_parent, &info, 1);
849
        goto out;
850
}
851
 
852
/*
853
 * Add a new device special file into a directory.
854
 *
855
 * #Specification: Special files / strategy
856
 * Device special file, pipes, etc ... are created like normal
857
 * file in the msdos file system. Of course they remain empty.
858
 *
859
 * One strategy was to create those files only in the EMD file
860
 * since they were not important for MSDOS. The problem with
861
 * that, is that there were not getting inode number allocated.
862
 * The MSDOS filesystems is playing a nice game to fake inode
863
 * number, so why not use it.
864
 *
865
 * The absence of inode number compatible with those allocated
866
 * for ordinary files was causing major trouble with hard link
867
 * in particular and other parts of the kernel I guess.
868
 */
869
int UMSDOS_mknod (struct inode *dir, struct dentry *dentry,
870
                 int mode, int rdev)
871
{
872
        return umsdos_create_any (dir, dentry, mode, rdev, 0);
873
}
874
 
875
/*
876
 * Remove a sub-directory.
877
 */
878
int UMSDOS_rmdir (struct inode *dir, struct dentry *dentry)
879
{
880
        struct dentry *temp;
881
        int ret, err, empty;
882
        struct umsdos_info info;
883
 
884
        ret = umsdos_nevercreat (dir, dentry, -EPERM);
885
        if (ret)
886
                goto out;
887
 
888
        ret = -EBUSY;
889
        if (!d_unhashed(dentry))
890
                goto out;
891
 
892
        /* check whether the EMD is empty */
893
        ret = -ENOTEMPTY;
894
        empty = umsdos_isempty (dentry);
895
 
896
        /* Have to remove the EMD file? */
897
        if (empty == 1) {
898
                struct dentry *demd;
899
 
900
                demd = umsdos_get_emd_dentry(dentry);
901
                if (!IS_ERR(demd)) {
902
                        err = -ENOENT;
903
                        if (demd->d_inode)
904
                                err = msdos_unlink (dentry->d_inode, demd);
905
Printk (("UMSDOS_rmdir: unlinking empty EMD err=%d", err));
906
#ifdef UMSDOS_PARANOIA
907
if (err)
908
printk("umsdos_rmdir: EMD %s/%s unlink failed, err=%d\n",
909
demd->d_parent->d_name.name, demd->d_name.name, err);
910
#endif
911
                        if (!err) {
912
                                d_delete(demd);
913
                                ret = 0;
914
                        }
915
                        dput(demd);
916
                }
917
        } else if (empty == 2)
918
                ret = 0;
919
        if (ret)
920
                goto out;
921
 
922
        umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
923
        /* Call findentry to complete the mangling */
924
        umsdos_findentry (dentry->d_parent, &info, 2);
925
        temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
926
        ret = PTR_ERR(temp);
927
        if (IS_ERR(temp))
928
                goto out;
929
        /*
930
         * Attempt to remove the msdos name.
931
         */
932
        ret = msdos_rmdir (dir, temp);
933
        if (ret && ret != -ENOENT)
934
                goto out_dput;
935
 
936
        d_delete(temp);
937
        /* OK so far ... remove the name from the EMD */
938
        ret = umsdos_delentry (dentry->d_parent, &info, 1);
939
#ifdef UMSDOS_PARANOIA
940
if (ret)
941
printk("umsdos_rmdir: delentry %s failed, ret=%d\n", info.entry.name, ret);
942
#endif
943
 
944
        /* dput() temp if we didn't do it above */
945
out_dput:
946
        dput(temp);
947
 
948
out:
949
        Printk (("umsdos_rmdir %d\n", ret));
950
        return ret;
951
}
952
 
953
 
954
/*
955
 * Remove a file from the directory.
956
 *
957
 * #Specification: hard link / deleting a link
958
 * When we delete a file and this file is a link,
959
 * we must subtract 1 from the nlink field of the
960
 * hidden link.
961
 *
962
 * If the count goes to 0, we delete this hidden
963
 * link too.
964
 */
965
int UMSDOS_unlink (struct inode *dir, struct dentry *dentry)
966
{
967
        struct dentry *temp, *link = NULL;
968
        struct inode *inode;
969
        int ret;
970
        struct umsdos_info info;
971
 
972
Printk(("UMSDOS_unlink: entering %s/%s\n",
973
dentry->d_parent->d_name.name, dentry->d_name.name));
974
 
975
        ret = umsdos_nevercreat (dir, dentry, -EPERM);
976
        if (ret)
977
                goto out;
978
 
979
        ret = umsdos_parse (dentry->d_name.name, dentry->d_name.len, &info);
980
        if (ret)
981
                goto out;
982
 
983
        umsdos_lockcreate (dir);
984
        ret = umsdos_findentry (dentry->d_parent, &info, 1);
985
        if (ret) {
986
printk("UMSDOS_unlink: %s/%s not in EMD, ret=%d\n",
987
dentry->d_parent->d_name.name, dentry->d_name.name, ret);
988
                goto out_unlock;
989
        }
990
 
991
Printk (("UMSDOS_unlink %.*s ", info.fake.len, info.fake.fname));
992
 
993
        /*
994
         * Note! If this is a hardlink and the names are aliased,
995
         * the short-name lookup will return the hardlink dentry.
996
         * In order to get the correct (real) inode, we just drop
997
         * the original dentry.
998
         */
999
        if (info.entry.flags & UMSDOS_HLINK) {
1000
                d_drop(dentry);
1001
        }
1002
 
1003
        /* Do a real lookup to get the short name dentry */
1004
        temp = umsdos_covered(dentry->d_parent, info.fake.fname, info.fake.len);
1005
        ret = PTR_ERR(temp);
1006
        if (IS_ERR(temp))
1007
                goto out_unlock;
1008
 
1009
        /*
1010
         * Resolve hardlinks now, but defer processing until later.
1011
         */
1012
        if (info.entry.flags & UMSDOS_HLINK) {
1013
                link = umsdos_solve_hlink(dget(temp));
1014
        }
1015
 
1016
        /* Delete the EMD entry */
1017
        ret = umsdos_delentry (dentry->d_parent, &info, 0);
1018
        if (ret && ret != -ENOENT) {
1019
                printk(KERN_WARNING "UMSDOS_unlink: delentry %s, error=%d\n",
1020
                        info.entry.name, ret);
1021
                goto out_dput;
1022
        }
1023
 
1024
        ret = msdos_unlink(dir, temp);
1025
        if (!ret)
1026
                d_delete(temp);
1027
#ifdef UMSDOS_PARANOIA
1028
if (ret)
1029
printk("umsdos_unlink: %s/%s unlink failed, ret=%d\n",
1030
temp->d_parent->d_name.name, temp->d_name.name, ret);
1031
#endif
1032
 
1033
        /* dput() temp if we didn't do it above */
1034
out_dput:
1035
        dput(temp);
1036
 
1037
out_unlock:
1038
        umsdos_unlockcreate (dir);
1039
 
1040
        /*
1041
         * Now check for deferred handling of a hardlink.
1042
         */
1043
        if (!link)
1044
                goto out;
1045
 
1046
        if (IS_ERR(link)) {
1047
printk("umsdos_unlink: failed to resolve %s/%s\n",
1048
dentry->d_parent->d_name.name, dentry->d_name.name);
1049
                if (!ret)
1050
                        ret = PTR_ERR(link);
1051
                goto out;
1052
        }
1053
 
1054
Printk(("umsdos_unlink: link %s/%s deferred, pending ret=%d\n",
1055
link->d_parent->d_name.name, link->d_name.name, ret));
1056
 
1057
        /* already have an error? */
1058
        if (ret)
1059
                goto out_cleanup;
1060
 
1061
        /* make sure the link exists ... */
1062
        inode = link->d_inode;
1063
        if (!inode) {
1064
                printk(KERN_WARNING "umsdos_unlink: hard link not found\n");
1065
                goto out_cleanup;
1066
        }
1067
 
1068
        /*
1069
         * If this was the last linked reference, delete it now.
1070
         *
1071
         * N.B. Deadlock problem? We should be holding the lock
1072
         * for the hardlink's parent, but another process might
1073
         * be holding that lock waiting for us to finish ...
1074
         */
1075
        if (inode->i_nlink <= 1) {
1076
                ret = UMSDOS_unlink (link->d_parent->d_inode, link);
1077
                if (ret) {
1078
                        printk(KERN_WARNING
1079
                                "umsdos_unlink: link removal failed, ret=%d\n",
1080
                                 ret);
1081
                } else
1082
                        d_delete(link);
1083
        } else {
1084
                struct iattr newattrs;
1085
                inode->i_nlink--;
1086
                newattrs.ia_valid = 0;
1087
                ret = umsdos_notify_change_locked(link, &newattrs);
1088
                if (!ret)
1089
                        mark_inode_dirty(link->d_inode);
1090
        }
1091
 
1092
out_cleanup:
1093
        d_drop(link);
1094
        dput(link);
1095
 
1096
out:
1097
        Printk (("umsdos_unlink %d\n", ret));
1098
        return ret;
1099
}
1100
 
1101
/*
1102
 * Rename (move) a file.
1103
 */
1104
int UMSDOS_rename (struct inode *old_dir, struct dentry *old_dentry,
1105
                   struct inode *new_dir, struct dentry *new_dentry)
1106
{
1107
        int ret;
1108
 
1109
        ret = umsdos_nevercreat (new_dir, new_dentry, -EEXIST);
1110
        if (ret)
1111
                return ret;
1112
 
1113
                /*
1114
                 * If the target already exists, delete it first.
1115
                 */
1116
        if (new_dentry->d_inode) {
1117
                dget(new_dentry);
1118
                if (S_ISDIR(old_dentry->d_inode->i_mode))
1119
                        ret = UMSDOS_rmdir (new_dir, new_dentry);
1120
                else
1121
                        ret = UMSDOS_unlink (new_dir, new_dentry);
1122
                if (!ret)
1123
                        d_drop(new_dentry);
1124
                dput(new_dentry);
1125
                if (ret)
1126
                        return ret;
1127
        }
1128
        ret = umsdos_rename_f(old_dir, old_dentry, new_dir, new_dentry, 0);
1129
        return ret;
1130
}

powered by: WebSVN 2.1.0

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