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 4 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_macos: { any(freebsd, dragonfly, netbsd, openbsd) },
oowl marked this conversation as resolved.
Show resolved Hide resolved
linux_android: { any(android, linux) },
freebsdlike: { any(dragonfly, freebsd) },
netbsdlike: { any(netbsd, openbsd) },
Expand Down
125 changes: 125 additions & 0 deletions src/mount/apple.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,125 @@
use crate::{Errno, NixPath, Result};
use libc::c_int;

libc_bitflags!(
/// Used with [`Nmount::nmount`].
oowl marked this conversation as resolved.
Show resolved Hide resolved
pub struct MntFlags: c_int {
/// Do not interpret special files on the filesystem.
MNT_NODEV;
/// file system supports content protection
oowl marked this conversation as resolved.
Show resolved Hide resolved
MNT_CPROTECT;
/// filesystem is stored locally
oowl marked this conversation as resolved.
Show resolved Hide resolved
MNT_QUARANTINE;
/// filesystem is stored locally
MNT_LOCAL;
/// quotas are enabled on filesystem
MNT_QUOTA;
/// identifies the root filesystem
MNT_ROOTFS;
/// FS supports volfs (deprecated flag in Mac OS X 10.5)
oowl marked this conversation as resolved.
Show resolved Hide resolved
MNT_DOVOLFS;
/// 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;
/// All I/O to the file system should be done asynchronously.
oowl marked this conversation as resolved.
Show resolved Hide resolved
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.
///
oowl marked this conversation as resolved.
Show resolved Hide resolved
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 {
println!("mounting {:?} to {:?}", s, t);
oowl marked this conversation as resolved.
Show resolved Hide resolved
libc::mount(
s.as_ptr(),
t.as_ptr(),
flags.bits(),
d as *mut libc::c_void,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For pointer casting, we prefer .cast() and .cast_mut() over the as keyword:

Suggested change
d as *mut libc::c_void,
d.cast().cast_mut(),

BTW, we are casting an immutable reference (&P3) to a muable pinter (*mut c_void), is this safe?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

libc:mount() needs to recv libc:c_void type, It's hard to cast type to libc:c_void by the cast function, So I have changed it to d.cast_mut() as *mut libc::c_void,

Copy link
Member

@SteveLauC SteveLauC Apr 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's hard to cast type to libc:c_void by the cast function, So I have changed it to d.cast_mut() as *mut libc::c_void,

Yeah, .cast().cast_mut() should not work as the pointee type is unknown, .cast_mut().cast() should work.

BTW, we are casting an immutable reference (&P3) to a muable pinter (*mut c_void), is this safe?

Will mount(2) write to that pointer, if so, then a UB could happen:<

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

From https://developer.apple.com/library/archive/documentation/System/Conceptual/ManPages_iPhoneOS/man2/mount.2.html man page

 int
 mount(const char *type, const char *dir, int flags, void *data);

 int
 unmount(const char *dir, int flags);
   Data is a pointer to a structure that contains the type specific argu-ments arguments
   ments to mount.  The format for these argument structures is described in
   the manual page for each filesystem.

I think it's not be written, but nobody knows how Apple doing I think.

)
})
}))???;

Errno::result(res).map(drop)
}

/// Umount the file system mounted at `target`.
pub fn umount<P>(mountpoint: &P, flags: MntFlags) -> Result<()>
oowl marked this conversation as resolved.
Show resolved Hide resolved
where
P: ?Sized + NixPath,
{
let res = mountpoint.with_nix_path(|cstr| unsafe {
libc::unmount(cstr.as_ptr(), flags.bits())
})?;

Errno::result(res).map(drop)
}
10 changes: 8 additions & 2 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)]
#[cfg(bsd_without_macos)]
oowl marked this conversation as resolved.
Show resolved Hide resolved
mod bsd;
oowl marked this conversation as resolved.
Show resolved Hide resolved
oowl marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(bsd)]
#[cfg(bsd_without_macos)]
oowl marked this conversation as resolved.
Show resolved Hide resolved
pub use self::bsd::*;
oowl marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(apple_targets)]
mod apple;

#[cfg(apple_targets)]
pub use self::apple::*;