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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [uclinux/] [uClinux-2.0.x/] [fs/] [affs/] [namei.c] - Blame information for rev 1765

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/affs/namei.c
3
 *
4
 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
5
 *
6
 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
7
 *
8
 *  (C) 1991  Linus Torvalds - minix filesystem
9
 */
10
 
11
#include <linux/sched.h>
12
#include <linux/affs_fs.h>
13
#include <linux/kernel.h>
14
#include <linux/string.h>
15
#include <linux/stat.h>
16
#include <linux/fcntl.h>
17
#include <linux/locks.h>
18
#include <linux/amigaffs.h>
19
#include <asm/segment.h>
20
 
21
#include <linux/errno.h>
22
 
23
/* Simple toupper() for DOS\1 */
24
 
25
static inline unsigned int
26
affs_toupper(unsigned int ch)
27
{
28
        return ch >= 'a' && ch <= 'z' ? ch -= ('a' - 'A') : ch;
29
}
30
 
31
/* International toupper() for DOS\3 */
32
 
33
static inline unsigned int
34
affs_intl_toupper(unsigned int ch)
35
{
36
        return (ch >= 'a' && ch <= 'z') || (ch >= 0xE0
37
                && ch <= 0xFE && ch != 0xF7) ?
38
                ch - ('a' - 'A') : ch;
39
}
40
 
41
/*
42
 * NOTE! unlike strncmp, affs_match returns 1 for success, 0 for failure.
43
 */
44
 
45
static int
46
affs_match(const char *name, int len, const char *compare, int dlen, int intl)
47
{
48
        if (!compare)
49
                return 0;
50
 
51
        if (len > 30)
52
                len = 30;
53
        if (dlen > 30)
54
                dlen = 30;
55
 
56
        /* "" means "." ---> so paths like "/usr/lib//libc.a" work */
57
        if (!len && dlen == 1 && compare[0] == '.')
58
                return 1;
59
        if (dlen != len)
60
                return 0;
61
        if (intl) {
62
                while (dlen--) {
63
                        if (affs_intl_toupper(*name & 0xFF) != affs_intl_toupper(*compare & 0xFF))
64
                                return 0;
65
                        name++;
66
                        compare++;
67
                }
68
        } else {
69
                while (dlen--) {
70
                        if (affs_toupper(*name & 0xFF) != affs_toupper(*compare & 0xFF))
71
                                return 0;
72
                        name++;
73
                        compare++;
74
                }
75
        }
76
        return 1;
77
}
78
 
79
int
80
affs_hash_name(const char *name, int len, int intl, int hashsize)
81
{
82
        unsigned int i, x;
83
 
84
        if (len > 30)
85
                len = 30;
86
 
87
        x = len;
88
        for (i = 0; i < len; i++)
89
                if (intl)
90
                        x = (x * 13 + affs_intl_toupper(name[i] & 0xFF)) & 0x7ff;
91
                else
92
                        x = (x * 13 + affs_toupper(name[i] & 0xFF)) & 0x7ff;
93
 
94
        return x % hashsize;
95
}
96
 
97
static struct buffer_head *
98
affs_find_entry(struct inode *dir, const char *name, int namelen,
99
                unsigned long *ino)
