From bc374af3b978fa485dad04bcbae3c27b40ca6359 Mon Sep 17 00:00:00 2001 From: Jun Ouyang Date: Tue, 2 Apr 2024 15:05:55 +0800 Subject: [PATCH] feat: introduce macos mount API support (#2347) * feat: introduce macos mount API support * feat: add doc comment * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code * feat: fix code --- build.rs | 1 + changelog/2347.added.md | 1 + src/mount/apple.rs | 122 +++++++++++++++++++++ src/mount/{bsd.rs => bsd_without_apple.rs} | 5 +- src/mount/mod.rs | 14 ++- test/mount/mod.rs | 6 + test/{ => mount}/test_mount.rs | 0 test/mount/test_mount_apple.rs | 8 ++ test/{ => mount}/test_nmount.rs | 0 test/test.rs | 5 +- 10 files changed, 151 insertions(+), 11 deletions(-) create mode 100644 changelog/2347.added.md create mode 100644 src/mount/apple.rs rename src/mount/{bsd.rs => bsd_without_apple.rs} (98%) create mode 100644 test/mount/mod.rs rename test/{ => mount}/test_mount.rs (100%) create mode 100644 test/mount/test_mount_apple.rs rename test/{ => mount}/test_nmount.rs (100%) diff --git a/build.rs b/build.rs index ecadc04f5d..fd19de0fe9 100644 --- a/build.rs +++ b/build.rs @@ -19,6 +19,7 @@ fn main() { // cfg aliases we would like to use apple_targets: { any(ios, macos, watchos, tvos) }, bsd: { any(freebsd, dragonfly, netbsd, openbsd, apple_targets) }, + bsd_without_apple: { any(freebsd, dragonfly, netbsd, openbsd) }, linux_android: { any(android, linux) }, freebsdlike: { any(dragonfly, freebsd) }, netbsdlike: { any(netbsd, openbsd) }, diff --git a/changelog/2347.added.md b/changelog/2347.added.md new file mode 100644 index 0000000000..9000d61deb --- /dev/null +++ b/changelog/2347.added.md @@ -0,0 +1 @@ +Add `mount` and `unmount` API for apple targets. diff --git a/src/mount/apple.rs b/src/mount/apple.rs new file mode 100644 index 0000000000..6759ed20bb --- /dev/null +++ b/src/mount/apple.rs @@ -0,0 +1,122 @@ +use crate::{Errno, NixPath, Result}; +use libc::c_int; + +libc_bitflags!( + /// Used with [`mount()`] and [`unmount()`]. + pub struct MntFlags: c_int { + /// Do not interpret special files on the filesystem. + MNT_NODEV; + /// Enable data protection on the filesystem if the filesystem is configured for it. + MNT_CPROTECT; + /// file system is quarantined + MNT_QUARANTINE; + /// filesystem is stored locally + MNT_LOCAL; + /// quotas are enabled on filesystem + MNT_QUOTA; + /// identifies the root filesystem + MNT_ROOTFS; + /// file system is not appropriate path to user data + MNT_DONTBROWSE; + /// VFS will ignore ownership information on filesystem objects + MNT_IGNORE_OWNERSHIP; + /// filesystem was mounted by automounter + MNT_AUTOMOUNTED; + /// filesystem is journaled + MNT_JOURNALED; + /// Don't allow user extended attributes + MNT_NOUSERXATTR; + /// filesystem should defer writes + MNT_DEFWRITE; + /// don't block unmount if not responding + MNT_NOBLOCK; + /// file system is exported + MNT_EXPORTED; + /// file system written asynchronously + MNT_ASYNC; + /// Force a read-write mount even if the file system appears to be + /// unclean. + MNT_FORCE; + /// MAC support for objects. + MNT_MULTILABEL; + /// Do not update access times. + MNT_NOATIME; + /// Disallow program execution. + MNT_NOEXEC; + /// Do not honor setuid or setgid bits on files when executing them. + MNT_NOSUID; + /// Mount read-only. + MNT_RDONLY; + /// Causes the vfs subsystem to update its data structures pertaining to + /// the specified already mounted file system. + MNT_RELOAD; + /// Create a snapshot of the file system. + MNT_SNAPSHOT; + /// All I/O to the file system should be done synchronously. + MNT_SYNCHRONOUS; + /// Union with underlying fs. + MNT_UNION; + /// Indicates that the mount command is being applied to an already + /// mounted file system. + MNT_UPDATE; + } +); + +/// Mount a file system. +/// +/// # Arguments +/// - `source` - Specifies the file system. e.g. `/dev/sd0`. +/// - `target` - Specifies the destination. e.g. `/mnt`. +/// - `flags` - Optional flags controlling the mount. +/// - `data` - Optional file system specific data. +/// +/// # see also +/// [`mount`](https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html) +pub fn mount< + P1: ?Sized + NixPath, + P2: ?Sized + NixPath, + P3: ?Sized + NixPath, +>( + source: &P1, + target: &P2, + flags: MntFlags, + data: Option<&P3>, +) -> Result<()> { + fn with_opt_nix_path(p: Option<&P>, f: F) -> Result + where + P: ?Sized + NixPath, + F: FnOnce(*const libc::c_char) -> T, + { + match p { + Some(path) => path.with_nix_path(|p_str| f(p_str.as_ptr())), + None => Ok(f(std::ptr::null())), + } + } + + let res = source.with_nix_path(|s| { + target.with_nix_path(|t| { + with_opt_nix_path(data, |d| unsafe { + libc::mount( + s.as_ptr(), + t.as_ptr(), + flags.bits(), + d.cast_mut().cast(), + ) + }) + }) + })???; + + Errno::result(res).map(drop) +} + +/// Umount the file system mounted at `target`. +pub fn unmount

(target: &P, flags: MntFlags) -> Result<()> +where + P: ?Sized + NixPath, +{ + let res = target.with_nix_path(|cstr| unsafe { + libc::unmount(cstr.as_ptr(), flags.bits()) + })?; + + Errno::result(res).map(drop) +} diff --git a/src/mount/bsd.rs b/src/mount/bsd_without_apple.rs similarity index 98% rename from src/mount/bsd.rs rename to src/mount/bsd_without_apple.rs index 248e0ab1d2..ae9eed7c0e 100644 --- a/src/mount/bsd.rs +++ b/src/mount/bsd_without_apple.rs @@ -30,7 +30,7 @@ libc_bitflags!( #[cfg(target_os = "freebsd")] MNT_GJOURNAL; /// MAC support for objects. - #[cfg(any(apple_targets, target_os = "freebsd"))] + #[cfg(target_os = "freebsd")] MNT_MULTILABEL; /// Disable read clustering. #[cfg(freebsdlike)] @@ -58,7 +58,7 @@ libc_bitflags!( /// Create a snapshot of the file system. /// /// See [mksnap_ffs(8)](https://www.freebsd.org/cgi/man.cgi?query=mksnap_ffs) - #[cfg(any(apple_targets, target_os = "freebsd"))] + #[cfg(target_os = "freebsd")] MNT_SNAPSHOT; /// Using soft updates. #[cfg(any(freebsdlike, netbsdlike))] @@ -71,7 +71,6 @@ libc_bitflags!( MNT_SYNCHRONOUS; /// Union with underlying fs. #[cfg(any( - apple_targets, target_os = "freebsd", target_os = "netbsd" ))] diff --git a/src/mount/mod.rs b/src/mount/mod.rs index 8caf27f7df..41e7b3ec6d 100644 --- a/src/mount/mod.rs +++ b/src/mount/mod.rs @@ -5,8 +5,14 @@ mod linux; #[cfg(linux_android)] pub use self::linux::*; -#[cfg(bsd)] -mod bsd; +#[cfg(bsd_without_apple)] +mod bsd_without_apple; -#[cfg(bsd)] -pub use self::bsd::*; +#[cfg(bsd_without_apple)] +pub use self::bsd_without_apple::*; + +#[cfg(apple_targets)] +mod apple; + +#[cfg(apple_targets)] +pub use self::apple::*; diff --git a/test/mount/mod.rs b/test/mount/mod.rs new file mode 100644 index 0000000000..2764b83f71 --- /dev/null +++ b/test/mount/mod.rs @@ -0,0 +1,6 @@ +#[cfg(target_os = "linux")] +mod test_mount; +#[cfg(apple_targets)] +mod test_mount_apple; +#[cfg(target_os = "freebsd")] +mod test_nmount; diff --git a/test/test_mount.rs b/test/mount/test_mount.rs similarity index 100% rename from test/test_mount.rs rename to test/mount/test_mount.rs diff --git a/test/mount/test_mount_apple.rs b/test/mount/test_mount_apple.rs new file mode 100644 index 0000000000..f2868500d0 --- /dev/null +++ b/test/mount/test_mount_apple.rs @@ -0,0 +1,8 @@ +use nix::errno::Errno; +use nix::mount::{mount, MntFlags}; + +#[test] +fn test_mount() { + let res = mount::("", "", MntFlags::empty(), None); + assert_eq!(res, Err(Errno::ENOENT)); +} diff --git a/test/test_nmount.rs b/test/mount/test_nmount.rs similarity index 100% rename from test/test_nmount.rs rename to test/mount/test_nmount.rs diff --git a/test/test.rs b/test/test.rs index c7231426c2..f32a85a3b7 100644 --- a/test/test.rs +++ b/test/test.rs @@ -4,6 +4,7 @@ extern crate cfg_if; extern crate nix; mod common; +mod mount; mod sys; #[cfg(not(target_os = "redox"))] mod test_dir; @@ -11,8 +12,6 @@ mod test_errno; mod test_fcntl; #[cfg(linux_android)] mod test_kmod; -#[cfg(target_os = "linux")] -mod test_mount; #[cfg(any( freebsdlike, target_os = "fushsia", @@ -23,8 +22,6 @@ mod test_mq; #[cfg(not(target_os = "redox"))] mod test_net; mod test_nix_path; -#[cfg(target_os = "freebsd")] -mod test_nmount; mod test_poll; #[cfg(not(any( target_os = "redox",