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.
375 lines
8.5 KiB
375 lines
8.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
|
|
);
|
|
|
|
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;
|
|
}
|
|
|