diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index 6f6d361148..007dc59196 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -1,5 +1,6 @@ use crate::error::Error; -use crate::file::{FileCaps, FileType, OFlags, WasiFile}; +use crate::file::{FileCaps, FileType, Filestat, OFlags, WasiFile}; +use std::convert::TryInto; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -21,6 +22,7 @@ pub trait WasiDir { fn remove_dir(&self, path: &str) -> Result<(), Error>; fn unlink_file(&self, path: &str) -> Result<(), Error>; fn read_link(&self, path: &str) -> Result; + fn get_filestat(&self) -> Result; } pub(crate) struct DirEntry { @@ -69,8 +71,8 @@ impl DirEntry { pub fn child_file_caps(&self, desired_caps: FileCaps) -> FileCaps { self.file_caps.intersection(&desired_caps) } - pub fn get_dirstat(&self) -> DirStat { - DirStat { + pub fn get_dir_fdstat(&self) -> DirFdStat { + DirFdStat { dir_caps: self.caps, file_caps: self.file_caps, } @@ -113,16 +115,15 @@ impl DirCaps { pub const SYMLINK: Self = DirCaps { flags: 512 }; pub const REMOVE_DIRECTORY: Self = DirCaps { flags: 1024 }; pub const UNLINK_FILE: Self = DirCaps { flags: 2048 }; + pub const PATH_FILESTAT_GET: Self = DirCaps { flags: 4096 }; + pub const PATH_FILESTAT_SET_TIMES: Self = DirCaps { flags: 8192 }; + pub const FILESTAT_GET: Self = DirCaps { flags: 16384 }; + pub const FILESTAT_SET_TIMES: Self = DirCaps { flags: 32768 }; // Missing that are in wasi-common directory_base: // FD_FDSTAT_SET_FLAGS // FD_SYNC // FD_ADVISE - // PATH_FILESTAT_GET - // PATH_FILESTAT_SET_SIZE - // PATH_FILESTAT_SET_TIMES - // FD_FILESTAT_GET - // FD_FILESTAT_SET_TIMES pub fn all() -> DirCaps { Self::CREATE_DIRECTORY @@ -137,6 +138,10 @@ impl DirCaps { | Self::SYMLINK | Self::REMOVE_DIRECTORY | Self::UNLINK_FILE + | Self::PATH_FILESTAT_GET + | Self::PATH_FILESTAT_SET_TIMES + | Self::FILESTAT_GET + | Self::FILESTAT_SET_TIMES } } @@ -149,7 +154,7 @@ impl std::ops::BitOr for DirCaps { } } -pub struct DirStat { +pub struct DirFdStat { pub file_caps: FileCaps, pub dir_caps: DirCaps, } @@ -290,4 +295,18 @@ impl WasiDir for cap_std::fs::Dir { let link = self.read_link(Path::new(path))?; Ok(link) } + fn get_filestat(&self) -> Result { + let meta = self.metadata(".")?; + use cap_fs_ext::MetadataExt; + Ok(Filestat { + device_id: meta.dev(), + inode: meta.ino(), + filetype: FileType::from(&meta.file_type()), + nlink: meta.nlink(), + size: meta.len(), + atim: meta.accessed().map(|t| Some(t.into_std())).unwrap_or(None), + mtim: meta.modified().map(|t| Some(t.into_std())).unwrap_or(None), + ctim: meta.created().map(|t| Some(t.into_std())).unwrap_or(None), + }) + } } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index c4f2f2b03a..536ba6023d 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -1,10 +1,10 @@ #![allow(unused_variables)] -use crate::dir::{DirCaps, DirEntry, DirStat, ReaddirCursor, TableDirExt}; +use crate::dir::{DirCaps, DirEntry, DirFdStat, ReaddirCursor, ReaddirEntity, TableDirExt}; use crate::file::{FdFlags, FdStat, FileCaps, FileEntry, FileType, Filestat, OFlags}; use crate::{Error, WasiCtx}; use fs_set_times::SystemTimeSpec; use std::cell::{Ref, RefMut}; -use std::convert::TryFrom; +use std::convert::{TryFrom, TryInto}; use std::io::{IoSlice, IoSliceMut}; use std::ops::Deref; use tracing::debug; @@ -228,8 +228,8 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { Ok(types::Fdstat::from(&fdstat)) } else if table.is::(fd) { let dir_entry: Ref = table.get(fd)?; - let dirstat = dir_entry.get_dirstat(); - Ok(types::Fdstat::from(&dirstat)) + let dir_fdstat = dir_entry.get_dir_fdstat(); + Ok(types::Fdstat::from(&dir_fdstat)) } else { Err(Error::Badf) } @@ -267,10 +267,20 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_filestat_get(&self, fd: types::Fd) -> Result { let table = self.table(); - let file_entry: Ref = table.get(u32::from(fd))?; - let f = file_entry.get_cap(FileCaps::FILESTAT_GET)?; - let filestat = f.get_filestat()?; - Ok(filestat.into()) + let fd = u32::from(fd); + if table.is::(fd) { + let file_entry: Ref = table.get(fd)?; + let f = file_entry.get_cap(FileCaps::FILESTAT_GET)?; + let filestat = f.get_filestat()?; + Ok(filestat.into()) + } else if table.is::(fd) { + let dir_entry: Ref = table.get(fd)?; + let d = dir_entry.get_cap(DirCaps::FILESTAT_GET)?; + let filestat = d.get_filestat()?; + Ok(filestat.into()) + } else { + Err(Error::Badf) + } } fn fd_filestat_set_size(&self, fd: types::Fd, size: types::Filesize) -> Result<(), Error> { @@ -289,10 +299,6 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fst_flags: types::Fstflags, ) -> Result<(), Error> { use std::time::{Duration, UNIX_EPOCH}; - let table = self.table(); - let file_entry: Ref = 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); @@ -320,8 +326,20 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { None }; - f.set_times(atim, mtim)?; - Ok(()) + let fd = u32::from(fd); + let table = self.table(); + if table.is::(fd) { + let file_entry: Ref = table.get(fd).unwrap(); + let f = file_entry.get_cap(FileCaps::FILESTAT_SET_TIMES)?; + f.set_times(atim, mtim)?; + Ok(()) + } else if table.is::(fd) { + let dir_entry: Ref = table.get(fd).unwrap(); + let d = dir_entry.get_cap(DirCaps::FILESTAT_SET_TIMES)?; + todo!("d.set_times(atim, mtim)?;") + } else { + Err(Error::Badf) + } } fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result { @@ -560,7 +578,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { flags: types::Lookupflags, path: &GuestPtr<'_, str>, ) -> Result { - unimplemented!() + let table = self.table(); + let dir_entry: Ref = table.get(u32::from(dirfd))?; + let dir = dir_entry.get_cap(DirCaps::PATH_FILESTAT_GET)?; + todo!() } fn path_filestat_set_times( @@ -572,7 +593,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { mtim: types::Timestamp, fst_flags: types::Fstflags, ) -> Result<(), Error> { - unimplemented!() + let table = self.table(); + let dir_entry: Ref = table.get(u32::from(dirfd))?; + let dir = dir_entry.get_cap(DirCaps::PATH_FILESTAT_SET_TIMES)?; + todo!() } fn path_link( @@ -781,8 +805,8 @@ impl From<&FdStat> for types::Fdstat { } } -impl From<&DirStat> for types::Fdstat { - fn from(dirstat: &DirStat) -> types::Fdstat { +impl From<&DirFdStat> for types::Fdstat { + fn from(dirstat: &DirFdStat) -> types::Fdstat { let fs_rights_base = types::Rights::from(&dirstat.dir_caps); let fs_rights_inheriting = types::Rights::from(&dirstat.file_caps); types::Fdstat { @@ -922,6 +946,18 @@ impl From<&DirCaps> for types::Rights { if caps.contains(&DirCaps::UNLINK_FILE) { rights = rights | types::Rights::PATH_UNLINK_FILE; } + if caps.contains(&DirCaps::PATH_FILESTAT_GET) { + rights = rights | types::Rights::PATH_FILESTAT_GET; + } + if caps.contains(&DirCaps::PATH_FILESTAT_SET_TIMES) { + rights = rights | types::Rights::PATH_FILESTAT_SET_TIMES; + } + if caps.contains(&DirCaps::FILESTAT_GET) { + rights = rights | types::Rights::FD_FILESTAT_GET; + } + if caps.contains(&DirCaps::FILESTAT_SET_TIMES) { + rights = rights | types::Rights::FD_FILESTAT_SET_TIMES; + } rights } } @@ -966,6 +1002,18 @@ impl From<&types::Rights> for DirCaps { if rights.contains(&types::Rights::PATH_UNLINK_FILE) { caps = caps | DirCaps::UNLINK_FILE; } + if rights.contains(&types::Rights::PATH_FILESTAT_GET) { + caps = caps | DirCaps::PATH_FILESTAT_GET; + } + if rights.contains(&types::Rights::PATH_FILESTAT_SET_TIMES) { + caps = caps | DirCaps::PATH_FILESTAT_SET_TIMES; + } + if rights.contains(&types::Rights::FD_FILESTAT_GET) { + caps = caps | DirCaps::FILESTAT_GET; + } + if rights.contains(&types::Rights::FD_FILESTAT_SET_TIMES) { + caps = caps | DirCaps::FILESTAT_SET_TIMES; + } caps } }