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

Subversion Repositories or1k

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

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 199 simons
/*
2
 *  linux/fs/affs/file.c
3
 *
4
 *  (c) 1996  Hans-Joachim Widmaier - Rewritten
5
 *
6
 *  (C) 1993  Ray Burr - Modified for Amiga FFS filesystem.
7
 *
8
 *  (C) 1992  Eric Youngdale Modified for ISO9660 filesystem.
9
 *
10
 *  (C) 1991  Linus Torvalds - minix filesystem
11
 *
12
 *  affs regular file handling primitives
13
 */
14
 
15
#include <asm/segment.h>
16
#include <asm/system.h>
17
#include <linux/sched.h>
18
#include <linux/affs_fs.h>
19
#include <linux/fcntl.h>
20
#include <linux/kernel.h>
21
#include <linux/errno.h>
22
#include <linux/stat.h>
23
#include <linux/locks.h>
24
#include <linux/dirent.h>
25
#include <linux/fs.h>
26
#include <linux/amigaffs.h>
27
#include <linux/mm.h>
28
#include <linux/pagemap.h>
29
 
30
#define MIN(a,b) (((a)<(b))?(a):(b))
31
#define MAX(a,b) (((a)>(b))?(a):(b))
32
 
33
static int affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count);
34
static int affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count);
35
static int affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count);
36
static void affs_release_file(struct inode *inode, struct file *filp);
37
 
38
static struct file_operations affs_file_operations = {
39
        NULL,                   /* lseek - default */
40
        generic_file_read,      /* read */
41
        affs_file_write,        /* write */
42
        NULL,                   /* readdir - bad */
43
        NULL,                   /* select - default */
44
        NULL,                   /* ioctl - default */
45
        generic_file_mmap,      /* mmap */
46
        NULL,                   /* no special open is needed */
47
        affs_release_file,      /* release */
48
        file_fsync              /* brute force, but works */
49
};
50
 
51
struct inode_operations affs_file_inode_operations = {
52
        &affs_file_operations,  /* default file operations */
53
        NULL,                   /* create */
54
        NULL,                   /* lookup */
55
        NULL,                   /* link */
56
        NULL,                   /* unlink */
57
        NULL,                   /* symlink */
58
        NULL,                   /* mkdir */
59
        NULL,                   /* rmdir */
60
        NULL,                   /* mknod */
61
        NULL,                   /* rename */
62
        NULL,                   /* readlink */
63
        NULL,                   /* follow_link */
64
        generic_readpage,       /* readpage */
65
        NULL,                   /* writepage */
66
        affs_bmap,              /* bmap */
67
        affs_truncate,          /* truncate */
68
        NULL,                   /* permission */
69
        NULL                    /* smap */
70
};
71
 
72
static struct file_operations affs_file_operations_ofs = {
73
        NULL,                   /* lseek - default */
74
        affs_file_read_ofs,     /* read */
75
        affs_file_write_ofs,    /* write */
76
        NULL,                   /* readdir - bad */
77
        NULL,                   /* select - default */
78
        NULL,                   /* ioctl - default */
79
        NULL,                   /* mmap */
80
        NULL,                   /* no special open is needed */
81
        affs_release_file,      /* release */
82
        file_fsync              /* brute force, but works */
83
};
84
 
85
struct inode_operations affs_file_inode_operations_ofs = {
86
        &affs_file_operations_ofs,      /* default file operations */
87
        NULL,                   /* create */
88
        NULL,                   /* lookup */
89
        NULL,                   /* link */
90
        NULL,                   /* unlink */
91
        NULL,                   /* symlink */
92
        NULL,                   /* mkdir */
93
        NULL,                   /* rmdir */
94
        NULL,                   /* mknod */
95
        NULL,                   /* rename */
96
        NULL,                   /* readlink */
97
        NULL,                   /* follow_link */
98
        NULL,                   /* readpage */
99
        NULL,                   /* writepage */
100
        NULL,                   /* bmap */
101
        affs_truncate,          /* truncate */
102
        NULL,                   /* permission */
103
        NULL                    /* smap */
104
};
105
 
