windows-nt/Source/XPSP1/NT/ds/nw/rdr/close.c

581 lines
13 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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;
}