Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1321 lines
33 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
create.c
Abstract:
This module implements the file create routine for the MUP.
Author:
Manny Weiser (mannyw) 16-Dec-1991
Revision History:
--*/
#include "mup.h"
#include "fsrtl.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_CREATE)
//
// Local functions
//
NTSTATUS
CreateRedirectedFile(
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PIO_SECURITY_CONTEXT Security
);
NTSTATUS
QueryPathCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
);
NTSTATUS
MupRerouteOpenToDfs (
IN PFILE_OBJECT FileObject
);
NTSTATUS
BroadcastOpen (
IN PIRP Irp
);
IO_STATUS_BLOCK
OpenMupFileSystem (
IN PVCB Vcb,
IN PFILE_OBJECT FileObject,
IN ACCESS_MASK DesiredAccess,
IN USHORT ShareAccess
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, BroadcastOpen )
#pragma alloc_text( PAGE, CreateRedirectedFile )
#pragma alloc_text( PAGE, MupCreate )
#pragma alloc_text( PAGE, MupRerouteOpen )
#pragma alloc_text( PAGE, MupRerouteOpenToDfs )
#pragma alloc_text( PAGE, OpenMupFileSystem )
#pragma alloc_text( PAGE, QueryPathCompletionRoutine )
#endif
NTSTATUS
MupCreate (
IN PMUP_DEVICE_OBJECT MupDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine implements the the Create IRP.
Arguments:
MupDeviceObject - Supplies the device object to use.
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The status for the IRP.
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT fileObject;
PFILE_OBJECT relatedFileObject;
STRING fileName;
ACCESS_MASK desiredAccess;
USHORT shareAccess;
BOOLEAN caseInsensitive = TRUE; //**** Make all searches case insensitive
PVCB vcb;
PAGED_CODE();
DebugTrace(+1, Dbg, "MupCreate\n", 0);
//
// Make local copies of our input parameters to make things easier.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
fileObject = irpSp->FileObject;
relatedFileObject = irpSp->FileObject->RelatedFileObject;
fileName = *((PSTRING)(&irpSp->FileObject->FileName));
desiredAccess = irpSp->Parameters.Create.SecurityContext->DesiredAccess;
shareAccess = irpSp->Parameters.Create.ShareAccess;
vcb = &MupDeviceObject->Vcb;
DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp );
DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)fileObject );
DebugTrace( 0, Dbg, "FileName = %Z\n", (ULONG)&fileName );
FsRtlEnterFileSystem();
try {
//
// Check to see if this is an open that came in via a Dfs device
// object.
//
if (MupEnableDfs) {
if ((MupDeviceObject->DeviceObject.DeviceType == FILE_DEVICE_DFS) ||
(MupDeviceObject->DeviceObject.DeviceType ==
FILE_DEVICE_DFS_FILE_SYSTEM)) {
status = DfsFsdCreate( (PDEVICE_OBJECT) MupDeviceObject, Irp );
try_return( NOTHING );
}
}
//
// Check if we are trying to open the mup file system
//
if ( fileName.Length == 0
&&
( relatedFileObject == NULL ||
BlockType(relatedFileObject->FsContext) == BlockTypeVcb ) ) {
DebugTrace(0, Dbg, "Open MUP file system\n", 0);
Irp->IoStatus = OpenMupFileSystem( &MupDeviceObject->Vcb,
fileObject,
desiredAccess,
shareAccess );
status = Irp->IoStatus.Status;
MupCompleteRequest( Irp, status );
try_return( NOTHING );
}
//
// This is a UNC file open. Try to pass the request on.
//
status = CreateRedirectedFile(
Irp,
fileObject,
irpSp->Parameters.Create.SecurityContext
);
if ( status == STATUS_REPARSE ) {
Irp->IoStatus.Information = IO_REPARSE;
} else if( status == STATUS_PENDING ) {
IoMarkIrpPending( Irp );
}
try_exit: NOTHING;
} except ( EXCEPTION_EXECUTE_HANDLER ) {
NOTHING;
}
FsRtlExitFileSystem();
DebugTrace(-1, Dbg, "MupCreate -> %08lx\n", status);
return status;
}
IO_STATUS_BLOCK
OpenMupFileSystem (
IN PVCB Vcb,
IN PFILE_OBJECT FileObject,
IN ACCESS_MASK DesiredAccess,
IN USHORT ShareAccess
)
/*++
Routine Description:
This routine attempts to open the VCB.
Arguments:
Vcb - A pointer to the MUP volume control block.
FileObject - A pointer to the IO system supplied file object for this
Create IRP.
DesiredAccess - The user specified desired access to the VCB.
ShareAccess - The user specified share access to the VCB.
Return Value:
NTSTATUS - The status for the IRP.
--*/
{
IO_STATUS_BLOCK iosb;
PAGED_CODE();
DebugTrace(+1, Dbg, "MupOpenMupFileSystem\n", 0 );
ExAcquireResourceExclusive( &MupVcbLock, TRUE );
try {
//
// Set the new share access
//
if (!NT_SUCCESS(iosb.Status = IoCheckShareAccess( DesiredAccess,
ShareAccess,
FileObject,
&Vcb->ShareAccess,
TRUE ))) {
DebugTrace(0, Dbg, "bad share access\n", 0);
try_return( NOTHING );
}
//
// Supply the file object with a referenced pointer to the VCB.
//
MupReferenceBlock( Vcb );
MupSetFileObject( FileObject, Vcb, NULL );
//
// Set the return status.
//
iosb.Status = STATUS_SUCCESS;
iosb.Information = FILE_OPENED;
try_exit: NOTHING;
} finally {
ExReleaseResource( &MupVcbLock );
}
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "MupOpenMupFileSystem -> Iosb.Status = %08lx\n", iosb.Status);
return iosb;
}
NTSTATUS
CreateRedirectedFile(
IN PIRP Irp,
IN PFILE_OBJECT FileObject,
IN PIO_SECURITY_CONTEXT SecurityContext
)
/*++
Routine Description:
This routine attempts to reroute a file create request to a redirector.
It attempts to find the correct redirector in 2 steps.
(1) The routine checks a list of known prefixes. If the file object -
file name prefix matches a known prefix, the request is forwarded to
the redirector that "owns" the prefix.
(2) The routine queries each redirector in turn, until one claims
ownership of the file. The request is then rerouted to that redirector.
If after these steps no owner is located, the MUP fails the request.
Arguments:
Irp - A pointer to the create IRP.
FileObject - A pointer to the IO system supplied file object for this
create request.
SecurityContext - A pointer to the IO security context for this request.
Return Value:
NTSTATUS - The status for the IRP.
--*/
{
NTSTATUS status;
PUNICODE_PREFIX_TABLE_ENTRY entry;
PKNOWN_PREFIX knownPrefix;
PLIST_ENTRY listEntry;
PUNC_PROVIDER provider;
PWCH buffer;
USHORT length;
BOOLEAN ownLock;
BOOLEAN providerReferenced = FALSE;
PQUERY_PATH_REQUEST qpRequest;
PMASTER_QUERY_PATH_CONTEXT masterContext = NULL;
PQUERY_PATH_CONTEXT queryContext;
PIRP irp;
PIO_STACK_LOCATION irpSp;
LARGE_INTEGER now;
PAGED_CODE();
DebugTrace(+1, Dbg, "CreateRedirectedFile\n", 0);
//
// Check to see if this file name begins with a known prefix.
//
ACQUIRE_LOCK( &MupPrefixTableLock );
entry = RtlFindUnicodePrefix( &MupPrefixTable, &FileObject->FileName, TRUE );
if ( entry != NULL ) {
DebugTrace(0, Dbg, "Prefix %Z is known, rerouting...\n", (PSTRING)&FileObject->FileName);
//
// This is a known file, forward appropriately
//
knownPrefix = CONTAINING_RECORD( entry, KNOWN_PREFIX, TableEntry );
KeQuerySystemTime( &now );
if ( now.QuadPart < knownPrefix->LastUsedTime.QuadPart ) {
//
// The known prefix has not timed out yet, recalculate the
// timeout time and reroute the open.
//
MupCalculateTimeout( &knownPrefix->LastUsedTime );
RELEASE_LOCK( &MupPrefixTableLock );
status = MupRerouteOpen( FileObject, knownPrefix->UncProvider );
DebugTrace(-1, Dbg, "CreateRedirectedFile -> %8lx", status );
MupCompleteRequest( Irp, status );
return status;
} else {
DebugTrace(0, Dbg, "Prefix %Z has timed out\n", (PSTRING)&FileObject->FileName);
//
// The known prefix has timed out, dereference it so that
// it will get removed from the table.
//
MupDereferenceKnownPrefix( knownPrefix );
RELEASE_LOCK( &MupPrefixTableLock );
}
} else {
RELEASE_LOCK( &MupPrefixTableLock );
}
//
// Is this a client side mailslot file? It is if the file name
// is of the form \\server\mailslot\Anything, and this is a create
// operation.
//
irpSp = IoGetCurrentIrpStackLocation( Irp );
buffer = (PWCH)FileObject->FileName.Buffer;
length = FileObject->FileName.Length;
if ( *buffer == L'\\' && irpSp->MajorFunction == IRP_MJ_CREATE ) {
buffer++;
while ( (length -= sizeof(WCHAR)) > 0 && *buffer++ != L'\\' );
length -= sizeof(WCHAR);
if ( length > 0 &&
_wcsnicmp(
buffer,
L"Mailslot",
MIN( length/sizeof(WCHAR), (sizeof( L"MAILSLOT" ) - sizeof(WCHAR)) / sizeof(WCHAR) ) ) == 0 ) {
//
// This is a mailslot file. Forward the create IRP to all
// redirectors that support broadcast.
//
DebugTrace(0, Dbg, "Prefix %Z is a mailslot\n", (ULONG)&FileObject->FileName);
status = BroadcastOpen( Irp );
DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
MupCompleteRequest( Irp, status );
return status;
}
}
//
// Check to see if this is a Dfs name. If so, we'll handle it separately
//
if (MupEnableDfs &&
(FileObject->FsContext2 != (PVOID) DFS_DOWNLEVEL_OPEN_CONTEXT)) {
UNICODE_STRING pathName;
status = DfsFsctrlIsThisADfsPath( &FileObject->FileName, &pathName );
if (status == STATUS_SUCCESS) {
DebugTrace(-1, Dbg, "Rerouting open of [%wZ] to Dfs\n", &FileObject->FileName);
status = MupRerouteOpenToDfs(FileObject);
MupCompleteRequest( Irp, status );
return( status );
}
}
try {
//
// Create an entry for this file.
//
knownPrefix = MupAllocatePrefixEntry( 0 );
//
// We don't know who owns this file, query the redirectors in sequence
// until one works.
//
masterContext = MupAllocateMasterQueryContext();
masterContext->OriginalIrp = Irp;
masterContext->FileObject = FileObject;
masterContext->Provider = NULL;
masterContext->KnownPrefix = knownPrefix;
masterContext->ErrorStatus = STATUS_BAD_NETWORK_PATH;
MupAcquireGlobalLock();
MupReferenceBlock( knownPrefix );
MupReleaseGlobalLock();
try {
MupAcquireGlobalLock();
ownLock = TRUE;
listEntry = MupProviderList.Flink;
while ( listEntry != &MupProviderList ) {
provider = CONTAINING_RECORD(
listEntry,
UNC_PROVIDER,
ListEntry
);
//
// Reference the provider block so that it doesn't go away
// while we are using it.
//
MupReferenceBlock( provider );
providerReferenced = TRUE;
MupReleaseGlobalLock();
ownLock = FALSE;
//
// Allocate buffers for the io request.
//
qpRequest = ALLOCATE_PAGED_POOL(
sizeof( QUERY_PATH_REQUEST ) +
FileObject->FileName.Length,
BlockTypeBuffer
);
queryContext = ALLOCATE_PAGED_POOL(
sizeof( QUERY_PATH_CONTEXT ),
BlockTypeQueryContext
);
queryContext->MasterContext = masterContext;
queryContext->Buffer = qpRequest;
//
// Generate a query path request.
//
qpRequest->PathNameLength = FileObject->FileName.Length;
qpRequest->SecurityContext = SecurityContext;
RtlMoveMemory(
qpRequest->FilePathName,
FileObject->FileName.Buffer,
FileObject->FileName.Length
);
//
// Build the query path Io control IRP.
//
irp = MupBuildIoControlRequest(
NULL,
provider->FileObject,
queryContext,
IRP_MJ_DEVICE_CONTROL,
IOCTL_REDIR_QUERY_PATH,
qpRequest,
sizeof( QUERY_PATH_REQUEST ) + FileObject->FileName.Length,
qpRequest,
sizeof( QUERY_PATH_RESPONSE ),
QueryPathCompletionRoutine
);
if ( irp == NULL ) {
ExRaiseStatus( STATUS_INSUFFICIENT_RESOURCES );
}
//
// Set the RequestorMode to KernelMode, since all the
// parameters to this Irp are in kernel space
//
irp->RequestorMode = KernelMode;
//
// Get a referenced pointer to the provider, the reference
// is release when the IO completes.
//
queryContext->Provider = provider;
MupAcquireGlobalLock();
MupReferenceBlock( provider );
MupReferenceBlock( masterContext );
MupReleaseGlobalLock();
//
// Submit the request.
//
IoCallDriver( provider->DeviceObject, irp );
//
// Acquire the lock that protects the provider list, and get
// a pointer to the next provider in the list.
//
MupAcquireGlobalLock();
ownLock = TRUE;
listEntry = listEntry->Flink;
MupDereferenceUncProvider( provider );
providerReferenced = FALSE;
} // while
} finally {
//
// Dereference the previous provider.
//
if ( providerReferenced ) {
MupDereferenceUncProvider( provider );
}
if ( ownLock ) {
MupReleaseGlobalLock();
}
}
} finally {
if (AbnormalTermination()) {
status = STATUS_INSUFFICIENT_RESOURCES;
MupCompleteRequest( Irp, status );
} else {
ASSERT( masterContext != NULL );
//
// Release our reference to the query context.
//
status = MupDereferenceMasterQueryContext( masterContext );
}
}
DebugTrace(-1, Dbg, "CreateRedirectedFile -> 0x%8lx\n", status );
return status;
}
NTSTATUS
MupRerouteOpen (
IN PFILE_OBJECT FileObject,
IN PUNC_PROVIDER UncProvider
)
/*++
Routine Description:
This routine redirects an create IRP request to the specified redirector
by changing the name of the file and returning STATUS_REPARSE to the
IO system
Arguments:
FileObject - The file object to open
UncProvider - The UNC provider that will process the create IRP.
Return Value:
NTSTATUS - The status of the operation
--*/
{
PCHAR buffer;
ULONG deviceNameLength;
PAGED_CODE();
//
// Allocate storage for the new file name.
//
buffer = ExAllocatePoolWithTag(
PagedPool,
UncProvider->DeviceName.Length + FileObject->FileName.Length,
' puM'
);
if ( buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Copy the device name to the string buffer.
//
RtlMoveMemory(
buffer,
UncProvider->DeviceName.Buffer,
UncProvider->DeviceName.Length
);
deviceNameLength = UncProvider->DeviceName.Length;
//
// Append the file name
//
RtlMoveMemory(
buffer + deviceNameLength,
FileObject->FileName.Buffer,
FileObject->FileName.Length
);
//
// Free the old file name string buffer.
//
ExFreePool( FileObject->FileName.Buffer );
FileObject->FileName.Buffer = (PWCHAR)buffer;
FileObject->FileName.MaximumLength =
FileObject->FileName.Length + (USHORT)deviceNameLength;
FileObject->FileName.Length = FileObject->FileName.MaximumLength;
//
// Tell the file system to try again.
//
return STATUS_REPARSE;
}
NTSTATUS
MupRerouteOpenToDfs (
IN PFILE_OBJECT FileObject
)
/*++
Routine Description:
This routine redirects an create IRP request to the Dfs part of this
driver by changing the name of the file and returning
STATUS_REPARSE to the IO system
Arguments:
FileObject - The file object to open
Return Value:
NTSTATUS - The status of the operation
--*/
{
PCHAR buffer;
ULONG deviceNameLength;
PAGED_CODE();
//
// Allocate storage for the new file name.
//
buffer = ExAllocatePoolWithTag(
PagedPool,
sizeof(DFS_DEVICE_ROOT) + FileObject->FileName.Length,
' puM'
);
if ( buffer == NULL) {
return STATUS_INSUFFICIENT_RESOURCES;
}
//
// Copy the device name to the string buffer.
//
RtlMoveMemory(
buffer,
DFS_DEVICE_ROOT,
sizeof(DFS_DEVICE_ROOT)
);
deviceNameLength = sizeof(DFS_DEVICE_ROOT) - sizeof(UNICODE_NULL);
//
// Append the file name
//
RtlMoveMemory(
buffer + deviceNameLength,
FileObject->FileName.Buffer,
FileObject->FileName.Length
);
//
// Free the old file name string buffer.
//
ExFreePool( FileObject->FileName.Buffer );
FileObject->FileName.Buffer = (PWCHAR)buffer;
FileObject->FileName.MaximumLength =
FileObject->FileName.Length + (USHORT)deviceNameLength;
FileObject->FileName.Length = FileObject->FileName.MaximumLength;
//
// Tell the file system to try again.
//
return STATUS_REPARSE;
}
NTSTATUS
BroadcastOpen (
PIRP Irp
)
/*++
Routine Description:
Arguments:
Return Value:
NTSTATUS - The status for the IRP.
--*/
{
NTSTATUS status;
PFCB fcb;
PIO_STACK_LOCATION irpSp;
PFILE_OBJECT fileObject;
BOOLEAN requestForwarded;
PLIST_ENTRY listEntry;
PUNC_PROVIDER uncProvider, previousUncProvider = NULL;
OBJECT_ATTRIBUTES objectAttributes;
IO_STATUS_BLOCK ioStatusBlock;
PCCB ccb;
OBJECT_HANDLE_INFORMATION handleInformation;
HANDLE handle;
BOOLEAN lockHeld = FALSE;
BOOLEAN providerReferenced = FALSE;
NTSTATUS statusToReturn = STATUS_NO_SUCH_FILE;
ULONG priorityOfStatus = 0xFFFFFFFF;
PAGED_CODE();
DebugTrace(+1, Dbg, "BroadcastOpen\n", 0 );
irpSp = IoGetCurrentIrpStackLocation( Irp );
try {
//
// Create a FCB for this file.
//
fcb = MupCreateFcb( );
//
// Set the file object back pointers and our pointer to the
// server file object.
//
fileObject = irpSp->FileObject;
MupAcquireGlobalLock();
lockHeld = TRUE;
MupSetFileObject( fileObject,
fcb,
NULL );
fcb->FileObject = fileObject;
//
// Loop through the list of UNC providers and try to create the
// file on all file systems that support broadcast.
//
requestForwarded = FALSE;
listEntry = MupProviderList.Flink;
while ( listEntry != &MupProviderList ) {
uncProvider = CONTAINING_RECORD( listEntry, UNC_PROVIDER, ListEntry );
//
// Reference the provider so that it won't go away
//
MupReferenceBlock( uncProvider );
providerReferenced = TRUE;
MupReleaseGlobalLock();
lockHeld = FALSE;
if ( uncProvider->MailslotsSupported ) {
//
// Build the rerouted file name, consisting of the file
// named we received appended to the UNC provider device
// name.
//
UNICODE_STRING fileName;
fileName.MaximumLength = fileName.Length =
uncProvider->DeviceName.Length + fileObject->FileName.Length;
fileName.Buffer =
ALLOCATE_PAGED_POOL(
fileName.MaximumLength,
BlockTypeBuffer
);
RtlMoveMemory(
fileName.Buffer,
uncProvider->DeviceName.Buffer,
uncProvider->DeviceName.Length
);
RtlMoveMemory(
(PCHAR)fileName.Buffer + uncProvider->DeviceName.Length,
fileObject->FileName.Buffer,
fileObject->FileName.Length
);
//
// Attempt to open the file. Copy all of the information
// from the create IRP we received, masking off additional
// baggage that the IO system added along the way.
//
DebugTrace( 0, Dbg, "Attempt to open %Z\n", (ULONG)&fileName );
InitializeObjectAttributes(
&objectAttributes,
&fileName,
OBJ_CASE_INSENSITIVE, // !!! can we do this?
0,
NULL // !!! Security
);
status = IoCreateFile(
&handle,
irpSp->Parameters.Create.SecurityContext->DesiredAccess & 0x1FF,
&objectAttributes,
&ioStatusBlock,
NULL,
irpSp->Parameters.Create.FileAttributes & FILE_ATTRIBUTE_VALID_FLAGS,
irpSp->Parameters.Create.ShareAccess & FILE_SHARE_VALID_FLAGS,
FILE_OPEN,
irpSp->Parameters.Create.Options & FILE_VALID_SET_FLAGS,
NULL, // Ea buffer
0, // Ea length
CreateFileTypeNone,
NULL, // parameters
IO_NO_PARAMETER_CHECKING
);
FREE_POOL( fileName.Buffer );
if ( NT_SUCCESS( status ) ) {
status = ioStatusBlock.Status;
}
if ( NT_SUCCESS( status ) ) {
DebugTrace( 0, Dbg, "Open attempt succeeded\n", 0 );
ccb = MupCreateCcb( );
status = ObReferenceObjectByHandle(
handle,
0,
NULL,
KernelMode,
(PVOID *)&ccb->FileObject,
&handleInformation
);
ASSERT( NT_SUCCESS( status ) );
ZwClose( handle );
ccb->DeviceObject =
IoGetRelatedDeviceObject( ccb->FileObject );
ccb->Fcb = fcb;
MupAcquireGlobalLock();
lockHeld = TRUE;
MupReferenceBlock( fcb );
MupReleaseGlobalLock();
lockHeld = FALSE;
//
// At least one provider will accept this mailslot
// request.
//
requestForwarded = TRUE;
//
// Keep a list of CCBs. Since we just created the FCB
// there is no need to use the lock to access the list.
//
InsertTailList( &fcb->CcbList, &ccb->ListEntry );
} else { // NT_SUCCESS( status ), IoCreateFile
DebugTrace( 0, Dbg, "Open attempt failed %8lx\n", status );
//
// Remember the status code if this is the highest
// priority provider so far. This code is returned if
// all providers fail the Create operation.
//
if ( uncProvider->Priority <= priorityOfStatus ) {
priorityOfStatus = uncProvider->Priority;
statusToReturn = status;
}
}
} // uncProvider->MailslotsSupported
MupAcquireGlobalLock();
lockHeld = TRUE;
listEntry = listEntry->Flink;
//
// It is now safe to dereference the previous provider.
//
MupDereferenceUncProvider( uncProvider );
providerReferenced = FALSE;
} // while
MupReleaseGlobalLock();
lockHeld = FALSE;
//
// And set our return status
//
if ( requestForwarded ) {
status = STATUS_SUCCESS;
} else {
status = statusToReturn;
}
} finally {
DebugTrace(-1, Dbg, "BroadcastOpen -> %08lx\n", status);
if ( providerReferenced ) {
MupDereferenceUncProvider( uncProvider );
}
if ( lockHeld ) {
MupReleaseGlobalLock();
}
//
// Now if we ever terminate the preceding try-statement with
// a status that is not successful and the FCB pointer
// is non-null then we need to deallocate the structure.
//
if (!NT_SUCCESS( status ) && fcb != NULL) {
MupFreeFcb( fcb );
}
}
return status;
}
NTSTATUS
QueryPathCompletionRoutine (
IN PDEVICE_OBJECT DeviceObject,
IN PIRP Irp,
IN PVOID Context
)
/*++
Routine Description:
This is the completion routine the querying a path. Cleanup our
IRP and complete the original IRP if necessary.
Arguments:
DeviceObject - Pointer to target device object for the request.
Irp - Pointer to I/O request packet
Context - Caller-specified context parameter associated with IRP.
This is actually a pointer to a Work Context block.
Return Value:
NTSTATUS - If STATUS_MORE_PROCESSING_REQUIRED is returned, I/O
completion processing by IoCompleteRequest terminates its
operation. Otherwise, IoCompleteRequest continues with I/O
completion.
--*/
{
PQUERY_PATH_RESPONSE qpResponse;
PMASTER_QUERY_PATH_CONTEXT masterContext;
PQUERY_PATH_CONTEXT queryPathContext;
PCH buffer;
PKNOWN_PREFIX knownPrefix;
ULONG lengthAccepted;
NTSTATUS status;
DeviceObject; // prevent compiler warnings
queryPathContext = Context;
masterContext = queryPathContext->MasterContext;
qpResponse = queryPathContext->Buffer;
lengthAccepted = qpResponse->LengthAccepted;
status = Irp->IoStatus.Status;
//
// Acquire the lock to protect access to the master context Provider
// field.
//
ACQUIRE_LOCK( &masterContext->Lock );
if ( NT_SUCCESS( status ) &&
lengthAccepted != 0) {
knownPrefix = masterContext->KnownPrefix;
if ( masterContext->Provider != NULL ) {
if ( queryPathContext->Provider->Priority < masterContext->Provider->Priority ) {
//
// A provider of higher priority (i.e. a lower priority code)
// has claimed this prefix. Release the previous provider's
// claim.
//
ACQUIRE_LOCK( &MupPrefixTableLock );
if ( knownPrefix->InTable ) {
RtlRemoveUnicodePrefix(
&MupPrefixTable,
&knownPrefix->TableEntry
);
knownPrefix->InTable = FALSE;
}
RELEASE_LOCK( &MupPrefixTableLock );
FREE_POOL( knownPrefix->Prefix.Buffer );
MupDereferenceUncProvider( knownPrefix->UncProvider );
} else {
//
// The current provider keeps ownership of the prefix.
//
goto not_this_one;
}
}
//
// This provider get the prefix.
//
masterContext->Provider = queryPathContext->Provider;
try {
//
// We have found a match. Attempt to remember it.
//
if (masterContext->FileObject->FsContext2 != (PVOID) DFS_DOWNLEVEL_OPEN_CONTEXT) {
buffer = ALLOCATE_PAGED_POOL( lengthAccepted, BlockTypeBuffer );
RtlMoveMemory(
buffer,
masterContext->FileObject->FileName.Buffer,
lengthAccepted
);
//
// Copy the reference provider pointer for the known prefix
// block.
//
knownPrefix->UncProvider = masterContext->Provider;
knownPrefix->Prefix.Buffer = (PWCH)buffer;
knownPrefix->Prefix.Length = (USHORT)lengthAccepted;
knownPrefix->Prefix.MaximumLength = (USHORT)lengthAccepted;
knownPrefix->PrefixStringAllocated = TRUE;
ACQUIRE_LOCK( &MupPrefixTableLock );
RtlInsertUnicodePrefix(
&MupPrefixTable,
&knownPrefix->Prefix,
&knownPrefix->TableEntry
);
knownPrefix->InTable = TRUE;
RELEASE_LOCK( &MupPrefixTableLock );
}
} finally {
if ( AbnormalTermination() ) {
ACQUIRE_LOCK( &MupPrefixTableLock );
MupDereferenceKnownPrefix( knownPrefix );
RELEASE_LOCK( &MupPrefixTableLock );
}
RELEASE_LOCK( &masterContext->Lock );
//
// Free our buffers
//
FREE_POOL( qpResponse );
FREE_POOL( queryPathContext );
IoFreeIrp( Irp );
}
} else {
//
// If our error status is more significant than the error status
// stored in the masterContext, then put ours there
//
ULONG newError, oldError;
//
// MupOrderedErrorList is a list of error codes ordered from least
// important to most important. We're calling down to multiple
// redirectors, but we can only return 1 error code on complete failure.
//
// To figure out which error to return, we look at the stored error and
// the current error. We return the error having the highest index in
// the MupOrderedErrorList
//
if( NT_SUCCESS( masterContext->ErrorStatus ) ) {
masterContext->ErrorStatus = status;
} else {
for( oldError = 0; MupOrderedErrorList[ oldError ]; oldError++ )
if( masterContext->ErrorStatus == MupOrderedErrorList[ oldError ] )
break;
for( newError = 0; newError < oldError; newError++ )
if( status == MupOrderedErrorList[ newError ] )
break;
if( newError >= oldError ) {
masterContext->ErrorStatus = status;
}
}
not_this_one:
MupDereferenceUncProvider( queryPathContext->Provider );
//
// Free our buffers
//
FREE_POOL( qpResponse );
FREE_POOL( queryPathContext );
IoFreeIrp( Irp );
RELEASE_LOCK( &masterContext->Lock );
}
MupDereferenceMasterQueryContext( masterContext );
//
// Return more processing required to the IO system so that it
// doesn't attempt further processing on the IRP we just freed.
//
return STATUS_MORE_PROCESSING_REQUIRED;
}