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.

307 lines
7.2 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. readsup.c
  5. Abstract:
  6. This module implements the read support routine. This is a common
  7. read function that is called to do read and peek.
  8. Author:
  9. Manny Weiser (mannyw) 15-Jan-1991
  10. Revision History:
  11. --*/
  12. #include "mailslot.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_READSUP)
  17. #ifdef ALLOC_PRAGMA
  18. #pragma alloc_text( PAGE, MsReadDataQueue )
  19. #pragma alloc_text( PAGE, MsTimeoutRead )
  20. #endif
  21. IO_STATUS_BLOCK
  22. MsReadDataQueue (
  23. IN PDATA_QUEUE ReadQueue,
  24. IN ENTRY_TYPE Operation,
  25. IN PUCHAR ReadBuffer,
  26. IN ULONG ReadLength,
  27. OUT PULONG MessageLength
  28. )
  29. /*++
  30. Routine Description:
  31. This function reads data from the read queue and fills up the
  32. read buffer. It will also dequeue the data entry if this is not
  33. a peek operation.
  34. It will only be called if there is at least one message to read.
  35. Arguments:
  36. ReadQueue - Provides the read queue to examine. Its state must
  37. already be set to WriteEntries.
  38. Operation - Indicates the type of operation to perform. If the
  39. operation is Peek, the write data entry is not dequeued.
  40. ReadBuffer - Supplies a buffer to receive the data
  41. ReadLength - Supplies the length, in bytes, of ReadBuffer.
  42. MessageLength - Returns the full size of the message, even if the
  43. read buffer is not large enough to contain the entire message.
  44. Return Value:
  45. IO_STATUS_BLOCK - Indicates the result of the operation.
  46. --*/
  47. {
  48. IO_STATUS_BLOCK iosb;
  49. PLIST_ENTRY listEntry;
  50. PDATA_ENTRY dataEntry;
  51. PFCB fcb;
  52. PUCHAR writeBuffer;
  53. ULONG writeLength;
  54. ULONG amountRead;
  55. PAGED_CODE();
  56. DebugTrace(+1, Dbg, "MsReadDataQueue\n", 0);
  57. DebugTrace( 0, Dbg, "ReadQueue = %08lx\n", (ULONG)ReadQueue);
  58. DebugTrace( 0, Dbg, "Operation = %08lx\n", Operation);
  59. DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", (ULONG)ReadBuffer);
  60. DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
  61. //
  62. // Read the first message out of the data queue.
  63. //
  64. iosb.Status = STATUS_SUCCESS;
  65. iosb.Information = 0;
  66. listEntry = MsGetNextDataQueueEntry( ReadQueue );
  67. ASSERT( listEntry != &ReadQueue->DataEntryList );
  68. dataEntry = CONTAINING_RECORD( listEntry, DATA_ENTRY, ListEntry );
  69. //
  70. // Calculate how much data is in this entry.
  71. //
  72. writeBuffer = dataEntry->DataPointer;
  73. writeLength = dataEntry->DataSize;
  74. DebugTrace(0, Dbg, "WriteBuffer = %08lx\n", (ULONG)writeBuffer);
  75. DebugTrace(0, Dbg, "WriteLength = %08lx\n", writeLength);
  76. //
  77. // Fail this operation, if it is a read and the buffer is not large
  78. // enough.
  79. //
  80. if (ReadLength < writeLength) {
  81. if (Operation != Peek) {
  82. iosb.Information = 0;
  83. iosb.Status = STATUS_BUFFER_TOO_SMALL;
  84. return iosb;
  85. }
  86. iosb.Status = STATUS_BUFFER_OVERFLOW;
  87. DebugTrace(0, Dbg, "Overflowed peek buffer\n", 0);
  88. amountRead = ReadLength;
  89. } else {
  90. amountRead = writeLength;
  91. }
  92. //
  93. // Copy data from the write buffer at write offset to the
  94. // read buffer by the mininum of write remaining or read length
  95. //
  96. // This copy may take an exception and thats why this call needs to be enclosed
  97. // in try/except.
  98. //
  99. try {
  100. RtlCopyMemory (ReadBuffer,
  101. writeBuffer,
  102. amountRead);
  103. } except (EXCEPTION_EXECUTE_HANDLER) {
  104. iosb.Status = GetExceptionCode ();
  105. return iosb;
  106. }
  107. *MessageLength = dataEntry->DataSize;
  108. //
  109. // If write length is larger than read length, this must be an
  110. // overflowed peek.
  111. //
  112. if (writeLength <= ReadLength) {
  113. //
  114. // The write entry is done so remove it from the read
  115. // queue, if this is not a peek operation. This might
  116. // also have an IRP that needs to be completed.
  117. //
  118. if (Operation != Peek) {
  119. PIRP writeIrp;
  120. if ((writeIrp = MsRemoveDataQueueEntry( ReadQueue,
  121. dataEntry )) != NULL) {
  122. //
  123. // Writes don't get queued. This is an error
  124. //
  125. KeBugCheckEx( MAILSLOT_FILE_SYSTEM,
  126. 1,
  127. (ULONG_PTR) writeIrp,
  128. (ULONG_PTR) ReadQueue,
  129. (ULONG_PTR) dataEntry );
  130. }
  131. }
  132. DebugTrace(0, Dbg, "Successful mailslot read\n", 0);
  133. //
  134. // Indicate success.
  135. //
  136. iosb.Status = STATUS_SUCCESS;
  137. }
  138. DebugTrace(0, Dbg, "Amount read = %08lx\n", amountRead);
  139. iosb.Information = amountRead;
  140. DebugTrace(-1, Dbg, "MsReadDataQueue -> iosb.Status = %08lx\n", iosb.Status);
  141. return iosb;
  142. }
  143. VOID
  144. MsTimeoutRead (
  145. IN PDEVICE_OBJECT DeviceObject,
  146. IN PVOID Context
  147. )
  148. /*++
  149. Routine Description:
  150. This routine times out a read operation. It gains exclusive
  151. access to the FCB, and searches the data queue of read operations.
  152. If the timed out read operation is not found, it is assumed that
  153. a write IRP completed the read after the time out DPC ran, but
  154. before this function could complete the read IRP.
  155. Arguments:
  156. Context - a pointer to our WorkContext
  157. Return Value:
  158. None.
  159. --*/
  160. {
  161. PDATA_QUEUE dataQueue;
  162. PLIST_ENTRY listEntry;
  163. PIRP queuedIrp;
  164. PDATA_ENTRY dataEntry;
  165. PWORK_CONTEXT workContext;
  166. PIRP irp;
  167. PFCB fcb;
  168. PAGED_CODE();
  169. //
  170. // Reference our local variables.
  171. //
  172. workContext = (PWORK_CONTEXT)Context;
  173. fcb = workContext->Fcb;
  174. dataQueue = &fcb->DataQueue;
  175. //
  176. // Acquire exclusive access to the FCB. This must succeed.
  177. //
  178. MsAcquireExclusiveFcb( fcb );
  179. //
  180. // There are two cases to consider here. Either this timer is the first completion
  181. // event for this IRP or we werent but we started running before they could cancel the timer.
  182. // When the second case is detected the other thread NULL's out the IRP pointer.
  183. //
  184. irp = workContext->Irp;
  185. if (irp) {
  186. dataEntry = (PDATA_ENTRY)IoGetNextIrpStackLocation( irp );
  187. //
  188. // Nobody else should touch this once we release the lock.
  189. //
  190. dataEntry->TimeoutWorkContext = NULL;
  191. //
  192. // If cancel isn't active for the IRP.
  193. //
  194. irp = MsRemoveDataQueueEntry( dataQueue, dataEntry );
  195. }
  196. //
  197. // Release the FCB, and derefernce it.
  198. //
  199. MsReleaseFcb( fcb );
  200. MsDereferenceFcb( fcb );
  201. //
  202. // Free the work context and the work item. We have to do this unconditionaly
  203. // if we started running
  204. //
  205. IoFreeWorkItem (workContext->WorkItem);
  206. ExFreePool( workContext );
  207. if (irp != NULL) {
  208. DebugTrace(0, Dbg, "Completing IRP %p\n", irp );
  209. MsCompleteRequest( irp, STATUS_IO_TIMEOUT );
  210. }
  211. }