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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 1628 jcastillo
/*
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
#include <linux/errno.h>
11
#include <linux/kernel.h>
12
#include <linux/sched.h>
13
#include <linux/types.h>
14
#include <linux/fcntl.h>
15
#include <linux/stat.h>
16
#include <linux/string.h>
17
#include <linux/msdos_fs.h>
18
#include <linux/umsdos_fs.h>
19
#include <linux/malloc.h>
20
 
21
#define PRINTK(x)
22
#define Printk(x)       printk x
23
 
24
#if 1
25
/*
26
        Wait for creation exclusivity.
27
        Return 0 if the dir was already available.
28
        Return 1 if a wait was necessary.
29
                When 1 is return, it means a wait was done. It does not
30
                mean the directory is available.
31
*/
32
static int umsdos_waitcreate(struct inode *dir)
33
{
34
        int ret = 0;
35
        if (dir->u.umsdos_i.u.dir_info.creating
36
                && dir->u.umsdos_i.u.dir_info.pid != current->pid){
37
                sleep_on(&dir->u.umsdos_i.u.dir_info.p);
38
                ret = 1;
39
        }
40
        return ret;
41
}
42
/*
43
        Wait for any lookup process to finish
44
*/
45
static void umsdos_waitlookup (struct inode *dir)
46
{
47
        while (dir->u.umsdos_i.u.dir_info.looking){
48
                sleep_on(&dir->u.umsdos_i.u.dir_info.p);
49
        }
50
}
51
/*
52
        Lock all other process out of this directory.
53
*/
54
void umsdos_lockcreate (struct inode *dir)
55
{
56
        /* #Specification: file creation / not atomic
57
                File creation is a two step process. First we create (allocate)
58
                an entry in the EMD file and then (using the entry offset) we
59
                build a unique name for MSDOS. We create this name in the msdos
60
                space.
61
 
62
                We have to use semaphore (sleep_on/wake_up) to prevent lookup
63
                into a directory when we create a file or directory and to
64
                prevent creation while a lookup is going on. Since many lookup
65
                may happen at the same time, the semaphore is a counter.
66
 
67
                Only one creation is allowed at the same time. This protection
68
                may not be necessary. The problem arise mainly when a lookup
69
                or a readdir is done while a file is partially created. The
70
                lookup process see that as a "normal" problem and silently
71
                erase the file from the EMD file. Normal because a file
72
                may be erased during a MSDOS session, but not removed from
73
                the EMD file.
74
 
75
                The locking is done on a directory per directory basis. Each
76
                directory inode has its wait_queue.
77
 
78
                For some operation like hard link, things even get worse. Many
79
                creation must occur at once (atomic). To simplify the design
80
                a process is allowed to recursively lock the directory for
81
                creation. The pid of the locking process is kept along with
82
                a counter so a second level of locking is granted or not.
83
        */
84
        /*
85
                Wait for any creation process to finish except
86
                if we (the process) own the lock
87
        */
88
        while (umsdos_waitcreate(dir)!=0);
89
        dir->u.umsdos_i.u.dir_info.creating++;
90
        dir->u.umsdos_i.u.dir_info.pid = current->pid;
91
        umsdos_waitlookup (dir);
92
}
93
/*
94
        Lock all other process out of those two directories.
95
*/
96
static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2)
97
{
98
        /*
99
                We must check that both directory are available before
100
                locking anyone of them. This is to avoid some deadlock.
101
                Thanks to dglaude@is1.vub.ac.be (GLAUDE DAVID) for pointing
102
                this to me.
103
        */
104
        while (1){
105
                if (umsdos_waitcreate(dir1)==0
106
                        && umsdos_waitcreate(dir2)==0){
107
                        /* We own both now */
108
                        dir1->u.umsdos_i.u.dir_info.creating++;
109
                        dir1->u.umsdos_i.u.dir_info.pid = current->pid;
110
                        dir2->u.umsdos_i.u.dir_info.creating++;
111
                        dir2->u.umsdos_i.u.dir_info.pid = current->pid;
112
                        break;
113
                }
114
        }
115
        umsdos_waitlookup(dir1);
116
        umsdos_waitlookup(dir2);
117
}
118
/*
119
        Wait until creation is finish in this directory.
120
*/
121
void umsdos_startlookup (struct inode *dir)
122
{
123
        while (umsdos_waitcreate (dir) != 0);
124
        dir->u.umsdos_i.u.dir_info.looking++;
125
}
126
 
127
/*
128
        Unlock the directory.
129
*/
130
void umsdos_unlockcreate (struct inode *dir)
131
{
132
        dir->u.umsdos_i.u.dir_info.creating--;
133
        if (dir->u.umsdos_i.u.dir_info.creating < 0){
134
                printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.creating < 0: %d"
135
                        ,dir->u.umsdos_i.u.dir_info.creating);
136
        }
137
        wake_up (&dir->u.umsdos_i.u.dir_info.p);
