1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
use tracing::{field, instrument, trace_span};
use wasmer::{AsStoreMut, AsStoreRef, FunctionEnvMut, Memory, WasmPtr};
use wasmer_wasix_types::wasi::{
    Errno, Event, EventFdReadwrite, Eventrwflags, Eventtype, ExitCode, Fd, Filesize, Filestat,
    Filetype, Snapshot0Event, Snapshot0Filestat, Snapshot0Subscription, Snapshot0Whence,
    Subscription, Whence,
};

use crate::{
    mem_error_to_wasi,
    os::task::thread::WasiThread,
    state::{PollEventBuilder, PollEventSet},
    syscalls::types,
    syscalls::{self, handle_rewind},
    Memory32, MemorySize, WasiEnv, WasiError,
};

/// Wrapper around `syscalls::fd_filestat_get` for old Snapshot0
#[instrument(level = "trace", skip_all, ret)]
pub fn fd_filestat_get(
    mut ctx: FunctionEnvMut<WasiEnv>,
    fd: Fd,
    buf: WasmPtr<Snapshot0Filestat, Memory32>,
) -> Errno {
    let env = ctx.data();
    let memory = unsafe { env.memory_view(&ctx) };
    let result = syscalls::fd_filestat_get_old::<Memory32>(ctx.as_mut(), fd, buf);

    result
}

/// Wrapper around `syscalls::path_filestat_get` for old Snapshot0
#[instrument(level = "trace", skip_all, ret)]
pub fn path_filestat_get(
    mut ctx: FunctionEnvMut<WasiEnv>,
    fd: Fd,
    flags: types::LookupFlags,
    path: WasmPtr<u8, Memory32>,
    path_len: u32,
    buf: WasmPtr<Snapshot0Filestat, Memory32>,
) -> Errno {
    let env = ctx.data();
    let memory = unsafe { env.memory_view(&ctx) };

    let result =
        syscalls::path_filestat_get_old::<Memory32>(ctx.as_mut(), fd, flags, path, path_len, buf);

    result
}

/// Wrapper around `syscalls::fd_seek` with extra logic to remap the values
/// of `Whence`
#[instrument(level = "trace", skip_all, ret)]
pub fn fd_seek(
    ctx: FunctionEnvMut<WasiEnv>,
    fd: Fd,
    offset: types::FileDelta,
    whence: Snapshot0Whence,
    newoffset: WasmPtr<Filesize, Memory32>,
) -> Result<Errno, WasiError> {
    let new_whence = match whence {
        Snapshot0Whence::Cur => Whence::Cur,
        Snapshot0Whence::End => Whence::End,
        Snapshot0Whence::Set => Whence::Set,
        Snapshot0Whence::Unknown => return Ok(Errno::Inval),
    };
    syscalls::fd_seek::<Memory32>(ctx, fd, offset, new_whence, newoffset)
}

/// Wrapper around `syscalls::poll_oneoff` with extra logic to add the removed
/// userdata field back
#[instrument(level = "trace", skip_all, fields(timeout_ms = field::Empty, fd_guards = field::Empty, seen = field::Empty), ret)]
pub fn poll_oneoff<M: MemorySize>(
    mut ctx: FunctionEnvMut<WasiEnv>,
    in_: WasmPtr<Snapshot0Subscription, Memory32>,
    out_: WasmPtr<Snapshot0Event, Memory32>,
    nsubscriptions: u32,
    nevents: WasmPtr<u32, Memory32>,
) -> Result<Errno, WasiError> {
    wasi_try_ok!(WasiEnv::process_signals_and_exit(&mut ctx)?);

    let env = ctx.data();
    let memory = unsafe { env.memory_view(&ctx) };
    let mut subscriptions = Vec::new();
    let in_origs = wasi_try_mem_ok!(in_.slice(&memory, nsubscriptions));
    let in_origs = wasi_try_mem_ok!(in_origs.read_to_vec());
    for in_orig in in_origs {
        subscriptions.push((
            None,
            PollEventSet::default(),
            Into::<Subscription>::into(in_orig),
        ));
    }

    // Function to invoke once the poll is finished
    let process_events = |ctx: &FunctionEnvMut<'_, WasiEnv>, triggered_events: Vec<Event>| {
        let env = ctx.data();
        let memory = unsafe { env.memory_view(&ctx) };

        // Process all the events that were triggered
        let mut events_seen: u32 = 0;
        let event_array = wasi_try_mem!(out_.slice(&memory, nsubscriptions));
        for event in triggered_events {
            let event = Snapshot0Event {
                userdata: event.userdata,
                error: event.error,
                type_: Eventtype::FdRead,
                fd_readwrite: match event.type_ {
                    Eventtype::FdRead => unsafe { event.u.fd_readwrite },
                    Eventtype::FdWrite => unsafe { event.u.fd_readwrite },
                    Eventtype::Clock => EventFdReadwrite {
                        nbytes: 0,
                        flags: Eventrwflags::empty(),
                    },
                    Eventtype::Unknown => return Errno::Inval,
                },
            };
            wasi_try_mem!(event_array.index(events_seen as u64).write(event));
            events_seen += 1;
        }
        let out_ptr = nevents.deref(&memory);
        wasi_try_mem!(out_ptr.write(events_seen));
        Errno::Success
    };

    // We clear the number of events
    wasi_try_mem_ok!(nevents.write(&memory, 0));

    // Poll and receive all the events that triggered
    syscalls::poll_oneoff_internal::<M, _>(ctx, subscriptions, process_events)
}