3 #include <minix/vfsif.h>
10 static char getdents_buf
[GETDENTS_BUFSIZ
];
13 /*===========================================================================*
15 *===========================================================================*/
17 int r
, chunk
, block_size
;
20 off_t position
, f_size
, bytes_left
;
21 unsigned int off
, cum_io
;
23 struct dir_record
*dir
;
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 */
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
);
76 /*===========================================================================*
78 *===========================================================================*/
81 int r
, rw_flag
, chunk
, block_size
;
85 unsigned int off
, cum_io
;
87 struct dir_record
*dir
;
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 */
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
;
134 /*===========================================================================*
136 *===========================================================================*/
137 int fs_getdents(void) {
138 struct dir_record
*dir
;
142 off_t pos
, block_pos
, block
, cur_pos
, tmpbuf_offset
, userbuf_off
;
144 struct dir_record
*dir_tmp
;
146 int r
,done
,o
,len
,reclen
;
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 */
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 */
172 while (cur_pos
<dir
->d_file_size
) {
173 bp
= get_block(block
); /* Get physical block */
176 release_dir_record(dir
);
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
;
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);
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
);
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
;
223 /* Compute record length */
224 reclen
= offsetof(struct dirent
, d_name
) + len
+ 1;
225 o
= (reclen
% sizeof(long));
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
);
236 panic("fs_getdents: sys_safecopyto failed: %d", r
);
237 userbuf_off
+= tmpbuf_offset
;
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
);
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 */
282 /*===========================================================================*
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
;
300 int file_unit
, rel_block
, offset
;
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
);
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
;
319 b
= dir
->loc_extent_l
+ div64u(position
, block_size
); /* Physical position
325 /* In all cases, bp now points to a valid buffer. */
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
);