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.

524 lines
14 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Write.c
  5. Abstract:
  6. This module implements the File Write 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_WRITE)
  17. #if DBG
  18. ULONG NpFastWriteTrue = 0;
  19. ULONG NpFastWriteFalse = 0;
  20. ULONG NpSlowWriteCalls = 0;
  21. #endif
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text(PAGE, NpCommonWrite)
  24. #pragma alloc_text(PAGE, NpFastWrite)
  25. #pragma alloc_text(PAGE, NpFsdWrite)
  26. #endif
  27. NTSTATUS
  28. NpFsdWrite (
  29. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  30. IN PIRP Irp
  31. )
  32. /*++
  33. Routine Description:
  34. This routine implements the FSD part of the NtWriteFile API calls.
  35. Arguments:
  36. NpfsDeviceObject - Supplies the device object to use.
  37. Irp - Supplies the Irp being processed
  38. Return Value:
  39. NTSTATUS - The Fsd status for the Irp
  40. --*/
  41. {
  42. IO_STATUS_BLOCK Iosb;
  43. PIO_STACK_LOCATION IrpSp;
  44. LIST_ENTRY DeferredList;
  45. PAGED_CODE();
  46. DebugTrace(+1, Dbg, "NpFsdWrite\n", 0);
  47. DbgDoit( NpSlowWriteCalls += 1 );
  48. InitializeListHead (&DeferredList);
  49. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  50. FsRtlEnterFileSystem();
  51. NpAcquireSharedVcb();
  52. (VOID) NpCommonWrite( IrpSp->FileObject,
  53. Irp->UserBuffer,
  54. IrpSp->Parameters.Write.Length,
  55. Irp->Tail.Overlay.Thread,
  56. &Iosb,
  57. Irp,
  58. &DeferredList );
  59. NpReleaseVcb();
  60. //
  61. // Complete any deferred IRPs now we have dropped the locks
  62. //
  63. NpCompleteDeferredIrps (&DeferredList);
  64. FsRtlExitFileSystem();
  65. if (Iosb.Status != STATUS_PENDING) {
  66. Irp->IoStatus.Information = Iosb.Information;
  67. NpCompleteRequest (Irp, Iosb.Status);
  68. }
  69. //
  70. // And return to our caller
  71. //
  72. DebugTrace(-1, Dbg, "NpFsdWrite -> %08lx\n", Iosb.Status );
  73. return Iosb.Status;
  74. }
  75. BOOLEAN
  76. NpFastWrite (
  77. IN PFILE_OBJECT FileObject,
  78. IN PLARGE_INTEGER FileOffset,
  79. IN ULONG Length,
  80. IN BOOLEAN Wait,
  81. IN ULONG LockKey,
  82. IN PVOID Buffer,
  83. OUT PIO_STATUS_BLOCK IoStatus,
  84. IN PDEVICE_OBJECT DeviceObject
  85. )
  86. /*++
  87. Routine Description:
  88. This routine does a fast write bypassing the usual file system
  89. entry routine (i.e., without the Irp).
  90. Arguments:
  91. FileObject - Pointer to the file object being read.
  92. FileOffset - Byte offset in file for desired data.
  93. Length - Length of desired data in bytes.
  94. Wait - FALSE if caller may not block, TRUE otherwise
  95. LockKey - Supplies the Key used to use if the byte range being read is locked.
  96. Buffer - Pointer to output buffer to which data should be copied.
  97. IoStatus - Pointer to standard I/O status block to receive the status
  98. for the transfer.
  99. Return Value:
  100. BOOLEAN - TRUE if the operation completed successfully and FALSE if the
  101. caller needs to take the long IRP based route.
  102. --*/
  103. {
  104. BOOLEAN Results = FALSE;
  105. LIST_ENTRY DeferredList;
  106. UNREFERENCED_PARAMETER( FileOffset );
  107. UNREFERENCED_PARAMETER( Wait );
  108. UNREFERENCED_PARAMETER( LockKey );
  109. UNREFERENCED_PARAMETER( DeviceObject );
  110. PAGED_CODE();
  111. InitializeListHead (&DeferredList);
  112. FsRtlEnterFileSystem();
  113. NpAcquireSharedVcb();
  114. if (NpCommonWrite( FileObject,
  115. Buffer,
  116. Length,
  117. PsGetCurrentThread(),
  118. IoStatus,
  119. NULL,
  120. &DeferredList )) {
  121. DbgDoit( NpFastWriteTrue += 1 );
  122. Results = TRUE;
  123. } else {
  124. DbgDoit( NpFastWriteFalse += 1 );
  125. }
  126. NpReleaseVcb();
  127. //
  128. // Complete any deferred IRPs now we have dropped the locks
  129. //
  130. NpCompleteDeferredIrps (&DeferredList);
  131. FsRtlExitFileSystem();
  132. return Results;
  133. }
  134. //
  135. // Internal support routine
  136. //
  137. BOOLEAN
  138. NpCommonWrite (
  139. IN PFILE_OBJECT FileObject,
  140. IN PVOID WriteBuffer,
  141. IN ULONG WriteLength,
  142. IN PETHREAD UserThread,
  143. OUT PIO_STATUS_BLOCK Iosb,
  144. IN PIRP Irp OPTIONAL,
  145. IN PLIST_ENTRY DeferredList
  146. )
  147. /*++
  148. Routine Description:
  149. This is the common routine for writing data to a named pipe both via the
  150. fast path and with an Irp.
  151. Arguments:
  152. FileObject - Supplies the file object used in this operation
  153. WriteBuffer - Supplies the buffer where data from which data is to be read
  154. WriteLength - Supplies the length of the write buffer in bytes
  155. UserThread - Supplies the thread id of the caller
  156. Iosb - Receives the final completion status of this operation
  157. Irp - Optionally supplies an Irp to be used in this operation
  158. Return Value:
  159. NTSTATUS - the return status for the operation
  160. --*/
  161. {
  162. NODE_TYPE_CODE NodeTypeCode;
  163. PCCB Ccb;
  164. PNONPAGED_CCB NonpagedCcb;
  165. NAMED_PIPE_END NamedPipeEnd;
  166. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  167. ULONG WriteRemaining;
  168. PDATA_QUEUE WriteQueue;
  169. PEVENT_TABLE_ENTRY Event;
  170. READ_MODE ReadMode;
  171. BOOLEAN Status;
  172. PDATA_ENTRY DataEntry;
  173. PAGED_CODE();
  174. DebugTrace(+1, Dbg, "NpCommonWrite\n", 0);
  175. DebugTrace( 0, Dbg, "FileObject = %08lx\n", FileObject);
  176. DebugTrace( 0, Dbg, "WriteBuffer = %08lx\n", WriteBuffer);
  177. DebugTrace( 0, Dbg, "WriteLength = %08lx\n", WriteLength);
  178. DebugTrace( 0, Dbg, "UserThread = %08lx\n", UserThread);
  179. DebugTrace( 0, Dbg, "Iosb = %08lx\n", Iosb);
  180. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  181. Iosb->Information = 0;
  182. //
  183. // Get the Ccb and figure out who we are, and make sure we're not
  184. // disconnected
  185. //
  186. if ((NodeTypeCode = NpDecodeFileObject( FileObject,
  187. NULL,
  188. &Ccb,
  189. &NamedPipeEnd )) == NTC_UNDEFINED) {
  190. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  191. Iosb->Status = STATUS_PIPE_DISCONNECTED;
  192. return TRUE;
  193. }
  194. //
  195. // Now we only will allow write operations on the pipe and not a directory
  196. // or the device
  197. //
  198. if (NodeTypeCode != NPFS_NTC_CCB) {
  199. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  200. Iosb->Status = STATUS_INVALID_PARAMETER;
  201. return TRUE;
  202. }
  203. NpAcquireExclusiveCcb(Ccb);
  204. NonpagedCcb = Ccb->NonpagedCcb;
  205. try {
  206. //
  207. // Check if the pipe is not in the connected state.
  208. //
  209. if ((Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) ||
  210. (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) ||
  211. (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE)) {
  212. DebugTrace(0, Dbg, "Pipe in disconnected or listening or closing state\n", 0);
  213. if (Ccb->NamedPipeState == FILE_PIPE_DISCONNECTED_STATE) {
  214. Iosb->Status = STATUS_PIPE_DISCONNECTED;
  215. } else if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
  216. Iosb->Status = STATUS_PIPE_LISTENING;
  217. } else {
  218. Iosb->Status = STATUS_PIPE_CLOSING;
  219. }
  220. try_return(Status = TRUE);
  221. }
  222. ASSERT(Ccb->NamedPipeState == FILE_PIPE_CONNECTED_STATE);
  223. //
  224. // We only allow a write by the server on a non inbound only pipe
  225. // and by the client on a non outbound only pipe
  226. //
  227. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  228. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  229. (NamedPipeConfiguration == FILE_PIPE_INBOUND))
  230. ||
  231. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  232. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
  233. DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
  234. Iosb->Status = STATUS_INVALID_PARAMETER;
  235. try_return(Status = TRUE);
  236. }
  237. //
  238. // Set up the amount of data we will have written by the time this
  239. // operation gets completed and indicate success until we set it otherwise.
  240. //
  241. Iosb->Status = STATUS_SUCCESS;
  242. Iosb->Information = WriteLength;
  243. //
  244. // Now the data queue that we write into and the event that we signal
  245. // are based on the named pipe end. The server writes to the outbound
  246. // queue and signals the client event. The client does just the
  247. // opposite. We also need to figure out the read mode for the opposite
  248. // end of the pipe.
  249. //
  250. if (NamedPipeEnd == FILE_PIPE_SERVER_END) {
  251. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  252. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  253. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  254. } else {
  255. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  256. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  257. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  258. }
  259. //
  260. // The next section checks if we should continue with the write operation.
  261. // The reasons why we will not continue are if we recongnize that the
  262. // pipe quota will not support this write and it is a message mode type
  263. // with complete operations. We will also bail out now if the quota will
  264. // not support the write and this is a fast I/O write request.
  265. //
  266. // If the pipe contains readers and amount to read plus pipe quota is less
  267. // than the write length then we need to do some additional checks.
  268. // Or if pipe does not contain reads and the amount of quota left is less
  269. // than the write length then we need to do some additional checks.
  270. //
  271. if ((NpIsDataQueueReaders( WriteQueue ) &&
  272. (WriteQueue->BytesInQueue < WriteLength) &&
  273. (WriteQueue->Quota < WriteLength - WriteQueue->BytesInQueue))
  274. ||
  275. (!NpIsDataQueueReaders( WriteQueue ) &&
  276. ((WriteQueue->Quota - WriteQueue->QuotaUsed) < WriteLength))) {
  277. DebugTrace(0, Dbg, "Quota is not sufficient for the request\n", 0);
  278. //
  279. // If this is a message mode pipe with complete operations then we
  280. // complete without writing the message
  281. //
  282. if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) &&
  283. (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
  284. Iosb->Information = 0;
  285. Iosb->Status = STATUS_SUCCESS;
  286. try_return(Status = TRUE);
  287. }
  288. //
  289. // If this is a fast I/O pipe then we tell the call to take the long
  290. // Irp based route
  291. //
  292. if (!ARGUMENT_PRESENT(Irp)) {
  293. DebugTrace(0, Dbg, "Need to supply Irp\n", 0);
  294. try_return(Status = FALSE);
  295. }
  296. }
  297. //
  298. // Now we'll call our common write data queue routine to
  299. // transfer data out of our write buffer into the data queue.
  300. // If the result of the call is FALSE then we still have some
  301. // write data to put into the write queue.
  302. //
  303. Iosb->Status = NpWriteDataQueue( WriteQueue,
  304. ReadMode,
  305. WriteBuffer,
  306. WriteLength,
  307. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  308. &WriteRemaining,
  309. Ccb,
  310. NamedPipeEnd,
  311. UserThread,
  312. DeferredList );
  313. if (Iosb->Status == STATUS_MORE_PROCESSING_REQUIRED) {
  314. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  315. //
  316. // Check if the operation is not to block and if so then we
  317. // will complete the operation now with what we're written, if what is
  318. // left will not fit in the quota for the file
  319. //
  320. if (((Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) ||
  321. Irp == NULL) &&
  322. ((WriteQueue->Quota - WriteQueue->QuotaUsed) < WriteRemaining)) {
  323. DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
  324. Iosb->Information = WriteLength - WriteRemaining;
  325. Iosb->Status = STATUS_SUCCESS;
  326. } else {
  327. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  328. //
  329. // Add this write request to the write queue
  330. //
  331. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  332. Iosb->Status = NpAddDataQueueEntry( NamedPipeEnd,
  333. Ccb,
  334. WriteQueue,
  335. WriteEntries,
  336. Buffered,
  337. WriteLength,
  338. Irp,
  339. WriteBuffer,
  340. WriteLength - WriteRemaining );
  341. }
  342. } else {
  343. DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
  344. }
  345. //
  346. // And because we've done something we need to signal the
  347. // other ends event
  348. //
  349. NpSignalEventTableEntry( Event );
  350. Status = TRUE;
  351. try_exit: NOTHING;
  352. } finally {
  353. NpReleaseCcb(Ccb);
  354. }
  355. DebugTrace(-1, Dbg, "NpCommonWrite -> TRUE\n", 0);
  356. return Status;
  357. }