Subversion Repositories HelenOS

Rev

Rev 2404 | Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 1987,1997, Prentice Hall
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use of the MINIX operating system in source and
  6.  * binary forms, with or without modification, are permitted provided
  7.  * that the following conditions are met:
  8.  
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  
  12.  * - Redistributions in binary form must reproduce the above
  13.  *   copyright notice, this list of conditions and the following
  14.  *   disclaimer in the documentation and/or other materials provided
  15.  *   with the distribution.
  16.  
  17.  * - Neither the name of Prentice Hall nor the names of the software
  18.  *   authors or contributors may be used to endorse or promote
  19.  *   products derived from this software without specific prior
  20.  *   written permission.
  21.  
  22.  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, AUTHORS, AND
  23.  * CONTRIBUTORS ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
  24.  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
  25.  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  26.  * IN NO EVENT SHALL PRENTICE HALL OR ANY AUTHORS OR CONTRIBUTORS BE
  27.  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
  28.  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
  29.  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
  30.  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
  31.  * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
  32.  * OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
  33.  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  34.  */
  35.  
  36. /** @addtogroup FileSystemImpl
  37. * @{
  38. */
  39.  
  40. /**
  41.  * @file    read.c
  42.  * @brief   This file contains the heart of the mechanism used to read files.
  43.  *        Read requests are split up into chunks that do not cross block
  44.  *        boundaries. Each chunk is then processed in turn.
  45.  */
  46.  
  47. #include <stdio.h>
  48. #include "fs.h"
  49. #include "block.h"
  50. #include "file.h"
  51. #include "fproc.h"
  52. #include "inode.h"
  53. #include "super.h"
  54. #include "param.h"
  55.  
  56.  
  57. static int read_chunk(inode_t *rip, offset_t position,
  58.         unsigned off, int chunk, char *buff);
  59.  
  60. /**
  61.  * Perform the READ system call
  62.  */
  63. int do_read()
  64. {
  65.    
  66.     /* Perform read(fd, buffer, nbytes) call. */
  67.    
  68.     register inode_t *rip;
  69.     register filp_t *f;
  70.     offset_t bytes_left, f_size, position;
  71.     unsigned int off, cum_io;
  72.     int oflags, r, chunk;
  73.     int regular;
  74.     mode_t mode_word;
  75.     void *old_addr;
  76.    
  77.  
  78.     /* If the file descriptor is valid, get the inode, size and mode. */
  79.     if (nbytes < 0)
  80.         return FS_EINVAL;
  81.  
  82.     if ((f = get_filp(fd)) == NIL_FILP)
  83.         return err_code;
  84.  
  85.     if (f->filp_mode == FILP_CLOSED)
  86.         return FS_EIO;
  87.      
  88.     if (nbytes == 0)
  89.         return 0;    
  90.      
  91.     position = f->filp_pos;
  92.     if (position > MAX_FILE_POS)
  93.         return FS_EINVAL;
  94.  
  95.     if (position + nbytes < position)
  96.         return FS_EINVAL;   /* unsigned overflow */
  97.      
  98.     oflags = f->filp_flags;
  99.     rip = f->filp_ino;
  100.     f_size = rip->i_size;
  101.     r = OK;  
  102.     cum_io = 0;
  103.     mode_word = rip->i_mode & I_TYPE;
  104.     regular = (mode_word == I_REGULAR);
  105.     status = OK;                /* set to EIO if disk error occurs */
  106.    
  107.     old_addr = fp->buffer; 
  108.    
  109.     /* Split the transfer into chunks that don't span two blocks. */
  110.     while (nbytes != 0) {
  111.         off = (unsigned int)(position % BLOCK_SIZE); /* offset in blk*/
  112.         chunk = MIN(nbytes, BLOCK_SIZE - off);
  113.         if (chunk < 0) {
  114.             chunk = BLOCK_SIZE - off;
  115.         }
  116.        
  117.         bytes_left = f_size - position;
  118.  
  119.         if (position >= f_size) {
  120.             break;          /* we are beyond EOF */
  121.         }
  122.         if (chunk > bytes_left)
  123.             chunk = (int)bytes_left;
  124.        
  125.  
  126.         /* Read 'chunk' bytes. */
  127.         r = read_chunk(rip, position, off, chunk, fp->buffer);
  128.    
  129.         if (status < 0)
  130.             break;
  131.    
  132.         /* Update counters and pointers. */
  133.         fp->buffer += chunk * sizeof(char);         /* user buffer address */
  134.            
  135.         nbytes -= chunk;        /* bytes yet to be read */
  136.         cum_io += chunk;        /* bytes read so far */
  137.             position += chunk;      /* position within the file */
  138.        
  139.     }
  140.    
  141.     if (bytes_left <= 0 || nbytes == 0)
  142.         status = END_OF_FILE;
  143.  
  144.     fp->buffer = old_addr;
  145.    
  146.     f->filp_pos = position;
  147.     rip->i_seek = NO_SEEK;
  148.    
  149.     if (status != OK) {
  150.         r = status;     /* check for disk error */
  151.     }
  152.     if (status == END_OF_FILE) {
  153.         r = OK;
  154.     }
  155.     if (r == OK) {
  156.         fp->fp_cum_io_partial = 0;
  157.         print_console("File was successfully read into buffer\n");
  158.  
  159.             return cum_io;
  160.     }
  161.     else {
  162.         print_console("Some error occured during reading the file\n");
  163.         return r;
  164.     }
  165. }
  166.  
  167. /**
  168.  * Given an inode and file position, look up its zone number
  169.  */
  170. static int read_chunk(register inode_t *rip, offset_t position, unsigned off,
  171.     int chunk, char *buff)
  172. {
  173.    
  174.     /*
  175.      * rip: pointer to inode for file to be read
  176.      * position:    position within file to read or write
  177.      * off:     off within the current block
  178.      * chunk:   number of bytes to read or write
  179.      * buff:    virtual address of the user buffer
  180.      */
  181.  
  182.     /* Read (part of) a block. */
  183.    
  184.     register block_t *bp;
  185.     block_num_t b;
  186.    
  187.     b = read_map(rip, position);
  188.      
  189.     /* Reading from a nonexistent block.  Must read as all zeros.*/
  190.     if (b == NO_BLOCK) {
  191.          bp = get_zero_block();    /* get a zero block */  
  192.     }
  193.     else {
  194.         bp = get_block(b);
  195.     }
  196.  
  197.     /* Copy a chunk from the block buffer to user space. */
  198.     memcpy((void *)buff, (void *)(bp->b.b__data+off), chunk);
  199.      
  200.     return OK;
  201. }
  202.  
  203. /**
  204.  * Read an entry in an indirect block
  205.  */
  206. block_num_t read_map(register inode_t *rip, offset_t position)
  207. {
  208.    
  209.     /* Given an inode and a position within the corresponding file, locate the
  210.      * block (not zone) number in which that position is to be found and return it.
  211.      */
  212.    
  213.     register block_t *bp;
  214.     register zone_t z;
  215.     int scale, boff, dzones, nr_indirects, index, zind, ex;
  216.     block_num_t b;
  217.     long excess, zone, block_pos;
  218.      
  219.     scale = rip->i_sp->s_log_zone_size;   /* for block-zone conversion */
  220.     block_pos = position/BLOCK_SIZE;      /* relative blk # in file */
  221.     zone = block_pos >> scale;    /* position's zone */
  222.     boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
  223.     dzones = rip->i_ndzones;
  224.     nr_indirects = rip->i_nindirs;
  225.    
  226.     /* Is 'position' to be found in the inode itself? */
  227.     if (zone < dzones) {
  228.         zind = (int)zone;      /* index should be an int */
  229.         z = rip->i_zone[zind];
  230.         if (z == NO_ZONE)
  231.            return NO_BLOCK;
  232.         b = ((block_num_t) z << scale) + boff;
  233.         return b;
  234.     }
  235.    
  236.     /* It is not in the inode, so it must be single or double indirect. */
  237.     excess = zone - dzones;       /* first Vx_NR_DZONES don't count */
  238.    
  239.     if (excess < nr_indirects) {
  240.     /* 'position' can be located via the single indirect block. */
  241.     z = rip->i_zone[dzones];
  242.     }
  243.     else {
  244.     /* 'position' can be located via the double indirect block. */
  245.         if ( (z = rip->i_zone[dzones+1]) == NO_ZONE)
  246.             return NO_BLOCK;
  247.  
  248.         excess -= nr_indirects;         /* single indir doesn't count*/
  249.         b = (block_num_t) z << scale;
  250.         bp = get_block(b);              /* get double indirect block */
  251.         index = (int) (excess/nr_indirects);
  252.         z = rd_indir(bp, index);        /* z= zone for single*/
  253.         excess = excess % nr_indirects;     /* index into single ind blk */
  254.     }
  255.    
  256.     /* 'z' is zone num for single indirect block; 'excess' is index into it. */
  257.     if (z == NO_ZONE)
  258.         return NO_BLOCK;
  259.  
  260.     b = (block_num_t) z << scale;       /* b is blk # for single ind */
  261.     bp = get_block(b);              /* get single indirect block */
  262.     ex = (int) excess;          /* need an integer */
  263.     z = rd_indir(bp, ex);           /* get block pointed to */
  264.      
  265.     if (z == NO_ZONE)
  266.         return NO_BLOCK;
  267.  
  268.     b = ((block_num_t) z << scale) + boff;
  269.  
  270.     return b;
  271. }
  272.    
  273. /**
  274.  *
  275.  */
  276. zone_t rd_indir(block_t *bp, int index)
  277. {
  278.  
  279.     super_block_t *sp;
  280.     zone_t zone;   
  281.    
  282.     sp = get_super();   /* need super block to find file sys type */
  283.    
  284.     /* read a zone from an indirect block */
  285.     if (sp->s_version == V1) {
  286.         zone = (zone_t)bp->b.b__v1_ind[index];
  287.     }
  288.     else {
  289.         zone = (zone_t)bp->b.b__v2_ind[index];
  290.     }
  291.     if (zone != NO_ZONE && (zone < (zone_t)sp->s_firstdatazone || zone >= sp->s_zones)) {
  292.         print_console_int("Illegal zone number %d ", zone);
  293.         print_console_int("in indirect block, index %d\n", index);
  294.     }
  295.  
  296.     return zone;
  297. }
  298.    
  299.  
  300. /**
  301.  * }
  302.  */
  303.  
  304.