Trash support

What is the recommended way to determine whether an item can be moved to Finder Trash on a given volume?

If no Trash directory is available, is user confirmation followed by immediate deletion the expected path?

For which common volume types is a Trash directory unavailable?

Thanks!

Answered by DTS Engineer in 891083022

What is the recommended way to determine whether an item can be moved to Finder Trash on a given volume?

So, my general recommendation would be that you not try to predict this. Just call NSFileManager.trashItem(at:...) and do "something else" if it fails. You can use url(for:in:appropriateFor:create:) and .trashDirectory, but that tells you where the trash dir is/"should" be, NOT whether or not the trash will work (more on that shortly...). I'm also not sure it's entirely reliable either since, for example, FileProvider clients aren't really required to implement "trash" semantics using the same "put the object in this directory" approach the system uses, assuming they return a target directory at all.

Similarly, in terms of doing your own prediction...

For which common volume types is a Trash directory unavailable?

...The problem is that there are a huge number of edge cases, most of which aren't necessarily tied to the volume itself. Our general behavior is that we try to find/create a trash directory on most volume formats, but regardless of our default behavior edge cases issue like:

  • A nested file provider can create a "trash-able" location on a volume that we wouldn't normally support trash on.

  • Access issues mean we may not be able to trash an item we "should" be able to trash.

That last point is what makes this really challenging, as this isn't just an issue of simple permissions. The EndpointSecurity API basically gives an ES client the ability to "veto" a broad set of system calls, which means the trash attempt can still fail even if EVERYTHING else said it "should" work. Critically, this also means that the failure can be entirely arbitrary, so even the failure or success of one request doesn't ACTUALLY mean the next request will succeed.

All of that makes doing any kind of preflighting fairly pointless, since you'll always have failures your preflight can't predict.

If no Trash directory is available, is user confirmation followed by immediate deletion the expected path?

That's the typical approach, though there are certainly cases where a different approach might make sense. For example, a "shoebox" app that's particularly concerned about unintentional data loss might create its own "trash" directory instead of using the system-level trash. Case in point, that's essentially what Photos.app is doing with its "Recently Deleted" album.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Accepted Answer

What is the recommended way to determine whether an item can be moved to Finder Trash on a given volume?

So, my general recommendation would be that you not try to predict this. Just call NSFileManager.trashItem(at:...) and do "something else" if it fails. You can use url(for:in:appropriateFor:create:) and .trashDirectory, but that tells you where the trash dir is/"should" be, NOT whether or not the trash will work (more on that shortly...). I'm also not sure it's entirely reliable either since, for example, FileProvider clients aren't really required to implement "trash" semantics using the same "put the object in this directory" approach the system uses, assuming they return a target directory at all.

Similarly, in terms of doing your own prediction...

For which common volume types is a Trash directory unavailable?

...The problem is that there are a huge number of edge cases, most of which aren't necessarily tied to the volume itself. Our general behavior is that we try to find/create a trash directory on most volume formats, but regardless of our default behavior edge cases issue like:

  • A nested file provider can create a "trash-able" location on a volume that we wouldn't normally support trash on.

  • Access issues mean we may not be able to trash an item we "should" be able to trash.

That last point is what makes this really challenging, as this isn't just an issue of simple permissions. The EndpointSecurity API basically gives an ES client the ability to "veto" a broad set of system calls, which means the trash attempt can still fail even if EVERYTHING else said it "should" work. Critically, this also means that the failure can be entirely arbitrary, so even the failure or success of one request doesn't ACTUALLY mean the next request will succeed.

All of that makes doing any kind of preflighting fairly pointless, since you'll always have failures your preflight can't predict.

If no Trash directory is available, is user confirmation followed by immediate deletion the expected path?

That's the typical approach, though there are certainly cases where a different approach might make sense. For example, a "shoebox" app that's particularly concerned about unintentional data loss might create its own "trash" directory instead of using the system-level trash. Case in point, that's essentially what Photos.app is doing with its "Recently Deleted" album.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Thanks, that makes sense.

In my app the user first moves items into an app-level trash, and “empty trash” already requires confirmation. Based on your answer, I’ll treat Finder Trash as best-effort: attempt trashItem first, fall back to immediate deletion if it fails, and only remove the database entries for files where one of those operations succeeded.

In my app, the user first moves items into an app-level trash, and “empty trash” already requires confirmation. Based on your answer, I’ll treat Finder Trash as best-effort: attempt trashItem first, fall back to immediate deletion if it fails, and only remove the database entries for files where one of those operations succeeded.

That all sounds reasonable with one qualifier. If you’re dealing with very large files and/or very high file counts, there are situations where direct deletion makes more sense, particularly if these are files the system thinks of as "your files" not "their files". The trash can is a "shared" across the entire system, so you don't want to create situations like:

  • They're forced to empty the trash because they actually need the space the giant files they just told you to delete are occupying.

  • They can't actually "see" the useful content of their trash can because you've dumped 10,000 tiny files into it.

Note that thinking about these details can also reveal small opportunities for improvement— for example, in the second case, the easiest solution is to have your app thrash an entire directory (<app name> Trash <date>) instead of the individual files. This both declutters the trash can and makes the entire operation WAY faster. I'd actually move your entire trash directory (renaming it during the move) then create a new empty directory as your new trash can.

__
Kevin Elliott
DTS Engineer, CoreOS/Hardware

Trash support
 
 
Q