138
}
139
/*
140
        Tell directory lookup is over.
141
*/
142
void umsdos_endlookup (struct inode *dir)
143
{
144
        dir->u.umsdos_i.u.dir_info.looking--;
145
        if (dir->u.umsdos_i.u.dir_info.looking < 0){
146
                printk ("UMSDOS: dir->u.umsdos_i.u.dir_info.looking < 0: %d"
147
                        ,dir->u.umsdos_i.u.dir_info.looking);
148
        }
149
        wake_up (&dir->u.umsdos_i.u.dir_info.p);
150
}
151
#else
152
static void umsdos_lockcreate (struct inode *dir){}
153
static void umsdos_lockcreate2 (struct inode *dir1, struct inode *dir2){}
154
void umsdos_startlookup (struct inode *dir){}
155
static void umsdos_unlockcreate (struct inode *dir){}
156
void umsdos_endlookup (struct inode *dir){}
157
#endif
158
static int umsdos_nevercreat(
159
        struct inode *dir,
160
        const char *name,               /* Name of the file to add */
161
        int len,
162
        int errcod)                             /* Length of the name */
163
{
164
        int ret = 0;
165
        if (umsdos_is_pseudodos(dir,name,len)){
166
                /* #Specification: pseudo root / any file creation /DOS
167
                        The pseudo sub-directory /DOS can't be created!
168
                        EEXIST is returned.
169
 
170
                        The pseudo sub-directory /DOS can't be removed!
171
                        EPERM is returned.
172
                */
173
                ret = -EPERM;
174
                ret = errcod;
175
        }else if (name[0] == '.'
176
                && (len == 1 || (len == 2 && name[1] == '.'))){
177
                /* #Specification: create / . and ..
178
                        If one try to creates . or .., it always fail and return
179
                        EEXIST.
180
 
181
                        If one try to delete . or .., it always fail and return
182
                        EPERM.
183
 
184
                        This should be test at the VFS layer level to avoid
185
                        duplicating this in all file systems. Any comments ?
186
                */
187
                ret = errcod;
188
        }
189
        return ret;
190
}
191
 
192
/*
193
        Add a new file (ordinary or special) into the alternate directory.
194
        The file is added to the real MSDOS directory. If successful, it
195
        is then added to the EDM file.
196
 
197
        Return the status of the operation. 0 mean success.
198
*/
199
static int umsdos_create_any (
200
        struct inode *dir,
201
        const char *name,               /* Name of the file to add */
202
        int len,                                /* Length of the name */
203
        int mode,                               /* Permission bit + file type ??? */
204
        int rdev,                               /* major, minor or 0 for ordinary file */
205
                                                        /* and symlinks */
206
        char flags,
207
        struct inode **result)  /* Will hold the inode of the newly created */
208
                                                        /* file */
209
{
210
        int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
211
        if (ret == 0){
212
                struct umsdos_info info;
213
                ret = umsdos_parse (name,len,&info);
214
                *result = NULL;
215
                if (ret == 0){
216
                        info.entry.mode = mode;
217
                        info.entry.rdev = rdev;
218
                        info.entry.flags = flags;
219
                        info.entry.uid = current->fsuid;
220
                        info.entry.gid = (dir->i_mode & S_ISGID)
221
                                ? dir->i_gid : current->fsgid;
222
                        info.entry.ctime = info.entry.atime = info.entry.mtime
223
                                = CURRENT_TIME;
224
                        info.entry.nlink = 1;
225
                        umsdos_lockcreate(dir);
226
                        ret = umsdos_newentry (dir,&info);
227
                        if (ret == 0){
228
                                dir->i_count++;
229
                                ret = msdos_create (dir,info.fake.fname,info.fake.len
230
                                        ,S_IFREG|0777,result);
231
                                if (ret == 0){
232
                                        struct inode *inode = *result;
233
                                        umsdos_lookup_patch (dir,inode,&info.entry,info.f_pos);
234
                                        PRINTK (("inode %p[%ld] ",inode,inode->i_count));
235
                                        PRINTK (("Creation OK: [%d] %s %d pos %d\n",dir->i_ino
236
                                                ,info.fake.fname,current->pid,info.f_pos));
237
                                }else{
238
                                        /* #Specification: create / file exist in DOS
239
                                                Here is a situation. Trying to create a file with
240
                                                UMSDOS. The file is unknown to UMSDOS but already
241
                                                exist in the DOS directory.
242
 
243
                                                Here is what we are NOT doing:
244
 
245
                                                We could silently assume that everything is fine
246
                                                and allows the creation to succeed.
247
 
248
                                                It is possible not all files in the partition
249
                                                are mean to be visible from linux. By trying to create
250
                                                those file in some directory, one user may get access
251
                                                to those file without proper permissions. Looks like
252
                                                a security hole to me. Off course sharing a file system
253
                                                with DOS is some kind of security hole :-)
254
 
255
                                                So ?
256
 
257
                                                We return EEXIST in this case.
258
                                                The same is true for directory creation.
259
                                        */
260
                                        if (ret == -EEXIST){
261
                                                printk ("UMSDOS: out of sync, Creation error [%ld], "
262
                                                        "deleting %s %d %d pos %ld\n",dir->i_ino
263
                                                        ,info.fake.fname,-ret,current->pid,info.f_pos);
264
                                        }
265
                                        umsdos_delentry (dir,&info,0);
266
                                }
267
                                PRINTK (("umsdos_create %s ret = %d pos %d\n"
268
                                        ,info.fake.fname,ret,info.f_pos));
269
                        }
270
                        umsdos_unlockcreate(dir);
271
                }
272
        }
273
        iput (dir);
274
        return ret;
275
}
276
/*
277
        Initialise the new_entry from the old for a rename operation.
278
        (Only useful for umsdos_rename_f() below).
279
*/
280
static void umsdos_ren_init(
281
        struct umsdos_info *new_info,
282
        struct umsdos_info *old_info,
283
        int flags)              /* 0 == copy flags from old_name */
