3 #include <minix/vfsif.h>
4 #include <minix/minlib.h>
9 static char getdents_buf
[GETDENTS_BUFSIZ
];
12 /*===========================================================================*
14 *===========================================================================*/
16 int r
, chunk
, block_size
;
19 off_t position
, f_size
, bytes_left
;
20 unsigned int off
, cum_io
;
22 struct dir_record
*dir
;
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");
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 */
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
,
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
);
83 /*===========================================================================*
85 *===========================================================================*/
88 int r
, rw_flag
, chunk
, block_size
;
92 unsigned int off
, cum_io
;
94 struct dir_record
*dir
;
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 */
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
;
140 /*===========================================================================*
142 *===========================================================================*/
143 int fs_getdents(void)
145 struct dir_record
*dir
;
149 off_t pos
, block_pos
, block
, cur_pos
, tmpbuf_offset
, userbuf_off
;
151 struct dir_record
*dir_tmp
;
153 int r
,done
,o
,len
,reclen
;
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 */
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 */
179 while (cur_pos
<dir
->d_file_size
) {
180 bp
= get_block(block
); /* Get physical block */
183 release_dir_record(dir
);
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
;
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);
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
);
223 strlcpy(name_old
, name
, NAME_MAX
+ 1);
225 /* Compute the length of the name */
226 cp
= memchr(name
, '\0', NAME_MAX
);
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
);
242 panic("fs_getdents: sys_safecopyto failed: %d", r
);
243 userbuf_off
+= tmpbuf_offset
;
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
);
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 */
289 /*===========================================================================*
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
;
308 int file_unit
, rel_block
, offset
;
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
;
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
;
327 b
= dir
->loc_extent_l
+ (unsigned long)(position
/ block_size
);
328 /* Physical position to read. */
333 /* In all cases, bp now points to a valid buffer. */
335 panic("bp not valid in rw_chunk; this can't happen");
339 r
= sys_safecopyto(VFS_PROC_NR
, gid
, buf_off
,
340 (vir_bytes
) (b_data(bp
)+off
), (phys_bytes
) chunk
);