wasmer_wasix/syscalls/wasi/
fd_close.rs

1use super::*;
2use crate::fs::FlushPoller;
3use crate::syscalls::*;
4
5/// Best-effort flush of a file handle captured before fd removal.
6pub(crate) fn flush_captured_handle(
7    env: &WasiEnv,
8    flush_target: Option<
9        std::sync::Arc<std::sync::RwLock<Box<dyn virtual_fs::VirtualFile + Send + Sync>>>,
10    >,
11) -> Result<Errno, WasiError> {
12    let Some(file) = flush_target else {
13        return Ok(Errno::Success);
14    };
15
16    match __asyncify_light(env, None, FlushPoller { file })? {
17        Ok(_)
18        | Err(Errno::Isdir)
19        | Err(Errno::Io)
20        | Err(Errno::Access)
21        // EINVAL is returned by e.g. pipe-backed stdio and is safe to ignore.
22        | Err(Errno::Inval) => Ok(Errno::Success),
23        Err(e) => Ok(e),
24    }
25}
26
27/// ### `fd_close()`
28/// Close an open file descriptor
29/// For sockets this will flush the data before the socket is closed
30/// Inputs:
31/// - `Fd fd`
32///     A file descriptor mapping to an open file to close
33/// Errors:
34/// - `Errno::Isdir`
35///     If `fd` is a directory
36/// - `Errno::Badf`
37///     If `fd` is invalid or not open
38#[instrument(level = "trace", skip_all, fields(pid = ctx.data().process.pid().raw(), %fd), ret)]
39pub fn fd_close(mut ctx: FunctionEnvMut<'_, WasiEnv>, fd: WasiFd) -> Result<Errno, WasiError> {
40    WasiEnv::do_pending_operations(&mut ctx)?;
41
42    let env = ctx.data();
43    let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
44
45    let outcome = state.fs.close_fd_and_capture_flush(fd);
46
47    if outcome.skipped_preopen {
48        trace!("Skipping fd_close for pre-opened FD ({})", fd);
49        return Ok(Errno::Success);
50    }
51
52    if !outcome.removed {
53        return Ok(Errno::Badf);
54    }
55
56    flush_captured_handle(env, outcome.flush_target)?;
57
58    #[cfg(feature = "journal")]
59    if env.enable_journal {
60        JournalEffector::save_fd_close(&mut ctx, fd).map_err(|err| {
61            tracing::error!("failed to save close descriptor event - {}", err);
62            WasiError::Exit(ExitCode::from(Errno::Fault))
63        })?;
64    }
65
66    Ok(Errno::Success)
67}