I'm working with Kqueues on mac os x and I'm trying to monitor a folder
so I used EVFILT_VNODE filter and I want to get a notification whenever a file is deleted , I tried NOTE_DELETE
but it only detects when a file gets deleted through unlink() system call
but not when I move the file to trash.
The question is How can I detect when a file is sent to trash?
There's no simple way to do this. kqueue()
can inform you when the file has been moved (a.k.a. renamed), but it doesn't consider the trash to be any sort of special destination or have any special significance with respect to the continued existence of the file. That is, moving a file to the trash is just like moving it to any other directory as far as the BSD layer is concerned.
So, you'd monitor for NOTE_RENAME
to find out when the file is moved/renamed. Then, you can use fcntl(fd, F_GETPATH, buffer)
to find out the new path. Note that for a hard-linked file, this may give the path to one of the other links, not the path of the item as the user thinks of it. This should be fairly rare, though.
You would then have to see if the new path is inside of the trash. That is also complicated.
If you can require OS X 10.10 or later, you can use [[NSFileManager defaultManager] getRelationship:&relationship ofDirectory:NSTrashDirectory inDomain:0 toItemAtURL:[NSURL fileURLWithPath:pathFromFcntl] error:NULL]
. If that method returns true and sets relationship
to anything other than NSURLRelationshipOther
, the file has been moved to the trash.
If you need to support versions 10.9 and earlier, you have to do this manually:
There's not just one trash directory. There's a different directory for each user on each volume. To find the trash directory that a particular file would use, call [[NSFileManager defaultManager] URLForDirectory:NSTrashDirectory inDomain:NSUserDomainMask appropriateForURL:[NSURL fileURLWithPath:pathFromFcntl] create:NO error:NULL]
.
Then you have to determine if the new path is somewhere within that directory (not just immediately inside it). You need to iterate up the directories of the path. For each directory, use -[NSURL getResourceValue:forKey:error:]
with NSURLFileResourceIdentifierKey
as the key to get its resource identifier. Get the same value for the trash directory. Compare the two using -isEqual:
. If you find an ancestor directory whose resource identifier is equal to the trash directory's, then the file is in the trash. If the iteration of ancestor directories reaches root without finding that, then it's not.