====== APFS And Firmlinks ====== APFS is a copy-on-write filesystem that is optimized for SSDs, has its own native encryption and uses snapshotting extensively. APFS uses a single GPT partition to hold its own kind of volumes. These volumes share the same disk space, so in the above example Container A is a single 700GB partition that all the volumes share. ==== Firmlinks ==== * Firmlinks are similar to symlinks in function, but very different in how they work * Introduced in MacOS Catalina 10.x * They can only be directories * Non-configurable, they are defined by MacOS in /usr/share/firmlinks * Users cannot create firmlinks, only MacOS can * They can only be created as part of the boot process (explained below) * Apple's definition: _Bi-directional wormhole in path traversal. Firmlinks are used on the system volume to point to the user data on the data volume. ==== APFS Boot Snapshotting and Firmlinking ==== The MacOS Boot sequence is as follows: - A read-only snapshot of the System volume is created - APFS mounts the snapshot as the root filesystem - The Data volume is mounted at /System/Volumes/Data - /usr/share/firmlinks is parsed by apfs.util and firmlinks are created on the mounted snapshots. These are the default firmlinks in Monterey, the right hand path has an assumed preprended path of /System/Volumes/Data: /AppleInternal AppleInternal /Applications Applications /Library Library /System/Library/Caches System/Library/Caches /System/Library/Assets System/Library/Assets /System/Library/PreinstalledAssets System/Library/PreinstalledAssets /System/Library/AssetsV2 System/Library/AssetsV2 /System/Library/PreinstalledAssetsV2 System/Library/PreinstalledAssetsV2 /System/Library/CoreServices/CoreTypes.bundle/Contents/Library System/Library/CoreServices/CoreTypes.bundle/Contents/Library /System/Library/Speech System/Library/Speech /Users Users /Volumes Volumes /cores cores /opt opt /private private /usr/local usr/local /usr/libexec/cups usr/libexec/cups /usr/share/snmp usr/share/snmp - /etc/synthetic.conf is parsed to create root-level symlinks (not firmlinks!) to writeable locations on the Data volume. For example, /Users/alice/foo could be symlinked to /foo. There are none by default, this is mostly for mounting resources at root and making them writable to all users. ==== APFS Folder Sharing ==== APFS supports the ability to make folders that are firmlinked source from multiple locations. For example, the folder containing main apps, which used to be /Applications, now contains a mixture of apps from two different folders, /System/Applications, which is on the System volume and contains Apple's bundled apps, and the Applications folder on the Data volume, which would otherwise be found at /System/Volumes/Data/Applications. When you install your own apps, they automatically get placed in the latter folder, as it's the one which you can write to. When you view the /Applications folder in the Finder, though, you are actually seeing the combined contents of both folders, an illusion which is created by the firmlink at /Applications and the Finder. One interesting behavioral note is that only Finder seems to be aware of this pseudo-merging of directories. If you cd to /Applications in a terminal session, all you’ll see is what’s in the Data volume and not the system applications. Other Finder-replacement software seems to implement what’s needed to show the merged directories as well (tested with [Commander One](https://ftp-mac.com/)) ==== Firmlink Resolution ==== === Open Source Research === In looking at open source projects, there seems to be two major strategies for dealing with firmlinks. Either the application ignores them completely, which is what Apple would prefer, and just let APFS handle path resolution. The other strategy can be generalized as: - Create some data structure (usually a hashmap) of the system’s firmlinks by parsing /usr/share/firmlinks - Whenever a path is supplied, have logic that checks if the supplied path is a firmlink - If the firmlink does **not** use Folder Sharing, append /System/Volumes/Data to the path - If the firmlink does use Folder Sharing, like /Applications, check both possible pathways to the file and resolve the correct one This approach is used by several big-name projects like vagrant. There is another approach that might be worth investigating: apple-libc seems to have some support for firmlinks, though it is undocumented: https://github.com/sanvit/apple-libc/blob/6517c5cffa0fd48e89fefd90c3a1271ab53300c6/gen/FreeBSD/getcwd.c#L66 Further research could start looking at the open source code for find: https://opensource.apple.com/source/shell_cmds/shell_cmds-216.60.1/find/ ==== Links ==== * https://robservatory.com/living-the-bifurcated-life-in-macos-catalina/ * https://eclecticlight.co/2019/10/11/macos-catalina-boot-volume-layout-revised-for-10-15-release/ * https://bombich.com/kb/ccc6/working-apfs-volume-groups * http://www.swiftforensics.com/2019/10/macos-1015-volumes-firmlink-magic.html * https://developer.apple.com/forums/thread/120665 * https://apple.stackexchange.com/questions/423712/creating-a-firmlink-in-usr-on-macos-10-15-11 * https://developer.apple.com/forums/thread/117521