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

Subversion Repositories test_project

[/] [test_project/] [trunk/] [linux_sd_driver/] [fs/] [affs/] [amigaffs.c] - Blame information for rev 62

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 62 marcus.erl
/*
2
 *  linux/fs/affs/amigaffs.c
3
 *
4
 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
5
 *
6
 *  (C) 1993  Ray Burr - Amiga FFS filesystem.
7
 *
8
 *  Please send bug reports to: hjw@zvw.de
9
 */
10
 
11
#include "affs.h"
12
 
13
extern struct timezone sys_tz;
14
 
15
static char ErrorBuffer[256];
16
 
17
/*
18
 * Functions for accessing Amiga-FFS structures.
19
 */
20
 
21
 
22
/* Insert a header block bh into the directory dir
23
 * caller must hold AFFS_DIR->i_hash_lock!
24
 */
25
 
26
int
27
affs_insert_hash(struct inode *dir, struct buffer_head *bh)
28
{
29
        struct super_block *sb = dir->i_sb;
30
        struct buffer_head *dir_bh;
31
        u32 ino, hash_ino;
32
        int offset;
33
 
34
        ino = bh->b_blocknr;
35
        offset = affs_hash_name(sb, AFFS_TAIL(sb, bh)->name + 1, AFFS_TAIL(sb, bh)->name[0]);
36
 
37
        pr_debug("AFFS: insert_hash(dir=%u, ino=%d)\n", (u32)dir->i_ino, ino);
38
 
39
        dir_bh = affs_bread(sb, dir->i_ino);
40
        if (!dir_bh)
41
                return -EIO;
42
 
43
        hash_ino = be32_to_cpu(AFFS_HEAD(dir_bh)->table[offset]);
44
        while (hash_ino) {
45
                affs_brelse(dir_bh);
46
                dir_bh = affs_bread(sb, hash_ino);
47
                if (!dir_bh)
48
                        return -EIO;
49
                hash_ino = be32_to_cpu(AFFS_TAIL(sb, dir_bh)->hash_chain);
50
        }
51
        AFFS_TAIL(sb, bh)->parent = cpu_to_be32(dir->i_ino);
52
        AFFS_TAIL(sb, bh)->hash_chain = 0;
53
        affs_fix_checksum(sb, bh);
54
 
55
        if (dir->i_ino == dir_bh->b_blocknr)
56
                AFFS_HEAD(dir_bh)->table[offset] = cpu_to_be32(ino);
57
        else
58
                AFFS_TAIL(sb, dir_bh)->hash_chain = cpu_to_be32(ino);
59
 
60
        affs_adjust_checksum(dir_bh, ino);
61
        mark_buffer_dirty_inode(dir_bh, dir);
62
        affs_brelse(dir_bh);
63
 
64
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
65
        dir->i_version++;
66
        mark_inode_dirty(dir);
67
 
68
        return 0;
69
}
70
 
71
/* Remove a header block from its directory.
72
 * caller must hold AFFS_DIR->i_hash_lock!
73
 */
74
 
75
int
76
affs_remove_hash(struct inode *dir, struct buffer_head *rem_bh)
77
{
78
        struct super_block *sb;
79
        struct buffer_head *bh;
80
        u32 rem_ino, hash_ino;
81
        __be32 ino;
82
        int offset, retval;
83
 
84
        sb = dir->i_sb;
85
        rem_ino = rem_bh->b_blocknr;
86
        offset = affs_hash_name(sb, AFFS_TAIL(sb, rem_bh)->name+1, AFFS_TAIL(sb, rem_bh)->name[0]);
87
        pr_debug("AFFS: remove_hash(dir=%d, ino=%d, hashval=%d)\n", (u32)dir->i_ino, rem_ino, offset);
88
 
89
        bh = affs_bread(sb, dir->i_ino);
90
        if (!bh)
91
                return -EIO;
92
 
93
        retval = -ENOENT;
94
        hash_ino = be32_to_cpu(AFFS_HEAD(bh)->table[offset]);
95
        while (hash_ino) {
96
                if (hash_ino == rem_ino) {
97
                        ino = AFFS_TAIL(sb, rem_bh)->hash_chain;
98
                        if (dir->i_ino == bh->b_blocknr)
99
                                AFFS_HEAD(bh)->table[offset] = ino;
100
                        else
101
                                AFFS_TAIL(sb, bh)->hash_chain = ino;
102
                        affs_adjust_checksum(bh, be32_to_cpu(ino) - hash_ino);
103
                        mark_buffer_dirty_inode(bh, dir);
104
                        AFFS_TAIL(sb, rem_bh)->parent = 0;
105
                        retval = 0;
106
                        break;
107
                }
108
                affs_brelse(bh);
109
                bh = affs_bread(sb, hash_ino);
110
                if (!bh)
111
                        return -EIO;
112
                hash_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->hash_chain);
113
        }
