home *** CD-ROM | disk | FTP | other *** search
/ Il CD di internet / CD.iso / SOURCE / KERNEL-S / V1.2 / LINUX-1.2 / LINUX-1 / linux / fs / msdos / file.c < prev    next >
Encoding:
C/C++ Source or Header  |  1995-01-23  |  10.1 KB  |  371 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. #ifdef MODULE
  10. #include <linux/module.h>
  11. #endif
  12.  
  13. #include <asm/segment.h>
  14. #include <asm/system.h>
  15.  
  16. #include <linux/sched.h>
  17. #include <linux/locks.h>
  18. #include <linux/fs.h>
  19. #include <linux/msdos_fs.h>
  20. #include <linux/errno.h>
  21. #include <linux/fcntl.h>
  22. #include <linux/stat.h>
  23. #include <linux/string.h>
  24.  
  25. #include "msbuffer.h"
  26.  
  27. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  28. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  29.  
  30. #define PRINTK(x)
  31. #define Printk(x) printk x
  32.  
  33. static struct file_operations msdos_file_operations = {
  34.     NULL,            /* lseek - default */
  35.     msdos_file_read,    /* read */
  36.     msdos_file_write,    /* write */
  37.     NULL,            /* readdir - bad */
  38.     NULL,            /* select - default */
  39.     NULL,            /* ioctl - default */
  40.     generic_mmap,        /* mmap */
  41.     NULL,            /* no special open is needed */
  42.     NULL,            /* release */
  43.     file_fsync        /* fsync */
  44. };
  45.  
  46. struct inode_operations msdos_file_inode_operations = {
  47.     &msdos_file_operations,    /* default file operations */
  48.     NULL,            /* create */
  49.     NULL,            /* lookup */
  50.     NULL,            /* link */
  51.     NULL,            /* unlink */
  52.     NULL,            /* symlink */
  53.     NULL,            /* mkdir */
  54.     NULL,            /* rmdir */
  55.     NULL,            /* mknod */
  56.     NULL,            /* rename */
  57.     NULL,            /* readlink */
  58.     NULL,            /* follow_link */
  59.     msdos_bmap,        /* bmap */
  60.     msdos_truncate,        /* truncate */
  61.     NULL,            /* permission */
  62.     NULL            /* smap */
  63. };
  64. /* #Specification: msdos / special devices / mmap    
  65.     Mmapping does work because a special mmap is provide in that case.
  66.     Note that it is much less efficient than the generic_mmap normally
  67.     used since it allocate extra buffer. generic_mmap is used for
  68.     normal device (512 bytes hardware sectors).
  69. */
  70. static struct file_operations msdos_file_operations_1024 = {
  71.     NULL,            /* lseek - default */
  72.     msdos_file_read,    /* read */
  73.     msdos_file_write,    /* write */
  74.     NULL,            /* readdir - bad */
  75.     NULL,            /* select - default */
  76.     NULL,            /* ioctl - default */
  77.     msdos_mmap,        /* mmap */
  78.     NULL,            /* no special open is needed */
  79.     NULL,            /* release */
  80.     file_fsync        /* fsync */
  81. };
  82.  
  83. /* #Specification: msdos / special devices / swap file
  84.     Swap file can't work on special devices with a large sector
  85.     size (1024 bytes hard sector). Those devices have a weird
  86.     MsDOS filesystem layout. Generally a single hardware sector
  87.     may contain 2 unrelated logical sector. This mean that there is
  88.     no easy way to do a mapping between disk sector of a file and virtual
  89.     memory. So swap file is difficult (not available right now)
  90.     on those devices. Off course, Ext2 does not have this problem.
  91. */
  92. struct inode_operations msdos_file_inode_operations_1024 = {
  93.     &msdos_file_operations_1024,    /* default file operations */
  94.     NULL,            /* create */
  95.     NULL,            /* lookup */
  96.     NULL,            /* link */
  97.     NULL,            /* unlink */
  98.     NULL,            /* symlink */
  99.     NULL,            /* mkdir */
  100.     NULL,            /* rmdir */
  101.     NULL,            /* mknod */
  102.     NULL,            /* rename */
  103.     NULL,            /* readlink */
  104.     NULL,            /* follow_link */
  105.     NULL,            /* bmap */
  106.     msdos_truncate,        /* truncate */
  107.     NULL,            /* permission */
  108.     NULL            /* smap */
  109. };
  110.  
  111. #define MSDOS_PREFETCH    32
  112. struct msdos_pre {
  113.     int file_sector;/* Next sector to read in the prefetch table */
  114.             /* This is relative to the file, not the disk */
  115.     struct buffer_head *bhlist[MSDOS_PREFETCH];    /* All buffers needed */
  116.     int nblist;    /* Number of buffers in bhlist */
  117.     int nolist;    /* index in bhlist */
  118. };
  119. /*
  120.     Order the prefetch of more sectors.
  121. */
  122. static void msdos_prefetch (
  123.     struct inode *inode,
  124.     struct msdos_pre *pre,
  125.     int nb)        /* How many must be prefetch at once */
  126. {
  127.     struct super_block *sb = inode->i_sb;
  128.     struct buffer_head *bhreq[MSDOS_PREFETCH];    /* Buffers not */
  129.                                                 /* already read */
  130.     int nbreq=0;            /* Number of buffers in bhreq */
  131.     int i;
  132.     for (i=0; i<nb; i++){
  133.         int sector = msdos_smap(inode,pre->file_sector);
  134.         if (sector != 0){
  135.             struct buffer_head *bh;
  136.             PRINTK (("fsector2 %d -> %d\n",pre->file_sector-1,sector));
  137.             pre->file_sector++;
  138.             bh = getblk(inode->i_dev,sector,SECTOR_SIZE);
  139.             if (bh == NULL)    break;
  140.             pre->bhlist[pre->nblist++] = bh;
  141.             if (!msdos_is_uptodate(sb,bh)) bhreq[nbreq++] = bh;
  142.         }else{
  143.             break;
  144.         }
  145.     }
  146.     if (nbreq > 0) msdos_ll_rw_block (sb,READ,nbreq,bhreq);
  147.     for (i=pre->nblist; i<MSDOS_PREFETCH; i++) pre->bhlist[i] = NULL;
  148. }
  149.  
  150. /*
  151.     Read a file into user space
  152. */
  153. int msdos_file_read(
  154.     struct inode *inode,
  155.     struct file *filp,
  156.     char *buf,
  157.     int count)
  158. {
  159.     struct super_block *sb = inode->i_sb;
  160.     char *start = buf;
  161.     char *end   = buf + count;
  162.     int i;
  163.     int left_in_file;
  164.     struct msdos_pre pre;
  165.         
  166.  
  167.     if (!inode) {
  168.         printk("msdos_file_read: inode = NULL\n");
  169.         return -EINVAL;
  170.     }
  171.     /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
  172.     if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
  173.         printk("msdos_file_read: mode = %07o\n",inode->i_mode);
  174.         return -EINVAL;
  175.     }
  176.     if (filp->f_pos >= inode->i_size || count <= 0) return 0;
  177.     /*
  178.         Tell the buffer cache which block we expect to read in advance
  179.         Since we are limited with the stack, we preread only MSDOS_PREFETCH
  180.         because we have to keep the result into the local
  181.         arrays pre.bhlist and bhreq.
  182.         
  183.         Each time we process one block in bhlist, we replace
  184.         it by a new prefetch block if needed.
  185.     */
  186.     PRINTK (("#### ino %ld pos %ld size %ld count %d\n",inode->i_ino,filp->f_pos,inode->i_size,count));
  187.     {
  188.         /*
  189.             We must prefetch complete block, so we must
  190.             take in account the offset in the first block.
  191.         */
  192.         int count_max = (filp->f_pos & (SECTOR_SIZE-1)) + count;
  193.         int   to_reada;    /* How many block to read all at once */
  194.         pre.file_sector = filp->f_pos >> SECTOR_BITS;
  195.         to_reada = count_max / SECTOR_SIZE;
  196.         if (count_max & (SECTOR_SIZE-1)) to_reada++;
  197.         if (filp->f_reada || !MSDOS_I(inode)->i_binary){
  198.             /* Doing a read ahead on ascii file make sure we always */
  199.             /* pre read enough, since we don't know how many blocks */
  200.             /* we really need */
  201.             int ahead = read_ahead[MAJOR(inode->i_dev)];
  202.             PRINTK (("to_reada %d ahead %d\n",to_reada,ahead));
  203.             if (ahead == 0) ahead = 8;
  204.             to_reada += ahead;
  205.         }
  206.         if (to_reada > MSDOS_PREFETCH) to_reada = MSDOS_PREFETCH;
  207.         pre.nblist = 0;
  208.         msdos_prefetch (inode,&pre,to_reada);
  209.     }
  210.     pre.nolist = 0;
  211.     PRINTK (("count %d ahead %d nblist %d\n",count,read_ahead[MAJOR(inode->i_dev)],pre.nblist));
  212.     while ((left_in_file = inode->i_size - filp->f_pos) > 0
  213.         && buf < end){
  214.         struct buffer_head *bh = pre.bhlist[pre.nolist];
  215.         char *data;
  216.         int size,offset;
  217.         if (bh == NULL) break;
  218.         pre.bhlist[pre.nolist] = NULL;
  219.         pre.nolist++;
  220.         if (pre.nolist == MSDOS_PREFETCH/2){
  221.             memcpy (pre.bhlist,pre.bhlist+MSDOS_PREFETCH/2
  222.                 ,(MSDOS_PREFETCH/2)*sizeof(pre.bhlist[0]));
  223.             pre.nblist -= MSDOS_PREFETCH/2;
  224.             msdos_prefetch (inode,&pre,MSDOS_PREFETCH/2);
  225.             pre.nolist = 0;
  226.         }
  227.         PRINTK (("file_read pos %ld nblist %d %d %d\n",filp->f_pos,pre.nblist,pre.fetched,count));
  228.         wait_on_buffer(bh);
  229.         if (!msdos_is_uptodate(sb,bh)){
  230.             /* read error  ? */
  231.             brelse (bh);
  232.             break;
  233.         }
  234.         offset = filp->f_pos & (SECTOR_SIZE-1);
  235.         data = bh->b_data + offset;
  236.         size = MIN(SECTOR_SIZE-offset,left_in_file);
  237.         if (MSDOS_I(inode)->i_binary) {
  238.             size = MIN(size,end-buf);
  239.             memcpy_tofs(buf,data,size);
  240.             buf += size;
  241.             filp->f_pos += size;
  242.         }else{
  243.             for (; size && buf < end; size--) {
  244.                 char ch = *data++;
  245.                 filp->f_pos++;
  246.                 if (ch == 26){
  247.                     filp->f_pos = inode->i_size;
  248.                     break;
  249.                 }else if (ch != '\r'){
  250.                     put_fs_byte(ch,buf++);
  251.                 }
  252.             }
  253.         }
  254.         brelse(bh);
  255.     }
  256.     PRINTK (("--- %d -> %d\n",count,(int)(buf-start)));
  257.     for (i=0; i<pre.nblist; i++) brelse (pre.bhlist[i]);
  258.     if (start == buf) return -EIO;
  259.     if (!IS_RDONLY(inode)) inode->i_atime = CURRENT_TIME;
  260.     filp->f_reada = 1;    /* Will be reset if a lseek is done */
  261.     return buf-start;
  262. }
  263.  
  264. /*
  265.     Write to a file either from user space
  266. */
  267. int msdos_file_write(
  268.     struct inode *inode,
  269.     struct file *filp,
  270.     char *buf,
  271.     int count)
  272. {
  273.     struct super_block *sb = inode->i_sb;
  274.     int sector,offset,size,left,written;
  275.     int error,carry;
  276.     char *start,*to,ch;
  277.     struct buffer_head *bh;
  278.     int binary_mode = MSDOS_I(inode)->i_binary;
  279.  
  280.     if (!inode) {
  281.         printk("msdos_file_write: inode = NULL\n");
  282.         return -EINVAL;
  283.     }
  284.     /* S_ISLNK allows for UMSDOS. Should never happen for normal MSDOS */
  285.     if (!S_ISREG(inode->i_mode) && !S_ISLNK(inode->i_mode)) {
  286.         printk("msdos_file_write: mode = %07o\n",inode->i_mode);
  287.         return -EINVAL;
  288.     }
  289. /*
  290.  * ok, append may not work when many processes are writing at the same time
  291.  * but so what. That way leads to madness anyway.
  292.  */
  293.     if (filp->f_flags & O_APPEND) filp->f_pos = inode->i_size;
  294.     if (count <= 0) return 0;
  295.     error = carry = 0;
  296.     for (start = buf; count || carry; count -= size) {
  297.         while (!(sector = msdos_smap(inode,filp->f_pos >> SECTOR_BITS)))
  298.             if ((error = msdos_add_cluster(inode)) < 0) break;
  299.         if (error) {
  300.             msdos_truncate(inode);
  301.             break;
  302.         }
  303.         offset = filp->f_pos & (SECTOR_SIZE-1);
  304.         size = MIN(SECTOR_SIZE-offset,MAX(carry,count));
  305.         if (binary_mode
  306.             && offset == 0
  307.             && (size == SECTOR_SIZE
  308.                 || filp->f_pos + size >= inode->i_size)){
  309.             /* No need to read the block first since we will */
  310.             /* completely overwrite it */
  311.             /* or at least write past the end of file */
  312.             if (!(bh = getblk(inode->i_dev,sector,SECTOR_SIZE))){
  313.                 error = -EIO;
  314.                 break;
  315.             }
  316.         }else if (!(bh = bread(inode->i_dev,sector,SECTOR_SIZE))) {
  317.             error = -EIO;
  318.             break;
  319.         }
  320.         if (binary_mode) {
  321.             memcpy_fromfs(bh->b_data+offset,buf,written = size);
  322.             buf += size;
  323.         }
  324.         else {
  325.             written = left = SECTOR_SIZE-offset;
  326.             to = (char *) bh->b_data+(filp->f_pos & (SECTOR_SIZE-1));
  327.             if (carry) {
  328.                 *to++ = '\n';
  329.                 left--;
  330.                 carry = 0;
  331.             }
  332.             for (size = 0; size < count && left; size++) {
  333.                 if ((ch = get_fs_byte(buf++)) == '\n') {
  334.                     *to++ = '\r';
  335.                     left--;
  336.                 }
  337.                 if (!left) carry = 1;
  338.                 else {
  339.                     *to++ = ch;
  340.                     left--;
  341.                 }
  342.             }
  343.             written -= left;
  344.         }
  345.         filp->f_pos += written;
  346.         if (filp->f_pos > inode->i_size) {
  347.             inode->i_size = filp->f_pos;
  348.             inode->i_dirt = 1;
  349.         }
  350.         msdos_set_uptodate(sb,bh,1);
  351.         mark_buffer_dirty(bh, 0);
  352.         brelse(bh);
  353.     }
  354.     if (start == buf)
  355.         return error;
  356.     inode->i_mtime = inode->i_ctime = CURRENT_TIME;
  357.     MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
  358.     inode->i_dirt = 1;
  359.     return buf-start;
  360. }
  361.  
  362. void msdos_truncate(struct inode *inode)
  363. {
  364.     int cluster;
  365.  
  366.     cluster = SECTOR_SIZE*MSDOS_SB(inode->i_sb)->cluster_size;
  367.     (void) fat_free(inode,(inode->i_size+(cluster-1))/cluster);
  368.     MSDOS_I(inode)->i_attrs |= ATTR_ARCH;
  369.     inode->i_dirt = 1;
  370. }
  371.