284
                                        /* != 0, this is the value of flags */
285
{
286
        new_info->entry.mode = old_info->entry.mode;
287
        new_info->entry.rdev = old_info->entry.rdev;
288
        new_info->entry.uid = old_info->entry.uid;
289
        new_info->entry.gid = old_info->entry.gid;
290
        new_info->entry.ctime = old_info->entry.ctime;
291
        new_info->entry.atime = old_info->entry.atime;
292
        new_info->entry.mtime = old_info->entry.mtime;
293
        new_info->entry.flags = flags ? flags : old_info->entry.flags;
294
        new_info->entry.nlink = old_info->entry.nlink;
295
}
296
 
297
#define chkstk() \
298
        if (STACK_MAGIC != *(unsigned long *)current->kernel_stack_page){\
299
                printk(KERN_ALERT "UMSDOS: %s magic %x != %lx ligne %d\n" \
300
                , current->comm,STACK_MAGIC \
301
                ,*(unsigned long *)current->kernel_stack_page \
302
                ,__LINE__); \
303
        }
304
 
305
/*
306
        Rename a file (move) in the file system.
307
*/
308
static int umsdos_rename_f(
309
        struct inode * old_dir,
310
        const char * old_name,
311
        int old_len,
312
        struct inode * new_dir,
313
        const char * new_name,
314
        int new_len,
315
        int flags)              /* 0 == copy flags from old_name */
316
                                        /* != 0, this is the value of flags */
317
{
318
        int ret = -EPERM;
319
        struct umsdos_info old_info;
320
        int old_ret = umsdos_parse (old_name,old_len,&old_info);
321
        struct umsdos_info new_info;
322
        int new_ret = umsdos_parse (new_name,new_len,&new_info);
323
chkstk();
324
        PRINTK (("umsdos_rename %d %d ",old_ret,new_ret));
325
        if (old_ret == 0 && new_ret == 0){
326
                umsdos_lockcreate2(old_dir,new_dir);
327
chkstk();
328
                PRINTK (("old findentry "));
329
                ret = umsdos_findentry(old_dir,&old_info,0);
330
chkstk();
331
                PRINTK (("ret %d ",ret));
332
                if (ret == 0){
333
                        /* check sticky bit on old_dir */
334
                        if ( !(old_dir->i_mode & S_ISVTX) || fsuser() ||
335
                            current->fsuid == old_info.entry.uid ||
336
                            current->fsuid == old_dir->i_uid ) {
337
                                /* Does new_name already exist? */
338
                                PRINTK(("new findentry "));
339
                                ret = umsdos_findentry(new_dir,&new_info,0);
340
                                if (ret != 0 || /* if destination file exists, are we allowed to replace it ? */
341
                                    !(new_dir->i_mode & S_ISVTX) || fsuser() ||
342
                                    current->fsuid == new_info.entry.uid ||
343
                                    current->fsuid == new_dir->i_uid ) {
344
                                        PRINTK (("new newentry "));
345
                                        umsdos_ren_init(&new_info,&old_info,flags);
346
                                        ret = umsdos_newentry (new_dir,&new_info);
347
chkstk();
348
                                        PRINTK (("ret %d %d ",ret,new_info.fake.len));
349
                                        if (ret == 0){
350
                                                PRINTK (("msdos_rename "));
351
                                                old_dir->i_count++;
352
                                                new_dir->i_count++;     /* Both inode are needed later */
353
                                                ret = msdos_rename (old_dir
354
                                                                    ,old_info.fake.fname,old_info.fake.len
355
                                                                    ,new_dir
356
                                                                    ,new_info.fake.fname,new_info.fake.len
357
                                                                    ,0);
358
chkstk();
359
                                                PRINTK (("after m_rename ret %d ",ret));
360
                                                if (ret != 0){
361
                                                        umsdos_delentry (new_dir,&new_info
362
                                                                         ,S_ISDIR(new_info.entry.mode));
363
chkstk();
364
                                                }else{
365
                                                        ret = umsdos_delentry (old_dir,&old_info
366
                                                                               ,S_ISDIR(old_info.entry.mode));
367
chkstk();
368
                                                        if (ret == 0){
369
                                                                /*
370
                                                                   This UMSDOS_lookup does not look very useful.
371
                                                                   It makes sure that the inode of the file will
372
                                                                   be correctly setup (umsdos_patch_inode()) in
373
                                                                   case it is already in use.
374
 
375
                                                                   Not very efficient ...
376
                                                                   */
377
                                                                struct inode *inode;
378
                                                                new_dir->i_count++;
379
                                                                PRINTK (("rename lookup len %d %d -- ",new_len,new_info.entry.flags));
380
                                                                ret = UMSDOS_lookup (new_dir,new_name,new_len
381
                                                                                     ,&inode);
382
chkstk();
383
                                                                if (ret != 0){
384
                                                                        printk ("UMSDOS: partial rename for file %s\n"
385
                                                                                ,new_info.entry.name);
386
                                                                }else{
387
                                                                        /*
388
                                                                           Update f_pos so notify_change will succeed
389
                                                                           if the file was already in use.
390
                                                                           */
391
                                                                        umsdos_set_dirinfo (inode,new_dir,new_info.f_pos);
392
chkstk();
393
                                                                        iput (inode);
394
                                                                }
395
                                                        }
396
                                                }
397
                                        }
398
                                }else{
399
                                        /* sticky bit set on new_dir */
400
                                        PRINTK(("sticky set on new "));
401
                                        ret = -EPERM;
402
                                }
403
                        }else{
404
                                /* sticky bit set on old_dir */
405
                                PRINTK(("sticky set on old "));
406
                                ret = -EPERM;
407
                        }
408
                }
409
                umsdos_unlockcreate(old_dir);
410
                umsdos_unlockcreate(new_dir);
411
        }
412
        iput (old_dir);
413
        iput (new_dir);
414
        PRINTK (("\n"));
415
        return ret;
416
}
417
/*
418
        Setup un Symbolic link or a (pseudo) hard link
419
        Return a negative error code or 0 if ok.
420
*/
421
static int umsdos_symlink_x(
422
        struct inode * dir,
423
        const char * name,
424
        int len,
425
        const char * symname,   /* name will point to this path */
426
        int mode,
427
        char flags)
