mirror of https://github.com/tongzx/nt5src
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.
595 lines
12 KiB
595 lines
12 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
cleanup.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the file cleanup routine for Netware Redirector.
|
|
|
|
Author:
|
|
|
|
Manny Weiser (mannyw) 9-Feb-1993
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "procs.h"
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CLEANUP)
|
|
|
|
//
|
|
// local procedure prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
NwCommonCleanup (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
|
|
NTSTATUS
|
|
NwCleanupRcb (
|
|
IN PIRP Irp,
|
|
IN PRCB Rcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCleanupScb (
|
|
IN PIRP Irp,
|
|
IN PSCB Scb
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCleanupIcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp,
|
|
IN PICB Icb
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, NwFsdCleanup )
|
|
#pragma alloc_text( PAGE, NwCommonCleanup )
|
|
#pragma alloc_text( PAGE, NwCleanupScb )
|
|
|
|
#ifndef QFE_BUILD
|
|
#pragma alloc_text( PAGE1, NwCleanupIcb )
|
|
#endif
|
|
|
|
#endif
|
|
|
|
#if 0 // Not pageable
|
|
|
|
NwCleanupRcb
|
|
|
|
// see ifndef QFE_BUILD above
|
|
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NwFsdCleanup (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the FSD part of the NtCleanupFile API calls.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the device object to use.
|
|
|
|
Irp - Supplies the Irp being processed
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - The Fsd status for the Irp
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIRP_CONTEXT IrpContext = NULL;
|
|
BOOLEAN TopLevel;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwFsdCleanup\n", 0);
|
|
|
|
//
|
|
// Call the common cleanup routine.
|
|
//
|
|
|
|
TopLevel = NwIsIrpTopLevel( Irp );
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
try {
|
|
|
|
IrpContext = AllocateIrpContext( Irp );
|
|
status = NwCommonCleanup( IrpContext );
|
|
|
|
} except(NwExceptionFilter( Irp, GetExceptionInformation() )) {
|
|
|
|
if ( IrpContext == NULL ) {
|
|
|
|
//
|
|
// If we couldn't allocate an irp context, just complete
|
|
// irp without any fanfare.
|
|
//
|
|
|
|
status = STATUS_INSUFFICIENT_RESOURCES;
|
|
Irp->IoStatus.Status = status;
|
|
Irp->IoStatus.Information = 0;
|
|
IoCompleteRequest ( Irp, IO_NETWORK_INCREMENT );
|
|
|
|
} else {
|
|
|
|
//
|
|
// We had some trouble trying to perform the requested
|
|
// operation, so we'll abort the I/O request with
|
|
// the error status that we get back from the
|
|
// execption code.
|
|
//
|
|
|
|
status = NwProcessException( IrpContext, GetExceptionCode() );
|
|
}
|
|
}
|
|
|
|
if ( IrpContext ) {
|
|
NwCompleteRequest( IrpContext, status );
|
|
}
|
|
|
|
if ( TopLevel ) {
|
|
NwSetTopLevelIrp( NULL );
|
|
}
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// Return to our caller.
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "NwFsdCleanup -> %08lx\n", status );
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCommonCleanup (
|
|
IN PIRP_CONTEXT IrpContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common routine for cleaning up a file.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - Supplies the Irp to process
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - the return status for the operation
|
|
|
|
--*/
|
|
|
|
{
|
|
PIRP Irp;
|
|
PIO_STACK_LOCATION irpSp;
|
|
NTSTATUS status;
|
|
NODE_TYPE_CODE nodeTypeCode;
|
|
PVOID fsContext, fsContext2;
|
|
|
|
PAGED_CODE();
|
|
|
|
Irp = IrpContext->pOriginalIrp;
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
DebugTrace(+1, Dbg, "NwCommonCleanup\n", 0);
|
|
DebugTrace( 0, Dbg, "IrpContext = %08lx\n", (ULONG_PTR)IrpContext);
|
|
DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG_PTR)Irp);
|
|
DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG_PTR)irpSp->FileObject);
|
|
|
|
try {
|
|
|
|
//
|
|
// Get the a referenced pointer to the node and make sure it is
|
|
// not being closed.
|
|
//
|
|
|
|
if ((nodeTypeCode = NwDecodeFileObject( irpSp->FileObject,
|
|
&fsContext,
|
|
&fsContext2 )) == NTC_UNDEFINED) {
|
|
|
|
DebugTrace(0, Dbg, "The file is disconnected\n", 0);
|
|
|
|
status = STATUS_INVALID_HANDLE;
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonCleanup -> %08lx\n", status );
|
|
try_return( NOTHING );
|
|
}
|
|
|
|
//
|
|
// Decide how to handle this IRP.
|
|
//
|
|
|
|
switch (nodeTypeCode) {
|
|
|
|
case NW_NTC_RCB: // Cleanup the file system
|
|
|
|
status = NwCleanupRcb( Irp, (PRCB)fsContext2 );
|
|
break;
|
|
|
|
case NW_NTC_SCB: // Cleanup the server control block
|
|
|
|
status = NwCleanupScb( Irp, (PSCB)fsContext2 );
|
|
break;
|
|
|
|
case NW_NTC_ICB: // Cleanup the remote file
|
|
case NW_NTC_ICB_SCB: // Cleanup the server
|
|
|
|
status = NwCleanupIcb( IrpContext, Irp, (PICB)fsContext2 );
|
|
break;
|
|
|
|
#ifdef NWDBG
|
|
default:
|
|
|
|
//
|
|
// This is not one of ours.
|
|
//
|
|
|
|
KeBugCheck( RDR_FILE_SYSTEM );
|
|
break;
|
|
#endif
|
|
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonCleanup -> %08lx\n", status);
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCleanupRcb (
|
|
IN PIRP Irp,
|
|
IN PRCB Rcb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine cleans up a RCB.
|
|
|
|
This routine grabs a spinlock so must not be paged out while running.
|
|
|
|
Do not reference the code section since this will start the timer and
|
|
we don't stop it in the rcb close path.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the IRP associated with the cleanup.
|
|
|
|
Rcb - Supplies the RCB for MSFS.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - An appropriate completion status
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
PIO_STACK_LOCATION irpSp;
|
|
PFILE_OBJECT closingFileObject;
|
|
BOOLEAN OwnRcb;
|
|
BOOLEAN OwnMessageLock = FALSE;
|
|
KIRQL OldIrql;
|
|
PLIST_ENTRY listEntry, nextListEntry;
|
|
PIRP_CONTEXT pTestIrpContext;
|
|
PIO_STACK_LOCATION pTestIrpSp;
|
|
PIRP pTestIrp;
|
|
|
|
DebugTrace(+1, Dbg, "NwCleanupRcb...\n", 0);
|
|
|
|
//
|
|
// Now acquire exclusive access to the Rcb
|
|
//
|
|
|
|
NwAcquireExclusiveRcb( Rcb, TRUE );
|
|
OwnRcb = TRUE;
|
|
|
|
status = STATUS_SUCCESS;
|
|
|
|
try {
|
|
|
|
irpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
|
|
IoRemoveShareAccess( irpSp->FileObject,
|
|
&Rcb->ShareAccess );
|
|
|
|
NwReleaseRcb( Rcb );
|
|
OwnRcb = FALSE;
|
|
|
|
closingFileObject = irpSp->FileObject;
|
|
|
|
|
|
//
|
|
// Walk the message queue and complete any outstanding Get Message IRPs
|
|
//
|
|
|
|
KeAcquireSpinLock( &NwMessageSpinLock, &OldIrql );
|
|
OwnMessageLock = TRUE;
|
|
|
|
for ( listEntry = NwGetMessageList.Flink;
|
|
listEntry != &NwGetMessageList;
|
|
listEntry = nextListEntry ) {
|
|
|
|
nextListEntry = listEntry->Flink;
|
|
|
|
//
|
|
// If the file object of the queued request, matches the file object
|
|
// that is being closed, remove the IRP from the queue, and
|
|
// complete it with an error.
|
|
//
|
|
|
|
pTestIrpContext = CONTAINING_RECORD( listEntry, IRP_CONTEXT, NextRequest );
|
|
pTestIrp = pTestIrpContext->pOriginalIrp;
|
|
pTestIrpSp = IoGetCurrentIrpStackLocation( pTestIrp );
|
|
|
|
if ( pTestIrpSp->FileObject == closingFileObject ) {
|
|
RemoveEntryList( listEntry );
|
|
|
|
IoAcquireCancelSpinLock( &pTestIrp->CancelIrql );
|
|
IoSetCancelRoutine( pTestIrp, NULL );
|
|
IoReleaseCancelSpinLock( pTestIrp->CancelIrql );
|
|
|
|
NwCompleteRequest( pTestIrpContext, STATUS_INVALID_HANDLE );
|
|
}
|
|
|
|
}
|
|
|
|
KeReleaseSpinLock( &NwMessageSpinLock, OldIrql );
|
|
OwnMessageLock = FALSE;
|
|
|
|
} finally {
|
|
|
|
if ( OwnRcb ) {
|
|
NwReleaseRcb( Rcb );
|
|
}
|
|
|
|
if ( OwnMessageLock ) {
|
|
KeReleaseSpinLock( &NwMessageSpinLock, OldIrql );
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "NwCleanupRcb -> %08lx\n", status);
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCleanupScb (
|
|
IN PIRP Irp,
|
|
IN PSCB Scb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine cleans up an ICB.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the IRP associated with the cleanup.
|
|
|
|
Scb - Supplies the SCB to cleanup.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - An appropriate completion status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwCleanupScb...\n", 0);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
try {
|
|
|
|
//
|
|
// Ensure that this SCB is still active.
|
|
//
|
|
|
|
NwVerifyScb( Scb );
|
|
|
|
//
|
|
// Cancel any IO on this SCB.
|
|
//
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "NwCleanupScb -> %08lx\n", Status);
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCleanupIcb (
|
|
IN PIRP_CONTEXT pIrpContext,
|
|
IN PIRP Irp,
|
|
IN PICB Icb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine cleans up an ICB.
|
|
|
|
Arguments:
|
|
|
|
Irp - Supplies the IRP associated with the cleanup.
|
|
|
|
Rcb - Supplies the RCB for MSFS.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - An appropriate completion status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PNONPAGED_FCB NpFcb;
|
|
|
|
DebugTrace(+1, Dbg, "NwCleanupIcb...\n", 0);
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
try {
|
|
|
|
Icb->State = ICB_STATE_CLEANED_UP;
|
|
|
|
//
|
|
// Cancel any IO on this ICB.
|
|
//
|
|
|
|
#if 0
|
|
// HACKHACK
|
|
|
|
if ( Icb->SuperType.Fcb->NodeTypeCode == NW_NTC_DCB ) {
|
|
|
|
PLIST_ENTRY listEntry;
|
|
|
|
NwAcquireExclusiveRcb( &NwRcb, TRUE );
|
|
|
|
for ( listEntry = FnList.Flink; listEntry != &FnList ; listEntry = listEntry->Flink ) {
|
|
|
|
PIRP_CONTEXT IrpContext;
|
|
|
|
IrpContext = CONTAINING_RECORD( listEntry, IRP_CONTEXT, NextRequest );
|
|
|
|
if ( IrpContext->Icb == Icb ) {
|
|
|
|
PIRP irp = pIrpContext->pOriginalIrp;
|
|
|
|
IoAcquireCancelSpinLock( &irp->CancelIrql );
|
|
IoSetCancelRoutine( irp, NULL );
|
|
IoReleaseCancelSpinLock( irp->CancelIrql );
|
|
|
|
RemoveEntryList( &IrpContext->NextRequest );
|
|
NwCompleteRequest( IrpContext, STATUS_NOT_SUPPORTED );
|
|
break;
|
|
}
|
|
}
|
|
|
|
NwReleaseRcb( &NwRcb );
|
|
}
|
|
#endif
|
|
|
|
//
|
|
// If this is a remote file clear all the cache garbage.
|
|
//
|
|
|
|
if ( Icb->NodeTypeCode == NW_NTC_ICB ) {
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
//
|
|
// Free all of file lock structures that are still hanging around.
|
|
//
|
|
|
|
pIrpContext->pScb = Icb->SuperType.Fcb->Scb;
|
|
pIrpContext->pNpScb = Icb->SuperType.Fcb->Scb->pNpScb;
|
|
|
|
NwFreeLocksForIcb( pIrpContext, Icb );
|
|
|
|
NwDequeueIrpContext( pIrpContext, FALSE );
|
|
|
|
//
|
|
//
|
|
//
|
|
// If this is an executable opened over the net, then
|
|
// its possible that the executables image section
|
|
// might still be kept open.
|
|
//
|
|
// Ask MM to flush the section closed. This will fail
|
|
// if the executable in question is still running.
|
|
//
|
|
|
|
NpFcb = Icb->SuperType.Fcb->NonPagedFcb;
|
|
MmFlushImageSection(&NpFcb->SegmentObject, MmFlushForWrite);
|
|
|
|
//
|
|
// There is also a possiblity that there is a user section
|
|
// open on this file, in which case we need to force the
|
|
// section closed to make sure that they are cleaned up.
|
|
//
|
|
|
|
MmForceSectionClosed(&NpFcb->SegmentObject, TRUE);
|
|
|
|
}
|
|
|
|
//
|
|
// Acquire the fcb and remove shared access.
|
|
//
|
|
|
|
NwAcquireExclusiveFcb( Icb->SuperType.Fcb->NonPagedFcb, TRUE );
|
|
|
|
IoRemoveShareAccess(
|
|
Icb->FileObject,
|
|
&Icb->SuperType.Fcb->ShareAccess );
|
|
|
|
NwReleaseFcb( Icb->SuperType.Fcb->NonPagedFcb );
|
|
}
|
|
|
|
|
|
} finally {
|
|
|
|
DebugTrace(-1, Dbg, "NwCleanupIcb -> %08lx\n", Status);
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return Status;
|
|
}
|
|
|