106
int
107
affs_bmap(struct inode *inode, int block)
108
{
109
        struct buffer_head      *bh;
110
        int                      ext, key;
111
        int                      ptype, stype;
112
 
113
        pr_debug("AFFS: bmap(%lu,%d)\n",inode->i_ino,block);
114
 
115
        if (block < 0) {
116
                printk("affs_bmap: block < 0\n");
117
                return 0;
118
        }
119
 
120
        /* If this is a hard link, quietly exchange the inode with the original */
121
 
122
        key = inode->u.affs_i.i_original ? inode->u.affs_i.i_original : inode->i_ino;
123
 
124
        ext = block / AFFS_I2HSIZE(inode);
125
        if (ext) {
126
                if (ext > inode->u.affs_i.i_max_ext)
127
                        ext = inode->u.affs_i.i_max_ext;
128
                if (ext)
129
                        key = inode->u.affs_i.i_ext[ext -  1];
130
                block -= ext * AFFS_I2HSIZE(inode);
131
        }
132
 
133
        for (;;) {
134
                bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
135
                if (!bh)
136
                        return 0;
137
                if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&ptype,&stype) ||
138
                    (ptype != T_SHORT && ptype != T_LIST) || stype != ST_FILE) {
139
                        affs_brelse(bh);
140
                        return 0;
141
                }
142
                if (block < AFFS_I2HSIZE(inode))
143
                        break;
144
                block -= AFFS_I2HSIZE(inode);
145
                key    = htonl(FILE_END(bh->b_data,inode)->extension);
146
                affs_brelse(bh);
147
                if (ext < EXT_CACHE_SIZE - 1) {
148
                        inode->u.affs_i.i_ext[ext] = key;
149
                        inode->u.affs_i.i_max_ext  = ++ext;
150
                }
151
        }
152
        key = AFFS_GET_HASHENTRY(bh->b_data,(AFFS_I2HSIZE(inode) - 1) - block);
153
        affs_brelse(bh);
154
        return key;
155
}
156
 
157
struct buffer_head *
158
affs_getblock(struct inode *inode, int block)
159
{
160
        struct buffer_head      *bh;
161
        struct buffer_head      *ebh;
162
        int                      key;
163
        int                      ext;
164
        int                      cnt, j, pt;
165
 
166
        pr_debug("AFFS: getblock(%lu,%d)\n",inode->i_ino,block);
167
 
168
        if (block < 0)
169
                return NULL;
170
        key = inode->i_ino;
171
        pt  = T_SHORT;
172
 
173
        ext = block / AFFS_I2HSIZE(inode);
174
        if (ext) {
175
                if (ext > inode->u.affs_i.i_max_ext)
176
                        ext = inode->u.affs_i.i_max_ext;
177
                if (ext) {
178
                        key    = inode->u.affs_i.i_ext[ext - 1];
179
                        block -= ext * AFFS_I2HSIZE(inode);
180
                        pt     = T_LIST;
181
                }
182
        }
183
 
184
        for (;;) {
185
                bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
186
                if (!bh)
187
                        return NULL;
188
                if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
189
                    cnt != pt || j != ST_FILE) {
190
                        printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
191
                               pt == T_SHORT ? "file header" : "extension block");
192
                        affs_brelse(bh);
193
                        return NULL;
194
                }
195
                j = htonl(((struct file_front *)bh->b_data)->block_count);
196
                while (j < AFFS_I2HSIZE(inode) && j <= block) {
197
                        key = affs_new_data(inode);
198
                        if (!key)
199
                                break;
200
                        lock_super(inode->i_sb);
201
                        if (AFFS_BLOCK(bh->b_data,inode,j)) {
202
                                unlock_super(inode->i_sb);
203
                                printk("AFFS: getblock(): block already allocated\n");
204
                                affs_free_block(inode->i_sb,key);
205
                                j++;
206
                                continue;
207
                        }
208
                        unlock_super(inode->i_sb);
209
                        AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
210
                        j++;
211
                }
