Minifilter catch file deletion

Hello,

I have to log file deletions in a NTFS file system using a minifilter.
I read that I have to catch file disposition on IRP_CREATE and
IRP_SET_INFORMATION, and this is easy, but my problem is when to log
the actual deletion. Suppose we have two files “test1” and “test2”
that are hard links to the same stream. Here there are some cases that
I tested, with some comments.

*** Case 1: two open handles ***

create(“test1”, handle1)
create(“test1”, handle2)
set_disposition_information(handle2)
close(handle2)

> Stream Handle Contex for handle2 deleted (handle2 closed) <<
close(handle1)
> All handles to “test1” closed <<
> Stream Context deleted (all handles to the stream closed) <<
> File “test1” deleted <<

Comment: file deletion happens when the last handle to the file name
has been released, so I cannot use the Stream Handle Context to track
it.

*** Case 2: hard links ***

create(“test1”, handle1)
create(“test2”, handle2)
set_disposition_information(handle2)
close(handle2)

> Stream Handle Contex for handle2 deleted (handle 2 closed) <<
> All handles to “test2” closed <<
> File “test2” deleted <<
close(handle1)
> Stream Context deleted (all handles to the stream closed) <<

Comment: I cannot use the Stream Context too, because it depends on
the stream (so every name of the stream) and not on the file name.

*** Case 3: mixed ***

create(“test1”, handle1)
create(“test1”, handle2)
create(“test2”, handle3)
set_disposition_information(handle2)
close(handle2)

> Stream Handle Context for handle2 deleted (handle2 closed) <<
close(handle1)
> All handles to “test1” closed <<
> File “test1” deleted <<
close(handle3)
> Stream Context deleted (all handles to the stream closed) <<

Comment: here it is clear that I can’t use any context to track when
“file1” deletion will actually happen. How can my minifilter be
notified about file deletion? Is there a way to get how many handles
are still opened on a file name (not on a stream)? With this
information, I could write a callback for cleanup or close IRPs and
see if the deletion is going to happen.

Thanks,
Paolo

The is a good example of why filters are so hard to write - you are dealing
with a black box (usually with a potentially dead cat inside:-) and there is
no way to actually find out what you want.

As you point out it is impossible to know when a file is being deleted, all
you can do is infer that the file *might* be deleted. Based on empirical
observation of one particular filesystem in one particular version you can
probably asymptotically approach perfection, but in all cases you are really
guessing behaviour based on obervation of stimuli. You will miss stimuli
and you have no guarantee that the behaviour will be what you guessed it
would be.

I’d suggest that you try and discover what the requirements are in detail.
Do you care when the directory entry disappears or is it when the data
disappears or both? What are your constraints about being crash proof ?
For instance if you take an action in the pre call the file hasn’t
disappeared yet and may “come back” if the system crashes between you
logging the delete and the FSD getting the operation. If you do the logging
in the post call you have the inverse problem - the file might go away and
then the system will crash before you can log it.

I think that the best approximation you will get will be by keeping
reference counts in your contexts and separating the reference counts for
each different name by which the file is known. This means you will also
need to track rename. If you use a stream handle context, you can partially
shield yourself from Cleanup/Close operations for which you haven’t seen the
create. But no matter what you will still get problems when you cannot
observe the stimuli which provoked the delete. This includes, operations
which happen before you attach, operations performed by lower filters and
operations performed by other clients (if you are filtering a redirector).

Good luck

If you are trying to figure if a delete is actually happening (despite the initial settings) then in IRP_MJ_CLEANUP with pFileObject->DeletePending will tell you that the guy is really being deleted.

Larry