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

Subversion Repositories or1k

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

powered by: WebSVN 2.1.0

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