212
                if (pt == T_SHORT)
213
                        ((struct file_front *)bh->b_data)->first_data =
214
                                                                AFFS_BLOCK(bh->b_data,inode,0);
215
                ((struct file_front *)bh->b_data)->block_count = ntohl(j);
216
                affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
217
                mark_buffer_dirty(bh,1);
218
 
219
                if (block < j)
220
                        break;
221
                if (j < AFFS_I2HSIZE(inode)) {
222
                        affs_brelse(bh);
223
                        return NULL;
224
                }
225
 
226
                block -= AFFS_I2HSIZE(inode);
227
                key    = htonl(FILE_END(bh->b_data,inode)->extension);
228
                if (!key) {
229
                        key = affs_new_header(inode);
230
                        if (!key) {
231
                                affs_brelse(bh);
232
                                return NULL;
233
                        }
234
                        ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
235
                        if (!ebh) {
236
                                affs_free_block(inode->i_sb,key);
237
                                return NULL;
238
                        }
239
                        ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
240
                        ((struct file_front *)ebh->b_data)->own_key      = ntohl(key);
241
                        FILE_END(ebh->b_data,inode)->secondary_type      = ntohl(ST_FILE);
242
                        FILE_END(ebh->b_data,inode)->parent              = ntohl(inode->i_ino);
243
                        affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
244
                        FILE_END(bh->b_data,inode)->extension = ntohl(key);
245
                        affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
246
                        mark_buffer_dirty(bh,1);
247
                        affs_brelse(bh);
248
                        bh = ebh;
249
                }
250
                affs_brelse(bh);
251
                pt = T_LIST;
252
                if (ext < EXT_CACHE_SIZE - 1) {
253
                        inode->u.affs_i.i_ext[ext] = key;
254
                        inode->u.affs_i.i_max_ext  = ++ext;
255
                }
256
        }
257
        key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
258
        affs_brelse(bh);
259
        if (!key)
260
                return NULL;
261
 
262
        return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
263
}
264
 
265
struct buffer_head *
266
affs_getblock_ofs(struct inode *inode, int block, int *blk_key)
267
{
268
        struct buffer_head      *bh;
269
        struct buffer_head      *pbh;
270
        struct buffer_head      *ebh;
271
        int                      key;
272
        int                      ext;
273
        int                      cnt, j, pt;
274
 
275
        pr_debug("AFFS: getblock_ofs(%lu,%d)\n",inode->i_ino,block);
276
 
277
        if (block < 0)
278
                return NULL;
279
        key = inode->i_ino;
280
        pt  = T_SHORT;
281
 
282
        ext = block / AFFS_I2HSIZE(inode);
283
        if (ext) {
284
                if (ext > inode->u.affs_i.i_max_ext)
285
                        ext = inode->u.affs_i.i_max_ext;
286
                if (ext) {
287
                        key    = inode->u.affs_i.i_ext[ext - 1];
288
                        block -= ext * AFFS_I2HSIZE(inode);
289
                        pt     = T_LIST;
290
                }
291
        }
292
 
293
        pbh = NULL;
294
        for (;;) {
295
                bh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
296
                if (!bh)
297
                        return NULL;
298
                if (affs_checksum_block(AFFS_I2BSIZE(inode),bh->b_data,&cnt,&j) ||
299
                    cnt != pt || j != ST_FILE) {
300
                        printk("AFFS: getblock(): inode %d is not a valid %s\n",key,
301
                               pt == T_SHORT ? "file header" : "extension block");
302
                        affs_brelse(bh);
303
                        return NULL;
304
                }
305
                j = htonl(((struct file_front *)bh->b_data)->block_count);
306
                while (j < AFFS_I2HSIZE(inode) && j <= block) {
307
                        if (!pbh && inode->u.affs_i.i_lastblock >= 0) {
308
                                if (j > 0)
309
                                        pbh = affs_bread(inode->i_dev,ntohl(AFFS_BLOCK(bh->b_data,inode,j - 1)),
310
                                                         AFFS_I2BSIZE(inode));
311
                                else
312
                                        pbh = affs_getblock_ofs(inode,inode->u.affs_i.i_lastblock,&key);
313
                                if (!pbh) {
314
                                        printk("AFFS: getblock(): cannot get last block in file\n");
315
                                        break;
316
                                }
317
                        }
318
                        key = affs_new_data(inode);
319
                        if (!key)
320
                                break;
321
                        lock_super(inode->i_sb);
322
                        if (AFFS_BLOCK(bh->b_data,inode,j)) {
323
                                unlock_super(inode->i_sb);
324
                                printk("AFFS: getblock(): block already allocated\n");
325
                                affs_free_block(inode->i_sb,key);
326
                                j++;
327
                                continue;
328
                        }
329
                        AFFS_BLOCK(bh->b_data,inode,j) = ntohl(key);
330
                        unlock_super(inode->i_sb);
331
                        ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
332
                        if (!ebh) {
333
                                printk("AFFS: getblock(): cannot get block %d\n",key);
334
                                affs_free_block(inode->i_sb,key);
335
                                AFFS_BLOCK(bh->b_data,inode,j) = 0;
336
                                break;
337
                        }
338
                        inode->u.affs_i.i_lastblock++;
339
                        DATA_FRONT(ebh)->primary_type    = ntohl(T_DATA);
340
                        DATA_FRONT(ebh)->header_key      = ntohl(inode->i_ino);
341
                        DATA_FRONT(ebh)->sequence_number = ntohl(inode->u.affs_i.i_lastblock + 1);
342
                        if (pbh) {
343
                                DATA_FRONT(pbh)->data_size = ntohl(AFFS_I2BSIZE(inode) - 24);
344
                                DATA_FRONT(pbh)->next_data = ntohl(key);
345
                                affs_fix_checksum(AFFS_I2BSIZE(inode),pbh->b_data,5);
346
                                mark_buffer_dirty(pbh,0);
347
                                mark_buffer_dirty(ebh,0);
348
                                affs_brelse(pbh);
349
                        }
350
                        pbh = ebh;
351
                        j++;
352
                }
353
                if (pt == T_SHORT)
354
                        ((struct file_front *)bh->b_data)->first_data =
355
                                                                AFFS_BLOCK(bh->b_data,inode,0);
356
                ((struct file_front *)bh->b_data)->block_count = ntohl(j);
357
                affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
358
                mark_buffer_dirty(bh,1);
359
 
360
                if (block < j) {
361
                        if (pbh)
362
                                affs_brelse(pbh);
363
                        break;
364
                }
365
                if (j < AFFS_I2HSIZE(inode)) {
366
                        affs_brelse(bh);
367
                        return NULL;
368
                }
369
 
370
                block -= AFFS_I2HSIZE(inode);
371
                key    = htonl(FILE_END(bh->b_data,inode)->extension);
372
                if (!key) {
373
                        key = affs_new_header(inode);
374
                        if (!key) {
375
                                affs_brelse(bh);
376
                                return NULL;
377
                        }
378
                        ebh = affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
379
                        if (!ebh) {
380
                                affs_free_block(inode->i_sb,key);
381
                                return NULL;
382
                        }
383
                        ((struct file_front *)ebh->b_data)->primary_type = ntohl(T_LIST);
384
                        ((struct file_front *)ebh->b_data)->own_key      = ntohl(key);
385
                        FILE_END(ebh->b_data,inode)->secondary_type      = ntohl(ST_FILE);
386
                        FILE_END(ebh->b_data,inode)->parent              = ntohl(inode->i_ino);
387
                        affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
388
                        FILE_END(bh->b_data,inode)->extension = ntohl(key);
389
                        affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
390
                        mark_buffer_dirty(bh,1);
391
                        affs_brelse(bh);
392
                        bh = ebh;
393
                }
394
                affs_brelse(bh);
395
                pt = T_LIST;
396
                if (ext < EXT_CACHE_SIZE - 1) {
397
                        inode->u.affs_i.i_ext[ext] = key;
398
                        inode->u.affs_i.i_max_ext  = ++ext;
399
                }
400
        }
401
        key = htonl(AFFS_BLOCK(bh->b_data,inode,block));
402
        affs_brelse(bh);
403
        if (!key)
404
                return NULL;
405
        *blk_key = key;
406
 
407
        return affs_bread(inode->i_dev,key,AFFS_I2BSIZE(inode));
408
}
409
 
