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

Subversion Repositories or1k

[/] [or1k/] [trunk/] [rc203soc/] [sw/] [uClinux/] [fs/] [fat/] [file.c] - Blame information for rev 1628

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1628 jcastillo
/*
2
 *  linux/fs/fat/file.c
3
 *
4
 *  Written 1992,1993 by Werner Almesberger
5
 *
6
 *  regular file handling primitives for fat-based filesystems
7
 */
8
 
9
#define ASC_LINUX_VERSION(V, P, S)      (((V) * 65536) + ((P) * 256) + (S))
10
#include <linux/version.h>
11
#include <linux/sched.h>
12
#include <linux/locks.h>
13
#include <linux/fs.h>
14
#include <linux/msdos_fs.h>
15
#include <linux/errno.h>
16
#include <linux/fcntl.h>
17
#include <linux/stat.h>
18
#include <linux/string.h>
19
#include <linux/pagemap.h>
20
 
21
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
22
#include <asm/uaccess.h>
23
#define FAT_COPY_TO_USER(uaddr, kaddr, len) copy_to_user(uaddr, kaddr, len)
24
#define FAT_COPY_FROM_USER(uaddr, kaddr, len) copy_from_user(uaddr, kaddr, len)
25
#define FAT_GET_USER(c, ptr) get_user((c), ptr)
26
#else
27
#include <asm/segment.h>
28
#define FAT_COPY_TO_USER(uaddr, kaddr, len) memcpy_tofs(uaddr, kaddr, len)
29
#define FAT_COPY_FROM_USER(uaddr, kaddr, len) memcpy_fromfs(uaddr, kaddr, len)
30
#define FAT_GET_USER(c, ptr) (c) = get_user(ptr)
31
#endif
32
#include <asm/system.h>
33
 
34
#include "msbuffer.h"
35
 
36
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
37
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
38
 
39
#define PRINTK(x)
40
#define Printk(x) printk x
41
 
42
static struct file_operations fat_file_operations = {
43
        NULL,                   /* lseek - default */
44
        fat_file_read,          /* read */
45
        fat_file_write,         /* write */
46
        NULL,                   /* readdir - bad */
47
        NULL,                   /* select v2.0.x/poll v2.1.x - default */
48
        NULL,                   /* ioctl - default */
49
        generic_file_mmap,      /* mmap */
50
        NULL,                   /* no special open is needed */
51
        NULL,                   /* release */
52
        file_fsync              /* fsync */
53
};
54
 
55
struct inode_operations fat_file_inode_operations = {
56
        &fat_file_operations,   /* default file operations */
57
        NULL,                   /* create */
58
        NULL,                   /* lookup */
59
        NULL,                   /* link */
60
        NULL,                   /* unlink */
61
        NULL,                   /* symlink */
62
        NULL,                   /* mkdir */
63
        NULL,                   /* rmdir */
64
        NULL,                   /* mknod */
65
        NULL,                   /* rename */
66
        NULL,                   /* readlink */
67
        NULL,                   /* follow_link */
68
        generic_readpage,       /* readpage */
69
        NULL,                   /* writepage */
70
        fat_bmap,               /* bmap */
71
        fat_truncate,           /* truncate */
72
        NULL,                   /* permission */
73
        NULL                    /* smap */
74
};
75
/* #Specification: msdos / special devices / mmap
76
        Mmapping does work because a special mmap is provide in that case.
77
        Note that it is much less efficient than the generic_file_mmap normally
78
        used since it allocate extra buffer. generic_file_mmap is used for
79
        normal device (512 bytes hardware sectors).
80
*/
81
static struct file_operations fat_file_operations_1024 = {
82
        NULL,                   /* lseek - default */
83
        fat_file_read,          /* read */
84
        fat_file_write,         /* write */
85
        NULL,                   /* readdir - bad */
86
        NULL,                   /* select v2.0.x/poll v2.1.x - default */
87
        NULL,                   /* ioctl - default */
88
        fat_mmap,               /* mmap */
89
        NULL,                   /* no special open is needed */
90
        NULL,                   /* release */
91
        file_fsync              /* fsync */
92
};
93
 
