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.
1166 lines
23 KiB
1166 lines
23 KiB
/*++
|
|
|
|
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;
|
|
}
|