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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

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

powered by: WebSVN 2.1.0

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