Windows Explorer creates about 1000 files when using FltCancelFileOpen

Hi all,
I use the following code to delete a file at post IRP_MJ_CREATE, but the file cannot be deleted.
And if we use Windows Explorer to create file (right click -> New -> Text Document), about 1000 files are created.

Please help me.
Thanks a lot.

FILE_DISPOSITION_INFORMATION fileDispositionInformation;
NTSTATUS status;

if(FltObjects->FileObject->WriteAccess)
{
fileDispositionInformation.DeleteFile = TRUE;
status = FltSetInformationFile(
FltObjects->Instance,
FltObjects->FileObject,
&fileDispositionInformation,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation
);
}

FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );

Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;

Probable scenario (not confirmed by debugging explorer.exe)

  1. Explorer checks if the current directory is read-only.
    In OP’s case, it’s not.

  2. Tries to create file “New Text Document.txt”. It fails, so
    Explorer assumes the file already exists.

  3. Tries to create New Text Document(2).txt". It fails, so
    Explorer assumes the file already exists.

  4. Tries to create New Text Document(3).txt". It fails, so
    Explorer assumes the file already exists.

  5. Tries to create New Text Document(4).txt". It fails, so
    Explorer assumes the file already exists.

  6. Tries to create New Text Document(5).txt". It fails, so
    Explorer assumes the file already exists.

  7. Tries to create New Text Document(6).txt". It fails, so
    Explorer assumes the file already exists.

  1. The internal counter of newly created files exceeded 1000,
    so Explorer stops trying.

L.

What is your meaning by saying “about 1000 files are created”? Say if you
want to create foo.txt, what are the file names for those 1000 files?

Another thing. According to WDK *FltCancelFileOpen* must be called before
any handles are created for the file. If FO_HANDLE_CREATED flag is set, then
it is not safe to call FltCancelFileOpen.

On Mon, Sep 21, 2009 at 6:33 AM, wrote:

> Hi all,
> I use the following code to delete a file at post IRP_MJ_CREATE, but the
> file cannot be deleted.
> And if we use Windows Explorer to create file (right click -> New -> Text
> Document), about 1000 files are created.
>
> Please help me.
> Thanks a lot.
>
> FILE_DISPOSITION_INFORMATION fileDispositionInformation;
> NTSTATUS status;
>
> if(FltObjects->FileObject->WriteAccess)
> {
> fileDispositionInformation.DeleteFile = TRUE;
> status = FltSetInformationFile(
> FltObjects->Instance,
> FltObjects->FileObject,
> &fileDispositionInformation,
> sizeof(FILE_DISPOSITION_INFORMATION),
> FileDispositionInformation
> );
> }
>
> FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject
> );
>
> Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> Data->IoStatus.Information = 0;
>
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule of debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

@ Ladislav Zezula: The scenario is right, but why couldn’t I delete the file created by using FltSetInformationFile?
@ Michael Zhu: The Windows Explorer creates default name “New Text Document.txt” or “New Briefcase”, so the file names are: “New Text Document.txt (N)” & “New Briefcase (N)” with N = 1, 2, 3, …, 999.
For “FltCancelFileOpen”, at http://msdn.microsoft.com/en-us/library/aa488553.aspx says:
"FltCancelFileOpen can only be called from a minifilter driver’s post-create callback routine. Calling FltCancelFileOpen from a postoperation callback ( PFLT_POST_OPERATION_CALLBACK) routine for any other type of I/O operation, or calling it from a preoperation callback ( PFLT_PRE_OPERATION_CALLBACK) routine, is a programming error.

Callers of FltCancelFileOpen must be running at IRQL PASSIVE_LEVEL. However, it is safe for minifilter drivers to call this routine from a post-create callback routine, because post-create callback routines are guaranteed to be called at IRQL PASSIVE_LEVEL, in the context of the thread that originated the IRP_MJ_CREATE request. "

Is there anyone met this problem, please help.
Thanks a lot.

Well, I’m still not sure what the problem is. Do the files appear on disk ? Or do you simply get 1000 requests that you fail ?

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

Thanks Alex.
The files appear on disk with no content (0 KB). I use the code to delete files, but not affect:

FILE_DISPOSITION_INFORMATION fileDispositionInformation;
NTSTATUS status;

if(FltObjects->FileObject->WriteAccess)
{
fileDispositionInformation.DeleteFile = TRUE;
status = FltSetInformationFile(
FltObjects->Instance,
FltObjects->FileObject,
&fileDispositionInformation,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation
);

FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );

Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;

Please help.
Thanks

