wasmer_wasix/syscalls/wasi/
path_create_directory.rs1use std::{
2 path::{Component, PathBuf},
3 str::FromStr,
4};
5
6use super::*;
7use crate::syscalls::*;
8
9#[instrument(level = "trace", skip_all, fields(%fd, path = field::Empty), ret)]
23pub fn path_create_directory<M: MemorySize>(
24 mut ctx: FunctionEnvMut<'_, WasiEnv>,
25 fd: WasiFd,
26 path: WasmPtr<u8, M>,
27 path_len: M::Offset,
28) -> Result<Errno, WasiError> {
29 WasiEnv::do_pending_operations(&mut ctx)?;
30
31 let env = ctx.data();
32 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
33
34 let mut path_string = unsafe { get_input_str_ok!(&memory, path, path_len) };
35 Span::current().record("path", path_string.as_str());
36
37 wasi_try_ok!(path_create_directory_internal(&mut ctx, fd, &path_string));
38 let env = ctx.data();
39
40 #[cfg(feature = "journal")]
41 if env.enable_journal {
42 JournalEffector::save_path_create_directory(&mut ctx, fd, path_string).map_err(|err| {
43 tracing::error!("failed to save create directory event - {}", err);
44 WasiError::Exit(ExitCode::from(Errno::Fault))
45 })?;
46 }
47
48 Ok(Errno::Success)
49}
50
51pub(crate) fn path_create_directory_internal(
52 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
53 fd: WasiFd,
54 path: &str,
55) -> Result<(), Errno> {
56 let env = ctx.data();
57 let (memory, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
58 let working_dir = state.fs.get_fd(fd)?;
59
60 if !working_dir
61 .inner
62 .rights
63 .contains(Rights::PATH_CREATE_DIRECTORY)
64 {
65 trace!("working directory (fd={fd}) has no rights to create a directory");
66 return Err(Errno::Access);
67 }
68
69 let (parent_inode, dir_name) =
70 state
71 .fs
72 .get_parent_inode_at_path(inodes, fd, Path::new(path), true)?;
73
74 let mut guard = parent_inode.write();
75 match guard.deref_mut() {
76 Kind::Dir { entries, path, .. } => {
77 if let Some(child) = entries.get(&dir_name) {
78 return Err(Errno::Exist);
79 }
80
81 let mut new_dir_path = path.clone();
82 new_dir_path.push(&dir_name);
83
84 drop(guard);
85
86 if path_filestat_get_internal(
89 &memory,
90 state,
91 inodes,
92 fd,
93 0,
94 &new_dir_path.to_string_lossy(),
95 )
96 .is_ok()
97 {
98 return Err(Errno::Exist);
99 }
100
101 state.fs_create_dir(&new_dir_path)?;
102
103 let kind = Kind::Dir {
104 parent: parent_inode.downgrade(),
105 path: new_dir_path,
106 entries: Default::default(),
107 };
108 let new_inode = state
109 .fs
110 .create_inode(inodes, kind, false, dir_name.clone())?;
111
112 {
114 let mut guard = parent_inode.write();
115 let Kind::Dir { entries, .. } = guard.deref_mut() else {
116 unreachable!();
117 };
118
119 entries.insert(dir_name, new_inode.clone());
120 }
121 }
122 Kind::Root { .. } => {
123 trace!("the root node can only contain pre-opened directories");
124 return Err(Errno::Access);
125 }
126 _ => {
127 trace!("path is not a directory");
128 return Err(Errno::Notdir);
129 }
130 }
131
132 Ok(())
133}