home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.0 / LINUX-1.0 / LINUX-1 / linux / fs / msdos / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1993-12-01  |  5.3 KB  |  224 lines

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