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(&mut ctx, fd, &path_str));
25 let env = ctx.data();
26
27 #[cfg(feature = "journal")]
28 if env.enable_journal {
29 wasi_try_ok!(
30 JournalEffector::save_path_remove_directory(&mut ctx, fd, path_str).map_err(|err| {
31 tracing::error!("failed to save remove directory event - {}", err);
32 Errno::Fault
33 })
34 )
35 }
36
37 Ok(Errno::Success)
38}
39
40pub(crate) fn path_remove_directory_internal(
41 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
42 fd: WasiFd,
43 path: &str,
44) -> Result<(), Errno> {
45 let env = ctx.data();
46 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
47 let working_dir = state.fs.get_fd(fd)?;
48
49 let (parent_inode, dir_name) =
50 state
51 .fs
52 .get_parent_inode_at_path(inodes, fd, Path::new(path), true)?;
53
54 let mut guard = parent_inode.write();
55 match guard.deref_mut() {
56 Kind::Dir {
57 entries: parent_entries,
58 ..
59 } => {
60 let Some(child_inode) = parent_entries.get(&dir_name) else {
61 return Err(Errno::Noent);
62 };
63
64 {
65 let Kind::Dir {
66 entries: ref child_entries,
67 path: ref child_path,
68 ..
69 } = *child_inode.read()
70 else {
71 return Err(Errno::Notdir);
72 };
73
74 if !child_entries.is_empty() {
75 return Err(Errno::Notempty);
76 }
77
78 if let Err(e) = state.fs_remove_dir(child_path) {
79 tracing::warn!(path = ?child_path, error = ?e, "failed to remove directory");
80 return Err(e);
81 }
82 }
83
84 parent_entries.remove(&dir_name).expect(
85 "Entry should exist since we checked before and have an exclusive write lock",
86 );
87
88 Ok(())
89 }
90 Kind::Root { .. } => {
91 trace!("directories directly in the root node can not be removed");
92 Err(Errno::Access)
93 }
94 _ => {
95 trace!("path is not a directory");
96 Err(Errno::Notdir)
97 }
98 }
99}