filestat ops

This commit is contained in:
Pat Hickey
2020-12-01 11:57:24 -08:00
parent 52035f51ee
commit beaad53dc0
3 changed files with 115 additions and 9 deletions

View File

@@ -104,6 +104,10 @@ pub enum Error {
/// Errno::Spipe: Invalid seek /// Errno::Spipe: Invalid seek
#[error("Spipe: Invalid seek")] #[error("Spipe: Invalid seek")]
Spipe, Spipe,
/// Errno::NotCapable: Not capable
#[error("Not capable")]
NotCapable,
} }
impl From<std::convert::Infallible> for Error { impl From<std::convert::Infallible> for Error {

View File

@@ -18,6 +18,19 @@ pub trait WasiFile: FileIoExt {
fn set_oflags(&self, _flags: OFlags) -> Result<(), Error> { fn set_oflags(&self, _flags: OFlags) -> Result<(), Error> {
todo!("FileIoExt has no facilities for oflags"); 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)] #[derive(Debug, Copy, Clone)]
@@ -53,6 +66,24 @@ impl OFlags {
// etc // 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) struct FileEntry {
pub(crate) base_caps: FileCaps, pub(crate) base_caps: FileCaps,
pub(crate) inheriting_caps: FileCaps, pub(crate) inheriting_caps: FileCaps,
@@ -93,10 +124,13 @@ impl FileCaps {
pub const WRITE: Self = FileCaps { flags: 64 }; pub const WRITE: Self = FileCaps { flags: 64 };
pub const ADVISE: Self = FileCaps { flags: 128 }; pub const ADVISE: Self = FileCaps { flags: 128 };
pub const ALLOCATE: Self = FileCaps { flags: 256 }; 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 // This isnt in wasi-common, but lets use a cap to check
// if its valid to close a file, rather than depend on // if its valid to close a file, rather than depend on
// preopen logic // preopen logic
pub const CLOSE: Self = FileCaps { flags: 512 }; pub const CLOSE: Self = FileCaps { flags: 4096 };
} }
impl std::fmt::Display for FileCaps { impl std::fmt::Display for FileCaps {

View File

@@ -1,5 +1,5 @@
#![allow(unused_variables)] #![allow(unused_variables)]
use crate::file::{FileCaps, FileEntry, Filetype, OFlags}; use crate::file::{FileCaps, FileEntry, Filestat, FilestatSetTime, Filetype, OFlags};
use crate::{Error, WasiCtx}; use crate::{Error, WasiCtx};
use std::cell::RefMut; use std::cell::RefMut;
use std::convert::TryFrom; use std::convert::TryFrom;
@@ -27,9 +27,9 @@ impl types::GuestErrorConversion for WasiCtx {
} }
impl types::UserErrorConversion 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); debug!("Error: {:?}", e);
e.into() Ok(e.into())
} }
} }
@@ -69,6 +69,7 @@ impl From<Error> for types::Errno {
Error::Perm => Errno::Perm, Error::Perm => Errno::Perm,
Error::Spipe => Errno::Spipe, Error::Spipe => Errno::Spipe,
Error::FileNotCapable { .. } => Errno::Notcapable, 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 table = self.table();
let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?; let file_entry: RefMut<FileEntry> = table.get(u32::from(fd))?;
let f = file_entry.get_cap(FileCaps::FDSTAT_SET_FLAGS)?; let f = file_entry.get_cap(FileCaps::FDSTAT_SET_FLAGS)?;
f.set_oflags(OFlags::try_from(flags)?)?; f.set_oflags(OFlags::try_from(flags)?)?;
Ok(()) Ok(())
} }
@@ -196,15 +196,35 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
fs_rights_base: types::Rights, fs_rights_base: types::Rights,
fs_rights_inheriting: types::Rights, fs_rights_inheriting: types::Rights,
) -> Result<(), Error> { ) -> 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> { 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> { 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( fn fd_filestat_set_times(
@@ -214,7 +234,40 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx {
mtim: types::Timestamp, mtim: types::Timestamp,
fst_flags: types::Fstflags, fst_flags: types::Fstflags,
) -> Result<(), Error> { ) -> 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> { 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 { impl From<&FileCaps> for types::Rights {
fn from(caps: &FileCaps) -> types::Rights { fn from(caps: &FileCaps) -> types::Rights {
todo!("translate FileCaps flags to Rights flags") 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 { impl From<&Filetype> for types::Filetype {
fn from(ft: &Filetype) -> types::Filetype { fn from(ft: &Filetype) -> types::Filetype {
match ft { match ft {
@@ -486,3 +548,9 @@ impl TryFrom<types::Fdflags> for OFlags {
todo!() todo!()
} }
} }
impl From<Filestat> for types::Filestat {
fn from(stat: Filestat) -> types::Filestat {
todo!()
}
}