wasmer_wasix/syscalls/wasi/
fd_readdir.rs1use super::*;
2use crate::syscalls::*;
3
4#[instrument(level = "trace", skip_all, fields(%fd), ret)]
20pub fn fd_readdir<M: MemorySize>(
21 mut ctx: FunctionEnvMut<'_, WasiEnv>,
22 fd: WasiFd,
23 buf: WasmPtr<u8, M>,
24 buf_len: M::Offset,
25 cookie: Dircookie,
26 bufused: WasmPtr<M::Offset, M>,
27) -> Result<Errno, WasiError> {
28 WasiEnv::do_pending_operations(&mut ctx)?;
29
30 let env = ctx.data();
31 let (memory, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
32 let buf_arr = wasi_try_mem_ok!(buf.slice(&memory, buf_len));
36 let bufused_ref = bufused.deref(&memory);
37 let working_dir = wasi_try_ok!(state.fs.get_fd(fd));
38 let mut buf_idx = 0usize;
39
40 let entries: Vec<(String, Filetype, u64)> = {
41 let guard = working_dir.inode.read();
42 match guard.deref() {
43 Kind::Dir { path, entries, .. } => {
44 trace!("reading dir {:?}", path);
45 let fs_info = wasi_try_ok!(
50 wasi_try_ok!(state.fs_read_dir(path))
51 .collect::<Result<Vec<_>, _>>()
52 .map_err(fs_error_into_wasi_err)
53 );
54 let mut entry_vec = wasi_try_ok!(
55 fs_info
56 .into_iter()
57 .map(|entry| {
58 let filename = entry.file_name().to_string_lossy().to_string();
59 trace!("getting file: {:?}", filename);
60 let filetype = virtual_file_type_to_wasi_file_type(
61 entry.file_type().map_err(fs_error_into_wasi_err)?,
62 );
63 Ok((
64 filename, filetype, 0, ))
66 })
67 .collect::<Result<Vec<(String, Filetype, u64)>, _>>()
68 );
69 let entry_names: std::collections::HashSet<_> =
70 entry_vec.iter().map(|(name, _, _)| name.clone()).collect();
71 entry_vec.extend(
72 entries
73 .iter()
74 .filter(|(name, _)| !entry_names.contains(*name))
75 .map(|(name, inode)| {
76 let stat = inode.stat.read().unwrap();
77 (name.clone(), stat.st_filetype, stat.st_ino)
78 }),
79 );
80 entry_vec.push((".".to_string(), Filetype::Directory, 0));
83 entry_vec.push(("..".to_string(), Filetype::Directory, 0));
84 entry_vec.sort_by(|a, b| a.0.cmp(&b.0));
85 entry_vec
86 }
87 Kind::Root { entries } => {
88 trace!("reading root");
89 let sorted_entries = {
90 let mut entry_vec: Vec<(String, InodeGuard)> = entries
91 .iter()
92 .map(|(a, b)| (a.clone(), b.clone()))
93 .collect();
94 entry_vec.sort_by(|a, b| a.0.cmp(&b.0));
95 entry_vec
96 };
97 sorted_entries
98 .into_iter()
99 .map(|(name, inode)| {
100 let stat = inode.stat.read().unwrap();
101 (
102 format!("/{}", inode.name.read().unwrap().as_ref()),
103 stat.st_filetype,
104 stat.st_ino,
105 )
106 })
107 .collect()
108 }
109 Kind::File { .. }
110 | Kind::Symlink { .. }
111 | Kind::Buffer { .. }
112 | Kind::Socket { .. }
113 | Kind::PipeRx { .. }
114 | Kind::PipeTx { .. }
115 | Kind::DuplexPipe { .. }
116 | Kind::EventNotifications { .. }
117 | Kind::Epoll { .. } => return Ok(Errno::Notdir),
118 }
119 };
120
121 for (cur_cookie, (entry_path_str, wasi_file_type, ino)) in
122 (cookie + 1..).zip(entries.iter().skip(cookie as usize))
123 {
124 let namlen = entry_path_str.len();
125 trace!("returning dirent for {}", entry_path_str);
126 let dirent = Dirent {
127 d_next: cur_cookie,
128 d_ino: *ino,
129 d_namlen: namlen as u32,
130 d_type: *wasi_file_type,
131 };
132 let dirent_bytes = dirent_to_le_bytes(&dirent);
133 let buf_len: u64 = buf_len.into();
134 let upper_limit = std::cmp::min(
135 (buf_len - buf_idx as u64) as usize,
136 std::mem::size_of::<Dirent>(),
137 );
138 for (i, b) in dirent_bytes.iter().enumerate().take(upper_limit) {
139 wasi_try_mem_ok!(buf_arr.index((i + buf_idx) as u64).write(*b));
140 }
141 buf_idx += upper_limit;
142 if upper_limit != std::mem::size_of::<Dirent>() {
143 break;
144 }
145 let upper_limit = std::cmp::min((buf_len - buf_idx as u64) as usize, namlen);
146 for (i, b) in entry_path_str.bytes().take(upper_limit).enumerate() {
147 wasi_try_mem_ok!(buf_arr.index((i + buf_idx) as u64).write(b));
148 }
149 buf_idx += upper_limit;
150 if upper_limit != namlen {
151 break;
152 }
153 }
154
155 let buf_idx: M::Offset = wasi_try_ok!(buf_idx.try_into().map_err(|_| Errno::Overflow));
156 wasi_try_mem_ok!(bufused_ref.write(buf_idx));
157 Ok(Errno::Success)
158}