root/fs/msdos/file.c

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

DEFINITIONS

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

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