312 lines
9.3 KiB
C
312 lines
9.3 KiB
C
|
/*++
|
|||
|
|
|||
|
Copyright (c) 1989 Microsoft Corporation
|
|||
|
|
|||
|
Module Name:
|
|||
|
|
|||
|
ReadSup.c
|
|||
|
|
|||
|
Abstract:
|
|||
|
|
|||
|
This module implements the Read support routine. This is a common
|
|||
|
read function that is called to do read, unbuffered read, peek, and
|
|||
|
transceive.
|
|||
|
|
|||
|
Author:
|
|||
|
|
|||
|
Gary Kimura [GaryKi] 20-Sep-1990
|
|||
|
|
|||
|
Revision History:
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
#include "NpProcs.h"
|
|||
|
|
|||
|
//
|
|||
|
// The debug trace level
|
|||
|
//
|
|||
|
|
|||
|
#define Dbg (DEBUG_TRACE_READSUP)
|
|||
|
|
|||
|
#ifdef ALLOC_PRAGMA
|
|||
|
#pragma alloc_text(PAGE, NpReadDataQueue)
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
IO_STATUS_BLOCK
|
|||
|
NpReadDataQueue (
|
|||
|
IN PDATA_QUEUE ReadQueue,
|
|||
|
IN BOOLEAN PeekOperation,
|
|||
|
IN BOOLEAN ReadOverflowOperation,
|
|||
|
IN PUCHAR ReadBuffer,
|
|||
|
IN ULONG ReadLength,
|
|||
|
IN READ_MODE ReadMode,
|
|||
|
IN PCCB Ccb,
|
|||
|
IN PLIST_ENTRY DeferredList
|
|||
|
)
|
|||
|
|
|||
|
/*++
|
|||
|
|
|||
|
Routine Description:
|
|||
|
|
|||
|
This procedure reads data from the read queue and fills up the
|
|||
|
read buffer. It will also dequeue the queue or leave it alone based
|
|||
|
on an input parameter.
|
|||
|
|
|||
|
Arguments:
|
|||
|
|
|||
|
ReadQueue - Provides the read queue to examine. Its state must
|
|||
|
already be set to WriteEntries.
|
|||
|
|
|||
|
PeekOperation - Indicates if the operation is to dequeue information
|
|||
|
off of the queue as it is being read or leave the queue alone.
|
|||
|
TRUE means to leave the queue alone.
|
|||
|
|
|||
|
ReadOverflowOperation - Indicates if this is a read overflow operation.
|
|||
|
With read overflow we will not alter the named pipe if the data
|
|||
|
will overflow the read buffer.
|
|||
|
|
|||
|
ReadBuffer - Supplies a buffer to receive the data
|
|||
|
|
|||
|
ReadLength - Supplies the length, in bytes, of ReadBuffer.
|
|||
|
|
|||
|
ReadMode - Indicates if the read operation is message mode or
|
|||
|
byte stream mode.
|
|||
|
|
|||
|
NamedPipeEnd - Supplies the end of the named pipe doing the read
|
|||
|
|
|||
|
Ccb - Supplies the ccb for the pipe
|
|||
|
|
|||
|
DeferredList - List of IRP's to complete later after we drop locks
|
|||
|
|
|||
|
Return Value:
|
|||
|
|
|||
|
IO_STATUS_BLOCK - Indicates the result of the operation.
|
|||
|
|
|||
|
--*/
|
|||
|
|
|||
|
{
|
|||
|
IO_STATUS_BLOCK Iosb= {0};
|
|||
|
|
|||
|
PDATA_ENTRY DataEntry;
|
|||
|
|
|||
|
ULONG ReadRemaining;
|
|||
|
ULONG AmountRead;
|
|||
|
|
|||
|
PUCHAR WriteBuffer;
|
|||
|
ULONG WriteLength;
|
|||
|
ULONG WriteRemaining;
|
|||
|
BOOLEAN StartStalled = FALSE;
|
|||
|
|
|||
|
ULONG AmountToCopy;
|
|||
|
|
|||
|
PAGED_CODE();
|
|||
|
|
|||
|
DebugTrace(+1, Dbg, "NpReadDataQueue\n", 0);
|
|||
|
DebugTrace( 0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
|
|||
|
DebugTrace( 0, Dbg, "PeekOperation = %08lx\n", PeekOperation);
|
|||
|
DebugTrace( 0, Dbg, "ReadOverflowOperation = %08lx\n", ReadOverflowOperation);
|
|||
|
DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
|
|||
|
DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
|
|||
|
DebugTrace( 0, Dbg, "ReadMode = %08lx\n", ReadMode);
|
|||
|
DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
|
|||
|
|
|||
|
//
|
|||
|
// If this is an overflow operation then we will force us to do peeks.
|
|||
|
// Later when are determine that the opreation succeeded we will complete
|
|||
|
// the write irp.
|
|||
|
//
|
|||
|
|
|||
|
if (ReadOverflowOperation) {
|
|||
|
|
|||
|
PeekOperation = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now for every real data entry we loop until either we run out
|
|||
|
// of data entries or until the read buffer is full
|
|||
|
//
|
|||
|
|
|||
|
ReadRemaining = ReadLength;
|
|||
|
Iosb.Status = STATUS_SUCCESS;
|
|||
|
Iosb.Information = 0;
|
|||
|
AmountRead = 0;
|
|||
|
|
|||
|
for (DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, NULL )
|
|||
|
: NpGetNextRealDataQueueEntry( ReadQueue, DeferredList ));
|
|||
|
|
|||
|
(DataEntry != (PDATA_ENTRY) &ReadQueue->Queue) && (ReadRemaining > 0);
|
|||
|
|
|||
|
DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, DataEntry )
|
|||
|
: NpGetNextRealDataQueueEntry( ReadQueue, DeferredList ))) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Top of Loop\n", 0);
|
|||
|
DebugTrace(0, Dbg, "ReadRemaining = %08lx\n", ReadRemaining);
|
|||
|
|
|||
|
//
|
|||
|
// If this is a peek operation then make sure we got a real
|
|||
|
// data entry and not a close or flush
|
|||
|
//
|
|||
|
|
|||
|
if (!PeekOperation ||
|
|||
|
(DataEntry->DataEntryType == Buffered) ||
|
|||
|
(DataEntry->DataEntryType == Unbuffered)) {
|
|||
|
|
|||
|
//
|
|||
|
// Calculate how much data is in this entry. The write
|
|||
|
// remaining is based on whether this is the first entry
|
|||
|
// in the queue or a later data entry
|
|||
|
//
|
|||
|
|
|||
|
if (DataEntry->DataEntryType == Unbuffered) {
|
|||
|
WriteBuffer = DataEntry->Irp->AssociatedIrp.SystemBuffer;
|
|||
|
} else {
|
|||
|
WriteBuffer = DataEntry->DataBuffer;
|
|||
|
}
|
|||
|
|
|||
|
WriteLength = DataEntry->DataSize;
|
|||
|
WriteRemaining = WriteLength;
|
|||
|
|
|||
|
if (DataEntry == NpGetNextDataQueueEntry( ReadQueue, NULL )) {
|
|||
|
|
|||
|
WriteRemaining -= ReadQueue->NextByteOffset;
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
|
|||
|
DebugTrace(0, Dbg, "WriteLength = %08lx\n", WriteLength);
|
|||
|
DebugTrace(0, Dbg, "WriteRemaining = %08lx\n", WriteRemaining);
|
|||
|
|
|||
|
//
|
|||
|
// copy data from the write buffer at write offset to the
|
|||
|
// read buffer at read offset by the mininum of write
|
|||
|
// remaining or read remaining
|
|||
|
//
|
|||
|
|
|||
|
AmountToCopy = (WriteRemaining < ReadRemaining ? WriteRemaining
|
|||
|
: ReadRemaining);
|
|||
|
|
|||
|
try {
|
|||
|
|
|||
|
RtlCopyMemory( &ReadBuffer[ ReadLength - ReadRemaining ],
|
|||
|
&WriteBuffer[ WriteLength - WriteRemaining ],
|
|||
|
AmountToCopy );
|
|||
|
|
|||
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|||
|
|
|||
|
Iosb.Status = GetExceptionCode ();
|
|||
|
goto exit_1;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Update the Read and Write remaining counts, the total
|
|||
|
// amount we've read and the next byte offset field in the
|
|||
|
// read queue
|
|||
|
//
|
|||
|
|
|||
|
ReadRemaining -= AmountToCopy;
|
|||
|
WriteRemaining -= AmountToCopy;
|
|||
|
AmountRead += AmountToCopy;
|
|||
|
|
|||
|
if (!PeekOperation) {
|
|||
|
DataEntry->QuotaCharged -= AmountToCopy;
|
|||
|
ReadQueue->QuotaUsed -= AmountToCopy;
|
|||
|
ReadQueue->NextByteOffset += AmountToCopy;
|
|||
|
StartStalled = TRUE;
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// Now update the security fields in the ccb
|
|||
|
//
|
|||
|
|
|||
|
NpCopyClientContext( Ccb, DataEntry );
|
|||
|
|
|||
|
//
|
|||
|
// If the remaining write length is greater than zero
|
|||
|
// then we've filled up the read buffer so we need to
|
|||
|
// figure out if its an overflow error
|
|||
|
//
|
|||
|
|
|||
|
if (WriteRemaining > 0 ||
|
|||
|
(ReadOverflowOperation && (AmountRead == 0))) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Write remaining is > 0\n", 0);
|
|||
|
|
|||
|
if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Overflow message mode read\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// Set the status field and break out of the for-loop.
|
|||
|
//
|
|||
|
|
|||
|
Iosb.Status = STATUS_BUFFER_OVERFLOW;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
} else {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Remaining Write is zero\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// The write entry is done so remove it from the read
|
|||
|
// queue, if this is not a peek operation. This might
|
|||
|
// also have an Irp that needs to be completed
|
|||
|
//
|
|||
|
|
|||
|
if (!PeekOperation || ReadOverflowOperation) {
|
|||
|
|
|||
|
PIRP WriteIrp;
|
|||
|
|
|||
|
//
|
|||
|
// For a read overflow operation we need to get the read data
|
|||
|
// queue entry and remove it.
|
|||
|
//
|
|||
|
|
|||
|
if (ReadOverflowOperation) {
|
|||
|
PDATA_ENTRY TempDataEntry;
|
|||
|
TempDataEntry = NpGetNextRealDataQueueEntry( ReadQueue, DeferredList );
|
|||
|
ASSERT(TempDataEntry == DataEntry);
|
|||
|
}
|
|||
|
|
|||
|
if ((WriteIrp = NpRemoveDataQueueEntry( ReadQueue, TRUE, DeferredList)) != NULL) {
|
|||
|
WriteIrp->IoStatus.Information = WriteLength;
|
|||
|
NpDeferredCompleteRequest( WriteIrp, STATUS_SUCCESS, DeferredList );
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
//
|
|||
|
// And if we are doing message mode reads then we'll
|
|||
|
// work on completing this irp without going back
|
|||
|
// to the top of the loop
|
|||
|
//
|
|||
|
|
|||
|
if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "Successful message mode read\n", 0);
|
|||
|
|
|||
|
//
|
|||
|
// Set the status field and break out of the for-loop.
|
|||
|
//
|
|||
|
|
|||
|
Iosb.Status = STATUS_SUCCESS;
|
|||
|
break;
|
|||
|
}
|
|||
|
|
|||
|
ASSERTMSG("Srv cannot use read overflow on a byte stream pipe ", !ReadOverflowOperation);
|
|||
|
}
|
|||
|
}
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(0, Dbg, "End of loop, AmountRead = %08lx\n", AmountRead);
|
|||
|
|
|||
|
Iosb.Information = AmountRead;
|
|||
|
|
|||
|
exit_1:
|
|||
|
if (StartStalled) {
|
|||
|
NpCompleteStalledWrites (ReadQueue, DeferredList);
|
|||
|
}
|
|||
|
|
|||
|
DebugTrace(-1, Dbg, "NpReadDataQueue -> Iosb.Status = %08lx\n", Iosb.Status);
|
|||
|
return Iosb;
|
|||
|
}
|