Open pwang7 opened 4 years ago
Yep. Though it probably wouldn't be hard to extend it to work on OSX, too.
@asomers could you please advise me how to extend mount to work on OSX?
Uh, not really. I don't have a Mac and I haven't used one since 10.3. You'll have to figure out how mount works on that platform.
Let me explain what I found first.
It seems mount(2)
differs a lot w.r.t. Linux and OSX.
Linux: int mount(const char *source, const char *target, const char *filesystemtype, unsigned long mountflags, const void *data);
5 input arguments;
OSX: int mount(const char *type, const char *dir, int flags, void *data);
4 input arguments.
The trick part is the last input argument of mount(2)
, void *data
, which has different meaning w.r.t. Linux and OSX. According to Linux man page, the data
argument is a c-string of comma-separated options understood by this filesystem. Whereas, under OSX, the data
argument is a pointer to a structure that contains the type specific arguments to mount, and the format for these argument structures is different w.r.t. each filesystem.
Another thing is the mount flags are different w.r.t. Linux and OSX.
I used libc::mount()
under OSX to successfully mount a Filesystem in User Space (FUSE), which requires a struct as following:
struct fuse_mount_args {
char mntpath[MAXPATHLEN]; // path to the mount point
char fsname[MAXPATHLEN]; // file system description string
char fstypename[MFSTYPENAMELEN]; // file system type name
char volname[MAXPATHLEN]; // volume name
uint64_t altflags; // see mount-time flags below
uint32_t blocksize; // fictitious block size of our "storage"
uint32_t daemon_timeout; // timeout in seconds for upcalls to daemon
uint32_t fsid; // optional custom value for part of fsid[0]
uint32_t fssubtype; // file system sub type id
uint32_t iosize; // maximum size for reading or writing
uint32_t random; // random "secret" from device
uint32_t rdev; // dev_t for the /dev/osxfuse{n} in question
};
Whereas it seems the struct to mount Mac HFS under OSX is something else, which I haven't tried yet:
struct hfs_mount_args {
char *fspec; // The device to mount
uid_t hfs_uid;
gid_t hfs_gid;
mode_t hfs_mask;
u_int32_t hfs_encoding;
struct timezone hfs_timezone;
int flags;
int journal_tbuffer_size;
int journal_flags;
int journal_disable;
};
Although libc::mount
should work under OSX, I found it's very hard to debug (no much documentation) and unsafe. It seems lib::mount
is a thin wrapper to syscalls. Another painful thing is when doing Rust FFI with C, handling char str[MAX_LENGTH]
is less inconvenient than char *str
.
I wish I could contribute to nix about mount under OSX, but I'm new to nix. That's why I ask for your advise @asomers.
Thanks!
Yes, your analysis is correct. libc only provides a very thin wrapper around native C library calls (which are themselves usually thin wrappers around syscalls). The mount function is very different between operating systems, and the C structures can be awkward. The good news is that you don't have to worry about cross-platform compatibility. Nix should expose mount
in the way that makes the most sense for each operating system. For OSX (and FreeBSD, which has the same interface), I suggest something like this:
trait MountData {
fn fstype() -> &'static OsStr;
fn as_data(&self) -> *const c_void;
}
libc_bitflags!(
pub struct MntFlags: c_int {
MNT_RDONLY;
...
}
);
fn mount<MD: MountData, P: ?Sized + NixPath>(dir: &P, flags: MntFlags, data: &MD) -> Result<()> {
...
}
Does that sound good?
Cool, your design looks good to me.
One more thing is the mount flags are also different w.r.t. Linux and OSX (or BSD). Linux mount flags:
#define MS_RDONLY 1 /* Mount read-only */
#define MS_NOSUID 2 /* Ignore suid and sgid bits */
...
BSD mount flags:
#define MNT_RDONLY 0x00000001 /* read only filesystem */
#define MNT_SYNCHRONOUS 0x00000002 /* file system written synchronously */
...
It seems libc doesn't define all of MNT_*
flags, should the MNT_*
flags be defined in nix? Or do they have to be defined in libc first?
BTW, I checked the nix mount.rs file, is it the right place to start with?
Those flags should all be defined in libc. If they aren't there already, then you'll have to submit a PR to libc to add them. And yes, mount.rs is the right place.
OK, I'll deal with libc first, thanks Alan!
Just to follow up, I've added macOS mount flags to libc, https://github.com/rust-lang/libc/pull/1690
I'm trying nix to make some syscalls, instead of using libc. But it seems nix has no mount for MacOS, am I right?