428
{
429
        /* #Specification: symbolic links / strategy
430
                A symbolic link is simply a file which hold a path. It is
431
                implemented as a normal MSDOS file (not very space efficient :-()
432
 
433
                I see 2 different way to do it. One is to place the link data
434
                in unused entry of the EMD file. The other is to have a separate
435
                file dedicated to hold all symbolic links data.
436
 
437
                Let's go for simplicity...
438
        */
439
        struct inode *inode;
440
        int ret;
441
        dir->i_count++;         /* We keep the inode in case we need it */
442
                                                /* later */
443
        ret = umsdos_create_any (dir,name,len,mode,0,flags,&inode);
444
        PRINTK (("umsdos_symlink ret %d ",ret));
445
        if (ret == 0){
446
                int len = strlen(symname);
447
                struct file filp;
448
                filp.f_pos = 0;
449
                /* Make the inode acceptable to MSDOS */
450
                ret = umsdos_file_write_kmem (inode,&filp,symname,len);
451
                iput (inode);
452
                if (ret >= 0){
453
                        if (ret != len){
454
                                ret = -EIO;
455
                                printk ("UMSDOS: "
456
                                        "Can't write symbolic link data\n");
457
                        }else{
458
                                ret = 0;
459
                        }
460
                }
461
                if (ret != 0){
462
                        UMSDOS_unlink (dir,name,len);
463
                        dir = NULL;
464
                }
465
        }
466
        iput (dir);
467
        PRINTK (("\n"));
468
        return ret;
469
}
470
/*
471
        Setup un Symbolic link.
472
        Return a negative error code or 0 if ok.
473
*/
474
int UMSDOS_symlink(
475
        struct inode * dir,
476
        const char * name,
477
        int len,
478
        const char * symname)   /* name will point to this path */
479
{
480
        return umsdos_symlink_x (dir,name,len,symname,S_IFLNK|0777,0);
481
}
482
/*
483
        Add a link to an inode in a directory
484
*/
485
int UMSDOS_link (
486
        struct inode * oldinode,
487
        struct inode * dir,
488
        const char * name,
489
        int len)
