wasmer_wasix/syscalls/wasi/
fd_renumber.rs1use super::*;
2use crate::syscalls::*;
3use std::{future::Future, pin::Pin, sync::Arc, task::Context, task::Poll};
4use virtual_fs::VirtualFile;
5
6struct FlushPoller {
7 file: Arc<std::sync::RwLock<Box<dyn VirtualFile + Send + Sync>>>,
8}
9
10impl Future for FlushPoller {
11 type Output = Result<(), Errno>;
12
13 fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
14 let mut file = self.file.write().unwrap();
15 Pin::new(file.as_mut())
16 .poll_flush(cx)
17 .map_err(|_| Errno::Io)
18 }
19}
20
21#[instrument(level = "trace", skip_all, fields(%from, %to), ret)]
29pub fn fd_renumber(
30 mut ctx: FunctionEnvMut<'_, WasiEnv>,
31 from: WasiFd,
32 to: WasiFd,
33) -> Result<Errno, WasiError> {
34 WasiEnv::do_pending_operations(&mut ctx)?;
35
36 let ret = fd_renumber_internal(&mut ctx, from, to)?;
37 let env = ctx.data();
38
39 if ret == Errno::Success {
40 #[cfg(feature = "journal")]
41 if env.enable_journal {
42 JournalEffector::save_fd_renumber(&mut ctx, from, to).map_err(|err| {
43 tracing::error!("failed to save file descriptor renumber event - {}", err);
44 WasiError::Exit(ExitCode::from(Errno::Fault))
45 })?;
46 }
47 }
48
49 Ok(ret)
50}
51
52pub(crate) fn fd_renumber_internal(
53 ctx: &mut FunctionEnvMut<'_, WasiEnv>,
54 from: WasiFd,
55 to: WasiFd,
56) -> Result<Errno, WasiError> {
57 if from == to {
58 return Ok(Errno::Success);
59 }
60 let env = ctx.data();
61 let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
62
63 let old_fd;
67 {
68 let mut fd_map = state.fs.fd_map.write().unwrap();
69
70 let fd_entry = wasi_try_ok!(fd_map.get(from).ok_or(Errno::Badf));
72
73 if let Some(target_fd) = fd_map.get(to)
75 && !target_fd.is_stdio
76 && target_fd.inode.is_preopened
77 {
78 warn!("Refusing fd_renumber({from}, {to}) because FD {to} is pre-opened");
79 return Ok(Errno::Notsup);
80 }
81
82 let new_fd_entry = Fd {
83 inner: FdInner {
84 offset: fd_entry.inner.offset.clone(),
85 rights: fd_entry.inner.rights_inheriting,
86 fd_flags: {
87 let mut f = fd_entry.inner.fd_flags;
88 f.set(Fdflagsext::CLOEXEC, false);
89 f
90 },
91 ..fd_entry.inner
92 },
93 inode: fd_entry.inode.clone(),
94 ..*fd_entry
95 };
96
97 old_fd = fd_map.remove(to);
100
101 if !fd_map.insert(true, to, new_fd_entry) {
102 panic!("Internal error: expected FD {to} to be free after closing in fd_renumber");
103 }
104 }
105 let flush_target = old_fd.as_ref().and_then(|fd_entry| {
109 let guard = fd_entry.inode.read();
110 match guard.deref() {
111 Kind::File {
112 handle: Some(file), ..
113 } => Some(file.clone()),
114 _ => None,
115 }
116 });
117 drop(old_fd);
118
119 if let Some(file) = flush_target {
120 let _ = __asyncify_light(env, None, FlushPoller { file })?;
121 }
122
123 Ok(Errno::Success)
124}