filestat ops
This commit is contained in:
@@ -104,6 +104,10 @@ pub enum Error {
|
||||
/// Errno::Spipe: Invalid seek
|
||||
#[error("Spipe: Invalid seek")]
|
||||
Spipe,
|
||||
|
||||
/// Errno::NotCapable: Not capable
|
||||
#[error("Not capable")]
|
||||
NotCapable,
|
||||
}
|
||||
|
||||
impl From<std::convert::Infallible> for Error {
|
||||
|
||||
@@ -18,6 +18,19 @@ pub trait WasiFile: FileIoExt {
|
||||
fn set_oflags(&self, _flags: OFlags) -> Result<(), Error> {
|
||||
todo!("FileIoExt has no facilities for oflags");
|
||||
}
|
||||
fn filestat_get(&self) -> Result<Filestat, Error> {
|
||||
todo!()
|
||||
}
|
||||
fn filestat_set_times(
|
||||
&self,
|
||||
_atim: Option<FilestatSetTime>,
|
||||
_mtim: Option<FilestatSetTime>,
|
||||
) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
fn filestat_set_size(&self, _size: u64) -> Result<(), Error> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
@@ -53,6 +66,24 @@ impl OFlags {
|
||||
// etc
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Filestat {
|
||||
device_id: u64,
|
||||
inode: u64,
|
||||
filetype: Filetype,
|
||||
nlink: u64,
|
||||
size: usize,
|
||||
atim: std::time::SystemTime,
|
||||
mtim: std::time::SystemTime,
|
||||
ctim: std::time::SystemTime,
|
||||
}
|
||||
|
||||
#[derive(Debug, Copy, Clone)]
|
||||
pub enum FilestatSetTime {
|
||||
Now,
|
||||
Absolute(std::time::SystemTime),
|
||||
}
|
||||
|
||||
pub(crate) struct FileEntry {
|
||||
pub(crate) base_caps: FileCaps,
|
||||
pub(crate) inheriting_caps: FileCaps,
|
||||
@@ -93,10 +124,13 @@ impl FileCaps {
|
||||
pub const WRITE: Self = FileCaps { flags: 64 };
|
||||
pub const ADVISE: Self = FileCaps { flags: 128 };
|
||||
pub const ALLOCATE: Self = FileCaps { flags: 256 };
|
||||
pub const FILESTAT_GET: Self = FileCaps { flags: 512 };
|
||||
pub const FILESTAT_SET_SIZE: Self = FileCaps { flags: 1024 };
|
||||
pub const FILESTAT_SET_TIMES: Self = FileCaps { flags: 2048 };
|
||||
// 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 };
|
||||
pub const CLOSE: Self = FileCaps { flags: 4096 };
|
||||
}
|
||||
|
||||
impl std::fmt::Display for FileCaps {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
#![allow(unused_variables)]
|
||||
use crate::file::{FileCaps, FileEntry, Filetype, OFlags};
|
||||
use crate::file::{FileCaps, FileEntry, Filestat, FilestatSetTime, Filetype, OFlags};
|
||||
use crate::{Error, WasiCtx};
|
||||
use std::cell::RefMut;
|
||||
use std::convert::TryFrom;
|
||||
@@ -27,9 +27,9 @@ impl types::GuestErrorConversion for WasiCtx {
|
||||
}
|
||||
|
||||
impl types::UserErrorConversion for WasiCtx {
|
||||
fn errno_from_error(&self, e: Error) -> types::Errno {
|
||||
fn errno_from_error(&self, e: Error) -> Result<types::Errno, String> {
|
||||
debug!("Error: {:?}", e);
|
||||
e.into()
|
||||
Ok(e.into())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -69,6 +69,7 @@ impl From<Error> for types::Errno {
|
||||
Error::Perm => Errno::Perm,
|
||||
Error::Spipe => Errno::Spipe,
|
||||
Error::FileNotCapable { .. } => Errno::Notcapable,
|
||||
Error::NotCapable => Errno::Notcapable,
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -185,7 +186,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::FDSTAT_SET_FLAGS)?;
|
||||
|
||||
f.set_oflags(OFlags::try_from(flags)?)?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -196,15 +196,35 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
fs_rights_base: types::Rights,
|
||||
fs_rights_inheriting: types::Rights,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let mut file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let base_caps = FileCaps::try_from(&fs_rights_base)?;
|
||||
let inheriting_caps = FileCaps::try_from(&fs_rights_inheriting)?;
|
||||
if file_entry.base_caps.contains(&base_caps)
|
||||
&& file_entry.inheriting_caps.contains(&inheriting_caps)
|
||||
{
|
||||
file_entry.base_caps = base_caps;
|
||||
file_entry.inheriting_caps = inheriting_caps;
|
||||
Ok(())
|
||||
} else {
|
||||
Err(Error::NotCapable)
|
||||
}
|
||||
}
|
||||
|
||||
fn fd_filestat_get(&self, fd: types::Fd) -> Result<types::Filestat, Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::FILESTAT_GET)?;
|
||||
let filestat = f.filestat_get()?;
|
||||
Ok(filestat.into())
|
||||
}
|
||||
|
||||
fn fd_filestat_set_size(&self, fd: types::Fd, size: types::Filesize) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::FILESTAT_SET_SIZE)?;
|
||||
f.filestat_set_size(size)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fd_filestat_set_times(
|
||||
@@ -214,7 +234,40 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
|
||||
mtim: types::Timestamp,
|
||||
fst_flags: types::Fstflags,
|
||||
) -> Result<(), Error> {
|
||||
unimplemented!()
|
||||
use std::time::{Duration, UNIX_EPOCH};
|
||||
let table = self.table();
|
||||
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
|
||||
let f = file_entry.get_cap(FileCaps::FILESTAT_SET_TIMES)?;
|
||||
|
||||
// Validate flags, transform into well-structured arguments
|
||||
let set_atim = fst_flags.contains(&types::Fstflags::ATIM);
|
||||
let set_atim_now = fst_flags.contains(&types::Fstflags::ATIM_NOW);
|
||||
let set_mtim = fst_flags.contains(&types::Fstflags::MTIM);
|
||||
let set_mtim_now = fst_flags.contains(&types::Fstflags::MTIM_NOW);
|
||||
if (set_atim && set_atim_now) || (set_mtim && set_mtim_now) {
|
||||
return Err(Error::Inval);
|
||||
}
|
||||
let atim = if set_atim {
|
||||
Some(FilestatSetTime::Absolute(
|
||||
UNIX_EPOCH + Duration::from_nanos(atim),
|
||||
))
|
||||
} else if set_atim_now {
|
||||
Some(FilestatSetTime::Now)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let mtim = if set_mtim {
|
||||
Some(FilestatSetTime::Absolute(
|
||||
UNIX_EPOCH + Duration::from_nanos(mtim),
|
||||
))
|
||||
} else if set_mtim_now {
|
||||
Some(FilestatSetTime::Now)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
f.filestat_set_times(atim, mtim)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result<types::Size, Error> {
|
||||
@@ -457,12 +510,21 @@ impl From<&FileEntry> for types::Fdstat {
|
||||
}
|
||||
}
|
||||
|
||||
// FileCaps can always be represented as wasi Rights
|
||||
impl From<&FileCaps> for types::Rights {
|
||||
fn from(caps: &FileCaps) -> types::Rights {
|
||||
todo!("translate FileCaps flags to Rights flags")
|
||||
}
|
||||
}
|
||||
|
||||
// FileCaps are a subset of wasi Rights - not all Rights have a valid representation as FileCaps
|
||||
impl TryFrom<&types::Rights> for FileCaps {
|
||||
type Error = Error;
|
||||
fn try_from(rights: &types::Rights) -> Result<FileCaps, Self::Error> {
|
||||
todo!("translate Rights flags to FileCaps flags")
|
||||
}
|
||||
}
|
||||
|
||||
impl From<&Filetype> for types::Filetype {
|
||||
fn from(ft: &Filetype) -> types::Filetype {
|
||||
match ft {
|
||||
@@ -486,3 +548,9 @@ impl TryFrom<types::Fdflags> for OFlags {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Filestat> for types::Filestat {
|
||||
fn from(stat: Filestat) -> types::Filestat {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user