Subversion Repositories HelenOS

Rev

Rev 2404 | 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
 */
2435 jelen 35
 
36
/** @addtogroup FileSystemImpl
37
* @{
38
*/
2404 konopa 39
 
2435 jelen 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.
2379 konopa 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
 
2435 jelen 60
/**
61
 * Perform the READ system call
62
 */
2379 konopa 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
}
2435 jelen 166
 
167
/**
168
 * Given an inode and file position, look up its zone number
169
 */
2379 konopa 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
}
2435 jelen 202
 
203
/**
204
 * Read an entry in an indirect block
205
 */
2379 konopa 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
 
2435 jelen 273
/**
274
 *
275
 */
2379 konopa 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
 
2435 jelen 299
 
300
/**
301
 * }
302
 */
303