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;
 107         int left;
 108         int i;
 109         struct msdos_pre pre;
 110                 
 111 
 112         if (!inode) {
 113                 printk("msdos_file_read: inode = NULL\n");
 114                 return -EINVAL;
 115         }
 116         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
 117         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
 118                 printk("msdos_file_read: mode = %07o\n",inode->i_mode);
 119                 return -EINVAL;
 120         }
 121         if (filp->f_pos >= inode->i_size || count <= 0) return 0;
 122         /*
 123                 Tell the buffer cache which block we expect to read in advance
 124                 Since we are limited with the stack, we preread only MSDOS_PREFETCH
 125                 because we have to keep the result into the local
 126                 arrays pre.bhlist and bhreq.
 127                 
 128                 Each time we process one block in bhlist, we replace
 129                 it by a new prefetch block if needed.
 130         */
 131         PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
 132         {
 133                 /*
 134                         We must prefetch complete block, so we must
 135                         take in account the offset in the first block.
 136                 */
 137                 int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
 138                 int   to_reada; /* How many block to read all at once */
 139                 pre.file_sector = filp->f_pos >> SECTOR_BITS;
 140                 to_reada = count_max / SECTOR_SIZE;
 141                 if (count_max & (SECTOR_SIZE-1)) to_reada++;
 142                 if (filp->f_reada || !MSDOS_I(inode)->i_binary){
 143                         /* Doing a read ahead on ascii file make sure we always */
 144                         /* pre read enough, since we don't know how many blocks */
 145                         /* we really need */
 146                         int ahead = read_ahead[MAJOR(inode->i_dev)];
 147                         if (ahead == 0) ahead = 8;
 148                         to_reada += ahead;
 149                 }
 150                 if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
 151                 pre.nblist = 0;
 152                 msdos_prefetch (inode,&pre,to_reada);
 153         }
 154         start = buf;
 155         pre.nolist = 0;
 156         PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
 157         while ((left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) > 0){
 158                 struct buffer_head *bh = pre.bhlist[pre.nolist];
 159                 char *data;
 160                 int size,offset;
 161                 if (bh == NULL) break;
 162                 pre.bhlist[pre.nolist] = NULL;
 163                 pre.nolist++;
 164                 if (pre.nolist == MSDOS_PREFETCH/2){
 165                         memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
 166                                 ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
 167                         pre.nblist -= MSDOS_PREFETCH/2;
 168                         msdos_prefetch (inode,&pre,MSDOS_PREFETCH/2);
 169                         pre.nolist = 0;
 170                 }
 171                 PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
 172                 wait_on_buffer(bh);
 173                 if (!bh->b_uptodate){
 174                         /* read error  ? */
 175                         brelse (bh);
 176                         break;
 177                 }
 178                 offset = filp->f_pos & (SECTOR_SIZE-1);
 179                 filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
 180                 data = bh->b_data + offset;
 181                 if (MSDOS_I(inode)->i_binary) {
 182                         memcpy_tofs(buf,data,size);
 183                         buf += size;
 184                 }else{
 185                         int cnt;
 186                         for (cnt = size; cnt; cnt--) {
 187                                 char ch = *data++;
 188                                 if (ch == 26){
 189                                         filp->f_pos = inode->i_size;
 190                                         break;
 191                                 }else if (ch != '\r'){
 192                                         put_fs_byte(ch,buf++);
 193                                 }
 194                         }
 195                 }
 196                 brelse(bh);
 197         }
 198         PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
 199         for (i=0; i<pre.nblist; i++) brelse (pre.bhlist[i]);
 200         if (start == buf) return -EIO;
 201         if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
 202         PRINTK (("file_read ret %d\n",(buf-start)));
 203         filp->f_reada = 1;      /* Will be reset if a lseek is done */
 204         return buf-start;
 205 }
 206 
 207 /*
 208         Write to a file either from user space
 209 */
 210 int msdos_file_write(
     /* [previous][next][first][last][top][bottom][index][help] */
 211         struct inode *inode,
 212         struct file *filp,
 213         char *buf,
 214         int count)
 215 {
 216         int sector,offset,size,left,written;
 217         int error,carry;
 218         char *start,*to,ch;
 219         struct buffer_head *bh;
 220         int binary_mode = MSDOS_I(inode)->i_binary;
 221 
 222         if (!inode) {
 223                 printk("msdos_file_write: inode = NULL\n");
 224                 return -EINVAL;
 225         }
 226         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
 227         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
 228                 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
 229                 return -EINVAL;
 230         }
 231 /*
 232  * ok, append may not work when many processes are writing at the same time
 233  * but so what. That way leads to madness anyway.
 234  */
 235         if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
 236         if (count <= 0) return 0;
 237         error = carry = 0;
 238         for (start = buf; count || carry; count -= size) {
 239                 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 240                         if ((error = msdos_add_cluster(inode)) < 0) break;
 241                 if (error) {
 242                         msdos_truncate(inode);
 243                         break;
 244                 }
 245                 offset = filp->f_pos & (SECTOR_SIZE-1);
 246                 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
 247                 if (binary_mode
 248                         && offset == 0
 249                         && (size == SECTOR_SIZE
 250                                 || filp->f_pos + size >= inode->i_size)){
 251                         /* No need to read the block first since we will */
 252                         /* completely overwrite it */
 253                         /* or at least write past the end of file */
 254                         if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
 255                                 error = -EIO;
 256                                 break;
 257                         }
 258                 }else if (!(bh = msdos_sread(inode->i_dev,sector))) {
 259                         error = -EIO;
 260                         break;
 261                 }
 262                 if (binary_mode) {
 263                         memcpy_fromfs(bh->b_data+offset,buf,written = size);
 264                         buf += size;
 265                 }
 266                 else {
 267                         written = left = SECTOR_SIZE-offset;
 268                         to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
 269                         if (carry) {
 270                                 *to++ = '\n';
 271                                 left--;
 272                                 carry = 0;
 273                         }
 274                         for (size = 0; size < count && left; size++) {
 275                                 if ((ch = get_fs_byte(buf++)) == '\n') {
 276                                         *to++ = '\r';
 277                                         left--;
 278                                 }
 279                                 if (!left) carry = 1;
 280                                 else {
 281                                         *to++ = ch;
 282                                         left--;
 283                                 }
 284                         }
 285                         written -= left;
 286                 }
 287                 filp->f_pos += written;
 288                 if (filp->f_pos > inode->i_size) {
 289                         inode->i_size = filp->f_pos;
 290                         inode->i_dirt = 1;
 291                 }
 292                 bh->b_uptodate = 1;
 293                 mark_buffer_dirty(bh, 0);
 294                 brelse(bh);
 295         }
 296         if (start == buf)
 297                 return error;
 298         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 299         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 300         inode->i_dirt = 1;
 301         return buf-start;
 302 }
 303 
 304 void msdos_truncate(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 305 {
 306         int cluster;
 307 
 308         cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 309         (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 310         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 311         inode->i_dirt = 1;
 312 }

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