From af8bdf8933e7a15a4dd9c64c6a1a1e07c5487759 Mon Sep 17 00:00:00 2001 From: Pat Hickey Date: Wed, 16 Dec 2020 15:55:30 -0800 Subject: [PATCH] table: borrow entry immutably or mutably --- crates/wasi-c2/src/dir.rs | 17 +++--- crates/wasi-c2/src/snapshots/preview_1.rs | 65 ++++++++++++----------- crates/wasi-c2/src/table.rs | 28 +++++++--- 3 files changed, 65 insertions(+), 45 deletions(-) diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index 1d5e8d36d6..052d0056ef 100644 --- a/crates/wasi-c2/src/dir.rs +++ b/crates/wasi-c2/src/dir.rs @@ -13,18 +13,14 @@ pub trait WasiDir { oflags: OFlags, caps: FileCaps, ) -> Result, Error>; - fn open_dir(&self, symlink_follow: bool, path: &str) -> Result, Error>; - fn create_dir(&self, path: &str) -> Result<(), Error>; - fn readdir( &self, cursor: ReaddirCursor, ) -> Result>>, Error>; - + fn symlink(&self, old_path: &str, new_path: &str) -> Result<(), Error>; fn remove_dir(&self, path: &str) -> Result<(), Error>; - fn unlink_file(&self, path: &str) -> Result<(), Error>; } @@ -166,7 +162,7 @@ pub trait TableDirExt { impl TableDirExt for crate::table::Table { fn is_preopen(&self, fd: u32) -> bool { if self.is::(fd) { - let dir_entry: std::cell::RefMut = self.get(fd).unwrap(); + let dir_entry: std::cell::Ref = self.get(fd).unwrap(); dir_entry.preopen_path.is_some() } else { false @@ -220,15 +216,14 @@ impl WasiDir for cap_std::fs::Dir { if oflags.contains(&OFlags::TRUNCATE) { opts.truncate(true); } - if caps.contains(&FileCaps::READ) { - opts.read(true); - } if caps.contains(&FileCaps::WRITE) || caps.contains(&FileCaps::DATASYNC) || caps.contains(&FileCaps::ALLOCATE) || caps.contains(&FileCaps::FILESTAT_SET_SIZE) { opts.write(true); + } else { + opts.read(true); } if symlink_follow { opts.follow(FollowSymlinks::Yes); @@ -287,6 +282,10 @@ impl WasiDir for cap_std::fs::Dir { }))) } + fn symlink(&self, src_path: &str, dest_path: &str) -> Result<(), Error> { + self.symlink(Path::new(src_path), Path::new(dest_path))?; + Ok(()) + } fn remove_dir(&self, path: &str) -> Result<(), Error> { self.remove_dir(Path::new(path))?; Ok(()) diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 624956bb6f..cddca8af8b 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -3,7 +3,7 @@ use crate::dir::{DirCaps, DirEntry, DirStat, ReaddirCursor, TableDirExt}; use crate::file::{FdFlags, FdStat, FileCaps, FileEntry, Filestat, Filetype, OFlags}; use crate::{Error, WasiCtx}; use fs_set_times::SystemTimeSpec; -use std::cell::RefMut; +use std::cell::{Ref, RefMut}; use std::convert::TryFrom; use std::io::{IoSlice, IoSliceMut}; use std::ops::Deref; @@ -145,7 +145,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { advice: types::Advice, ) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::ADVISE)?; f.advise(offset, len, advice.into())?; Ok(()) @@ -158,7 +158,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { len: types::Filesize, ) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::ALLOCATE)?; f.allocate(offset, len)?; Ok(()) @@ -177,7 +177,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let _ = table.delete(fd); } else if table.is::(fd) { // We cannot close preopened directories - let dir_entry: RefMut = table.get(fd).unwrap(); + let dir_entry: Ref = table.get(fd).unwrap(); if dir_entry.preopen_path().is_some() { return Err(Error::Notsup); } @@ -193,7 +193,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_datasync(&self, fd: types::Fd) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::DATASYNC)?; f.datasync()?; Ok(()) @@ -203,11 +203,11 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let table = self.table(); let fd = u32::from(fd); if table.is::(fd) { - let file_entry: RefMut = table.get(fd)?; + let file_entry: Ref = table.get(fd)?; let fdstat = file_entry.get_fdstat()?; Ok(types::Fdstat::from(&fdstat)) } else if table.is::(fd) { - let dir_entry: RefMut = table.get(fd)?; + let dir_entry: Ref = table.get(fd)?; let dirstat = dir_entry.get_dirstat(); Ok(types::Fdstat::from(&dirstat)) } else { @@ -217,7 +217,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_fdstat_set_flags(&self, fd: types::Fd, flags: types::Fdflags) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::FDSTAT_SET_FLAGS)?; f.set_fdflags(FdFlags::from(&flags))?; Ok(()) @@ -232,11 +232,11 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let table = self.table(); let fd = u32::from(fd); if table.is::(fd) { - let mut file_entry: RefMut = table.get(fd)?; + let mut file_entry: RefMut = table.get_mut(fd)?; let file_caps = FileCaps::from(&fs_rights_base); file_entry.drop_caps_to(file_caps) } else if table.is::(fd) { - let mut dir_entry: RefMut = table.get(fd)?; + let mut dir_entry: RefMut = table.get_mut(fd)?; let dir_caps = DirCaps::from(&fs_rights_base); let file_caps = FileCaps::from(&fs_rights_inheriting); dir_entry.drop_caps_to(dir_caps, file_caps) @@ -247,7 +247,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_filestat_get(&self, fd: types::Fd) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + 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()) @@ -255,7 +255,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_filestat_set_size(&self, fd: types::Fd, size: types::Filesize) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::FILESTAT_SET_SIZE)?; f.set_filestat_size(size)?; Ok(()) @@ -270,7 +270,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { ) -> Result<(), Error> { use std::time::{Duration, UNIX_EPOCH}; let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + 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 @@ -306,7 +306,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_read(&self, fd: types::Fd, iovs: &types::IovecArray<'_>) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::READ)?; let mut guest_slices: Vec> = iovs @@ -334,7 +334,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { offset: types::Filesize, ) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::READ | FileCaps::SEEK)?; let mut guest_slices: Vec> = iovs @@ -361,7 +361,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { ciovs: &types::CiovecArray<'_>, ) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::WRITE)?; let guest_slices: Vec> = ciovs @@ -389,7 +389,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { offset: types::Filesize, ) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::WRITE | FileCaps::SEEK)?; let guest_slices: Vec> = ciovs @@ -412,7 +412,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_prestat_get(&self, fd: types::Fd) -> Result { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(fd)).map_err(|_| Error::Badf)?; + let dir_entry: Ref = table.get(u32::from(fd)).map_err(|_| Error::Badf)?; if let Some(ref preopen) = dir_entry.preopen_path() { let path_str = preopen.to_str().ok_or(Error::Notsup)?; let pr_name_len = @@ -430,7 +430,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { path_max_len: types::Size, ) -> Result<(), Error> { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?; + let dir_entry: Ref = table.get(u32::from(fd)).map_err(|_| Error::Notdir)?; if let Some(ref preopen) = dir_entry.preopen_path() { let path_bytes = preopen.to_str().ok_or(Error::Notsup)?.as_bytes(); let path_len = path_bytes.len(); @@ -479,7 +479,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { }; let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(required_caps)?; let newoffset = f.seek(match whence { types::Whence::Cur => SeekFrom::Current(offset), @@ -491,7 +491,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_sync(&self, fd: types::Fd) -> Result<(), Error> { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::SYNC)?; f.sync()?; Ok(()) @@ -499,7 +499,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn fd_tell(&self, fd: types::Fd) -> Result { let table = self.table(); - let file_entry: RefMut = table.get(u32::from(fd))?; + let file_entry: Ref = table.get(u32::from(fd))?; let f = file_entry.get_cap(FileCaps::TELL)?; let offset = f.seek(std::io::SeekFrom::Current(0))?; Ok(offset) @@ -513,7 +513,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { cookie: types::Dircookie, ) -> Result { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let dir_entry: Ref = table.get(u32::from(dirfd))?; let d = dir_entry.get_cap(DirCaps::READDIR)?; for pair in d.readdir(ReaddirCursor::from(cookie))? { let (entity, name) = pair?; @@ -528,7 +528,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { path: &GuestPtr<'_, str>, ) -> Result<(), Error> { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let dir_entry: Ref = table.get(u32::from(dirfd))?; let dir = dir_entry.get_cap(DirCaps::CREATE_DIRECTORY)?; let path = path.as_str()?; dir.create_dir(path.deref()) @@ -577,7 +577,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fdflags: types::Fdflags, ) -> Result { let mut table = self.table(); - let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let dir_entry: Ref = table.get(u32::from(dirfd))?; let symlink_follow = dirflags.contains(&types::Lookupflags::SYMLINK_FOLLOW); @@ -633,7 +633,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { path: &GuestPtr<'_, str>, ) -> Result<(), Error> { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let dir_entry: Ref = table.get(u32::from(dirfd))?; let dir = dir_entry.get_cap(DirCaps::REMOVE_DIRECTORY)?; let path = path.as_str()?; dir.remove_dir(path.deref()) @@ -651,16 +651,21 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { fn path_symlink( &self, - old_path: &GuestPtr<'_, str>, + src_path: &GuestPtr<'_, str>, dirfd: types::Fd, - new_path: &GuestPtr<'_, str>, + dest_path: &GuestPtr<'_, str>, ) -> Result<(), Error> { - unimplemented!() + let table = self.table(); + let dir_entry: Ref = table.get(u32::from(dirfd))?; + let dir = dir_entry.get_cap(DirCaps::SYMLINK)?; + let src_path = src_path.as_str()?; + let dest_path = dest_path.as_str()?; + dir.symlink(src_path.deref(), dest_path.deref()) } fn path_unlink_file(&self, dirfd: types::Fd, path: &GuestPtr<'_, str>) -> Result<(), Error> { let table = self.table(); - let dir_entry: RefMut = table.get(u32::from(dirfd))?; + let dir_entry: Ref = table.get(u32::from(dirfd))?; let dir = dir_entry.get_cap(DirCaps::UNLINK_FILE)?; let path = path.as_str()?; dir.unlink_file(path.deref()) diff --git a/crates/wasi-c2/src/table.rs b/crates/wasi-c2/src/table.rs index d94cc020b1..788f8cebfd 100644 --- a/crates/wasi-c2/src/table.rs +++ b/crates/wasi-c2/src/table.rs @@ -1,6 +1,6 @@ use crate::Error; use std::any::Any; -use std::cell::{RefCell, RefMut}; +use std::cell::{Ref, RefCell, RefMut}; use std::collections::HashMap; pub struct Table { @@ -49,12 +49,28 @@ impl Table { false } } - // Todo: we can refine these errors and translate them to Exist at abi - pub fn get(&self, key: u32) -> Result, Error> { + + pub fn get(&self, key: u32) -> Result, Error> { if let Some(refcell) = self.map.get(&key) { - if let Ok(refmut) = refcell.try_borrow_mut() { - if refmut.is::() { - Ok(RefMut::map(refmut, |r| r.downcast_mut::().unwrap())) + if let Ok(r) = refcell.try_borrow() { + if r.is::() { + Ok(Ref::map(r, |r| r.downcast_ref::().unwrap())) + } else { + Err(Error::Exist) // Exists at another type + } + } else { + Err(Error::Exist) // Does exist, but borrowed + } + } else { + Err(Error::Exist) // Does not exist + } + } + + pub fn get_mut(&self, key: u32) -> Result, Error> { + if let Some(refcell) = self.map.get(&key) { + if let Ok(r) = refcell.try_borrow_mut() { + if r.is::() { + Ok(RefMut::map(r, |r| r.downcast_mut::().unwrap())) } else { Err(Error::Exist) // Exists at another type }