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 let host_adjusted_path = {
66 let guard = parent_inode.read();
67 match guard.deref() {
68 Kind::Dir { path, .. } => path.join(&childs_name),
69 Kind::Root { .. } => return Ok(Errno::Access),
70 _ => unreachable!(
71 "Internal logic error in wasi::path_unlink_file, parent is not a directory"
72 ),
73 }
74 };
75
76 let removed_inode = {
77 let mut guard = parent_inode.write();
78 match guard.deref_mut() {
79 Kind::Dir { entries, .. } => {
80 let removed_inode = wasi_try_ok!(entries.remove(&childs_name).ok_or(Errno::Inval));
81 assert!(inode.ino() == removed_inode.ino());
83 debug_assert!(inode.stat.read().unwrap().st_nlink > 0);
84 removed_inode
85 }
86 Kind::Root { .. } => return Ok(Errno::Access),
87 _ => unreachable!(
88 "Internal logic error in wasi::path_unlink_file, parent is not a directory"
89 ),
90 }
91 };
92
93 let st_nlink = {
94 let mut guard = removed_inode.stat.write().unwrap();
95 guard.st_nlink -= 1;
96 guard.st_nlink
97 };
98 if st_nlink == 0 {
99 {
100 let mut guard = removed_inode.read();
101 match guard.deref() {
102 Kind::File { handle, path, .. } => {
103 if let Some(h) = handle {
104 let mut h = h.write().unwrap();
105 wasi_try_ok!(h.unlink().map_err(fs_error_into_wasi_err));
106 } else {
107 let path = path.clone();
111 drop(guard);
112 wasi_try_ok!(state.fs_remove_file(path));
113 }
114 }
115 Kind::Dir { .. } | Kind::Root { .. } => return Ok(Errno::Isdir),
116 Kind::Symlink { .. } => {
117 match state.fs_remove_file(host_adjusted_path.as_path()) {
118 Ok(()) => {}
119 Err(Errno::Noent)
120 if state
121 .fs
122 .ephemeral_symlink_at(host_adjusted_path.as_path())
123 .is_some() => {}
124 Err(err) => return Ok(err),
125 }
126 state
127 .fs
128 .unregister_ephemeral_symlink(host_adjusted_path.as_path());
129 }
130 _ => unimplemented!("wasi::path_unlink_file for Buffer"),
131 }
132 }
133 }
134
135 Ok(Errno::Success)
136}