410
/* This could be made static, regardless of what the former comment said.
411
 * You cannot directly read affs directories.
412
 */
413
 
414
static int
415
affs_file_read_ofs(struct inode *inode, struct file *filp, char *buf, int count)
416
{
417
        char *start;
418
        int left, offset, size, sector;
419
        int blocksize;
420
        struct buffer_head *bh;
421
        void *data;
422
 
423
        pr_debug("AFFS: file_read_ofs(ino=%lu,pos=%lu,%d)\n",inode->i_ino,(long)filp->f_pos,count);
424
 
425
        if (!inode) {
426
                printk("affs_file_read: inode = NULL\n");
427
                return -EINVAL;
428
        }
429
        blocksize = AFFS_I2BSIZE(inode) - 24;
430
        if (!(S_ISREG(inode->i_mode))) {
431
                pr_debug("affs_file_read: mode = %07o\n",inode->i_mode);
432
                return -EINVAL;
433
        }
434
        if (filp->f_pos >= inode->i_size || count <= 0)
435
                return 0;
436
 
437
        start = buf;
438
        for (;;) {
439
                left = MIN (inode->i_size - filp->f_pos,count - (buf - start));
440
                if (!left)
441
                        break;
442
                sector = affs_bmap(inode,(__u32)filp->f_pos / blocksize);
443
                if (!sector)
444
                        break;
445
                offset = (__u32)filp->f_pos % blocksize;
446
                bh = affs_bread(inode->i_dev,sector,AFFS_I2BSIZE(inode));
447
                if (!bh)
448
                        break;
449
                data = bh->b_data + 24;
450
                size = MIN(blocksize - offset,left);
451
                filp->f_pos += size;
452
                memcpy_tofs(buf,data + offset,size);
453
                buf += size;
454
                affs_brelse(bh);
455
        }
456
        if (start == buf)
457
                return -EIO;
458
        return buf - start;
459
}
460
 
461
static int
462
affs_file_write(struct inode *inode, struct file *filp, const char *buf, int count)
463
{
464
        off_t                    pos;
465
        int                      written;
466
        int                      c;
467
        int                      blocksize;
468
        struct buffer_head      *bh;
469
        struct inode            *ino;
470
        char                    *p;
471
 
472
        pr_debug("AFFS: file_write(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
473
                (unsigned long)filp->f_pos,count);
474
 
475
        ino = NULL;
476
        if (!inode) {
477
                printk("AFFS: file_write(): inode=NULL\n");
478
                return -EINVAL;
479
        }
480
        if (inode->u.affs_i.i_original) {
481
                ino = iget(inode->i_sb,inode->u.affs_i.i_original);
482
                if (!ino) {
483
                        printk("AFFS: could not follow link from inode %lu to %d\n",
484
                               inode->i_ino,inode->u.affs_i.i_original);
485
                        return -EINVAL;
486
                }
487
                inode = ino;
488
        }
489
        if (!S_ISREG(inode->i_mode)) {
490
                printk("AFFS: file_write(): mode=%07o\n",inode->i_mode);
491
                iput(inode);
492
                return -EINVAL;
493
        }
494
        if (filp->f_flags & O_APPEND) {
495
                pos = inode->i_size;
496
        } else
497
                pos = filp->f_pos;
498
        written   = 0;
499
        blocksize = AFFS_I2BSIZE(inode);
500
 
501
        while (written < count) {
502
                bh = affs_getblock(inode,pos / blocksize);
503
                if (!bh) {
504
                        if (!written)
505
                                written = -ENOSPC;
506
                        break;
507
                }
508
                c = blocksize - (pos % blocksize);
509
                if (c > count - written)
510
                        c = count - written;
511
                if (c != blocksize && !buffer_uptodate(bh)) {
512
                        ll_rw_block(READ,1,&bh);
513
                        wait_on_buffer(bh);
514
                        if (!buffer_uptodate(bh)) {
515
                                affs_brelse(bh);
516
                                if (!written)
517
                                        written = -EIO;
518
                                break;
519
                        }
520
                }
521
                p = (pos % blocksize) + bh->b_data;
522
                memcpy_fromfs(p,buf,c);
523
                update_vm_cache(inode,pos,p,c);
524
                mark_buffer_uptodate(bh,1);
525
                mark_buffer_dirty(bh,0);
526
                affs_brelse(bh);
527
                pos     += c;
528
                written += c;
529
                buf     += c;
530
        }
531
        if (pos > inode->i_size)
532
                inode->i_size = pos;
533
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
534
        filp->f_pos    = pos;
535
        inode->i_dirt  = 1;
536
        iput(ino);
537
        return written;
538
}
539
 
