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

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