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

Subversion Repositories or1k

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

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

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  Linux/fs/xiafs/namei.c
3
 *
4
 *  Copyright (C) Q. Frank Xia, 1993.
5
 *
6
 *  Based on Linus' minix/namei.c
7
 *  Copyright (C) Linus Torvalds, 1991, 1992.
8
 *
9
 *  This software may be redistributed per Linux Copyright.
10
 */
11
 
12
#include <linux/sched.h>
13
#include <linux/xia_fs.h>
14
#include <linux/kernel.h>
15
#include <linux/string.h>
16
#include <linux/stat.h>
17
#include <linux/fcntl.h>
18
#include <linux/errno.h>
19
 
20
#include <asm/segment.h>
21
 
22
#include "xiafs_mac.h"
23
 
24
#define RNDUP4(x)       ((3+(u_long)(x)) & ~3)
25
/*
26
 * ok, we cannot use strncmp, as the name is not in our data space.
27
 * Thus we'll have to use xiafs_match. No big problem. Match also makes
28
 * some sanity tests.
29
 *
30
 * NOTE! unlike strncmp, xiafs_match returns 1 for success, 0 for failure.
31
 */
32
static int xiafs_match(int len, const char * name, struct xiafs_direct * dep)
33
{
34
    int i;
35
 
36
    if (!dep || !dep->d_ino || len > _XIAFS_NAME_LEN)
37
        return 0;
38
    /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
39
    if (!len && (dep->d_name[0]=='.') && (dep->d_name[1]=='\0'))
40
        return 1;
41
    if (len != dep->d_name_len)
42
        return 0;
43
    for (i=0; i < len; i++)
44
        if (*name++ != dep->d_name[i])
45
            return 0;
46
    return 1;
47
}
48
 
49
/*
50
 *      xiafs_find_entry()
51
 *
52
 * finds an entry in the specified directory with the wanted name. It
53
 * returns the cache buffer in which the entry was found, and the entry
54
 * itself (as a parameter - res_dir). It does NOT read the inode of the
55
 * entry - you'll have to do that yourself if you want to.
56
 */
57
static struct buffer_head *
58
xiafs_find_entry(struct inode * inode, const char * name, int namelen,
59
               struct xiafs_direct ** res_dir, struct xiafs_direct ** res_pre)
60
{
61
    int i, zones, pos;
62
    struct buffer_head * bh;
63
    struct xiafs_direct * dep, * dep_pre;
64
 
65
    *res_dir = NULL;
66
    if (!inode)
67
        return NULL;
68
    if (namelen > _XIAFS_NAME_LEN)
69
        return NULL;
70
 
71
    if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb) - 1)) {
72
        printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR);
73
        return NULL;
74
    }
75
    zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb);
76
    for (i=0; i < zones; i++ ) {
77
        bh = xiafs_bread(inode, i, 0);
78
        if (!bh)
79
            continue;
80
        dep_pre=dep=(struct xiafs_direct *)bh->b_data;
81
        if (!i && (dep->d_rec_len != 12 || !dep->d_ino ||
82
                   dep->d_name_len != 1 || strcmp(dep->d_name, "."))) {
83
            printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
84
            brelse(bh);
85
            return NULL;
86
        }
87
        pos = 0;
88
        while ( pos < XIAFS_ZSIZE(inode->i_sb) ) {
89
            if (dep->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
90
                dep->d_rec_len < 12 ||
91
                dep->d_rec_len+(char *)dep > bh->b_data+XIAFS_ZSIZE(inode->i_sb) ||
92
                dep->d_name_len + 8 > dep->d_rec_len || dep->d_name_len <= 0 ||
93
                dep->d_name[dep->d_name_len] ) {
94
                brelse(bh);
95
                return NULL;
96
            }
97
            if (xiafs_match(namelen, name, dep)) {
98
                *res_dir=dep;
99
                if (res_pre)
100
                    *res_pre=dep_pre;
101
                return bh;
102
            }
103
            pos += dep->d_rec_len;
104
            dep_pre=dep;
105
            dep=(struct xiafs_direct *)(bh->b_data + pos);
106
        }
107
        brelse(bh);
108
        if (pos > XIAFS_ZSIZE(inode->i_sb)) {
109
            printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
110
            return NULL;
111
        }
112
    }