100
{
101
        struct buffer_head *bh;
102
        int      intl;
103
        int      key;
104
 
105
        pr_debug("AFFS: find_entry(%.*s)=\n",namelen,name);
106
 
107
        intl = AFFS_I2FSTYPE(dir);
108
        bh   = affs_bread(dir->i_dev,dir->i_ino,AFFS_I2BSIZE(dir));
109
        if (!bh)
110
                return NULL;
111
 
112
        if (affs_match(name,namelen,".",1,intl)) {
113
                *ino = dir->i_ino;
114
                return bh;
115
        }
116
        if (affs_match(name,namelen,"..",2,intl)) {
117
                *ino = affs_parent_ino(dir);
118
                return bh;
119
        }
120
 
121
        key = AFFS_GET_HASHENTRY(bh->b_data,affs_hash_name(name,namelen,intl,AFFS_I2HSIZE(dir)));
122
 
123
        for (;;) {
124
                char *cname;
125
                int cnamelen;
126
 
127
                affs_brelse(bh);
128
                if (key == 0) {
129
                        bh = NULL;
130
                        break;
131
                }
132
                bh = affs_bread(dir->i_dev,key,AFFS_I2BSIZE(dir));
133
                if (!bh)
134
                        break;
135
                cnamelen = affs_get_file_name(AFFS_I2BSIZE(dir),bh->b_data,&cname);
136
                if (affs_match(name,namelen,cname,cnamelen,intl))
137
                        break;
138
                key = htonl(FILE_END(bh->b_data,dir)->hash_chain);
139
        }
140
        *ino = key;
141
        return bh;
142
}
143
 
144
int
145
affs_lookup(struct inode *dir, const char *name, int len, struct inode **result)
146
{
147
        int res;
148
        unsigned long ino;
149
        struct buffer_head *bh;
150
 
151
        pr_debug("AFFS: lookup(%.*s)\n",len,name);
152
 
153
        *result = NULL;
154
        if (!dir)
155
                return -ENOENT;
156
 
157
        res = -ENOENT;
158
        if (S_ISDIR(dir->i_mode)) {
159
                if ((bh = affs_find_entry(dir,name,len,&ino))) {
160
                        if (FILE_END(bh->b_data,dir)->original)
161
                                ino = htonl(FILE_END(bh->b_data,dir)->original);
162
                        affs_brelse(bh);
163
                        if ((*result = iget(dir->i_sb,ino)))
164
                                res = 0;
165
                        else
166
                                res = -EACCES;
167
                }
168
        }
169
        iput(dir);
170
        return res;
171
}
172
 
173
int
174
affs_unlink(struct inode *dir, const char *name, int len)
175
{
176
        int                      retval;
177
        struct buffer_head      *bh;
178
        unsigned long            ino;
179
        struct inode            *inode;
180
 
181
        pr_debug("AFFS: unlink(dir=%ld,\"%.*s\")\n",dir->i_ino,len,name);
182
 
183
        bh      = NULL;
184
        inode   = NULL;
185
        retval  = -ENOENT;
186
        if (!(bh = affs_find_entry(dir,name,len,&ino))) {
187
                goto unlink_done;
188
        }
189
        if (!(inode = iget(dir->i_sb,ino))) {
190
                goto unlink_done;
191
        }
192
        if (S_ISDIR(inode->i_mode)) {
193
                retval = -EPERM;
194
                goto unlink_done;
195
        }
196
 
197
        if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
198
                                         AFFS_I2HSIZE(dir)) + 6,ino,
199
                                         FILE_END(bh->b_data,dir)->hash_chain)))
200
                goto unlink_done;
201
 
202
        if ((retval = affs_fixup(bh,inode)))
203
                goto unlink_done;
204
 
205
        inode->i_nlink=0;
206
        inode->i_dirt=1;
207
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
208
        dir->i_version = ++event;
209
        dir->i_dirt=1;
210
unlink_done:
211
        affs_brelse(bh);
212
        iput(inode);
213
        iput(dir);
214
        return retval;
215
}
216
 