490
{
491
        /* #Specification: hard link / strategy
492
                Well ... hard link are difficult to implement on top of an
493
                MsDOS fat file system. Unlike UNIX file systems, there are no
494
                inode. A directory entry hold the functionality of the inode
495
                and the entry.
496
 
497
                We will used the same strategy as a normal Unix file system
498
                (with inode) except we will do it symbolically (using paths).
499
 
500
                Because anything can happen during a DOS session (defragment,
501
                directory sorting, etc...), we can't rely on MsDOS pseudo
502
                inode number to record the link. For this reason, the link
503
                will be done using hidden symbolic links. The following
504
                scenario illustrate how it work.
505
 
506
                Given a file /foo/file
507
 
508
                #
509
                        ln /foo/file /tmp/file2
510
 
511
                        become internally
512
 
513
                        mv /foo/file /foo/-LINK1
514
                        ln -s /foo/-LINK1 /foo/file
515
                        ln -s /foo/-LINK1 /tmp/file2
516
                #
517
 
518
                Using this strategy, we can operate on /foo/file or /foo/file2.
519
                We can remove one and keep the other, like a normal Unix hard link.
520
                We can rename /foo/file or /tmp/file2 independently.
521
 
522
                The entry -LINK1 will be hidden. It will hold a link count.
523
                When all link are erased, the hidden file is erased too.
524
        */
525
        /* #Specification: weakness / hard link
526
                The strategy for hard link introduces a side effect that
527
                may or may not be acceptable. Here is the sequence
528
 
529
                #
530
                mkdir subdir1
531
                touch subdir1/file
532
                mkdir subdir2
533
                ln    subdir1/file subdir2/file
534
                rm    subdir1/file
535
                rmdir subdir1
536
                rmdir: subdir1: Directory not empty
537
                #
538
 
539
                This happen because there is an invisible file (--link) in
540
                subdir1 which is referenced by subdir2/file.
541
 
542
                Any idea ?
543
        */
544
        /* #Specification: weakness / hard link / rename directory
545
                Another weakness of hard link come from the fact that
546
                it is based on hidden symbolic links. Here is an example.
547
 
548
                #
549
                mkdir /subdir1
550
                touch /subdir1/file
551
                mkdir /subdir2
552
                ln    /subdir1/file subdir2/file
553
                mv    /subdir1 subdir3
554
                ls -l /subdir2/file
555
                #
556
 
557
                Since /subdir2/file is a hidden symbolic link
558
                to /subdir1/..hlinkNNN, accessing it will fail since
559
                /subdir1 does not exist anymore (has been renamed).
560
        */
561
        int ret = 0;
562
        if (S_ISDIR(oldinode->i_mode)){
563
                /* #Specification: hard link / directory
564
                        A hard link can't be made on a directory. EPERM is returned
565
                        in this case.
566
                */
567
                ret = -EPERM;
568
        }else if ((ret = umsdos_nevercreat(dir,name,len,-EPERM))==0){
569
                struct inode *olddir;
570
                ret = umsdos_get_dirowner(oldinode,&olddir);
571
                PRINTK (("umsdos_link dir_owner = %d -> %p [%ld] "
572
                        ,oldinode->u.umsdos_i.i_dir_owner,olddir,olddir->i_count));
573
                if (ret == 0){
574
                        struct umsdos_dirent entry;
575
                        umsdos_lockcreate2(dir,olddir);
576
                        ret = umsdos_inode2entry (olddir,oldinode,&entry);
577
                        if (ret == 0){
578
                                PRINTK (("umsdos_link :%s: ino %d flags %d "
579
                                        ,entry.name
580
                                        ,oldinode->i_ino,entry.flags));
581
                                if (!(entry.flags & UMSDOS_HIDDEN)){
582
                                        /* #Specification: hard link / first hard link
583
                                                The first time a hard link is done on a file, this
584
                                                file must be renamed and hidden. Then an internal
585
                                                symbolic link must be done on the hidden file.
586
 
587
                                                The second link is done after on this hidden file.
588
 
589
                                                It is expected that the Linux MSDOS file system
590
                                                keeps the same pseudo inode when a rename operation
591
                                                is done on a file in the same directory.
592
                                        */
593
                                        struct umsdos_info info;
594
                                        ret = umsdos_newhidden (olddir,&info);
595
                                        if (ret == 0){
596
                                                olddir->i_count+=2;
597
                                                PRINTK (("olddir[%ld] ",olddir->i_count));
598
                                                ret = umsdos_rename_f (olddir,entry.name
599
                                                        ,entry.name_len
600
                                                        ,olddir,info.entry.name,info.entry.name_len
601
                                                        ,UMSDOS_HIDDEN);
602
                                                if (ret == 0){
603
                                                        char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
604
                                                        if (path == NULL){
605
                                                                ret = -ENOMEM;
606
                                                        }else{
607
                                                                PRINTK (("olddir[%ld] ",olddir->i_count));
608
                                                                ret = umsdos_locate_path (oldinode,path);
609
                                                                PRINTK (("olddir[%ld] ",olddir->i_count));
610
                                                                if (ret == 0){
611
                                                                        olddir->i_count++;
612
                                                                        ret = umsdos_symlink_x (olddir
613
                                                                                ,entry.name
614
                                                                                ,entry.name_len,path
615
                                                                                ,S_IFREG|0777,UMSDOS_HLINK);
616
                                                                        if (ret == 0){
617
                                                                                dir->i_count++;
618
                                                                                ret = umsdos_symlink_x (dir,name,len
619
                                                                                        ,path
620
                                                                                        ,S_IFREG|0777,UMSDOS_HLINK);
621
                                                                        }
622
                                                                }
623
                                                                kfree (path);
624
                                                        }
625
                                                }
626
                                        }
627
                                }else{
628
                                        char *path = (char*)kmalloc(PATH_MAX,GFP_KERNEL);
629
                                        if (path == NULL){
630
                                                ret = -ENOMEM;
631
                                        }else{
632
                                                ret = umsdos_locate_path (oldinode,path);
633
                                                if (ret == 0){
634
                                                        dir->i_count++;
635
                                                        ret = umsdos_symlink_x (dir,name,len,path
636
                                                                                        ,S_IFREG|0777,UMSDOS_HLINK);
637
                                                }
638
                                                kfree (path);
639
                                        }
640
                                }
641
                        }
642
                        umsdos_unlockcreate(olddir);
643
                        umsdos_unlockcreate(dir);
644
                }
645
                iput (olddir);
646
        }
647
        if (ret == 0){
648
                struct iattr newattrs;
649
                oldinode->i_nlink++;
650
                newattrs.ia_valid = 0;
651
                ret = UMSDOS_notify_change(oldinode, &newattrs);
652
        }
653
        iput (oldinode);
654
        iput (dir);
655
        PRINTK (("umsdos_link %d\n",ret));
656
        return ret;
657
}
658
/*
659
        Add a new file into the alternate directory.
660
        The file is added to the real MSDOS directory. If successful, it
661
        is then added to the EDM file.
662
 
663
        Return the status of the operation. 0 mean success.
664
*/
665
int UMSDOS_create (
666
        struct inode *dir,
667
        const char *name,               /* Name of the file to add */
668
        int len,                                /* Length of the name */
669
        int mode,                               /* Permission bit + file type ??? */
670
        struct inode **result)  /* Will hold the inode of the newly created */
671
                                                        /* file */
672
{
673
        return umsdos_create_any (dir,name,len,mode,0,0,result);
674
}
675
/*
676
        Add a sub-directory in a directory
677
*/
678
int UMSDOS_mkdir(
679
        struct inode * dir,
680
        const char * name,
681
        int len,
682
        int mode)