113
    return NULL;
114
}
115
 
116
int xiafs_lookup(struct inode * dir, const char * name, int len,
117
               struct inode ** result)
118
{
119
    int ino;
120
    struct xiafs_direct * dep;
121
    struct buffer_head * bh;
122
 
123
    *result = NULL;
124
    if (!dir)
125
        return -ENOENT;
126
    if (!S_ISDIR(dir->i_mode)) {
127
        iput(dir);
128
        return -ENOENT;
129
    }
130
    if (!(bh = xiafs_find_entry(dir, name, len, &dep, NULL))) {
131
        iput(dir);
132
        return -ENOENT;
133
    }
134
    ino = dep->d_ino;
135
    brelse(bh);
136
    if (!(*result = iget(dir->i_sb, ino))) {
137
        iput(dir);
138
        return -EACCES;
139
    }
140
    iput(dir);
141
    return 0;
142
}
143
 
144
/*
145
 *      xiafs_add_entry()
146
 *
147
 * adds a file entry to the specified directory, using the same
148
 * semantics as xiafs_find_entry(). It returns NULL if it failed.
149
 *
150
 * NOTE!! The inode part of 'de' is left at 0 - which means you
151
 * may not sleep between calling this and putting something into
152
 * the entry, as someone else might have used it while you slept.
153
 */
154
static struct buffer_head * xiafs_add_entry(struct inode * dir,
155
        const char * name, int namelen, struct xiafs_direct ** res_dir,
156
        struct xiafs_direct ** res_pre)
