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
use super::*;
use crate::syscalls::*;
use crate::types::wasi::Snapshot0Filestat;

/// ### `fd_filestat_get()`
/// Get the metadata of an open file
///
/// Input:
/// - `Fd fd`
///     The open file descriptor whose metadata will be read
///
/// Output:
/// - `Filestat *buf`
///     Where the metadata from `fd` will be written
#[instrument(level = "trace", skip_all, fields(%fd, size = field::Empty, mtime = field::Empty), ret)]
pub fn fd_filestat_get<M: MemorySize>(
    mut ctx: FunctionEnvMut<'_, WasiEnv>,
    fd: WasiFd,
    buf: WasmPtr<Filestat, M>,
) -> Errno {
    let stat = wasi_try!(fd_filestat_get_internal(&mut ctx, fd));

    // These two values have proved to be helpful in multiple investigations
    Span::current().record("size", stat.st_size);
    Span::current().record("mtime", stat.st_mtim);

    let env = ctx.data();
    let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
    let buf = buf.deref(&memory);
    wasi_try_mem!(buf.write(stat));

    Errno::Success
}

/// ### `fd_filestat_get()`
/// Get the metadata of an open file
///
/// Input:
/// - `__wasi_fd_t fd`
///     The open file descriptor whose metadata will be read
///
/// Output:
/// - `__wasi_filestat_t *buf`
///     Where the metadata from `fd` will be written
pub(crate) fn fd_filestat_get_internal(
    ctx: &mut FunctionEnvMut<'_, WasiEnv>,
    fd: WasiFd,
) -> Result<Filestat, Errno> {
    let env = ctx.data();
    let (_, state, inodes) = unsafe { env.get_memory_and_wasi_state_and_inodes(&ctx, 0) };
    let fd_entry = state.fs.get_fd(fd)?;
    if !fd_entry.rights.contains(Rights::FD_FILESTAT_GET) {
        return Err(Errno::Access);
    }

    state.fs.filestat_fd(fd)
}

/// ### `fd_filestat_get_old()`
/// Get the metadata of an open file
///
/// Input:
/// - `Fd fd`
///     The open file descriptor whose metadata will be read
///
/// Output:
/// - `Snapshot0Filestat *buf`
///     Where the metadata from `fd` will be written
#[instrument(level = "trace", skip_all, fields(%fd), ret)]
pub fn fd_filestat_get_old<M: MemorySize>(
    mut ctx: FunctionEnvMut<'_, WasiEnv>,
    fd: WasiFd,
    buf: WasmPtr<Snapshot0Filestat, M>,
) -> Errno {
    let stat = wasi_try!(fd_filestat_get_internal(&mut ctx, fd));

    let env = ctx.data();
    let (memory, _) = unsafe { env.get_memory_and_wasi_state(&ctx, 0) };
    let old_stat = Snapshot0Filestat {
        st_dev: stat.st_dev,
        st_ino: stat.st_ino,
        st_filetype: stat.st_filetype,
        st_nlink: stat.st_nlink as u32,
        st_size: stat.st_size,
        st_atim: stat.st_atim,
        st_mtim: stat.st_mtim,
        st_ctim: stat.st_ctim,
    };

    let buf = buf.deref(&memory);
    wasi_try_mem!(buf.write(old_stat));

    Errno::Success
}