217
int
218
affs_create(struct inode *dir, const char *name, int len, int mode, struct inode **result)
219
{
220
        struct inode    *inode;
221
        int              error;
222
 
223
        pr_debug("AFFS: create(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
224
 
225
 
226
        *result = NULL;
227
 
228
        if (!dir || !dir->i_sb) {
229
                iput(dir);
230
                return -EINVAL;
231
        }
232
        inode = affs_new_inode(dir);
233
        if (!inode) {
234
                iput (dir);
235
                return -ENOSPC;
236
        }
237
        inode->i_mode = mode;
238
        if (dir->i_sb->u.affs_sb.s_flags & SF_OFS)
239
                inode->i_op = &affs_file_inode_operations_ofs;
240
        else
241
                inode->i_op = &affs_file_inode_operations;
242
 
243
        error = affs_add_entry(dir,NULL,inode,name,len,ST_FILE);
244
        if (error) {
245
                iput(dir);
246
                inode->i_nlink = 0;
247
                inode->i_dirt  = 1;
248
                iput(inode);
249
                return -ENOSPC;
250
        }
251
        inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
252
 
253
        iput(dir);
254
        *result = inode;
255
 
256
        return 0;
257
}
258
 
259
int
260
affs_mkdir(struct inode *dir, const char *name, int len, int mode)
261
{
262
        struct inode            *inode;
263
        struct buffer_head      *bh;
264
        unsigned long            i;
265
        int                      error;
266
 
267
        pr_debug("AFFS: mkdir(%lu,\"%.*s\",0%o)\n",dir->i_ino,len,name,mode);
268
 
269
        if (!dir || !dir->i_sb) {
270
                iput(dir);
271
                return -EINVAL;
272
        }
273
        bh = affs_find_entry(dir,name,len,&i);
274
        if (bh) {
275
                affs_brelse(bh);
276
                iput(dir);
277
                return -EEXIST;
278
        }
279
        inode = affs_new_inode(dir);
280
        if (!inode) {
281
                iput (dir);
282
                return -ENOSPC;
283
        }
284
        inode->i_op = &affs_dir_inode_operations;
285
        error       = affs_add_entry(dir,NULL,inode,name,len,ST_USERDIR);
286
        if (error) {
287
                iput(dir);
288
                inode->i_nlink = 0;
289
                inode->i_dirt  = 1;
290
                iput(inode);
291
                return error;
292
        }
293
        inode->i_mode = S_IFDIR | (mode & 0777 & ~current->fs->umask);
294
        inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
295
 
296
        iput(dir);
297
        iput(inode);
298
 
299
        return 0;
300
}
301
 
302
static int
303
empty_dir(struct buffer_head *bh, int hashsize)
304
{
305
        while (--hashsize >= 0) {
306
                if (((struct dir_front *)bh->b_data)->hashtable[hashsize])
307
                        return 0;
308
        }
309
        return 1;
310
}
311
 
312
int
313
affs_rmdir(struct inode *dir, const char *name, int len)
314
{
315
        int                      retval;
316
        unsigned long            ino;
317
        struct inode            *inode;
318
        struct buffer_head      *bh;
319
 
320
        pr_debug("AFFS: rmdir(dir=%lu,\"%.*s\")\n",dir->i_ino,len,name);
321
 
322
        inode  = NULL;
323
        retval = -ENOENT;
324
        if (!(bh = affs_find_entry(dir,name,len,&ino))) {
325
                goto rmdir_done;
326
        }
327
        if (!(inode = iget(dir->i_sb,ino))) {
328
                goto rmdir_done;
329
        }
330
        retval = -EPERM;
331
        if (!fsuser() && current->fsuid != inode->i_uid &&
332
            current->fsuid != dir->i_uid)
333
                goto rmdir_done;
334
        if (inode->i_dev != dir->i_dev)
335
                goto rmdir_done;
336
        if (inode == dir)       /* we may not delete ".", but "../dir" is ok */
337
                goto rmdir_done;
338
        if (!S_ISDIR(inode->i_mode)) {
339
                retval = -ENOTDIR;
340
                goto rmdir_done;
341
        }
342
        if (!empty_dir(bh,AFFS_I2HSIZE(inode))) {
343
                retval = -ENOTEMPTY;
344
                goto rmdir_done;
345
        }
346
        if (inode->i_count > 1) {
347
                retval = -EBUSY;
348
                goto rmdir_done;
349
        }
350
        if ((retval = affs_fix_hash_pred(dir,affs_hash_name(name,len,AFFS_I2FSTYPE(dir),
351
                                         AFFS_I2HSIZE(dir)) + 6,ino,
352
                                         FILE_END(bh->b_data,dir)->hash_chain)))
353
                goto rmdir_done;
354
 
355
        if ((retval = affs_fixup(bh,inode)))
356
                goto rmdir_done;
357
 
358
        inode->i_nlink=0;
359
        inode->i_dirt=1;
360
        inode->i_ctime = dir->i_ctime = dir->i_mtime = CURRENT_TIME;
361
        dir->i_version = ++event;
362
        dir->i_dirt=1;
363
rmdir_done:
364
        iput(dir);
365
        iput(inode);
366
        affs_brelse(bh);
367
        return retval;
368
}
369
 
370
int
371
affs_symlink(struct inode *dir, const char *name, int len, const char *symname)
372
{
373
        struct buffer_head      *bh;
374
        struct inode            *inode;
375
        char                    *p;
376
        unsigned long            tmp;
377
        int                      i, maxlen;
378
        char                     c, lc;
379
 
380
        pr_debug("AFFS: symlink(%lu,\"%.*s\" -> \"%s\")\n",dir->i_ino,len,name,symname);
381
 
382
        maxlen = 4 * AFFS_I2HSIZE(dir) - 1;
383
        inode  = affs_new_inode(dir);
384
        if (!inode) {
385
                iput(dir);
386
                return -ENOSPC;
387
        }
388
        inode->i_op   = &affs_symlink_inode_operations;
389
        inode->i_mode = S_IFLNK | 0777;
390
        inode->u.affs_i.i_protect = mode_to_prot(inode->i_mode);
391
        bh = affs_bread(inode->i_dev,inode->i_ino,AFFS_I2BSIZE(inode));
392
        if (!bh) {
393
                iput(dir);
394
                inode->i_nlink = 0;
395
                inode->i_dirt  = 1;
396
                iput(inode);
397
                return -EIO;
398
        }
399
        i  = 0;
400
        p  = ((struct slink_front *)bh->b_data)->symname;
401
        lc = '/';
402
        if (*symname == '/') {
403
                while (*symname == '/')
404
                        symname++;
405
                while (inode->i_sb->u.affs_sb.s_volume[i])      /* Cannot overflow */
406
                        *p++ = inode->i_sb->u.affs_sb.s_volume[i++];
407
        }
408
        while (i < maxlen && (c = *symname++)) {
409
                if (c == '.' && lc == '/' && *symname == '.' && symname[1] == '/') {
410
                        *p++ = '/';
411
                        i++;
412
                        symname += 2;
413
                        lc = '/';
414
                } else if (c == '.' && lc == '/' && *symname == '/') {
415
                        symname++;
416
                        lc = '/';
417
                } else {
418
                        *p++ = c;
419
                        lc   = c;
420
                        i++;
421
                }
422
                if (lc == '/')
423
                        while (*symname == '/')
424
                                symname++;
425
        }
426
        *p = 0;
427
        mark_buffer_dirty(bh,1);
428
        affs_brelse(bh);
429
        inode->i_dirt = 1;
430
        bh = affs_find_entry(dir,name,len,&tmp);
431
        if (bh) {
432
                inode->i_nlink = 0;
433
                iput(inode);
434
                affs_brelse(bh);
435
                iput(dir);
436
                return -EEXIST;
437
        }
438
        i = affs_add_entry(dir,NULL,inode,name,len,ST_SOFTLINK);
439
        if (i) {
440
                inode->i_nlink = 0;
441
                inode->i_dirt  = 1;
442
                iput(inode);
443
                affs_brelse(bh);
444
                iput(dir);
445
                return i;
446
        }
447
        iput(dir);
448
        iput(inode);
449
 
450
        return 0;
451
}
452
 
453
int
454
affs_link(struct inode *oldinode, struct inode *dir, const char *name, int len)
455
{
456
        struct inode            *inode;
457
        struct buffer_head      *bh;
458
        unsigned long            i;
459
        int                      error;
460
 
461
        pr_debug("AFFS: link(%lu,%lu,\"%.*s\")\n",oldinode->i_ino,dir->i_ino,len,name);
462
 
463
        bh = affs_find_entry(dir,name,len,&i);
464
        if (bh) {
465
                affs_brelse(bh);
466
                iput(oldinode);
467
                iput(dir);
468
                return -EEXIST;
469
        }
470
        if (oldinode->u.affs_i.i_hlink) {
471
                i = oldinode->u.affs_i.i_original;
472
                iput(oldinode);
473
                oldinode = iget(dir->i_sb,i);
474
                if (!oldinode) {
475
                        printk("AFFS: link(): original does not exist.\n");
476
                        iput(dir);
477
                        return -ENOENT;
478
                }
479
        }
480
        inode = affs_new_inode(dir);
481
        if (!inode) {
482
                iput(oldinode);
483
                iput(dir);
484
                return -ENOSPC;
485
        }
486
        inode->i_op                = oldinode->i_op;
487
        inode->i_mode              = oldinode->i_mode;
488
        inode->i_uid               = oldinode->i_uid;
489
        inode->i_gid               = oldinode->i_gid;
490
        inode->u.affs_i.i_protect  = mode_to_prot(inode->i_mode);
491
        inode->u.affs_i.i_original = oldinode->i_ino;
492
        inode->u.affs_i.i_hlink    = 1;
493
 
494
        if (S_ISDIR(oldinode->i_mode))
495
                error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKDIR);
496
        else
497
                error = affs_add_entry(dir,oldinode,inode,name,len,ST_LINKFILE);
498
        if (error) {
499
                inode->i_nlink = 0;
500
                inode->i_dirt  = 1;
501
        }
502
        iput(dir);
503
        iput(inode);
504
        iput(oldinode);
505
 
506
        return error;
507
}
508
 
