windows-nt/Source/XPSP1/NT/base/fs/mailslot/writesup.c

193 lines
4.6 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/*++
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
NTSTATUS
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.
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:
STATUS_MORE_PROCESSING_REQUIRED if not all the data was written,
other status codes as appropriate.
--*/
{
NTSTATUS status;
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.
//
status = STATUS_MORE_PROCESSING_REQUIRED;
for (listEntry = MsGetNextDataQueueEntry( WriteQueue );
(MsIsDataQueueReaders(WriteQueue) &&
status == STATUS_MORE_PROCESSING_REQUIRED);
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);
//
// 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. This may take an exception
// because its a raw user mode buffer
//
status = readStatus = STATUS_SUCCESS;
try {
RtlCopyMemory (readBuffer,
WriteBuffer,
WriteLength);
} except (EXCEPTION_EXECUTE_HANDLER) {
return GetExceptionCode ();
}
} else {
//
// This read buffer was overflowed.
//
WriteLength = 0;
readStatus = STATUS_BUFFER_TOO_SMALL;
}
//
// We are about to complete a read IRP, so dequeue it.
//
readIrp = MsRemoveDataQueueEntry( WriteQueue, dataEntry );
if ( readIrp == NULL) {
//
// Cancel routine was already running for this IRP. Ignore it as it will be completed by
// cancel code. Force the loop for the next read irp if there is one.
//
status = STATUS_MORE_PROCESSING_REQUIRED;
continue;
}
//
// 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 );
}
readIrp->IoStatus.Information = WriteLength;
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 ( status == STATUS_MORE_PROCESSING_REQUIRED ) {
ASSERT( !MsIsDataQueueReaders( WriteQueue ));
}
DebugTrace(-1, Dbg, "MsWriteDataQueue -> %08lx\n", status);
return status;
}