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    let mut current_size;
52    {
53        let mut guard = inode.write();
54        match guard.deref_mut() {
55            Kind::File { handle, .. } => {
56                if let Some(handle) = handle {
57                    let mut handle = handle.write().unwrap();
58                    current_size = handle.size();
59                    if new_size > current_size {
60                        handle.set_len(new_size).map_err(fs_error_into_wasi_err)?;
61                        current_size = new_size;
62                    }
63                } else {
64                    return Err(Errno::Badf);
65                }
66            }
67            Kind::Buffer { buffer } => {
68                current_size = buffer.len() as u64;
69                if new_size > current_size {
70                    buffer.resize(new_size as usize, 0);
71                    current_size = new_size;
72                }
73            }
74            Kind::Socket { .. }
75            | Kind::PipeRx { .. }
76            | Kind::PipeTx { .. }
77            | Kind::DuplexPipe { .. }
78            | Kind::Symlink { .. }
79            | Kind::EventNotifications { .. }
80            | Kind::Epoll { .. } => return Err(Errno::Badf),
81            Kind::Dir { .. } | Kind::Root { .. } => return Err(Errno::Isdir),
82        }
83    }
84    inode.stat.write().unwrap().st_size = current_size;
85    debug!(%new_size);
86
87    Ok(())
88}