So, did you validate that the code that sets the delete disposition actually gets executed? Also, I don’t see a check for what FltSetInformationFile returned…

Any reason why you can’t fail the operation in preCreate ?

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

Can someone show me the way to delete a file at post IRP_MJ_CREATE?
Thanks a lot…

Can any of the file system gurus give an answer on this? This is something I
want to know too.

On Thu, Sep 24, 2009 at 12:12 PM, wrote:

> Can someone show me the way to delete a file at post IRP_MJ_CREATE?
> Thanks a lot…
>
> —
> NTFSD is sponsored by OSR
>
> For our schedule of debugging and file system seminars
> (including our new fs mini-filter seminar) visit:
> http://www.osr.com/seminars
>
> To unsubscribe, visit the List Server section of OSR Online at
> http://www.osronline.com/page.cfm?name=ListServer
>

If I call *FltCancelFileOpen* at the post create (remove *FltSetInformationFile*), has the same result (there are about 1000 files created):

FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );
Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;

Any idea, please help?
Thanks

Yes, read the notes for FltCancelFileOpen especially:

Note that FltCancelFileOpen does not undo any modifications to the file. For
example, FltCancelFileOpen does not delete a newly created file or restore a
file that was overwritten or superseded to its previous state.

Do it in PreCreate.

wrote in message news:xxxxx@ntfsd…
> If I call FltCancelFileOpen at the post create (remove
> FltSetInformationFile), has the same result (there are about 1000 files
> created):
>
> FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );
> Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> Data->IoStatus.Information = 0;
>
> Any idea, please help?
> Thanks
>

Don’t we have any way to delete a file at the post create IRP?

That doesn’t sound like a good idea. How about a file that is to be
superseded? It existed and the CreateFile truncated it to zero, then you
want to delete it. I think both are bad ideas if you trying to implement
security. At the most a non-existent file can be canceled and deleted in
the post create or an existing file that is not changed by the create can
also be done, but be careful with delete on close files. This design is
just a bad idea if trying to implement security.

wrote in message news:xxxxx@ntfsd…
> Don’t we have any way to delete a file at the post create IRP?
>

I’ve checked the Microsoft examples, such as Scanner, it implements cancel the IRP at the post CREATE:

FLT_POSTOP_CALLBACK_STATUS
ScannerPostCreate (
__inout PFLT_CALLBACK_DATA Data,
__in PCFLT_RELATED_OBJECTS FltObjects,
__in_opt PVOID CompletionContext,
__in FLT_POST_OPERATION_FLAGS Flags
)
/*++

Routine Description:

Post create callback. We can’t scan the file until after the create has
gone to the filesystem, since otherwise the filesystem wouldn’t be ready
to read the file for us.

Arguments:

Data - The structure which describes the operation parameters.

FltObject - The structure which describes the objects affected by this
operation.

CompletionContext - The operation context passed fron the pre-create
callback.

Flags - Flags to say why we are getting this post-operation callback.

Return Value:

FLT_POSTOP_FINISHED_PROCESSING - ok to open the file or we wish to deny
access to this file, hence undo the open

–*/
{
PSCANNER_STREAM_HANDLE_CONTEXT scannerContext;
FLT_POSTOP_CALLBACK_STATUS returnStatus = FLT_POSTOP_FINISHED_PROCESSING;
PFLT_FILE_NAME_INFORMATION nameInfo;
NTSTATUS status;
BOOLEAN safeToOpen, scanFile;

UNREFERENCED_PARAMETER( CompletionContext );
UNREFERENCED_PARAMETER( Flags );

//
// If this create was failing anyway, don’t bother scanning now.
//

if (!NT_SUCCESS( Data->IoStatus.Status ) ||
(STATUS_REPARSE == Data->IoStatus.Status)) {

return FLT_POSTOP_FINISHED_PROCESSING;
}

//
// Check if we are interested in this file.
//

status = FltGetFileNameInformation( Data,
FLT_FILE_NAME_NORMALIZED |
FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo );

if (!NT_SUCCESS( status )) {

return FLT_POSTOP_FINISHED_PROCESSING;
}

FltParseFileNameInformation( nameInfo );

//
// Check if the extension matches the list of extensions we are interested in
//

scanFile = ScannerpCheckExtension( &nameInfo->Extension );

//
// Release file name info, we’re done with it
//

FltReleaseFileNameInformation( nameInfo );

if (!scanFile) {

//
// Not an extension we are interested in
//

return FLT_POSTOP_FINISHED_PROCESSING;
}

status = ScannerpScanFileInUserMode( FltObjects->Instance,
FltObjects->FileObject,
&safeToOpen );

if (!safeToOpen) {

//
// Ask the filter manager to undo the create.
//

DbgPrint( “!!! scanner.sys – foul language detected in postcreate !!!\n” );

DbgPrint( “!!! scanner.sys – undoing create \n” );

FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );

Data->IoStatus.Status = STATUS_ACCESS_DENIED;
Data->IoStatus.Information = 0;

returnStatus = FLT_POSTOP_FINISHED_PROCESSING;

} else if (FltObjects->FileObject->WriteAccess) {

//
//
// The create has requested write access, mark to rescan the file.
// Allocate the context.
//

status = FltAllocateContext( ScannerData.Filter,
FLT_STREAMHANDLE_CONTEXT,
sizeof(SCANNER_STREAM_HANDLE_CONTEXT),
PagedPool,
&scannerContext );

if (NT_SUCCESS(status)) {

//
// Set the handle context.
//

scannerContext->RescanRequired = TRUE;

status = FltSetStreamHandleContext( FltObjects->Instance,
FltObjects->FileObject,
FLT_SET_CONTEXT_REPLACE_IF_EXISTS,
scannerContext,
NULL );

//
// The only error status that could be returned would tell us that
// contexts are not supported. Even if we got this error,
// we just want to release the context now and that will free
// this memory if it was not successfully set.
//

//
// Release our reference on the context (the set adds a reference)
//

FltReleaseContext( scannerContext );
}
}

