294 lines
8.5 KiB
C
294 lines
8.5 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
|
||
)
|
||
|
||
/*++
|
||
|
||
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
|
||
|
||
Return Value:
|
||
|
||
IO_STATUS_BLOCK - Indicates the result of the operation.
|
||
|
||
--*/
|
||
|
||
{
|
||
IO_STATUS_BLOCK Iosb;
|
||
|
||
PDATA_ENTRY DataEntry;
|
||
|
||
ULONG ReadRemaining;
|
||
ULONG AmountRead;
|
||
|
||
PUCHAR WriteBuffer;
|
||
ULONG WriteLength;
|
||
ULONG WriteRemaining;
|
||
|
||
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;
|
||
AmountRead = 0;
|
||
|
||
for (DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, NULL )
|
||
: NpGetNextRealDataQueueEntry( ReadQueue ));
|
||
|
||
(DataEntry != NULL) && (ReadRemaining > 0);
|
||
|
||
DataEntry = (PeekOperation ? NpGetNextDataQueueEntry( ReadQueue, DataEntry )
|
||
: NpGetNextRealDataQueueEntry( ReadQueue ))) {
|
||
|
||
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
|
||
//
|
||
|
||
WriteBuffer = DataEntry->DataPointer;
|
||
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) {
|
||
|
||
ExRaiseStatus( STATUS_INVALID_USER_BUFFER );
|
||
}
|
||
|
||
//
|
||
// 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) {
|
||
|
||
ReadQueue->NextByteOffset = WriteLength - WriteRemaining;
|
||
}
|
||
|
||
//
|
||
// 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 );
|
||
ASSERT(TempDataEntry == DataEntry);
|
||
}
|
||
|
||
if ((WriteIrp = NpRemoveDataQueueEntry( ReadQueue )) != NULL) {
|
||
|
||
NpCompleteRequest( WriteIrp, STATUS_SUCCESS );
|
||
}
|
||
}
|
||
|
||
//
|
||
// 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;
|
||
|
||
DebugTrace(-1, Dbg, "NpReadDataQueue -> Iosb.Status = %08lx\n", Iosb.Status);
|
||
return Iosb;
|
||
}
|