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.
580 lines
13 KiB
580 lines
13 KiB
/*++
|
|
|
|
Copyright (c) 1992-4 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
Close.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the File Close routine for the NetWare
|
|
redirector called by the dispatch driver.
|
|
|
|
Author:
|
|
|
|
Colin Watson [ColinW] 19-Dec-1992
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "Procs.h"
|
|
|
|
//
|
|
// The local debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_CLOSE)
|
|
|
|
//
|
|
// Local procedure prototypes
|
|
//
|
|
|
|
NTSTATUS
|
|
NwCommonClose (
|
|
IN PIRP_CONTEXT IrpContext
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCloseRcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRCB Rcb
|
|
);
|
|
|
|
NTSTATUS
|
|
NwCloseIcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb
|
|
);
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, NwFsdClose )
|
|
#pragma alloc_text( PAGE, NwCommonClose )
|
|
#pragma alloc_text( PAGE, NwCloseRcb )
|
|
#pragma alloc_text( PAGE, NwCloseIcb )
|
|
#endif
|
|
|
|
|
|
NTSTATUS
|
|
NwFsdClose (
|
|
IN PDEVICE_OBJECT DeviceObject,
|
|
IN PIRP Irp
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This routine implements the FSD part of Close.
|
|
|
|
Arguments:
|
|
|
|
DeviceObject - Supplies the redirector device object.
|
|
|
|
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, "NwFsdClose\n", 0);
|
|
|
|
FsRtlEnterFileSystem();
|
|
|
|
NwReferenceUnlockableCodeSection ();
|
|
|
|
//
|
|
// Call the common Close routine
|
|
//
|
|
|
|
TopLevel = NwIsIrpTopLevel( Irp );
|
|
|
|
try {
|
|
|
|
IrpContext = AllocateIrpContext( Irp );
|
|
Status = NwCommonClose( 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 ) {
|
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|
NwCompleteRequest( IrpContext, Status );
|
|
}
|
|
|
|
if ( TopLevel ) {
|
|
NwSetTopLevelIrp( NULL );
|
|
}
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "NwFsdClose -> %08lx\n", Status);
|
|
|
|
NwDereferenceUnlockableCodeSection ();
|
|
UNREFERENCED_PARAMETER( DeviceObject );
|
|
|
|
FsRtlExitFileSystem();
|
|
|
|
return Status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCommonClose (
|
|
IN PIRP_CONTEXT IrpContext
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This is the common routine for closing 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, "NwCommonClose\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, "NwCommonClose -> %08lx\n", status );
|
|
try_return( NOTHING );
|
|
}
|
|
|
|
//
|
|
// Decide how to handle this IRP.
|
|
//
|
|
|
|
switch (nodeTypeCode) {
|
|
|
|
|
|
case NW_NTC_RCB: // Close the file system
|
|
|
|
status = NwCloseRcb( IrpContext, (PRCB)fsContext2 );
|
|
status = STATUS_SUCCESS;
|
|
break;
|
|
|
|
case NW_NTC_ICB: // Close the remote file
|
|
case NW_NTC_ICB_SCB: // Close the SCB
|
|
|
|
status = NwCloseIcb( IrpContext, (PICB)fsContext2 );
|
|
NwDereferenceUnlockableCodeSection ();
|
|
break;
|
|
|
|
#ifdef NWDBG
|
|
default:
|
|
|
|
//
|
|
// This is not one of ours.
|
|
//
|
|
|
|
KeBugCheck( RDR_FILE_SYSTEM );
|
|
break;
|
|
#endif
|
|
|
|
}
|
|
|
|
try_exit: NOTHING;
|
|
|
|
} finally {
|
|
|
|
//
|
|
// Just in-case this handle was the last one before we unload.
|
|
//
|
|
|
|
NwUnlockCodeSections(TRUE);
|
|
|
|
DebugTrace(-1, Dbg, "NwCommonClose -> %08lx\n", status);
|
|
|
|
}
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCloseRcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PRCB Rcb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine cleans up a RCB.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - Supplies the IRP context pointers for this close.
|
|
|
|
Rcb - Supplies the RCB for MSFS.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - An appropriate completion status
|
|
|
|
--*/
|
|
|
|
{
|
|
NTSTATUS status;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwCloseRcb...\n", 0);
|
|
|
|
//
|
|
// Now acquire exclusive access to the Rcb
|
|
//
|
|
|
|
NwAcquireExclusiveRcb( Rcb, TRUE );
|
|
|
|
status = STATUS_SUCCESS;
|
|
--Rcb->OpenCount;
|
|
|
|
NwReleaseRcb( Rcb );
|
|
|
|
DebugTrace(-1, Dbg, "MsCloseRcb -> %08lx\n", status);
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
return status;
|
|
}
|
|
|
|
|
|
NTSTATUS
|
|
NwCloseIcb (
|
|
IN PIRP_CONTEXT IrpContext,
|
|
IN PICB Icb
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
The routine cleans up an ICB.
|
|
|
|
Arguments:
|
|
|
|
IrpContext - Supplies the IRP context pointers for this close.
|
|
|
|
Rcb - Supplies the RCB for MSFS.
|
|
|
|
Return Value:
|
|
|
|
NTSTATUS - An appropriate completion status
|
|
|
|
--*/
|
|
{
|
|
NTSTATUS Status;
|
|
PNONPAGED_SCB pNpScb;
|
|
PVCB Vcb;
|
|
PFCB Fcb;
|
|
|
|
PAGED_CODE();
|
|
|
|
DebugTrace(+1, Dbg, "NwCloseIcb...\n", 0);
|
|
|
|
ASSERT( Icb->State == ICB_STATE_CLEANED_UP ||
|
|
Icb->State == ICB_STATE_CLOSE_PENDING );
|
|
|
|
//
|
|
// If this is a remote file close the remote handle.
|
|
//
|
|
|
|
Status = STATUS_SUCCESS;
|
|
IrpContext->Icb = Icb;
|
|
Fcb = Icb->SuperType.Fcb;
|
|
|
|
if (( Icb->NodeTypeCode == NW_NTC_ICB ) ||
|
|
( Icb->NodeTypeCode == NW_NTC_DCB )) {
|
|
|
|
pNpScb = Fcb->Scb->pNpScb;
|
|
IrpContext->pNpScb = pNpScb;
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
Vcb = Fcb->Vcb;
|
|
|
|
//
|
|
// Dump the write behind cache.
|
|
//
|
|
|
|
Status = AcquireFcbAndFlushCache( IrpContext, Fcb->NonPagedFcb );
|
|
|
|
if ( !NT_SUCCESS( Status ) ) {
|
|
IoRaiseInformationalHardError(
|
|
STATUS_LOST_WRITEBEHIND_DATA,
|
|
&Fcb->FullFileName,
|
|
(PKTHREAD)IrpContext->pOriginalIrp->Tail.Overlay.Thread );
|
|
}
|
|
|
|
//
|
|
// Is this a print job?
|
|
// Icb->IsPrintJob will be false if a 16 bit app is
|
|
// responsible for sending the job.
|
|
//
|
|
|
|
if ( FlagOn( Vcb->Flags, VCB_FLAG_PRINT_QUEUE ) &&
|
|
Icb->IsPrintJob ) {
|
|
|
|
//
|
|
// Yes, did we print?
|
|
//
|
|
|
|
if ( Icb->ActuallyPrinted ) {
|
|
|
|
//
|
|
// Yes. Send a close file and start queue job NCP
|
|
//
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"Sdw",
|
|
NCP_ADMIN_FUNCTION, NCP_CLOSE_FILE_AND_START_JOB,
|
|
Vcb->Specific.Print.QueueId,
|
|
Icb->JobId );
|
|
} else {
|
|
|
|
//
|
|
// No. Cancel the job.
|
|
//
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"Sdw",
|
|
NCP_ADMIN_FUNCTION, NCP_CLOSE_FILE_AND_CANCEL_JOB,
|
|
Vcb->Specific.Print.QueueId,
|
|
Icb->JobId );
|
|
}
|
|
|
|
} else {
|
|
|
|
if ( Icb->SuperType.Fcb->NodeTypeCode != NW_NTC_DCB ) {
|
|
|
|
//
|
|
// No, send a close file NCP.
|
|
//
|
|
|
|
ASSERT( IrpContext->pTdiStruct == NULL );
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_CLOSE,
|
|
Icb->Handle, sizeof( Icb->Handle ) );
|
|
|
|
// If this is in the long file name space and
|
|
// the last access flag has been set, we have to
|
|
// reset the last access time _after_ closing the file.
|
|
|
|
if ( Icb->UserSetLastAccessTime &&
|
|
BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LONG_NAME ) ) {
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"LbbWD_W_bDbC",
|
|
NCP_LFN_SET_INFO,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
Fcb->Vcb->Specific.Disk.LongNameSpace,
|
|
SEARCH_ALL_FILES,
|
|
LFN_FLAG_SET_INFO_LASTACCESS_DATE,
|
|
28,
|
|
Fcb->LastAccessDate,
|
|
8,
|
|
Fcb->Vcb->Specific.Disk.VolumeNumber,
|
|
Fcb->Vcb->Specific.Disk.Handle,
|
|
0,
|
|
&Fcb->RelativeFileName );
|
|
}
|
|
|
|
//
|
|
// If someone set the shareable bit, then
|
|
// see if we can send the NCP over the wire (all
|
|
// instances of the file need to be closed).
|
|
//
|
|
|
|
if ( BooleanFlagOn( Fcb->Flags, FCB_FLAGS_LAZY_SET_SHAREABLE ) ) {
|
|
LazySetShareable( IrpContext, Icb, Fcb );
|
|
}
|
|
|
|
} else {
|
|
|
|
Status = ExchangeWithWait (
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"Sb",
|
|
NCP_DIR_FUNCTION, NCP_DEALLOCATE_DIR_HANDLE,
|
|
Icb->Handle[0]);
|
|
}
|
|
|
|
}
|
|
|
|
Icb->HasRemoteHandle = FALSE;
|
|
}
|
|
|
|
} else {
|
|
|
|
pNpScb = Icb->SuperType.Scb->pNpScb;
|
|
IrpContext->pNpScb = pNpScb;
|
|
IrpContext->pScb = pNpScb->pScb;
|
|
|
|
if ( Icb->HasRemoteHandle ) {
|
|
|
|
//
|
|
// If we have a remote handle this is a file stream ICB. We
|
|
// need to close the remote handle. The exchange will get us
|
|
// to the head of the queue to protect the SCB state.
|
|
//
|
|
|
|
Status = ExchangeWithWait(
|
|
IrpContext,
|
|
SynchronousResponseCallback,
|
|
"F-r",
|
|
NCP_CLOSE,
|
|
Icb->Handle, sizeof( Icb->Handle ) );
|
|
|
|
Icb->HasRemoteHandle = FALSE;
|
|
|
|
pNpScb->pScb->OpenNdsStreams--;
|
|
|
|
ASSERT( pNpScb->pScb->MajorVersion > 3 );
|
|
|
|
//
|
|
// Do we need to unlicense this connection?
|
|
//
|
|
|
|
if ( ( pNpScb->pScb->UserName.Length == 0 ) &&
|
|
( pNpScb->pScb->VcbCount == 0 ) &&
|
|
( pNpScb->pScb->OpenNdsStreams == 0 ) ) {
|
|
NdsUnlicenseConnection( IrpContext );
|
|
}
|
|
|
|
NwDequeueIrpContext( IrpContext, FALSE );
|
|
}
|
|
|
|
if ( Icb->IsExCredentialHandle ) {
|
|
ExCreateDereferenceCredentials( IrpContext, Icb->pContext );
|
|
}
|
|
|
|
}
|
|
|
|
if ( Icb->Pid != INVALID_PID ) {
|
|
|
|
//
|
|
// This ICB was involved in a search, send the end job,
|
|
// then free the PID.
|
|
//
|
|
|
|
NwUnmapPid(pNpScb, Icb->Pid, IrpContext );
|
|
}
|
|
|
|
//
|
|
// Update the time the SCB was last used.
|
|
//
|
|
|
|
KeQuerySystemTime( &pNpScb->LastUsedTime );
|
|
|
|
//
|
|
// Wait the SCB queue. We do this now since NwDeleteIcb may cause
|
|
// a packet to be sent by this thread (from NwCleanupVcb()) while
|
|
// holding the RCB. To eliminate this potential source of deadlock,
|
|
// queue this IrpContext to the SCB queue before acquiring the RCB.
|
|
//
|
|
// Also, we mark this IRP context not reconnectable, since the
|
|
// reconnect logic, will try to acquire the RCB.
|
|
//
|
|
|
|
NwAppendToQueueAndWait( IrpContext );
|
|
ClearFlag( IrpContext->Flags, IRP_FLAG_RECONNECTABLE );
|
|
|
|
//
|
|
// Delete the ICB.
|
|
//
|
|
|
|
NwDeleteIcb( IrpContext, Icb );
|
|
|
|
//
|
|
// And return to our caller
|
|
//
|
|
|
|
DebugTrace(-1, Dbg, "NwCloseIcb -> %08lx\n", Status);
|
|
return Status;
|
|
}
|