Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: introduce macos mount API support #2347

Merged
merged 12 commits into from
Apr 2, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) },
Expand Down
1 change: 1 addition & 0 deletions changelog/2347.added.md
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
Add `mount` and `unmount` API for apple targets.
122 changes: 122 additions & 0 deletions src/mount/apple.rs
Original file line number Diff line number Diff line change
@@ -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.
oowl marked this conversation as resolved.
Show resolved Hide resolved
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, T, F>(p: Option<&P>, f: F) -> Result<T>
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<P>(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)
}
5 changes: 2 additions & 3 deletions src/mount/bsd.rs → src/mount/bsd_without_apple.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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))]
Expand All @@ -71,7 +71,6 @@ libc_bitflags!(
MNT_SYNCHRONOUS;
/// Union with underlying fs.
#[cfg(any(
apple_targets,
target_os = "freebsd",
target_os = "netbsd"
))]
Expand Down
14 changes: 10 additions & 4 deletions src/mount/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
6 changes: 6 additions & 0 deletions test/mount/mod.rs
Original file line number Diff line number Diff line change
@@ -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;
File renamed without changes.
8 changes: 8 additions & 0 deletions test/mount/test_mount_apple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
use nix::errno::Errno;
use nix::mount::{mount, MntFlags};

#[test]
fn test_mount() {
let res = mount::<str, str, str>("", "", MntFlags::empty(), None);
assert_eq!(res, Err(Errno::ENOENT));
}
File renamed without changes.
5 changes: 1 addition & 4 deletions test/test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,14 @@ extern crate cfg_if;
extern crate nix;

mod common;
mod mount;
mod sys;
#[cfg(not(target_os = "redox"))]
mod test_dir;
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",
Expand All @@ -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",
Expand Down