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

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