Subversion Repositories HelenOS

Rev

Rev 2379 | 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.  
  37. /* This file contains the heart of the mechanism used to read files.
  38.  * Read requests are split up into chunks that do not cross block
  39.  * boundaries. Each chunk is then processed in turn.
  40.  */
  41.  
  42. /* Methods:
  43.  * do_read:    perform the READ system call
  44.  * read_map:   given an inode and file position, look up its zone number
  45.  * rd_indir:   read an entry in an indirect block
  46.  */
  47.  
  48. #include <stdio.h>
  49. #include "fs.h"
  50. #include "block.h"
  51. #include "file.h"
  52. #include "fproc.h"
  53. #include "inode.h"
  54. #include "super.h"
  55. #include "param.h"
  56.  
  57.  
  58. static int read_chunk(inode_t *rip, offset_t position,
  59.         unsigned off, int chunk, char *buff);
  60.  
  61. int do_read()
  62. {
  63.    
  64.     /* Perform read(fd, buffer, nbytes) call. */
  65.    
  66.     register inode_t *rip;
  67.     register filp_t *f;
  68.     offset_t bytes_left, f_size, position;
  69.     unsigned int off, cum_io;
  70.     int oflags, r, chunk;
  71.     int regular;
  72.     mode_t mode_word;
  73.     void *old_addr;
  74.    
  75.  
  76.     /* If the file descriptor is valid, get the inode, size and mode. */
  77.     if (nbytes < 0)
  78.         return FS_EINVAL;
  79.  
  80.     if ((f = get_filp(fd)) == NIL_FILP)
  81.         return err_code;
  82.  
  83.     if (f->filp_mode == FILP_CLOSED)
  84.         return FS_EIO;
  85.      
  86.     if (nbytes == 0)
  87.         return 0;    
  88.      
  89.     position = f->filp_pos;
  90.     if (position > MAX_FILE_POS)
  91.         return FS_EINVAL;
  92.  
  93.     if (position + nbytes < position)
  94.         return FS_EINVAL;   /* unsigned overflow */
  95.      
  96.     oflags = f->filp_flags;
  97.     rip = f->filp_ino;
  98.     f_size = rip->i_size;
  99.     r = OK;  
  100.     cum_io = 0;
  101.     mode_word = rip->i_mode & I_TYPE;
  102.     regular = (mode_word == I_REGULAR);
  103.     status = OK;                /* set to EIO if disk error occurs */
  104.    
  105.     old_addr = fp->buffer; 
  106.    
  107.     /* Split the transfer into chunks that don't span two blocks. */
  108.     while (nbytes != 0) {
  109.         off = (unsigned int)(position % BLOCK_SIZE); /* offset in blk*/
  110.         chunk = MIN(nbytes, BLOCK_SIZE - off);
  111.         if (chunk < 0) {
  112.             chunk = BLOCK_SIZE - off;
  113.         }
  114.        
  115.         bytes_left = f_size - position;
  116.  
  117.         if (position >= f_size) {
  118.             break;          /* we are beyond EOF */
  119.         }
  120.         if (chunk > bytes_left)
  121.             chunk = (int)bytes_left;
  122.        
  123.  
  124.         /* Read 'chunk' bytes. */
  125.         r = read_chunk(rip, position, off, chunk, fp->buffer);
  126.    
  127.         if (status < 0)
  128.             break;
  129.    
  130.         /* Update counters and pointers. */
  131.         fp->buffer += chunk * sizeof(char);         /* user buffer address */
  132.            
  133.         nbytes -= chunk;        /* bytes yet to be read */
  134.         cum_io += chunk;        /* bytes read so far */
  135.             position += chunk;      /* position within the file */
  136.        
  137.     }
  138.    
  139.     if (bytes_left <= 0 || nbytes == 0)
  140.         status = END_OF_FILE;
  141.  
  142.     fp->buffer = old_addr;
  143.    
  144.     f->filp_pos = position;
  145.     rip->i_seek = NO_SEEK;
  146.    
  147.     if (status != OK) {
  148.         r = status;     /* check for disk error */
  149.     }
  150.     if (status == END_OF_FILE) {
  151.         r = OK;
  152.     }
  153.     if (r == OK) {
  154.         fp->fp_cum_io_partial = 0;
  155.         print_console("File was successfully read into buffer\n");
  156.  
  157.             return cum_io;
  158.     }
  159.     else {
  160.         print_console("Some error occured during reading the file\n");
  161.         return r;
  162.     }
  163. }
  164.    
  165. static int read_chunk(register inode_t *rip, offset_t position, unsigned off,
  166.     int chunk, char *buff)
  167. {
  168.    
  169.     /*
  170.      * rip: pointer to inode for file to be read
  171.      * position:    position within file to read or write
  172.      * off:     off within the current block
  173.      * chunk:   number of bytes to read or write
  174.      * buff:    virtual address of the user buffer
  175.      */
  176.  
  177.     /* Read (part of) a block. */
  178.    
  179.     register block_t *bp;
  180.     block_num_t b;
  181.    
  182.     b = read_map(rip, position);
  183.      
  184.     /* Reading from a nonexistent block.  Must read as all zeros.*/
  185.     if (b == NO_BLOCK) {
  186.          bp = get_zero_block();    /* get a zero block */  
  187.     }
  188.     else {
  189.         bp = get_block(b);
  190.     }
  191.  
  192.     /* Copy a chunk from the block buffer to user space. */
  193.     memcpy((void *)buff, (void *)(bp->b.b__data+off), chunk);
  194.      
  195.     return OK;
  196. }
  197.    
  198. block_num_t read_map(register inode_t *rip, offset_t position)
  199. {
  200.    
  201.     /* Given an inode and a position within the corresponding file, locate the
  202.      * block (not zone) number in which that position is to be found and return it.
  203.      */
  204.    
  205.     register block_t *bp;
  206.     register zone_t z;
  207.     int scale, boff, dzones, nr_indirects, index, zind, ex;
  208.     block_num_t b;
  209.     long excess, zone, block_pos;
  210.      
  211.     scale = rip->i_sp->s_log_zone_size;   /* for block-zone conversion */
  212.     block_pos = position/BLOCK_SIZE;      /* relative blk # in file */
  213.     zone = block_pos >> scale;    /* position's zone */
  214.     boff = (int) (block_pos - (zone << scale) ); /* relative blk # within zone */
  215.     dzones = rip->i_ndzones;
  216.     nr_indirects = rip->i_nindirs;
  217.    
  218.     /* Is 'position' to be found in the inode itself? */
  219.     if (zone < dzones) {
  220.         zind = (int)zone;      /* index should be an int */
  221.         z = rip->i_zone[zind];
  222.         if (z == NO_ZONE)
  223.            return NO_BLOCK;
  224.         b = ((block_num_t) z << scale) + boff;
  225.         return b;
  226.     }
  227.    
  228.     /* It is not in the inode, so it must be single or double indirect. */
  229.     excess = zone - dzones;       /* first Vx_NR_DZONES don't count */
  230.    
  231.     if (excess < nr_indirects) {
  232.     /* 'position' can be located via the single indirect block. */
  233.     z = rip->i_zone[dzones];
  234.     }
  235.     else {
  236.     /* 'position' can be located via the double indirect block. */
  237.         if ( (z = rip->i_zone[dzones+1]) == NO_ZONE)
  238.             return NO_BLOCK;
  239.  
  240.         excess -= nr_indirects;         /* single indir doesn't count*/
  241.         b = (block_num_t) z << scale;
  242.         bp = get_block(b);              /* get double indirect block */
  243.         index = (int) (excess/nr_indirects);
  244.         z = rd_indir(bp, index);        /* z= zone for single*/
  245.         excess = excess % nr_indirects;     /* index into single ind blk */
  246.     }
  247.    
  248.     /* 'z' is zone num for single indirect block; 'excess' is index into it. */
  249.     if (z == NO_ZONE)
  250.         return NO_BLOCK;
  251.  
  252.     b = (block_num_t) z << scale;       /* b is blk # for single ind */
  253.     bp = get_block(b);              /* get single indirect block */
  254.     ex = (int) excess;          /* need an integer */
  255.     z = rd_indir(bp, ex);           /* get block pointed to */
  256.      
  257.     if (z == NO_ZONE)
  258.         return NO_BLOCK;
  259.  
  260.     b = ((block_num_t) z << scale) + boff;
  261.  
  262.     return b;
  263. }
  264.    
  265. zone_t rd_indir(block_t *bp, int index)
  266. {
  267.  
  268.     super_block_t *sp;
  269.     zone_t zone;   
  270.    
  271.     sp = get_super();   /* need super block to find file sys type */
  272.    
  273.     /* read a zone from an indirect block */
  274.     if (sp->s_version == V1) {
  275.         zone = (zone_t)bp->b.b__v1_ind[index];
  276.     }
  277.     else {
  278.         zone = (zone_t)bp->b.b__v2_ind[index];
  279.     }
  280.     if (zone != NO_ZONE && (zone < (zone_t)sp->s_firstdatazone || zone >= sp->s_zones)) {
  281.         print_console_int("Illegal zone number %d ", zone);
  282.         print_console_int("in indirect block, index %d\n", index);
  283.     }
  284.  
  285.     return zone;
  286. }
  287.    
  288.