114
 
115
        affs_brelse(bh);
116
 
117
        dir->i_mtime = dir->i_ctime = CURRENT_TIME_SEC;
118
        dir->i_version++;
119
        mark_inode_dirty(dir);
120
 
121
        return retval;
122
}
123
 
124
static void
125
affs_fix_dcache(struct dentry *dentry, u32 entry_ino)
126
{
127
        struct inode *inode = dentry->d_inode;
128
        void *data = dentry->d_fsdata;
129
        struct list_head *head, *next;
130
 
131
        spin_lock(&dcache_lock);
132
        head = &inode->i_dentry;
133
        next = head->next;
134
        while (next != head) {
135
                dentry = list_entry(next, struct dentry, d_alias);
136
                if (entry_ino == (u32)(long)dentry->d_fsdata) {
137
                        dentry->d_fsdata = data;
138
                        break;
139
                }
140
                next = next->next;
141
        }
142
        spin_unlock(&dcache_lock);
143
}
144
 
145
 
146
/* Remove header from link chain */
147
 
148
static int
149
affs_remove_link(struct dentry *dentry)
150
{
151
        struct inode *dir, *inode = dentry->d_inode;
152
        struct super_block *sb = inode->i_sb;
153
        struct buffer_head *bh = NULL, *link_bh = NULL;
154
        u32 link_ino, ino;
155
        int retval;
156
 
157
        pr_debug("AFFS: remove_link(key=%ld)\n", inode->i_ino);
158
        retval = -EIO;
159
        bh = affs_bread(sb, inode->i_ino);
160
        if (!bh)
161
                goto done;
162
 
163
        link_ino = (u32)(long)dentry->d_fsdata;
164
        if (inode->i_ino == link_ino) {
165
                /* we can't remove the head of the link, as its blocknr is still used as ino,
166
                 * so we remove the block of the first link instead.
167
                 */
168
                link_ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain);
169
                link_bh = affs_bread(sb, link_ino);
170
                if (!link_bh)
171
                        goto done;
172
 
173
                dir = iget(sb, be32_to_cpu(AFFS_TAIL(sb, link_bh)->parent));
174
                if (!dir)
175
                        goto done;
176
 
177
                affs_lock_dir(dir);
178
                affs_fix_dcache(dentry, link_ino);
179
                retval = affs_remove_hash(dir, link_bh);
180
                if (retval)
181
                        goto done;
182
                mark_buffer_dirty_inode(link_bh, inode);
183
 
184
                memcpy(AFFS_TAIL(sb, bh)->name, AFFS_TAIL(sb, link_bh)->name, 32);
185
                retval = affs_insert_hash(dir, bh);
186
                if (retval)
187
                        goto done;
188
                mark_buffer_dirty_inode(bh, inode);
189
 
190
                affs_unlock_dir(dir);
191
                iput(dir);
192
        } else {
193
                link_bh = affs_bread(sb, link_ino);
194
                if (!link_bh)
195
                        goto done;
196
        }
197
 
198
        while ((ino = be32_to_cpu(AFFS_TAIL(sb, bh)->link_chain)) != 0) {
199
                if (ino == link_ino) {
200
                        __be32 ino2 = AFFS_TAIL(sb, link_bh)->link_chain;
201
                        AFFS_TAIL(sb, bh)->link_chain = ino2;
202
                        affs_adjust_checksum(bh, be32_to_cpu(ino2) - link_ino);
203
                        mark_buffer_dirty_inode(bh, inode);
204
                        retval = 0;
205
                        /* Fix the link count, if bh is a normal header block without links */
206
                        switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
207
                        case ST_LINKDIR:
208
                        case ST_LINKFILE:
209
                                break;
210
                        default:
211
                                if (!AFFS_TAIL(sb, bh)->link_chain)
212
                                        inode->i_nlink = 1;
213
                        }
214
                        affs_free_block(sb, link_ino);
215
                        goto done;
216
                }
217
                affs_brelse(bh);
218
                bh = affs_bread(sb, ino);
219
                if (!bh)
220
                        goto done;
221
        }
222
        retval = -ENOENT;
223
done:
224
        affs_brelse(link_bh);
225
        affs_brelse(bh);
226
        return retval;
227
}
228
 
229
 
230
static int
231
affs_empty_dir(struct inode *inode)
232
{
233
        struct super_block *sb = inode->i_sb;
234
        struct buffer_head *bh;
235
        int retval, size;
236
 
237
        retval = -EIO;
238
        bh = affs_bread(sb, inode->i_ino);
239
        if (!bh)
240
                goto done;
241
 
242
        retval = -ENOTEMPTY;
243
        for (size = AFFS_SB(sb)->s_hashsize - 1; size >= 0; size--)
244
                if (AFFS_HEAD(bh)->table[size])
245
                        goto not_empty;
246
        retval = 0;
247
not_empty:
248
        affs_brelse(bh);
249
done:
250
        return retval;
251
}
252
 
