diff --git a/Cargo.lock b/Cargo.lock index d700ae6887..4d7c5e9e38 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2460,6 +2460,7 @@ name = "wasi-c2" version = "0.22.0" dependencies = [ "anyhow", + "bitflags", "cap-fs-ext", "cap-rand", "cap-std", diff --git a/crates/wasi-c2/Cargo.toml b/crates/wasi-c2/Cargo.toml index 5115ef6b03..f82015d450 100644 --- a/crates/wasi-c2/Cargo.toml +++ b/crates/wasi-c2/Cargo.toml @@ -31,6 +31,7 @@ cap-time-ext = "0.9" cap-rand = "0.9" fs-set-times = "0.2.2" cfg-if = "1" +bitflags = "1.2" [badges] maintenance = { status = "actively-developed" } diff --git a/crates/wasi-c2/src/dir.rs b/crates/wasi-c2/src/dir.rs index bd5bc52643..9269a3e83b 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::{FdFlags, FileCaps, FileType, Filestat, OFlags, WasiFile}; +use bitflags::bitflags; use cap_fs_ext::SystemTimeSpec; use std::any::Any; use std::convert::TryInto; @@ -66,7 +67,7 @@ impl DirEntry { } } pub fn get_cap(&self, caps: DirCaps) -> Result<&dyn WasiDir, Error> { - if self.caps.contains(&caps) { + if self.caps.contains(caps) { Ok(self.dir.deref()) } else { Err(Error::DirNotCapable { @@ -76,7 +77,7 @@ impl DirEntry { } } pub fn drop_caps_to(&mut self, caps: DirCaps, file_caps: FileCaps) -> Result<(), Error> { - if self.caps.contains(&caps) && self.file_caps.contains(&file_caps) { + if self.caps.contains(caps) && self.file_caps.contains(file_caps) { self.caps = caps; self.file_caps = file_caps; Ok(()) @@ -85,10 +86,10 @@ impl DirEntry { } } pub fn child_dir_caps(&self, desired_caps: DirCaps) -> DirCaps { - self.caps.intersection(&desired_caps) + self.caps & desired_caps } pub fn child_file_caps(&self, desired_caps: FileCaps) -> FileCaps { - self.file_caps.intersection(&desired_caps) + self.file_caps & desired_caps } pub fn get_dir_fdstat(&self) -> DirFdStat { DirFdStat { @@ -101,75 +102,24 @@ impl DirEntry { } } -#[derive(Debug, Clone, Copy)] -pub struct DirCaps { - flags: u32, -} - -impl DirCaps { - pub fn empty() -> Self { - DirCaps { flags: 0 } - } - - /// Checks if `other` is a subset of those capabilties: - pub fn contains(&self, other: &Self) -> bool { - self.flags & other.flags == other.flags - } - - /// Intersection of two sets of flags (bitwise and) - pub fn intersection(&self, rhs: &Self) -> Self { - DirCaps { - flags: self.flags & rhs.flags, - } - } - pub const CREATE_DIRECTORY: Self = DirCaps { flags: 1 }; - pub const CREATE_FILE: Self = DirCaps { flags: 2 }; - pub const LINK_SOURCE: Self = DirCaps { flags: 4 }; - pub const LINK_TARGET: Self = DirCaps { flags: 8 }; - pub const OPEN: Self = DirCaps { flags: 16 }; - pub const READDIR: Self = DirCaps { flags: 32 }; - pub const READLINK: Self = DirCaps { flags: 64 }; - pub const RENAME_SOURCE: Self = DirCaps { flags: 128 }; - pub const RENAME_TARGET: Self = DirCaps { flags: 256 }; - 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 - - pub fn all() -> DirCaps { - Self::CREATE_DIRECTORY - | Self::CREATE_FILE - | Self::LINK_SOURCE - | Self::LINK_TARGET - | Self::OPEN - | Self::READDIR - | Self::READLINK - | Self::RENAME_SOURCE - | Self::RENAME_TARGET - | Self::SYMLINK - | Self::REMOVE_DIRECTORY - | Self::UNLINK_FILE - | Self::PATH_FILESTAT_GET - | Self::PATH_FILESTAT_SET_TIMES - | Self::FILESTAT_GET - | Self::FILESTAT_SET_TIMES - } -} - -impl std::ops::BitOr for DirCaps { - type Output = DirCaps; - fn bitor(self, rhs: DirCaps) -> DirCaps { - DirCaps { - flags: self.flags | rhs.flags, - } +bitflags! { + pub struct DirCaps: u32 { + const CREATE_DIRECTORY = 0b1; + const CREATE_FILE = 0b10; + const LINK_SOURCE = 0b100; + const LINK_TARGET = 0b1000; + const OPEN = 0b10000; + const READDIR = 0b100000; + const READLINK = 0b1000000; + const RENAME_SOURCE = 0b10000000; + const RENAME_TARGET = 0b100000000; + const SYMLINK = 0b1000000000; + const REMOVE_DIRECTORY = 0b10000000000; + const UNLINK_FILE = 0b100000000000; + const PATH_FILESTAT_GET = 0b1000000000000; + const PATH_FILESTAT_SET_TIMES = 0b10000000000000; + const FILESTAT_GET = 0b100000000000000; + const FILESTAT_SET_TIMES = 0b1000000000000000; } } @@ -229,20 +179,20 @@ impl WasiDir for cap_std::fs::Dir { let mut opts = cap_std::fs::OpenOptions::new(); - if oflags.contains(&(OFlags::CREATE | OFlags::EXCLUSIVE)) { + if oflags.contains(OFlags::CREATE | OFlags::EXCLUSIVE) { opts.create_new(true); opts.write(true); - } else if oflags.contains(&OFlags::CREATE) { + } else if oflags.contains(OFlags::CREATE) { opts.create(true); opts.write(true); } - if oflags.contains(&OFlags::TRUNCATE) { + if oflags.contains(OFlags::TRUNCATE) { opts.truncate(true); } - if caps.contains(&FileCaps::WRITE) - || caps.contains(&FileCaps::DATASYNC) - || caps.contains(&FileCaps::ALLOCATE) - || caps.contains(&FileCaps::FILESTAT_SET_SIZE) + if caps.contains(FileCaps::WRITE) + || caps.contains(FileCaps::DATASYNC) + || caps.contains(FileCaps::ALLOCATE) + || caps.contains(FileCaps::FILESTAT_SET_SIZE) { opts.write(true); } else { @@ -251,10 +201,10 @@ impl WasiDir for cap_std::fs::Dir { // get_cap check. opts.read(true); } - if caps.contains(&FileCaps::READ) { + if caps.contains(FileCaps::READ) { opts.read(true); } - if fdflags.contains(&FdFlags::APPEND) { + if fdflags.contains(FdFlags::APPEND) { opts.append(true); } // XXX what about rest of fdflags - dsync, sync become oflags. diff --git a/crates/wasi-c2/src/file.rs b/crates/wasi-c2/src/file.rs index ab0d04c093..0f37792936 100644 --- a/crates/wasi-c2/src/file.rs +++ b/crates/wasi-c2/src/file.rs @@ -1,4 +1,5 @@ use crate::Error; +use bitflags::bitflags; use fs_set_times::SetTimes; use std::ops::Deref; use system_interface::fs::FileIoExt; @@ -50,60 +51,22 @@ impl From<&cap_std::fs::FileType> for FileType { } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct FdFlags { - flags: u32, -} - -impl FdFlags { - /// Checks if `other` is a subset of those capabilties: - pub fn contains(&self, other: &Self) -> bool { - self.flags & other.flags == other.flags - } - pub fn empty() -> FdFlags { - FdFlags { flags: 0 } - } - pub const APPEND: FdFlags = FdFlags { flags: 1 }; - pub const DSYNC: FdFlags = FdFlags { flags: 2 }; - pub const NONBLOCK: FdFlags = FdFlags { flags: 4 }; - pub const RSYNC: FdFlags = FdFlags { flags: 8 }; - pub const SYNC: FdFlags = FdFlags { flags: 16 }; - // etc -} - -impl std::ops::BitOr for FdFlags { - type Output = FdFlags; - fn bitor(self, rhs: FdFlags) -> FdFlags { - FdFlags { - flags: self.flags | rhs.flags, - } +bitflags! { + pub struct FdFlags: u32 { + const APPEND = 0b1; + const DSYNC = 0b10; + const NONBLOCK = 0b100; + const RSYNC = 0b1000; + const SYNC = 0b10000; } } -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct OFlags { - flags: u32, -} - -impl OFlags { - /// Checks if `other` is a subset of those capabilties: - pub fn contains(&self, other: &Self) -> bool { - self.flags & other.flags == other.flags - } - pub fn empty() -> Self { - OFlags { flags: 0 } - } - pub const CREATE: OFlags = OFlags { flags: 1 }; - pub const DIRECTORY: OFlags = OFlags { flags: 2 }; - pub const EXCLUSIVE: OFlags = OFlags { flags: 4 }; - pub const TRUNCATE: OFlags = OFlags { flags: 8 }; -} -impl std::ops::BitOr for OFlags { - type Output = OFlags; - fn bitor(self, rhs: OFlags) -> OFlags { - OFlags { - flags: self.flags | rhs.flags, - } +bitflags! { + pub struct OFlags: u32 { + const CREATE = 0b1; + const DIRECTORY = 0b10; + const EXCLUSIVE = 0b100; + const TRUNCATE = 0b1000; } } @@ -130,7 +93,7 @@ impl FileEntry { } pub fn get_cap(&self, caps: FileCaps) -> Result<&dyn WasiFile, Error> { - if self.caps.contains(&caps) { + if self.caps.contains(caps) { Ok(self.file.deref()) } else { Err(Error::FileNotCapable { @@ -141,7 +104,7 @@ impl FileEntry { } pub fn drop_caps_to(&mut self, caps: FileCaps) -> Result<(), Error> { - if self.caps.contains(&caps) { + if self.caps.contains(caps) { self.caps = caps; Ok(()) } else { @@ -158,63 +121,20 @@ impl FileEntry { } } -#[derive(Debug, Clone, Copy)] -pub struct FileCaps { - flags: u32, -} - -impl FileCaps { - pub fn empty() -> Self { - FileCaps { flags: 0 } - } - - /// Checks if `other` is a subset of those capabilties: - pub fn contains(&self, other: &Self) -> bool { - self.flags & other.flags == other.flags - } - - /// Intersection of two sets of flags (bitwise and) - pub fn intersection(&self, rhs: &Self) -> Self { - FileCaps { - flags: self.flags & rhs.flags, - } - } - - pub const DATASYNC: Self = FileCaps { flags: 1 }; - pub const READ: Self = FileCaps { flags: 2 }; - pub const SEEK: Self = FileCaps { flags: 4 }; - pub const FDSTAT_SET_FLAGS: Self = FileCaps { flags: 8 }; - pub const SYNC: Self = FileCaps { flags: 16 }; - pub const TELL: Self = FileCaps { flags: 32 }; - 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 }; - - pub fn all() -> FileCaps { - Self::DATASYNC - | Self::READ - | Self::SEEK - | Self::FDSTAT_SET_FLAGS - | Self::SYNC - | Self::TELL - | Self::WRITE - | Self::ADVISE - | Self::ALLOCATE - | Self::FILESTAT_GET - | Self::FILESTAT_SET_SIZE - | Self::FILESTAT_SET_TIMES - } -} - -impl std::ops::BitOr for FileCaps { - type Output = FileCaps; - fn bitor(self, rhs: FileCaps) -> FileCaps { - FileCaps { - flags: self.flags | rhs.flags, - } +bitflags! { + pub struct FileCaps : u32 { + const DATASYNC = 0b1; + const READ = 0b10; + const SEEK = 0b100; + const FDSTAT_SET_FLAGS = 0b1000; + const SYNC = 0b10000; + const TELL = 0b100000; + const WRITE = 0b1000000; + const ADVISE = 0b10000000; + const ALLOCATE = 0b100000000; + const FILESTAT_GET = 0b1000000000; + const FILESTAT_SET_SIZE = 0b10000000000; + const FILESTAT_SET_TIMES = 0b100000000000; } } diff --git a/crates/wasi-c2/src/snapshots/preview_1.rs b/crates/wasi-c2/src/snapshots/preview_1.rs index 08c591ccf9..df7d6566b5 100644 --- a/crates/wasi-c2/src/snapshots/preview_1.rs +++ b/crates/wasi-c2/src/snapshots/preview_1.rs @@ -768,10 +768,10 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { let oflags = OFlags::from(&oflags); let fdflags = FdFlags::from(&fdflags); let path = path.as_str()?; - if oflags.contains(&OFlags::DIRECTORY) { - if oflags.contains(&OFlags::CREATE) - || oflags.contains(&OFlags::EXCLUSIVE) - || oflags.contains(&OFlags::TRUNCATE) + if oflags.contains(OFlags::DIRECTORY) { + if oflags.contains(OFlags::CREATE) + || oflags.contains(OFlags::EXCLUSIVE) + || oflags.contains(OFlags::TRUNCATE) { return Err(Error::Inval); } @@ -787,7 +787,7 @@ impl<'a> wasi_snapshot_preview1::WasiSnapshotPreview1 for WasiCtx { Ok(types::Fd::from(fd)) } else { let mut required_caps = DirCaps::OPEN; - if oflags.contains(&OFlags::CREATE) { + if oflags.contains(OFlags::CREATE) { required_caps = required_caps | DirCaps::CREATE_FILE; } @@ -976,40 +976,40 @@ impl From<&DirFdStat> for types::Fdstat { impl From<&FileCaps> for types::Rights { fn from(caps: &FileCaps) -> types::Rights { let mut rights = types::Rights::empty(); - if caps.contains(&FileCaps::DATASYNC) { + if caps.contains(FileCaps::DATASYNC) { rights = rights | types::Rights::FD_DATASYNC; } - if caps.contains(&FileCaps::READ) { + if caps.contains(FileCaps::READ) { rights = rights | types::Rights::FD_READ; } - if caps.contains(&FileCaps::SEEK) { + if caps.contains(FileCaps::SEEK) { rights = rights | types::Rights::FD_SEEK; } - if caps.contains(&FileCaps::FDSTAT_SET_FLAGS) { + if caps.contains(FileCaps::FDSTAT_SET_FLAGS) { rights = rights | types::Rights::FD_FDSTAT_SET_FLAGS; } - if caps.contains(&FileCaps::SYNC) { + if caps.contains(FileCaps::SYNC) { rights = rights | types::Rights::FD_SYNC; } - if caps.contains(&FileCaps::TELL) { + if caps.contains(FileCaps::TELL) { rights = rights | types::Rights::FD_TELL; } - if caps.contains(&FileCaps::WRITE) { + if caps.contains(FileCaps::WRITE) { rights = rights | types::Rights::FD_WRITE; } - if caps.contains(&FileCaps::ADVISE) { + if caps.contains(FileCaps::ADVISE) { rights = rights | types::Rights::FD_ADVISE; } - if caps.contains(&FileCaps::ALLOCATE) { + if caps.contains(FileCaps::ALLOCATE) { rights = rights | types::Rights::FD_ALLOCATE; } - if caps.contains(&FileCaps::FILESTAT_GET) { + if caps.contains(FileCaps::FILESTAT_GET) { rights = rights | types::Rights::FD_FILESTAT_GET; } - if caps.contains(&FileCaps::FILESTAT_SET_SIZE) { + if caps.contains(FileCaps::FILESTAT_SET_SIZE) { rights = rights | types::Rights::FD_FILESTAT_SET_SIZE; } - if caps.contains(&FileCaps::FILESTAT_SET_TIMES) { + if caps.contains(FileCaps::FILESTAT_SET_TIMES) { rights = rights | types::Rights::FD_FILESTAT_SET_TIMES; } rights @@ -1064,52 +1064,52 @@ impl From<&types::Rights> for FileCaps { impl From<&DirCaps> for types::Rights { fn from(caps: &DirCaps) -> types::Rights { let mut rights = types::Rights::empty(); - if caps.contains(&DirCaps::CREATE_DIRECTORY) { + if caps.contains(DirCaps::CREATE_DIRECTORY) { rights = rights | types::Rights::PATH_CREATE_DIRECTORY; } - if caps.contains(&DirCaps::CREATE_FILE) { + if caps.contains(DirCaps::CREATE_FILE) { rights = rights | types::Rights::PATH_CREATE_FILE; } - if caps.contains(&DirCaps::LINK_SOURCE) { + if caps.contains(DirCaps::LINK_SOURCE) { rights = rights | types::Rights::PATH_LINK_SOURCE; } - if caps.contains(&DirCaps::LINK_TARGET) { + if caps.contains(DirCaps::LINK_TARGET) { rights = rights | types::Rights::PATH_LINK_TARGET; } - if caps.contains(&DirCaps::OPEN) { + if caps.contains(DirCaps::OPEN) { rights = rights | types::Rights::PATH_OPEN; } - if caps.contains(&DirCaps::READDIR) { + if caps.contains(DirCaps::READDIR) { rights = rights | types::Rights::FD_READDIR; } - if caps.contains(&DirCaps::READLINK) { + if caps.contains(DirCaps::READLINK) { rights = rights | types::Rights::PATH_READLINK; } - if caps.contains(&DirCaps::RENAME_SOURCE) { + if caps.contains(DirCaps::RENAME_SOURCE) { rights = rights | types::Rights::PATH_RENAME_SOURCE; } - if caps.contains(&DirCaps::RENAME_TARGET) { + if caps.contains(DirCaps::RENAME_TARGET) { rights = rights | types::Rights::PATH_RENAME_TARGET; } - if caps.contains(&DirCaps::SYMLINK) { + if caps.contains(DirCaps::SYMLINK) { rights = rights | types::Rights::PATH_SYMLINK; } - if caps.contains(&DirCaps::REMOVE_DIRECTORY) { + if caps.contains(DirCaps::REMOVE_DIRECTORY) { rights = rights | types::Rights::PATH_REMOVE_DIRECTORY; } - if caps.contains(&DirCaps::UNLINK_FILE) { + if caps.contains(DirCaps::UNLINK_FILE) { rights = rights | types::Rights::PATH_UNLINK_FILE; } - if caps.contains(&DirCaps::PATH_FILESTAT_GET) { + if caps.contains(DirCaps::PATH_FILESTAT_GET) { rights = rights | types::Rights::PATH_FILESTAT_GET; } - if caps.contains(&DirCaps::PATH_FILESTAT_SET_TIMES) { + if caps.contains(DirCaps::PATH_FILESTAT_SET_TIMES) { rights = rights | types::Rights::PATH_FILESTAT_SET_TIMES; } - if caps.contains(&DirCaps::FILESTAT_GET) { + if caps.contains(DirCaps::FILESTAT_GET) { rights = rights | types::Rights::FD_FILESTAT_GET; } - if caps.contains(&DirCaps::FILESTAT_SET_TIMES) { + if caps.contains(DirCaps::FILESTAT_SET_TIMES) { rights = rights | types::Rights::FD_FILESTAT_SET_TIMES; } rights @@ -1189,19 +1189,19 @@ impl From<&FileType> for types::Filetype { impl From<&FdFlags> for types::Fdflags { fn from(fdflags: &FdFlags) -> types::Fdflags { let mut out = types::Fdflags::empty(); - if fdflags.contains(&FdFlags::APPEND) { + if fdflags.contains(FdFlags::APPEND) { out = out | types::Fdflags::APPEND; } - if fdflags.contains(&FdFlags::DSYNC) { + if fdflags.contains(FdFlags::DSYNC) { out = out | types::Fdflags::DSYNC; } - if fdflags.contains(&FdFlags::NONBLOCK) { + if fdflags.contains(FdFlags::NONBLOCK) { out = out | types::Fdflags::NONBLOCK; } - if fdflags.contains(&FdFlags::RSYNC) { + if fdflags.contains(FdFlags::RSYNC) { out = out | types::Fdflags::RSYNC; } - if fdflags.contains(&FdFlags::SYNC) { + if fdflags.contains(FdFlags::SYNC) { out = out | types::Fdflags::SYNC; } out @@ -1252,16 +1252,16 @@ impl From<&types::Oflags> for OFlags { impl From<&OFlags> for types::Oflags { fn from(oflags: &OFlags) -> types::Oflags { let mut out = types::Oflags::empty(); - if oflags.contains(&OFlags::CREATE) { + if oflags.contains(OFlags::CREATE) { out = out | types::Oflags::CREAT; } - if oflags.contains(&OFlags::DIRECTORY) { + if oflags.contains(OFlags::DIRECTORY) { out = out | types::Oflags::DIRECTORY; } - if oflags.contains(&OFlags::EXCLUSIVE) { + if oflags.contains(OFlags::EXCLUSIVE) { out = out | types::Oflags::EXCL; } - if oflags.contains(&OFlags::TRUNCATE) { + if oflags.contains(OFlags::TRUNCATE) { out = out | types::Oflags::TRUNC; } out