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_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 msdos_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("msdos_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("msdos_file_write: mode = %07o\n",inode->i_mode);
 288                 return -EINVAL;
 289         }
 290 /*
 291  * ok, append may not work when many processes are writing at the same time
 292  * but so what. That way leads to madness anyway.
 293  */
 294         if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
 295         if (count <= 0) return 0;
 296         error = carry = 0;
 297         for (start = buf; count || carry; count -= size) {
 298                 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 299                         if ((error = msdos_add_cluster(inode)) < 0) break;
 300                 if (error) {
 301                         msdos_truncate(inode);
 302                         break;
 303                 }
 304                 offset = filp->f_pos & (SECTOR_SIZE-1);
 305                 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
 306                 if (binary_mode
 307                         && offset == 0
 308                         && (size == SECTOR_SIZE
 309                                 || filp->f_pos + size >= inode->i_size)){
 310                         /* No need to read the block first since we will */
 311                         /* completely overwrite it */
 312                         /* or at least write past the end of file */
 313                         if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
 314                                 error = -EIO;
 315                                 break;
 316                         }
 317                 }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
 318                         error = -EIO;
 319                         break;
 320                 }
 321                 if (binary_mode) {
 322                         memcpy_fromfs(bh->b_data+offset,buf,written = size);
 323                         buf += size;
 324                 }
 325                 else {
 326                         written = left = SECTOR_SIZE-offset;
 327                         to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
 328                         if (carry) {
 329                                 *to++ = '\n';
 330                                 left--;
 331                                 carry = 0;
 332                         }
 333                         for (size = 0; size < count && left; size++) {
 334                                 if ((ch = get_user(buf++)) == '\n') {
 335                                         *to++ = '\r';
 336                                         left--;
 337                                 }
 338                                 if (!left) carry = 1;
 339                                 else {
 340                                         *to++ = ch;
 341                                         left--;
 342                                 }
 343                         }
 344                         written -= left;
 345                 }
 346                 filp->f_pos += written;
 347                 if (filp->f_pos > inode->i_size) {
 348                         inode->i_size = filp->f_pos;
 349                         inode->i_dirt = 1;
 350                 }
 351                 msdos_set_uptodate(sb,bh,1);
 352                 mark_buffer_dirty(bh, 0);
 353                 brelse(bh);
 354         }
 355         if (start == buf)
 356                 return error;
 357         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 358         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 359         inode->i_dirt = 1;
 360         return buf-start;
 361 }
 362 
 363 void msdos_truncate(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 364 {
 365         int cluster;
 366 
 367         cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 368         (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 369         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 370         inode->i_dirt = 1;
 371 }

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