root/fs/msdos/file.c

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

DEFINITIONS

This source file includes following definitions.
  1. msdos_prefetch
  2. msdos_file_read
  3. msdos_file_write
  4. msdos_truncate

   1 /*
   2  *  linux/fs/msdos/file.c
   3  *
   4  *  Written 1992,1993 by Werner Almesberger
   5  *
   6  *  MS-DOS regular file handling primitives
   7  */
   8 
   9 #ifdef MODULE
  10 #include <linux/module.h>
  11 #endif
  12 
  13 #include <asm/segment.h>
  14 #include <asm/system.h>
  15 
  16 #include <linux/sched.h>
  17 #include <linux/locks.h>
  18 #include <linux/fs.h>
  19 #include <linux/msdos_fs.h>
  20 #include <linux/errno.h>
  21 #include <linux/fcntl.h>
  22 #include <linux/stat.h>
  23 #include <linux/string.h>
  24 
  25 #include "msbuffer.h"
  26 
  27 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  28 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  29 
  30 #define PRINTK(x)
  31 #define Printk(x) printk x
  32 
  33 static struct file_operations msdos_file_operations = {
  34         NULL,                   /* lseek - default */
  35         msdos_file_read,        /* read */
  36         msdos_file_write,       /* write */
  37         NULL,                   /* readdir - bad */
  38         NULL,                   /* select - default */
  39         NULL,                   /* ioctl - default */
  40         generic_mmap,           /* mmap */
  41         NULL,                   /* no special open is needed */
  42         NULL,                   /* release */
  43         file_fsync              /* fsync */
  44 };
  45 
  46 struct inode_operations msdos_file_inode_operations = {
  47         &msdos_file_operations, /* default file operations */
  48         NULL,                   /* create */
  49         NULL,                   /* lookup */
  50         NULL,                   /* link */
  51         NULL,                   /* unlink */
  52         NULL,                   /* symlink */
  53         NULL,                   /* mkdir */
  54         NULL,                   /* rmdir */
  55         NULL,                   /* mknod */
  56         NULL,                   /* rename */
  57         NULL,                   /* readlink */
  58         NULL,                   /* follow_link */
  59         msdos_bmap,             /* bmap */
  60         msdos_truncate,         /* truncate */
  61         NULL,                   /* permission */
  62         NULL                    /* smap */
  63 };
  64 /* #Specification: msdos / special devices / mmap       
  65         Mmapping does work because a special mmap is provide in that case.
  66         Note that it is much less efficient than the generic_mmap normally
  67         used since it allocate extra buffer. generic_mmap is used for
  68         normal device (512 bytes hardware sectors).
  69 */
  70 static struct file_operations msdos_file_operations_1024 = {
  71         NULL,                   /* lseek - default */
  72         msdos_file_read,        /* read */
  73         msdos_file_write,       /* write */
  74         NULL,                   /* readdir - bad */
  75         NULL,                   /* select - default */
  76         NULL,                   /* ioctl - default */
  77         msdos_mmap,             /* mmap */
  78         NULL,                   /* no special open is needed */
  79         NULL,                   /* release */
  80         file_fsync              /* fsync */
  81 };
  82 
  83 /* #Specification: msdos / special devices / swap file
  84         Swap file can't work on special devices with a large sector
  85         size (1024 bytes hard sector). Those devices have a weird
  86         MsDOS filesystem layout. Generally a single hardware sector
  87         may contain 2 unrelated logical sector. This mean that there is
  88         no easy way to do a mapping between disk sector of a file and virtual
  89         memory. So swap file is difficult (not available right now)
  90         on those devices. Off course, Ext2 does not have this problem.
  91 */
  92 struct inode_operations msdos_file_inode_operations_1024 = {
  93         &msdos_file_operations_1024,    /* default file operations */
  94         NULL,                   /* create */
  95         NULL,                   /* lookup */
  96         NULL,                   /* link */
  97         NULL,                   /* unlink */
  98         NULL,                   /* symlink */
  99         NULL,                   /* mkdir */
 100         NULL,                   /* rmdir */
 101         NULL,                   /* mknod */
 102         NULL,                   /* rename */
 103         NULL,                   /* readlink */
 104         NULL,                   /* follow_link */
 105         NULL,                   /* bmap */
 106         msdos_truncate,         /* truncate */
 107         NULL,                   /* permission */
 108         NULL                    /* smap */
 109 };
 110 
 111 #define MSDOS_PREFETCH  32
 112 struct msdos_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 msdos_prefetch (
     /* [previous][next][first][last][top][bottom][index][help] */
 123         struct inode *inode,
 124         struct msdos_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 = msdos_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 (!msdos_is_uptodate(sb,bh)) bhreq[nbreq++] = bh;
 142                 }else{
 143                         break;
 144                 }
 145         }
 146         if (nbreq > 0) msdos_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 msdos_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 msdos_pre pre;
 165                 
 166 
 167         if (!inode) {
 168                 printk("msdos_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("msdos_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                 msdos_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                         msdos_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 (!msdos_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_fs_byte(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 msdos_file_write(
     /* [previous][next][first][last][top][bottom][index][help] */
 268         struct inode *inode,
 269         struct file *filp,
 270         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         char *start,*to,ch;
 277         struct buffer_head *bh;
 278         int binary_mode = MSDOS_I(inode)->i_binary;
 279 
 280         if (!inode) {
 281                 printk("msdos_file_write: inode = NULL\n");
 282                 return -EINVAL;
 283         }
 284         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
 285         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
 286                 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
 287                 return -EINVAL;
 288         }
 289 /*
 290  * ok, append may not work when many processes are writing at the same time
 291  * but so what. That way leads to madness anyway.
 292  */
 293         if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
 294         if (count <= 0) return 0;
 295         error = carry = 0;
 296         for (start = buf; count || carry; count -= size) {
 297                 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 298                         if ((error = msdos_add_cluster(inode)) < 0) break;
 299                 if (error) {
 300                         msdos_truncate(inode);
 301                         break;
 302                 }
 303                 offset = filp->f_pos & (SECTOR_SIZE-1);
 304                 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
 305                 if (binary_mode
 306                         && offset == 0
 307                         && (size == SECTOR_SIZE
 308                                 || filp->f_pos + size >= inode->i_size)){
 309                         /* No need to read the block first since we will */
 310                         /* completely overwrite it */
 311                         /* or at least write past the end of file */
 312                         if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
 313                                 error = -EIO;
 314                                 break;
 315                         }
 316                 }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
 317                         error = -EIO;
 318                         break;
 319                 }
 320                 if (binary_mode) {
 321                         memcpy_fromfs(bh->b_data+offset,buf,written = size);
 322                         buf += size;
 323                 }
 324                 else {
 325                         written = left = SECTOR_SIZE-offset;
 326                         to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
 327                         if (carry) {
 328                                 *to++ = '\n';
 329                                 left--;
 330                                 carry = 0;
 331                         }
 332                         for (size = 0; size < count && left; size++) {
 333                                 if ((ch = get_fs_byte(buf++)) == '\n') {
 334                                         *to++ = '\r';
 335                                         left--;
 336                                 }
 337                                 if (!left) carry = 1;
 338                                 else {
 339                                         *to++ = ch;
 340                                         left--;
 341                                 }
 342                         }
 343                         written -= left;
 344                 }
 345                 filp->f_pos += written;
 346                 if (filp->f_pos > inode->i_size) {
 347                         inode->i_size = filp->f_pos;
 348                         inode->i_dirt = 1;
 349                 }
 350                 msdos_set_uptodate(sb,bh,1);
 351                 mark_buffer_dirty(bh, 0);
 352                 brelse(bh);
 353         }
 354         if (start == buf)
 355                 return error;
 356         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 357         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 358         inode->i_dirt = 1;
 359         return buf-start;
 360 }
 361 
 362 void msdos_truncate(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 363 {
 364         int cluster;
 365 
 366         cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 367         (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 368         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 369         inode->i_dirt = 1;
 370 }

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