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

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