94
/* #Specification: msdos / special devices / swap file
95
        Swap file can't work on special devices with a large sector
96
        size (1024 bytes hard sector). Those devices have a weird
97
        MsDOS filesystem layout. Generally a single hardware sector
98
        may contain 2 unrelated logical sector. This mean that there is
99
        no easy way to do a mapping between disk sector of a file and virtual
100
        memory. So swap file is difficult (not available right now)
101
        on those devices. Off course, Ext2 does not have this problem.
102
*/
103
struct inode_operations fat_file_inode_operations_1024 = {
104
        &fat_file_operations_1024,      /* default file operations */
105
        NULL,                   /* create */
106
        NULL,                   /* lookup */
107
        NULL,                   /* link */
108
        NULL,                   /* unlink */
109
        NULL,                   /* symlink */
110
        NULL,                   /* mkdir */
111
        NULL,                   /* rmdir */
112
        NULL,                   /* mknod */
113
        NULL,                   /* rename */
114
        NULL,                   /* readlink */
115
        NULL,                   /* follow_link */
116
        NULL,                   /* readpage */
117
        NULL,                   /* writepage */
118
        NULL,                   /* bmap */
119
        fat_truncate,           /* truncate */
120
        NULL,                   /* permission */
121
        NULL                    /* smap */
122
};
123
 
124
#define MSDOS_PREFETCH  32
125
struct fat_pre {
126
        int file_sector;/* Next sector to read in the prefetch table */
127
                        /* This is relative to the file, not the disk */
128
        struct buffer_head *bhlist[MSDOS_PREFETCH];     /* All buffers needed */
129
        int nblist;     /* Number of buffers in bhlist */
130
        int nolist;     /* index in bhlist */
131
};
132
/*
133
        Order the prefetch of more sectors.
134
*/
135
static void fat_prefetch (
136
        struct inode *inode,
137
        struct fat_pre *pre,
138
        int nb)         /* How many must we prefetch at once */
139
{
140
        struct super_block *sb = inode->i_sb;
141
        struct buffer_head *bhreq[MSDOS_PREFETCH];      /* Buffers not */
142
                                                        /* already read */
143
        int nbreq = 0;                   /* Number of buffers in bhreq */
144
        int i;
145
        for (i=0; i<nb; i++){
146
                int sector = fat_smap(inode,pre->file_sector);
147
                if (sector != 0){
148
                        struct buffer_head *bh;
149
                        PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
150
                        pre->file_sector++;
151
                        bh = fat_getblk(sb, sector);
152
                        if (bh == NULL) break;
153
                        pre->bhlist[pre->nblist++] = bh;
154
                        if (!fat_is_uptodate(sb,bh))
155
                                bhreq[nbreq++] = bh;
156
                }else{
157
                        break;
158
                }
159
        }
160
        if (nbreq > 0) fat_ll_rw_block (sb,READ,nbreq,bhreq);
161
        for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
162
}
163
 
164
/*
165
        Read a file into user space
166
*/
167
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
168
long fat_file_read(struct inode *inode,struct file *filp,char *buf,
169
                   unsigned long count)
170
#else
171
int fat_file_read(struct inode *inode,struct file *filp,char *buf,int count)
172
#endif
173
{
174
        struct super_block *sb = inode->i_sb;
175
        char *start = buf;
176
        char *end   = buf + count;
177
        int i;
178
        int left_in_file;
179
        struct fat_pre pre;
180
 
181
 
182
        if (!inode) {
183
                printk("fat_file_read: inode = NULL\n");
184
                return -EINVAL;
185
        }
186
        /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
187
        if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
188
                printk("fat_file_read: mode = %07o\n",inode->i_mode);
189
                return -EINVAL;
190
        }
191
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
192
        if (filp->f_pos >= inode->i_size || count == 0) return 0;
193
#else
194
        if (filp->f_pos >= inode->i_size || count <= 0) return 0;
