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.
450 lines
12 KiB
450 lines
12 KiB
//+----------------------------------------------------------------------------
|
|
//
|
|
// Copyright (C) 1992, Microsoft Corporation.
|
|
//
|
|
// File: CLOSE.C
|
|
//
|
|
// Contents: This module implements the File Close and Cleanup routines for
|
|
// Dsfs called by the dispatch driver.
|
|
//
|
|
// Functions: DfsFsdClose - FSD entry point for Close IRP
|
|
// DfsFsdCleanup - FSD entry point for Cleanup IRP
|
|
// DfsFspClose - FSP entry point for Close IRP
|
|
// DfsCommonClose - Common close IRP handler
|
|
//
|
|
// History: 12 Nov 1991 AlanW Created from CDFS souce.
|
|
//-----------------------------------------------------------------------------
|
|
|
|
|
|
#include "dfsprocs.h"
|
|
#include "fcbsup.h"
|
|
#include "mupwml.h"
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CLOSE)
|
|
|
|
//
|
|
// Local procedure prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
DfsCommonClose (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
);
|
|
|
|
VOID
|
|
DfsCloseWorkInSystemContext (
|
|
PDFS_FCB pDfsFcb );
|
|
|
|
VOID
|
|
DfsClosePostSystemWork(
|
|
PDFS_FCB pDfsFcb );
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, DfsFsdClose )
|
|
#pragma alloc_text( PAGE, DfsFsdCleanup )
|
|
#pragma alloc_text( PAGE, DfsFspClose )
|
|
#pragma alloc_text( PAGE, DfsCommonClose )
|
|
#endif // ALLOC_PRAGMA
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsdClose, public
|
|
//
|
|
// Synopsis: This routine implements the FSD part of closing down the
|
|
// last reference to a file object.
|
|
//
|
|
// Arguments: [DeviceObject] -- Supplies the device object where the
|
|
// file being closed exists
|
|
// [Irp] - Supplies the Irp being processed
|
|
//
|
|
// Returns: NTSTATUS - The FSD status for the IRP
|
|
//
|
|
// Notes: Even when the close is through the attached device
|
|
// object, we need to check if the file is one of ours,
|
|
// since files opened via the logical root device
|
|
// object get switched over to the attached device for
|
|
// local volumes.
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsdClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
) {
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
NTSTATUS Status;
|
|
PIRP_CONTEXT IrpContext;
|
|
|
|
MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Entry,
|
|
LOGPTR(DeviceObject)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject));
|
|
|
|
DfsDbgTrace(+1, Dbg, "DfsFsdClose: Entered\n", 0);
|
|
ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
|
|
|
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS_VOLUME) {
|
|
if (DfsLookupFcb(IrpSp->FileObject) == NULL) {
|
|
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
|
DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status) );
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Call the common close routine, with blocking allowed if synchronous
|
|
//
|
|
FsRtlEnterFileSystem();
|
|
|
|
try {
|
|
|
|
IrpContext = DfsCreateIrpContext( Irp, CanFsdWait( Irp ) );
|
|
if (IrpContext == NULL)
|
|
ExRaiseStatus(STATUS_INSUFFICIENT_RESOURCES);
|
|
Status = DfsCommonClose( IrpContext, Irp );
|
|
|
|
|
|
} except(DfsExceptionFilter( IrpContext, GetExceptionCode(), GetExceptionInformation() )) {
|
|
|
|
//
|
|
// 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 = DfsProcessException( IrpContext, Irp, GetExceptionCode() );
|
|
}
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFsdClose: Exit -> %08lx\n", ULongToPtr(Status));
|
|
|
|
MUP_TRACE_HIGH(TRACE_IRP, DfsFsdClose_Exit,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(DeviceObject)
|
|
LOGPTR(Irp)
|
|
LOGPTR(FileObject));
|
|
return Status;
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFsdCleanup, public
|
|
//
|
|
// Synopsis: This routine implements the FSD part of closing down the
|
|
// last user handle to a file object.
|
|
//
|
|
// Arguments: [DeviceObject] -- Supplies the device object where the
|
|
// file being closed exists
|
|
// [Irp] - Supplies the Irp being processed
|
|
//
|
|
// Returns: NTSTATUS - The FSD status for the IRP
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsFsdCleanup (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
) {
|
|
NTSTATUS Status;
|
|
PIRP_CONTEXT IrpContext;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
TYPE_OF_OPEN TypeOfOpen;
|
|
PDFS_VCB Vcb;
|
|
PDFS_FCB Fcb;
|
|
|
|
DfsDbgTrace(+1, Dbg, "DfsFsdCleanup: Entered\n", 0);
|
|
MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Entry,
|
|
LOGPTR(DeviceObject)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
|
|
ASSERT(IoIsOperationSynchronous(Irp) == TRUE);
|
|
|
|
//
|
|
// Now, pass through to the device that opened the file for us if the
|
|
// file was a redirected open of some kind.
|
|
//
|
|
|
|
if (DeviceObject->DeviceType == FILE_DEVICE_DFS) {
|
|
TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
|
|
if (TypeOfOpen == RedirectedFileOpen) {
|
|
Status = DfsVolumePassThrough(DeviceObject, Irp);
|
|
DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: RedirectedOpen.Exit -> %08lx\n", ULongToPtr(Status) );
|
|
return Status;
|
|
}
|
|
}
|
|
|
|
//
|
|
// TypeOfOpen != RedirectedFileOpen. We do nothing special for cleanup;
|
|
// everything is done in the close routine.
|
|
//
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
Status = STATUS_SUCCESS;
|
|
|
|
DfsCompleteRequest( NULL, Irp, Status );
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFsdCleanup: Exit -> %08lx\n", ULongToPtr(Status));
|
|
|
|
MUP_TRACE_HIGH(TRACE_IRP, DfsFsdCleanup_Exit,
|
|
LOGSTATUS(Status)
|
|
LOGPTR(DeviceObject)
|
|
LOGPTR(FileObject)
|
|
LOGPTR(Irp));
|
|
return Status;
|
|
|
|
}
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsFspClose, public
|
|
//
|
|
// Synopsis: This routine implements the FSP part of closing down the
|
|
// last reference to a file object.
|
|
//
|
|
// Arguments: [IrpContext] -- Supplies the IRP context for the request
|
|
// being processed.
|
|
// [Irp] - Supplies the Irp being processed
|
|
//
|
|
// Returns: PDEVICE_OBJECT - Returns the volume device object
|
|
// of the volume just processed by this operation.
|
|
// This value is used by the Fsp dispatcher to examine
|
|
// the device object's overflow queue
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
|
|
VOID
|
|
DfsFspClose (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
) {
|
|
DfsDbgTrace(+1, Dbg, "DfsFspClose: Entered\n", 0);
|
|
|
|
//
|
|
// Call the common close routine.
|
|
//
|
|
|
|
(VOID)DfsCommonClose( IrpContext, Irp );
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsFspClose: Exit -> VOID\n", 0);
|
|
}
|
|
|
|
|
|
|
|
|
|
//+-------------------------------------------------------------------
|
|
//
|
|
// Function: DfsCommonClose, local
|
|
//
|
|
// Synopsis: This is the common routine for closing a file/directory
|
|
// called by both the fsd and fsp threads.
|
|
//
|
|
// Close is invoked whenever the last reference to a file
|
|
// object is deleted. Cleanup is invoked when the last handle
|
|
// to a file object is closed, and is called before close.
|
|
//
|
|
// The function of close is to completely tear down and
|
|
// remove the DFS_FCB structures associated with the
|
|
// file object.
|
|
//
|
|
// Arguments: [Irp] -- Supplies the Irp to process
|
|
//
|
|
// Returns: NTSTATUS - The return status for the operation
|
|
//
|
|
//--------------------------------------------------------------------
|
|
|
|
NTSTATUS
|
|
DfsCommonClose (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PIRP Irp
|
|
) {
|
|
NTSTATUS Status = STATUS_SUCCESS;
|
|
|
|
PIO_STACK_LOCATION IrpSp = IoGetCurrentIrpStackLocation( Irp );
|
|
PFILE_OBJECT FileObject = IrpSp->FileObject;
|
|
|
|
TYPE_OF_OPEN TypeOfOpen;
|
|
PDFS_VCB Vcb;
|
|
PDFS_FCB Fcb;
|
|
|
|
BOOLEAN DontComplete = FALSE;
|
|
BOOLEAN pktLocked;
|
|
|
|
DfsDbgTrace(+1, Dbg, "DfsCommonClose: Entered\n", 0);
|
|
|
|
DfsDbgTrace( 0, Dbg, "Irp = %08lx\n", Irp);
|
|
DfsDbgTrace( 0, Dbg, "->FileObject = %08lx\n", FileObject);
|
|
|
|
|
|
//
|
|
// This action is a noop for unopened file objects. Nothing needs
|
|
// to be done for FS device opens, either.
|
|
//
|
|
|
|
TypeOfOpen = DfsDecodeFileObject( FileObject, &Vcb, &Fcb);
|
|
if (TypeOfOpen == UnopenedFileObject ||
|
|
TypeOfOpen == FilesystemDeviceOpen ) {
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsCommonClose: Filesystem file object\n", 0);
|
|
DfsCompleteRequest( IrpContext, Irp, STATUS_SUCCESS );
|
|
return STATUS_SUCCESS;
|
|
}
|
|
|
|
try {
|
|
|
|
//
|
|
// Case on the type of open that we are trying to close.
|
|
//
|
|
|
|
switch (TypeOfOpen) {
|
|
|
|
case LogicalRootDeviceOpen:
|
|
|
|
DfsDbgTrace(0, Dbg, "DfsCommonClose: Close LogicalRootDevice\n", 0);
|
|
|
|
InterlockedDecrement(&Vcb->DirectAccessOpenCount);
|
|
InterlockedDecrement(&Vcb->OpenFileCount);
|
|
|
|
if (Vcb->VcbState & VCB_STATE_FLAG_LOCKED) {
|
|
Vcb->VcbState &= ~VCB_STATE_FLAG_LOCKED;
|
|
Vcb->FileObjectWithVcbLocked = NULL;
|
|
}
|
|
|
|
try_return( Status = STATUS_SUCCESS );
|
|
|
|
case RedirectedFileOpen:
|
|
|
|
DfsDbgTrace(0, Dbg, "DfsCommonClose: File -> %wZ\n", &Fcb->FullFileName);
|
|
|
|
//
|
|
// Decrement the OpenFileCount for the Vcb through which this
|
|
// file was opened.
|
|
//
|
|
|
|
InterlockedDecrement(&Vcb->OpenFileCount);
|
|
|
|
|
|
//
|
|
// Close the redirected file by simply passing through
|
|
// to the redirected device. We detach the DFS_FCB from the
|
|
// file object before the close so it cannot be looked
|
|
// up in some other thread.
|
|
//
|
|
|
|
DfsDetachFcb( FileObject, Fcb);
|
|
Status = DfsFilePassThrough(Fcb, Irp);
|
|
|
|
DontComplete = TRUE;
|
|
|
|
//
|
|
// Post to system work here, to avoid deadlocks with RDR.
|
|
// workaround for bug 20642.
|
|
//
|
|
DfsClosePostSystemWork( Fcb );
|
|
|
|
break;
|
|
|
|
default:
|
|
BugCheck("Dfs close, unexpected open type");
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
//
|
|
// If this is a normal termination, then complete the request.
|
|
// Even if we're not to complete the IRP, we still need to
|
|
// delete the IRP_CONTEXT.
|
|
//
|
|
|
|
if (!AbnormalTermination()) {
|
|
if (DontComplete) {
|
|
DfsCompleteRequest( IrpContext, NULL, 0 );
|
|
} else {
|
|
DfsCompleteRequest( IrpContext, Irp, Status );
|
|
}
|
|
}
|
|
|
|
DfsDbgTrace(-1, Dbg, "DfsCommonClose: Exit -> %08lx\n", ULongToPtr(Status));
|
|
}
|
|
return Status;
|
|
}
|
|
|
|
|
|
VOID
|
|
DfsClosePostSystemWork(
|
|
PDFS_FCB pDfsFcb )
|
|
{
|
|
ExInitializeWorkItem( &pDfsFcb->WorkQueueItem,
|
|
DfsCloseWorkInSystemContext,
|
|
pDfsFcb );
|
|
|
|
ExQueueWorkItem( &pDfsFcb->WorkQueueItem, CriticalWorkQueue );
|
|
|
|
return;
|
|
}
|
|
|
|
//
|
|
//work around for bug 20642.
|
|
//
|
|
VOID
|
|
DfsCloseWorkInSystemContext (
|
|
PDFS_FCB pDfsFcb )
|
|
{
|
|
|
|
BOOLEAN pktLocked;
|
|
//
|
|
// Decrement the RefCount on the DFS_MACHINE_ENTRY through which
|
|
// this file was opened
|
|
//
|
|
|
|
PktAcquireExclusive( TRUE, &pktLocked );
|
|
|
|
ExAcquireResourceExclusiveLite( &DfsData.Resource, TRUE );
|
|
|
|
DfsDecrementMachEntryCount(pDfsFcb->DfsMachineEntry, TRUE);
|
|
|
|
ExReleaseResourceLite( &DfsData.Resource );
|
|
|
|
PktRelease();
|
|
|
|
|
|
DfsDeleteFcb( NULL, pDfsFcb );
|
|
}
|
|
|
|
|