3 #include <minix/vfsif.h>
7 PRIVATE
char getdents_buf
[GETDENTS_BUFSIZ
];
10 /*===========================================================================*
12 *===========================================================================*/
13 PUBLIC
int fs_read(void) {
14 int r
, chunk
, block_size
;
17 off_t position
, f_size
, bytes_left
;
18 unsigned int off
, cum_io
;
20 struct dir_record
*dir
;
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 */
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
);
73 /*===========================================================================*
75 *===========================================================================*/
76 PUBLIC
int fs_bread(void)
78 int r
, rw_flag
, chunk
, block_size
;
82 unsigned int off
, cum_io
;
84 int completed
, r2
= OK
;
85 struct dir_record
*dir
;
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 */
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
;
132 /*===========================================================================*
134 *===========================================================================*/
135 PUBLIC
int fs_getdents(void) {
136 struct dir_record
*dir
;
139 size_t size_to_read
, block_size
;
140 off_t pos
, block_pos
, block
, cur_pos
, tmpbuf_offset
, userbuf_off
;
142 struct dir_record
*dir_tmp
;
144 int r
,done
,o
,len
,reclen
;
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 */
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 */
171 while (cur_pos
<dir
->d_file_size
) {
172 bp
= get_block(block
); /* Get physical block */
175 release_dir_record(dir
);
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
;
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
,"..");
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
);
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
;
220 /* Compute record length */
221 reclen
= offsetof(struct dirent
, d_name
) + len
+ 1;
222 o
= (reclen
% sizeof(long));
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
);
234 "fs_getdents: sys_safecopyto failed\n",r
);
236 userbuf_off
+= tmpbuf_offset
;
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
);
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 */
281 /*===========================================================================*
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
;
301 int file_unit
, rel_block
, offset
;
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
);
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
;
320 b
= dir
->loc_extent_l
+ div64u(position
, block_size
); /* Physical position
326 /* In all cases, bp now points to a valid buffer. */
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
);