windows-nt/Source/XPSP1/NT/base/fs/mailslot/read.c
2020-09-26 16:20:57 +08:00

376 lines
8.2 KiB
C
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*++
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;
}