use crate::fs::{FollowSymlinks, OpenOptionsExt}; /// Options and flags which can be used to configure how a file is opened. /// /// This corresponds to [`std::fs::OpenOptions`]. /// /// This `OpenOptions` has no `open` method. To open a file with an /// `OptionOptions`, first obtain a [`Dir`] containing the path, and then call /// [`Dir::open_with`]. /// /// [`Dir`]: https://docs.rs/cap-std/latest/cap_std/fs/struct.Dir.html /// [`Dir::open_with`]: https://docs.rs/cap-std/latest/cap_std/fs/struct.Dir.html#method.open_with /// ///
/// We need to define our own version because the libstd `OpenOptions` doesn't /// have public accessors that we can use. ///
#[derive(Debug, Clone)] pub struct OpenOptions { pub(crate) read: bool, pub(crate) write: bool, pub(crate) append: bool, pub(crate) truncate: bool, pub(crate) create: bool, pub(crate) create_new: bool, pub(crate) dir_required: bool, pub(crate) maybe_dir: bool, pub(crate) sync: bool, pub(crate) dsync: bool, pub(crate) rsync: bool, pub(crate) nonblock: bool, pub(crate) readdir_required: bool, pub(crate) follow: FollowSymlinks, #[cfg(any(unix, windows, target_os = "vxworks"))] pub(crate) ext: OpenOptionsExt, } impl OpenOptions { /// Creates a blank new set of options ready for configuration. /// /// This corresponds to [`std::fs::OpenOptions::new`]. #[allow(clippy::new_without_default)] #[inline] pub const fn new() -> Self { Self { read: false, write: false, append: false, truncate: false, create: false, create_new: false, dir_required: false, maybe_dir: false, sync: false, dsync: false, rsync: false, nonblock: false, readdir_required: false, follow: FollowSymlinks::Yes, #[cfg(any(unix, windows, target_os = "vxworks"))] ext: OpenOptionsExt::new(), } } /// Sets the option for read access. /// /// This corresponds to [`std::fs::OpenOptions::read`]. #[inline] pub fn read(&mut self, read: bool) -> &mut Self { self.read = read; self } /// Sets the option for write access. /// /// This corresponds to [`std::fs::OpenOptions::write`]. #[inline] pub fn write(&mut self, write: bool) -> &mut Self { self.write = write; self } /// Sets the option for the append mode. /// /// This corresponds to [`std::fs::OpenOptions::append`]. #[inline] pub fn append(&mut self, append: bool) -> &mut Self { self.append = append; self } /// Sets the option for truncating a previous file. /// /// This corresponds to [`std::fs::OpenOptions::truncate`]. #[inline] pub fn truncate(&mut self, truncate: bool) -> &mut Self { self.truncate = truncate; self } /// Sets the option to create a new file. /// /// This corresponds to [`std::fs::OpenOptions::create`]. #[inline] pub fn create(&mut self, create: bool) -> &mut Self { self.create = create; self } /// Sets the option to always create a new file. /// /// This corresponds to [`std::fs::OpenOptions::create_new`]. #[inline] pub fn create_new(&mut self, create_new: bool) -> &mut Self { self.create_new = create_new; self } /// Sets the option to enable or suppress following of symlinks. #[inline] pub(crate) fn follow(&mut self, follow: FollowSymlinks) -> &mut Self { self.follow = follow; self } /// Sets the option to enable an error if the opened object is not a /// directory. #[inline] pub(crate) fn dir_required(&mut self, dir_required: bool) -> &mut Self { self.dir_required = dir_required; self } /// Sets the option to disable an error if the opened object is a /// directory. #[inline] pub(crate) fn maybe_dir(&mut self, maybe_dir: bool) -> &mut Self { self.maybe_dir = maybe_dir; self } /// Requests write operations complete as defined by synchronized I/O file /// integrity completion. #[inline] pub(crate) fn sync(&mut self, enable: bool) -> &mut Self { self.sync = enable; self } /// Requests write operations complete as defined by synchronized I/O data /// integrity completion. #[inline] pub(crate) fn dsync(&mut self, enable: bool) -> &mut Self { self.dsync = enable; self } /// Requests read operations complete as defined by the level of integrity /// specified by `sync` and `dsync`. #[inline] pub(crate) fn rsync(&mut self, enable: bool) -> &mut Self { self.rsync = enable; self } /// Requests that I/O operations fail with `std::io::ErrorKind::WouldBlock` /// if they would otherwise block. /// /// This option is commonly not implemented for regular files, so blocking /// may still occur. #[inline] pub(crate) fn nonblock(&mut self, enable: bool) -> &mut Self { self.nonblock = enable; self } /// Sets the option to request the ability to read directory entries. #[inline] pub(crate) fn readdir_required(&mut self, readdir_required: bool) -> &mut Self { self.readdir_required = readdir_required; self } /// Wrapper to allow `follow` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsFollowExt` instead of calling /// this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_follow(&mut self, follow: FollowSymlinks) -> &mut Self { self.follow(follow) } /// Wrapper to allow `maybe_dir` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsMaybeDirExt` instead of /// calling this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_maybe_dir(&mut self, maybe_dir: bool) -> &mut Self { self.maybe_dir(maybe_dir) } /// Wrapper to allow `sync` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsSyncExt` instead of /// calling this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_sync(&mut self, enable: bool) -> &mut Self { self.sync(enable) } /// Wrapper to allow `dsync` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsSyncExt` instead of /// calling this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_dsync(&mut self, enable: bool) -> &mut Self { self.dsync(enable) } /// Wrapper to allow `rsync` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsSyncExt` instead of /// calling this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_rsync(&mut self, enable: bool) -> &mut Self { self.rsync(enable) } /// Wrapper to allow `nonblock` to be exposed by the `cap-fs-ext` crate. /// /// This is hidden from the main API since this functionality isn't present /// in `std`. Use `cap_fs_ext::OpenOptionsSyncExt` instead of /// calling this directly. #[doc(hidden)] #[inline] pub fn _cap_fs_ext_nonblock(&mut self, enable: bool) -> &mut Self { self.nonblock(enable) } } #[cfg(unix)] impl std::os::unix::fs::OpenOptionsExt for OpenOptions { #[inline] fn mode(&mut self, mode: u32) -> &mut Self { self.ext.mode(mode); self } #[inline] fn custom_flags(&mut self, flags: i32) -> &mut Self { self.ext.custom_flags(flags); self } } #[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] fn mode(&mut self, mode: u32) -> &mut Self { self.ext.mode(mode); self } #[inline] fn custom_flags(&mut self, flags: i32) -> &mut Self { self.ext.custom_flags(flags); self } } #[cfg(windows)] impl std::os::windows::fs::OpenOptionsExt for OpenOptions { #[inline] fn access_mode(&mut self, access: u32) -> &mut Self { self.ext.access_mode(access); self } /// To prevent race conditions on Windows, handles for directories must be /// opened without `FILE_SHARE_DELETE`. #[inline] fn share_mode(&mut self, val: u32) -> &mut Self { self.ext.share_mode(val); self } #[inline] fn custom_flags(&mut self, flags: u32) -> &mut Self { self.ext.custom_flags(flags); self } #[inline] fn attributes(&mut self, val: u32) -> &mut Self { self.ext.attributes(val); self } #[inline] fn security_qos_flags(&mut self, flags: u32) -> &mut Self { self.ext.security_qos_flags(flags); self } } #[cfg(feature = "arbitrary")] impl arbitrary::Arbitrary<'_> for OpenOptions { fn arbitrary(u: &mut arbitrary::Unstructured<'_>) -> arbitrary::Result { use arbitrary::Arbitrary; let (read, write) = match u.int_in_range(0..=2)? { 0 => (true, false), 1 => (false, true), 2 => (true, true), _ => panic!(), }; // TODO: `OpenOptionsExt` options. Ok(Self::new() .read(read) .write(write) .create(::arbitrary(u)?) .append(::arbitrary(u)?) .truncate(::arbitrary(u)?) .create(::arbitrary(u)?) .create_new(::arbitrary(u)?) .dir_required(::arbitrary(u)?) .maybe_dir(::arbitrary(u)?) .sync(::arbitrary(u)?) .dsync(::arbitrary(u)?) .rsync(::arbitrary(u)?) .nonblock(::arbitrary(u)?) .readdir_required(::arbitrary(u)?) .follow(::arbitrary(u)?) .clone()) } }