157
{
158
    int i, pos, offset;
159
    struct buffer_head * bh;
160
    struct xiafs_direct * de, * de_pre;
161
 
162
    *res_dir = NULL;
163
    if (!dir || !namelen || namelen > _XIAFS_NAME_LEN)
164
        return NULL;
165
 
166
    if (dir->i_size & (XIAFS_ZSIZE(dir->i_sb) - 1)) {
167
        printk("XIA-FS: bad dir size (%s %d)\n", WHERE_ERR);
168
        return NULL;
169
    }
170
    pos=0;
171
    for ( ; ; ) {
172
        bh =  xiafs_bread(dir, pos >> XIAFS_ZSIZE_BITS(dir->i_sb), pos ? 1:0);
173
        if (!bh)
174
            return NULL;
175
        de_pre=de=(struct xiafs_direct *)bh->b_data;
176
        if (!pos) {
177
            if (de->d_rec_len != 12 || !de->d_ino || de->d_name_len != 1 ||
178
                strcmp(de->d_name, ".")) {
179
                printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
180
                brelse(bh);
181
                return NULL;
182
            }
183
            offset = 12;
184
            de_pre=de=(struct xiafs_direct *)(bh->b_data+12);
185
        } else
186
            offset = 0;
187
        while (offset < XIAFS_ZSIZE(dir->i_sb)) {
188
            if (pos >= dir->i_size) {
189
                de->d_ino=0;
190
                de->d_name_len=0;
191
                de->d_name[0]=0;
192
                de->d_rec_len=XIAFS_ZSIZE(dir->i_sb);
193
                dir->i_size += XIAFS_ZSIZE(dir->i_sb);
194
                dir->i_dirt = 1;
195
            } else {
196
                if (de->d_ino > dir->i_sb->u.xiafs_sb.s_ninodes ||
197
                    de->d_rec_len < 12 ||
198
                    (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(dir->i_sb) ||
199
                    de->d_name_len + 8 > de->d_rec_len ||
200
                    de->d_name[de->d_name_len]) {
201
                    printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
202
                    brelse(bh);
203
                    return NULL;
204
                }
205
                if (de->d_ino &&
206
                    RNDUP4(de->d_name_len)+RNDUP4(namelen)+16<=de->d_rec_len) {
207
                    i=RNDUP4(de->d_name_len)+8;
208
                    de_pre=de;
209
                    de=(struct xiafs_direct *)(i+(u_char *)de_pre);
210
                    de->d_ino=0;
211
                    de->d_rec_len=de_pre->d_rec_len-i;
212
                    de_pre->d_rec_len=i;
213
                }
214
            }
215
            if (!de->d_ino && RNDUP4(namelen)+8 <= de->d_rec_len) {
216
                /*
217
                 * XXX all times should be set by caller upon successful
218
                 * completion.
219
                 */
220
                dir->i_ctime = dir->i_mtime = CURRENT_TIME;
221
                dir->i_dirt = 1;
222
                memcpy(de->d_name, name, namelen);
223
                de->d_name[namelen]=0;
224
                de->d_name_len=namelen;
225
                mark_buffer_dirty(bh, 1);
226
                *res_dir = de;
227
                if (res_pre)
228
                    *res_pre = de_pre;
229
                return bh;
230
            }
231
            offset+=de->d_rec_len;
232
            de_pre=de;
233
            de=(struct xiafs_direct *)(bh->b_data+offset);
234
        }
235
        brelse(bh);
236
        if (offset > XIAFS_ZSIZE(dir->i_sb)) {
237
            printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
238
            return NULL;
239
        }
240
        pos+=XIAFS_ZSIZE(dir->i_sb);
241
    }
242
    return NULL;
243
}
244
 
245
int xiafs_create(struct inode * dir, const char * name, int len, int mode,
246
        struct inode ** result)
247
{
248
    struct inode * inode;
249
    struct buffer_head * bh;
250
    struct xiafs_direct * de;
251
 
252
    *result = NULL;
253
    if (!dir)
254
        return -ENOENT;
255
    inode = xiafs_new_inode(dir);
256
    if (!inode) {
257
        iput(dir);
258
        return -ENOSPC;
259
    }
260
    inode->i_op = &xiafs_file_inode_operations;
261
    inode->i_mode = mode;
262
    inode->i_dirt = 1;
263
    bh = xiafs_add_entry(dir, name, len, &de, NULL);
264
    if (!bh) {
265
        inode->i_nlink--;
266
        inode->i_dirt = 1;
267
        iput(inode);
268
        iput(dir);
269
        return -ENOSPC;
270
    }
271
    de->d_ino = inode->i_ino;
272
    mark_buffer_dirty(bh, 1);
273
    brelse(bh);
274
    iput(dir);
275
    *result = inode;
276
    return 0;
277
}
278
 
279
int xiafs_mknod(struct inode *dir, const char *name, int len, int mode, int rdev)
280
{
281
    struct inode * inode;
282
    struct buffer_head * bh;
283
    struct xiafs_direct * de;
284
 
285
    if (!dir)
286
        return -ENOENT;
287
    bh = xiafs_find_entry(dir,name,len,&de, NULL);
288
    if (bh) {
289
        brelse(bh);
290
        iput(dir);
291
        return -EEXIST;
292
    }
293
    inode = xiafs_new_inode(dir);
294
    if (!inode) {
295
        iput(dir);
296
        return -ENOSPC;
297
    }
298
    inode->i_uid = current->fsuid;
299
    inode->i_mode = mode;
300
    inode->i_op = NULL;
301
    if (S_ISREG(inode->i_mode))
302
        inode->i_op = &xiafs_file_inode_operations;
303
    else if (S_ISDIR(inode->i_mode)) {
304
        inode->i_op = &xiafs_dir_inode_operations;
305
        if (dir->i_mode & S_ISGID)
306
            inode->i_mode |= S_ISGID;
307
    }
308
    else if (S_ISLNK(inode->i_mode))
309
        inode->i_op = &xiafs_symlink_inode_operations;
310
    else if (S_ISCHR(inode->i_mode))
311
        inode->i_op = &chrdev_inode_operations;
312
    else if (S_ISBLK(inode->i_mode))
313
        inode->i_op = &blkdev_inode_operations;
314
    else if (S_ISFIFO(inode->i_mode))
315
        init_fifo(inode);
316
    if (S_ISBLK(mode) || S_ISCHR(mode))
317
        inode->i_rdev = to_kdev_t(rdev);
318
    inode->i_atime = inode->i_ctime = inode->i_atime = CURRENT_TIME;
319
    inode->i_dirt = 1;
320
    bh = xiafs_add_entry(dir, name, len, &de, NULL);
321
    if (!bh) {
322
        inode->i_nlink--;
323
        inode->i_dirt = 1;
324
        iput(inode);
325
        iput(dir);
326
        return -ENOSPC;
327
    }
328
    de->d_ino = inode->i_ino;
329
    mark_buffer_dirty(bh, 1);
330
    brelse(bh);
331
    iput(dir);
332
    iput(inode);
333
    return 0;
334
}
335
 
336
int xiafs_mkdir(struct inode * dir, const char * name, int len, int mode)
337
{
338
    struct inode * inode;
339
    struct buffer_head * bh, *dir_block;
340
    struct xiafs_direct * de;
341
 
342
    bh = xiafs_find_entry(dir,name,len,&de, NULL);
343
    if (bh) {
344
        brelse(bh);
345
        iput(dir);
346
        return -EEXIST;
347
    }
348
    if (dir->i_nlink > 64000) {
349
        iput(dir);
350
        return -EMLINK;
351
    }
352
    inode = xiafs_new_inode(dir);
353
    if (!inode) {
354
        iput(dir);
355
        return -ENOSPC;
356
    }
357
    inode->i_op = &xiafs_dir_inode_operations;
358
    inode->i_size = XIAFS_ZSIZE(dir->i_sb);
359
    inode->i_atime = inode->i_ctime = inode->i_mtime = CURRENT_TIME;
360
    inode->i_dirt = 1;
361
    dir_block = xiafs_bread(inode,0,1);
362
    if (!dir_block) {
363
        iput(dir);
364
        inode->i_nlink--;
365
        inode->i_dirt = 1;
366
        iput(inode);
367
        return -ENOSPC;
368
    }
369
    de = (struct xiafs_direct *) dir_block->b_data;
370
    de->d_ino=inode->i_ino;
371
    strcpy(de->d_name,".");
372
    de->d_name_len=1;
373
    de->d_rec_len=12;
374
    de =(struct xiafs_direct *)(12 + dir_block->b_data);
375
    de->d_ino = dir->i_ino;
376
    strcpy(de->d_name,"..");
377
    de->d_name_len=2;
378
    de->d_rec_len=XIAFS_ZSIZE(dir->i_sb)-12;
379
    inode->i_nlink = 2;
380
    mark_buffer_dirty(dir_block, 1);
381
    brelse(dir_block);
382
    inode->i_mode = S_IFDIR | (mode & S_IRWXUGO & ~current->fs->umask);
383
    if (dir->i_mode & S_ISGID)
384
        inode->i_mode |= S_ISGID;
385
    inode->i_dirt = 1;
386
    bh = xiafs_add_entry(dir, name, len, &de, NULL);
387
    if (!bh) {
388
        iput(dir);
389
        inode->i_nlink=0;
390
        iput(inode);
391
        return -ENOSPC;
392
    }
393
    de->d_ino = inode->i_ino;
394
    mark_buffer_dirty(bh, 1);
395
    dir->i_nlink++;
396
    dir->i_dirt = 1;
397
    iput(dir);
398
    iput(inode);
399
    brelse(bh);
400
    return 0;
401
}
402
 
403
/*
404
 * routine to check that the specified directory is empty (for rmdir)
405
 */
406
static int empty_dir(struct inode * inode)
407
{
408
    int i, zones, offset;
409
    struct buffer_head * bh;
410
    struct xiafs_direct * de;
411
 
412
    if (inode->i_size & (XIAFS_ZSIZE(inode->i_sb)-1) ) {
413
        printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
414
        return 1;
415
    }
416
 
417
    zones=inode->i_size >> XIAFS_ZSIZE_BITS(inode->i_sb);
418
    for (i=0; i < zones; i++) {
419
        bh =  xiafs_bread(inode, i, 0);
420
        if (!i) {
421
            if (!bh) {
422
                printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
423
                return 1;
424
            }
425
            de=(struct xiafs_direct *)bh->b_data;
426
            if (de->d_ino != inode->i_ino || strcmp(".", de->d_name) ||
427
                    de->d_rec_len != 12 ) {
428
                printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
429
                brelse(bh);
430
                return 1;
431
            }
432
            de=(struct xiafs_direct *)(12 + bh->b_data);
433
            if (!de->d_ino || strcmp("..", de->d_name)) {
434
                printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
435
                brelse(bh);
436
                return 1;
437
            }
438
            offset=de->d_rec_len+12;
439
        }
440
        else
441
            offset = 0;
442
        if (!bh)
443
            continue;
444
        while (offset < XIAFS_ZSIZE(inode->i_sb)) {
445
            de=(struct xiafs_direct *)(bh->b_data+offset);
446
            if (de->d_ino > inode->i_sb->u.xiafs_sb.s_ninodes ||
447
                de->d_rec_len < 12 ||
448
                (char *)de+de->d_rec_len > bh->b_data+XIAFS_ZSIZE(inode->i_sb) ||
449
                de->d_name_len + 8 > de->d_rec_len ||
450
                de->d_name[de->d_name_len]) {
451
                printk("XIA-FS: bad directory (%s %d)\n", WHERE_ERR);
452
                brelse(bh);
453
                return 1;
454
            }
455
            if (de->d_ino) {
456
                brelse(bh);
457
                return 0;
458
            }
459
            offset+=de->d_rec_len;
460
        }
461
        brelse(bh);
462
    }
463
    return 1;
464
}
465
 
466
static void xiafs_rm_entry(struct xiafs_direct *de, struct xiafs_direct * de_pre)
467
{
468
    if (de==de_pre) {
469
        de->d_ino=0;
470
        return;
471
    }
472
    while (de_pre->d_rec_len+(u_char *)de_pre < (u_char *)de) {
473
        if (de_pre->d_rec_len < 12) {
474
            printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
475
            return;
476
        }
477
        de_pre=(struct xiafs_direct *)(de_pre->d_rec_len+(u_char *)de_pre);
478
    }
479
    if (de_pre->d_rec_len+(u_char *)de_pre > (u_char *)de) {
480
        printk("XIA-FS: bad directory entry (%s %d)\n", WHERE_ERR);
481
        return;
482
    }
483
    de_pre->d_rec_len+=de->d_rec_len;
484
}
485
 
486
int xiafs_rmdir(struct inode * dir, const char * name, int len)
487
{
488
    int retval;
489
    struct inode * inode;
490
    struct buffer_head * bh;
491
    struct xiafs_direct * de, * de_pre;
492
 
493
    inode = NULL;
494
    bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
495
    retval = -ENOENT;
496
    if (!bh)
497
        goto end_rmdir;
498
    retval = -EPERM;
499
    if (!(inode = iget(dir->i_sb, de->d_ino)))
500
        goto end_rmdir;
501
    if ((dir->i_mode & S_ISVTX) && !fsuser() &&
502
            current->fsuid != inode->i_uid &&
503
            current->fsuid != dir->i_uid)
504
        goto end_rmdir;
505
    if (inode->i_dev != dir->i_dev)
506
        goto end_rmdir;
507
    if (inode == dir)   /* we may not delete ".", but "../dir" is ok */
508
        goto end_rmdir;
509
    if (!S_ISDIR(inode->i_mode)) {
510
        retval = -ENOTDIR;
511
        goto end_rmdir;
512
    }
513
    if (!empty_dir(inode)) {
514
        retval = -ENOTEMPTY;
515
        goto end_rmdir;
516
    }
517
    if (inode->i_count > 1) {
518
        retval = -EBUSY;
519
        goto end_rmdir;
520
    }
521
    if (inode->i_nlink != 2)
522
        printk("XIA-FS: empty directory has nlink!=2 (%s %d)\n", WHERE_ERR);
523
    xiafs_rm_entry(de, de_pre);
524
    mark_buffer_dirty(bh, 1);
525
    inode->i_nlink=0;
526
    inode->i_dirt=1;
527
    dir->i_nlink--;
528
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
529
    dir->i_dirt=1;
530
    retval = 0;
531
end_rmdir:
532
    iput(dir);
533
    iput(inode);
534
    brelse(bh);
535
    return retval;
536
}
537
 
538
int xiafs_unlink(struct inode * dir, const char * name, int len)
539
{
540
    int retval;
541
    struct inode * inode;
542
    struct buffer_head * bh;
543
    struct xiafs_direct * de, * de_pre;
544
 
545
repeat:
546
    retval = -ENOENT;
547
    inode = NULL;
548
    bh = xiafs_find_entry(dir, name, len, &de, &de_pre);
549
    if (!bh)
550
        goto end_unlink;
551
    if (!(inode = iget(dir->i_sb, de->d_ino)))
552
        goto end_unlink;
553
    retval = -EPERM;
554
    if (S_ISDIR(inode->i_mode))
555
        goto end_unlink;
556
    if (de->d_ino != inode->i_ino) {
557
        iput(inode);
558
        brelse(bh);
559
        current->counter = 0;
560
        schedule();
561
        goto repeat;
562
    }
563
    if ((dir->i_mode & S_ISVTX) && !fsuser() &&
564
            current->fsuid != inode->i_uid &&
565
            current->fsuid != dir->i_uid)
566
        goto end_unlink;
567
    if (!inode->i_nlink) {
568
        printk("XIA-FS: Deleting nonexistent file (%s %d)\n", WHERE_ERR);
569
        inode->i_nlink=1;
570
    }
571
    xiafs_rm_entry(de, de_pre);
572
    mark_buffer_dirty(bh, 1);
573
    inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
574
    dir->i_dirt = 1;
575
    inode->i_nlink--;
576
    inode->i_dirt = 1;
577
    retval = 0;
578
end_unlink:
579
    brelse(bh);
580
    iput(inode);
581
    iput(dir);
582
    return retval;
583
}
584
 
585
int xiafs_symlink(struct inode * dir, const char * name,
586
                int len, const char * symname)
587
{
588
    struct xiafs_direct * de;
589
    struct inode * inode = NULL;
590
    struct buffer_head * bh = NULL, * name_block = NULL;
591
    int i;
592
    char c;
593
 
594
    bh = xiafs_find_entry(dir,name,len, &de, NULL);
595
    if (bh) {
596
        brelse(bh);
597
        iput(dir);
598
        return -EEXIST;
599
    }
600
    if (!(inode = xiafs_new_inode(dir))) {
601
        iput(dir);
602
        return -ENOSPC;
603
    }
604
    inode->i_mode = S_IFLNK | S_IRWXUGO;
605
    inode->i_op = &xiafs_symlink_inode_operations;
606
    name_block = xiafs_bread(inode,0,1);
607
    if (!name_block) {
608
        iput(dir);
609
        inode->i_nlink--;
610
        inode->i_dirt = 1;
611
        iput(inode);
612
        return -ENOSPC;
613
    }
614
    for (i = 0; i < BLOCK_SIZE-1 && (c=*symname++); i++)
615
        name_block->b_data[i] = c;
616
    name_block->b_data[i] = 0;
617
    mark_buffer_dirty(name_block, 1);
618
    brelse(name_block);
619
    inode->i_size = i;
620
    inode->i_dirt = 1;
621
    bh = xiafs_add_entry(dir, name, len, &de, NULL);
622
    if (!bh) {
623
        inode->i_nlink--;
624
        inode->i_dirt = 1;
625
        iput(inode);
626
        iput(dir);
627
        return -ENOSPC;
628
    }
629
    de->d_ino = inode->i_ino;
630
    mark_buffer_dirty(bh, 1);
631
    brelse(bh);
632
    iput(dir);
633
    iput(inode);
634
    return 0;
635
}
636
 
637
int xiafs_link(struct inode * oldinode, struct inode * dir,
638
             const char * name, int len)
639
{
640
    struct xiafs_direct * de;
641
    struct buffer_head * bh;
642
 
643
    if (S_ISDIR(oldinode->i_mode)) {
644
        iput(oldinode);
645
        iput(dir);
646
        return -EPERM;
647
    }
648
    if (oldinode->i_nlink > 64000) {
649
        iput(oldinode);
650
        iput(dir);
651
        return -EMLINK;
652
    }
653
    bh = xiafs_find_entry(dir, name, len, &de, NULL);
654
    if (bh) {
655
        brelse(bh);
656
        iput(dir);
657
        iput(oldinode);
658
        return -EEXIST;
659
    }
660
    bh = xiafs_add_entry(dir, name, len, &de, NULL);
661
    if (!bh) {
662
        iput(dir);
663
        iput(oldinode);
664
        return -ENOSPC;
665
    }
666
    de->d_ino = oldinode->i_ino;
667
    mark_buffer_dirty(bh, 1);
668
    brelse(bh);
669
    iput(dir);
670
    oldinode->i_nlink++;
671
    oldinode->i_ctime = CURRENT_TIME;
672
    oldinode->i_dirt = 1;
673
    iput(oldinode);
674
    return 0;
675
}
676
 
677
static int subdir(struct inode * new_inode, struct inode * old_inode)
678
{
679
    int ino;
680
    int result;
681
 
682
    new_inode->i_count++;
683
    result = 0;
684
    for (;;) {
685
        if (new_inode == old_inode) {
686
            result = 1;
687
            break;
688
        }
689
        if (new_inode->i_dev != old_inode->i_dev)
690
            break;
691
        ino = new_inode->i_ino;
692
        if (xiafs_lookup(new_inode,"..",2,&new_inode))
693
            break;
694
        if (new_inode->i_ino == ino)
695
            break;
696
    }
697
    iput(new_inode);
698
    return result;
699
}
700
 
701
#define PARENT_INO(buffer) \
702
    (((struct xiafs_direct *) ((u_char *)(buffer) + 12))->d_ino)
703
 
704
/*
705
 * rename uses retry to avoid race-conditions: at least they should be minimal.
706
 * it tries to allocate all the blocks, then sanity-checks, and if the sanity-
707
 * checks fail, it tries to restart itself again. Very practical - no changes
708
 * are done until we know everything works ok.. and then all the changes can be
709
 * done in one fell swoop when we have claimed all the buffers needed.
710
 *
711
 * Anybody can rename anything with this: the permission checks are left to the
712
 * higher-level routines.
713
 */
714
static int do_xiafs_rename(struct inode * old_dir, const char * old_name,
715
                         int old_len, struct inode * new_dir,
716
                         const char * new_name, int new_len,
717
                         int must_be_dir)
718
{
719
    struct inode * old_inode, * new_inode;
720
    struct buffer_head * old_bh, * new_bh, * dir_bh;
721
    struct xiafs_direct * old_de, * old_de_pre, * new_de, * new_de_pre;
722
    int retval;
723
 
724
try_again:
725
    old_inode = new_inode = NULL;
726
    old_bh = new_bh = dir_bh = NULL;
727
    old_bh = xiafs_find_entry(old_dir, old_name, old_len, &old_de, &old_de_pre);
728
    retval = -ENOENT;
729
    if (!old_bh)
730
        goto end_rename;
731
    old_inode = __iget(old_dir->i_sb, old_de->d_ino, 0); /* don't cross mnt-points */
732
    if (!old_inode)
733
        goto end_rename;
734
    if (must_be_dir && !S_ISDIR(old_inode->i_mode))
735
        goto end_rename;
736
    retval = -EPERM;
737
    if ((old_dir->i_mode & S_ISVTX) &&
738
            current->fsuid != old_inode->i_uid &&
739
            current->fsuid != old_dir->i_uid && !fsuser())
740
        goto end_rename;
741
    new_bh = xiafs_find_entry(new_dir, new_name, new_len, &new_de, NULL);
742
    if (new_bh) {
743
        new_inode = __iget(new_dir->i_sb, new_de->d_ino, 0);
744
        if (!new_inode) {
745
            brelse(new_bh);
746
            new_bh = NULL;
747
        }
748
    }
749
    if (new_inode == old_inode) {
750
        retval = 0;
751
        goto end_rename;
752
    }
753
    if (new_inode && S_ISDIR(new_inode->i_mode)) {
754
        retval = -EEXIST;
755
        goto end_rename;
756
    }
757
    retval = -EPERM;
758
    if (new_inode && (new_dir->i_mode & S_ISVTX) &&
759
            current->fsuid != new_inode->i_uid &&
760
            current->fsuid != new_dir->i_uid && !fsuser())
761
        goto end_rename;
762
    if (S_ISDIR(old_inode->i_mode)) {
763
        retval = -EEXIST;
764
        if (new_bh)
765
            goto end_rename;
766
        if ((retval = permission(old_inode, MAY_WRITE)) != 0)
767
            goto end_rename;
768
        retval = -EINVAL;
769
        if (subdir(new_dir, old_inode))
770
            goto end_rename;
771
        retval = -EIO;
772
        dir_bh = xiafs_bread(old_inode,0,0);
773
        if (!dir_bh)
774
            goto end_rename;
775
        if (PARENT_INO(dir_bh->b_data) != old_dir->i_ino)
776
            goto end_rename;
777
        retval = -EMLINK;
778
        if (new_dir->i_nlink > 64000)
779
            goto end_rename;
780
    }
781
    if (!new_bh)
782
        new_bh = xiafs_add_entry(new_dir, new_name, new_len, &new_de, &new_de_pre);
783
    retval = -ENOSPC;
784
    if (!new_bh)
785
        goto end_rename;
786
    /* sanity checking */
787
    if ( (new_inode && (new_de->d_ino != new_inode->i_ino))
788
            || (new_de->d_ino && !new_inode)
789
            || (old_de->d_ino != old_inode->i_ino)) {
790
        xiafs_rm_entry(new_de, new_de_pre);
791
        brelse(old_bh);
792
        brelse(new_bh);
793
        brelse(dir_bh);
794
        iput(old_inode);
795
        iput(new_inode);
796
        current->counter=0;
797
        schedule();
798
        goto try_again;
799
    }
800
    xiafs_rm_entry(old_de, old_de_pre);
801
    new_de->d_ino = old_inode->i_ino;
802
    if (new_inode) {
803
        new_inode->i_nlink--;
804
        new_inode->i_dirt = 1;
805
    }
806
    mark_buffer_dirty(old_bh, 1);
807
    mark_buffer_dirty(new_bh, 1);
808
    if (dir_bh) {
809
        PARENT_INO(dir_bh->b_data) = new_dir->i_ino;
810
        mark_buffer_dirty(dir_bh, 1);
811
        old_dir->i_nlink--;
812
        new_dir->i_nlink++;
813
        old_dir->i_dirt = 1;
814
        new_dir->i_dirt = 1;
815
    }
816
    retval = 0;
817
end_rename:
818
    brelse(dir_bh);
819
    brelse(old_bh);
820
    brelse(new_bh);
821
    iput(old_inode);
822
    iput(new_inode);
823
    iput(old_dir);
824
    iput(new_dir);
825
    return retval;
826
}
827
 
828
/*
829
 * Ok, rename also locks out other renames, as they can change the parent of
830
 * a directory, and we don't want any races. Other races are checked for by
831
 * "do_rename()", which restarts if there are inconsistencies.
832
 *
833
 * Note that there is no race between different filesystems: it's only within
834
 * the same device that races occur: many renames can happen at once, as long
835
 * as they are on different partitions.
836
 */
837
int xiafs_rename(struct inode * old_dir, const char * old_name, int old_len,
838
        struct inode * new_dir, const char * new_name, int new_len,
839
        int must_be_dir)
840
{
841
    static struct wait_queue * wait = NULL;
842
    static int lock = 0;
843
    int result;
844
 
845
    while (lock)
846
        sleep_on(&wait);
847
    lock = 1;
848
    result = do_xiafs_rename(old_dir, old_name, old_len,
849
                           new_dir, new_name, new_len,
850
                           must_be_dir);
851
    lock = 0;
852
    wake_up(&wait);
853
    return result;
854
}

powered by: WebSVN 2.1.0

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