It’s something that should be simple to answer: can an app running from this user account read or write this file? It’s been driving me to the depths of despair, to the point where I just want to give up. This issue is, of course, determining whether preference file permissions are correct.
In the beginning, this was simply a matter of permissions. If I as a user have read and write access to a file, then apps running as that user have too. Then came additional file system metadata, such as file locking, and immutable flags, which don’t change permissions but can just as effectively stop an app writing to that file. So merely checking permissions isn’t sufficient, there are other attributes to check too.
A year and a half ago, Apple complicated this further with its privacy protections, which have become even more protean in Catalina. Although everything else might be lined up correctly, if the accessing app isn’t allowed to see that folder, then it can’t even find out whether that file exists, let alone open it. So checking from an app which has Full Disk Access enabled could give a misleading picture. For the purposes of an app designed to check access to preference and similar files, it just has to make assumptions.
Thankfully, there are two operating system calls which should make this simpler, in Foundation’s File Manager:
isReadableFile(). These each return a Boolean value, defined by Apple’s documentation as being “true if the current process has write privileges for the file at path; otherwise false if the process does not have write privileges or the existence of the file could not be determined.” (In the case of isWritableFile().)
There is a warning, though:
“Attempting to predicate behavior based on the current state of the file system or a particular file on the file system is not recommended. Doing so can cause odd behavior or race conditions. It’s far better to attempt an operation (such as loading a file or creating a directory), check for errors, and handle those errors gracefully than it is to try to figure out ahead of time whether the operation will succeed.”
Thankfully race conditions shouldn’t concern us here, but what Apple is saying is that you can’t rely on either of these calls to tell whether an app will have access to any given file, when it comes to try to access it. I can feel the rug being pulled from under my code here.
In any case, to scan a full ~/Library folder can involve checking more than a million files, in as short a time as possible. Trying to open every one of those for reading or writing would surely cause mayhem, and run exceedingly slow. Given that the exhaustive iteration through every nook and cranny of the directory hierarchy is already neither quick nor sparing of memory, that doesn’t seem a good way ahead either.
This all seemed like a fair compromise until two users informed me of four false positives: preference files which the Finder reports as being readable and writable as expected, but which fail to return true to
isWritableFile(). At first I thought I could explain this away as being a temporary glitch in a beta-release, but the second user to report this isn’t even running Catalina, but Mojave. Maybe the answer is in that final phrase in the documentation; “false if […] the existence of the file could not be determined”.
To determine whether the existence of the file can’t be determined by the File Manager is a matter of making a different call, to
fileExists(), which also returns false if the file’s existence “could not be determined” (as well as when the file doesn’t exist). But in these false positives, the Finder can find the file and pronounce on its permissions, so why can’t the File Manager? And if the File Manager can’t discover a basic fact about the file, what can?
It’s looking like checking whether file permissions are correct has now become an impossible task. No small wonder then that users encounter problems when their apps can’t change settings when they want. But writing any utility which attempts to check permissions is fast becoming a hiding to nothing. However you try to test files, macOS seems likely to return false positives and negatives. Perhaps I should just abandon this whole project as being a waste of time and effort? Maybe I’ll try releasing version 1.6 of PermissionScanner and see if I can guess my way around this.
I’m getting the feeling that macOS is no longer the crisply deterministic system we’d like to think it is. Anyone for quantum file permissions?