253
 
254
/* Remove a filesystem object. If the object to be removed has
255
 * links to it, one of the links must be changed to inherit
256
 * the file or directory. As above, any inode will do.
257
 * The buffer will not be freed. If the header is a link, the
258
 * block will be marked as free.
259
 * This function returns a negative error number in case of
260
 * an error, else 0 if the inode is to be deleted or 1 if not.
261
 */
262
 
263
int
264
affs_remove_header(struct dentry *dentry)
265
{
266
        struct super_block *sb;
267
        struct inode *inode, *dir;
268
        struct buffer_head *bh = NULL;
269
        int retval;
270
 
271
        dir = dentry->d_parent->d_inode;
272
        sb = dir->i_sb;
273
 
274
        retval = -ENOENT;
275
        inode = dentry->d_inode;
276
        if (!inode)
277
                goto done;
278
 
279
        pr_debug("AFFS: remove_header(key=%ld)\n", inode->i_ino);
280
        retval = -EIO;
281
        bh = affs_bread(sb, (u32)(long)dentry->d_fsdata);
282
        if (!bh)
283
                goto done;
284
 
285
        affs_lock_link(inode);
286
        affs_lock_dir(dir);
287
        switch (be32_to_cpu(AFFS_TAIL(sb, bh)->stype)) {
288
        case ST_USERDIR:
289
                /* if we ever want to support links to dirs
290
                 * i_hash_lock of the inode must only be
291
                 * taken after some checks
292
                 */
293
                affs_lock_dir(inode);
294
                retval = affs_empty_dir(inode);
295
                affs_unlock_dir(inode);
296
                if (retval)
297
                        goto done_unlock;
298
                break;
299
        default:
300
                break;
301
        }
302
 
303
        retval = affs_remove_hash(dir, bh);
304
        if (retval)
305
                goto done_unlock;
306
        mark_buffer_dirty_inode(bh, inode);
307
 
308
        affs_unlock_dir(dir);
309
 
310
        if (inode->i_nlink > 1)
311
                retval = affs_remove_link(dentry);
312
        else
313
                inode->i_nlink = 0;
314
        affs_unlock_link(inode);
315
        inode->i_ctime = CURRENT_TIME_SEC;
316
        mark_inode_dirty(inode);
317
 
318
done:
319
        affs_brelse(bh);
320
        return retval;
321
 
322
done_unlock:
323
        affs_unlock_dir(dir);
324
        affs_unlock_link(inode);
325
        goto done;
326
}
327
 
328
/* Checksum a block, do various consistency checks and optionally return
329
   the blocks type number.  DATA points to the block.  If their pointers
330
   are non-null, *PTYPE and *STYPE are set to the primary and secondary
331
   block types respectively, *HASHSIZE is set to the size of the hashtable
332
   (which lets us calculate the block size).
333
   Returns non-zero if the block is not consistent. */
334
 
335
u32
336
affs_checksum_block(struct super_block *sb, struct buffer_head *bh)
337
{
338
        __be32 *ptr = (__be32 *)bh->b_data;
339
        u32 sum;
340
        int bsize;
341
 
342
        sum = 0;
343
        for (bsize = sb->s_blocksize / sizeof(__be32); bsize > 0; bsize--)
344
                sum += be32_to_cpu(*ptr++);
345
        return sum;
346
}
347
 
348
/*
349
 * Calculate the checksum of a disk block and store it
350
 * at the indicated position.
351
 */
352
 
353
void
354
affs_fix_checksum(struct super_block *sb, struct buffer_head *bh)
355
{
356
        int cnt = sb->s_blocksize / sizeof(__be32);
357
        __be32 *ptr = (__be32 *)bh->b_data;
358
        u32 checksum;
359
        __be32 *checksumptr;
360
 
361
        checksumptr = ptr + 5;
362
        *checksumptr = 0;
363
        for (checksum = 0; cnt > 0; ptr++, cnt--)
364
                checksum += be32_to_cpu(*ptr);
365
        *checksumptr = cpu_to_be32(-checksum);
366
}
367
 
368
void
369
secs_to_datestamp(time_t secs, struct affs_date *ds)
370
{
371
        u32      days;
372
        u32      minute;
373
 
374
        secs -= sys_tz.tz_minuteswest * 60 + ((8 * 365 + 2) * 24 * 60 * 60);
375
        if (secs < 0)
376
                secs = 0;
377
        days    = secs / 86400;
378
        secs   -= days * 86400;
379
        minute  = secs / 60;
380
        secs   -= minute * 60;
381
 
382
        ds->days = cpu_to_be32(days);
383
        ds->mins = cpu_to_be32(minute);
384
        ds->ticks = cpu_to_be32(secs * 50);
385
}
386
 
