root/fs/fat/file.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. fat_prefetch
  2. fat_file_read
  3. fat_file_write
  4. fat_truncate

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

/* [previous][next][first][last][top][bottom][index][help] */