1167 lines
22 KiB
C
1167 lines
22 KiB
C
/*++
|
||
|
||
Copyright (c) 1989 Microsoft Corporation
|
||
|
||
Module Name:
|
||
|
||
block.c
|
||
|
||
Abstract:
|
||
|
||
This module implements block management functions.
|
||
|
||
Author:
|
||
|
||
Manny Weiser (mannyw) 12-29-91
|
||
|
||
Revision History:
|
||
|
||
--*/
|
||
|
||
#include "mup.h"
|
||
|
||
//
|
||
// The debug trace level
|
||
//
|
||
|
||
#define Dbg (DEBUG_TRACE_BLOCK)
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, MupAllocateMasterIoContext )
|
||
#pragma alloc_text( PAGE, MupAllocateMasterQueryContext )
|
||
#pragma alloc_text( PAGE, MupAllocatePrefixEntry )
|
||
#pragma alloc_text( PAGE, MupAllocateUncProvider )
|
||
#pragma alloc_text( PAGE, MupCalculateTimeout )
|
||
#pragma alloc_text( PAGE, MupCloseUncProvider )
|
||
#pragma alloc_text( PAGE, MupCreateCcb )
|
||
#pragma alloc_text( PAGE, MupCreateFcb )
|
||
#pragma alloc_text( PAGE, MupDereferenceVcb )
|
||
#pragma alloc_text( INIT, MupInitializeVcb )
|
||
#endif
|
||
|
||
VOID
|
||
MupInitializeVcb(
|
||
IN PVCB Vcb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine initializes the VCB for the MUP.
|
||
|
||
Arguments:
|
||
|
||
VCB - A pointer to the MUP VCB.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
DebugTrace(+1, Dbg, "MupInitializeVcb\n", 0);
|
||
|
||
RtlZeroMemory( Vcb, sizeof( VCB ) );
|
||
|
||
Vcb->BlockHeader.BlockType = BlockTypeVcb;
|
||
Vcb->BlockHeader.BlockState = BlockStateActive;
|
||
Vcb->BlockHeader.ReferenceCount = 1;
|
||
Vcb->BlockHeader.BlockSize = sizeof( VCB );
|
||
|
||
DebugTrace(-1, Dbg, "MupInitializeVcb -> VOID\n", 0);
|
||
}
|
||
|
||
VOID
|
||
MupDereferenceVcb(
|
||
PVCB Vcb
|
||
)
|
||
{
|
||
LONG result;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace( +1, Dbg, "MupDereferenceVcb\n", 0 );
|
||
|
||
result = InterlockedDecrement(
|
||
&Vcb->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
DebugTrace( 0, Dbg, "ReferenceCount = %d\n", Vcb->BlockHeader.ReferenceCount );
|
||
|
||
if ( result == 0 ) {
|
||
|
||
KeBugCheckEx( FILE_SYSTEM, 3, 0, 0, 0 );
|
||
}
|
||
|
||
DebugTrace( -1, Dbg, "MupDereferenceVcb -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
PFCB
|
||
MupCreateFcb(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates an FCB block
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the allocated FCB.
|
||
|
||
--*/
|
||
|
||
{
|
||
PFCB fcb;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace( +1, Dbg, "MupCreateFcb\n", 0 );
|
||
|
||
//
|
||
// Attempt to allocate memory.
|
||
//
|
||
|
||
fcb = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(FCB),
|
||
' puM');
|
||
|
||
if (fcb == NULL) {
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the UNC provider block header
|
||
//
|
||
|
||
fcb->BlockHeader.BlockType = BlockTypeFcb;
|
||
fcb->BlockHeader.BlockState = BlockStateActive;
|
||
fcb->BlockHeader.ReferenceCount = 1;
|
||
fcb->BlockHeader.BlockSize = sizeof( FCB );
|
||
|
||
InitializeListHead( &fcb->CcbList );
|
||
|
||
DebugTrace( -1, Dbg, "MupCreateFcb -> 0x%8lx\n", fcb );
|
||
return fcb;
|
||
|
||
|
||
}
|
||
|
||
VOID
|
||
MupDereferenceFcb(
|
||
PFCB Fcb
|
||
)
|
||
{
|
||
LONG result;
|
||
|
||
ASSERT( Fcb->BlockHeader.BlockType == BlockTypeFcb );
|
||
|
||
DebugTrace( +1, Dbg, "MupDereferenceFcb\n", 0 );
|
||
|
||
result = InterlockedDecrement(
|
||
&Fcb->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
DebugTrace( 0, Dbg, "ReferenceCount = %d\n", Fcb->BlockHeader.ReferenceCount);
|
||
|
||
if ( result == 0 ) {
|
||
|
||
ASSERT( IsListEmpty( &Fcb->CcbList ) );
|
||
|
||
MupFreeFcb( Fcb );
|
||
}
|
||
|
||
DebugTrace( -1, Dbg, "MupDereferenceFcb -> VOID\n", 0 );
|
||
|
||
}
|
||
|
||
VOID
|
||
MupFreeFcb(
|
||
PFCB Fcb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine frees an FCB block
|
||
|
||
Arguments:
|
||
|
||
A pointer to the FCB block to free.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugTrace( +1, Dbg, "MupFreeFcb\n", 0 );
|
||
ASSERT( Fcb->BlockHeader.BlockType == BlockTypeFcb );
|
||
|
||
ExFreePool( Fcb );
|
||
|
||
DebugTrace( -1, Dbg, "MupFreeFcb -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
PCCB
|
||
MupCreateCcb(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates an CCB block
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the allocated CCB.
|
||
|
||
--*/
|
||
|
||
{
|
||
PCCB ccb;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace( +1, Dbg, "MupCreateCcb\n", 0 );
|
||
|
||
//
|
||
// Attempt to allocate memory.
|
||
//
|
||
|
||
ccb = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
sizeof(CCB),
|
||
' puM');
|
||
|
||
if (ccb == NULL) {
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
//
|
||
// Initialize the UNC provider block header
|
||
//
|
||
|
||
ccb->BlockHeader.BlockType = BlockTypeCcb;
|
||
ccb->BlockHeader.BlockState = BlockStateActive;
|
||
ccb->BlockHeader.ReferenceCount = 1;
|
||
ccb->BlockHeader.BlockSize = sizeof( CCB );
|
||
|
||
DebugTrace( -1, Dbg, "MupCreateCcb -> 0x%8lx\n", ccb );
|
||
|
||
return ccb;
|
||
}
|
||
|
||
VOID
|
||
MupDereferenceCcb(
|
||
PCCB Ccb
|
||
)
|
||
{
|
||
LONG result;
|
||
|
||
DebugTrace( +1, Dbg, "MupDereferenceCcb\n", 0 );
|
||
|
||
ASSERT( Ccb->BlockHeader.BlockType == BlockTypeCcb );
|
||
|
||
result = InterlockedDecrement(
|
||
&Ccb->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
DebugTrace( 0, Dbg, "ReferenceCount = %d\n", Ccb->BlockHeader.ReferenceCount );
|
||
|
||
if ( result == 0 ) {
|
||
|
||
ACQUIRE_LOCK( &MupCcbListLock );
|
||
RemoveEntryList( &Ccb->ListEntry );
|
||
RELEASE_LOCK( &MupCcbListLock );
|
||
|
||
//
|
||
// Release our references then free the CCB.
|
||
//
|
||
|
||
ObDereferenceObject( Ccb->FileObject );
|
||
|
||
MupDereferenceFcb( Ccb->Fcb );
|
||
|
||
MupFreeCcb( Ccb );
|
||
}
|
||
|
||
DebugTrace( -1, Dbg, "MupDereferenceCcb -> VOID\n", 0 );
|
||
}
|
||
|
||
VOID
|
||
MupFreeCcb(
|
||
PCCB Ccb
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine frees a CCB block
|
||
|
||
Arguments:
|
||
|
||
A pointer to the CCB block to free.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugTrace( +1, Dbg, "MupFreeCcb\n", 0 );
|
||
|
||
ASSERT( Ccb->BlockHeader.BlockType == BlockTypeCcb );
|
||
|
||
ExFreePool( Ccb );
|
||
|
||
DebugTrace( -1, Dbg, "MupFreeCcb -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
PUNC_PROVIDER
|
||
MupAllocateUncProvider(
|
||
ULONG DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine allocates and initializes the VCB for the MUP.
|
||
|
||
Arguments:
|
||
|
||
DataLength - The size (in bytes) of the UNC provider.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PUNC_PROVIDER uncProvider;
|
||
ULONG size;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace(+1, Dbg, "MupAllocateUncProvider\n", 0);
|
||
|
||
size = DataLength + sizeof( UNC_PROVIDER );
|
||
|
||
uncProvider = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
size,
|
||
' puM');
|
||
|
||
if (uncProvider != NULL) {
|
||
|
||
//
|
||
// Initialize the UNC provider block header
|
||
//
|
||
|
||
uncProvider->BlockHeader.BlockType = BlockTypeUncProvider;
|
||
uncProvider->BlockHeader.BlockState = BlockStateActive;
|
||
uncProvider->BlockHeader.ReferenceCount = 0;
|
||
uncProvider->BlockHeader.BlockSize = size;
|
||
|
||
//
|
||
// By default we will make the provider unregistered
|
||
//
|
||
|
||
uncProvider->Registered = FALSE;
|
||
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "MupAllocateUncProvider -> 0x%8lx\n", uncProvider);
|
||
|
||
return uncProvider;
|
||
}
|
||
|
||
|
||
VOID
|
||
MupDereferenceUncProvider(
|
||
PUNC_PROVIDER UncProvider
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine dereference a UNC provider block.
|
||
|
||
Arguments:
|
||
|
||
UncProvider - A pointer to the UNC provider block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG result;
|
||
|
||
DebugTrace(+1, Dbg, "MupDereferenceProvider\n", 0);
|
||
|
||
ASSERT( UncProvider->BlockHeader.BlockType == BlockTypeUncProvider );
|
||
|
||
result = InterlockedDecrement(
|
||
&UncProvider->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
DebugTrace(0, Dbg, "ReferenceCount = %d\n", UncProvider->BlockHeader.ReferenceCount);
|
||
|
||
ASSERT( result >= 0 );
|
||
|
||
//
|
||
// Do not free this block, even if the result is zero. This
|
||
// saves us from having to reread information for this provider
|
||
// from the registry when the provider re-registers.
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "MupDereferenceUncProvider -> VOID\n", 0);
|
||
}
|
||
|
||
|
||
VOID
|
||
MupCloseUncProvider(
|
||
PUNC_PROVIDER UncProvider
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine closes a UNC provider block.
|
||
|
||
Arguments:
|
||
|
||
UncProvider - A pointer to the UNC provider block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
PAGED_CODE();
|
||
DebugTrace(+1, Dbg, "MupDereferenceProvider\n", 0);
|
||
|
||
ASSERT( UncProvider->BlockHeader.BlockType == BlockTypeUncProvider );
|
||
|
||
MupAcquireGlobalLock();
|
||
|
||
if ( UncProvider->BlockHeader.BlockState == BlockStateActive ) {
|
||
|
||
DebugTrace(0, Dbg, "Closing UNC provider %08lx\n", UncProvider );
|
||
|
||
UncProvider->BlockHeader.BlockState = BlockStateClosing;
|
||
|
||
//
|
||
// Mark the provider as unregistered
|
||
//
|
||
|
||
UncProvider->Registered = FALSE;
|
||
|
||
MupReleaseGlobalLock();
|
||
|
||
//
|
||
// Close our handle to the provider, and release our reference
|
||
// to the file object.
|
||
//
|
||
|
||
if (UncProvider->FileObject != NULL) {
|
||
ZwClose( UncProvider->Handle );
|
||
ObDereferenceObject( UncProvider->FileObject );
|
||
}
|
||
|
||
} else {
|
||
MupReleaseGlobalLock();
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "MupDereferenceUncProvider -> VOID\n", 0);
|
||
|
||
}
|
||
|
||
|
||
PKNOWN_PREFIX
|
||
MupAllocatePrefixEntry(
|
||
ULONG DataLength
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine allocates known prefix block.
|
||
|
||
Arguments:
|
||
|
||
DataLength - The size (in bytes) of the extra data to allocate in the
|
||
buffer for the prefix buffer.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the newly allocated block or NULL if it could not be
|
||
allocated.
|
||
|
||
--*/
|
||
|
||
{
|
||
PKNOWN_PREFIX knownPrefix;
|
||
ULONG size;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace(+1, Dbg, "MupAllocatePrefixEntry\n", 0);
|
||
|
||
size = DataLength + sizeof( KNOWN_PREFIX );
|
||
|
||
knownPrefix = ExAllocatePoolWithTag(
|
||
PagedPool,
|
||
size,
|
||
' puM');
|
||
|
||
if (knownPrefix == NULL) {
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
RtlZeroMemory( knownPrefix, size );
|
||
|
||
//
|
||
// Initialize the UNC provider block header
|
||
//
|
||
|
||
knownPrefix->BlockHeader.BlockType = BlockTypeKnownPrefix;
|
||
knownPrefix->BlockHeader.BlockState = BlockStateActive;
|
||
knownPrefix->BlockHeader.ReferenceCount = 1;
|
||
knownPrefix->BlockHeader.BlockSize = size;
|
||
|
||
if ( DataLength > 0 ) {
|
||
knownPrefix->Prefix.Buffer = (PWCH)(knownPrefix + 1);
|
||
knownPrefix->Prefix.MaximumLength = (USHORT)DataLength;
|
||
} else {
|
||
//
|
||
// It is up to the caller to really allocate the memory!
|
||
//
|
||
knownPrefix->PrefixStringAllocated = TRUE;
|
||
}
|
||
|
||
knownPrefix->Active = FALSE;
|
||
|
||
MupCalculateTimeout( &knownPrefix->LastUsedTime );
|
||
|
||
DebugTrace(-1, Dbg, "MupAllocatePrefixEntry -> 0x%8lx\n", knownPrefix);
|
||
|
||
return knownPrefix;
|
||
|
||
}
|
||
|
||
VOID
|
||
MupDereferenceKnownPrefix(
|
||
PKNOWN_PREFIX KnownPrefix
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine dereferences a Known prefix block.
|
||
|
||
*** MupPrefixTableLock assumed held when this routine is called.
|
||
Remains held on exit. ***
|
||
|
||
Arguments:
|
||
|
||
KnownPrefix - A pointer to the Known prefix block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG result;
|
||
|
||
DebugTrace(+1, Dbg, "MupDereferenceKnownPrefix\n", 0);
|
||
|
||
ASSERT( KnownPrefix->BlockHeader.BlockType == BlockTypeKnownPrefix );
|
||
|
||
result = InterlockedDecrement(
|
||
&KnownPrefix->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
DebugTrace(0, Dbg, "ReferenceCount = %d\n", KnownPrefix->BlockHeader.ReferenceCount);
|
||
|
||
ASSERT( result >= 0 );
|
||
|
||
if ( result == 0 ) {
|
||
|
||
//
|
||
// Remove the table entry
|
||
//
|
||
|
||
if ( KnownPrefix->InTable ) {
|
||
RtlRemoveUnicodePrefix( &MupPrefixTable, &KnownPrefix->TableEntry );
|
||
RemoveEntryList(&KnownPrefix->ListEntry);
|
||
}
|
||
|
||
//
|
||
// Free the Prefix string.
|
||
//
|
||
|
||
if ( KnownPrefix->PrefixStringAllocated &&
|
||
KnownPrefix->Prefix.Buffer != NULL ) {
|
||
|
||
ExFreePool( KnownPrefix->Prefix.Buffer );
|
||
}
|
||
|
||
//
|
||
// Dereference the associated UNC provider
|
||
//
|
||
|
||
if ( KnownPrefix->UncProvider != NULL ) {
|
||
MupDereferenceUncProvider( KnownPrefix->UncProvider );
|
||
}
|
||
|
||
//
|
||
// Time to free the block
|
||
//
|
||
|
||
MupFreeKnownPrefix( KnownPrefix );
|
||
|
||
}
|
||
|
||
DebugTrace( 0, Dbg, "MupDereferenceKnownPrefix -> VOID\n", 0 );
|
||
}
|
||
|
||
VOID
|
||
MupFreeKnownPrefix(
|
||
PKNOWN_PREFIX KnownPrefix
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine frees a known prefix block
|
||
|
||
Arguments:
|
||
|
||
A pointer to the known prefix block to free.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugTrace( +1, Dbg, "MupFreeKnownPrefix\n", 0 );
|
||
|
||
ASSERT( KnownPrefix->BlockHeader.BlockType == BlockTypeKnownPrefix );
|
||
|
||
ExFreePool( KnownPrefix );
|
||
|
||
DebugTrace( -1, Dbg, "MupFreeKnownPrefix -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
|
||
PMASTER_FORWARDED_IO_CONTEXT
|
||
MupAllocateMasterIoContext(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates a master fowarded io context block.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the master forwarded context block, or NULL if the
|
||
allocation fails
|
||
|
||
--*/
|
||
|
||
{
|
||
PMASTER_FORWARDED_IO_CONTEXT masterContext;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace( +1, Dbg, "MupAllocateMasterIoContext\n", 0 );
|
||
|
||
masterContext = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof( MASTER_FORWARDED_IO_CONTEXT ),
|
||
' puM');
|
||
|
||
if (masterContext != NULL) {
|
||
|
||
//
|
||
// Initialize the block header
|
||
//
|
||
|
||
masterContext->BlockHeader.BlockType = BlockTypeMasterIoContext;
|
||
masterContext->BlockHeader.BlockState = BlockStateActive;
|
||
masterContext->BlockHeader.ReferenceCount = 1;
|
||
masterContext->BlockHeader.BlockSize = sizeof( MASTER_FORWARDED_IO_CONTEXT );
|
||
|
||
}
|
||
|
||
DebugTrace( -1, Dbg, "MupAllocateWorkContext -> 0x%8lx\n", masterContext );
|
||
|
||
return masterContext;
|
||
}
|
||
|
||
|
||
|
||
NTSTATUS
|
||
MupDereferenceMasterIoContext(
|
||
PMASTER_FORWARDED_IO_CONTEXT MasterContext,
|
||
PNTSTATUS Status
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine dereferences a Master forwarded io context block.
|
||
If the count reaches zero the original IRP is completed.
|
||
|
||
Arguments:
|
||
|
||
A pointer to the a master forwarded io context block.
|
||
|
||
Status for this mini context.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - OPTIONAL - The status of the original IRP.
|
||
|
||
--*/
|
||
|
||
{
|
||
int result;
|
||
PIRP originalIrp;
|
||
NTSTATUS status;
|
||
PIO_STACK_LOCATION irpSp;
|
||
KIRQL oldIrql;
|
||
|
||
DebugTrace(+1, Dbg, "MupDereferenceMasterIoContext\n", 0);
|
||
DebugTrace( 0, Dbg, "MasterContext = 0x%08lx\n", MasterContext );
|
||
|
||
|
||
ASSERT( MasterContext->BlockHeader.BlockType == BlockTypeMasterIoContext );
|
||
|
||
//
|
||
// If any requests pass then set Irp status to success and leave
|
||
// it as success. If they all fail then use the last errorcode.
|
||
// To make this work we create the context with an error status.
|
||
//
|
||
|
||
if (Status != NULL) {
|
||
|
||
//
|
||
// We can modify MasterContext because we have it referenced and
|
||
// we write 32 bits which is atomic.
|
||
//
|
||
|
||
if (NT_SUCCESS(*Status)) {
|
||
|
||
MasterContext->SuccessStatus = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
MasterContext->ErrorStatus = *Status;
|
||
|
||
}
|
||
|
||
}
|
||
|
||
DebugTrace(0, Dbg, "ReferenceCount = %d\n", MasterContext->BlockHeader.ReferenceCount);
|
||
DebugTrace(0, Dbg, "MasterContext->Status = %8lx\n", MasterContext->ErrorStatus);
|
||
|
||
|
||
result = InterlockedDecrement(
|
||
&MasterContext->BlockHeader.ReferenceCount
|
||
);
|
||
|
||
ASSERT( result >= 0 );
|
||
|
||
if ( result == 0 ) {
|
||
|
||
//
|
||
// Complete the original IRP
|
||
//
|
||
|
||
originalIrp = MasterContext->OriginalIrp;
|
||
|
||
irpSp = IoGetCurrentIrpStackLocation( originalIrp );
|
||
if ( irpSp->MajorFunction == IRP_MJ_WRITE ) {
|
||
originalIrp->IoStatus.Information = irpSp->Parameters.Write.Length;
|
||
} else {
|
||
originalIrp->IoStatus.Information = 0;
|
||
}
|
||
|
||
//
|
||
// If any requests pass then set Irp status to success and return
|
||
// success. If they all fail then use the last errorcode.
|
||
//
|
||
|
||
if (NT_SUCCESS(MasterContext->SuccessStatus)) {
|
||
|
||
status = STATUS_SUCCESS;
|
||
|
||
} else {
|
||
|
||
status = MasterContext->ErrorStatus;
|
||
|
||
}
|
||
|
||
DebugTrace(0, Dbg, "MupCompleteRequest = %8lx\n", status);
|
||
MupCompleteRequest( originalIrp, status );
|
||
|
||
//
|
||
// Dereference the FCB
|
||
//
|
||
|
||
MupDereferenceFcb( MasterContext->Fcb );
|
||
|
||
//
|
||
// Free the Master context block
|
||
//
|
||
|
||
MupFreeMasterIoContext( MasterContext );
|
||
|
||
// return status
|
||
|
||
} else {
|
||
|
||
status = STATUS_PENDING;
|
||
|
||
}
|
||
|
||
DebugTrace( 0, Dbg, "MupDereferenceMasterIoContext -> %X\n", status );
|
||
|
||
return status;
|
||
}
|
||
|
||
VOID
|
||
MupFreeMasterIoContext(
|
||
PMASTER_FORWARDED_IO_CONTEXT MasterContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine frees a master forwarded io context block.
|
||
|
||
Arguments:
|
||
|
||
A pointer to the a master forwarded io context block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugTrace( +1, Dbg, "MupFreeMasterIoContext\n", 0 );
|
||
|
||
ASSERT( MasterContext->BlockHeader.BlockType == BlockTypeMasterIoContext );
|
||
ExFreePool( MasterContext );
|
||
|
||
DebugTrace( -1, Dbg, "MupFreeMasterIoContext -> VOID\n", 0 );
|
||
}
|
||
|
||
|
||
|
||
|
||
PMASTER_QUERY_PATH_CONTEXT
|
||
MupAllocateMasterQueryContext(
|
||
VOID
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine allocates a master query path context block.
|
||
|
||
Arguments:
|
||
|
||
None.
|
||
|
||
Return Value:
|
||
|
||
A pointer to the master query path block. If the allocation
|
||
fails, NULL is returned.
|
||
|
||
--*/
|
||
|
||
{
|
||
PMASTER_QUERY_PATH_CONTEXT masterContext;
|
||
|
||
PAGED_CODE();
|
||
DebugTrace( +1, Dbg, "MupAllocateMasterQueryContext\n", 0 );
|
||
|
||
masterContext = ExAllocatePoolWithTag(
|
||
NonPagedPool,
|
||
sizeof( MASTER_QUERY_PATH_CONTEXT ),
|
||
' puM');
|
||
|
||
if (masterContext == NULL) {
|
||
|
||
return NULL;
|
||
|
||
}
|
||
|
||
|
||
//
|
||
// Initialize the block header
|
||
//
|
||
|
||
masterContext->BlockHeader.BlockType = BlockTypeMasterQueryContext;
|
||
masterContext->BlockHeader.BlockState = BlockStateActive;
|
||
masterContext->BlockHeader.ReferenceCount = 1;
|
||
masterContext->BlockHeader.BlockSize = sizeof( MASTER_QUERY_PATH_CONTEXT );
|
||
InitializeListHead(&masterContext->MasterQueryList);
|
||
InitializeListHead(&masterContext->QueryList);
|
||
|
||
|
||
INITIALIZE_LOCK(
|
||
&masterContext->Lock,
|
||
QUERY_CONTEXT_LOCK_LEVEL,
|
||
"Master query context lock"
|
||
);
|
||
|
||
DebugTrace( -1, Dbg, "MupAllocateMasterQueryContext -> 0x%8lx\n", masterContext );
|
||
|
||
return masterContext;
|
||
}
|
||
|
||
NTSTATUS
|
||
MupDereferenceMasterQueryContext(
|
||
PMASTER_QUERY_PATH_CONTEXT MasterContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
The routine dereferences a Master query path context block.
|
||
If the count reaches zero the original IRP is completed.
|
||
|
||
Arguments:
|
||
|
||
A pointer to the a master query path context block.
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - The final create IRP status.
|
||
|
||
--*/
|
||
|
||
{
|
||
LONG result;
|
||
NTSTATUS status;
|
||
|
||
DebugTrace(+1, Dbg, "MupDereferenceMasterQueryContext\n", 0);
|
||
DebugTrace( 0, Dbg, "MasterContext = 0x%08lx\n", MasterContext );
|
||
|
||
ASSERT( MasterContext->BlockHeader.BlockType == BlockTypeMasterQueryContext );
|
||
|
||
MupAcquireGlobalLock();
|
||
|
||
result = --MasterContext->BlockHeader.ReferenceCount;
|
||
|
||
MupReleaseGlobalLock();
|
||
DebugTrace(0, Dbg, "ReferenceCount = %d\n", MasterContext->BlockHeader.ReferenceCount);
|
||
|
||
ASSERT( result >= 0 );
|
||
|
||
if ( result == 0 ) {
|
||
|
||
BOOLEAN fActive;
|
||
|
||
if (MasterContext->OriginalIrp == NULL) {
|
||
|
||
DbgPrint("OriginalIrp == NULL, MasterContext=0x%x\n", MasterContext);
|
||
KeBugCheck( FILE_SYSTEM );
|
||
|
||
}
|
||
|
||
// we are done with this master query so remove it from the global list
|
||
MupAcquireGlobalLock();
|
||
RemoveEntryList(&MasterContext->MasterQueryList);
|
||
MupReleaseGlobalLock();
|
||
|
||
|
||
ACQUIRE_LOCK( &MupPrefixTableLock );
|
||
|
||
fActive = MasterContext->KnownPrefix->Active;
|
||
|
||
MupDereferenceKnownPrefix( MasterContext->KnownPrefix );
|
||
|
||
//
|
||
// Reroute the request and complete the original IRP
|
||
//
|
||
|
||
if (( MasterContext->Provider != NULL) &&
|
||
( MasterContext->ErrorStatus == STATUS_SUCCESS )) {
|
||
|
||
//
|
||
// Remove final ref if nothing ended up in the table
|
||
//
|
||
if (fActive == FALSE) {
|
||
MupDereferenceKnownPrefix( MasterContext->KnownPrefix );
|
||
}
|
||
|
||
RELEASE_LOCK( &MupPrefixTableLock );
|
||
|
||
MUP_TRACE_NORM(TRACE_IRP, MupDereferenceMasterQueryContext_RerouteOpen,
|
||
LOGUSTR(MasterContext->Provider->DeviceName)
|
||
LOGUSTR(MasterContext->FileObject->FileName)
|
||
LOGPTR(MasterContext->OriginalIrp)
|
||
LOGPTR(MasterContext->FileObject));
|
||
status = MupRerouteOpen(
|
||
MasterContext->FileObject,
|
||
MasterContext->Provider
|
||
);
|
||
|
||
} else {
|
||
|
||
if (MasterContext->Provider != NULL) {
|
||
MupDereferenceUncProvider(MasterContext->Provider);
|
||
}
|
||
|
||
//
|
||
// No provider claimed this open. Dereference the known prefix
|
||
// entry and fail the create request.
|
||
//
|
||
|
||
MupDereferenceKnownPrefix( MasterContext->KnownPrefix );
|
||
RELEASE_LOCK( &MupPrefixTableLock );
|
||
status = MasterContext->ErrorStatus;
|
||
|
||
}
|
||
|
||
MUP_TRACE_NORM(TRACE_IRP, MupDereferenceMasterQueryContext_CompleteRequest,
|
||
LOGPTR(MasterContext->OriginalIrp)
|
||
LOGSTATUS(status));
|
||
FsRtlCompleteRequest( MasterContext->OriginalIrp, status );
|
||
MasterContext->OriginalIrp = NULL;
|
||
MupFreeMasterQueryContext( MasterContext );
|
||
|
||
} else {
|
||
|
||
status = STATUS_PENDING;
|
||
|
||
}
|
||
|
||
DebugTrace( 0, Dbg, "MupDereferenceMasterQueryContext -> 0x%08lx\n", status );
|
||
|
||
return status;
|
||
|
||
}
|
||
|
||
VOID
|
||
MupFreeMasterQueryContext(
|
||
PMASTER_QUERY_PATH_CONTEXT MasterContext
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine frees a master query path context block.
|
||
|
||
Arguments:
|
||
|
||
A pointer to the a master query path context block.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
DebugTrace( +1, Dbg, "MupFreeMasterQueryPathContext\n", 0 );
|
||
|
||
ASSERT( BlockType( MasterContext ) == BlockTypeMasterQueryContext );
|
||
|
||
DELETE_LOCK( &MasterContext->Lock );
|
||
ExFreePool( MasterContext );
|
||
|
||
DebugTrace( -1, Dbg, "MupFreeMasterQueryPathContext -> VOID\n", 0 );
|
||
}
|
||
|
||
VOID
|
||
MupCalculateTimeout(
|
||
PLARGE_INTEGER Time
|
||
)
|
||
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine calculates the an absolute timeout time. This value
|
||
equals the current system time plus the MUP timeout time.
|
||
|
||
Arguments:
|
||
|
||
A pointer to the time structure.
|
||
|
||
Return Value:
|
||
|
||
None.
|
||
|
||
--*/
|
||
|
||
{
|
||
LARGE_INTEGER now;
|
||
|
||
PAGED_CODE();
|
||
KeQuerySystemTime( &now );
|
||
Time->QuadPart = now.QuadPart + MupKnownPrefixTimeout.QuadPart;
|
||
|
||
return;
|
||
}
|