Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

384 lines
9.5 KiB

/*++
Copyright (c) 1989 Microsoft Corporation
Module Name:
read.c
Abstract:
This module implements the file read routine for MSFS called by the
dispatch driver.
Author:
Manny Weiser (mannyw) 15-Jan-1991
Revision History:
--*/
#include "mailslot.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_READ)
//
// local procedure prototypes
//
NTSTATUS
MsCommonRead (
IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
IN PIRP Irp
);
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, MsCommonRead )
#pragma alloc_text( PAGE, MsFsdRead )
#endif
NTSTATUS
MsFsdRead (
IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This routine implements the FSD part of the NtReadFile API calls.
Arguments:
MsfsDeviceObject - Supplies the device object to use.
Irp - Supplies the Irp being processed
Return Value:
NTSTATUS - The Fsd status for the Irp
--*/
{
NTSTATUS status;
PAGED_CODE();
DebugTrace(+1, Dbg, "MsFsdRead\n", 0);
try {
status = MsCommonRead( MsfsDeviceObject, Irp );
} except(MsExceptionFilter( GetExceptionCode() )) {
//
// 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 = MsProcessException( MsfsDeviceObject, Irp, GetExceptionCode() );
}
//
// Return to the caller.
//
DebugTrace(-1, Dbg, "MsFsdRead -> %08lx\n", status );
return status;
}
NTSTATUS
MsCommonRead (
IN PMSFS_DEVICE_OBJECT MsfsDeviceObject,
IN PIRP Irp
)
/*++
Routine Description:
This is the common routine for reading a file.
Arguments:
Irp - Supplies the Irp to process
Return Value:
NTSTATUS - the return status for the operation
--*/
{
NTSTATUS status;
PIO_STACK_LOCATION irpSp;
NODE_TYPE_CODE nodeTypeCode;
PFCB fcb;
PVOID fsContext2;
PIRP readIrp;
PUCHAR readBuffer;
ULONG readLength;
ULONG readRemaining;
PDATA_QUEUE readQueue;
ULONG messageLength;
LARGE_INTEGER timeout;
PKTIMER timer;
PKDPC dpc;
PWORK_CONTEXT workContext = NULL;
PDATA_ENTRY dataEntry;
PAGED_CODE();
irpSp = IoGetCurrentIrpStackLocation( Irp );
DebugTrace(+1, Dbg, "MsCommonRead\n", 0);
DebugTrace( 0, Dbg, "MsfsDeviceObject = %08lx\n", (ULONG)MsfsDeviceObject);
DebugTrace( 0, Dbg, "Irp = %08lx\n", (ULONG)Irp);
DebugTrace( 0, Dbg, "FileObject = %08lx\n", (ULONG)irpSp->FileObject);
//
// Get the FCB and make sure that the file isn't closing.
//
if ((nodeTypeCode = MsDecodeFileObject( irpSp->FileObject,
(PVOID *)&fcb,
&fsContext2 )) == NTC_UNDEFINED) {
DebugTrace(0, Dbg, "Mailslot is disconnected from us\n", 0);
MsCompleteRequest( Irp, STATUS_FILE_FORCED_CLOSED );
status = STATUS_FILE_FORCED_CLOSED;
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status );
return status;
}
//
// Allow read operations only if this is a server side handle to
// a mailslot file.
//
if (nodeTypeCode != MSFS_NTC_FCB) {
DebugTrace(0, Dbg, "FileObject is not the correct type\n", 0);
MsDereferenceNode( (PNODE_HEADER)fcb );
MsCompleteRequest( Irp, STATUS_INVALID_PARAMETER );
status = STATUS_INVALID_PARAMETER;
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status );
return status;
}
//
// Make local copies of the input parameters to make things easier, and
// initialize the main variables that describe the read command.
//
readIrp = Irp;
readBuffer = Irp->UserBuffer;
readLength = irpSp->Parameters.Read.Length;
readRemaining = readLength;
readQueue = &fcb->DataQueue;
//
// Acquire exclusive access to the FCB.
//
MsAcquireExclusiveFcb( fcb );
try {
//
// Ensure that this FCB still belongs to an active open mailslot.
//
MsVerifyFcb( fcb );
DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", (ULONG)readBuffer);
DebugTrace(0, Dbg, "ReadLength = %08lx\n", readLength);
DebugTrace(0, Dbg, "ReadQueue = %08lx\n", (ULONG)readQueue);
//
// If the read queue does not contain any write entries
// then we either need to queue this operation or
// fail immediately.
//
if (!MsIsDataQueueWriters( readQueue )) {
//
// There are no outstanding writes. If the read timeout is
// non-zero queue the read IRP, otherwise fail it.
//
timeout = fcb->Specific.Fcb.ReadTimeout;
if (timeout.HighPart == 0 && timeout.LowPart == 0) {
DebugTrace(0, Dbg, "Failing read with 0 timeout\n", 0);
MsCompleteRequest( Irp, STATUS_IO_TIMEOUT );
status = STATUS_IO_TIMEOUT;
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status );
try_return( NOTHING );
} else if ( timeout.QuadPart == -1 ) {
//
// An infinite timeout is specified. Just queue the IRP,
// do not start a timer.
//
DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
(VOID)MsAddDataQueueEntry( readQueue,
ReadEntries,
readLength,
readIrp );
IoMarkIrpPending( Irp );
status = STATUS_PENDING;
} else {
//
// The read timeout is non-zero. Queue the IRP and start
// a timer.
//
DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
dataEntry = MsAddDataQueueEntry( readQueue,
ReadEntries,
readLength,
readIrp );
//
// Allocate memory for the work context.
//
workContext = FsRtlAllocatePool( NonPagedPool,
sizeof(WORK_CONTEXT));
timer = &workContext->Timer;
dpc = &workContext->Dpc;
//
// By current definitions, timer and DPC will be aligned
// structures.
//
ASSERT ( ((ULONG)timer & 3) == 0 );
ASSERT ( ((ULONG)dpc & 3) == 0 );
//
// Keep a pointer to the timer, so that it can be canceled
// if the read completes.
//
dataEntry->TimeoutWorkContext = workContext;
//
// Fill in the work context structure.
//
workContext->Irp = readIrp;
ExInitializeWorkItem( &workContext->WorkItem,
MsTimeoutRead,
(PVOID)workContext );
//
// Keep a reference to the FCB to make sure it doesn't go
// away until this IRP completes.
//
workContext->Fcb = fcb;
MsAcquireGlobalLock();
MsReferenceNode( &fcb->Header );
MsReleaseGlobalLock();
DebugTrace(0,
DEBUG_TRACE_REFCOUNT,
"Referencing block %08lx\n",
(ULONG)fcb);
DebugTrace(0,
DEBUG_TRACE_REFCOUNT,
" Reference count = %lx\n",
fcb->Header.ReferenceCount );
//
// Now set up a DPC and set the timer to the user specified
// timeout.
//
KeInitializeTimer( timer );
KeInitializeDpc( dpc, MsReadTimeoutHandler, workContext );
(VOID)KeSetTimer( timer, timeout, dpc );
IoMarkIrpPending( Irp );
status = STATUS_PENDING;
}
} else {
//
// Otherwise we have a read IRP on a queue that contains
// one or more write entries. Read the data and complete
// the read IRP.
//
readIrp->IoStatus = MsReadDataQueue( readQueue,
FALSE,
readBuffer,
readLength,
&messageLength
);
status = readIrp->IoStatus.Status;
//
// Update the file last access time and finish up the read IRP.
//
if ( NT_SUCCESS( status ) ) {
KeQuerySystemTime( &fcb->Specific.Fcb.LastAccessTime );
}
MsCompleteRequest( readIrp, status );
}
try_exit: NOTHING;
} finally {
MsReleaseFcb( fcb );
MsDereferenceFcb( fcb );
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status);
}
return status;
}