195
#endif
196
        /*
197
                Tell the buffer cache which block we expect to read in advance
198
                Since we are limited with the stack, we preread only MSDOS_PREFETCH
199
                because we have to keep the result into the local
200
                arrays pre.bhlist and bhreq.
201
 
202
                Each time we process one block in bhlist, we replace
203
                it by a new prefetch block if needed.
204
        */
205
        PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
206
        {
207
                /*
208
                        We must prefetch complete block, so we must
209
                        take in account the offset in the first block.
210
                */
211
                int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
212
                int   to_reada; /* How many block to read all at once */
213
                pre.file_sector = filp->f_pos >> SECTOR_BITS;
214
                to_reada = count_max / SECTOR_SIZE;
215
                if (count_max & (SECTOR_SIZE-1)) to_reada++;
216
                if (filp->f_reada || !MSDOS_I(inode)->i_binary){
217
                        /* Doing a read ahead on ascii file make sure we always */
218
                        /* pre read enough, since we don't know how many blocks */
219
                        /* we really need */
220
                        int ahead = read_ahead[MAJOR(inode->i_dev)];
221
                        PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
222
                        if (ahead == 0) ahead = 8;
223
                        to_reada += ahead;
224
                }
225
                if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
226
                pre.nblist = 0;
227
                fat_prefetch (inode,&pre,to_reada);
228
        }
229
        pre.nolist = 0;
230
        PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
231
        while ((left_in_file = inode->i_size - filp->f_pos) > 0
232
                && buf < end){
233
                struct buffer_head *bh = pre.bhlist[pre.nolist];
234
                char *data;
235
                int size,offset;
236
                if (bh == NULL) break;
237
                pre.bhlist[pre.nolist] = NULL;
238
                pre.nolist++;
239
                if (pre.nolist == MSDOS_PREFETCH/2){
240
                        memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
241
                                ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
242
                        pre.nblist -= MSDOS_PREFETCH/2;
243
                        fat_prefetch (inode,&pre,MSDOS_PREFETCH/2);
244
                        pre.nolist = 0;
245
                }
246
                PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
247
                wait_on_buffer(bh);
248
                if (!fat_is_uptodate(sb,bh)){
249
                        /* read error  ? */
250
                        fat_brelse (sb, bh);
251
                        break;
252
                }
253
                offset = filp->f_pos & (SECTOR_SIZE-1);
254
                data = bh->b_data + offset;
255
                size = MIN(SECTOR_SIZE-offset,left_in_file);
256
                if (MSDOS_I(inode)->i_binary) {
257
                        size = MIN(size,end-buf);
258
                        FAT_COPY_TO_USER(buf,data,size);
259
                        buf += size;
260
                        filp->f_pos += size;
261
                }else{
262
                        for (; size && buf < end; size--) {
263
                                char ch = *data++;
264
                                filp->f_pos++;
265
                                if (ch == 26){
266
                                        filp->f_pos = inode->i_size;
267
                                        break;
268
                                }else if (ch != '\r'){
269
                                        put_user(ch,buf++);
270
                                }
271
                        }
272
                }
273
                fat_brelse(sb, bh);
274
        }
275
        PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
276
        for (i=0; i<pre.nblist; i++)
277
                fat_brelse (sb, pre.bhlist[i]);
278
        if (start == buf)
279
                return -EIO;
280
        if (!IS_RDONLY(inode))
281
                inode->i_atime = CURRENT_TIME;
282
        filp->f_reada = 1;      /* Will be reset if a lseek is done */
283
        return buf-start;
284
}
285
 
286
/*
287
        Write to a file either from user space
288
*/
289
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
290
long fat_file_write(struct inode *inode,struct file *filp,const char *buf,
291
                    unsigned long count)