return returnStatus;
}

I have to get the file name at post CREATE, check the file name to do appropriate operations. At the pre CREATE, I’m not sure to get exactly file name.
Do you have any idea if I move the code to check file name at pre CREATE?
–Thanks

This does fit into the idea of just opening a file without altering it, so
canceling the create can be made to work. Most scanners in legacy mode
obtained the file name before the FSD saw the create. How do you think the
FSD can open the file if is doesn’t know the file name or file ID? You can
duplicate the create and open it yourself calling downward and not through
the top of the stack, scan it, and close it then decide to reject or permit
the create. There are complications to handle but it can be done.

wrote in message news:xxxxx@ntfsd…
> I’ve checked the Microsoft examples, such as Scanner, it implements cancel
> the IRP at the post CREATE:
>
> FLT_POSTOP_CALLBACK_STATUS
> ScannerPostCreate (
> inout PFLT_CALLBACK_DATA Data,
>
in PCFLT_RELATED_OBJECTS FltObjects,
> in_opt PVOID CompletionContext,
>
in FLT_POST_OPERATION_FLAGS Flags
> )
> /++
>
> Routine Description:
>
> Post create callback. We can’t scan the file until after the create
> has
> gone to the filesystem, since otherwise the filesystem wouldn’t be
> ready
> to read the file for us.
>
> Arguments:
>
> Data - The structure which describes the operation parameters.
>
> FltObject - The structure which describes the objects affected by this
> operation.
>
> CompletionContext - The operation context passed fron the pre-create
> callback.
>
> Flags - Flags to say why we are getting this post-operation callback.
>
> Return Value:
>
> FLT_POSTOP_FINISHED_PROCESSING - ok to open the file or we wish to deny
> access to this file, hence undo the
> open
>
> –
/
> {
> PSCANNER_STREAM_HANDLE_CONTEXT scannerContext;
> FLT_POSTOP_CALLBACK_STATUS returnStatus =
> FLT_POSTOP_FINISHED_PROCESSING;
> PFLT_FILE_NAME_INFORMATION nameInfo;
> NTSTATUS status;
> BOOLEAN safeToOpen, scanFile;
>
> UNREFERENCED_PARAMETER( CompletionContext );
> UNREFERENCED_PARAMETER( Flags );
>
> //
> // If this create was failing anyway, don’t bother scanning now.
> //
>
> if (!NT_SUCCESS( Data->IoStatus.Status ) ||
> (STATUS_REPARSE == Data->IoStatus.Status)) {
>
> return FLT_POSTOP_FINISHED_PROCESSING;
> }
>
> //
> // Check if we are interested in this file.
> //
>
> status = FltGetFileNameInformation( Data,
> FLT_FILE_NAME_NORMALIZED |
> FLT_FILE_NAME_QUERY_DEFAULT,
> &nameInfo );
>
> if (!NT_SUCCESS( status )) {
>
> return FLT_POSTOP_FINISHED_PROCESSING;
> }
>
> FltParseFileNameInformation( nameInfo );
>
> //
> // Check if the extension matches the list of extensions we are
> interested in
> //
>
> scanFile = ScannerpCheckExtension( &nameInfo->Extension );
>
> //
> // Release file name info, we’re done with it
> //
>
> FltReleaseFileNameInformation( nameInfo );
>
> if (!scanFile) {
>
> //
> // Not an extension we are interested in
> //
>
> return FLT_POSTOP_FINISHED_PROCESSING;
> }
>
> status = ScannerpScanFileInUserMode( FltObjects->Instance,
> FltObjects->FileObject,
> &safeToOpen );
>
> if (!safeToOpen) {
>
> //
> // Ask the filter manager to undo the create.
> //
>
> DbgPrint( “!!! scanner.sys – foul language detected in postcreate
> !!!\n” );
>
> DbgPrint( “!!! scanner.sys – undoing create \n” );
>
> FltCancelFileOpen( FltObjects->Instance, FltObjects->FileObject );
>
> Data->IoStatus.Status = STATUS_ACCESS_DENIED;
> Data->IoStatus.Information = 0;
>
> returnStatus = FLT_POSTOP_FINISHED_PROCESSING;
>
> } else if (FltObjects->FileObject->WriteAccess) {
>
> //
> //
> // The create has requested write access, mark to rescan the file.
> // Allocate the context.
> //
>
> status = FltAllocateContext( ScannerData.Filter,
> FLT_STREAMHANDLE_CONTEXT,
> sizeof(SCANNER_STREAM_HANDLE_CONTEXT),
> PagedPool,
> &scannerContext );
>
> if (NT_SUCCESS(status)) {
>
> //
> // Set the handle context.
> //
>
> scannerContext->RescanRequired = TRUE;
>
> status = FltSetStreamHandleContext( FltObjects->Instance,
> FltObjects->FileObject,
>
> FLT_SET_CONTEXT_REPLACE_IF_EXISTS,
> scannerContext,
> NULL );
>
> //
> // The only error status that could be returned would tell us
> that
> // contexts are not supported. Even if we got this error,
> // we just want to release the context now and that will free
> // this memory if it was not successfully set.
> //
>
> //
> // Release our reference on the context (the set adds a
> reference)
> //
>
> FltReleaseContext( scannerContext );
> }
> }
>
> return returnStatus;
> }
>
> I have to get the file name at post CREATE, check the file name to do
> appropriate operations. At the pre CREATE, I’m not sure to get exactly
> file name.
> Do you have any idea if I move the code to check file name at pre CREATE?
> --Thanks
>
>

