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

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