Fixed extern declaration from pointer to array
[minix.git] / servers / iso9660fs / read.c
blob3d32ce26db80a8970dd64c8796f54cf38e895e37
1 #include "inc.h"
2 #include <minix/com.h>
3 #include <minix/vfsif.h>
4 #include <fcntl.h>
5 #include "buf.h"
7 PRIVATE char getdents_buf[GETDENTS_BUFSIZ];
10 /*===========================================================================*
11 * fs_read *
12 *===========================================================================*/
13 PUBLIC int fs_read(void) {
14 int r, chunk, block_size;
15 int nrbytes;
16 cp_grant_id_t gid;
17 off_t position, f_size, bytes_left;
18 unsigned int off, cum_io;
19 int completed;
20 struct dir_record *dir;
22 r = OK;
24 /* Try to get inode according to its index */
25 dir = get_dir_record(fs_m_in.REQ_INODE_NR);
26 if (dir == NULL) return(EINVAL); /* no inode found */
28 position = fs_m_in.REQ_SEEK_POS_LO;
29 nrbytes = (unsigned) fs_m_in.REQ_NBYTES; /* number of bytes to read */
30 block_size = v_pri.logical_block_size_l;
31 gid = fs_m_in.REQ_GRANT;
32 f_size = dir->d_file_size;
34 rdwt_err = OK; /* set to EIO if disk error occurs */
36 cum_io = 0;
37 /* Split the transfer into chunks that don't span two blocks. */
38 while (nrbytes != 0) {
39 off = (unsigned int) (position % block_size);
41 chunk = MIN(nrbytes, block_size - off);
42 if (chunk < 0) chunk = block_size - off;
44 bytes_left = f_size - position;
45 if (position >= f_size) break; /* we are beyond EOF */
46 if (chunk > bytes_left) chunk = (int) bytes_left;
48 /* Read or write 'chunk' bytes. */
49 r = read_chunk(dir, cvul64(position), off, chunk, (unsigned) nrbytes,
50 gid, cum_io, block_size, &completed);
52 if (r != OK) break; /* EOF reached */
53 if (rdwt_err < 0) break;
55 /* Update counters and pointers. */
56 nrbytes -= chunk; /* bytes yet to be read */
57 cum_io += chunk; /* bytes read so far */
58 position += chunk; /* position within the file */
61 fs_m_out.RES_SEEK_POS_LO = position;
63 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
64 if (rdwt_err == END_OF_FILE) r = OK;
66 fs_m_out.RES_NBYTES = cum_io; /*dir->d_file_size;*/
67 release_dir_record(dir);
69 return(r);
73 /*===========================================================================*
74 * fs_bread *
75 *===========================================================================*/
76 PUBLIC int fs_bread(void)
78 int r, rw_flag, chunk, block_size;
79 cp_grant_id_t gid;
80 int nrbytes;
81 u64_t position;
82 unsigned int off, cum_io;
83 mode_t mode_word;
84 int completed, r2 = OK;
85 struct dir_record *dir;
87 r = OK;
89 rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
90 gid = fs_m_in.REQ_GRANT;
91 position = make64(fs_m_in.REQ_SEEK_POS_LO, fs_m_in.REQ_SEEK_POS_HI);
92 nrbytes = (unsigned) fs_m_in.REQ_NBYTES;
93 block_size = v_pri.logical_block_size_l;
94 dir = v_pri.dir_rec_root;
96 if(rw_flag == WRITING) return (EIO); /* Not supported */
97 rdwt_err = OK; /* set to EIO if disk error occurs */
99 cum_io = 0;
100 /* Split the transfer into chunks that don't span two blocks. */
101 while (nrbytes != 0) {
102 off = rem64u(position, block_size); /* offset in blk*/
104 chunk = MIN(nrbytes, block_size - off);
105 if (chunk < 0) chunk = block_size - off;
107 /* Read 'chunk' bytes. */
108 r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes,
109 gid, cum_io, block_size, &completed);
111 if (r != OK) break; /* EOF reached */
112 if (rdwt_err < 0) break;
114 /* Update counters and pointers. */
115 nrbytes -= chunk; /* bytes yet to be read */
116 cum_io += chunk; /* bytes read so far */
117 position= add64ul(position, chunk); /* position within the file */
120 fs_m_out.RES_SEEK_POS_LO = ex64lo(position);
121 fs_m_out.RES_SEEK_POS_HI = ex64hi(position);
123 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
124 if (rdwt_err == END_OF_FILE) r = OK;
126 fs_m_out.RES_NBYTES = cum_io;
128 return(r);
132 /*===========================================================================*
133 * fs_getdents *
134 *===========================================================================*/
135 PUBLIC int fs_getdents(void) {
136 struct dir_record *dir;
137 ino_t ino;
138 cp_grant_id_t gid;
139 size_t size_to_read, block_size;
140 off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off;
141 struct buf *bp;
142 struct dir_record *dir_tmp;
143 struct dirent *dirp;
144 int r,done,o,len,reclen;
145 char *cp;
146 char name[NAME_MAX + 1];
147 char name_old[NAME_MAX + 1];
149 /* Initialize the tmp arrays */
150 memset(name,'\0',NAME_MAX);
151 memset(name_old,'\0',NAME_MAX);
153 /* Get input parameters */
154 ino = fs_m_in.REQ_INODE_NR;
155 gid = fs_m_in.REQ_GRANT;
156 size_to_read = fs_m_in.REQ_MEM_SIZE;
157 pos = fs_m_in.REQ_SEEK_POS_LO;
159 block_size = v_pri.logical_block_size_l;
160 cur_pos = pos; /* The current position */
161 tmpbuf_offset = 0;
162 userbuf_off = 0;
163 memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
165 if ((dir = get_dir_record(ino)) == NULL) return(EINVAL);
167 block = dir->loc_extent_l; /* First block of the directory */
168 block += pos / block_size; /* Shift to the block where start to read */
169 done = FALSE;
171 while (cur_pos<dir->d_file_size) {
172 bp = get_block(block); /* Get physical block */
174 if (bp == NIL_BUF) {
175 release_dir_record(dir);
176 return(EINVAL);
179 block_pos = cur_pos % block_size; /* Position where to start read */
181 while (block_pos < block_size) {
182 dir_tmp = get_free_dir_record();
183 create_dir_record(dir_tmp,bp->b_data + block_pos,
184 block*block_size + block_pos);
185 if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */
186 block_pos = block_size;
187 done = TRUE;
188 release_dir_record(dir_tmp);
189 } else { /* The dir record is valid. Copy data... */
190 if (dir_tmp->file_id[0] == 0) strcpy(name,".");
191 else if (dir_tmp->file_id[0] == 1) strcpy(name,"..");
192 else {
193 /* Extract the name from the field file_id */
194 strncpy(name, dir_tmp->file_id,
195 dir_tmp->length_file_id);
196 name[dir_tmp->length_file_id] = 0;
198 /* Tidy up file name */
199 cp = memchr(name, ';', NAME_MAX);
200 if (cp != NULL) name[cp - name] = 0;
202 /*If no file extension, then remove final '.'*/
203 if (name[strlen(name) - 1] == '.')
204 name[strlen(name) - 1] = '\0';
207 if (strcmp(name_old, name) == 0) {
208 cur_pos += dir_tmp->length;
209 release_dir_record(dir_tmp);
210 continue;
213 strcpy(name_old,name);
215 /* Compute the length of the name */
216 cp = memchr(name, '\0', NAME_MAX);
217 if (cp == NULL) len = NAME_MAX;
218 else len= cp - name;
220 /* Compute record length */
221 reclen = offsetof(struct dirent, d_name) + len + 1;
222 o = (reclen % sizeof(long));
223 if (o != 0)
224 reclen += sizeof(long) - o;
226 /* If the new record does not fit, then copy the buffer
227 * and start from the beginning. */
228 if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) {
229 r = sys_safecopyto(FS_PROC_NR, gid, userbuf_off,
230 (vir_bytes)getdents_buf, tmpbuf_offset, D);
232 if (r != OK)
233 panic(__FILE__,
234 "fs_getdents: sys_safecopyto failed\n",r);
236 userbuf_off += tmpbuf_offset;
237 tmpbuf_offset= 0;
240 /* The standard data structure is created using the
241 * data in the buffer. */
242 dirp = (struct dirent *) &getdents_buf[tmpbuf_offset];
243 dirp->d_ino = (ino_t)(bp->b_data + block_pos);
244 dirp->d_off= cur_pos;
245 dirp->d_reclen= reclen;
246 memcpy(dirp->d_name, name, len);
247 dirp->d_name[len]= '\0';
248 tmpbuf_offset += reclen;
250 cur_pos += dir_tmp->length;
251 release_dir_record(dir_tmp);
254 block_pos += dir_tmp->length;
257 put_block(bp); /* release the block */
258 if (done == TRUE) break;
260 cur_pos += block_size - cur_pos;
261 block++; /* read the next one */
264 if (tmpbuf_offset != 0) {
265 r = sys_safecopyto(FS_PROC_NR, gid, userbuf_off,
266 (vir_bytes) getdents_buf, tmpbuf_offset, D);
267 if (r != OK)
268 panic(__FILE__, "fs_getdents: sys_safecopyto failed\n", r);
270 userbuf_off += tmpbuf_offset;
273 fs_m_out.RES_NBYTES = userbuf_off;
274 fs_m_out.RES_SEEK_POS_LO = cur_pos;
276 release_dir_record(dir); /* release the inode */
277 return(OK);
281 /*===========================================================================*
282 * read_chunk *
283 *===========================================================================*/
284 PUBLIC int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed)
285 register struct dir_record *dir;/* pointer to inode for file to be rd/wr */
286 u64_t position; /* position within file to read or write */
287 unsigned off; /* off within the current block */
288 int chunk; /* number of bytes to read or write */
289 unsigned left; /* max number of bytes wanted after position */
290 cp_grant_id_t gid; /* grant */
291 unsigned buf_off; /* offset in grant */
292 int block_size; /* block size of FS operating on */
293 int *completed; /* number of bytes copied */
296 register struct buf *bp;
297 register int r = OK;
298 int n;
299 block_t b;
300 dev_t dev;
301 int file_unit, rel_block, offset;
303 *completed = 0;
305 if ((ex64lo(position) <= dir->d_file_size) &&
306 (ex64lo(position) > dir->data_length_l)) {
307 while ((dir->d_next != NULL) && (ex64lo(position) > dir->data_length_l)) {
308 position = sub64ul(position, dir->data_length_l);
309 dir = dir->d_next;
313 if (dir->inter_gap_size != 0) {
314 rel_block = div64u(position, block_size);
315 file_unit = rel_block / dir->data_length_l;
316 offset = rel_block % dir->file_unit_size;
317 b = dir->loc_extent_l + (dir->file_unit_size +
318 dir->inter_gap_size) * file_unit + offset;
319 } else {
320 b = dir->loc_extent_l + div64u(position, block_size); /* Physical position
321 * to read. */
324 bp = get_block(b);
326 /* In all cases, bp now points to a valid buffer. */
327 if (bp == NIL_BUF) {
328 panic(__FILE__,"bp not valid in rw_chunk, this can't happen", NO_NUM);
331 r = sys_safecopyto(FS_PROC_NR, gid, buf_off,
332 (vir_bytes) (bp->b_data+off), (phys_bytes) chunk, D);
334 put_block(bp);
336 return(r);