/*++ 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; }