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

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