In the callback, I can see that the failure occurs on a .DS_Store file inside the folder. So for a .DS_Store, it is simple enough for me to just ignore the error and return COPYFILE_SKIP, but the somewhat more concerning issue here is that the true error reason is seemingly not reported? In the callback, if I read errno, it is 0. When copyfile returns, it returns -1 after I return COPYFILE_QUIT (and errno is 0), so I don't know what the error is or the appropriate way to handle it.
FYI, the code to copyfile is actually open-source, so you can fairly easily find all of the places where your callback would have been called by looking for "COPYFILE_ERR" in the source.
However:
For .DS_Store, just skipping seems reasonable, but when copying a folder, it may be appropriate to get the true failure reason.
...I'd ignore all .DS_Store errors and, potentially, just skip copying them all together. The system will generate the file anytime it needs/wants to, and it's very likely that it won't consider the copied file "valid" and will end up regenerating it anyway.
But checking the last path component of the source path seems like a hack way to handle errors.
The big thing I'd look at here actually is the stage, not the error, as I suspect the reason errno isn't set is that particular stage doesn't really have an "error".
If a file in the copying folder with important user data, I can't just silently skip it.
Theoretically, a user might choose to store their data in a file named ".DS_Store“; however, if the system encounters a ".DS_Store" file that it can't process, then I believe it will just destroy the file and create a new one. Skipping these files is kinder than what the system will already do.
It isn't clear to me how I should properly proceed in a situation where I can't get the actual reason for the failure.
I think the idea you're getting at here is that you should be able to point your copy engine at any point in the file system, have it do the "right" thing based only on the information it's provided by copyfile, not external knowledge (like the full source path).
That's a lovely idea, but for better or worse, macOS just does not work that way. There are a huge number of special cases (most of which are basically undocumented), and that's before external factors like EndpointSecurity (that API basically lets the client app arbitrarily "veto" critical syscalls) become involved. Most of the time, these don't matter because the user is working with "their" file (which is the simple case), but if you want to work with the "full" system... Well, I don't think there's any way to do without grappling with a whole bunch of edge cases.
__
Kevin Elliott
DTS Engineer, CoreOS/Hardware