540
static int
541
affs_file_write_ofs(struct inode *inode, struct file *filp, const char *buf, int count)
542
{
543
        off_t                    pos;
544
        int                      written;
545
        int                      c;
546
        int                      key;
547
        int                      blocksize;
548
        struct buffer_head      *bh;
549
        struct inode            *ino;
550
        char                    *p;
551
 
552
        pr_debug("AFFS: file_write_ofs(ino=%lu,pos=%lu,count=%d)\n",inode->i_ino,
553
                (unsigned long)filp->f_pos,count);
554
 
555
        if (!inode) {
556
                printk("AFFS: file_write_ofs(): inode=NULL\n");
557
                return -EINVAL;
558
        }
559
        ino = NULL;
560
        if (inode->u.affs_i.i_original) {
561
                ino = iget(inode->i_sb,inode->u.affs_i.i_original);
562
                if (!ino) {
563
                        printk("AFFS: could not follow link from inode %lu to %d\n",
564
                               inode->i_ino,inode->u.affs_i.i_original);
565
                        return -EINVAL;
566
                }
567
                inode = ino;
568
        }
569
        if (!S_ISREG(inode->i_mode)) {
570
                printk("AFFS: file_write_ofs(): mode=%07o\n",inode->i_mode);
571
                iput(inode);
572
                return -EINVAL;
573
        }
574
        if (filp->f_flags & O_APPEND)
575
                pos = inode->i_size;
576
        else
577
                pos = filp->f_pos;
578
 
579
        bh        = NULL;
580
        blocksize = AFFS_I2BSIZE(inode) - 24;
581
        written   = 0;
582
        while (written < count) {
583
                bh = affs_getblock_ofs(inode,pos / blocksize,&key);
584
                if (!bh) {
585
                        if (!written)
586
                                written = -ENOSPC;
587
                        break;
588
                }
589
                c = blocksize - (pos % blocksize);
590
                if (c > count - written)
591
                        c = count - written;
592
                if (c != blocksize && !buffer_uptodate(bh)) {
593
                        ll_rw_block(READ,1,&bh);
594
                        wait_on_buffer(bh);
595
                        if (!buffer_uptodate(bh)) {
596
                                affs_brelse(bh);
597
                                if (!written)
598
                                        written = -EIO;
599
                                break;
600
                        }
601
                }
602
                p = (pos % blocksize) + bh->b_data + 24;
603
                memcpy_fromfs(p,buf,c);
604
                update_vm_cache(inode,pos,p,c);
605
 
606
                pos     += c;
607
                buf     += c;
608
                written += c;
609
                DATA_FRONT(bh)->data_size = ntohl(htonl(DATA_FRONT(bh)->data_size) + c);
610
                affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
611
                mark_buffer_uptodate(bh,1);
612
                mark_buffer_dirty(bh,0);
613
                affs_brelse(bh);
614
        }
615
        if (pos > inode->i_size)
616
                inode->i_size = pos;
617
        filp->f_pos = pos;
618
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
619
        inode->i_dirt  = 1;
620
        iput(ino);
621
        return written;
622
}
623
 
