macosmountapfs

Mount an APFS snapshot using the mount() function, not the mount tool


I want to mount an APFS snapshot using code running on macOS, using the equivalent of this tool invocation:

mount_apfs -o ro,nobrowse -s snapshot_name snapshot_volume destpath

As there's no mount_apfs() function, I'm stuck with mount(). I also cannot use fs_snapshot_mount() because that requires root permissions, and my app doesn't have those.

man 2 mount states:

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

Data is a pointer to a structure that contains the type specific
arguments to mount.  The format for these argument structures is
described in the manual page for each filesystem.

The problem is that I am unable to find a definition for this data structure for APFS. E.g., where's that "manual page"?

In short, how do I pass the root path of the volume and its snapshot name to the mount() function?

How I choose the parameters

Regarding the current two answers, here's an example of how I'd find the snapshot name and the device name:

% diskutil apfs listSnapshots /System/Volumes/Data
Snapshot for disk3s5 (1 found)
|
+-- A391E61C-0B69-4A45-8543-C455EAF7F788
    Name:        com.apple.TimeMachine.2025-06-22-165948.local
    XID:         37638462
    Purgeable:   Yes
    NOTE:        This snapshot limits the minimum size of APFS Container disk3

% mount | grep "/System/Volumes/Data"
/dev/disk3s5 on /System/Volumes/Data (apfs, local, journaled, nobrowse, protect, root data)
map auto_home on /System/Volumes/Data/home (autofs, automounted, nobrowse)

In the above, com.apple.TimeMachine.2025-06-22-165948.local is the snapshot name and /dev/disk3s5 the device path.


Solution

  • The structure can be found at: mount_args.h from palera1n/jbinit jailbreak repository

    With that the call to mount looks like this:

    The snapshot name is part of the structure, there're only 256 bytes reserved for it.

    The unk_flags are unknown flags and i don't know why these specific flags are required, but that's what's being passed when you use the arguments that you provided in your question.

    What surprises me a bit is the lack of source-volume. In theory that's the first member of the struct apfs_mount_args but in practice it's a null-pointer.