Source code of Windows XP (NT5)
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.

488 lines
12 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Read.c
  5. Abstract:
  6. This module implements the File Read routine for NPFS called by the
  7. dispatch driver.
  8. Author:
  9. Gary Kimura [GaryKi] 21-Aug-1990
  10. Revision History:
  11. --*/
  12. #include "NpProcs.h"
  13. //
  14. // The debug trace level
  15. //
  16. #define Dbg (DEBUG_TRACE_READ)
  17. #if DBG
  18. ULONG NpFastReadTrue = 0;
  19. ULONG NpFastReadFalse = 0;
  20. ULONG NpSlowReadCalls = 0;
  21. #endif
  22. //
  23. // local procedure prototypes
  24. //
  25. BOOLEAN
  26. NpCommonRead (
  27. IN PFILE_OBJECT FileObject,
  28. OUT PVOID ReadBuffer,
  29. IN ULONG ReadLength,
  30. OUT PIO_STATUS_BLOCK Iosb,
  31. IN PIRP Irp OPTIONAL,
  32. IN PLIST_ENTRY DeferredList
  33. );
  34. #ifdef ALLOC_PRAGMA
  35. #pragma alloc_text(PAGE, NpCommonRead)
  36. #pragma alloc_text(PAGE, NpFastRead)
  37. #pragma alloc_text(PAGE, NpFsdRead)
  38. #endif
  39. NTSTATUS
  40. NpFsdRead (
  41. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  42. IN PIRP Irp
  43. )
  44. /*++
  45. Routine Description:
  46. This routine implements the FSD part of the NtReadFile API calls.
  47. Arguments:
  48. NpfsDeviceObject - Supplies the device object to use.
  49. Irp - Supplies the Irp being processed
  50. Return Value:
  51. NTSTATUS - The Fsd status for the Irp
  52. --*/
  53. {
  54. IO_STATUS_BLOCK Iosb;
  55. PIO_STACK_LOCATION IrpSp;
  56. LIST_ENTRY DeferredList;
  57. DebugTrace(+1, Dbg, "NpFsdRead\n", 0);
  58. DbgDoit( NpSlowReadCalls += 1 );
  59. PAGED_CODE();
  60. InitializeListHead (&DeferredList);
  61. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  62. FsRtlEnterFileSystem ();
  63. NpAcquireSharedVcb ();
  64. (VOID) NpCommonRead (IrpSp->FileObject,
  65. Irp->UserBuffer,
  66. IrpSp->Parameters.Read.Length,
  67. &Iosb,
  68. Irp,
  69. &DeferredList);
  70. NpReleaseVcb ();
  71. NpCompleteDeferredIrps (&DeferredList);
  72. FsRtlExitFileSystem ();
  73. if (Iosb.Status != STATUS_PENDING) {
  74. Irp->IoStatus.Information = Iosb.Information;
  75. NpCompleteRequest (Irp, Iosb.Status);
  76. }
  77. //
  78. // And return to our caller
  79. //
  80. DebugTrace(-1, Dbg, "NpFsdRead -> %08lx\n", Iosb.Status );
  81. return Iosb.Status;
  82. }
  83. BOOLEAN
  84. NpFastRead (
  85. IN PFILE_OBJECT FileObject,
  86. IN PLARGE_INTEGER FileOffset,
  87. IN ULONG Length,
  88. IN BOOLEAN Wait,
  89. IN ULONG LockKey,
  90. OUT PVOID Buffer,
  91. OUT PIO_STATUS_BLOCK IoStatus,
  92. IN PDEVICE_OBJECT DeviceObject
  93. )
  94. /*++
  95. Routine Description:
  96. This routine does a fast read bypassing the usual file system
  97. entry routine (i.e., without the Irp).
  98. Arguments:
  99. FileObject - Pointer to the file object being read.
  100. FileOffset - Byte offset in file for desired data.
  101. Length - Length of desired data in bytes.
  102. Wait - FALSE if caller may not block, TRUE otherwise
  103. LockKey - Supplies the Key used to use if the byte range being read is locked.
  104. Buffer - Pointer to output buffer to which data should be copied.
  105. IoStatus - Pointer to standard I/O status block to receive the status
  106. for the transfer.
  107. Return Value:
  108. BOOLEAN - TRUE if the operation completed successfully and FALSE if the
  109. caller needs to take the long IRP based route.
  110. --*/
  111. {
  112. BOOLEAN Results = FALSE;
  113. LIST_ENTRY DeferredList;
  114. UNREFERENCED_PARAMETER (FileOffset);
  115. UNREFERENCED_PARAMETER (Wait);
  116. UNREFERENCED_PARAMETER (LockKey);
  117. UNREFERENCED_PARAMETER (DeviceObject);
  118. PAGED_CODE();
  119. InitializeListHead (&DeferredList);
  120. FsRtlEnterFileSystem ();
  121. NpAcquireSharedVcb ();
  122. Results = NpCommonRead (FileObject,
  123. Buffer,
  124. Length,
  125. IoStatus,
  126. NULL,
  127. &DeferredList);
  128. #if DBG
  129. if (Results) {
  130. NpFastReadTrue += 1;
  131. } else {
  132. NpFastReadFalse += 1;
  133. }
  134. #endif
  135. NpReleaseVcb ();
  136. NpCompleteDeferredIrps (&DeferredList);
  137. FsRtlExitFileSystem ();
  138. return Results;
  139. }
  140. //
  141. // Internal support routine
  142. //
  143. BOOLEAN
  144. NpCommonRead (
  145. IN PFILE_OBJECT FileObject,
  146. OUT PVOID ReadBuffer,
  147. IN ULONG ReadLength,
  148. OUT PIO_STATUS_BLOCK Iosb,
  149. IN PIRP Irp OPTIONAL,
  150. IN PLIST_ENTRY DeferredList
  151. )
  152. /*++
  153. Routine Description:
  154. This is the common routine for reading a named pipe both via the fast
  155. path and with an Irp
  156. Arguments:
  157. FileObject - Supplies the file object used in this operation
  158. ReadBuffer - Supplies the buffer where data is to be written
  159. ReadLength - Supplies the length of read buffer in bytes
  160. Iosb - Receives the final completion status of this operation
  161. Irp - Optionally supplies an Irp to be used in this operation
  162. DeferredList - List of IRP's to be completed after we drop the locks
  163. Return Value:
  164. BOOLEAN - TRUE if the operation was successful and FALSE if the caller
  165. needs to take the longer Irp based route.
  166. --*/
  167. {
  168. NODE_TYPE_CODE NodeTypeCode;
  169. PCCB Ccb;
  170. PNONPAGED_CCB NonpagedCcb;
  171. NAMED_PIPE_END NamedPipeEnd;
  172. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  173. ULONG ReadRemaining;
  174. READ_MODE ReadMode;
  175. COMPLETION_MODE CompletionMode;
  176. PDATA_QUEUE ReadQueue;
  177. PEVENT_TABLE_ENTRY Event;
  178. BOOLEAN Status;
  179. PAGED_CODE();
  180. DebugTrace(+1, Dbg, "NpCommonRead\n", 0);
  181. DebugTrace( 0, Dbg, "FileObject = %08lx\n", FileObject);
  182. DebugTrace( 0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  183. DebugTrace( 0, Dbg, "ReadLength = %08lx\n", ReadLength);
  184. DebugTrace( 0, Dbg, "Iosb = %08lx\n", Iosb);
  185. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  186. Iosb->Information = 0;
  187. //
  188. // Get the Ccb and figure out who we are, and make sure we're not
  189. // disconnected
  190. //
  191. if ((NodeTypeCode = NpDecodeFileObject( FileObject,
  192. NULL,
  193. &Ccb,
  194. &NamedPipeEnd )) == NTC_UNDEFINED) {
  195. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  196. Iosb->Status = STATUS_PIPE_DISCONNECTED;
  197. return TRUE;
  198. }
  199. //
  200. // Now we only will allow Read operations on the pipe and not a directory
  201. // or the device
  202. //
  203. if (NodeTypeCode != NPFS_NTC_CCB) {
  204. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  205. Iosb->Status = STATUS_INVALID_PARAMETER;
  206. return TRUE;
  207. }
  208. NpAcquireExclusiveCcb(Ccb);
  209. NonpagedCcb = Ccb->NonpagedCcb;
  210. try {
  211. //
  212. // Check if the pipe is not in the connected state.
  213. //
  214. if ((Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
  215. (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE)) {
  216. DebugTrace(0, Dbg, "Pipe in disconnected or listening state\n", 0);
  217. if (Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) {
  218. Iosb->Status = STATUS_PIPE_DISCONNECTED;
  219. } else {
  220. Iosb->Status = STATUS_PIPE_LISTENING;
  221. }
  222. try_return(Status = TRUE);
  223. }
  224. ASSERT((Ccb->NamedPipeState == FILE_PIPE_CONNECTED_STATE) ||
  225. (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE));
  226. //
  227. // We only allow a read by the server on a non outbound only pipe
  228. // and by the client on a non inbound only pipe
  229. //
  230. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  231. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  232. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
  233. ||
  234. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  235. (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
  236. DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
  237. Iosb->Status = STATUS_INVALID_PARAMETER;
  238. try_return (Status = TRUE);
  239. }
  240. //
  241. // Reference our input parameters to make things easier, and
  242. // initialize our main variables that describe the Read command
  243. //
  244. ReadRemaining = ReadLength;
  245. ReadMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].ReadMode;
  246. CompletionMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].CompletionMode;
  247. //
  248. // Now the data queue that we read from into and the event that we signal
  249. // are based on the named pipe end. The server read from the inbound
  250. // queue and signals the client event. The client does just the
  251. // opposite.
  252. //
  253. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  254. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  255. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  256. } else {
  257. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  258. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  259. }
  260. DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  261. DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
  262. DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
  263. DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode);
  264. DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
  265. DebugTrace(0, Dbg, "Event = %08lx\n", Event);
  266. //
  267. // if the read queue does not contain any write entries
  268. // then we either need to enqueue this operation or
  269. // fail immediately
  270. //
  271. if (!NpIsDataQueueWriters( ReadQueue )) {
  272. //
  273. // Check if the other end of the pipe is closing, and if
  274. // so then we complete it with end of file.
  275. // Otherwise check to see if we should enqueue the irp
  276. // or complete the operation and tell the user the pipe is empty.
  277. //
  278. if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
  279. DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
  280. Iosb->Status = STATUS_PIPE_BROKEN;
  281. } else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
  282. if (!ARGUMENT_PRESENT(Irp)) {
  283. DebugTrace(0, Dbg, "Need to supply Irp\n", 0);
  284. try_return(Status = FALSE);
  285. }
  286. DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
  287. Iosb->Status = NpAddDataQueueEntry( NamedPipeEnd,
  288. Ccb,
  289. ReadQueue,
  290. ReadEntries,
  291. Buffered,
  292. ReadLength,
  293. Irp,
  294. NULL,
  295. 0 );
  296. if (!NT_SUCCESS (Iosb->Status)) {
  297. try_return(Status = FALSE);
  298. }
  299. } else {
  300. DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
  301. Iosb->Status = STATUS_PIPE_EMPTY;
  302. }
  303. } else {
  304. //
  305. // otherwise there we have a read irp against a read queue
  306. // that contains one or more write entries.
  307. //
  308. *Iosb = NpReadDataQueue( ReadQueue,
  309. FALSE,
  310. FALSE,
  311. ReadBuffer,
  312. ReadLength,
  313. ReadMode,
  314. Ccb,
  315. DeferredList );
  316. if (!NT_SUCCESS (Iosb->Status)) {
  317. try_return(Status = TRUE);
  318. }
  319. }
  320. Status = TRUE;
  321. //
  322. // And because we've done something we need to signal the
  323. // other ends event
  324. //
  325. NpSignalEventTableEntry( Event );
  326. try_exit: NOTHING;
  327. } finally {
  328. NpReleaseCcb(Ccb);
  329. }
  330. DebugTrace(-1, Dbg, "NpCommonRead -> TRUE\n", 0);
  331. return Status;
  332. }