kernel: restore setting KTS_NONE
[minix.git] / servers / iso9660fs / read.c
blob012ee2bd7063eb205597e5edda35314d4eac25e6
1 #include "inc.h"
2 #include <minix/com.h>
3 #include <minix/vfsif.h>
4 #include <fcntl.h>
5 #ifdef __NBSD_LIBC
6 #include <stddef.h>
7 #endif
8 #include "buf.h"
10 static char getdents_buf[GETDENTS_BUFSIZ];
13 /*===========================================================================*
14 * fs_read *
15 *===========================================================================*/
16 int fs_read(void) {
17 int r, chunk, block_size;
18 int nrbytes;
19 cp_grant_id_t gid;
20 off_t position, f_size, bytes_left;
21 unsigned int off, cum_io;
22 int completed;
23 struct dir_record *dir;
25 r = OK;
27 /* Try to get inode according to its index */
28 dir = get_dir_record(fs_m_in.REQ_INODE_NR);
29 if (dir == NULL) return(EINVAL); /* no inode found */
31 position = fs_m_in.REQ_SEEK_POS_LO;
32 nrbytes = (unsigned) fs_m_in.REQ_NBYTES; /* number of bytes to read */
33 block_size = v_pri.logical_block_size_l;
34 gid = fs_m_in.REQ_GRANT;
35 f_size = dir->d_file_size;
37 rdwt_err = OK; /* set to EIO if disk error occurs */
39 cum_io = 0;
40 /* Split the transfer into chunks that don't span two blocks. */
41 while (nrbytes != 0) {
42 off = (unsigned int) (position % block_size);
44 chunk = MIN(nrbytes, block_size - off);
45 if (chunk < 0) chunk = block_size - off;
47 bytes_left = f_size - position;
48 if (position >= f_size) break; /* we are beyond EOF */
49 if (chunk > bytes_left) chunk = (int) bytes_left;
51 /* Read or write 'chunk' bytes. */
52 r = read_chunk(dir, cvul64(position), off, chunk, (unsigned) nrbytes,
53 gid, cum_io, block_size, &completed);
55 if (r != OK) break; /* EOF reached */
56 if (rdwt_err < 0) break;
58 /* Update counters and pointers. */
59 nrbytes -= chunk; /* bytes yet to be read */
60 cum_io += chunk; /* bytes read so far */
61 position += chunk; /* position within the file */
64 fs_m_out.RES_SEEK_POS_LO = position;
66 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
67 if (rdwt_err == END_OF_FILE) r = OK;
69 fs_m_out.RES_NBYTES = cum_io; /*dir->d_file_size;*/
70 release_dir_record(dir);
72 return(r);
76 /*===========================================================================*
77 * fs_bread *
78 *===========================================================================*/
79 int fs_bread(void)
81 int r, rw_flag, chunk, block_size;
82 cp_grant_id_t gid;
83 int nrbytes;
84 u64_t position;
85 unsigned int off, cum_io;
86 int completed;
87 struct dir_record *dir;
89 r = OK;
91 rw_flag = (fs_m_in.m_type == REQ_BREAD ? READING : WRITING);
92 gid = fs_m_in.REQ_GRANT;
93 position = make64(fs_m_in.REQ_SEEK_POS_LO, fs_m_in.REQ_SEEK_POS_HI);
94 nrbytes = (unsigned) fs_m_in.REQ_NBYTES;
95 block_size = v_pri.logical_block_size_l;
96 dir = v_pri.dir_rec_root;
98 if(rw_flag == WRITING) return (EIO); /* Not supported */
99 rdwt_err = OK; /* set to EIO if disk error occurs */
101 cum_io = 0;
102 /* Split the transfer into chunks that don't span two blocks. */
103 while (nrbytes != 0) {
104 off = rem64u(position, block_size); /* offset in blk*/
106 chunk = MIN(nrbytes, block_size - off);
107 if (chunk < 0) chunk = block_size - off;
109 /* Read 'chunk' bytes. */
110 r = read_chunk(dir, position, off, chunk, (unsigned) nrbytes,
111 gid, cum_io, block_size, &completed);
113 if (r != OK) break; /* EOF reached */
114 if (rdwt_err < 0) break;
116 /* Update counters and pointers. */
117 nrbytes -= chunk; /* bytes yet to be read */
118 cum_io += chunk; /* bytes read so far */
119 position= add64ul(position, chunk); /* position within the file */
122 fs_m_out.RES_SEEK_POS_LO = ex64lo(position);
123 fs_m_out.RES_SEEK_POS_HI = ex64hi(position);
125 if (rdwt_err != OK) r = rdwt_err; /* check for disk error */
126 if (rdwt_err == END_OF_FILE) r = OK;
128 fs_m_out.RES_NBYTES = cum_io;
130 return(r);
134 /*===========================================================================*
135 * fs_getdents *
136 *===========================================================================*/
137 int fs_getdents(void) {
138 struct dir_record *dir;
139 ino_t ino;
140 cp_grant_id_t gid;
141 size_t block_size;
142 off_t pos, block_pos, block, cur_pos, tmpbuf_offset, userbuf_off;
143 struct buf *bp;
144 struct dir_record *dir_tmp;
145 struct dirent *dirp;
146 int r,done,o,len,reclen;
147 char *cp;
148 char name[NAME_MAX + 1];
149 char name_old[NAME_MAX + 1];
151 /* Initialize the tmp arrays */
152 memset(name,'\0',NAME_MAX);
153 memset(name_old,'\0',NAME_MAX);
155 /* Get input parameters */
156 ino = fs_m_in.REQ_INODE_NR;
157 gid = fs_m_in.REQ_GRANT;
158 pos = fs_m_in.REQ_SEEK_POS_LO;
160 block_size = v_pri.logical_block_size_l;
161 cur_pos = pos; /* The current position */
162 tmpbuf_offset = 0;
163 userbuf_off = 0;
164 memset(getdents_buf, '\0', GETDENTS_BUFSIZ); /* Avoid leaking any data */
166 if ((dir = get_dir_record(ino)) == NULL) return(EINVAL);
168 block = dir->loc_extent_l; /* First block of the directory */
169 block += pos / block_size; /* Shift to the block where start to read */
170 done = FALSE;
172 while (cur_pos<dir->d_file_size) {
173 bp = get_block(block); /* Get physical block */
175 if (bp == NULL) {
176 release_dir_record(dir);
177 return(EINVAL);
180 block_pos = cur_pos % block_size; /* Position where to start read */
182 while (block_pos < block_size) {
183 dir_tmp = get_free_dir_record();
184 create_dir_record(dir_tmp,b_data(bp) + block_pos,
185 block*block_size + block_pos);
186 if (dir_tmp->length == 0) { /* EOF. I exit and return 0s */
187 block_pos = block_size;
188 done = TRUE;
189 release_dir_record(dir_tmp);
190 } else { /* The dir record is valid. Copy data... */
191 if (dir_tmp->file_id[0] == 0)
192 strlcpy(name, ".", NAME_MAX + 1);
193 else if (dir_tmp->file_id[0] == 1)
194 strlcpy(name, "..", NAME_MAX + 1);
195 else {
196 /* Extract the name from the field file_id */
197 strncpy(name, dir_tmp->file_id,
198 dir_tmp->length_file_id);
199 name[dir_tmp->length_file_id] = 0;
201 /* Tidy up file name */
202 cp = memchr(name, ';', NAME_MAX);
203 if (cp != NULL) name[cp - name] = 0;
205 /*If no file extension, then remove final '.'*/
206 if (name[strlen(name) - 1] == '.')
207 name[strlen(name) - 1] = '\0';
210 if (strcmp(name_old, name) == 0) {
211 cur_pos += dir_tmp->length;
212 release_dir_record(dir_tmp);
213 continue;
216 strlcpy(name_old, name, NAME_MAX + 1);
218 /* Compute the length of the name */
219 cp = memchr(name, '\0', NAME_MAX);
220 if (cp == NULL) len = NAME_MAX;
221 else len= cp - name;
223 /* Compute record length */
224 reclen = offsetof(struct dirent, d_name) + len + 1;
225 o = (reclen % sizeof(long));
226 if (o != 0)
227 reclen += sizeof(long) - o;
229 /* If the new record does not fit, then copy the buffer
230 * and start from the beginning. */
231 if (tmpbuf_offset + reclen > GETDENTS_BUFSIZ) {
232 r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
233 (vir_bytes)getdents_buf, tmpbuf_offset);
235 if (r != OK)
236 panic("fs_getdents: sys_safecopyto failed: %d", r);
237 userbuf_off += tmpbuf_offset;
238 tmpbuf_offset= 0;
241 /* The standard data structure is created using the
242 * data in the buffer. */
243 dirp = (struct dirent *) &getdents_buf[tmpbuf_offset];
244 dirp->d_ino = (ino_t)(b_data(bp) + block_pos);
245 dirp->d_off= cur_pos;
246 dirp->d_reclen= reclen;
247 memcpy(dirp->d_name, name, len);
248 dirp->d_name[len]= '\0';
249 tmpbuf_offset += reclen;
251 cur_pos += dir_tmp->length;
252 release_dir_record(dir_tmp);
255 block_pos += dir_tmp->length;
258 put_block(bp); /* release the block */
259 if (done == TRUE) break;
261 cur_pos += block_size - cur_pos;
262 block++; /* read the next one */
265 if (tmpbuf_offset != 0) {
266 r = sys_safecopyto(VFS_PROC_NR, gid, userbuf_off,
267 (vir_bytes) getdents_buf, tmpbuf_offset);
268 if (r != OK)
269 panic("fs_getdents: sys_safecopyto failed: %d", r);
271 userbuf_off += tmpbuf_offset;
274 fs_m_out.RES_NBYTES = userbuf_off;
275 fs_m_out.RES_SEEK_POS_LO = cur_pos;
277 release_dir_record(dir); /* release the inode */
278 return(OK);
282 /*===========================================================================*
283 * read_chunk *
284 *===========================================================================*/
285 int read_chunk(dir, position, off, chunk, left, gid, buf_off, block_size, completed)
286 register struct dir_record *dir;/* pointer to inode for file to be rd/wr */
287 u64_t position; /* position within file to read or write */
288 unsigned off; /* off within the current block */
289 int chunk; /* number of bytes to read or write */
290 unsigned left; /* max number of bytes wanted after position */
291 cp_grant_id_t gid; /* grant */
292 unsigned buf_off; /* offset in grant */
293 int block_size; /* block size of FS operating on */
294 int *completed; /* number of bytes copied */
297 register struct buf *bp;
298 register int r = OK;
299 block_t b;
300 int file_unit, rel_block, offset;
302 *completed = 0;
304 if ((ex64lo(position) <= dir->d_file_size) &&
305 (ex64lo(position) > dir->data_length_l)) {
306 while ((dir->d_next != NULL) && (ex64lo(position) > dir->data_length_l)) {
307 position = sub64ul(position, dir->data_length_l);
308 dir = dir->d_next;
312 if (dir->inter_gap_size != 0) {
313 rel_block = div64u(position, block_size);
314 file_unit = rel_block / dir->data_length_l;
315 offset = rel_block % dir->file_unit_size;
316 b = dir->loc_extent_l + (dir->file_unit_size +
317 dir->inter_gap_size) * file_unit + offset;
318 } else {
319 b = dir->loc_extent_l + div64u(position, block_size); /* Physical position
320 * to read. */
323 bp = get_block(b);
325 /* In all cases, bp now points to a valid buffer. */
326 if (bp == NULL) {
327 panic("bp not valid in rw_chunk; this can't happen");
330 r = sys_safecopyto(VFS_PROC_NR, gid, buf_off,
331 (vir_bytes) (b_data(bp)+off), (phys_bytes) chunk);
333 put_block(bp);
335 return(r);