216 lines
5.1 KiB
C
216 lines
5.1 KiB
C
/*++
|
|
|
|
Copyright (c) 1989 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
writesup.c
|
|
|
|
Abstract:
|
|
|
|
This module implements the write support routine. This is a common
|
|
write function that is called by write and mailslot write.
|
|
|
|
Author:
|
|
|
|
Manny Weiser (mannyw) 16-Jan-1991
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "mailslot.h"
|
|
|
|
//
|
|
// The debug trace level
|
|
//
|
|
|
|
#define Dbg (DEBUG_TRACE_WRITESUP)
|
|
|
|
#ifdef ALLOC_PRAGMA
|
|
#pragma alloc_text( PAGE, MsWriteDataQueue )
|
|
#endif
|
|
|
|
BOOLEAN
|
|
MsWriteDataQueue (
|
|
IN PDATA_QUEUE WriteQueue,
|
|
IN PUCHAR WriteBuffer,
|
|
IN ULONG WriteLength
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
This function writes data from the write buffer into read entries in
|
|
the write queue. It will also dequeue entries in the queue as necessary.
|
|
|
|
*** This function must be called from within a try statement.
|
|
|
|
Arguments:
|
|
|
|
WriteQueue - Provides the write queue to process.
|
|
|
|
WriteBuffer - Provides the buffer from which to read the data.
|
|
|
|
WriteLength - Provides the length, in bytes, of WriteBuffer.
|
|
|
|
Return Value:
|
|
|
|
BOOLEAN - TRUE if the operation wrote everything and FALSE otherwise.
|
|
|
|
--*/
|
|
|
|
{
|
|
BOOLEAN result;
|
|
|
|
PDATA_ENTRY dataEntry;
|
|
PLIST_ENTRY listEntry;
|
|
PFCB fcb;
|
|
|
|
PUCHAR readBuffer;
|
|
ULONG readLength;
|
|
PIRP readIrp;
|
|
NTSTATUS readStatus = STATUS_UNSUCCESSFUL;
|
|
|
|
PWORK_CONTEXT workContext;
|
|
PKTIMER timer;
|
|
|
|
PAGED_CODE();
|
|
DebugTrace(+1, Dbg, "MsWriteDataQueue\n", 0);
|
|
DebugTrace( 0, Dbg, "WriteQueue = %08lx\n", (ULONG)WriteQueue);
|
|
DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", (ULONG)WriteBuffer);
|
|
DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);
|
|
|
|
//
|
|
// Now while the write queue has some read entries in it and
|
|
// we have not successfully completed a read then we'll do the
|
|
// following main loop.
|
|
//
|
|
|
|
for (listEntry = MsGetNextDataQueueEntry( WriteQueue );
|
|
|
|
MsIsDataQueueReaders(WriteQueue) && !NT_SUCCESS(readStatus);
|
|
|
|
listEntry = MsGetNextDataQueueEntry( WriteQueue )) {
|
|
|
|
dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
|
|
readBuffer = dataEntry->DataPointer;
|
|
readLength = dataEntry->DataSize;
|
|
|
|
DebugTrace(0, Dbg, "Top of write loop...\n", 0);
|
|
DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", (ULONG)readBuffer);
|
|
DebugTrace(0, Dbg, "ReadLength = %08lx\n", readLength);
|
|
|
|
//
|
|
// We are about to complete a read IRP, so dequeue it.
|
|
//
|
|
|
|
readIrp = MsRemoveDataQueueEntry( WriteQueue, dataEntry );
|
|
ASSERT( readIrp != NULL );
|
|
|
|
//
|
|
// If the buffer for this read operation is large enough
|
|
// copy the data.
|
|
//
|
|
|
|
if ( readLength >= WriteLength ) {
|
|
|
|
//
|
|
// Copy the data from the write buffer to the read buffer.
|
|
//
|
|
|
|
RtlMoveMemory( readBuffer,
|
|
WriteBuffer,
|
|
WriteLength);
|
|
|
|
readIrp->IoStatus.Information = WriteLength;
|
|
readStatus = STATUS_SUCCESS;
|
|
|
|
} else {
|
|
|
|
//
|
|
// This read buffer was overflowed.
|
|
//
|
|
|
|
readIrp->IoStatus.Information = 0;
|
|
readStatus = STATUS_BUFFER_TOO_SMALL;
|
|
|
|
}
|
|
|
|
//
|
|
// Complete the read IRP.
|
|
//
|
|
|
|
workContext = dataEntry->TimeoutWorkContext;
|
|
if (workContext != NULL) {
|
|
|
|
DebugTrace( 0, Dbg, "Cancelling a timer\n", 0);
|
|
|
|
//
|
|
// There was a timer on this read operation. Attempt
|
|
// to cancel the operation. If the cancel operation
|
|
// is successful, then we must cleanup after the operation.
|
|
// If it was unsuccessful the timer DPC will run, and
|
|
// will eventually cleanup.
|
|
//
|
|
|
|
timer = &workContext->Timer;
|
|
|
|
if (KeCancelTimer( timer ) ) {
|
|
|
|
//
|
|
// Release the reference to the FCB.
|
|
//
|
|
|
|
MsDereferenceFcb( workContext->Fcb );
|
|
|
|
//
|
|
// Free the memory from the work context, the timer,
|
|
// and the DPC.
|
|
//
|
|
|
|
ExFreePool( workContext );
|
|
|
|
}
|
|
|
|
}
|
|
|
|
//
|
|
// Update the FCB last access time and complete the read request.
|
|
//
|
|
|
|
fcb = CONTAINING_RECORD( WriteQueue, FCB, DataQueue );
|
|
if ( NT_SUCCESS( readStatus ) ) {
|
|
KeQuerySystemTime( &fcb->Specific.Fcb.LastAccessTime );
|
|
}
|
|
|
|
MsCompleteRequest( readIrp, readStatus );
|
|
|
|
}
|
|
|
|
DebugTrace(0, Dbg, "Finished loop...\n", 0);
|
|
|
|
//
|
|
// At this point we've finished off all of the read entries in the
|
|
// queue and we might not have written the write data. If that
|
|
// is the case then we'll set our result to FALSE otherwise we're
|
|
// done so we'll return TRUE.
|
|
//
|
|
|
|
if ( !NT_SUCCESS( readStatus ) ) {
|
|
|
|
ASSERT( !MsIsDataQueueReaders( WriteQueue ));
|
|
result = FALSE;
|
|
|
|
} else {
|
|
|
|
result = TRUE;
|
|
}
|
|
|
|
DebugTrace(-1, Dbg, "MsWriteDataQueue -> %08lx\n", result);
|
|
return result;
|
|
|
|
}
|
|
|