I'm trying to restore an APFS volume to its previous state using a snapshot created with the tmutil command. The only native Apple tool I've found for this purpose is apfs.util. According to the documentation, the correct command for this task is /System/Library/Filesystems/apfs.fs/Contents/Resources/apfs.util -R <snapshot name> </dev/diskXsY>. However, this command is not working for me. It returns the error "No such file or directory" for any existing <snapshot name>. If I use a valid file/dir path instead of the <snapshot name> as an experiment, I get an "Invalid argument" error. To investigate the issue, I decided to debug apfs.util and found that the fsctl() function is responsible for these errors (ENOENT and EINVAL). The first argument passed to fsctl() is the <snapshot name> (or file/dir path in my experiment), and the second argument is the value 0x80084A01, which corresponds to the APFSIOC_REVERT_TO_SNAPSHOT command according to xnu's source code (https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/vfs/vfs_syscalls.c#L174). It seems that this command is not supported by the latest versions of macOS (see https://github.com/apple-oss-distributions/xnu/blob/8d741a5de7ff4191bf97d57b9f54c2f6d4a15585/bsd/vfs/vfs_syscalls.c#L12984) and always returns EINVAL error. Is this correct? Are there any other tools available that can be used to revert APFS snapshots?
I'm trying to restore an APFS volume to its previous state using a snapshot created with the tmutil command. The only native Apple tool I've found for this purpose is apfs.util.
We don't currently have any mechanism (tool or API) that allows snapshot reversion. If you'd like us to provide something like this, then all I can suggest is filing an enhancement request asking for us to add it.
It seems that this command is not supported by the latest versions of macOS
Basically, yes. Snapshot was originally implemented in APFS through fsctl(APFSIOC_REVERT_TO_SNAPSHOT), however, when snapshot support was added to the full VFS layer, that block as added to prevent sending the command through the fsctl path. If you look lower in the same file, snapshot_revert first tries VFSIOC_REVERT_SNAPSHOT (the public VFS ioctl) and then tries APFSIOC_REVERT_TO_SNAPSHOT (the APFS private ioctl).
For the curious, if you're wondering why this kind of code is there, the answer is that it's a hold over from the original transition and that it's still there because it provides the most flexibility to both teams. The VFS layer originally added it because they wanted the new code path to work even if the APFS team hadn't adopted VFSIOC_REVERT_SNAPSHOT (or, more likely, if someone wanted to test something like an older APFS build). Similarly, APFS actually does support VFSIOC_REVERT_SNAPSHOT but they left APFSIOC_REVERT_TO_SNAPSHOT in place because they didn't want to worry about breaking existing stuff that was still using APFSIOC_REVERT_TO_SNAPSHOT.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware