diff --git a/crates/wasi-c2/src/file.rs b/crates/wasi-c2/src/file.rs index 5f8116a84b..853b7b7efd 100644 --- a/crates/wasi-c2/src/file.rs +++ b/crates/wasi-c2/src/file.rs @@ -2,7 +2,56 @@ use crate::Error; use std::ops::Deref; use system_interface::fs::FileIoExt; -pub trait WasiFile: FileIoExt {} +pub trait WasiFile: FileIoExt { + fn allocate(&self, _offset: u64, _len: u64) -> Result<(), Error> { + todo!("to implement fd_allocate, FileIoExt needs methods to get and set length of a file") + } + fn datasync(&self) -> Result<(), Error> { + todo!("FileIoExt has no facilities for sync"); + } + fn filetype(&self) -> Filetype { + todo!("FileIoExt has no facilities for filetype"); + } + fn oflags(&self) -> OFlags { + todo!("FileIoExt has no facilities for oflags"); + } + fn set_oflags(&self, _flags: OFlags) -> Result<(), Error> { + todo!("FileIoExt has no facilities for oflags"); + } +} + +#[derive(Debug, Copy, Clone)] +pub enum Filetype { + BlockDevice, + CharacterDevice, + RegularFile, + SocketDgram, + SocketStream, +} + +pub struct OFlags { + flags: u32, +} + +impl OFlags { + /// Checks if `other` is a subset of those capabilties: + pub fn contains(&self, other: &Self) -> bool { + self.flags & other.flags == other.flags + } + + pub const ACCMODE: OFlags = OFlags { flags: 1 }; + pub const APPEND: OFlags = OFlags { flags: 2 }; + pub const CREATE: OFlags = OFlags { flags: 4 }; + pub const SYNC: OFlags = OFlags { flags: 4 }; + pub const NOFOLLOW: OFlags = OFlags { flags: 8 }; + pub const NONBLOCK: OFlags = OFlags { flags: 16 }; + pub const RDONLY: OFlags = OFlags { flags: 32 }; + pub const WRONLY: OFlags = OFlags { flags: 64 }; + pub const RDWR: OFlags = OFlags { + flags: Self::RDONLY.flags | Self::WRONLY.flags, + }; + // etc +} pub(crate) struct FileEntry { pub(crate) base_caps: FileCaps, @@ -44,6 +93,10 @@ impl FileCaps { pub const WRITE: Self = FileCaps { flags: 64 }; pub const ADVISE: Self = FileCaps { flags: 128 }; pub const ALLOCATE: Self = FileCaps { flags: 256 }; + // This isnt in wasi-common, but lets use a cap to check + // if its valid to close a file, rather than depend on + // preopen logic + pub const CLOSE: Self = FileCaps { flags: 512 }; } impl std::fmt::Display for FileCaps { diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 6b8b262ff1..4234d78e9f 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -1,7 +1,9 @@ #![allow(unused_variables)] -use crate::file::{FileCaps, FileEntry}; +use crate::file::{FileCaps, FileEntry, Filetype, OFlags}; use crate::{Error, WasiCtx}; use std::cell::RefMut; +use std::convert::TryFrom; +use std::ops::Deref; use tracing::debug; use wiggle::GuestPtr; @@ -148,23 +150,44 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { offset: types::Filesize, len: types::Filesize, ) -> Result<(), Error> { - unimplemented!() + let table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + let f = file_entry.get_cap(FileCaps::ALLOCATE)?; + f.allocate(offset, len)?; + Ok(()) } fn fd_close(&self, fd: types::Fd) -> Result<(), Error> { - unimplemented!() + let mut table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + let f = file_entry.get_cap(FileCaps::CLOSE)?; + drop(f); + drop(file_entry); + let _ = table.delete(u32::from(fd)); + Ok(()) } fn fd_datasync(&self, fd: types::Fd) -> Result<(), Error> { - unimplemented!() + let table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + let f = file_entry.get_cap(FileCaps::DATASYNC)?; + f.datasync()?; + Ok(()) } fn fd_fdstat_get(&self, fd: types::Fd) -> Result { - unimplemented!() + let table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + Ok(types::Fdstat::from(file_entry.deref())) } fn fd_fdstat_set_flags(&self, fd: types::Fd, flags: types::Fdflags) -> Result<(), Error> { - unimplemented!() + let table = self.table(); + let file_entry: RefMut = table.get(u32::from(fd))?; + let f = file_entry.get_cap(FileCaps::FDSTAT_SET_FLAGS)?; + + f.set_oflags(OFlags::try_from(flags)?)?; + Ok(()) } fn fd_fdstat_set_rights( @@ -422,3 +445,44 @@ impl From for system_interface::fs::Advice { } } } + +impl From<&FileEntry> for types::Fdstat { + fn from(entry: &FileEntry) -> types::Fdstat { + types::Fdstat { + fs_filetype: types::Filetype::from(&entry.file.filetype()), + fs_rights_base: types::Rights::from(&entry.base_caps), + fs_rights_inheriting: types::Rights::from(&entry.base_caps), + fs_flags: types::Fdflags::from(&entry.file.oflags()), + } + } +} + +impl From<&FileCaps> for types::Rights { + fn from(caps: &FileCaps) -> types::Rights { + todo!("translate FileCaps flags to Rights flags") + } +} + +impl From<&Filetype> for types::Filetype { + fn from(ft: &Filetype) -> types::Filetype { + match ft { + Filetype::BlockDevice => types::Filetype::BlockDevice, + Filetype::CharacterDevice => types::Filetype::CharacterDevice, + Filetype::RegularFile => types::Filetype::RegularFile, + Filetype::SocketDgram => types::Filetype::SocketDgram, + Filetype::SocketStream => types::Filetype::SocketStream, + } + } +} +impl From<&OFlags> for types::Fdflags { + fn from(caps: &OFlags) -> types::Fdflags { + todo!("translate OFlags flags to Fdflags flags") + } +} + +impl TryFrom for OFlags { + type Error = Error; + fn try_from(fdflags: types::Fdflags) -> Result { + todo!() + } +}