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 |