wasmer_wasix/syscalls/wasi/
fd_allocate.rs

1use super::*;
2use crate::syscalls::*;
3
4/// ### `fd_allocate`
5/// Allocate extra space for a file descriptor
6/// Inputs:
7/// - `Fd fd`
8///     The file descriptor to allocate for
9/// - `Filesize offset`
10///     The offset from the start marking the beginning of the allocation
11/// - `Filesize len`
12///     The length from the offset marking the end of the allocation
13#[instrument(level = "trace", skip_all, fields(%fd, %offset, %len), ret)]
14pub fn fd_allocate(
15    mut ctx: FunctionEnvMut<'_, WasiEnv>,
16    fd: WasiFd,
17    offset: Filesize,
18    len: Filesize,
19) -> Result<Errno, WasiError> {
20    WasiEnv::do_pending_operations(&mut ctx)?;
21
22    wasi_try_ok!(fd_allocate_internal(&mut ctx, fd, offset, len));
23    let env = ctx.data();
24
25    #[cfg(feature = "journal")]
26    if env.enable_journal {
27        JournalEffector::save_fd_allocate(&mut ctx, fd, offset, len).map_err(|err| {
28            tracing::error!("failed to save file descriptor allocate event - {}", err);
29            WasiError::Exit(ExitCode::from(Errno::Fault))
30        })?;
31    }
32
33    Ok(Errno::Success)
34}
35
36pub(crate) fn fd_allocate_internal(
37    ctx: &mut FunctionEnvMut<'_, WasiEnv>,
38    fd: WasiFd,
39    offset: Filesize,
40    len: Filesize,
41) -> Result<(), Errno> {
42    let env = ctx.data();
43    let (_, mut state) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
44    let fd_entry = state.fs.get_fd(fd)?;
45    let inode = fd_entry.inode;
46
47    if !fd_entry.inner.rights.contains(Rights::FD_ALLOCATE) {
48        return Err(Errno::Access);
49    }
50    let new_size = offset.checked_add(len).ok_or(Errno::Inval)?;
51    {
52        let mut guard = inode.write();
53        match guard.deref_mut() {
54            Kind::File { handle, .. } => {
55                if let Some(handle) = handle {
56                    let mut handle = handle.write().unwrap();
57                    handle.set_len(new_size).map_err(fs_error_into_wasi_err)?;
58                } else {
59                    return Err(Errno::Badf);
60                }
61            }
62            Kind::Buffer { buffer } => {
63                buffer.resize(new_size as usize, 0);
64            }
65            Kind::Socket { .. }
66            | Kind::PipeRx { .. }
67            | Kind::PipeTx { .. }
68            | Kind::DuplexPipe { .. }
69            | Kind::Symlink { .. }
70            | Kind::EventNotifications { .. }
71            | Kind::Epoll { .. } => return Err(Errno::Badf),
72            Kind::Dir { .. } | Kind::Root { .. } => return Err(Errno::Isdir),
73        }
74    }
75    inode.stat.write().unwrap().st_size = new_size;
76    debug!(%new_size);
77
78    Ok(())
79}