Leaked source code of windows server 2003
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.

329 lines
9.8 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. WriteSup.c
  5. Abstract:
  6. This module implements the Write support routine. This is a common
  7. write function that is called by write, unbuffered write, and transceive.
  8. Author:
  9. Gary Kimura [GaryKi] 21-Sep-1990
  10. Revision History:
  11. --*/
  12. #include "NpProcs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_WRITESUP)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text(PAGE, NpWriteDataQueue)
  19. #endif
  20. NTSTATUS
  21. NpWriteDataQueue (
  22. IN PDATA_QUEUE WriteQueue,
  23. IN READ_MODE ReadMode,
  24. IN PUCHAR WriteBuffer,
  25. IN ULONG WriteLength,
  26. IN NAMED_PIPE_TYPE PipeType,
  27. OUT PULONG WriteRemaining,
  28. IN PCCB Ccb,
  29. IN NAMED_PIPE_END NamedPipeEnd,
  30. IN PETHREAD UserThread,
  31. IN PLIST_ENTRY DeferredList
  32. )
  33. /*++
  34. Routine Description:
  35. This procedure writes data from the write buffer into read entries in
  36. the write queue. It will also dequeue entries in the queue as necessary.
  37. Arguments:
  38. WriteQueue - Provides the write queue to process.
  39. ReadMode - Supplies the read mode of read entries in the write queue.
  40. WriteBuffer - Provides the buffer from which to read the data.
  41. WriteLength - Provides the length, in bytes, of WriteBuffer.
  42. PipeType - Indicates if type of pipe (i.e., message or byte stream).
  43. WriteRemaining - Receives the number of bytes remaining to be transfered
  44. that were not completed by this call. If the operation wrote
  45. everything then is value is set to zero.
  46. Ccb - Supplies the ccb for the operation
  47. NamedPipeEnd - Supplies the end of the pipe doing the write
  48. UserThread - Supplies the user thread
  49. DeferredList - List of IRPs to be completed after we drop the locks
  50. Return Value:
  51. BOOLEAN - TRUE if the operation wrote everything and FALSE otherwise.
  52. Note that a zero byte message that hasn't been written will return
  53. a function result of FALSE and WriteRemaining of zero.
  54. --*/
  55. {
  56. NTSTATUS Result;
  57. BOOLEAN WriteZeroMessage;
  58. PDATA_ENTRY DataEntry;
  59. PUCHAR ReadBuffer;
  60. ULONG ReadLength;
  61. ULONG AmountToCopy;
  62. NTSTATUS Status;
  63. PSECURITY_CLIENT_CONTEXT SecurityContext;
  64. BOOLEAN DoneSecurity=FALSE;
  65. PIO_STACK_LOCATION IrpSp;
  66. BOOLEAN FreeBuffer;
  67. PIRP ReadIrp;
  68. PAGED_CODE();
  69. DebugTrace(+1, Dbg, "NpWriteDataQueue\n", 0);
  70. DebugTrace( 0, Dbg, "WriteQueue = %08lx\n", WriteQueue);
  71. DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
  72. DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);
  73. DebugTrace( 0, Dbg, "PipeType = %08lx\n", PipeType);
  74. DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
  75. DebugTrace( 0, Dbg, "NamedPipeEnd = %08lx\n", NamedPipeEnd);
  76. DebugTrace( 0, Dbg, "UserThread = %08lx\n", UserThread);
  77. //
  78. // Determine if we are to write a zero byte message, and initialize
  79. // WriteRemaining
  80. //
  81. *WriteRemaining = WriteLength;
  82. if ((PipeType == FILE_PIPE_MESSAGE_TYPE) && (WriteLength == 0)) {
  83. WriteZeroMessage = TRUE;
  84. } else {
  85. WriteZeroMessage = FALSE;
  86. }
  87. //
  88. // Now while the write queue has some read entries in it and
  89. // there is some remaining write data or this is a write zero message
  90. // then we'll do the following main loop
  91. //
  92. for (DataEntry = NpGetNextRealDataQueueEntry( WriteQueue, DeferredList );
  93. (NpIsDataQueueReaders(WriteQueue) &&
  94. ((*WriteRemaining > 0) || WriteZeroMessage));
  95. DataEntry = NpGetNextRealDataQueueEntry( WriteQueue, DeferredList )) {
  96. ReadLength = DataEntry->DataSize;
  97. DebugTrace(0, Dbg, "Top of main loop...\n", 0);
  98. DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  99. DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
  100. DebugTrace(0, Dbg, "*WriteRemaining = %08lx\n", *WriteRemaining);
  101. //
  102. // Check if this is a ReadOverflow Operation and if so then also check
  103. // that the read will succeed otherwise complete this read with
  104. // buffer overflow and continue on.
  105. //
  106. IrpSp = IoGetCurrentIrpStackLocation( DataEntry->Irp );
  107. if (IrpSp->MajorFunction == IRP_MJ_FILE_SYSTEM_CONTROL &&
  108. IrpSp->Parameters.FileSystemControl.FsControlCode == FSCTL_PIPE_INTERNAL_READ_OVFLOW) {
  109. if ((ReadLength < WriteLength) || WriteZeroMessage) {
  110. ReadIrp = NpRemoveDataQueueEntry( WriteQueue, TRUE, DeferredList );
  111. if (ReadIrp != NULL) {
  112. NpDeferredCompleteRequest( ReadIrp, STATUS_BUFFER_OVERFLOW, DeferredList );
  113. }
  114. continue;
  115. }
  116. }
  117. if (DataEntry->DataEntryType == Unbuffered) {
  118. DataEntry->Irp->Overlay.AllocationSize.QuadPart = WriteQueue->BytesInQueue - WriteQueue->BytesInQueue;
  119. }
  120. //
  121. // copy data from the write buffer at write offset to the
  122. // read buffer at read offset by the mininum of write remaining
  123. // or read remaining
  124. //
  125. AmountToCopy = (*WriteRemaining < ReadLength ? *WriteRemaining
  126. : ReadLength);
  127. if (DataEntry->DataEntryType != Unbuffered && AmountToCopy > 0) {
  128. ReadBuffer = NpAllocateNonPagedPool (AmountToCopy, 'RFpN');
  129. if (ReadBuffer == NULL) {
  130. return STATUS_INSUFFICIENT_RESOURCES;
  131. }
  132. FreeBuffer = TRUE;
  133. } else {
  134. ReadBuffer = DataEntry->Irp->AssociatedIrp.SystemBuffer;
  135. FreeBuffer = FALSE;
  136. }
  137. try {
  138. RtlCopyMemory( ReadBuffer,
  139. &WriteBuffer[ WriteLength - *WriteRemaining ],
  140. AmountToCopy );
  141. } except (EXCEPTION_EXECUTE_HANDLER) {
  142. if (FreeBuffer) {
  143. NpFreePool (ReadBuffer);
  144. }
  145. return GetExceptionCode ();
  146. }
  147. //
  148. // Done update the security in the CCB multiple times. It won't change.
  149. //
  150. if (DoneSecurity == FALSE) {
  151. DoneSecurity = TRUE;
  152. //
  153. // Now update the security fields in the nonpaged ccb
  154. //
  155. Status = NpGetClientSecurityContext (NamedPipeEnd,
  156. Ccb,
  157. UserThread,
  158. &SecurityContext);
  159. if (!NT_SUCCESS(Status)) {
  160. if (FreeBuffer) {
  161. NpFreePool (ReadBuffer);
  162. }
  163. return Status;
  164. }
  165. if (SecurityContext != NULL) {
  166. NpFreeClientSecurityContext (Ccb->SecurityClientContext);
  167. Ccb->SecurityClientContext = SecurityContext;
  168. }
  169. }
  170. //
  171. // Now we've done with the read entry so remove it from the
  172. // write queue, get its irp, and fill in the information field
  173. // to be the bytes that we've transferred into the read buffer.
  174. //
  175. ReadIrp = NpRemoveDataQueueEntry( WriteQueue, TRUE, DeferredList );
  176. if (ReadIrp == NULL) {
  177. if (FreeBuffer) {
  178. NpFreePool (ReadBuffer);
  179. }
  180. continue;
  181. }
  182. //
  183. // Update the Write remaining counts
  184. //
  185. *WriteRemaining -= AmountToCopy;
  186. ReadIrp->IoStatus.Information = AmountToCopy;
  187. if (FreeBuffer) {
  188. ReadIrp->AssociatedIrp.SystemBuffer = ReadBuffer;
  189. ReadIrp->Flags |= IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER | IRP_INPUT_OPERATION;
  190. }
  191. if (*WriteRemaining == 0) {
  192. DebugTrace(0, Dbg, "Finished up the write remaining\n", 0);
  193. //**** ASSERT( ReadIrp->IoStatus.Information != 0 );
  194. NpDeferredCompleteRequest( ReadIrp, STATUS_SUCCESS, DeferredList );
  195. WriteZeroMessage = FALSE;
  196. } else {
  197. //
  198. // There is still some space in the write buffer to be
  199. // written out, but before we can handle that (in the
  200. // following if statement) we need to finish the read.
  201. // If the read is message mode then we've overflowed the
  202. // buffer otherwise we completed successfully
  203. //
  204. if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
  205. DebugTrace(0, Dbg, "Read buffer Overflow\n", 0);
  206. NpDeferredCompleteRequest( ReadIrp, STATUS_BUFFER_OVERFLOW, DeferredList );
  207. } else {
  208. DebugTrace(0, Dbg, "Read buffer byte stream done\n", 0);
  209. //**** ASSERT( ReadIrp->IoStatus.Information != 0 );
  210. NpDeferredCompleteRequest( ReadIrp, STATUS_SUCCESS, DeferredList );
  211. }
  212. }
  213. }
  214. DebugTrace(0, Dbg, "Finished loop...\n", 0);
  215. DebugTrace(0, Dbg, "*WriteRemaining = %08lx\n", *WriteRemaining);
  216. DebugTrace(0, Dbg, "WriteZeroMessage = %08lx\n", WriteZeroMessage);
  217. //
  218. // At this point we've finished off all of the read entries in the
  219. // queue and we might still have something left to write. If that
  220. // is the case then we'll set our result to FALSE otherwise we're
  221. // done so we'll return TRUE.
  222. //
  223. if ((*WriteRemaining > 0) || (WriteZeroMessage)) {
  224. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  225. Result = STATUS_MORE_PROCESSING_REQUIRED;
  226. } else {
  227. Result = STATUS_SUCCESS;
  228. }
  229. DebugTrace(-1, Dbg, "NpWriteDataQueue -> %08lx\n", Result);
  230. return Result;
  231. }
  232.