How to programmatically delete a file on external disk under security-scoped bookmarks?

I have a problem with programmatically deleting files that reside on an external disk,

which must be accessed using security-scoped bookmarks.


In my app, I collect lists of files that reside on an external disk.

After the user has opened the directory of the files, I create a security-scoped bookmark like this:


   directoryBookmark_ = [dir bookmarkDataWithOptions: NSURLBookmarkCreationWithSecurityScope
                      includingResourceValuesForKeys: nil
                                       relativeToURL: nil
                                               error: &systemError];

Next time, the app runs, I resolve the bookmark like this:


   directoryLocation_ = [NSURL URLByResolvingBookmarkData: directoryBookmark_
                                                  options: NSURLBookmarkResolutionWithSecurityScope
                                            relativeToURL: nil
                                      bookmarkDataIsStale: & isStale
                                                    error: & error];
[directoryLocation_ startAccessingSecurityScopedResource];

(directoryBookmark_ is saved and loaded in the user preferences.)


At some later point, my app wants to delete one of the files in that directory (or sub-directory),

like this:


       NSString * abs_path = [self absolutePathFor: filename_];
       BOOL success = [self deleteFile: abs_path ];

This does not work. In the log, I get the error message:


Failed to delete /Volumes/.../image.jpg: “image.jpg” couldn’t be moved to the trash because you don’t have permission to access it.!


I then try to get more info about the problem using this code:


   NSURL * imgurl = [NSURL fileURLWithPath: abs_path isDirectory: NO];
   NSError * error;
   NSFileHandle * fileHandle = [NSFileHandle fileHandleForUpdatingURL: imgurl error: & error];

But it always returns a valid fileHandle, i.e., there is no error.


I selected "Read/Write" in the "User Selected File" entitlement of my app.


Of course, everything works fine when the files reside on my local disk (even across multiple invocations of the app).

The external disk is just a hard disk connected via USB to my laptop.

Deleting the files manually on the external hard disk works, of course.


Does anyone have an idea what mistake I might be making?

Or is there a way to get the necessary permission?


Surely, apps must have a way of deleting files programmatically, don't they?

At least, appe's docs don't mention anything indicating otherwise.


All hints and insights will be highly appreciated.

Replies

Catalina has a few additional locations that are protected. One of these is external volumes. Normally, when your tool accesses such a location, it will trigger a prompt (which the user can deny). But there is likely no prompt when you are creating the URL via security scoped bookmark.


How did you get access to the file on the external volume to begin with? Shouldn't you have had to request, and receive, access? Are you doing all of this on a developer machine? That will totally confuse the system databases. Anything involving this kind of stuff has to be tested in a VM. I suspect that it works fine there. This may just be a side effect of a developer machine.

Soryy I'm seeing this only now.


Re your question: I am getting a siectory from the user. For that, I create a security-scoped bookmark. Also, I create a list of files in that directory. I store both in the user preferences. Next time the app is invoked, I load the SSB, resolve it, and startAccessingSecurityScopedResource.


I am testing iths on my developer machine. And it cannot delete external files on external USB drives connected to that machine.

The new restrictions in Catalina are over and above anything related to the sandbox. You would have similar problems if you were debugging a non-sandboxed app.
Test your app in a VM. In the VM, go to System Preferences > Security & Privacy > Privacy > Files and Folders and make sure your app has privileges to access external volumes. Then, after doing the security-scoped bookmarks, it should work.