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/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 
  18 #include <asm/segment.h>
  19 #include <asm/system.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_user(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         const 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         const char *start;
 273         char *to,ch;
 274         struct buffer_head *bh;
 275         int binary_mode = MSDOS_I(inode)->i_binary;
 276 
 277         if (!inode) {
 278                 printk("msdos_file_write: inode = NULL\n");
 279                 return -EINVAL;
 280         }
 281         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
 282         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
 283                 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
 284                 return -EINVAL;
 285         }
 286         /* Must not harm system files */
 287         if (MSDOS_I(inode)->i_attrs & ATTR_SYS) return -EPERM;
 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         /* Must not harm system files */
 366         /* Why no return value?  Surely the disk could fail... */
 367         if (MSDOS_I(inode)->i_attrs & ATTR_SYS) return /* -EPERM */;
 368         cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 369         (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 370         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 371         inode->i_dirt = 1;
 372 }

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