683
{
684
        int ret = umsdos_nevercreat(dir,name,len,-EEXIST);
685
        if (ret == 0){
686
                struct umsdos_info info;
687
                ret = umsdos_parse (name,len,&info);
688
                PRINTK (("umsdos_mkdir %d\n",ret));
689
                if (ret == 0){
690
                        info.entry.mode = mode | S_IFDIR;
691
                        info.entry.rdev = 0;
692
                        info.entry.uid = current->fsuid;
693
                        info.entry.gid = (dir->i_mode & S_ISGID)
694
                                ? dir->i_gid : current->fsgid;
695
                        info.entry.ctime = info.entry.atime = info.entry.mtime
696
                                = CURRENT_TIME;
697
                        info.entry.flags = 0;
698
                        umsdos_lockcreate(dir);
699
                        info.entry.nlink = 1;
700
                        ret = umsdos_newentry (dir,&info);
701
                        PRINTK (("newentry %d ",ret));
702
                        if (ret == 0){
703
                                dir->i_count++;
704
                                ret = msdos_mkdir (dir,info.fake.fname,info.fake.len,mode);
705
                                if (ret != 0){
706
                                        umsdos_delentry (dir,&info,1);
707
                                        /* #Specification: mkdir / Directory already exist in DOS
708
                                                We do the same thing as for file creation.
709
                                                For all user it is an error.
710
                                        */
711
                                }else{
712
                                        /* #Specification: mkdir / umsdos directory / create EMD
713
                                                When we created a new sub-directory in a UMSDOS
714
                                                directory (one with full UMSDOS semantic), we
715
                                                create immediately an EMD file in the new
716
                                                sub-directory so it inherit UMSDOS semantic.
717
                                        */
718
                                        struct inode *subdir;
719
                                        ret = umsdos_real_lookup (dir,info.fake.fname
720
                                                ,info.fake.len,&subdir);
721
                                        if (ret == 0){
722
                                                struct inode *result;
723
                                                ret = msdos_create (subdir,UMSDOS_EMD_FILE
724
                                                        ,UMSDOS_EMD_NAMELEN,S_IFREG|0777,&result);
725
                                                subdir = NULL;
726
                                                iput (result);
727
                                        }
728
                                        if (ret < 0){
729
                                                printk ("UMSDOS: Can't create empty --linux-.---\n");
730
                                        }
731
                                        iput (subdir);
732
                                }
733
                        }
734
                        umsdos_unlockcreate(dir);
735
                }
736
        }
737
        PRINTK (("umsdos_mkdir %d\n",ret));
738
        iput (dir);
739
        return ret;
740
}
741
/*
742
        Add a new device special file into a directory.
743
*/
744
int UMSDOS_mknod(
745
        struct inode * dir,
746
        const char * name,
747
        int len,
748
        int mode,
749
        int rdev)
750
{
751
        /* #Specification: Special files / strategy
752
                Device special file, pipes, etc ... are created like normal
753
                file in the msdos file system. Of course they remain empty.
754
 
755
                One strategy was to create those files only in the EMD file
756
                since they were not important for MSDOS. The problem with
757
                that, is that there were not getting inode number allocated.
758
                The MSDOS filesystems is playing a nice game to fake inode
759
                number, so why not use it.
760
 
761
                The absence of inode number compatible with those allocated
762
                for ordinary files was causing major trouble with hard link
763
                in particular and other parts of the kernel I guess.
764
        */
765
        struct inode *inode;
766
        int ret = umsdos_create_any (dir,name,len,mode,rdev,0,&inode);
767
        iput (inode);
768
        return ret;
769
}
770
 
771
/*
772
        Remove a sub-directory.
773
*/
774
int UMSDOS_rmdir(
775
        struct inode * dir,
776
        const char * name,
777
        int len)