624
void
625
affs_truncate(struct inode *inode)
626
{
627
        struct buffer_head      *bh;
628
        struct buffer_head      *ebh;
629
        struct inode            *ino;
630
        struct affs_zone        *zone;
631
        int      first;
632
        int      block;
633
        int      key;
634
        int     *keyp;
635
        int      ekey;
636
        int      ptype, stype;
637
        int      freethis;
638
        int      blocksize;
639
        int      rem;
640
        int      ext;
641
 
642
        pr_debug("AFFS: file_truncate(inode=%ld,size=%lu)\n",inode->i_ino,inode->i_size);
643
 
644
        ino = NULL;
645
        if (inode->u.affs_i.i_original) {
646
                ino = iget(inode->i_sb,inode->u.affs_i.i_original);
647
                if (!ino) {
648
                        printk("AFFS: truncate(): cannot follow link from %lu to %u\n",
649
                               inode->i_ino,inode->u.affs_i.i_original);
650
                        return;
651
                }
652
                inode = ino;
653
        }
654
        blocksize = AFFS_I2BSIZE(inode) - ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) ? 24 : 0);
655
        first = (inode->i_size + blocksize - 1) / blocksize;
656
        if (inode->u.affs_i.i_lastblock < first - 1) {
657
                if (inode->i_sb->u.affs_sb.s_flags & SF_OFS)
658
                        bh = affs_getblock_ofs(inode,first - 1,&ekey);
659
                else
660
                        bh = affs_getblock(inode,first - 1);
661
 
662
                while (inode->u.affs_i.i_pa_cnt) {              /* Free any preallocated blocks */
663
                        affs_free_block(inode->i_sb,
664
                                        inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
665
                        inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
666
                        inode->u.affs_i.i_pa_cnt--;
667
                }
668
                if (inode->u.affs_i.i_zone) {
669
                        lock_super(inode->i_sb);
670
                        zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
671
                        if (zone->z_ino == inode->i_ino)
672
                                zone->z_ino = 0;
673
                        unlock_super(inode->i_sb);
674
                }
675
                if (!bh) {
676
                        printk("AFFS: truncate(): Cannot extend file\n");
677
                        inode->i_size = blocksize * (inode->u.affs_i.i_lastblock + 1);
678
                } else if (inode->i_sb->u.affs_sb.s_flags & SF_OFS) {
679
                        rem = inode->i_size % blocksize;
680
                        DATA_FRONT(bh)->data_size = ntohl(rem ? rem : blocksize);
681
                        affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
682
                        mark_buffer_dirty(bh,0);
683
                }
684
                affs_brelse(bh);
685
                iput(ino);
686
                return;
687
        }
688
        ekey  = inode->i_ino;
689
        ext   = 0;
690
 
691
        while (ekey) {
692
                if (!(bh = affs_bread(inode->i_dev,ekey,AFFS_I2BSIZE(inode)))) {
693
                        printk("AFFS: truncate(): Can't read block %d\n",ekey);
694
                        break;
695
                }
696
                ptype = htonl(((struct file_front *)bh->b_data)->primary_type);
697
                stype = htonl(FILE_END(bh->b_data,inode)->secondary_type);
698
                if (ekey == inode->i_ino && ptype == T_SHORT && stype == ST_LINKFILE &&
699
                    LINK_END(bh->b_data,inode)->original == 0) {
700
                        pr_debug("AFFS: truncate(): dumping link\n");
701
                        affs_brelse(bh);
702
                        break;
703
                }
704
                if (stype != ST_FILE || (ptype != T_SHORT && ptype != T_LIST)) {
705
                        printk("AFFS: truncate(): bad block (ptype=%d, stype=%d)\n",
706
                                ptype,stype);
707
                        affs_brelse(bh);
708
                        break;
709
                }
710
                /* Do not throw away file header */
711
                freethis = first == 0 && ekey != inode->i_ino;
712
                for ( block = first; block < AFFS_I2HSIZE(inode); block++) {
713
                        keyp = &AFFS_BLOCK(bh->b_data,inode,block);
714
                        key  = htonl(*keyp);
715
                        if (key) {
716
                                *keyp = 0;
717
                                affs_free_block(inode->i_sb,key);
718
                        } else {
719
                                block = AFFS_I2HSIZE(inode);
720
                                break;
721
                        }
722
                }
723
                keyp = &GET_END_PTR(struct file_end,bh->b_data,AFFS_I2BSIZE(inode))->extension;
724
                key  = htonl(*keyp);
725
                if (first <= AFFS_I2HSIZE(inode)) {
726
                        ((struct file_front *)bh->b_data)->block_count = htonl(first);
727
                        first = 0;
728
                        *keyp = 0;
729
                        if ((inode->i_sb->u.affs_sb.s_flags & SF_OFS) && first > 0) {
730
                                block = htonl(AFFS_BLOCK(bh->b_data,inode,first - 1));
731
                                if ((ebh = affs_bread(inode->i_dev,block,AFFS_I2BSIZE(inode)))) {
732
                                        if(!(affs_checksum_block(AFFS_I2BSIZE(inode),ebh->b_data,
733
                                             &ptype,NULL))) {
734
                                                rem = inode->i_size % blocksize;
735
                                                rem = ntohl(rem ? blocksize : rem);
736
                                                ((struct data_front *)ebh->b_data)->data_size = rem;
737
                                                ((struct data_front *)ebh->b_data)->next_data = 0;
738
                                                affs_fix_checksum(AFFS_I2BSIZE(inode),ebh->b_data,5);
739
                                                mark_buffer_dirty(ebh,1);
740
                                        }
741
                                        affs_brelse(ebh);
742
                                }
743
                        }
744
                } else {
745
                        first -= AFFS_I2HSIZE(inode);
746
                }
747
                if (freethis) {         /* Don't bother fixing checksum */
748
                        affs_brelse(bh);
749
                        affs_free_block(inode->i_sb,ekey);
750
                } else {
751
                        affs_fix_checksum(AFFS_I2BSIZE(inode),bh->b_data,5);
752
                        mark_buffer_dirty(bh,1);
753
                        affs_brelse(bh);
754
                }
755
                ekey = key;
756
        }
757
        inode->u.affs_i.i_lastblock = ((inode->i_size + blocksize - 1) / blocksize) - 1;
758
        inode->u.affs_i.i_max_ext   = 0;
759
        iput(ino);
760
}
761
 
762
static void
763
affs_release_file(struct inode *inode, struct file *filp)
764
{
765
        struct affs_zone        *zone;
766
 
767
        pr_debug("AFFS: release_file(ino=%lu)\n",inode->i_ino);
768
 
769
        if (filp->f_mode & 2) {         /* Free preallocated blocks */
770
                while (inode->u.affs_i.i_pa_cnt) {
771
                        affs_free_block(inode->i_sb,
772
                                        inode->u.affs_i.i_data[inode->u.affs_i.i_pa_next++]);
773
                        inode->u.affs_i.i_pa_next &= MAX_PREALLOC - 1;
774
                        inode->u.affs_i.i_pa_cnt--;
775
                }
776
                if (inode->u.affs_i.i_zone) {
777
                        lock_super(inode->i_sb);
778
                        zone = &inode->i_sb->u.affs_sb.s_zones[inode->u.affs_i.i_zone];
779
                        if (zone->z_ino == inode->i_ino)
780
                                zone->z_ino = 0;
781
                        unlock_super(inode->i_sb);
782
                }
783
        }
784
}

powered by: WebSVN 2.1.0

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