387
mode_t
388
prot_to_mode(u32 prot)
389
{
390
        int mode = 0;
391
 
392
        if (!(prot & FIBF_NOWRITE))
393
                mode |= S_IWUSR;
394
        if (!(prot & FIBF_NOREAD))
395
                mode |= S_IRUSR;
396
        if (!(prot & FIBF_NOEXECUTE))
397
                mode |= S_IXUSR;
398
        if (prot & FIBF_GRP_WRITE)
399
                mode |= S_IWGRP;
400
        if (prot & FIBF_GRP_READ)
401
                mode |= S_IRGRP;
402
        if (prot & FIBF_GRP_EXECUTE)
403
                mode |= S_IXGRP;
404
        if (prot & FIBF_OTR_WRITE)
405
                mode |= S_IWOTH;
406
        if (prot & FIBF_OTR_READ)
407
                mode |= S_IROTH;
408
        if (prot & FIBF_OTR_EXECUTE)
409
                mode |= S_IXOTH;
410
 
411
        return mode;
412
}
413
 
414
void
415
mode_to_prot(struct inode *inode)
416
{
417
        u32 prot = AFFS_I(inode)->i_protect;
418
        mode_t mode = inode->i_mode;
419
 
420
        if (!(mode & S_IXUSR))
421
                prot |= FIBF_NOEXECUTE;
422
        if (!(mode & S_IRUSR))
423
                prot |= FIBF_NOREAD;
424
        if (!(mode & S_IWUSR))
425
                prot |= FIBF_NOWRITE;
426
        if (mode & S_IXGRP)
427
                prot |= FIBF_GRP_EXECUTE;
428
        if (mode & S_IRGRP)
429
                prot |= FIBF_GRP_READ;
430
        if (mode & S_IWGRP)
431
                prot |= FIBF_GRP_WRITE;
432
        if (mode & S_IXOTH)
433
                prot |= FIBF_OTR_EXECUTE;
434
        if (mode & S_IROTH)
435
                prot |= FIBF_OTR_READ;
436
        if (mode & S_IWOTH)
437
                prot |= FIBF_OTR_WRITE;
438
 
439
        AFFS_I(inode)->i_protect = prot;
440
}
441
 
442
void
443
affs_error(struct super_block *sb, const char *function, const char *fmt, ...)
444
{
445
        va_list  args;
446
 
447
        va_start(args,fmt);
448
        vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args);
449
        va_end(args);
450
 
451
        printk(KERN_CRIT "AFFS error (device %s): %s(): %s\n", sb->s_id,
452
                function,ErrorBuffer);
453
        if (!(sb->s_flags & MS_RDONLY))
454
                printk(KERN_WARNING "AFFS: Remounting filesystem read-only\n");
455
        sb->s_flags |= MS_RDONLY;
456
}
457
 
458
void
459
affs_warning(struct super_block *sb, const char *function, const char *fmt, ...)
460
{
461
        va_list  args;
462
 
463
        va_start(args,fmt);
464
        vsnprintf(ErrorBuffer,sizeof(ErrorBuffer),fmt,args);
465
        va_end(args);
466
 
467
        printk(KERN_WARNING "AFFS warning (device %s): %s(): %s\n", sb->s_id,
468
                function,ErrorBuffer);
469
}
470
 
471
/* Check if the name is valid for a affs object. */
472
 
473
int
474
affs_check_name(const unsigned char *name, int len)
475
{
476
        int      i;
477
 
478
        if (len > 30)
479
#ifdef AFFS_NO_TRUNCATE
480
                return -ENAMETOOLONG;
481
#else
482
                len = 30;
483
#endif
484
 
485
        for (i = 0; i < len; i++) {
486
                if (name[i] < ' ' || name[i] == ':'
487
                    || (name[i] > 0x7e && name[i] < 0xa0))
488
                        return -EINVAL;
489
        }
490
 
491
        return 0;
492
}
493
 
494
/* This function copies name to bstr, with at most 30
495
 * characters length. The bstr will be prepended by
496
 * a length byte.
497
 * NOTE: The name will must be already checked by
498
 *       affs_check_name()!
499
 */
500
 
501
int
502
affs_copy_name(unsigned char *bstr, struct dentry *dentry)
503
{
504
        int len = min(dentry->d_name.len, 30u);
505
 
506
        *bstr++ = len;
507
        memcpy(bstr, dentry->d_name.name, len);
508
        return len;
509
}

powered by: WebSVN 2.1.0

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