Well, there are many things you need to consider. For example, the Scanner sample does not try to “undo” a user operation. It will simply block access to files that have “bad” content. So for overwrites and supersedes and newly created files it should never block access (since they are empty).

As others have pointed out, if your goal is to avoid files being created then you should focus on doing this in preCreate. In postCreate things get much more complicated.

Can you please explain what is it that you are trying to achieve ? Do you want to prevent new files being created ? Do you want to block access to existing files ? What is your policy for this (i.e. do you decide based on file name or on file contents) and so on…

Regards,
Alex.
This posting is provided “AS IS” with no warranties, and confers no rights.

Thanks Alex for your reply.
I will try to cancel the CREATE at the pre operation.

Thanks all.
I’ve moved the code from Post Create to Pre Create and it works correctly.
But there are some troubles to get the DOS name of a file:

NTSTATUS status;
PFLT_FILE_NAME_INFORMATION nameInfo = NULL;
UNICODE_STRING uniDosPath;

status = FltGetFileNameInformation( Data,
FLT_FILE_NAME_NORMALIZED |
FLT_FILE_NAME_QUERY_DEFAULT,
&nameInfo );

if (!NT_SUCCESS( status ))
{

leave;
}

status = FltParseFileNameInformation( nameInfo );
if (!NT_SUCCESS( status ))
{

leave;
}

uniDosPath.Buffer = ExAllocatePoolWithTag(NonPagedPool, MAX_PATH * sizeof(WCHAR), BUFFER_TAG);
RtlZeroMemory(uniDosPath.Buffer, MAX_PATH * sizeof(WCHAR));

// Build the path
memcpy(uniDosPath.Buffer, volCtx->Name.Buffer, volCtx->Name.Length);
memcpy(&uniDosPath.Buffer[volCtx->Name.Length / sizeof(WCHAR)], &nameInfo->Name.Buffer[nameInfo->Volume.Length / sizeof(WCHAR)], nameInfo->Name.Length - nameInfo->Volume.Length);

// Set the length for unicode string
uniDosPath.Length = volCtx->Name.Length + (nameInfo->Name.Length - nameInfo->Volume.Length);
uniDosPath.MaximumLength = uniDosPath.Length;

Can someone show me a better way to improve the performance?
Thanks a lot.