Windows NT 4.0 source code leak
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.
 
 
 
 
 
 

302 lines
6.8 KiB

/*++
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 and peek.
Author:
Manny Weiser (mannyw) 15-Jan-1991
Revision History:
--*/
#include "mailslot.h"
//
// The debug trace level
//
#define Dbg (DEBUG_TRACE_READSUP)
#ifdef ALLOC_PRAGMA
#pragma alloc_text( PAGE, MsReadDataQueue )
#pragma alloc_text( PAGE, MsTimeoutRead )
#endif
IO_STATUS_BLOCK
MsReadDataQueue (
IN PDATA_QUEUE ReadQueue,
IN ENTRY_TYPE Operation,
IN PUCHAR ReadBuffer,
IN ULONG ReadLength,
OUT PULONG MessageLength
)
/*++
Routine Description:
This function reads data from the read queue and fills up the
read buffer. It will also dequeue the data entry if this is not
a peek operation.
It will only be called if there is at least one message to read.
*** This function must be called from within a try statement.
Arguments:
ReadQueue - Provides the read queue to examine. Its state must
already be set to WriteEntries.
Operation - Indicates the type of operation to perform. If the
operation is Peek, the write data entry is not dequeued.
ReadBuffer - Supplies a buffer to receive the data
ReadLength - Supplies the length, in bytes, of ReadBuffer.
MessageLength - Returns the full size of the message, even if the
read buffer is not large enough to contain the entire message.
Return Value:
IO_STATUS_BLOCK - Indicates the result of the operation.
--*/
{
IO_STATUS_BLOCK iosb;
PLIST_ENTRY listEntry;
PDATA_ENTRY dataEntry;
PFCB fcb;
PUCHAR writeBuffer;
ULONG writeLength;
ULONG amountRead;
PAGED_CODE();
DebugTrace(+1, Dbg, "MsReadDataQueue\n", 0);
DebugTrace( 0, Dbg, "ReadQueue = %08lx\n", (ULONG)ReadQueue);
DebugTrace( 0, Dbg, "Operation = %08lx\n", Operation);
DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", (ULONG)ReadBuffer);
DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
//
// Read the first message out of the data queue.
//
iosb.Status = STATUS_SUCCESS;
listEntry = MsGetNextDataQueueEntry( ReadQueue );
ASSERT( listEntry != &ReadQueue->DataEntryList );
dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
//
// Calculate how much data is in this entry.
//
writeBuffer = dataEntry->DataPointer;
writeLength = dataEntry->DataSize;
DebugTrace(0, Dbg, "WriteBuffer = %08lx\n", (ULONG)writeBuffer);
DebugTrace(0, Dbg, "WriteLength = %08lx\n", writeLength);
//
// Fail this operation, if it is a read and the buffer is not large
// enough.
//
if ( (Operation != Peek) && (ReadLength < writeLength) ) {
iosb.Information = 0;
iosb.Status = STATUS_BUFFER_TOO_SMALL;
return iosb;
}
//
// Copy data from the write buffer at write offset to the
// read buffer by the mininum of write remaining or read length
//
RtlMoveMemory( ReadBuffer,
writeBuffer,
writeLength );
*MessageLength = dataEntry->DataSize;
//
// If write length is larger than read length, this must be an
// overflowed peek.
//
if ( writeLength > ReadLength) {
DebugTrace(0, Dbg, "Overflowed peek buffer\n", 0);
iosb.Status = STATUS_BUFFER_OVERFLOW;
} else {
//
// 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 (Operation != Peek) {
PIRP writeIrp;
if ((writeIrp = MsRemoveDataQueueEntry( ReadQueue,
dataEntry )) != NULL) {
//
// Update the last modification time.
//
fcb = CONTAINING_RECORD( ReadQueue, FCB, DataQueue );
KeQuerySystemTime( &fcb->Specific.Fcb.LastModificationTime );
MsCompleteRequest( writeIrp, STATUS_SUCCESS );
}
}
DebugTrace(0, Dbg, "Successful mailslot read\n", 0);
//
// Indicate success.
//
iosb.Status = STATUS_SUCCESS;
}
amountRead = writeLength < ReadLength ? writeLength : ReadLength;
DebugTrace(0, Dbg, "Amount read = %08lx\n", amountRead);
iosb.Information = amountRead;
DebugTrace(-1, Dbg, "MsReadDataQueue -> iosb.Status = %08lx\n", iosb.Status);
return iosb;
}
VOID
MsTimeoutRead (
IN PVOID Context
)
/*++
Routine Description:
This routine times out a read operation. It gains exclusive
access to the FCB, and searches the data queue of read operations.
If the timed out read operation is not found, it is assumed that
a write IRP completed the read after the time out DPC ran, but
before this function could complete the read IRP.
Arguments:
Context - a pointer to our WorkContext
Return Value:
None.
--*/
{
PDATA_QUEUE dataQueue;
PLIST_ENTRY listEntry;
PIRP queuedIrp;
PDATA_ENTRY dataEntry;
PWORK_CONTEXT workContext;
PIRP irp;
PFCB fcb;
PAGED_CODE();
//
// Reference our local variables.
//
workContext = (PWORK_CONTEXT)Context;
irp = workContext->Irp;
fcb = workContext->Fcb;
//
// Acquire exclusive access to the FCB. This must succeed.
//
MsAcquireExclusiveFcb( fcb );
//
// Walk the FCB's data queue, looking for this read IRP.
//
dataQueue = &fcb->DataQueue;
for (listEntry = MsGetNextDataQueueEntry( dataQueue );
listEntry != &dataQueue->DataEntryList;
listEntry = listEntry->Flink ) {
//
// This is an outstanding read request from this FCB.
// If it is the read request that has timed out, then
// complete it with a timed out status.
//
dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
queuedIrp = dataEntry->Irp;
if ( queuedIrp == irp ) {
//
// The timed out IRP is still queued. Dequeue it and complete
// it now.
//
MsRemoveDataQueueEntry( dataQueue, dataEntry );
DebugTrace(0, Dbg, "Completing IRP %08lx\n", (ULONG)queuedIrp );
MsCompleteRequest( queuedIrp, STATUS_IO_TIMEOUT );
break;
}
}
//
// Free the work context structure. Note that we have to free this
// whenever this routine runs, even if the I/O request was cancelled,
// because the canceller didn't free it.
//
ExFreePool( workContext );
//
// Release the FCB, and derefernce it.
//
MsReleaseFcb( fcb );
MsDereferenceFcb( fcb );
}