From e611b132f9b8abe35b362e5870b74bce94a1e58e Mon Sep 17 00:00:00 2001 From: Adam Date: Sat, 16 May 2020 20:51:50 -0700 Subject: initial commit --- private/nw/rdr/close.c | 571 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 571 insertions(+) create mode 100644 private/nw/rdr/close.c (limited to 'private/nw/rdr/close.c') diff --git a/private/nw/rdr/close.c b/private/nw/rdr/close.c new file mode 100644 index 000000000..7caddbd04 --- /dev/null +++ b/private/nw/rdr/close.c @@ -0,0 +1,571 @@ +/*++ + +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); + + // + // Call the common Close routine + // + + FsRtlEnterFileSystem(); + 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 ); + } + FsRtlExitFileSystem(); + + // + // And return to our caller + // + + DebugTrace(-1, Dbg, "NwFsdClose -> %08lx\n", Status); + + UNREFERENCED_PARAMETER( DeviceObject ); + + 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)IrpContext); + DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp); + DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)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->Pid != INVALID_PID ) { + + // + // This ICB was involved in a search, send the end job, + // then free the PID. + // + + NwUnmapPid( 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; +} -- cgit v1.2.3