wasmer_wasix/syscalls/wasi/
path_unlink_file.rs1use super::*;
2use crate::syscalls::*;
3
4#[instrument(level = "trace", skip_all, fields(%fd, path = field::Empty), ret)]
14pub fn path_unlink_file<M: MemorySize>(
15 mut ctx: FunctionEnvMut<'_, WasiEnv>,
16 fd: WasiFd,
17 path: WasmPtr<u8, M>,
18 path_len: M::Offset,
19) -> Result<Errno, WasiError> {
20 WasiEnv::do_pending_operations(&mut ctx)?;
21
22 let env = ctx.data();
23 let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
24
25 let base_dir = wasi_try_ok!(state.fs.get_fd(fd));
26 if !base_dir.inner.rights.contains(Rights::PATH_UNLINK_FILE) {
27 return Ok(Errno::Access);
28 }
29 let path_str = unsafe { get_input_str_ok!(&memory, path, path_len) };
30 Span::current().record("path", path_str.as_str());
31
32 let ret = path_unlink_file_internal(&mut ctx, fd, &path_str)?;
33 let env = ctx.data();
34
35 if ret == Errno::Success {
36 #[cfg(feature = "journal")]
37 if env.enable_journal {
38 wasi_try_ok!(
39 JournalEffector::save_path_unlink(&mut ctx, fd, path_str).map_err(|err| {
40 tracing::error!("failed to save unlink event - {}", err);
41 Errno::Fault
42 })
43 )
44 }
45 }
46
47 Ok(ret)
48}
49
50pub(crate) fn path_unlink_file_internal(
51 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
52 fd: WasiFd,
53 path: &str,
54) -> Result<Errno, WasiError> {
55 let env = ctx.data();
56 let (memory, mut state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
57
58 let inode = wasi_try_ok!(state.fs.get_inode_at_path(inodes, fd, path, false));
59 let (parent_inode, childs_name) = wasi_try_ok!(state.fs.get_parent_inode_at_path(
60 inodes,
61 fd,
62 std::path::Path::new(path),
63 false
64 ));
65
66 let removed_inode = {
67 let mut guard = parent_inode.write();
68 match guard.deref_mut() {
69 Kind::Dir { entries, .. } => {
70 let removed_inode = wasi_try_ok!(entries.remove(&childs_name).ok_or(Errno::Inval));
71 assert!(inode.ino() == removed_inode.ino());
73 debug_assert!(inode.stat.read().unwrap().st_nlink > 0);
74 removed_inode
75 }
76 Kind::Root { .. } => return Ok(Errno::Access),
77 _ => unreachable!(
78 "Internal logic error in wasi::path_unlink_file, parent is not a directory"
79 ),
80 }
81 };
82
83 let st_nlink = {
84 let mut guard = removed_inode.stat.write().unwrap();
85 guard.st_nlink -= 1;
86 guard.st_nlink
87 };
88 if st_nlink == 0 {
89 {
90 let mut guard = removed_inode.read();
91 match guard.deref() {
92 Kind::File { handle, path, .. } => {
93 if let Some(h) = handle {
94 let mut h = h.write().unwrap();
95 wasi_try_ok!(h.unlink().map_err(fs_error_into_wasi_err));
96 } else {
97 let path = path.clone();
101 drop(guard);
102 wasi_try_ok!(state.fs_remove_file(path));
103 }
104 }
105 Kind::Dir { .. } | Kind::Root { .. } => return Ok(Errno::Isdir),
106 Kind::Symlink { .. } => {
107 }
109 _ => unimplemented!("wasi::path_unlink_file for Buffer"),
110 }
111 }
112 }
113
114 Ok(Errno::Success)
115}