Subversion Repositories HelenOS

Rev

Rev 2379 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2404 konopa 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
 
2379 konopa 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