292
#else
293
int fat_file_write(struct inode *inode,struct file *filp,const char *buf,int count)
294
#endif
295
{
296
        struct super_block *sb = inode->i_sb;
297
        int sector,offset,size,left,written;
298
        int error,carry;
299
        const char *start;
300
        char *to,ch;
301
        struct buffer_head *bh;
302
        int binary_mode = MSDOS_I(inode)->i_binary;
303
 
304
        if (!inode) {
305
                printk("fat_file_write: inode = NULL\n");
306
                return -EINVAL;
307
        }
308
        /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
309
        if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
310
                printk("fat_file_write: mode = %07o\n",inode->i_mode);
311
                return -EINVAL;
312
        }
313
        /* system files may be immutable */
314
        if (IS_IMMUTABLE(inode))
315
                return -EPERM;
316
/*
317
 * ok, append may not work when many processes are writing at the same time
318
 * but so what. That way leads to madness anyway.
319
 */
320
        if (filp->f_flags & O_APPEND)
321
                filp->f_pos = inode->i_size;
322
#if LINUX_VERSION_CODE >= ASC_LINUX_VERSION(2,1,0)
323
        if (count == 0) return 0;
324
#else
325
        if (count <= 0) return 0;
326
#endif
327
        if (filp->f_pos + count > 0x7FFFFFFFL) {
328
                count = 0x7FFFFFFFL - filp->f_pos;
329
                if (!count)
330
                        return -EFBIG;
331
        }
332
 
333
        error = carry = 0;
334
        for (start = buf; count || carry; count -= size) {
335
                while (!(sector = fat_smap(inode,filp->f_pos >> SECTOR_BITS)))
336
                        if ((error = fat_add_cluster(inode)) < 0) break;
337
                if (error) {
338
                        fat_truncate(inode);
339
                        break;
340
                }
341
                offset = filp->f_pos & (SECTOR_SIZE-1);
342
                size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
343
                if (binary_mode
344
                        && offset == 0
345
                        && (size == SECTOR_SIZE
346
                                || filp->f_pos + size >= inode->i_size)){
347
                        /* No need to read the block first since we will */
348
                        /* completely overwrite it */
349
                        /* or at least write past the end of file */
350
                        if (!(bh = fat_getblk(sb,sector))){
351
                                error = -EIO;
352
                                break;
353
                        }
354
                } else if (!(bh = fat_bread(sb,sector))) {
355
                        error = -EIO;
356
                        break;
357
                }
358
                if (binary_mode) {
359
                        FAT_COPY_FROM_USER(bh->b_data+offset,buf,written = size);
360
                        buf += size;
361
                } else {
362
                        written = left = SECTOR_SIZE-offset;
363
                        to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
364
                        if (carry) {
365
                                *to++ = '\n';
366
                                left--;
367
                                carry = 0;
368
                        }
369
                        for (size = 0; size < count && left; size++) {
370
                                FAT_GET_USER(ch, buf++);
371
                                if (ch == '\n') {
372
                                        *to++ = '\r';
373
                                        left--;
374
                                }
375
                                if (!left) carry = 1;
376
                                else {
377
                                        *to++ = ch;
378
                                        left--;
379
                                }
380
                        }
381
                        written -= left;
382
                }
383
                update_vm_cache(inode, filp->f_pos, bh->b_data + (filp->f_pos & (SECTOR_SIZE-1)), written);
384
                filp->f_pos += written;
385
                if (filp->f_pos > inode->i_size) {
386
                        inode->i_size = filp->f_pos;
387
                        inode->i_dirt = 1;
388
                }
389
                fat_set_uptodate(sb, bh, 1);
390
                fat_mark_buffer_dirty(sb, bh, 0);
391
                fat_brelse(sb, bh);
392
        }
393
        if (start == buf)
394
                return error;
395
        inode->i_mtime = inode->i_ctime = CURRENT_TIME;
396
        MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
397
        inode->i_dirt = 1;
398
        return buf-start;
399
}
400
 
401
void fat_truncate(struct inode *inode)
402
{
403
        int cluster;
404
 
405
        /* Why no return value?  Surely the disk could fail... */
406
        if (IS_IMMUTABLE(inode))
407
                return /* -EPERM */;
408
        cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
409
        (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
410
        MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
411
        inode->i_dirt = 1;
412
}

powered by: WebSVN 2.1.0

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