From 42cf0286214a1fed684efe22794faf4b953a1d09 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 3 Jan 2022 19:17:49 -0600 Subject: [PATCH 1/3] Fix cap-std compilation on WASI. This gets cap-primitives and cap-std to the point where they compile on WASI. There are a few TODOs, and some of this will need to be revisited as WASI evolves and adds `chmod` support, but this should suffice for now. Fixes #195. --- cap-primitives/src/fs/dir_options.rs | 3 + cap-primitives/src/fs/metadata.rs | 38 ++++++ cap-primitives/src/fs/mod.rs | 2 + cap-primitives/src/fs/open_options.rs | 35 ++++++ cap-primitives/src/fs/permissions.rs | 11 +- cap-primitives/src/rustix/fs/copy_impl.rs | 20 ++++ .../src/rustix/fs/create_dir_unchecked.rs | 11 +- cap-primitives/src/rustix/fs/dir_utils.rs | 14 ++- cap-primitives/src/rustix/fs/file_path.rs | 2 - cap-primitives/src/rustix/fs/file_type_ext.rs | 14 ++- cap-primitives/src/rustix/fs/metadata_ext.rs | 108 +++++++++++++++++- cap-primitives/src/rustix/fs/mod.rs | 8 +- cap-primitives/src/rustix/fs/oflags.rs | 7 +- .../src/rustix/fs/open_unchecked.rs | 3 + .../src/rustix/fs/permissions_ext.rs | 10 ++ cap-std/src/fs/dir.rs | 8 +- cap-std/src/fs/file.rs | 30 ++--- cap-std/src/fs/mod.rs | 7 +- 18 files changed, 277 insertions(+), 54 deletions(-) diff --git a/cap-primitives/src/fs/dir_options.rs b/cap-primitives/src/fs/dir_options.rs index d9c6a7f8..358492eb 100644 --- a/cap-primitives/src/fs/dir_options.rs +++ b/cap-primitives/src/fs/dir_options.rs @@ -1,3 +1,4 @@ +#[cfg(not(target_os = "wasi"))] use crate::fs::DirOptionsExt; /// Options and flags which can be used to configure how a directory is @@ -6,6 +7,7 @@ use crate::fs::DirOptionsExt; /// This is to `create_dir` what to `OpenOptions` is to `open`. #[derive(Debug, Clone)] pub struct DirOptions { + #[cfg(not(target_os = "wasi"))] #[allow(dead_code)] pub(crate) ext: DirOptionsExt, } @@ -16,6 +18,7 @@ impl DirOptions { #[inline] pub const fn new() -> Self { Self { + #[cfg(not(target_os = "wasi"))] ext: DirOptionsExt::new(), } } diff --git a/cap-primitives/src/fs/metadata.rs b/cap-primitives/src/fs/metadata.rs index 3302a90e..58aad8f3 100644 --- a/cap-primitives/src/fs/metadata.rs +++ b/cap-primitives/src/fs/metadata.rs @@ -259,6 +259,44 @@ impl std::os::unix::fs::MetadataExt for Metadata { } } +#[cfg(target_os = "wasi")] +impl std::os::wasi::fs::MetadataExt for Metadata { + #[inline] + fn dev(&self) -> u64 { + self.ext.dev() + } + + #[inline] + fn ino(&self) -> u64 { + self.ext.ino() + } + + #[inline] + fn nlink(&self) -> u64 { + self.ext.nlink() + } + + #[inline] + fn size(&self) -> u64 { + self.ext.size() + } + + #[inline] + fn atim(&self) -> u64 { + self.ext.atim() + } + + #[inline] + fn mtim(&self) -> u64 { + self.ext.mtim() + } + + #[inline] + fn ctim(&self) -> u64 { + self.ext.ctim() + } +} + #[cfg(target_os = "vxworks")] impl std::os::vxworks::fs::MetadataExt for Metadata { #[inline] diff --git a/cap-primitives/src/fs/mod.rs b/cap-primitives/src/fs/mod.rs index 9172d855..70853687 100644 --- a/cap-primitives/src/fs/mod.rs +++ b/cap-primitives/src/fs/mod.rs @@ -32,6 +32,7 @@ mod remove_file; mod remove_open_dir; mod rename; mod reopen; +#[cfg(not(target_os = "wasi"))] mod set_permissions; mod set_times; mod stat; @@ -85,6 +86,7 @@ pub use remove_file::remove_file; pub use remove_open_dir::{remove_open_dir, remove_open_dir_all}; pub use rename::rename; pub use reopen::reopen; +#[cfg(not(target_os = "wasi"))] pub use set_permissions::set_permissions; pub use set_times::{set_times, set_times_nofollow}; pub use stat::stat; diff --git a/cap-primitives/src/fs/open_options.rs b/cap-primitives/src/fs/open_options.rs index 8b3b55be..de634785 100644 --- a/cap-primitives/src/fs/open_options.rs +++ b/cap-primitives/src/fs/open_options.rs @@ -178,6 +178,41 @@ impl std::os::unix::fs::OpenOptionsExt for OpenOptions { } } +#[cfg(target_os = "wasi")] +impl std::os::wasi::fs::OpenOptionsExt for OpenOptions { + fn lookup_flags(&mut self, _: u32) -> &mut Self { + todo!() + } + fn directory(&mut self, dir_required: bool) -> &mut Self { + self.dir_required = dir_required; + self + } + fn dsync(&mut self, _: bool) -> &mut Self { + todo!() + } + fn nonblock(&mut self, _: bool) -> &mut Self { + todo!() + } + fn rsync(&mut self, _: bool) -> &mut Self { + todo!() + } + fn sync(&mut self, _: bool) -> &mut Self { + todo!() + } + fn fs_rights_base(&mut self, _: u64) -> &mut Self { + todo!() + } + fn fs_rights_inheriting(&mut self, _: u64) -> &mut Self { + todo!() + } + fn open_at