509
static int
510
subdir(struct inode * new_inode, struct inode * old_inode)
511
{
512
    int ino;
513
    int result;
514
 
515
    new_inode->i_count++;
516
    result = 0;
517
    for (;;) {
518
        if (new_inode == old_inode) {
519
            result = 1;
520
            break;
521
        }
522
        if (new_inode->i_dev != old_inode->i_dev)
523
            break;
524
        ino = new_inode->i_ino;
525
        if (affs_lookup(new_inode,"..",2,&new_inode))
526
            break;
527
        if (new_inode->i_ino == ino)
528
            break;
529
    }
530
    iput(new_inode);
531
    return result;
532
}
533
 
534
/* I'm afraid this might not be race proof. Maybe next time. */
535
 
536
int
537
affs_rename(struct inode *old_dir, const char *old_name, int old_len,
538
            struct inode *new_dir, const char *new_name, int new_len,
539
            int must_be_dir)
540
{
541
        struct inode            *old_inode;
542
        struct inode            *new_inode;
543
        struct buffer_head      *old_bh;
544
        struct buffer_head      *new_bh;
545
        unsigned long            old_ino;
546
        unsigned long            new_ino;
547
        int                      retval;
548
 
549
        pr_debug("AFFS: rename(old=%lu,\"%*s\" to new=%lu,\"%*s\")\n",old_dir->i_ino,old_len,old_name,
550
                 new_dir->i_ino,new_len,new_name);
551
 
552
        if (new_len > 30)
553
                new_len = 30;
554
        goto start_up;
555
retry:
556
        affs_brelse(old_bh);
557
        affs_brelse(new_bh);
558
        iput(new_inode);
559
        iput(old_inode);
560
        current->counter = 0;
561
        schedule();
562
start_up:
563
        old_inode = new_inode = NULL;
564
        old_bh    = new_bh = NULL;
565
        retval    = -ENOENT;
566
 
567
        old_bh = affs_find_entry(old_dir,old_name,old_len,&old_ino);
568
        if (!old_bh)
569
                goto end_rename;
570
        old_inode = __iget(old_dir->i_sb,old_ino,0);
571
        if (!old_inode)
572
                goto end_rename;
573
        if (must_be_dir && !S_ISDIR(old_inode->i_mode))
574
                goto end_rename;
575
        new_bh = affs_find_entry(new_dir,new_name,new_len,&new_ino);
576
        if (new_bh) {
577
                new_inode = __iget(new_dir->i_sb,new_ino,0);
578
                if (!new_inode) {               /* What does this mean? */
579
                        affs_brelse(new_bh);
580
                        new_bh = NULL;
581
                }
582
        }
583
        if (new_inode == old_inode) {           /* Won't happen */
584
                retval = 0;
585
                goto end_rename;
586
        }
587
        if (new_inode && S_ISDIR(new_inode->i_mode)) {
588
                retval = -EISDIR;
589
                if (!S_ISDIR(old_inode->i_mode))
590
                        goto end_rename;
591
                retval = -EINVAL;
592
                if (subdir(new_dir,old_inode))
593
                        goto end_rename;
594
                retval = -ENOTEMPTY;
595
                if (!empty_dir(new_bh,AFFS_I2HSIZE(new_inode)))
596
                        goto end_rename;
597
                retval = -EBUSY;
598
                if (new_inode->i_count > 1)
599
                        goto end_rename;
600
        }
601
        if (S_ISDIR(old_inode->i_mode)) {
602
                retval = -ENOTDIR;
603
                if (new_inode && !S_ISDIR(new_inode->i_mode))
604
                        goto end_rename;
605
                retval = -EINVAL;
606
                if (subdir(new_dir,old_inode))
607
                        goto end_rename;
608
                if (affs_parent_ino(old_inode) != old_dir->i_ino)
609
                        goto end_rename;
610
        }
611
        /* Unlink destination if existent */
612
        if (new_inode) {
613
                if ((retval = affs_fix_hash_pred(new_dir,affs_hash_name(new_name,new_len,
614
                                                 AFFS_I2FSTYPE(new_dir),AFFS_I2HSIZE(new_dir)) + 6,
615
                                                 new_ino,
616
                                                 FILE_END(new_bh->b_data,new_dir)->hash_chain)))
617
                        goto retry;
618
                if ((retval = affs_fixup(new_bh,new_inode)))
619
                        goto retry;
620
                mark_buffer_dirty(new_bh,1);
621
                new_dir->i_version = ++event;
622
                new_dir->i_dirt    = 1;
623
                new_inode->i_nlink = 0;
624
                new_inode->i_dirt  = 1;
625
        }
626
        retval = affs_fix_hash_pred(old_dir,affs_hash_name(old_name,old_len,AFFS_I2FSTYPE(old_dir),
627
                                    AFFS_I2HSIZE(old_dir)) + 6,old_ino,
628
                                    FILE_END(old_bh->b_data,old_dir)->hash_chain);
629
        if (retval)
630
                goto retry;
631
 
632
        retval = affs_add_entry(new_dir,NULL,old_inode,new_name,new_len,
633
                                htonl(FILE_END(old_bh->b_data,old_dir)->secondary_type));
634
 
635
        new_dir->i_ctime   = new_dir->i_mtime = old_dir->i_ctime = old_dir->i_mtime = CURRENT_TIME;
636
        new_dir->i_version = ++event;
637
        old_dir->i_version = ++event;
638
        new_dir->i_dirt    = 1;
639
        old_dir->i_dirt    = 1;
640
        mark_buffer_dirty(old_bh,1);
641
 
642
end_rename:
643
        affs_brelse(old_bh);
644
        affs_brelse(new_bh);
645
        iput(new_inode);
646
        iput(old_inode);
647
        iput(old_dir);
648
        iput(new_dir);
649
 
650
        return retval;
651
}
652
 