778
{
779
        /* #Specification: style / iput strategy
780
                In the UMSDOS project, I am trying to apply a single
781
                programming style regarding inode management. Many
782
                entry point are receiving an inode to act on, and must
783
                do an iput() as soon as they are finished with
784
                the inode.
785
 
786
                For simple case, there is no problem. When you introduce
787
                error checking, you end up with many iput placed around the
788
                code.
789
 
790
                The coding style I use all around is one where I am trying
791
                to provide independent flow logic (I don't know how to
792
                name this). With this style, code is easier to understand
793
                but you rapidly get iput() all around. Here is an exemple
794
                of what I am trying to avoid.
795
 
796
                #
797
                if (a){
798
                        ...
799
                        if(b){
800
                                ...
801
                        }
802
                        ...
803
                        if (c){
804
                                // Complex state. Was b true ?
805
                                ...
806
                        }
807
                        ...
808
                }
809
                // Weird state
810
                if (d){
811
                        // ...
812
                }
813
                // Was iput finally done ?
814
                return status;
815
                #
816
 
817
                Here is the style I am using. Still sometime I do the
818
                first when things are very simple (or very complicated :-( )
819
 
820
                #
821
                if (a){
822
                        if (b){
823
                                ...
824
                        }else if (c){
825
                                // A single state gets here
826
                        }
827
                }else if (d){
828
                        ...
829
                }
830
                return status;
831
                #
832
 
833
                Again, while this help clarifying the code, I often get a lot
834
                of iput(), unlike the first style, where I can place few
835
                "strategic" iput(). "strategic" also mean, more difficult
836
                to place.
837
 
838
                So here is the style I will be using from now on in this project.
839
                There is always an iput() at the end of a function (which has
840
                to do an iput()). One iput by inode. There is also one iput()
841
                at the places where a successful operation is achieved. This
842
                iput() is often done by a sub-function (often from the msdos
843
                file system). So I get one too many iput() ? At the place
844
                where an iput() is done, the inode is simply nulled, disabling
845
                the last one.
846
 
847
                #
848
                if (a){
849
                        if (b){
850
                                ...
851
                        }else if (c){
852
                                msdos_rmdir(dir,...);
853
                                dir = NULL;
854
                        }
855
                }else if (d){
856
                        ...
857
                }
858
                iput (dir);
859
                return status;
860
                #
861
 
862
                Note that the umsdos_lockcreate() and umsdos_unlockcreate() function
863
                pair goes against this practice of "forgetting" the inode as soon
864
                as possible.
865
        */
866
        int ret = umsdos_nevercreat(dir,name,len,-EPERM);
867
        if (ret == 0){
868
                struct inode *sdir;
869
                dir->i_count++;
870
                ret = UMSDOS_lookup (dir,name,len,&sdir);
871
                PRINTK (("rmdir lookup %d ",ret));
872
                if (ret == 0){
873
                        int empty;
874
                        umsdos_lockcreate(dir);
875
                        if (sdir->i_count > 1){
876
                                ret = -EBUSY;
877
                        }else if ((empty = umsdos_isempty (sdir)) != 0){
878
                                PRINTK (("isempty %d i_count %ld ",empty,sdir->i_count));
879
                                /* check sticky bit */
880
                                if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
881
                                    current->fsuid == sdir->i_uid ||
882
                                    current->fsuid == dir->i_uid ) {
883
                                        if (empty == 1){
884
                                                /* We have to removed the EMD file */
885
                                                ret = msdos_unlink(sdir,UMSDOS_EMD_FILE
886
                                                                   ,UMSDOS_EMD_NAMELEN);
887
                                                sdir = NULL;
888
                                        }
889
                                        /* sdir must be free before msdos_rmdir() */
890
                                        iput (sdir);
891
                                        sdir = NULL;
892
                                        PRINTK (("isempty ret %d nlink %d ",ret,dir->i_nlink));
893
                                        if (ret == 0){
894
                                                struct umsdos_info info;
895
                                                dir->i_count++;
896
                                                umsdos_parse (name,len,&info);
897
                                                /* The findentry is there only to complete */
898
                                                /* the mangling */
899
                                                umsdos_findentry (dir,&info,2);
900
                                                ret = msdos_rmdir (dir,info.fake.fname
901
                                                                   ,info.fake.len);
902
                                                if (ret == 0){
903
                                                        ret = umsdos_delentry (dir,&info,1);
904
                                                }
905
                                        }
906
                                }else{
907
                                        /* sticky bit set and we don't have permission */
908
                                        PRINTK(("sticky set "));
909
                                        ret = -EPERM;
910
                                }
911
                        }else{
912
                                /*
913
                                        The subdirectory is not empty, so leave it there
914
                                */
915
                                ret = -ENOTEMPTY;
916
                        }
917
                        iput(sdir);
918
                        umsdos_unlockcreate(dir);
919
                }
920
        }
921
        iput (dir);
922
        PRINTK (("umsdos_rmdir %d\n",ret));
923
        return ret;
924
}
925
/*
926
        Remove a file from the directory.
927
*/
928
int UMSDOS_unlink (
929
        struct inode * dir,
930
        const char * name,
931
        int len)
932
{
933
        int ret = umsdos_nevercreat(dir,name,len,-EPERM);
934
        if (ret == 0){
935
                struct umsdos_info info;
936
                ret = umsdos_parse (name,len,&info);
937
                if (ret == 0){
938
                        umsdos_lockcreate(dir);
939
                        ret = umsdos_findentry(dir,&info,1);
940
                        if (ret == 0){
941
                                PRINTK (("UMSDOS_unlink %s ",info.fake.fname));
942
                                /* check sticky bit */
943
                                if ( !(dir->i_mode & S_ISVTX) || fsuser() ||
944
                                    current->fsuid == info.entry.uid ||
945
                                    current->fsuid == dir->i_uid ) {
946
                                        if (info.entry.flags & UMSDOS_HLINK){
947
                                                /* #Specification: hard link / deleting a link
948
                                                   When we deletes a file, and this file is a link
949
                                                   we must subtract 1 to the nlink field of the
950
                                                   hidden link.
951
 
952
                                                   If the count goes to 0, we delete this hidden
953
                                                   link too.
954
                                                   */
955
                                                /*
956
                                                   First, get the inode of the hidden link
957
                                                   using the standard lookup function.
958
                                                   */
959
                                                struct inode *inode;
960
                                                dir->i_count++;
961
                                                ret = UMSDOS_lookup (dir,name,len,&inode);
962
                                                if (ret == 0){
963
                                                        PRINTK (("unlink nlink = %d ",inode->i_nlink));
964
                                                        inode->i_nlink--;
965
                                                        if (inode->i_nlink == 0){
966
                                                                struct inode *hdir = iget(inode->i_sb
967
                                                                                          ,inode->u.umsdos_i.i_dir_owner);
968
                                                                struct umsdos_dirent entry;
969
                                                                ret = umsdos_inode2entry (hdir,inode,&entry);
970
                                                                if (ret == 0){
971
                                                                        ret = UMSDOS_unlink (hdir,entry.name
972
                                                                                             ,entry.name_len);
973
                                                                }else{
974
                                                                        iput (hdir);
975
                                                                }
976
                                                        }else{
977
                                                                struct iattr newattrs;
978
                                                                newattrs.ia_valid = 0;
979
                                                                ret = UMSDOS_notify_change (inode, &newattrs);
980
                                                        }
981
                                                        iput (inode);
982
                                                }
983
                                        }
984
                                        if (ret == 0){
985
                                                ret = umsdos_delentry (dir,&info,0);
986
                                                if (ret == 0){
987
                                                        PRINTK (("Avant msdos_unlink %s ",info.fake.fname));
988
                                                        dir->i_count++;
989
                                                        ret = msdos_unlink_umsdos (dir,info.fake.fname
990
                                                                                   ,info.fake.len);
991
                                                        PRINTK (("msdos_unlink %s %o ret %d ",info.fake.fname
992
                                                                 ,info.entry.mode,ret));
993
                                                }
994
                                        }
995
                                }else{
996
                                        /* sticky bit set and we've not got permission */
997
                                        PRINTK(("sticky set "));
998
                                        ret = -EPERM;
999
                                }
1000
                        }
1001
                        umsdos_unlockcreate(dir);
1002
                }
1003
        }
1004
        iput (dir);
1005
        PRINTK (("umsdos_unlink %d\n",ret));
1006
        return ret;
1007
}
1008
 