(&self, dirfd: &std::fs::File, path: P) -> Result + where + P: AsRef, + { + crate::fs::open(dirfd, path.as_ref(), self) + } +} + #[cfg(target_os = "vxworks")] impl std::os::vxworks::fs::OpenOptionsExt for OpenOptions { #[inline] diff --git a/cap-primitives/src/fs/permissions.rs b/cap-primitives/src/fs/permissions.rs index 9d9f9ac1..be356b68 100644 --- a/cap-primitives/src/fs/permissions.rs +++ b/cap-primitives/src/fs/permissions.rs @@ -1,4 +1,4 @@ -#[cfg(any(unix, target_os = "vxworks"))] +#[cfg(not(windows))] use crate::fs::PermissionsExt; #[cfg(unix)] use rustix::fs::RawMode; @@ -52,6 +52,15 @@ impl Permissions { Ok(fs::Permissions::from_mode(self.ext.mode())) } + #[cfg(target_os = "wasi")] + #[inline] + #[allow(clippy::unnecessary_wraps)] + fn _into_std(self, file: &fs::File) -> io::Result { + let mut permissions = file.metadata()?.permissions(); + permissions.set_readonly(self.readonly()); + Ok(permissions) + } + #[cfg(windows)] #[inline] fn _into_std(self, file: &fs::File) -> io::Result { diff --git a/cap-primitives/src/rustix/fs/copy_impl.rs b/cap-primitives/src/rustix/fs/copy_impl.rs index 312a7928..561a6ac7 100644 --- a/cap-primitives/src/rustix/fs/copy_impl.rs +++ b/cap-primitives/src/rustix/fs/copy_impl.rs @@ -25,6 +25,7 @@ fn open_from(start: &fs::File, path: &Path) -> io::Result<(fs::File, fs::Metadat Ok((reader, metadata)) } +#[cfg(not(target_os = "wasi"))] fn open_to_and_set_permissions( start: &fs::File, path: &Path, @@ -54,6 +55,25 @@ fn open_to_and_set_permissions( Ok((writer, writer_metadata)) } +#[cfg(target_os = "wasi")] +fn open_to_and_set_permissions( + start: &fs::File, + path: &Path, + reader_metadata: fs::Metadata, +) -> io::Result<(fs::File, fs::Metadata)> { + let writer = open( + start, + path, + OpenOptions::new() + // create the file with the correct mode right away + .write(true) + .create(true) + .truncate(true), + )?; + let writer_metadata = writer.metadata()?; + Ok((writer, writer_metadata)) +} + #[cfg(not(any( target_os = "linux", target_os = "android", diff --git a/cap-primitives/src/rustix/fs/create_dir_unchecked.rs b/cap-primitives/src/rustix/fs/create_dir_unchecked.rs index 38dbd11c..652162c7 100644 --- a/cap-primitives/src/rustix/fs/create_dir_unchecked.rs +++ b/cap-primitives/src/rustix/fs/create_dir_unchecked.rs @@ -10,9 +10,10 @@ pub(crate) fn create_dir_unchecked( path: &Path, options: &DirOptions, ) -> io::Result<()> { - Ok(mkdirat( - start, - path, - Mode::from_bits(options.ext.mode as RawMode).unwrap(), - )?) + #[cfg(not(target_os = "wasi"))] + let raw_mode = options.ext.mode as RawMode; + #[cfg(target_os = "wasi")] + let raw_mode = 0; + + Ok(mkdirat(start, path, Mode::from_bits(raw_mode).unwrap())?) } diff --git a/cap-primitives/src/rustix/fs/dir_utils.rs b/cap-primitives/src/rustix/fs/dir_utils.rs index 85e04b47..bb18ee02 100644 --- a/cap-primitives/src/rustix/fs/dir_utils.rs +++ b/cap-primitives/src/rustix/fs/dir_utils.rs @@ -6,7 +6,7 @@ use std::ops::Deref; #[cfg(unix)] use std::os::unix::{ffi::OsStrExt, fs::OpenOptionsExt}; #[cfg(target_os = "wasi")] -use std::os::wasi::{ffi::OsStrExt, fs::OpenOptionsExt}; +use std::os::wasi::ffi::OsStrExt; use std::path::Path; #[cfg(racy_asserts)] use std::{ffi::OsString, os::unix::ffi::OsStringExt, path::PathBuf}; @@ -104,10 +104,13 @@ pub(crate) fn open_ambient_dir_impl(path: &Path, _: AmbientAuthority) -> io::Res // `O_DIRECTORY` manually. let flags = OFlags::DIRECTORY | target_o_path(); - fs::OpenOptions::new() - .read(true) - .custom_flags(flags.bits() as i32) - .open(&path) + let mut options = fs::OpenOptions::new(); + options.read(true); + + #[cfg(not(target_os = "wasi"))] + options.custom_flags(flags.bits() as i32); + + options.open(&path) } /// Use `O_PATH` on platforms which have it, or none otherwise. @@ -131,6 +134,7 @@ pub(crate) const fn target_o_path() -> OFlags { target_os = "macos", target_os = "netbsd", target_os = "openbsd", + target_os = "wasi", ))] { OFlags::empty() diff --git a/cap-primitives/src/rustix/fs/file_path.rs b/cap-primitives/src/rustix/fs/file_path.rs index 8e144878..211ec01b 100644 --- a/cap-primitives/src/rustix/fs/file_path.rs +++ b/cap-primitives/src/rustix/fs/file_path.rs @@ -6,8 +6,6 @@ use std::ffi::OsString; use std::fs; #[cfg(unix)] use std::os::unix::ffi::OsStringExt; -#[cfg(target_os = "wasi")] -use std::os::wasi::ffi::OsStringExt; use std::path::PathBuf; pub(crate) fn file_path_by_ttyname_or_seaching(file: &fs::File) -> Option { diff --git a/cap-primitives/src/rustix/fs/file_type_ext.rs b/cap-primitives/src/rustix/fs/file_type_ext.rs index 868c3c46..64ca2a03 100644 --- a/cap-primitives/src/rustix/fs/file_type_ext.rs +++ b/cap-primitives/src/rustix/fs/file_type_ext.rs @@ -44,12 +44,16 @@ impl FileTypeExt { FileType::ext(Self::BlockDevice) } else if std.is_char_device() { FileType::ext(Self::CharDevice) - } else if std.is_fifo() { - FileType::ext(Self::Fifo) - } else if std.is_socket() { - FileType::ext(Self::Socket) } else { - FileType::unknown() + #[cfg(not(target_os = "wasi"))] + if std.is_fifo() { + return FileType::ext(Self::Fifo); + } + if std.is_socket() { + FileType::ext(Self::Socket) + } else { + FileType::unknown() + } } } diff --git a/cap-primitives/src/rustix/fs/metadata_ext.rs b/cap-primitives/src/rustix/fs/metadata_ext.rs index 2eb04646..6087121a 100644 --- a/cap-primitives/src/rustix/fs/metadata_ext.rs +++ b/cap-primitives/src/rustix/fs/metadata_ext.rs @@ -1,6 +1,7 @@ #![allow(clippy::useless_conversion)] -use crate::fs::{FileTypeExt, Metadata, PermissionsExt}; +use crate::fs::PermissionsExt; +use crate::fs::{FileTypeExt, Metadata}; use crate::time::{Duration, SystemClock, SystemTime}; #[cfg(all(target_os = "linux", target_env = "gnu"))] use rustix::fs::{makedev, Statx}; @@ -12,20 +13,38 @@ use std::{fs, io}; pub(crate) struct MetadataExt { dev: u64, ino: u64, + #[cfg(not(target_os = "wasi"))] mode: u32, nlink: u64, + #[cfg(not(target_os = "wasi"))] uid: u32, + #[cfg(not(target_os = "wasi"))] gid: u32, + #[cfg(not(target_os = "wasi"))] rdev: u64, size: u64, + #[cfg(not(target_os = "wasi"))] atime: i64, + #[cfg(not(target_os = "wasi"))] atime_nsec: i64, + #[cfg(not(target_os = "wasi"))] mtime: i64, + #[cfg(not(target_os = "wasi"))] mtime_nsec: i64, + #[cfg(not(target_os = "wasi"))] ctime: i64, + #[cfg(not(target_os = "wasi"))] ctime_nsec: i64, + #[cfg(not(target_os = "wasi"))] blksize: u64, + #[cfg(not(target_os = "wasi"))] blocks: u64, + #[cfg(target_os = "wasi")] + atim: u64, + #[cfg(target_os = "wasi")] + mtim: u64, + #[cfg(target_os = "wasi")] + ctim: u64, } impl MetadataExt { @@ -46,20 +65,38 @@ impl MetadataExt { Self { dev: std.dev(), ino: std.ino(), + #[cfg(not(target_os = "wasi"))] mode: std.mode(), nlink: std.nlink(), + #[cfg(not(target_os = "wasi"))] uid: std.uid(), + #[cfg(not(target_os = "wasi"))] gid: std.gid(), + #[cfg(not(target_os = "wasi"))] rdev: std.rdev(), size: std.size(), + #[cfg(not(target_os = "wasi"))] atime: std.atime(), + #[cfg(not(target_os = "wasi"))] atime_nsec: std.atime_nsec(), + #[cfg(not(target_os = "wasi"))] mtime: std.mtime(), + #[cfg(not(target_os = "wasi"))] mtime_nsec: std.mtime_nsec(), + #[cfg(not(target_os = "wasi"))] ctime: std.ctime(), + #[cfg(not(target_os = "wasi"))] ctime_nsec: std.ctime_nsec(), + #[cfg(not(target_os = "wasi"))] blksize: std.blksize(), + #[cfg(not(target_os = "wasi"))] blocks: std.blocks(), + #[cfg(target_os = "wasi")] + atim: std.atim(), + #[cfg(target_os = "wasi")] + mtim: std.mtim(), + #[cfg(target_os = "wasi")] + ctim: std.ctim(), } } @@ -69,14 +106,17 @@ impl MetadataExt { Metadata { file_type: FileTypeExt::from_raw_mode(stat.st_mode as RawMode), len: u64::try_from(stat.st_size).unwrap(), + #[cfg(not(target_os = "wasi"))] permissions: PermissionsExt::from_raw_mode(stat.st_mode as RawMode), + #[cfg(target_os = "wasi")] + permissions: PermissionsExt::default(), - #[cfg(not(target_os = "netbsd"))] + #[cfg(not(any(target_os = "netbsd", target_os = "wasi")))] modified: system_time_from_rustix( stat.st_mtime.try_into().unwrap(), stat.st_mtime_nsec as _, ), - #[cfg(not(target_os = "netbsd"))] + #[cfg(not(any(target_os = "netbsd", target_os = "wasi")))] accessed: system_time_from_rustix( stat.st_atime.try_into().unwrap(), stat.st_atime_nsec as _, @@ -93,6 +133,11 @@ impl MetadataExt { stat.st_atimensec as _, ), + #[cfg(target_os = "wasi")] + modified: system_time_from_rustix(stat.st_mtim.tv_sec, stat.st_mtim.tv_nsec as _), + #[cfg(target_os = "wasi")] + accessed: system_time_from_rustix(stat.st_atim.tv_sec, stat.st_atim.tv_nsec as _), + #[cfg(any( target_os = "freebsd", target_os = "openbsd", @@ -123,29 +168,53 @@ impl MetadataExt { ext: Self { dev: u64::try_from(stat.st_dev).unwrap(), ino: stat.st_ino.into(), + #[cfg(not(target_os = "wasi"))] mode: u32::from(stat.st_mode), nlink: u64::from(stat.st_nlink), + #[cfg(not(target_os = "wasi"))] uid: stat.st_uid, + #[cfg(not(target_os = "wasi"))] gid: stat.st_gid, + #[cfg(not(target_os = "wasi"))] rdev: u64::try_from(stat.st_rdev).unwrap(), size: u64::try_from(stat.st_size).unwrap(), + #[cfg(not(target_os = "wasi"))] atime: i64::try_from(stat.st_atime).unwrap(), - #[cfg(not(target_os = "netbsd"))] + #[cfg(not(any(target_os = "netbsd", target_os = "wasi")))] atime_nsec: stat.st_atime_nsec as _, #[cfg(target_os = "netbsd")] atime_nsec: stat.st_atimensec as _, + #[cfg(not(target_os = "wasi"))] mtime: i64::try_from(stat.st_mtime).unwrap(), - #[cfg(not(target_os = "netbsd"))] + #[cfg(not(any(target_os = "netbsd", target_os = "wasi")))] mtime_nsec: stat.st_mtime_nsec as _, #[cfg(target_os = "netbsd")] mtime_nsec: stat.st_mtimensec as _, + #[cfg(not(target_os = "wasi"))] ctime: i64::try_from(stat.st_ctime).unwrap(), - #[cfg(not(target_os = "netbsd"))] + #[cfg(not(any(target_os = "netbsd", target_os = "wasi")))] ctime_nsec: stat.st_ctime_nsec as _, #[cfg(target_os = "netbsd")] ctime_nsec: stat.st_ctimensec as _, + #[cfg(not(target_os = "wasi"))] blksize: u64::try_from(stat.st_blksize).unwrap(), + #[cfg(not(target_os = "wasi"))] blocks: u64::try_from(stat.st_blocks).unwrap(), + #[cfg(target_os = "wasi")] + atim: u64::try_from( + stat.st_atim.tv_sec as u64 * 1000000000 + stat.st_atim.tv_nsec as u64, + ) + .unwrap(), + #[cfg(target_os = "wasi")] + mtim: u64::try_from( + stat.st_mtim.tv_sec as u64 * 1000000000 + stat.st_mtim.tv_nsec as u64, + ) + .unwrap(), + #[cfg(target_os = "wasi")] + ctim: u64::try_from( + stat.st_ctim.tv_sec as u64 * 1000000000 + stat.st_ctim.tv_nsec as u64, + ) + .unwrap(), }, } } @@ -207,6 +276,7 @@ impl rustix::fs::MetadataExt for MetadataExt { self.ino } + #[cfg(not(target_os = "wasi"))] #[inline] fn mode(&self) -> u32 { self.mode @@ -217,16 +287,19 @@ impl rustix::fs::MetadataExt for MetadataExt { self.nlink } + #[cfg(not(target_os = "wasi"))] #[inline] fn uid(&self) -> u32 { self.uid } + #[cfg(not(target_os = "wasi"))] #[inline] fn gid(&self) -> u32 { self.gid } + #[cfg(not(target_os = "wasi"))] #[inline] fn rdev(&self) -> u64 { self.rdev @@ -237,43 +310,66 @@ impl rustix::fs::MetadataExt for MetadataExt { self.size } + #[cfg(not(target_os = "wasi"))] #[inline] fn atime(&self) -> i64 { self.atime } + #[cfg(not(target_os = "wasi"))] #[inline] fn atime_nsec(&self) -> i64 { self.atime_nsec } + #[cfg(not(target_os = "wasi"))] #[inline] fn mtime(&self) -> i64 { self.mtime } + #[cfg(not(target_os = "wasi"))] #[inline] fn mtime_nsec(&self) -> i64 { self.mtime_nsec } + #[cfg(not(target_os = "wasi"))] #[inline] fn ctime(&self) -> i64 { self.ctime } + #[cfg(not(target_os = "wasi"))] #[inline] fn ctime_nsec(&self) -> i64 { self.ctime_nsec } + #[cfg(not(target_os = "wasi"))] #[inline] fn blksize(&self) -> u64 { self.blksize } + #[cfg(not(target_os = "wasi"))] #[inline] fn blocks(&self) -> u64 { self.blocks } + + #[cfg(target_os = "wasi")] + fn atim(&self) -> u64 { + self.atim + } + + #[cfg(target_os = "wasi")] + fn mtim(&self) -> u64 { + self.mtim + } + + #[cfg(target_os = "wasi")] + fn ctim(&self) -> u64 { + self.ctim + } } diff --git a/cap-primitives/src/rustix/fs/mod.rs b/cap-primitives/src/rustix/fs/mod.rs index 29e619a3..9dcd1e4a 100644 --- a/cap-primitives/src/rustix/fs/mod.rs +++ b/cap-primitives/src/rustix/fs/mod.rs @@ -1,6 +1,7 @@ mod copy_impl; mod create_dir_unchecked; mod dir_entry_inner; +#[cfg(not(target_os = "wasi"))] mod dir_options_ext; mod dir_utils; #[cfg(not(any(target_os = "android", target_os = "linux")))] @@ -23,7 +24,7 @@ mod remove_file_unchecked; mod remove_open_dir_by_searching; mod rename_unchecked; mod reopen_impl; -#[cfg(not(any(target_os = "android", target_os = "linux")))] +#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))] mod set_permissions_impl; #[cfg(not(any(target_os = "android", target_os = "linux")))] mod set_times_impl; @@ -62,8 +63,10 @@ pub(super) use file_path::file_path_by_ttyname_or_seaching; target_os = "ios" )))] pub(crate) use file_path::file_path_by_ttyname_or_seaching as file_path; +#[cfg(not(any(target_os = "android", target_os = "linux", target_os = "wasi")))] +pub(crate) use set_permissions_impl::set_permissions_impl; #[cfg(not(any(target_os = "android", target_os = "linux")))] -pub(crate) use {set_permissions_impl::set_permissions_impl, set_times_impl::set_times_impl}; +pub(crate) use set_times_impl::set_times_impl; #[rustfmt::skip] pub(crate) use crate::fs::{ @@ -80,6 +83,7 @@ pub(crate) use crate::fs::{ pub(crate) use copy_impl::copy_impl; pub(crate) use create_dir_unchecked::create_dir_unchecked; pub(crate) use dir_entry_inner::DirEntryInner; +#[cfg(not(target_os = "wasi"))] pub(crate) use dir_options_ext::DirOptionsExt; pub(crate) use dir_utils::*; pub(crate) use file_type_ext::FileTypeExt; diff --git a/cap-primitives/src/rustix/fs/oflags.rs b/cap-primitives/src/rustix/fs/oflags.rs index a4259473..85ffbd2a 100644 --- a/cap-primitives/src/rustix/fs/oflags.rs +++ b/cap-primitives/src/rustix/fs/oflags.rs @@ -21,8 +21,11 @@ pub(in super::super) fn compute_oflags(options: &OpenOptions) -> io::Result { diff --git a/cap-primitives/src/rustix/fs/permissions_ext.rs b/cap-primitives/src/rustix/fs/permissions_ext.rs index e0855ab9..ffbec959 100644 --- a/cap-primitives/src/rustix/fs/permissions_ext.rs +++ b/cap-primitives/src/rustix/fs/permissions_ext.rs @@ -4,9 +4,11 @@ use std::fs; #[derive(Debug, Clone, Eq, PartialEq)] pub(crate) struct PermissionsExt { + #[cfg(not(target_os = "wasi"))] mode: RawMode, } +#[cfg(not(target_os = "wasi"))] impl PermissionsExt { /// Constructs a new instance of `Self` from the given /// [`std::fs::Permissions`]. @@ -49,6 +51,7 @@ impl PermissionsExt { } } +#[cfg(not(target_os = "wasi"))] impl std::os::unix::fs::PermissionsExt for PermissionsExt { fn mode(&self) -> u32 { self.mode as u32 @@ -64,3 +67,10 @@ impl std::os::unix::fs::PermissionsExt for PermissionsExt { } } } + +#[cfg(target_os = "wasi")] +impl PermissionsExt { + pub(crate) fn default() -> Permissions { + Permissions { readonly: false } + } +} diff --git a/cap-std/src/fs/dir.rs b/cap-std/src/fs/dir.rs index 6e3e245c..e02a4d48 100644 --- a/cap-std/src/fs/dir.rs +++ b/cap-std/src/fs/dir.rs @@ -1,10 +1,12 @@ use crate::fs::{DirBuilder, File, Metadata, OpenOptions, ReadDir}; #[cfg(unix)] use crate::os::unix::net::{UnixDatagram, UnixListener, UnixStream}; +#[cfg(not(target_os = "wasi"))] +use cap_primitives::fs::set_permissions; use cap_primitives::fs::{ canonicalize, copy, create_dir, hard_link, open, open_ambient_dir, open_dir, open_parent_dir, read_base_dir, read_dir, read_link, remove_dir, remove_dir_all, remove_file, remove_open_dir, - remove_open_dir_all, rename, set_permissions, stat, DirOptions, FollowSymlinks, Permissions, + remove_open_dir_all, rename, stat, DirOptions, FollowSymlinks, Permissions, }; use cap_primitives::AmbientAuthority; #[cfg(not(windows))] @@ -125,6 +127,7 @@ impl Dir { /// builder. /// /// This corresponds to [`std::fs::DirBuilder::create`]. + #[cfg(not(target_os = "wasi"))] #[inline] pub fn create_dir_with>( &self, @@ -234,7 +237,7 @@ impl Dir { /// This corresponds to [`std::fs::metadata`], but only accesses paths /// relative to `self`. #[inline] - pub fn metadata>(&self, path: P) -> io::Result { + pub fn metadata>(&self, path: P) -> io::Result { stat(&self.std_file, path.as_ref(), FollowSymlinks::Yes) } @@ -364,6 +367,7 @@ impl Dir { /// paths relative to `self`. Also, on some platforms, this function /// may fail if the file or directory cannot be opened for reading or /// writing first. + #[cfg(not(target_os = "wasi"))] #[inline] pub fn set_permissions>(&self, path: P, perm: Permissions) -> io::Result<()> { set_permissions(&self.std_file, path.as_ref(), perm) diff --git a/cap-std/src/fs/file.rs b/cap-std/src/fs/file.rs index 9e22e33f..9240b2ad 100644 --- a/cap-std/src/fs/file.rs +++ b/cap-std/src/fs/file.rs @@ -8,8 +8,6 @@ use io_lifetimes::{AsFd, BorrowedFd, FromFd, IntoFd, OwnedFd}; #[cfg(windows)] use io_lifetimes::{AsHandle, BorrowedHandle, FromHandle, IntoHandle, OwnedHandle}; use std::io::{self, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; -#[cfg(target_os = "wasi")] -use std::path::Path; use std::path::Path; use std::{fmt, fs, process}; #[cfg(windows)] @@ -150,30 +148,16 @@ impl File { } } -#[cfg(not(target_os = "wasi"))] #[inline] fn metadata_from(file: &fs::File) -> io::Result { Metadata::from_file(file) } -#[cfg(target_os = "wasi")] -#[inline] -fn metadata_from(file: &fs::File) -> io::Result { - file.metadata() -} - -#[cfg(not(target_os = "wasi"))] #[inline] fn permissions_into_std(file: &fs::File, permissions: Permissions) -> io::Result { permissions.into_std(file) } -#[cfg(target_os = "wasi")] -#[inline] -fn permissions_into_std(_file: &fs::File, permissions: Permissions) -> io::Result { - permissions -} - #[cfg(not(windows))] impl FromRawFd for File { #[inline] @@ -479,15 +463,25 @@ impl std::os::unix::fs::FileExt for File { #[cfg(target_os = "wasi")] impl std::os::wasi::fs::FileExt for File { #[inline] - fn read_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result { + fn read_at(&self, bufs: &mut [u8], offset: u64) -> io::Result { self.std.read_at(bufs, offset) } #[inline] - fn write_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result { + fn write_at(&self, bufs: &[u8], offset: u64) -> io::Result { self.std.write_at(bufs, offset) } + #[inline] + fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result { + self.std.read_vectored_at(bufs, offset) + } + + #[inline] + fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result { + self.std.write_vectored_at(bufs, offset) + } + #[inline] fn tell(&self) -> std::result::Result { self.std.tell() diff --git a/cap-std/src/fs/mod.rs b/cap-std/src/fs/mod.rs index 29ff968e..e3ec3855 100644 --- a/cap-std/src/fs/mod.rs +++ b/cap-std/src/fs/mod.rs @@ -32,10 +32,5 @@ pub use dir_entry::DirEntry; pub use file::File; pub use read_dir::ReadDir; -// Re-export things from `cap_primitives` that we can use as-is. -#[cfg(not(target_os = "wasi"))] +// Re-export types from `cap_primitives`. pub use cap_primitives::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions}; - -// Re-export things from `std` that we can use as-is. -#[cfg(target_os = "wasi")] -pub use std::fs::{DirBuilder, FileType, Metadata, OpenOptions, Permissions}; From 9b3dd6c8016e13d0bb583a2fb29c40330194e547 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 3 Jan 2022 22:34:47 -0600 Subject: [PATCH 2/3] Fix fs_utf8 support for WASI. --- cap-std/src/fs_utf8/dir.rs | 2 ++ cap-std/src/fs_utf8/file.rs | 46 ++++++++++++++++++++----------------- 2 files changed, 27 insertions(+), 21 deletions(-) diff --git a/cap-std/src/fs_utf8/dir.rs b/cap-std/src/fs_utf8/dir.rs index dc491fe7..b696a5e2 100644 --- a/cap-std/src/fs_utf8/dir.rs +++ b/cap-std/src/fs_utf8/dir.rs @@ -110,6 +110,7 @@ impl Dir { /// builder. /// /// This corresponds to [`std::fs::DirBuilder::create`]. + #[cfg(not(target_os = "wasi"))] #[inline] pub fn create_dir_with>( &self, @@ -308,6 +309,7 @@ impl Dir { /// paths relative to `self`. Also, on some platforms, this function /// may fail if the file or directory cannot be opened for reading or /// writing first. + #[cfg(not(target_os = "wasi"))] pub fn set_permissions>( &self, path: P, diff --git a/cap-std/src/fs_utf8/file.rs b/cap-std/src/fs_utf8/file.rs index 9315188a..a597dbad 100644 --- a/cap-std/src/fs_utf8/file.rs +++ b/cap-std/src/fs_utf8/file.rs @@ -462,13 +462,23 @@ impl std::os::unix::fs::FileExt for File { #[cfg(target_os = "wasi")] impl std::os::wasi::fs::FileExt for File { #[inline] - fn read_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result { - self.cap_std.read_at(bufs, offset) + fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { + self.cap_std.read_at(buf, offset) + } + + #[inline] + fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { + self.cap_std.write_at(buf, offset) + } + + #[inline] + fn read_vectored_at(&self, bufs: &mut [IoSliceMut], offset: u64) -> io::Result { + self.cap_std.read_vectored_at(bufs, offset) } #[inline] - fn write_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result { - self.cap_std.write_at(bufs, offset) + fn write_vectored_at(&self, bufs: &[IoSlice], offset: u64) -> io::Result { + self.cap_std.write_vectored_at(bufs, offset) } #[inline] @@ -501,45 +511,39 @@ impl std::os::wasi::fs::FileExt for File { } #[inline] - fn create_directory>( - &self, - dir: P, - ) -> std::result::Result<(), std::io::Error> { - let path = from_utf8(path)?; - self.cap_std.create_directory(dir) + fn create_directory>(&self, path: P) -> std::result::Result<(), std::io::Error> { + let path = path.as_ref(); + self.cap_std.create_directory(path) } #[inline] - fn read_link>( + fn read_link>( &self, path: P, ) -> std::result::Result { - let path = from_utf8(path)?; + let path = path.as_ref(); self.cap_std.read_link(path) } #[inline] - fn metadata_at>( + fn metadata_at>( &self, lookup_flags: u32, path: P, ) -> std::result::Result { - let path = from_utf8(path)?; + let path = path.as_ref(); self.cap_std.metadata_at(lookup_flags, path) } #[inline] - fn remove_file>(&self, path: P) -> std::result::Result<(), std::io::Error> { - let path = from_utf8(path)?; + fn remove_file>(&self, path: P) -> std::result::Result<(), std::io::Error> { + let path = path.as_ref(); self.cap_std.remove_file(path) } #[inline] - fn remove_directory>( - &self, - path: P, - ) -> std::result::Result<(), std::io::Error> { - let path = from_utf8(path)?; + fn remove_directory>(&self, path: P) -> std::result::Result<(), std::io::Error> { + let path = path.as_ref(); self.cap_std.remove_directory(path) } } From c40d8fb81908ea4b4d02d2cbf4688da12c676f04 Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Mon, 3 Jan 2022 22:34:57 -0600 Subject: [PATCH 3/3] Add a WASI cross-check to CI. --- .github/workflows/main.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 22959050..b4f7f62f 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -150,6 +150,7 @@ jobs: riscv64gc-unknown-linux-gnu arm-unknown-linux-gnueabihf aarch64-linux-android + wasm32-wasi - run: cargo check --workspace --all-targets --all-features --release -vv - run: cargo check --workspace --all-targets --all-features --release -vv --target=x86_64-unknown-linux-musl - run: cargo check --workspace --all-targets --all-features --release -vv --target=x86_64-unknown-linux-gnux32 @@ -163,6 +164,7 @@ jobs: - run: cargo check --workspace --all-targets --all-features --release -vv --target=riscv64gc-unknown-linux-gnu - run: cargo check --workspace --all-targets --all-features --release -vv --target=arm-unknown-linux-gnueabihf - run: cargo check --workspace --all-targets --all-features --release -vv --target=aarch64-linux-android + - run: cd cap-std && cargo check --features=fs_utf8 --release -vv check_cross_nightly_windows: name: Check Cross-Compilation on Rust nightly on Windows