wasmer_wasix/syscalls/wasi/
path_remove_directory.rs1use std::fs;
2
3use super::*;
4use crate::syscalls::*;
5
6#[instrument(level = "trace", skip_all, fields(%fd, path = field::Empty), ret)]
8pub fn path_remove_directory<M: MemorySize>(
9 mut ctx: FunctionEnvMut<'_, WasiEnv>,
10 fd: WasiFd,
11 path: WasmPtr<u8, M>,
12 path_len: M::Offset,
13) -> Result<Errno, WasiError> {
14 WasiEnv::do_pending_operations(&mut ctx)?;
15
16 let env = ctx.data();
18 let (memory, mut state, _inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
19
20 let base_dir = wasi_try_ok!(state.fs.get_fd(fd));
21 let path_str = unsafe { get_input_str_ok!(&memory, path, path_len) };
22 Span::current().record("path", path_str.as_str());
23
24 wasi_try_ok!(path_remove_directory_internal(
25 &mut ctx, fd, base_dir, &path_str
26 ));
27 let env = ctx.data();
28
29 #[cfg(feature = "journal")]
30 if env.enable_journal {
31 wasi_try_ok!(
32 JournalEffector::save_path_remove_directory(&mut ctx, fd, path_str).map_err(|err| {
33 tracing::error!("failed to save remove directory event - {}", err);
34 Errno::Fault
35 })
36 )
37 }
38
39 Ok(Errno::Success)
40}
41
42pub(crate) fn path_remove_directory_internal(
43 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
44 fd: WasiFd,
45 _base_dir: Fd,
46 path: &str,
47) -> Result<(), Errno> {
48 let env = ctx.data();
49 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
50
51 let (parent_inode, dir_name) =
52 state
53 .fs
54 .get_parent_inode_at_path(inodes, fd, Path::new(path), true)?;
55
56 let mut guard = parent_inode.write();
57 match guard.deref_mut() {
58 Kind::Dir {
59 entries: parent_entries,
60 ..
61 } => {
62 let Some(child_inode) = parent_entries.get(&dir_name) else {
63 return Err(Errno::Noent);
64 };
65
66 {
67 let Kind::Dir {
68 entries: ref child_entries,
69 path: ref child_path,
70 ..
71 } = *child_inode.read()
72 else {
73 return Err(Errno::Notdir);
74 };
75
76 if !child_entries.is_empty() {
77 return Err(Errno::Notempty);
78 }
79
80 if let Err(e) = state.fs_remove_dir(child_path) {
81 tracing::warn!(path = ?child_path, error = ?e, "failed to remove directory");
82 return Err(e);
83 }
84 }
85
86 parent_entries.remove(&dir_name).expect(
87 "Entry should exist since we checked before and have an exclusive write lock",
88 );
89
90 Ok(())
91 }
92 Kind::Root { .. } => {
93 trace!("directories directly in the root node can not be removed");
94 Err(Errno::Access)
95 }
96 _ => {
97 trace!("path is not a directory");
98 Err(Errno::Notdir)
99 }
100 }
101}