1 /* VTreeFS - read.c - by Alen Stojanov and David van Moolenbroek */
6 #define GETDENTS_BUFSIZ 4096
7 #define DWORD_ALIGN(len) (((len) + sizeof(long) - 1) & ~(sizeof(long) - 1))
9 /*===========================================================================*
11 *===========================================================================*/
23 if (fs_m_in
.REQ_SEEK_POS_HI
!= 0)
26 /* Try to get inode by to its inode number. */
27 if ((node
= find_inode(fs_m_in
.REQ_INODE_NR
)) == NULL
)
30 /* Check whether the node is a regular file. */
31 if (!S_ISREG(node
->i_stat
.mode
))
34 /* Get the values from the request message. */
35 gid
= fs_m_in
.REQ_GRANT
;
36 pos
= fs_m_in
.REQ_SEEK_POS_LO
;
38 /* Call the read hook, if any. */
39 if (!is_inode_deleted(node
) && vtreefs_hooks
->read_hook
!= NULL
) {
40 len
= fs_m_in
.REQ_NBYTES
;
42 /* On success, the read hook provides us with a pointer to the
43 * resulting data. This avoids copying overhead.
45 r
= vtreefs_hooks
->read_hook(node
, pos
, &ptr
, &len
,
46 get_inode_cbdata(node
));
48 assert(len
<= fs_m_in
.REQ_NBYTES
);
50 /* Copy the resulting data to user space. */
51 if (r
== OK
&& len
> 0) {
52 r
= sys_safecopyto(fs_m_in
.m_source
, fs_m_in
.REQ_GRANT
,
53 0, (vir_bytes
) ptr
, len
);
56 /* Feign an empty file. */
62 fs_m_out
.RES_SEEK_POS_HI
= 0;
63 fs_m_out
.RES_SEEK_POS_LO
= pos
+ len
;
64 fs_m_out
.RES_NBYTES
= len
;
70 /*===========================================================================*
72 *===========================================================================*/
75 /* Retrieve directory entries.
77 struct inode
*node
, *child
= NULL
;
80 size_t len
, off
, user_off
, user_left
;
82 int r
, skip
, get_next
, indexed
;
83 static char buf
[GETDENTS_BUFSIZ
];
85 if (fs_m_in
.REQ_SEEK_POS_HI
!= 0)
88 if ((node
= find_inode(fs_m_in
.REQ_INODE_NR
)) == NULL
)
93 user_left
= fs_m_in
.REQ_MEM_SIZE
;
94 indexed
= node
->i_indexed
;
98 /* Call the getdents hook, if any, to "refresh" the directory. */
99 if (!is_inode_deleted(node
) && vtreefs_hooks
->getdents_hook
!= NULL
) {
100 r
= vtreefs_hooks
->getdents_hook(node
, get_inode_cbdata(node
));
101 if (r
!= OK
) return r
;
104 for (pos
= fs_m_in
.REQ_SEEK_POS_LO
; ; pos
++) {
105 /* Determine which inode and name to use for this entry. */
112 /* The ".." entry. */
113 child
= get_parent_inode(node
);
118 else if (pos
- 2 < indexed
) {
119 /* All indexed entries. */
120 child
= get_inode_by_index(node
, pos
- 2);
122 /* If there is no inode with this particular index,
123 * continue with the next index number.
125 if (child
== NULL
) continue;
127 name
= child
->i_name
;
130 /* All non-indexed entries. */
132 /* If this is the first loop iteration, first get to
133 * the non-indexed child identified by the current
136 if (get_next
== FALSE
) {
137 skip
= pos
- indexed
- 2;
138 child
= get_first_inode(node
);
140 /* Skip indexed children. */
141 while (child
!= NULL
&&
142 child
->i_index
!= NO_INDEX
)
143 child
= get_next_inode(child
);
145 /* Skip to the right position. */
146 while (child
!= NULL
&& skip
-- > 0)
147 child
= get_next_inode(child
);
152 child
= get_next_inode(child
);
155 /* No more children? Then stop. */
159 assert(!is_inode_deleted(child
));
161 name
= child
->i_name
;
164 len
= DWORD_ALIGN(sizeof(struct dirent
) + strlen(name
));
166 /* Is the user buffer too small to store another record? */
167 if (user_off
+ off
+ len
> user_left
) {
168 /* Is the user buffer too small for even a single
171 if (user_off
== 0 && off
== 0)
177 /* If our own buffer cannot contain the new record, copy out
180 if (off
+ len
> sizeof(buf
)) {
181 r
= sys_safecopyto(fs_m_in
.m_source
, fs_m_in
.REQ_GRANT
,
182 user_off
, (vir_bytes
) buf
, off
);
183 if (r
!= OK
) return r
;
190 /* Fill in the actual directory entry. */
191 dent
= (struct dirent
*) &buf
[off
];
192 dent
->d_ino
= get_inode_number(child
);
194 dent
->d_reclen
= len
;
195 strcpy(dent
->d_name
, name
);
200 /* If there is anything left in our own buffer, copy that out now. */
202 r
= sys_safecopyto(fs_m_in
.m_source
, fs_m_in
.REQ_GRANT
,
203 user_off
, (vir_bytes
) buf
, off
);
210 fs_m_out
.RES_SEEK_POS_HI
= 0;
211 fs_m_out
.RES_SEEK_POS_LO
= pos
;
212 fs_m_out
.RES_NBYTES
= user_off
;