tools/llvm: Do not build with symbols
[minix3.git] / minix / fs / iso9660fs / read.c
blobff5738a3b66ad6adda4eb2d976dfbe216712575c
1 #include "inc.h"
2 #include <minix/com.h>
3 #include <minix/vfsif.h>
4 #include <minix/minlib.h>
5 #include <fcntl.h>
6 #include <stddef.h>
7 #include "buf.h"
9 static char getdents_buf[GETDENTS_BUFSIZ];
12 /*===========================================================================*
13 * fs_read *
14 *===========================================================================*/
15 int fs_read(void) {
16 int r, chunk, block_size;
17 size_t nrbytes;
18 cp_grant_id_t gid;
19 off_t position, f_size, bytes_left;
20 unsigned int off, cum_io;
21 int completed;
22 struct dir_record *dir;
23 int rw;
25 switch(fs_m_in.m_type) {
26 case REQ_READ: rw = READING; break;
27 case REQ_PEEK: rw = PEEKING; break;
28 default: panic("odd m_type");
31 r = OK;
33 /* Try to get inode according to its index */
34 dir = get_dir_record(fs_m_in.m_vfs_fs_readwrite.inode);
35 if (dir == NULL) return(EINVAL); /* no inode found */
37 position = fs_m_in.m_vfs_fs_readwrite.seek_pos;
38 nrbytes = fs_m_in.m_vfs_fs_readwrite.nbytes; /* number of bytes to read */
39 block_size = v_pri.logical_block_size_l;
40 gid = fs_m_in.m_vfs_fs_readwrite.grant;
41 f_size = dir->d_file_size;
43 rdwt_err = OK; /* set to EIO if disk error occurs */
45 cum_io = 0;
46 /* Split the transfer into chunks that don't span two blocks. */
47 while (nrbytes != 0) {
48 off = position % block_size;
50 chunk = MIN(nrbytes, block_size - off);
51 if (chunk < 0) chunk = block_size - off;
53 bytes_left = f_size - position;
54 if (position >= f_size) break; /* we are beyond EOF */
55 if (chunk > bytes_left) chunk = (int32_t) bytes_left;
57 /* Read or write 'chunk' bytes. */
58 r = read_chunk(dir, position, off, chunk,
59 (uint32_t) nrbytes, gid, cum_io, block_size,
60 &completed, rw);
62 if (r != OK) break; /* EOF reached */
63 if (rdwt_err < 0) break;
65 /* Update counters and pointers. */
66 nrbytes -= chunk; /* bytes yet to be read */
67 cum_io += chunk; /* bytes read so far */
68 position += chunk; /* position within the file */
71 fs_m_out.m_fs_vfs_readwrite.seek_pos = position;
73 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
74 if (rdwt_err == END_OF_FILE) r = OK;
76 fs_m_out.m_fs_vfs_readwrite.nbytes = cum_io; /*dir->d_file_size;*/
77 release_dir_record(dir);
79 return(r);
83 /*===========================================================================*
84 * fs_bread *
85 *===========================================================================*/
86 int fs_bread(void)
88 int r, rw_flag, chunk, block_size;
89 cp_grant_id_t gid;
90 int nrbytes;
91 u64_t position;
92 unsigned int off, cum_io;
93 int completed;
94 struct dir_record *dir;
96 r = OK;
98 rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
99 gid = fs_m_in.m_vfs_fs_breadwrite.grant;
100 position = fs_m_in.m_vfs_fs_breadwrite.seek_pos;
101 nrbytes = fs_m_in.m_vfs_fs_breadwrite.nbytes;
102 block_size = v_pri.logical_block_size_l;
103 dir = v_pri.dir_rec_root;
105 if(rw_flag == WRITING) return (EIO); /* Not supported */
106 rdwt_err = OK; /* set to EIO if disk error occurs */
108 cum_io = 0;
109 /* Split the transfer into chunks that don't span two blocks. */
110 while (nrbytes != 0) {
111 off = (unsigned int)(position % block_size); /* offset in blk*/
113 chunk = MIN(nrbytes, block_size - off);
114 if (chunk < 0) chunk = block_size - off;
116 /* Read 'chunk' bytes. */
117 r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes,
118 gid, cum_io, block_size, &completed, READING);
120 if (r != OK) break; /* EOF reached */
121 if (rdwt_err < 0) break;
123 /* Update counters and pointers. */
124 nrbytes -= chunk; /* bytes yet to be read */
125 cum_io += chunk; /* bytes read so far */
126 position += chunk; /* position within the file */
129 fs_m_out.m_fs_vfs_breadwrite.seek_pos = position;
131 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
132 if (rdwt_err == END_OF_FILE) r = OK;
134 fs_m_out.m_fs_vfs_breadwrite.nbytes = cum_io;
136 return(r);
140 /*===========================================================================*
141 * fs_getdents *
142 *===========================================================================*/
143 int fs_getdents(void)
145 struct dir_record *dir;
146 ino_t ino;
147 cp_grant_id_t gid;
148 size_t block_size;
149 off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off;
150 struct buf *bp;
151 struct dir_record *dir_tmp;
152 struct dirent *dirp;
153 int r,done,o,len,reclen;
154 char *cp;
155 char name[NAME_MAX + 1];
156 char name_old[NAME_MAX + 1];
158 /* Initialize the tmp arrays */
159 memset(name,'\0',NAME_MAX);
160 memset(name_old,'\0',NAME_MAX);
162 /* Get input parameters */
163 ino = fs_m_in.m_vfs_fs_getdents.inode;
164 gid = fs_m_in.m_vfs_fs_getdents.grant;
165 pos = fs_m_in.m_vfs_fs_getdents.seek_pos;
167 block_size = v_pri.logical_block_size_l;
168 cur_pos = pos; /* The current position */
169 tmpbuf_offset = 0;
170 userbuf_off = 0;
171 memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
173 if ((dir = get_dir_record(ino)) == NULL) return(EINVAL);
175 block = dir->loc_extent_l; /* First block of the directory */
176 block += pos / block_size; /* Shift to the block where start to read */
177 done = FALSE;
179 while (cur_pos<dir->d_file_size) {
180 bp = get_block(block); /* Get physical block */
182 if (bp == NULL) {
183 release_dir_record(dir);
184 return(EINVAL);
187 block_pos = cur_pos % block_size; /* Position where to start read */
189 while (block_pos < block_size) {
190 dir_tmp = get_free_dir_record();
191 create_dir_record(dir_tmp,b_data(bp) + block_pos,
192 block*block_size + block_pos);
193 if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */
194 block_pos = block_size;
195 done = TRUE;
196 release_dir_record(dir_tmp);
197 } else { /* The dir record is valid. Copy data... */
198 if (dir_tmp->file_id[0] == 0)
199 strlcpy(name, ".", NAME_MAX + 1);
200 else if (dir_tmp->file_id[0] == 1)
201 strlcpy(name, "..", NAME_MAX + 1);
202 else {
203 /* Extract the name from the field file_id */
204 strncpy(name, dir_tmp->file_id,
205 dir_tmp->length_file_id);
206 name[dir_tmp->length_file_id] = 0;
208 /* Tidy up file name */
209 cp = memchr(name, ';', NAME_MAX);
210 if (cp != NULL) name[cp - name] = 0;
212 /*If no file extension, then remove final '.'*/
213 if (name[strlen(name) - 1] == '.')
214 name[strlen(name) - 1] = '\0';
217 if (strcmp(name_old, name) == 0) {
218 cur_pos += dir_tmp->length;
219 release_dir_record(dir_tmp);
220 continue;
223 strlcpy(name_old, name, NAME_MAX + 1);
225 /* Compute the length of the name */
226 cp = memchr(name, '\0', NAME_MAX);
227 if (cp == NULL)
228 len = NAME_MAX;
229 else
230 len= cp - name;
232 /* Compute record length; also does alignment. */
233 reclen = _DIRENT_RECLEN(dirp, len);
235 /* If the new record does not fit, then copy the buffer
236 * and start from the beginning. */
237 if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) {
238 r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
239 (vir_bytes)getdents_buf, tmpbuf_offset);
241 if (r != OK)
242 panic("fs_getdents: sys_safecopyto failed: %d", r);
243 userbuf_off += tmpbuf_offset;
244 tmpbuf_offset= 0;
247 /* The standard data structure is created using the
248 * data in the buffer. */
249 dirp = (struct dirent *) &getdents_buf[tmpbuf_offset];
250 dirp->d_fileno = (u32_t)(b_data(bp) + (size_t)block_pos);
251 dirp->d_reclen= reclen;
252 dirp->d_type = fs_mode_to_type(dir_tmp->d_mode);
253 dirp->d_namlen = len;
254 memcpy(dirp->d_name, name, len);
255 dirp->d_name[len]= '\0';
256 tmpbuf_offset += reclen;
258 cur_pos += dir_tmp->length;
259 release_dir_record(dir_tmp);
262 block_pos += dir_tmp->length;
265 put_block(bp); /* release the block */
266 if (done == TRUE) break;
268 cur_pos += block_size - cur_pos;
269 block++; /* read the next one */
272 if (tmpbuf_offset != 0) {
273 r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
274 (vir_bytes) getdents_buf, tmpbuf_offset);
275 if (r != OK)
276 panic("fs_getdents: sys_safecopyto failed: %d", r);
278 userbuf_off += tmpbuf_offset;
281 fs_m_out.m_fs_vfs_getdents.nbytes = userbuf_off;
282 fs_m_out.m_fs_vfs_getdents.seek_pos = cur_pos;
284 release_dir_record(dir); /* release the inode */
285 return(OK);
289 /*===========================================================================*
290 * read_chunk *
291 *===========================================================================*/
292 int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed, rw)
293 register struct dir_record *dir;/* pointer to inode for file to be rd/wr */
294 u64_t position; /* position within file to read or write */
295 unsigned off; /* off within the current block */
296 int chunk; /* number of bytes to read or write */
297 unsigned left; /* max number of bytes wanted after position */
298 cp_grant_id_t gid; /* grant */
299 unsigned buf_off; /* offset in grant */
300 int block_size; /* block size of FS operating on */
301 int *completed; /* number of bytes copied */
302 int rw; /* READING or PEEKING */
305 register struct buf *bp;
306 register int r = OK;
307 block_t b;
308 int file_unit, rel_block, offset;
310 *completed = 0;
312 if ((ex64lo(position) <= dir->d_file_size) &&
313 (ex64lo(position) > dir->data_length_l)) {
314 while ((dir->d_next != NULL) && (ex64lo(position) > dir->data_length_l)) {
315 position -= dir->data_length_l;
316 dir = dir->d_next;
320 if (dir->inter_gap_size != 0) {
321 rel_block = (unsigned long)(position / block_size);
322 file_unit = rel_block / dir->data_length_l;
323 offset = rel_block % dir->file_unit_size;
324 b = dir->loc_extent_l + (dir->file_unit_size +
325 dir->inter_gap_size) * file_unit + offset;
326 } else {
327 b = dir->loc_extent_l + (unsigned long)(position / block_size);
328 /* Physical position to read. */
331 bp = get_block(b);
333 /* In all cases, bp now points to a valid buffer. */
334 if (bp == NULL) {
335 panic("bp not valid in rw_chunk; this can't happen");
338 if(rw == READING) {
339 r = sys_safecopyto(VFS_PROC_NR, gid, buf_off,
340 (vir_bytes) (b_data(bp)+off), (phys_bytes) chunk);
343 put_block(bp);
345 return(r);