1009
/*
1010
        Rename a file (move) in the file system.
1011
*/
1012
int UMSDOS_rename(
1013
        struct inode * old_dir,
1014
        const char * old_name,
1015
        int old_len,
1016
        struct inode * new_dir,
1017
        const char * new_name,
1018
        int new_len,
1019
        int must_be_dir)
1020
{
1021
        /* #Specification: weakness / rename
1022
                There is a case where UMSDOS rename has a different behavior
1023
                than normal UNIX file system. Renaming an open file across
1024
                directory boundary does not work. Renaming an open file within
1025
                a directory does work however.
1026
 
1027
                The problem (not sure) is in the linux VFS msdos driver.
1028
                I believe this is not a bug but a design feature, because
1029
                an inode number represent some sort of directory address
1030
                in the MSDOS directory structure. So moving the file into
1031
                another directory does not preserve the inode number.
1032
        */
1033
        int ret = umsdos_nevercreat(new_dir,new_name,new_len,-EEXIST);
1034
        if (ret == 0){
1035
                /* umsdos_rename_f eat the inode and we may need those later */
1036
                old_dir->i_count++;
1037
                new_dir->i_count++;
1038
                ret = umsdos_rename_f (old_dir,old_name,old_len,new_dir,new_name
1039
                        ,new_len,0);
1040
                if (ret == -EEXIST){
1041
                        /* #Specification: rename / new name exist
1042
                                If the destination name already exist, it will
1043
                                silently be removed. EXT2 does it this way
1044
                                and this is the spec of SUNOS. So does UMSDOS.
1045
 
1046
                                If the destination is an empty directory it will
1047
                                also be removed.
1048
                        */
1049
                        /* #Specification: rename / new name exist / possible flaw
1050
                                The code to handle the deletion of the target (file
1051
                                and directory) use to be in umsdos_rename_f, surrounded
1052
                                by proper directory locking. This was insuring that only
1053
                                one process could achieve a rename (modification) operation
1054
                                in the source and destination directory. This was also
1055
                                insuring the operation was "atomic".
1056
 
1057
                                This has been changed because this was creating a kernel
1058
                                stack overflow (stack is only 4k in the kernel). To avoid
1059
                                the code doing the deletion of the target (if exist) has
1060
                                been moved to a upper layer. umsdos_rename_f is tried
1061
                                once and if it fails with EEXIST, the target is removed
1062
                                and umsdos_rename_f is done again.
1063
 
1064
                                This makes the code cleaner and (not sure) solve a
1065
                                deadlock problem one tester was experiencing.
1066
 
1067
                                The point is to mention that possibly, the semantic of
1068
                                "rename" may be wrong. Anyone dare to check that :-)
1069
                                Be aware that IF it is wrong, to produce the problem you
1070
                                will need two process trying to rename a file to the
1071
                                same target at the same time. Again, I am not sure it
1072
                                is a problem at all.
1073
                        */
1074
                        /* This is not super efficient but should work */
1075
                        new_dir->i_count++;
1076
                        ret = UMSDOS_unlink (new_dir,new_name,new_len);
1077
chkstk();
1078
                        PRINTK (("rename unlink ret %d %d -- ",ret,new_len));
1079
                        if (ret == -EISDIR){
1080
                                new_dir->i_count++;
1081
                                ret = UMSDOS_rmdir (new_dir,new_name,new_len);
1082
chkstk();
1083
                                PRINTK (("rename rmdir ret %d -- ",ret));
1084
                        }
1085
                        if (ret == 0){
1086
                                ret = umsdos_rename_f (old_dir,old_name,old_len
1087
                                        ,new_dir,new_name,new_len,0);
1088
                                new_dir = old_dir = NULL;
1089
                        }
1090
                }
1091
        }
1092
        iput (new_dir);
1093
        iput (old_dir);
1094
        return ret;
1095
}
1096
 

powered by: WebSVN 2.1.0

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