653
int
654
affs_fixup(struct buffer_head *bh, struct inode *inode)
655
{
656
        int                      key, link_key;
657
        int                      type;
658
        struct buffer_head      *nbh;
659
        struct inode            *ofinode;
660
 
661
        type = htonl(FILE_END(bh->b_data,inode)->secondary_type);
662
        if (type == ST_LINKFILE || type == ST_LINKDIR) {
663
                key = htonl(LINK_END(bh->b_data,inode)->original);
664
                LINK_END(bh->b_data,inode)->original = 0;
665
                if (!key) {
666
                        printk("AFFS: fixup(): hard link without original: ino=%lu\n",inode->i_ino);
667
                        return -ENOENT;
668
                }
669
                if (!(ofinode = iget(inode->i_sb,key)))
670
                        return -ENOENT;
671
                type = affs_fix_link_pred(ofinode,inode->i_ino,
672
                                          FILE_END(bh->b_data,inode)->link_chain);
673
                iput(ofinode);
674
                return type;
675
        } else if (type == ST_FILE || type == ST_USERDIR) {
676
                if ((key = htonl(FILE_END(bh->b_data,inode)->link_chain))) {
677
                        /* Get first link, turn it to a file */
678
                        if (!(ofinode = iget(inode->i_sb,key))) {
679
                                printk("AFFS: fixup(): cannot read inode %u\n",key);
680
                                return -ENOENT;
681
                        }
682
                        if (!ofinode->u.affs_i.i_hlink) {
683
                                printk("AFFS: fixup(): first link to %lu (%u) is not a link?\n",
684
                                        inode->i_ino,key);
685
                                iput(ofinode);
686
                                return -ENOENT;
687
                        }
688
                        if (!(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode)))) {
689
                                printk("AFFS: fixup(): cannot read block %u\n",key);
690
                                iput(ofinode);
691
                                return -ENOENT;
692
                        }
693
                        lock_super(inode->i_sb);
694
                        memcpy(nbh->b_data + 8,bh->b_data + 8,AFFS_I2BSIZE(inode) - 208);
695
                        FILE_END(nbh->b_data,inode)->byte_size = FILE_END(bh->b_data,inode)->
696
                                                                          byte_size;
697
                        FILE_END(nbh->b_data,inode)->extension = FILE_END(bh->b_data,inode)->
698
                                                                          extension;
699
                        FILE_END(nbh->b_data,inode)->secondary_type = FILE_END(bh->b_data,inode)->
700
                                                                          secondary_type;
701
                        FILE_END(nbh->b_data,inode)->original = 0;
702
 
703
                        ofinode->u.affs_i.i_original = 0;
704
                        ofinode->u.affs_i.i_hlink    = 0;
705
                        ofinode->i_size              = inode->i_size;
706
                        ofinode->i_uid               = inode->i_uid;
707
                        ofinode->i_gid               = inode->i_gid;
708
                        ofinode->i_dirt              = 1;
709
                        link_key                     = ofinode->i_ino;
710
 
711
                        /* Let all remaining links point to the new file */
712
                        while (1) {
713
                                affs_fix_checksum(AFFS_I2BSIZE(inode),nbh->b_data,5);
714
                                mark_buffer_dirty(nbh,1);
715
                                key = htonl(FILE_END(nbh->b_data,inode)->link_chain);
716
                                affs_brelse(nbh);
717
                                iput(ofinode);
718
                                if (!key || !(nbh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode))))
719
                                        break;
720
                                if ((ofinode = iget(inode->i_sb,key))) {
721
                                        if (!ofinode->u.affs_i.i_hlink)
722
                                                printk("AFFS: fixup() inode %u in link chain is "
723
                                                       "not a link\n",key);
724
                                        ofinode->u.affs_i.i_original = link_key;
725
                                        ofinode->i_dirt              = 1;
726
                                        FILE_END(nbh->b_data,inode)->original = htonl(link_key);
727
                                } else
728
                                        printk("AFFS: fixup(): cannot get inode %u\n",key);
729
                        }
730
                        /* Turn old inode to a link */
731
                        inode->u.affs_i.i_hlink = 1;
732
                        unlock_super(inode->i_sb);
733
                }
734
                return 0;
735
        } else if (type == ST_SOFTLINK) {
736
                return 0;
737
        } else {
738
                printk("AFFS: fixup(): secondary type=%d\n",type);
739
                return -EBADF;
740
        }
741
}

powered by: WebSVN 2.1.0

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