376 lines
8.5 KiB
C
376 lines
8.5 KiB
C
/*++
|
||
|
||
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
|
||
);
|
||
|
||
NTSTATUS
|
||
MsCreateWorkContext (
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PLARGE_INTEGER Timeout,
|
||
PFCB Fcb,
|
||
PIRP Irp,
|
||
PWORK_CONTEXT *ppWorkContext
|
||
);
|
||
|
||
#ifdef ALLOC_PRAGMA
|
||
#pragma alloc_text( PAGE, MsCommonRead )
|
||
#pragma alloc_text( PAGE, MsFsdRead )
|
||
#pragma alloc_text( PAGE, MsCreateWorkContext )
|
||
#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);
|
||
|
||
FsRtlEnterFileSystem();
|
||
|
||
status = MsCommonRead( MsfsDeviceObject, Irp );
|
||
|
||
FsRtlExitFileSystem();
|
||
|
||
//
|
||
// Return to the caller.
|
||
//
|
||
|
||
DebugTrace(-1, Dbg, "MsFsdRead -> %08lx\n", status );
|
||
|
||
return status;
|
||
}
|
||
|
||
NTSTATUS
|
||
MsCreateWorkContext (
|
||
PDEVICE_OBJECT DeviceObject,
|
||
PLARGE_INTEGER Timeout,
|
||
PFCB Fcb,
|
||
PIRP Irp,
|
||
PWORK_CONTEXT *ppWorkContext
|
||
)
|
||
/*++
|
||
|
||
Routine Description:
|
||
|
||
This routine build a timeout work context.
|
||
|
||
Arguments:
|
||
|
||
|
||
Return Value:
|
||
|
||
NTSTATUS - Status associated with the call
|
||
|
||
--*/
|
||
{
|
||
PKTIMER Timer;
|
||
PKDPC Dpc;
|
||
PWORK_CONTEXT WorkContext;
|
||
|
||
//
|
||
// Allocate memory for the work context.
|
||
//
|
||
*ppWorkContext = NULL;
|
||
|
||
WorkContext = MsAllocateNonPagedPoolWithQuota( sizeof(WORK_CONTEXT),
|
||
'wFsM' );
|
||
if (WorkContext == NULL) {
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
|
||
Timer = &WorkContext->Timer;
|
||
Dpc = &WorkContext->Dpc;
|
||
|
||
//
|
||
// Fill in the work context structure.
|
||
//
|
||
|
||
WorkContext->Irp = Irp;
|
||
WorkContext->Fcb = Fcb;
|
||
|
||
WorkContext->WorkItem = IoAllocateWorkItem (DeviceObject);
|
||
|
||
if (WorkContext->WorkItem == NULL) {
|
||
MsFreePool (WorkContext);
|
||
return STATUS_INSUFFICIENT_RESOURCES;
|
||
}
|
||
//
|
||
// Now set up a DPC and set the timer to the user specified
|
||
// timeout.
|
||
//
|
||
|
||
KeInitializeTimer( Timer );
|
||
KeInitializeDpc( Dpc, MsReadTimeoutHandler, WorkContext );
|
||
|
||
MsAcquireGlobalLock();
|
||
MsReferenceNode( &Fcb->Header );
|
||
MsReleaseGlobalLock();
|
||
|
||
*ppWorkContext = WorkContext;
|
||
return STATUS_SUCCESS;
|
||
}
|
||
|
||
|
||
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;
|
||
|
||
PWORK_CONTEXT workContext = NULL;
|
||
|
||
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 );
|
||
|
||
|
||
//
|
||
// Ensure that this FCB still belongs to an active open mailslot.
|
||
//
|
||
|
||
status = MsVerifyFcb( fcb );
|
||
if (NT_SUCCESS (status)) {
|
||
|
||
//
|
||
// 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);
|
||
|
||
status = STATUS_IO_TIMEOUT;
|
||
|
||
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status );
|
||
|
||
} else {
|
||
//
|
||
// Create a timer block to time the request if we need to.
|
||
//
|
||
if ( timeout.QuadPart != -1 ) {
|
||
status = MsCreateWorkContext (&MsfsDeviceObject->DeviceObject,
|
||
&timeout,
|
||
fcb,
|
||
readIrp,
|
||
&workContext);
|
||
}
|
||
|
||
|
||
if (NT_SUCCESS (status)) {
|
||
status = MsAddDataQueueEntry( readQueue,
|
||
ReadEntries,
|
||
readLength,
|
||
readIrp,
|
||
workContext );
|
||
}
|
||
}
|
||
|
||
} else {
|
||
|
||
//
|
||
// Otherwise we have a data on a queue that contains
|
||
// one or more write entries. Read the data and complete
|
||
// the read IRP.
|
||
//
|
||
|
||
readIrp->IoStatus = MsReadDataQueue( readQueue,
|
||
Read,
|
||
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 );
|
||
}
|
||
|
||
}
|
||
}
|
||
|
||
MsReleaseFcb( fcb );
|
||
|
||
MsDereferenceFcb( fcb );
|
||
|
||
if (status != STATUS_PENDING) {
|
||
|
||
if (workContext) {
|
||
MsDereferenceFcb ( fcb );
|
||
IoFreeWorkItem (workContext->WorkItem);
|
||
ExFreePool (workContext);
|
||
}
|
||
|
||
MsCompleteRequest( readIrp, status );
|
||
}
|
||
|
||
DebugTrace(-1, Dbg, "MsCommonRead -> %08lx\n", status);
|
||
|
||
return status;
|
||
}
|
||
|