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/fs.h>
  14 #include <linux/msdos_fs.h>
  15 #include <linux/errno.h>
  16 #include <linux/fcntl.h>
  17 #include <linux/stat.h>
  18 #include <linux/string.h>
  19 
  20 #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  21 #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  22 
  23 static struct file_operations msdos_file_operations = {
  24         NULL,                   /* lseek - default */
  25         msdos_file_read,        /* read */
  26         msdos_file_write,       /* write */
  27         NULL,                   /* readdir - bad */
  28         NULL,                   /* select - default */
  29         NULL,                   /* ioctl - default */
  30         msdos_mmap,             /* mmap */
  31         NULL,                   /* no special open is needed */
  32         NULL,                   /* release */
  33         file_fsync              /* fsync */
  34 };
  35 
  36 struct inode_operations msdos_file_inode_operations = {
  37         &msdos_file_operations, /* default file operations */
  38         NULL,                   /* create */
  39         NULL,                   /* lookup */
  40         NULL,                   /* link */
  41         NULL,                   /* unlink */
  42         NULL,                   /* symlink */
  43         NULL,                   /* mkdir */
  44         NULL,                   /* rmdir */
  45         NULL,                   /* mknod */
  46         NULL,                   /* rename */
  47         NULL,                   /* readlink */
  48         NULL,                   /* follow_link */
  49         msdos_bmap,             /* bmap */
  50         msdos_truncate,         /* truncate */
  51         NULL,                   /* permission */
  52         msdos_smap              /* smap */
  53 };
  54 
  55 /* No bmap for MS-DOS FS' that don't align data at kByte boundaries. */
  56 
  57 struct inode_operations msdos_file_inode_operations_no_bmap = {
  58         &msdos_file_operations, /* default file operations */
  59         NULL,                   /* create */
  60         NULL,                   /* lookup */
  61         NULL,                   /* link */
  62         NULL,                   /* unlink */
  63         NULL,                   /* symlink */
  64         NULL,                   /* mkdir */
  65         NULL,                   /* rmdir */
  66         NULL,                   /* mknod */
  67         NULL,                   /* rename */
  68         NULL,                   /* readlink */
  69         NULL,                   /* follow_link */
  70         NULL,                   /* bmap */
  71         msdos_truncate,         /* truncate */
  72         NULL,                   /* permission */
  73         msdos_smap              /* smap */
  74 };
  75 
  76 
  77 /*
  78         Read a file into user space
  79 */
  80 int msdos_file_read(
     /* [previous][next][first][last][top][bottom][index][help] */
  81         struct inode *inode,
  82         struct file *filp,
  83         char *buf,
  84         int count)
  85 {
  86         char *start;
  87         int left,offset,size,sector,cnt;
  88         char ch;
  89         struct buffer_head *bh;
  90         void *data;
  91 
  92 /* printk("msdos_file_read\n"); */
  93         if (!inode) {
  94                 printk("msdos_file_read: inode = NULL\n");
  95                 return -EINVAL;
  96         }
  97         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
  98         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
  99                 printk("msdos_file_read: mode = %07o\n",inode->i_mode);
 100                 return -EINVAL;
 101         }
 102         if (filp->f_pos >= inode->i_size || count <= 0) return 0;
 103         start = buf;
 104         while ((left = MIN(inode->i_size-filp->f_pos,count-(buf-start))) > 0){
 105                 if (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 106                         break;
 107                 offset = filp->f_pos & (SECTOR_SIZE-1);
 108                 if (!(bh = msdos_sread(inode->i_dev,sector,&data))) break;
 109                 filp->f_pos += (size = MIN(SECTOR_SIZE-offset,left));
 110                 if (MSDOS_I(inode)->i_binary) {
 111                         memcpy_tofs(buf,data+offset,size);
 112                         buf += size;
 113                 }
 114                 else for (cnt = size; cnt; cnt--) {
 115                                 if ((ch = *((char *) data+offset++)) == '\r')
 116                                         size--;
 117                                 else {
 118                                         if (ch != 26) put_fs_byte(ch,buf++);
 119                                         else {
 120                                                 filp->f_pos = inode->i_size;
 121                                                 brelse(bh);
 122                                                 if (start != buf
 123                                                     && !IS_RDONLY(inode))
 124                                                         inode->i_atime
 125                                                             = CURRENT_TIME;
 126                                                 return buf-start;
 127                                         }
 128                                 }
 129                         }
 130                 brelse(bh);
 131         }
 132         if (start == buf) return -EIO;
 133         if (!IS_RDONLY(inode))
 134                 inode->i_atime = CURRENT_TIME;
 135         return buf-start;
 136 }
 137 
 138 /*
 139         Write to a file either from user space
 140 */
 141 int msdos_file_write(
     /* [previous][next][first][last][top][bottom][index][help] */
 142         struct inode *inode,
 143         struct file *filp,
 144         char *buf,
 145         int count)
 146 {
 147         int sector,offset,size,left,written;
 148         int error,carry;
 149         char *start,*to,ch;
 150         struct buffer_head *bh;
 151         void *data;
 152 
 153         if (!inode) {
 154                 printk("msdos_file_write: inode = NULL\n");
 155                 return -EINVAL;
 156         }
 157         /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
 158         if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
 159                 printk("msdos_file_write: mode = %07o\n",inode->i_mode);
 160                 return -EINVAL;
 161         }
 162 /*
 163  * ok, append may not work when many processes are writing at the same time
 164  * but so what. That way leads to madness anyway.
 165  */
 166         if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
 167         if (count <= 0) return 0;
 168         error = carry = 0;
 169         for (start = buf; count || carry; count -= size) {
 170                 while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
 171                         if ((error = msdos_add_cluster(inode)) < 0) break;
 172                 if (error) {
 173                         msdos_truncate(inode);
 174                         break;
 175                 }
 176                 offset = filp->f_pos & (SECTOR_SIZE-1);
 177                 size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
 178                 if (!(bh = msdos_sread(inode->i_dev,sector,&data))) {
 179                         error = -EIO;
 180                         break;
 181                 }
 182                 if (MSDOS_I(inode)->i_binary) {
 183                         memcpy_fromfs(data+(filp->f_pos & (SECTOR_SIZE-1)),
 184                             buf,written = size);
 185                         buf += size;
 186                 }
 187                 else {
 188                         written = left = SECTOR_SIZE-offset;
 189                         to = (char *) data+(filp->f_pos & (SECTOR_SIZE-1));
 190                         if (carry) {
 191                                 *to++ = '\n';
 192                                 left--;
 193                                 carry = 0;
 194                         }
 195                         for (size = 0; size < count && left; size++) {
 196                                 if ((ch = get_fs_byte(buf++)) == '\n') {
 197                                         *to++ = '\r';
 198                                         left--;
 199                                 }
 200                                 if (!left) carry = 1;
 201                                 else {
 202                                         *to++ = ch;
 203                                         left--;
 204                                 }
 205                         }
 206                         written -= left;
 207                 }
 208                 filp->f_pos += written;
 209                 if (filp->f_pos > inode->i_size) {
 210                         inode->i_size = filp->f_pos;
 211                         inode->i_dirt = 1;
 212                 }
 213                 mark_buffer_dirty(bh, 0);
 214                 brelse(bh);
 215         }
 216         if (start == buf)
 217                 return error;
 218         inode->i_mtime = inode->i_ctime = CURRENT_TIME;
 219         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 220         inode->i_dirt = 1;
 221         return buf-start;
 222 }
 223 
 224 void msdos_truncate(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 225 {
 226         int cluster;
 227 
 228         cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
 229         (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
 230         MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
 231         inode->i_dirt = 1;
 232 }

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