📄 close.c
字号:
Wait - If this is TRUE we are allowed to block for the Vcb, if FALSE
then we must try to acquire the Vcb anyway.
VcbDeleted - Returns whether the VCB was deleted by this call.
Return Value:
NTSTATUS - The return status for the operation
--*/
{
NTSTATUS Status;
PDCB ParentDcb;
BOOLEAN RecursiveClose;
BOOLEAN LocalVcbDeleted;
IRP_CONTEXT IrpContext;
DebugTrace(+1, Dbg, "FatCommonClose...\n", 0);
//
// Initailize the callers variable, if needed.
//
LocalVcbDeleted = FALSE;
if (ARGUMENT_PRESENT( VcbDeleted )) {
*VcbDeleted = LocalVcbDeleted;
}
//
// Special case the unopened file object
//
if (TypeOfOpen == UnopenedFileObject) {
DebugTrace(0, Dbg, "Close unopened file object\n", 0);
Status = STATUS_SUCCESS;
DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status);
return Status;
}
//
// Set up our stack IrpContext.
//
RtlZeroMemory( &IrpContext, sizeof(IRP_CONTEXT) );
IrpContext.NodeTypeCode = FAT_NTC_IRP_CONTEXT;
IrpContext.NodeByteSize = sizeof( IrpContext );
IrpContext.MajorFunction = IRP_MJ_CLOSE;
IrpContext.Vcb = Vcb;
if (Wait) {
SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
}
//
// Acquire exclusive access to the Vcb and enqueue the irp if we didn't
// get access.
//
if (!ExAcquireResourceExclusiveLite( &Vcb->Resource, Wait )) {
return STATUS_PENDING;
}
//
// The following test makes sure that we don't blow away an Fcb if we
// are trying to do a Supersede/Overwrite open above us. This test
// does not apply for the EA file.
//
if (FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CREATE_IN_PROGRESS) &&
Vcb->EaFcb != Fcb) {
ExReleaseResourceLite( &Vcb->Resource );
return STATUS_PENDING;
}
//
// Setting the following flag prevents recursive closes of directory file
// objects, which are handled in a special case loop.
//
if ( FlagOn(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS) ) {
RecursiveClose = TRUE;
} else {
SetFlag(Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS);
RecursiveClose = FALSE;
//
// Since we are at the top of the close chain, we need to add
// a reference to the VCB. This will keep it from going away
// on us until we are ready to check for a dismount below.
//
Vcb->OpenFileCount += 1;
}
try {
//
// Case on the type of open that we are trying to close.
//
switch (TypeOfOpen) {
case VirtualVolumeFile:
DebugTrace(0, Dbg, "Close VirtualVolumeFile\n", 0);
//
// Remove this internal, residual open from the count.
//
InterlockedDecrement( &(Vcb->InternalOpenCount) );
InterlockedDecrement( &(Vcb->ResidualOpenCount) );
try_return( Status = STATUS_SUCCESS );
break;
case UserVolumeOpen:
DebugTrace(0, Dbg, "Close UserVolumeOpen\n", 0);
Vcb->DirectAccessOpenCount -= 1;
Vcb->OpenFileCount -= 1;
if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; }
FatDeleteCcb( &IrpContext, &Ccb );
try_return( Status = STATUS_SUCCESS );
break;
case EaFile:
DebugTrace(0, Dbg, "Close EaFile\n", 0);
//
// Remove this internal, residual open from the count.
//
InterlockedDecrement( &(Vcb->InternalOpenCount) );
InterlockedDecrement( &(Vcb->ResidualOpenCount) );
try_return( Status = STATUS_SUCCESS );
break;
case DirectoryFile:
DebugTrace(0, Dbg, "Close DirectoryFile\n", 0);
InterlockedDecrement( &Fcb->Specific.Dcb.DirectoryFileOpenCount );
//
// Remove this internal open from the count.
//
InterlockedDecrement( &(Vcb->InternalOpenCount) );
//
// If this is the root directory, it is a residual open
// as well.
//
if (NodeType( Fcb ) == FAT_NTC_ROOT_DCB) {
InterlockedDecrement( &(Vcb->ResidualOpenCount) );
}
//
// If this is a recursive close, just return here.
//
if ( RecursiveClose ) {
try_return( Status = STATUS_SUCCESS );
} else {
break;
}
case UserDirectoryOpen:
case UserFileOpen:
DebugTrace(0, Dbg, "Close UserFileOpen/UserDirectoryOpen\n", 0);
//
// Uninitialize the cache map if we no longer need to use it
//
if ((NodeType(Fcb) == FAT_NTC_DCB) &&
IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue) &&
(Fcb->OpenCount == 1) &&
(Fcb->Specific.Dcb.DirectoryFile != NULL)) {
PFILE_OBJECT DirectoryFileObject = Fcb->Specific.Dcb.DirectoryFile;
DebugTrace(0, Dbg, "Uninitialize the stream file object\n", 0);
CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
//
// Dereference the directory file. This may cause a close
// Irp to be processed, so we need to do this before we destory
// the Fcb.
//
Fcb->Specific.Dcb.DirectoryFile = NULL;
ObDereferenceObject( DirectoryFileObject );
}
Fcb->OpenCount -= 1;
Vcb->OpenFileCount -= 1;
if (FlagOn(Ccb->Flags, CCB_FLAG_READ_ONLY)) { Vcb->ReadOnlyCount -= 1; }
FatDeleteCcb( &IrpContext, &Ccb );
break;
default:
FatBugCheck( TypeOfOpen, 0, 0 );
}
//
// At this point we've cleaned up any on-disk structure that needs
// to be done, and we can now update the in-memory structures.
// Now if this is an unreferenced FCB or if it is
// an unreferenced DCB (not the root) then we can remove
// the fcb and set our ParentDcb to non null.
//
if (((NodeType(Fcb) == FAT_NTC_FCB) &&
(Fcb->OpenCount == 0))
||
((NodeType(Fcb) == FAT_NTC_DCB) &&
(IsListEmpty(&Fcb->Specific.Dcb.ParentDcbQueue)) &&
(Fcb->OpenCount == 0) &&
(Fcb->Specific.Dcb.DirectoryFileOpenCount == 0))) {
ParentDcb = Fcb->ParentDcb;
SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
FatDeleteFcb( &IrpContext, &Fcb );
//
// Uninitialize our parent's cache map if we no longer need
// to use it.
//
while ((NodeType(ParentDcb) == FAT_NTC_DCB) &&
IsListEmpty(&ParentDcb->Specific.Dcb.ParentDcbQueue) &&
(ParentDcb->OpenCount == 0) &&
(ParentDcb->Specific.Dcb.DirectoryFile != NULL)) {
PFILE_OBJECT DirectoryFileObject;
DirectoryFileObject = ParentDcb->Specific.Dcb.DirectoryFile;
DebugTrace(0, Dbg, "Uninitialize our parent Stream Cache Map\n", 0);
CcUninitializeCacheMap( DirectoryFileObject, NULL, NULL );
ParentDcb->Specific.Dcb.DirectoryFile = NULL;
ObDereferenceObject( DirectoryFileObject );
//
// Now, if the ObDereferenceObject() caused the final close
// to come in, then blow away the Fcb and continue up,
// otherwise wait for Mm to to dereference its file objects
// and stop here..
//
if ( ParentDcb->Specific.Dcb.DirectoryFileOpenCount == 0) {
PDCB CurrentDcb;
CurrentDcb = ParentDcb;
ParentDcb = CurrentDcb->ParentDcb;
SetFlag( Vcb->VcbState, VCB_STATE_FLAG_DELETED_FCB );
FatDeleteFcb( &IrpContext, &CurrentDcb );
} else {
break;
}
}
}
Status = STATUS_SUCCESS;
try_exit: NOTHING;
} finally {
DebugUnwind( FatCommonClose );
//
// We are done processing the close. If we are the top of the close
// chain, see if the VCB can go away. We have biased the open count by
// one, so we need to take that into account.
//
if (!RecursiveClose) {
//
// See if there is only one open left. If so, it is ours. We only want
// to check for a dismount if a dismount is not already in progress.
// We also only do this if the caller can handle the VCB going away.
// This is determined by whether they passed in the VcbDeleted argument.
//
if (Vcb->OpenFileCount == 1 &&
!FlagOn( Vcb->VcbState, VCB_STATE_FLAG_DISMOUNT_IN_PROGRESS )
&& ARGUMENT_PRESENT( VcbDeleted )) {
//
// We need the global lock, which must be acquired before the
// VCB. Since we already have the VCB, we have to drop and
// reaquire here. Note that we always want to wait from this
// point on. Note that the VCB cannot go away, since we have
// biased the open file count.
//
FatReleaseVcb( &IrpContext,
Vcb );
SetFlag( IrpContext.Flags, IRP_CONTEXT_FLAG_WAIT );
FatAcquireExclusiveGlobal( &IrpContext );
FatAcquireExclusiveVcb( &IrpContext,
Vcb );
//
// We have our locks in the correct order. Remove our
// extra open and check for a dismount. Note that if
// something changed while we dropped the lock, it will
// not matter, since the dismount code does the correct
// checks to make sure the volume can really go away.
//
Vcb->OpenFileCount -= 1;
LocalVcbDeleted = FatCheckForDismount( &IrpContext,
Vcb,
FALSE );
FatReleaseGlobal( &IrpContext );
//
// Let the caller know what happened, if they want this information.
//
if (ARGUMENT_PRESENT( VcbDeleted )) {
*VcbDeleted = LocalVcbDeleted;
}
} else {
//
// The volume cannot go away now. Just remove our extra reference.
//
Vcb->OpenFileCount -= 1;
}
//
// If the VCB is still around, clear our recursion flag.
//
if (!LocalVcbDeleted) {
ClearFlag( Vcb->VcbState, VCB_STATE_FLAG_CLOSE_IN_PROGRESS );
}
}
//
// Only release the VCB if it did not go away.
//
if (!LocalVcbDeleted) {
FatReleaseVcb( &IrpContext, Vcb );
}
DebugTrace(-1, Dbg, "FatCommonClose -> %08lx\n", Status);
}
return Status;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -