TODO: I'm not confident this works for multiple consecutive readdir calls to the same dir Correct behavior: truncate final entry
(
ctx: &mut VmCtx,
v_fd: SboxFd,
buf: SboxFd,
buf_len: usize,
cookie: u64,
)
| 1188 | // TODO: I'm not confident this works for multiple consecutive readdir calls to the same dir |
| 1189 | // Correct behavior: truncate final entry |
| 1190 | pub fn wasi_fd_readdir( |
| 1191 | ctx: &mut VmCtx, |
| 1192 | v_fd: SboxFd, |
| 1193 | buf: SboxFd, |
| 1194 | buf_len: usize, |
| 1195 | cookie: u64, |
| 1196 | ) -> RuntimeResult<u32> { |
| 1197 | let fd = ctx.fdmap.fd_to_native(v_fd)?; |
| 1198 | |
| 1199 | let mut host_buf: Vec<u8> = Vec::new(); |
| 1200 | host_buf.reserve_exact(buf_len as usize); |
| 1201 | |
| 1202 | let res = trace_getdents64(ctx, fd, &mut host_buf, buf_len)?; |
| 1203 | |
| 1204 | // the number of entries we have read so far. If less than cookie, don't output the directory |
| 1205 | let mut entry_idx = 0; |
| 1206 | let mut in_idx = 0; |
| 1207 | let mut out_idx = 0; |
| 1208 | |
| 1209 | let mut out_buf: Vec<u8> = Vec::new(); |
| 1210 | |
| 1211 | while in_idx < host_buf.len() && out_idx < buf_len { |
| 1212 | body_invariant!(ctx_safe(ctx)); |
| 1213 | body_invariant!(trace_safe(trace, ctx)); |
| 1214 | body_invariant!(in_idx < host_buf.len()); |
| 1215 | |
| 1216 | let dirent = Dirent::parse(&host_buf, in_idx)?; |
| 1217 | |
| 1218 | // if we haven't hit the cookie entry, skip |
| 1219 | if entry_idx < cookie { |
| 1220 | in_idx += dirent.reclen as usize; |
| 1221 | entry_idx += 1; |
| 1222 | continue; |
| 1223 | } |
| 1224 | |
| 1225 | let out_next = in_idx + 24 + dirent.out_namlen; |
| 1226 | |
| 1227 | // If we would overflow - don't :) |
| 1228 | if out_next > buf_len { |
| 1229 | break; |
| 1230 | } |
| 1231 | |
| 1232 | // Copy in next offset verbatim |
| 1233 | let out_next_bytes: [u8; 8] = out_next.to_le_bytes(); |
| 1234 | out_buf.extend_from_slice(&out_next_bytes); |
| 1235 | |
| 1236 | // Copy in Inode verbatim |
| 1237 | let d_ino_bytes: [u8; 8] = dirent.ino.to_le_bytes(); |
| 1238 | out_buf.extend_from_slice(&d_ino_bytes); |
| 1239 | |
| 1240 | // Copy namlen |
| 1241 | let out_namlen_bytes: [u8; 4] = (dirent.out_namlen as u32).to_le_bytes(); |
| 1242 | out_buf.extend_from_slice(&out_namlen_bytes); |
| 1243 | |
| 1244 | // Copy type |
| 1245 | let d_type = Filetype::from(dirent.typ as libc::mode_t); |
| 1246 | let out_type_bytes: [u8; 4] = (d_type.to_wasi() as u32).to_le_bytes(); |
| 1247 | out_buf.extend_from_slice(&out_type_bytes); |
no test coverage detected