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