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.

3110 lines
78 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. FsContrl.c
  5. Abstract:
  6. This module implements the File System Control routine for NPFS called by
  7. the dispatch driver.
  8. Author:
  9. Gary Kimura [GaryKi] 21-Aug-1990
  10. Revision History:
  11. --*/
  12. #include "NpProcs.h"
  13. //
  14. // The Bug check file id for this module
  15. //
  16. #define BugCheckFileId (NPFS_BUG_CHECK_FSCTRL)
  17. //
  18. // The debug trace level
  19. //
  20. #define Dbg (DEBUG_TRACE_FSCONTRL)
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, NpAssignEvent)
  23. #pragma alloc_text(PAGE, NpCommonFileSystemControl)
  24. #pragma alloc_text(PAGE, NpCompleteTransceiveIrp)
  25. #pragma alloc_text(PAGE, NpDisconnect)
  26. #pragma alloc_text(PAGE, NpFsdFileSystemControl)
  27. #pragma alloc_text(PAGE, NpImpersonate)
  28. #pragma alloc_text(PAGE, NpInternalRead)
  29. #pragma alloc_text(PAGE, NpInternalTransceive)
  30. #pragma alloc_text(PAGE, NpInternalWrite)
  31. #pragma alloc_text(PAGE, NpListen)
  32. #pragma alloc_text(PAGE, NpPeek)
  33. #pragma alloc_text(PAGE, NpQueryClientProcess)
  34. #pragma alloc_text(PAGE, NpQueryEvent)
  35. #pragma alloc_text(PAGE, NpSetClientProcess)
  36. #pragma alloc_text(PAGE, NpTransceive)
  37. #pragma alloc_text(PAGE, NpWaitForNamedPipe)
  38. #endif
  39. NTSTATUS
  40. NpFsdFileSystemControl (
  41. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  42. IN PIRP Irp
  43. )
  44. /*++
  45. Routine Description:
  46. This routine implements the FSD part of the NtFsControlFile 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. NTSTATUS Status;
  55. PAGED_CODE();
  56. DebugTrace(+1, Dbg, "NpFsdFileSystemControl\n", 0);
  57. //
  58. // Call the common FsControl routine.
  59. //
  60. FsRtlEnterFileSystem();
  61. Status = NpCommonFileSystemControl( NpfsDeviceObject,
  62. Irp );
  63. FsRtlExitFileSystem();
  64. if (Status != STATUS_PENDING) {
  65. NpCompleteRequest (Irp, Status);
  66. }
  67. //
  68. // And return to our caller
  69. //
  70. DebugTrace(-1, Dbg, "NpFsdFileSystemControl -> %08lx\n", Status );
  71. return Status;
  72. }
  73. //
  74. // Internal Support Routine
  75. //
  76. NTSTATUS
  77. NpCommonFileSystemControl (
  78. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  79. IN PIRP Irp
  80. )
  81. /*++
  82. Routine Description:
  83. This routine does the common code for handling/dispatching an fsctl
  84. function.
  85. Arguments:
  86. NpfsDeviceObject - Supplies the named pipe device object
  87. Irp - Supplies the Irp being processed
  88. Return Value:
  89. NTSTATUS - The return status for the operation
  90. --*/
  91. {
  92. NTSTATUS Status;
  93. PIO_STACK_LOCATION IrpSp;
  94. BOOLEAN ReadOverflowOperation;
  95. LIST_ENTRY DeferredList;
  96. PAGED_CODE();
  97. //
  98. // Reference our input parameters to make things easier
  99. //
  100. IrpSp = IoGetCurrentIrpStackLocation (Irp);
  101. InitializeListHead (&DeferredList);
  102. DebugTrace(+1, Dbg, "NpCommonFileSystemControl\n", 0);
  103. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  104. DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.OutputBufferLength);
  105. DebugTrace( 0, Dbg, "InputBufferLength = %08lx\n", IrpSp->Parameters.FileSystemControl.InputBufferLength);
  106. DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", IrpSp->Parameters.FileSystemControl.FsControlCode);
  107. //
  108. // Case on the type of function we're trying to do. In each case
  109. // we'll call a local work routine to do the actual work.
  110. //
  111. ReadOverflowOperation = FALSE;
  112. switch (IrpSp->Parameters.FileSystemControl.FsControlCode) {
  113. case FSCTL_PIPE_ASSIGN_EVENT:
  114. NpAcquireExclusiveVcb ();
  115. Status = NpAssignEvent (NpfsDeviceObject, Irp);
  116. break;
  117. case FSCTL_PIPE_DISCONNECT:
  118. NpAcquireExclusiveVcb ();
  119. Status = NpDisconnect (NpfsDeviceObject, Irp, &DeferredList);
  120. break;
  121. case FSCTL_PIPE_LISTEN:
  122. NpAcquireSharedVcb ();
  123. Status = NpListen (NpfsDeviceObject, Irp, &DeferredList);
  124. break;
  125. case FSCTL_PIPE_PEEK:
  126. NpAcquireExclusiveVcb ();
  127. Status = NpPeek (NpfsDeviceObject, Irp, &DeferredList);
  128. break;
  129. case FSCTL_PIPE_QUERY_EVENT:
  130. NpAcquireExclusiveVcb ();
  131. Status = NpQueryEvent (NpfsDeviceObject, Irp);
  132. break;
  133. case FSCTL_PIPE_TRANSCEIVE:
  134. NpAcquireSharedVcb ();
  135. Status = NpTransceive (NpfsDeviceObject, Irp, &DeferredList);
  136. break;
  137. case FSCTL_PIPE_WAIT:
  138. NpAcquireExclusiveVcb ();
  139. Status = NpWaitForNamedPipe (NpfsDeviceObject, Irp);
  140. break;
  141. case FSCTL_PIPE_IMPERSONATE:
  142. NpAcquireExclusiveVcb ();
  143. Status = NpImpersonate (NpfsDeviceObject, Irp);
  144. break;
  145. case FSCTL_PIPE_INTERNAL_READ_OVFLOW:
  146. ReadOverflowOperation = TRUE;
  147. case FSCTL_PIPE_INTERNAL_READ:
  148. NpAcquireSharedVcb ();
  149. Status = NpInternalRead (NpfsDeviceObject, Irp, ReadOverflowOperation, &DeferredList);
  150. break;
  151. case FSCTL_PIPE_INTERNAL_WRITE:
  152. NpAcquireSharedVcb ();
  153. Status = NpInternalWrite (NpfsDeviceObject, Irp, &DeferredList);
  154. break;
  155. case FSCTL_PIPE_INTERNAL_TRANSCEIVE:
  156. NpAcquireSharedVcb ();
  157. Status = NpInternalTransceive (NpfsDeviceObject, Irp, &DeferredList);
  158. break;
  159. case FSCTL_PIPE_QUERY_CLIENT_PROCESS:
  160. NpAcquireSharedVcb ();
  161. Status = NpQueryClientProcess (NpfsDeviceObject, Irp);
  162. break;
  163. case FSCTL_PIPE_SET_CLIENT_PROCESS:
  164. NpAcquireExclusiveVcb ();
  165. Status = NpSetClientProcess (NpfsDeviceObject, Irp);
  166. break;
  167. default:
  168. return STATUS_NOT_SUPPORTED; // No lock acquired
  169. }
  170. NpReleaseVcb ();
  171. //
  172. // Complete any deferred IRPs now we have dropped the last lock
  173. //
  174. NpCompleteDeferredIrps (&DeferredList);
  175. //
  176. // And return to our caller
  177. //
  178. DebugTrace(-1, Dbg, "NpCommonFileSystemControl -> %08lx\n", Status);
  179. return Status;
  180. }
  181. //
  182. // Local support routine
  183. //
  184. NTSTATUS
  185. NpAssignEvent (
  186. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  187. IN PIRP Irp
  188. )
  189. /*++
  190. Routine Description:
  191. This routine does the assign event control function
  192. Arguments:
  193. NpfsDeviceObject - Supplies our device object
  194. Irp - Supplies the Irp specifying the function
  195. Return Value:
  196. NTSTATUS - An appropriate return status
  197. --*/
  198. {
  199. PIO_STACK_LOCATION IrpSp;
  200. ULONG InputBufferLength;
  201. ULONG FsControlCode;
  202. PCCB Ccb;
  203. PNONPAGED_CCB NonpagedCcb;
  204. NAMED_PIPE_END NamedPipeEnd;
  205. PFILE_PIPE_ASSIGN_EVENT_BUFFER EventBuffer;
  206. NTSTATUS status;
  207. PAGED_CODE();
  208. //
  209. // Get the current stack location
  210. //
  211. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  212. DebugTrace(+1, Dbg, "NpAssignEvent...\n", 0);
  213. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  214. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  215. //
  216. // Decode the file object to figure out who we are. If the result
  217. // is not a ccb then the pipe has been disconnected.
  218. //
  219. if (NpDecodeFileObject( IrpSp->FileObject,
  220. NULL,
  221. &Ccb,
  222. &NamedPipeEnd ) != NPFS_NTC_CCB) {
  223. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  224. return STATUS_PIPE_DISCONNECTED;
  225. }
  226. NonpagedCcb = Ccb->NonpagedCcb;
  227. //
  228. // Reference the system buffer as an assign event buffer and make
  229. // sure it's large enough
  230. //
  231. EventBuffer = Irp->AssociatedIrp.SystemBuffer;
  232. if (InputBufferLength < sizeof(FILE_PIPE_ASSIGN_EVENT_BUFFER)) {
  233. DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
  234. return STATUS_INVALID_PARAMETER;
  235. }
  236. //
  237. // First thing we do is delete the old event if there is one
  238. // for this end of the pipe
  239. //
  240. NpDeleteEventTableEntry( &NpVcb->EventTable,
  241. NonpagedCcb->EventTableEntry[ NamedPipeEnd ] );
  242. NonpagedCcb->EventTableEntry[ NamedPipeEnd ] = NULL;
  243. //
  244. // Now if the new event handle is not null then we'll add the new
  245. // event to the event table
  246. //
  247. status = STATUS_SUCCESS;
  248. if (EventBuffer->EventHandle != NULL) {
  249. status = NpAddEventTableEntry( &NpVcb->EventTable,
  250. Ccb,
  251. NamedPipeEnd,
  252. EventBuffer->EventHandle,
  253. EventBuffer->KeyValue,
  254. PsGetCurrentProcess(),
  255. Irp->RequestorMode,
  256. &NonpagedCcb->EventTableEntry[ NamedPipeEnd ] );
  257. }
  258. DebugTrace(-1, Dbg, "NpAssignEvent -> STATUS_SUCCESS\n", 0);
  259. return status;
  260. }
  261. //
  262. // Local Support Routine
  263. //
  264. NTSTATUS
  265. NpDisconnect (
  266. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  267. IN PIRP Irp,
  268. IN PLIST_ENTRY DeferredList
  269. )
  270. /*++
  271. Routine Description:
  272. This routine does the disconnect control function
  273. Arguments:
  274. NpfsDeviceObject - Supplies our device object
  275. Irp - Supplies the being processed
  276. DeferredList - List of IRPs to complete after we drop the locks
  277. Return Value:
  278. NTSTATUS - An apprropriate return status
  279. --*/
  280. {
  281. NTSTATUS Status;
  282. PIO_STACK_LOCATION IrpSp;
  283. ULONG FsControlCode;
  284. PCCB Ccb;
  285. NAMED_PIPE_END NamedPipeEnd;
  286. PAGED_CODE();
  287. //
  288. // Get the current stack location
  289. //
  290. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  291. DebugTrace(+1, Dbg, "NpDisconnect...\n", 0);
  292. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  293. //
  294. // Decode the file object to figure out who we are. If the result
  295. // is not a ccb then the pipe has been disconnected.
  296. //
  297. if (NpDecodeFileObject( IrpSp->FileObject,
  298. NULL,
  299. &Ccb,
  300. &NamedPipeEnd ) != NPFS_NTC_CCB) {
  301. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  302. return STATUS_PIPE_DISCONNECTED;
  303. }
  304. //
  305. // Make sure that this is only the server that is doing this
  306. // action.
  307. //
  308. if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
  309. DebugTrace(0, Dbg, "Not the server end\n", 0);
  310. return STATUS_ILLEGAL_FUNCTION;
  311. }
  312. NpAcquireExclusiveCcb(Ccb);
  313. //
  314. // Now call the state support routine to set the ccb to
  315. // a disconnected state and remove the client's cached security
  316. // context.
  317. //
  318. Status = NpSetDisconnectedPipeState( Ccb, DeferredList );
  319. NpUninitializeSecurity( Ccb );
  320. NpReleaseCcb(Ccb);
  321. DebugTrace(-1, Dbg, "NpDisconnect -> %08lx\n", Status);
  322. return Status;
  323. }
  324. //
  325. // Local Support Routine
  326. //
  327. NTSTATUS
  328. NpListen (
  329. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  330. IN PIRP Irp,
  331. IN PLIST_ENTRY DeferredList
  332. )
  333. /*++
  334. Routine Description:
  335. This routine does the listen control function
  336. Arguments:
  337. NpfsDeviceObject - Supplies our device object
  338. Irp - Supplies the being processed
  339. DeferredList - List of IRPs to complete once we drop the locks
  340. Return Value:
  341. NTSTATUS - An apprropriate return status
  342. --*/
  343. {
  344. NTSTATUS Status;
  345. PIO_STACK_LOCATION IrpSp;
  346. ULONG FsControlCode;
  347. PCCB Ccb;
  348. NAMED_PIPE_END NamedPipeEnd;
  349. PAGED_CODE();
  350. //
  351. // Get the current stack location
  352. //
  353. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  354. DebugTrace(+1, Dbg, "NpListen...\n", 0);
  355. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  356. //
  357. // Decode the file object to figure out who we are. If the result
  358. // is not a ccb then the pipe has been disconnected.
  359. //
  360. if (NpDecodeFileObject( IrpSp->FileObject,
  361. NULL,
  362. &Ccb,
  363. &NamedPipeEnd ) != NPFS_NTC_CCB) {
  364. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  365. DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  366. return STATUS_ILLEGAL_FUNCTION;
  367. }
  368. //
  369. // Make sure that this is only the server that is doing this
  370. // action.
  371. //
  372. if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
  373. DebugTrace(0, Dbg, "Not the server end\n", 0);
  374. DebugTrace(-1, Dbg, "NpListen -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  375. return STATUS_ILLEGAL_FUNCTION;
  376. }
  377. NpAcquireExclusiveCcb(Ccb);
  378. //
  379. // Now call the state support routine to set the ccb to
  380. // a listening state. This routine will complete the Irp
  381. // for us.
  382. //
  383. Status = NpSetListeningPipeState( Ccb, Irp, DeferredList );
  384. NpReleaseCcb(Ccb);
  385. DebugTrace(-1, Dbg, "NpListen -> %08lx\n", Status);
  386. return Status;
  387. }
  388. //
  389. // Local Support Routine
  390. //
  391. NTSTATUS
  392. NpPeek (
  393. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  394. IN PIRP Irp,
  395. IN PLIST_ENTRY DeferredList
  396. )
  397. /*++
  398. Routine Description:
  399. This routine does the peek control function
  400. Arguments:
  401. NpfsDeviceObject - Supplies our device object
  402. Irp - Supplies the being processed
  403. DeferredList - List of IRPS to be completed after we drop the locks
  404. Return Value:
  405. NTSTATUS - An apprropriate return status
  406. --*/
  407. {
  408. NTSTATUS Status;
  409. PIO_STACK_LOCATION IrpSp;
  410. ULONG OutputBufferLength;
  411. ULONG FsControlCode;
  412. NODE_TYPE_CODE NodeTypeCode;
  413. PCCB Ccb;
  414. PNONPAGED_CCB NonpagedCcb;
  415. NAMED_PIPE_END NamedPipeEnd;
  416. PFILE_PIPE_PEEK_BUFFER PeekBuffer;
  417. PDATA_QUEUE ReadQueue;
  418. READ_MODE ReadMode;
  419. ULONG LengthWritten;
  420. PUCHAR ReadBuffer;
  421. ULONG ReadLength;
  422. ULONG ReadRemaining;
  423. PDATA_ENTRY DataEntry;
  424. PAGED_CODE();
  425. //
  426. // Get the current Irp stack location
  427. //
  428. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  429. DebugTrace(+1, Dbg, "NpPeek...\n", 0);
  430. //
  431. // Extract the important fields from the IrpSp
  432. //
  433. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  434. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  435. DebugTrace( 0, Dbg, "OutputBufferLength = %08lx\n", OutputBufferLength);
  436. DebugTrace( 0, Dbg, "FsControlCode = %08lx\n", FsControlCode);
  437. //
  438. // Decode the file object to figure out who we are. The results
  439. // have a disconnected pipe if we get back an undefined ntc
  440. //
  441. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  442. NULL,
  443. &Ccb,
  444. &NamedPipeEnd )) == NTC_UNDEFINED) {
  445. DebugTrace(0, Dbg, "FileObject has been disconnected\n", 0);
  446. DebugTrace(-1, Dbg, "NpPeek -> STATUS_PIPE_DISCONNECTED\n", 0 );
  447. return STATUS_PIPE_DISCONNECTED;
  448. }
  449. //
  450. // Now make sure the node type code is for a ccb otherwise it is an
  451. // invalid parameter
  452. //
  453. if (NodeTypeCode != NPFS_NTC_CCB) {
  454. DebugTrace(0, Dbg, "FileObject is not for a ccb\n", 0);
  455. DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 );
  456. return STATUS_INVALID_PARAMETER;
  457. }
  458. NonpagedCcb = Ccb->NonpagedCcb;
  459. //
  460. // Reference the system buffer as a peek buffer and make sure it's
  461. // large enough
  462. //
  463. if (OutputBufferLength < (ULONG)FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0])) {
  464. DebugTrace(0, Dbg, "Output buffer is too small\n", 0);
  465. DebugTrace(-1, Dbg, "NpPeek -> STATUS_INVALID_PARAMETER\n", 0 );
  466. return STATUS_INVALID_PARAMETER;
  467. }
  468. PeekBuffer = Irp->AssociatedIrp.SystemBuffer;
  469. //
  470. // Now the data queue that we read from is based on the named pipe
  471. // end. The server reads from the inbound queue and the client reads
  472. // from the outbound queue
  473. //
  474. switch (NamedPipeEnd) {
  475. case FILE_PIPE_SERVER_END:
  476. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  477. //ReadMode = Ccb->ReadMode[ FILE_PIPE_SERVER_END ];
  478. break;
  479. case FILE_PIPE_CLIENT_END:
  480. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  481. //ReadMode = Ccb->ReadMode[ FILE_PIPE_CLIENT_END ];
  482. break;
  483. default:
  484. NpBugCheck( NamedPipeEnd, 0, 0 );
  485. }
  486. //
  487. // Our read mode is really based upon the pipe type and not the set
  488. // read mode for the pipe end.
  489. //
  490. if (Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) {
  491. ReadMode = FILE_PIPE_MESSAGE_MODE;
  492. } else {
  493. ReadMode = FILE_PIPE_BYTE_STREAM_MODE;
  494. }
  495. DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
  496. DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
  497. //
  498. // If the state of the pipe is not in the connected or closing
  499. // state then it is an invalid pipe state
  500. //
  501. if ((Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) &&
  502. (Ccb->NamedPipeState != FILE_PIPE_CLOSING_STATE)) {
  503. DebugTrace(0, Dbg, "pipe not connected or closing\n", 0);
  504. return STATUS_INVALID_PIPE_STATE;
  505. }
  506. //
  507. // If the state of the pipe is closing and the queue does
  508. // not contain any writers then we return eof
  509. //
  510. if ((Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) &&
  511. (!NpIsDataQueueWriters( ReadQueue ))) {
  512. DebugTrace(0, Dbg, "pipe closing and is empty\n", 0);
  513. return STATUS_PIPE_BROKEN;
  514. }
  515. //
  516. // Zero out the standard header part of the peek buffer and
  517. // set the length written to the amount we've just zeroed out
  518. //
  519. RtlZeroMemory( PeekBuffer, FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]) );
  520. LengthWritten = FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
  521. //
  522. // Set the named pipe state
  523. //
  524. PeekBuffer->NamedPipeState = Ccb->NamedPipeState;
  525. //
  526. // There is only data available if the read queue contains
  527. // write entries otherwise the rest of record is all zero.
  528. //
  529. if (NpIsDataQueueWriters( ReadQueue )) {
  530. //
  531. // Now find the first real entry in the read queue. The
  532. // first entry actually better be a real one.
  533. //
  534. DataEntry = NpGetNextDataQueueEntry( ReadQueue, NULL );
  535. ASSERT( (DataEntry->DataEntryType == Buffered) ||
  536. (DataEntry->DataEntryType == Unbuffered) );
  537. //
  538. // Indicate how many bytes are available to read
  539. //
  540. PeekBuffer->ReadDataAvailable = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
  541. //
  542. // The number of messages and message length is only filled
  543. // in for a message mode pipe
  544. //
  545. if (ReadMode == FILE_PIPE_MESSAGE_MODE) {
  546. PeekBuffer->NumberOfMessages = ReadQueue->EntriesInQueue;
  547. PeekBuffer->MessageLength = DataEntry->DataSize - ReadQueue->NextByteOffset;
  548. }
  549. //
  550. // Now we are ready to copy over the data from the read queue
  551. // into the peek buffer. First establish how much room we
  552. // have in the peek buffer and who much is remaining.
  553. //
  554. ReadBuffer = &PeekBuffer->Data[0];
  555. ReadLength = OutputBufferLength - FIELD_OFFSET(FILE_PIPE_PEEK_BUFFER, Data[0]);
  556. ReadRemaining = ReadLength;
  557. DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  558. DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
  559. //
  560. // Now read the data queue.
  561. //
  562. if ( ReadLength != 0 ) {
  563. IO_STATUS_BLOCK Iosb;
  564. Iosb = NpReadDataQueue( ReadQueue,
  565. TRUE,
  566. FALSE,
  567. ReadBuffer,
  568. ReadLength,
  569. ReadMode,
  570. Ccb,
  571. DeferredList );
  572. Status = Iosb.Status;
  573. LengthWritten += (ULONG)Iosb.Information;
  574. } else {
  575. if ( PeekBuffer->ReadDataAvailable == 0) {
  576. Status = STATUS_SUCCESS;
  577. } else {
  578. Status = STATUS_BUFFER_OVERFLOW;
  579. }
  580. }
  581. } else {
  582. Status = STATUS_SUCCESS;
  583. }
  584. //
  585. // Complete the request. The amount of information copied
  586. // is stored in length written
  587. //
  588. Irp->IoStatus.Information = LengthWritten;
  589. DebugTrace(-1, Dbg, "NpPeek -> %08lx\n", Status);
  590. return Status;
  591. }
  592. //
  593. // Local Support Routine
  594. //
  595. NTSTATUS
  596. NpQueryEvent (
  597. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  598. IN PIRP Irp
  599. )
  600. /*++
  601. Routine Description:
  602. This routine does the query event control function
  603. Arguments:
  604. NpfsDeviceObject - Supplies our device object
  605. Irp - Supplies the Irp specifying the function
  606. Return Value:
  607. NTSTATUS - An appropriate return status
  608. --*/
  609. {
  610. PIO_STACK_LOCATION IrpSp;
  611. ULONG InputBufferLength;
  612. ULONG OutputBufferLength;
  613. ULONG FsControlCode;
  614. PCCB Ccb;
  615. NAMED_PIPE_END NamedPipeEnd;
  616. HANDLE EventHandle;
  617. PFILE_PIPE_EVENT_BUFFER EventArray;
  618. PFILE_PIPE_EVENT_BUFFER EventBuffer;
  619. ULONG EventArrayMaximumCount;
  620. ULONG EventCount;
  621. PEPROCESS Process;
  622. PEVENT_TABLE_ENTRY Ete;
  623. PDATA_QUEUE ReadQueue;
  624. PDATA_QUEUE WriteQueue;
  625. PVOID RestartKey;
  626. PAGED_CODE();
  627. //
  628. // Get the current stack location
  629. //
  630. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  631. DebugTrace(+1, Dbg, "NpQueryEvent...\n", 0);
  632. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  633. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  634. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  635. //
  636. // Decode the file object to figure out who we are. If the result
  637. // is not a Vcb then its an invalid parameter
  638. //
  639. if (NpDecodeFileObject( IrpSp->FileObject,
  640. NULL,
  641. &Ccb,
  642. &NamedPipeEnd ) != NPFS_NTC_VCB) {
  643. DebugTrace(0, Dbg, "FileObject is not the named pipe driver\n", 0);
  644. return STATUS_INVALID_PARAMETER;
  645. }
  646. //
  647. // Reference the system buffer as a handle and make sure it's large
  648. // enough
  649. //
  650. if (InputBufferLength < sizeof(HANDLE)) {
  651. DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
  652. return STATUS_INVALID_PARAMETER;
  653. }
  654. EventHandle = *(PHANDLE)Irp->AssociatedIrp.SystemBuffer;
  655. //
  656. // Reference the system buffer as an output event buffer, and compute
  657. // how many event buffer records we can put in the buffer.
  658. //
  659. EventArray = Irp->AssociatedIrp.SystemBuffer;
  660. EventArrayMaximumCount = OutputBufferLength / sizeof(FILE_PIPE_EVENT_BUFFER);
  661. EventCount = 0;
  662. //
  663. // Get our current process pointer that we'll need for our search
  664. //
  665. Process = PsGetCurrentProcess();
  666. //
  667. // Now enumerate the event table entries in the event table
  668. //
  669. RestartKey = NULL;
  670. for (Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey);
  671. Ete != NULL;
  672. Ete = NpGetNextEventTableEntry( &NpVcb->EventTable, &RestartKey)) {
  673. //
  674. // Check if the event table entry matches the event handle
  675. // and the process
  676. //
  677. if ((Ete->EventHandle == EventHandle) &&
  678. (Ete->Process == Process)) {
  679. //
  680. // Now based on the named pipe end we treat the inbound/
  681. // outbound as a read/write queue.
  682. //
  683. NpAcquireExclusiveCcb(Ete->Ccb);
  684. switch (Ete->NamedPipeEnd) {
  685. case FILE_PIPE_CLIENT_END:
  686. ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  687. WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  688. break;
  689. case FILE_PIPE_SERVER_END:
  690. ReadQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  691. WriteQueue = &Ete->Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  692. break;
  693. default:
  694. NpBugCheck( Ete->NamedPipeEnd, 0, 0 );
  695. }
  696. //
  697. // Now if there is any data in the read queue to be read
  698. // we fill in the buffer
  699. //
  700. if (NpIsDataQueueWriters(ReadQueue)) {
  701. //
  702. // First make sure there is enough room in the
  703. // EventBuffer to hold another entry
  704. //
  705. if (EventCount >= EventArrayMaximumCount) {
  706. DebugTrace(0, Dbg, "The event buffer is full\n", 0);
  707. NpReleaseCcb(Ete->Ccb);
  708. break;
  709. }
  710. //
  711. // Reference the event buffer and increment the
  712. // counter
  713. //
  714. EventBuffer = &EventArray[EventCount];
  715. EventCount += 1;
  716. //
  717. // Fill in the event buffer entry
  718. //
  719. EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState;
  720. EventBuffer->EntryType = FILE_PIPE_READ_DATA;
  721. EventBuffer->ByteCount = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
  722. EventBuffer->KeyValue = Ete->KeyValue;
  723. EventBuffer->NumberRequests = ReadQueue->EntriesInQueue;
  724. }
  725. //
  726. // We'll always fill in a write space buffer. The amount
  727. // will either be bytes of write space available or
  728. // the quota of write space that we can use.
  729. //
  730. //
  731. // First make sure there is enough room in the
  732. // EventBuffer to hold another entry
  733. //
  734. if (EventCount >= EventArrayMaximumCount) {
  735. DebugTrace(0, Dbg, "The event buffer is full\n", 0);
  736. NpReleaseCcb(Ete->Ccb);
  737. break;
  738. }
  739. //
  740. // Reference the event buffer and increment the
  741. // counter
  742. //
  743. EventBuffer = &EventArray[EventCount];
  744. EventCount += 1;
  745. //
  746. // Fill in the event buffer entry
  747. //
  748. EventBuffer->NamedPipeState = Ete->Ccb->NamedPipeState;
  749. EventBuffer->EntryType = FILE_PIPE_WRITE_SPACE;
  750. EventBuffer->KeyValue = Ete->KeyValue;
  751. //
  752. // Now either we put in the write space available or
  753. // we put in the quota available
  754. //
  755. if (NpIsDataQueueReaders(WriteQueue)) {
  756. EventBuffer->ByteCount = WriteQueue->BytesInQueue - WriteQueue->NextByteOffset;
  757. EventBuffer->NumberRequests = WriteQueue->EntriesInQueue;
  758. } else {
  759. EventBuffer->ByteCount = WriteQueue->Quota - WriteQueue->QuotaUsed;
  760. EventBuffer->NumberRequests = 0;
  761. }
  762. NpReleaseCcb(Ete->Ccb);
  763. }
  764. }
  765. //
  766. // Set the information field to be the number of bytes of output
  767. // data we've fill into the system buffer
  768. //
  769. Irp->IoStatus.Information = EventCount * sizeof(FILE_PIPE_EVENT_BUFFER);
  770. DebugTrace(-1, Dbg, "NpQueryEvent -> STATUS_SUCCESS\n", 0);
  771. return STATUS_SUCCESS;
  772. }
  773. //
  774. // Local Support Routine
  775. //
  776. NTSTATUS
  777. NpTransceive (
  778. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  779. IN PIRP Irp,
  780. IN PLIST_ENTRY DeferredList
  781. )
  782. /*++
  783. Routine Description:
  784. This routine does the transceive named pipe control function
  785. Arguments:
  786. NpfsDeviceObject - Supplies our device object
  787. Irp - Supplies the being processed
  788. DeferredList - List of IRPs to complete after we drop locks
  789. Return Value:
  790. NTSTATUS - An apprropriate return status
  791. --*/
  792. {
  793. static IO_STATUS_BLOCK Iosb;
  794. NTSTATUS Status;
  795. PIO_STACK_LOCATION IrpSp;
  796. PETHREAD UserThread;
  797. PUCHAR WriteBuffer;
  798. ULONG WriteLength;
  799. PUCHAR ReadBuffer;
  800. ULONG ReadLength;
  801. NODE_TYPE_CODE NodeTypeCode;
  802. PCCB Ccb;
  803. PNONPAGED_CCB NonpagedCcb;
  804. NAMED_PIPE_END NamedPipeEnd;
  805. PDATA_QUEUE ReadQueue;
  806. PDATA_QUEUE WriteQueue;
  807. PEVENT_TABLE_ENTRY Event;
  808. READ_MODE ReadMode;
  809. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  810. ULONG WriteRemaining;
  811. PIRP WriteIrp;
  812. //
  813. // The following variable is used during abnormal unwind
  814. //
  815. PVOID UnwindStorage = NULL;
  816. PAGED_CODE();
  817. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  818. DebugTrace(+1, Dbg, "NpTransceive\n", 0);
  819. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  820. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  821. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  822. WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  823. WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  824. ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  825. ReadBuffer = Irp->UserBuffer;
  826. //
  827. // Now if the requestor mode is user mode we need to probe the buffers
  828. // We do now need to have an exception handler here because our top
  829. // level caller already has one that will complete the Irp with
  830. // the appropriate status if we access violate.
  831. //
  832. if (Irp->RequestorMode != KernelMode) {
  833. try {
  834. ProbeForRead( WriteBuffer, WriteLength, sizeof(UCHAR) );
  835. ProbeForWrite( ReadBuffer, ReadLength, sizeof(UCHAR) );
  836. } except(EXCEPTION_EXECUTE_HANDLER) {
  837. return GetExceptionCode ();
  838. }
  839. }
  840. //
  841. // Get the Ccb and figure out who we are, and make sure we're not
  842. // disconnected
  843. //
  844. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  845. NULL,
  846. &Ccb,
  847. &NamedPipeEnd )) == NTC_UNDEFINED) {
  848. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  849. DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
  850. return STATUS_PIPE_DISCONNECTED;
  851. }
  852. //
  853. // Now we only will allow transceive operations on the pipe and not a
  854. // directory or the device
  855. //
  856. if (NodeTypeCode != NPFS_NTC_CCB) {
  857. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  858. DebugTrace(-1, Dbg, "NpTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
  859. return STATUS_PIPE_DISCONNECTED;
  860. }
  861. NonpagedCcb = Ccb->NonpagedCcb;
  862. NpAcquireExclusiveCcb(Ccb);
  863. WriteIrp = NULL;
  864. try {
  865. //
  866. // Check that the pipe is in the connected state
  867. //
  868. if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
  869. DebugTrace(0, Dbg, "Pipe not connected\n", 0);
  870. try_return( Status = STATUS_INVALID_PIPE_STATE );
  871. }
  872. //
  873. // Figure out the read/write queue, read mode, and event based
  874. // on the end of the named pipe doing the transceive.
  875. //
  876. switch (NamedPipeEnd) {
  877. case FILE_PIPE_SERVER_END:
  878. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  879. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  880. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  881. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  882. break;
  883. case FILE_PIPE_CLIENT_END:
  884. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  885. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  886. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  887. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  888. break;
  889. default:
  890. NpBugCheck( NamedPipeEnd, 0, 0 );
  891. }
  892. //
  893. // We only allow a transceive on a message mode, full duplex pipe.
  894. //
  895. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  896. if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) ||
  897. (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
  898. DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
  899. try_return( Status = STATUS_INVALID_PIPE_STATE );
  900. }
  901. //
  902. // Check that the read queue is empty.
  903. //
  904. if (!NpIsDataQueueEmpty( ReadQueue )) {
  905. DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
  906. try_return( Status = STATUS_PIPE_BUSY );
  907. }
  908. //
  909. // Do the transceive write operation. We first try and push the data
  910. // from the write buffer into any waiting readers in the write queue
  911. // and if that succeeds then we can go on and do the read operation
  912. // otherwise we need to make a copy of irp and to enqueue as
  913. // a data entry into the write queue.
  914. //
  915. // Now we'll call our common write data queue routine to
  916. // transfer data out of our write buffer into the data queue.
  917. // If the result of the call is FALSE then we still have some
  918. // write data to put into the write queue.
  919. //
  920. UserThread = Irp->Tail.Overlay.Thread;
  921. Status = NpWriteDataQueue( WriteQueue,
  922. ReadMode,
  923. WriteBuffer,
  924. WriteLength,
  925. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  926. &WriteRemaining,
  927. Ccb,
  928. NamedPipeEnd,
  929. UserThread,
  930. DeferredList );
  931. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  932. PIO_STACK_LOCATION WriteIrpSp;
  933. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  934. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  935. //
  936. // We need to do some more write processing. So to handle
  937. // this case we'll allocate a new irp and set its system
  938. // buffer to be the remaining part of the write buffer
  939. //
  940. if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, TRUE )) == NULL) {
  941. try_return (Status = STATUS_INSUFFICIENT_RESOURCES);
  942. }
  943. IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
  944. WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
  945. if (WriteRemaining > 0) {
  946. WriteIrp->AssociatedIrp.SystemBuffer = NpAllocatePagedPoolWithQuota( WriteRemaining, 'wFpN' );
  947. if (WriteIrp->AssociatedIrp.SystemBuffer == NULL) {
  948. IoFreeIrp (WriteIrp);
  949. try_return (Status = STATUS_INSUFFICIENT_RESOURCES);
  950. }
  951. //
  952. // Safely do the copy
  953. //
  954. try {
  955. RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer,
  956. &WriteBuffer[ WriteLength - WriteRemaining ],
  957. WriteRemaining );
  958. } except(EXCEPTION_EXECUTE_HANDLER) {
  959. NpFreePool (WriteIrp->AssociatedIrp.SystemBuffer);
  960. IoFreeIrp (WriteIrp);
  961. try_return (Status = GetExceptionCode ());
  962. }
  963. } else {
  964. WriteIrp->AssociatedIrp.SystemBuffer = NULL;
  965. }
  966. //
  967. // Set the current stack location, and set in the amount we are
  968. // try to write.
  969. //
  970. WriteIrp->CurrentLocation -= 1;
  971. WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp;
  972. WriteIrp->Tail.Overlay.Thread = UserThread;
  973. WriteIrp->IoStatus.Information = WriteRemaining;
  974. WriteIrpSp->Parameters.Write.Length = WriteRemaining;
  975. WriteIrpSp->MajorFunction = IRP_MJ_WRITE;
  976. //
  977. // Set it up to do buffered I/O and deallocate the buffer
  978. // on completion.
  979. if (WriteRemaining > 0) {
  980. WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  981. }
  982. WriteIrp->UserIosb = &Iosb;
  983. //
  984. // Add this write request to the write queue
  985. //
  986. Status = NpAddDataQueueEntry( NamedPipeEnd,
  987. Ccb,
  988. WriteQueue,
  989. WriteEntries,
  990. Unbuffered,
  991. WriteRemaining,
  992. WriteIrp,
  993. NULL,
  994. 0);
  995. if (Status != STATUS_PENDING) {
  996. NpDeferredCompleteRequest (WriteIrp, Status, DeferredList);
  997. }
  998. }
  999. if (!NT_SUCCESS (Status)) {
  1000. try_return (NOTHING);
  1001. }
  1002. //
  1003. // And because we've done something we need to signal the
  1004. // other ends event
  1005. //
  1006. NpSignalEventTableEntry( Event );
  1007. //
  1008. // Do the transceive read operation. This is just like a
  1009. // buffered read.
  1010. //
  1011. // Now we know that the read queue is empty so we'll enqueue this
  1012. // Irp to the read queue and return status pending, also mark the
  1013. // irp pending
  1014. //
  1015. ASSERT( NpIsDataQueueEmpty( ReadQueue ));
  1016. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1017. Ccb,
  1018. ReadQueue,
  1019. ReadEntries,
  1020. Buffered,
  1021. ReadLength,
  1022. Irp,
  1023. NULL,
  1024. 0 );
  1025. if (!NT_SUCCESS (Status)) {
  1026. try_return (NOTHING);
  1027. }
  1028. //
  1029. // And because we've done something we need to signal the
  1030. // other ends event
  1031. //
  1032. NpSignalEventTableEntry( Event );
  1033. try_exit: NOTHING;
  1034. } finally {
  1035. NpReleaseCcb(Ccb);
  1036. }
  1037. DebugTrace(-1, Dbg, "NpTransceive -> %08lx\n", Status);
  1038. return Status;
  1039. }
  1040. //
  1041. // Local Support Routine
  1042. //
  1043. NTSTATUS
  1044. NpWaitForNamedPipe (
  1045. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1046. IN PIRP Irp
  1047. )
  1048. /*++
  1049. Routine Description:
  1050. This routine does the wait for named pipe control function
  1051. Arguments:
  1052. NpfsDeviceObject - Supplies our device object
  1053. Irp - Supplies the being processed
  1054. Return Value:
  1055. NTSTATUS - An apprropriate return status
  1056. --*/
  1057. {
  1058. NTSTATUS Status;
  1059. PIO_STACK_LOCATION IrpSp;
  1060. ULONG InputBufferLength;
  1061. ULONG FsControlCode;
  1062. PFCB Fcb;
  1063. PCCB Ccb;
  1064. PFILE_PIPE_WAIT_FOR_BUFFER WaitBuffer;
  1065. UNICODE_STRING Name;
  1066. PVOID LocalBuffer;
  1067. PLIST_ENTRY Links;
  1068. BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
  1069. UNICODE_STRING RemainingPart;
  1070. BOOLEAN Translated;
  1071. PAGED_CODE();
  1072. //
  1073. // Get the current stack location
  1074. //
  1075. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1076. DebugTrace(+1, Dbg, "NpWaitForNamedPipe...\n", 0);
  1077. //
  1078. // Extract the important fields from the IrpSp
  1079. //
  1080. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1081. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  1082. Name.Buffer = NULL;
  1083. LocalBuffer = NULL;
  1084. try {
  1085. //
  1086. // Decode the file object to figure out who we are. If the result
  1087. // is an error if the we weren't given a Vcb.
  1088. //
  1089. {
  1090. PCCB Ccb;
  1091. NAMED_PIPE_END NamedPipeEnd;
  1092. if (NpDecodeFileObject( IrpSp->FileObject,
  1093. NULL,
  1094. &Ccb,
  1095. &NamedPipeEnd ) != NPFS_NTC_ROOT_DCB) {
  1096. DebugTrace(0, Dbg, "File Object is not for the named pipe root directory\n", 0);
  1097. try_return( Status = STATUS_ILLEGAL_FUNCTION );
  1098. }
  1099. }
  1100. //
  1101. // Reference the system buffer as a wait for buffer and make
  1102. // sure it's large enough
  1103. //
  1104. if (InputBufferLength < sizeof(FILE_PIPE_WAIT_FOR_BUFFER)) {
  1105. DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
  1106. try_return( Status = STATUS_INVALID_PARAMETER );
  1107. }
  1108. WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
  1109. //
  1110. // Check for an invalid buffer. The Name Length cannot be greater than
  1111. // MAXUSHORT minus the backslash otherwise it will overflow the buffer.
  1112. // We don't need to check for less than 0 because it is unsigned.
  1113. //
  1114. if ((WaitBuffer->NameLength > (MAXUSHORT - 2)) ||
  1115. (FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + WaitBuffer->NameLength > InputBufferLength)) {
  1116. DebugTrace(0, Dbg, "System buffer size or name length is too small\n", 0);
  1117. try_return( Status = STATUS_INVALID_PARAMETER );
  1118. }
  1119. //
  1120. // Set up the local variable Name to be the name we're looking
  1121. // for
  1122. //
  1123. Name.Length = (USHORT)(WaitBuffer->NameLength + 2);
  1124. Name.Buffer = LocalBuffer = NpAllocatePagedPool( Name.Length, 'WFpN' );
  1125. if (LocalBuffer == NULL) {
  1126. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  1127. }
  1128. Name.Buffer[0] = L'\\';
  1129. RtlCopyMemory( &Name.Buffer[1],
  1130. &WaitBuffer->Name[0],
  1131. WaitBuffer->NameLength );
  1132. //
  1133. // If the name is an alias, translate it
  1134. //
  1135. Status = NpTranslateAlias( &Name );
  1136. if ( !NT_SUCCESS(Status) ) {
  1137. try_return( NOTHING );
  1138. }
  1139. //
  1140. // Now check to see if we can find a named pipe with the right
  1141. // name
  1142. //
  1143. Fcb = NpFindPrefix( &Name, CaseInsensitive, &RemainingPart );
  1144. //
  1145. // If the Fcb is null then we can't wait for it, Also if the
  1146. // Fcb is not an Fcb then we also have nothing to wait for
  1147. //
  1148. if (NodeType(Fcb) != NPFS_NTC_FCB) {
  1149. DebugTrace(0, Dbg, "Bad nonexistent named pipe name", 0);
  1150. try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  1151. }
  1152. //
  1153. // If translated then Name.Buffer would point to the translated buffer
  1154. //
  1155. Translated = (Name.Buffer != LocalBuffer);
  1156. //
  1157. // Now we need to search to see if we find a ccb already in the
  1158. // listening state
  1159. // First try and find a ccb that is in the listening state
  1160. // If we exit the loop with ccb null then we haven't found
  1161. // one
  1162. //
  1163. Ccb = NULL;
  1164. for (Links = Fcb->Specific.Fcb.CcbQueue.Flink;
  1165. Links != &Fcb->Specific.Fcb.CcbQueue;
  1166. Links = Links->Flink) {
  1167. Ccb = CONTAINING_RECORD( Links, CCB, CcbLinks );
  1168. if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
  1169. break;
  1170. }
  1171. Ccb = NULL;
  1172. }
  1173. //
  1174. // Check if we found one
  1175. //
  1176. if (Ccb != NULL) {
  1177. DebugTrace(0, Dbg, "Found a ccb in listening state\n", 0);
  1178. try_return( Status = STATUS_SUCCESS );
  1179. }
  1180. //
  1181. // We weren't able to find one so we need to add a new waiter
  1182. //
  1183. Status = NpAddWaiter( &NpVcb->WaitQueue,
  1184. Fcb->Specific.Fcb.DefaultTimeOut,
  1185. Irp,
  1186. Translated ? &Name : NULL);
  1187. try_exit: NOTHING;
  1188. } finally {
  1189. if (LocalBuffer != NULL) {
  1190. NpFreePool( LocalBuffer );
  1191. }
  1192. }
  1193. DebugTrace(-1, Dbg, "NpWaitForNamedPipe -> %08lx\n", Status);
  1194. return Status;
  1195. }
  1196. //
  1197. // Local Support Routine
  1198. //
  1199. NTSTATUS
  1200. NpImpersonate (
  1201. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1202. IN PIRP Irp
  1203. )
  1204. /*++
  1205. Routine Description:
  1206. This routine does the impersonate of the named pipe
  1207. Arguments:
  1208. NpfsDeviceObject - Supplies our device object
  1209. Irp - Supplies the being processed
  1210. Return Value:
  1211. NTSTATUS - An apprropriate return status
  1212. --*/
  1213. {
  1214. NTSTATUS Status;
  1215. PIO_STACK_LOCATION IrpSp;
  1216. PCCB Ccb;
  1217. NAMED_PIPE_END NamedPipeEnd;
  1218. UNREFERENCED_PARAMETER( NpfsDeviceObject );
  1219. PAGED_CODE();
  1220. //
  1221. // Get the current stack location
  1222. //
  1223. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1224. DebugTrace(+1, Dbg, "NpImpersonate...\n", 0);
  1225. //
  1226. // Decode the file object to figure out who we are. If the result
  1227. // is an error if the we weren't given a Vcb.
  1228. //
  1229. if (NpDecodeFileObject( IrpSp->FileObject,
  1230. NULL,
  1231. &Ccb,
  1232. &NamedPipeEnd ) != NPFS_NTC_CCB) {
  1233. DebugTrace(0, Dbg, "File Object is not a named pipe\n", 0);
  1234. DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  1235. return STATUS_ILLEGAL_FUNCTION;
  1236. }
  1237. //
  1238. // Make sure that we are the server end and not the client end
  1239. //
  1240. if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
  1241. DebugTrace(0, Dbg, "Not the server end\n", 0);
  1242. DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  1243. return STATUS_ILLEGAL_FUNCTION;
  1244. }
  1245. //
  1246. // set up the impersonation
  1247. //
  1248. Status = NpImpersonateClientContext( Ccb );
  1249. DebugTrace(-1, Dbg, "NpImpersonate -> %08lx\n", Status);
  1250. return Status;
  1251. }
  1252. //
  1253. // Local Support Routine
  1254. //
  1255. NTSTATUS
  1256. NpInternalRead (
  1257. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1258. IN PIRP Irp,
  1259. IN BOOLEAN ReadOverflowOperation,
  1260. IN PLIST_ENTRY DeferredList
  1261. )
  1262. /*++
  1263. Routine Description:
  1264. This routine does the unbuffered read named pipe control function
  1265. Arguments:
  1266. NpfsDeviceObject - Supplies our device object
  1267. Irp - Supplies the being processed
  1268. ReadOverflowOperation - Used to indicate if the read being processed is a read overflow
  1269. operation.
  1270. DeferredList - List of IRP's to be completed later after we drop the locks
  1271. Return Value:
  1272. NTSTATUS - An apprropriate return status
  1273. --*/
  1274. {
  1275. NTSTATUS Status;
  1276. PIO_STACK_LOCATION IrpSp;
  1277. NODE_TYPE_CODE NodeTypeCode;
  1278. PCCB Ccb;
  1279. PNONPAGED_CCB NonpagedCcb;
  1280. NAMED_PIPE_END NamedPipeEnd;
  1281. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1282. PIRP ReadIrp;
  1283. PUCHAR ReadBuffer;
  1284. ULONG ReadLength;
  1285. ULONG ReadRemaining;
  1286. READ_MODE ReadMode;
  1287. COMPLETION_MODE CompletionMode;
  1288. PDATA_QUEUE ReadQueue;
  1289. PEVENT_TABLE_ENTRY Event;
  1290. PAGED_CODE();
  1291. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1292. DebugTrace(+1, Dbg, "NpInternalRead\n", 0);
  1293. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1294. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1295. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1296. //
  1297. // Get the Ccb and figure out who we are, and make sure we're not
  1298. // disconnected
  1299. //
  1300. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1301. NULL,
  1302. &Ccb,
  1303. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1304. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1305. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1306. return STATUS_PIPE_DISCONNECTED;
  1307. }
  1308. //
  1309. // Now we only will allow Read operations on the pipe and not a directory
  1310. // or the device
  1311. //
  1312. if (NodeTypeCode != NPFS_NTC_CCB) {
  1313. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1314. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
  1315. return STATUS_INVALID_PARAMETER;
  1316. }
  1317. NonpagedCcb = Ccb->NonpagedCcb;
  1318. NpAcquireExclusiveCcb(Ccb);
  1319. //
  1320. // Check if the pipe is not in the connected state.
  1321. //
  1322. switch (Ccb->NamedPipeState) {
  1323. case FILE_PIPE_DISCONNECTED_STATE:
  1324. DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
  1325. NpReleaseCcb(Ccb);
  1326. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1327. return STATUS_PIPE_DISCONNECTED;
  1328. case FILE_PIPE_LISTENING_STATE:
  1329. DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
  1330. NpReleaseCcb(Ccb);
  1331. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_LISTENING\n", 0 );
  1332. return STATUS_PIPE_LISTENING;
  1333. case FILE_PIPE_CONNECTED_STATE:
  1334. case FILE_PIPE_CLOSING_STATE:
  1335. break;
  1336. default:
  1337. DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
  1338. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  1339. }
  1340. //
  1341. // We only allow a read by the server on a non outbound only pipe
  1342. // and by the client on a non inbound only pipe
  1343. //
  1344. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1345. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  1346. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
  1347. ||
  1348. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  1349. (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
  1350. DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
  1351. NpReleaseCcb(Ccb);
  1352. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
  1353. return STATUS_INVALID_PARAMETER;
  1354. }
  1355. //
  1356. // Reference our input parameters to make things easier, and
  1357. // initialize our main variables that describe the Read command
  1358. //
  1359. ReadIrp = Irp;
  1360. ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
  1361. ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1362. ReadRemaining = ReadLength;
  1363. ReadMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].ReadMode;
  1364. CompletionMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].CompletionMode;
  1365. if (ReadOverflowOperation == TRUE && ReadMode != FILE_PIPE_MESSAGE_MODE) {
  1366. NpReleaseCcb(Ccb);
  1367. return STATUS_INVALID_READ_MODE;
  1368. }
  1369. //
  1370. // Now the data queue that we read from into and the event that we signal
  1371. // are based on the named pipe end. The server read from the inbound
  1372. // queue and signals the client event. The client does just the
  1373. // opposite.
  1374. //
  1375. switch (NamedPipeEnd) {
  1376. case FILE_PIPE_SERVER_END:
  1377. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1378. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1379. break;
  1380. case FILE_PIPE_CLIENT_END:
  1381. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1382. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1383. break;
  1384. default:
  1385. NpBugCheck( NamedPipeEnd, 0, 0 );
  1386. }
  1387. DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  1388. DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
  1389. DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
  1390. DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode);
  1391. DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
  1392. DebugTrace(0, Dbg, "Event = %08lx\n", Event);
  1393. //
  1394. // if the read queue does not contain any write entries
  1395. // then we either need to enqueue this operation or
  1396. // fail immediately
  1397. //
  1398. if (!NpIsDataQueueWriters( ReadQueue )) {
  1399. //
  1400. // Check if the other end of the pipe is closing, and if
  1401. // so then we complete it with end of file.
  1402. // Otherwise check to see if we should enqueue the irp
  1403. // or complete the operation and tell the user the pipe is empty.
  1404. //
  1405. if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
  1406. DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
  1407. Status = STATUS_PIPE_BROKEN;
  1408. } else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
  1409. DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
  1410. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1411. Ccb,
  1412. ReadQueue,
  1413. ReadEntries,
  1414. Unbuffered,
  1415. ReadLength,
  1416. ReadIrp,
  1417. NULL,
  1418. 0 );
  1419. } else {
  1420. DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
  1421. Status = STATUS_PIPE_EMPTY;
  1422. }
  1423. } else {
  1424. //
  1425. // otherwise there we have a read irp against a read queue
  1426. // that contains one or more write entries.
  1427. //
  1428. ReadIrp->IoStatus = NpReadDataQueue( ReadQueue,
  1429. FALSE,
  1430. ReadOverflowOperation,
  1431. ReadBuffer,
  1432. ReadLength,
  1433. ReadMode,
  1434. Ccb,
  1435. DeferredList );
  1436. Status = ReadIrp->IoStatus.Status;
  1437. //
  1438. // Now set the remaining byte count in the allocation size of
  1439. // the Irp.
  1440. //
  1441. ReadIrp->Overlay.AllocationSize.QuadPart = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
  1442. //
  1443. // Finish up the read irp.
  1444. //
  1445. }
  1446. //
  1447. // And because we've done something we need to signal the
  1448. // other ends event
  1449. //
  1450. NpSignalEventTableEntry( Event );
  1451. NpReleaseCcb(Ccb);
  1452. DebugTrace(-1, Dbg, "NpInternalRead -> %08lx\n", Status);
  1453. return Status;
  1454. }
  1455. //
  1456. // Local Support Routine
  1457. //
  1458. NTSTATUS
  1459. NpInternalWrite (
  1460. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1461. IN PIRP Irp,
  1462. IN PLIST_ENTRY DeferredList
  1463. )
  1464. /*++
  1465. Routine Description:
  1466. This routine does the unbuffered write named pipe control function
  1467. Arguments:
  1468. NpfsDeviceObject - Supplies our device object
  1469. Irp - Supplies the being processed
  1470. Return Value:
  1471. NTSTATUS - An apprropriate return status
  1472. --*/
  1473. {
  1474. NTSTATUS Status;
  1475. PIO_STACK_LOCATION IrpSp;
  1476. PETHREAD UserThread;
  1477. NODE_TYPE_CODE NodeTypeCode;
  1478. PCCB Ccb;
  1479. PNONPAGED_CCB NonpagedCcb;
  1480. NAMED_PIPE_END NamedPipeEnd;
  1481. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1482. PIRP WriteIrp;
  1483. PUCHAR WriteBuffer;
  1484. ULONG WriteLength;
  1485. ULONG WriteRemaining;
  1486. PDATA_QUEUE WriteQueue;
  1487. PEVENT_TABLE_ENTRY Event;
  1488. READ_MODE ReadMode;
  1489. PAGED_CODE();
  1490. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1491. DebugTrace(+1, Dbg, "NpInternalWrite\n", 0);
  1492. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1493. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1494. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1495. //
  1496. // This is a FSCTL path being used as a write. Make sure we can set the .Information field to the number
  1497. // of bytes written.
  1498. //
  1499. NpConvertFsctlToWrite (Irp);
  1500. //
  1501. // Get the Ccb and figure out who we are, and make sure we're not
  1502. // disconnected
  1503. //
  1504. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1505. NULL,
  1506. &Ccb,
  1507. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1508. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1509. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1510. return STATUS_PIPE_DISCONNECTED;
  1511. }
  1512. //
  1513. // Now we only will allow write operations on the pipe and not a directory
  1514. // or the device
  1515. //
  1516. if (NodeTypeCode != NPFS_NTC_CCB) {
  1517. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1518. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
  1519. return STATUS_PIPE_DISCONNECTED;
  1520. }
  1521. NonpagedCcb = Ccb->NonpagedCcb;
  1522. NpAcquireExclusiveCcb(Ccb);
  1523. //
  1524. // We only allow a write by the server on a non inbound only pipe
  1525. // and by the client on a non outbound only pipe
  1526. //
  1527. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1528. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  1529. (NamedPipeConfiguration == FILE_PIPE_INBOUND))
  1530. ||
  1531. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  1532. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
  1533. DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
  1534. NpReleaseCcb(Ccb);
  1535. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
  1536. return STATUS_PIPE_DISCONNECTED;
  1537. }
  1538. //
  1539. // Reference our input parameters to make things easier, and
  1540. // initialize our main variables that describe the write command
  1541. //
  1542. WriteIrp = Irp;
  1543. WriteBuffer = Irp->AssociatedIrp.SystemBuffer;
  1544. WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1545. //
  1546. // Set up the amount of data we will have written by the time this
  1547. // irp gets completed
  1548. //
  1549. WriteIrp->IoStatus.Information = WriteLength;
  1550. //
  1551. // Now the data queue that we write into and the event that we signal
  1552. // are based on the named pipe end. The server writes to the outbound
  1553. // queue and signals the client event. The client does just the
  1554. // opposite. We also need to figure out the read mode for the opposite
  1555. // end of the pipe.
  1556. //
  1557. switch (NamedPipeEnd) {
  1558. case FILE_PIPE_SERVER_END:
  1559. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1560. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1561. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  1562. break;
  1563. case FILE_PIPE_CLIENT_END:
  1564. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1565. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1566. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  1567. break;
  1568. default:
  1569. NpBugCheck( NamedPipeEnd, 0, 0 );
  1570. }
  1571. //
  1572. // Check if the pipe is not in the connected state.
  1573. //
  1574. switch (Ccb->NamedPipeState) {
  1575. case FILE_PIPE_DISCONNECTED_STATE:
  1576. DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
  1577. NpReleaseCcb(Ccb);
  1578. return STATUS_PIPE_DISCONNECTED;
  1579. case FILE_PIPE_LISTENING_STATE:
  1580. DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
  1581. NpReleaseCcb(Ccb);
  1582. return STATUS_PIPE_LISTENING;
  1583. case FILE_PIPE_CONNECTED_STATE:
  1584. break;
  1585. case FILE_PIPE_CLOSING_STATE:
  1586. DebugTrace(0, Dbg, "Pipe in closing state\n", 0);
  1587. NpReleaseCcb(Ccb);
  1588. return STATUS_PIPE_CLOSING;
  1589. default:
  1590. DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
  1591. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  1592. }
  1593. //
  1594. // Check if this is a message type pipe and the operation type is complete
  1595. // operation, If so then we also check that the queued reads is enough to
  1596. // complete the message otherwise we need to abort the write irp immediately.
  1597. //
  1598. if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) &&
  1599. (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
  1600. //
  1601. // If the pipe contains readers and amount to read is less than the write
  1602. // length then we cannot do it the write.
  1603. // Or if pipe does not contain reads then we also cannot do the write.
  1604. //
  1605. if ((NpIsDataQueueReaders( WriteQueue ) &&
  1606. (WriteQueue->BytesInQueue < WriteLength))
  1607. ||
  1608. (!NpIsDataQueueReaders( WriteQueue ))) {
  1609. DebugTrace(0, Dbg, "Cannot complete the message without blocking\n", 0);
  1610. NpReleaseCcb(Ccb);
  1611. Irp->IoStatus.Information = 0;
  1612. return STATUS_SUCCESS;
  1613. }
  1614. }
  1615. //
  1616. // Now we'll call our common write data queue routine to
  1617. // transfer data out of our write buffer into the data queue.
  1618. // If the result of the call is FALSE then we still have some
  1619. // write data to put into the write queue.
  1620. //
  1621. UserThread = Irp->Tail.Overlay.Thread;
  1622. Status = NpWriteDataQueue( WriteQueue,
  1623. ReadMode,
  1624. WriteBuffer,
  1625. WriteLength,
  1626. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  1627. &WriteRemaining,
  1628. Ccb,
  1629. NamedPipeEnd,
  1630. UserThread,
  1631. DeferredList );
  1632. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1633. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  1634. //
  1635. // Check if the operation is not to block and if so then we
  1636. // will complete the operation now with what we're written, if what is
  1637. // left will not fit in the quota for the file
  1638. //
  1639. if (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  1640. DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
  1641. Irp->IoStatus.Information = WriteLength - WriteRemaining;
  1642. Status = STATUS_SUCCESS;
  1643. } else {
  1644. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  1645. //
  1646. // Add this write request to the write queue
  1647. //
  1648. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1649. Ccb,
  1650. WriteQueue,
  1651. WriteEntries,
  1652. Unbuffered,
  1653. WriteLength,
  1654. Irp,
  1655. NULL,
  1656. WriteLength - WriteRemaining);
  1657. }
  1658. } else {
  1659. DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
  1660. //
  1661. // The write irp is finished so we can complete it now
  1662. //
  1663. }
  1664. //
  1665. // And because we've done something we need to signal the
  1666. // other ends event
  1667. //
  1668. NpSignalEventTableEntry( Event );
  1669. NpReleaseCcb(Ccb);
  1670. DebugTrace(-1, Dbg, "NpInternalWrite -> %08lx\n", Status);
  1671. return Status;
  1672. }
  1673. //
  1674. // Local Support Routine
  1675. //
  1676. NTSTATUS
  1677. NpInternalTransceive (
  1678. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1679. IN PIRP Irp,
  1680. IN PLIST_ENTRY DeferredList
  1681. )
  1682. /*++
  1683. Routine Description:
  1684. This routine does the internal (i.e., unbuffered) transceive named pipe
  1685. control function
  1686. Arguments:
  1687. NpfsDeviceObject - Supplies our device object
  1688. Irp - Supplies the being processed
  1689. DeferredList - List of IRP's to be completed once we drop our locks.
  1690. Return Value:
  1691. NTSTATUS - An apprropriate return status
  1692. --*/
  1693. {
  1694. static IO_STATUS_BLOCK Iosb;
  1695. NTSTATUS Status;
  1696. PIO_STACK_LOCATION IrpSp;
  1697. PETHREAD UserThread;
  1698. PUCHAR WriteBuffer;
  1699. ULONG WriteLength;
  1700. PUCHAR ReadBuffer;
  1701. ULONG ReadLength;
  1702. NODE_TYPE_CODE NodeTypeCode;
  1703. PCCB Ccb;
  1704. PNONPAGED_CCB NonpagedCcb;
  1705. NAMED_PIPE_END NamedPipeEnd;
  1706. PDATA_QUEUE ReadQueue;
  1707. PDATA_QUEUE WriteQueue;
  1708. PEVENT_TABLE_ENTRY Event;
  1709. READ_MODE ReadMode;
  1710. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1711. ULONG WriteRemaining;
  1712. PIRP WriteIrp;
  1713. //
  1714. // The following variable is used for abnormal unwind
  1715. //
  1716. PVOID UnwindStorage = NULL;
  1717. PAGED_CODE();
  1718. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1719. DebugTrace(+1, Dbg, "NpInternalTransceive\n", 0);
  1720. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1721. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1722. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1723. WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1724. WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  1725. ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1726. ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
  1727. //
  1728. // Get the Ccb and figure out who we are, and make sure we're not
  1729. // disconnected
  1730. //
  1731. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1732. NULL,
  1733. &Ccb,
  1734. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1735. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1736. DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1737. return STATUS_PIPE_DISCONNECTED;
  1738. }
  1739. //
  1740. // Now we only will allow transceive operations on the pipe and not a
  1741. // directory or the device
  1742. //
  1743. if (NodeTypeCode != NPFS_NTC_CCB) {
  1744. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1745. DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_INVALID_PARAMETER\n", 0 );
  1746. return STATUS_INVALID_PARAMETER;
  1747. }
  1748. NonpagedCcb = Ccb->NonpagedCcb;
  1749. WriteIrp = NULL;
  1750. NpAcquireExclusiveCcb(Ccb);
  1751. try {
  1752. //
  1753. // Check that the pipe is in the connected state
  1754. //
  1755. if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
  1756. DebugTrace(0, Dbg, "Pipe not connected\n", 0);
  1757. try_return( Status = STATUS_INVALID_PIPE_STATE );
  1758. }
  1759. //
  1760. // Figure out the read/write queue, read mode, and event based
  1761. // on the end of the named pipe doing the transceive.
  1762. //
  1763. switch (NamedPipeEnd) {
  1764. case FILE_PIPE_SERVER_END:
  1765. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1766. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1767. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1768. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  1769. break;
  1770. case FILE_PIPE_CLIENT_END:
  1771. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1772. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1773. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1774. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  1775. break;
  1776. default:
  1777. NpBugCheck( NamedPipeEnd, 0, 0 );
  1778. }
  1779. //
  1780. // We only allow a transceive on a message mode, full duplex pipe.
  1781. //
  1782. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1783. if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) ||
  1784. (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
  1785. DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
  1786. try_return( Status = STATUS_INVALID_READ_MODE );
  1787. }
  1788. //
  1789. // Check that the read queue is empty.
  1790. //
  1791. if (!NpIsDataQueueEmpty( ReadQueue )) {
  1792. DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
  1793. try_return( Status = STATUS_PIPE_BUSY );
  1794. }
  1795. //
  1796. // Do the transceive write operation. We first try and push the data
  1797. // from the write buffer into any waiting readers in the write queue
  1798. // and if that succeeds then we can go on and do the read operation
  1799. // otherwise we need to make a copy of irp and to enqueue as
  1800. // a data entry into the write queue.
  1801. //
  1802. // Now we'll call our common write data queue routine to
  1803. // transfer data out of our write buffer into the data queue.
  1804. // If the result of the call is FALSE then we still have some
  1805. // write data to put into the write queue.
  1806. //
  1807. UserThread = Irp->Tail.Overlay.Thread;
  1808. Status = NpWriteDataQueue( WriteQueue,
  1809. ReadMode,
  1810. WriteBuffer,
  1811. WriteLength,
  1812. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  1813. &WriteRemaining,
  1814. Ccb,
  1815. NamedPipeEnd,
  1816. UserThread,
  1817. DeferredList );
  1818. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1819. PIO_STACK_LOCATION WriteIrpSp;
  1820. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  1821. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  1822. //
  1823. // We need to do some more write processing. So to handle
  1824. // this case we'll allocate a new irp and set its system
  1825. // buffer to be the remaining part of the write buffer
  1826. //
  1827. if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, TRUE )) == NULL) {
  1828. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  1829. }
  1830. IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
  1831. WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
  1832. if (WriteRemaining > 0) {
  1833. WriteIrp->AssociatedIrp.SystemBuffer = NpAllocatePagedPoolWithQuota( WriteRemaining, 'wFpN' );
  1834. if (WriteIrp->AssociatedIrp.SystemBuffer == NULL) {
  1835. IoFreeIrp (WriteIrp);
  1836. try_return (Status = STATUS_INSUFFICIENT_RESOURCES);
  1837. }
  1838. //
  1839. // Safely do the copy
  1840. //
  1841. try {
  1842. RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer,
  1843. &WriteBuffer[ WriteLength - WriteRemaining ],
  1844. WriteRemaining );
  1845. WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  1846. } except(EXCEPTION_EXECUTE_HANDLER) {
  1847. NpFreePool (WriteIrp->AssociatedIrp.SystemBuffer);
  1848. IoFreeIrp (WriteIrp);
  1849. try_return (Status = GetExceptionCode ());
  1850. }
  1851. } else {
  1852. WriteIrp->AssociatedIrp.SystemBuffer = NULL;
  1853. }
  1854. //
  1855. // Set the current stack location
  1856. //
  1857. WriteIrp->CurrentLocation -= 1;
  1858. WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp;
  1859. WriteIrp->Tail.Overlay.Thread = UserThread;
  1860. WriteIrpSp->MajorFunction = IRP_MJ_WRITE;
  1861. WriteIrp->UserIosb = &Iosb;
  1862. //
  1863. // Add this write request to the write queue
  1864. //
  1865. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1866. Ccb,
  1867. WriteQueue,
  1868. WriteEntries,
  1869. Unbuffered,
  1870. WriteRemaining,
  1871. WriteIrp,
  1872. NULL,
  1873. 0 );
  1874. if (Status != STATUS_PENDING) {
  1875. NpDeferredCompleteRequest (WriteIrp, Status, DeferredList);
  1876. }
  1877. }
  1878. if (!NT_SUCCESS (Status)) {
  1879. try_return (NOTHING)
  1880. }
  1881. //
  1882. // And because we've done something we need to signal the
  1883. // other ends event
  1884. //
  1885. NpSignalEventTableEntry( Event );
  1886. //
  1887. // Do the transceive read operation. This is just like an
  1888. // unbuffered read.
  1889. //
  1890. // Now we know that the read queue is empty so we'll enqueue this
  1891. // Irp to the read queue and return status pending, also mark the
  1892. // irp pending
  1893. //
  1894. ASSERT( NpIsDataQueueEmpty( ReadQueue ));
  1895. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1896. Ccb,
  1897. ReadQueue,
  1898. ReadEntries,
  1899. Unbuffered,
  1900. ReadLength,
  1901. Irp,
  1902. NULL,
  1903. 0 );
  1904. if (!NT_SUCCESS (Status)) {
  1905. try_return (Status);
  1906. }
  1907. //
  1908. // And because we've done something we need to signal the
  1909. // other ends event
  1910. //
  1911. NpSignalEventTableEntry( Event );
  1912. try_exit: NOTHING;
  1913. } finally {
  1914. NpReleaseCcb(Ccb);
  1915. }
  1916. DebugTrace(-1, Dbg, "NpInternalTransceive -> %08lx\n", Status);
  1917. return Status;
  1918. }
  1919. //
  1920. // Internal support routine
  1921. //
  1922. NTSTATUS
  1923. NpQueryClientProcess (
  1924. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1925. IN PIRP Irp
  1926. )
  1927. /*++
  1928. Routine Description:
  1929. This routine does the query client process named pipe control function
  1930. The output buffer may be either a FILE_PIPE_CLIENT_PROCESS_BUFFER or a
  1931. FILE_PIPE_CLIENT_PROCESS_BUFFER_EX.
  1932. Arguments:
  1933. NpfsDeviceObject - Supplies our device object
  1934. Irp - Supplies the being processed
  1935. Return Value:
  1936. NTSTATUS - An apprropriate return status
  1937. --*/
  1938. {
  1939. PIO_STACK_LOCATION IrpSp;
  1940. ULONG OutputBufferLength;
  1941. PCCB Ccb;
  1942. PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer;
  1943. PCLIENT_INFO ClientInfo;
  1944. CLIENT_INFO NullInfo = {0};
  1945. PAGED_CODE();
  1946. //
  1947. // Get the current stack location
  1948. //
  1949. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1950. DebugTrace(+1, Dbg, "NpQueryClientProcess\n", 0);
  1951. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1952. //
  1953. // Decode the file object to figure out who we are.
  1954. //
  1955. if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
  1956. DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
  1957. return STATUS_PIPE_DISCONNECTED;
  1958. }
  1959. //
  1960. // Make sure the output buffer is large enough
  1961. //
  1962. if (OutputBufferLength < sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER)) {
  1963. DebugTrace(0, Dbg, "Output System buffer size is too small\n", 0);
  1964. return STATUS_INVALID_PARAMETER;
  1965. }
  1966. NpAcquireExclusiveCcb(Ccb);
  1967. //
  1968. // Copy over the client process ID
  1969. //
  1970. ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
  1971. ClientProcessBuffer->ClientProcess = Ccb->ClientProcess;
  1972. ClientInfo = Ccb->ClientInfo;
  1973. if (ClientInfo == NULL) {
  1974. ClientInfo = &NullInfo;
  1975. }
  1976. ClientProcessBuffer->ClientSession = ClientInfo->ClientSession;
  1977. //
  1978. // Return extended client information if so requested
  1979. // Set the information field to the size of the client process
  1980. // buffer
  1981. //
  1982. if (OutputBufferLength >= sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
  1983. ClientProcessBuffer->ClientComputerNameLength =
  1984. ClientInfo->ClientComputerNameLength;
  1985. RtlCopyMemory( ClientProcessBuffer->ClientComputerBuffer,
  1986. ClientInfo->ClientComputerBuffer,
  1987. ClientInfo->ClientComputerNameLength );
  1988. ClientProcessBuffer->ClientComputerBuffer[
  1989. ClientProcessBuffer->ClientComputerNameLength / sizeof(WCHAR)] = L'\0';
  1990. Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX);
  1991. } else {
  1992. Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER);
  1993. }
  1994. NpReleaseCcb(Ccb);
  1995. DebugTrace(-1, Dbg, "NpQueryClientProcess -> STATUS_SUCCESS\n", 0);
  1996. return STATUS_SUCCESS;
  1997. }
  1998. //
  1999. // Internal support routine
  2000. //
  2001. NTSTATUS
  2002. NpSetClientProcess (
  2003. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  2004. IN PIRP Irp
  2005. )
  2006. /*++
  2007. Routine Description:
  2008. This routine does the set client process named pipe control function
  2009. Note that we expect a FILE_PIPE_CLIENT_PROCESS_BUFFER_EX structure to be
  2010. passed in to us.
  2011. Arguments:
  2012. NpfsDeviceObject - Supplies our device object
  2013. Irp - Supplies the being processed
  2014. Return Value:
  2015. NTSTATUS - An apprropriate return status
  2016. --*/
  2017. {
  2018. PIO_STACK_LOCATION IrpSp;
  2019. PCLIENT_INFO ClientInfo;
  2020. ULONG InputBufferLength;
  2021. PCCB Ccb;
  2022. PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer;
  2023. PAGED_CODE();
  2024. //
  2025. // Get the current stack location
  2026. //
  2027. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2028. DebugTrace(+1, Dbg, "NpSetClientProcess\n", 0);
  2029. //
  2030. // Only allow kernel callers for this API as RPC relies on this info being solid.
  2031. //
  2032. if (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL) {
  2033. return STATUS_ACCESS_DENIED;
  2034. }
  2035. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  2036. //
  2037. // Decode the file object to figure out who we are.
  2038. //
  2039. if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
  2040. DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
  2041. return STATUS_PIPE_DISCONNECTED;
  2042. }
  2043. //
  2044. // Make sure the input buffer is large enough
  2045. //
  2046. if (InputBufferLength != sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
  2047. DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
  2048. return STATUS_INVALID_PARAMETER;
  2049. }
  2050. ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
  2051. //
  2052. // Make verify input length is valid
  2053. //
  2054. if (ClientProcessBuffer->ClientComputerNameLength >
  2055. FILE_PIPE_COMPUTER_NAME_LENGTH * sizeof (WCHAR)) {
  2056. DebugTrace(0, Dbg, "Computer Name length is too large\n", 0);
  2057. return STATUS_INVALID_PARAMETER;
  2058. }
  2059. ClientInfo = NpAllocatePagedPoolWithQuota (FIELD_OFFSET (CLIENT_INFO, ClientComputerBuffer) +
  2060. ClientProcessBuffer->ClientComputerNameLength,
  2061. 'iFpN');
  2062. if (ClientInfo == NULL) {
  2063. return STATUS_INSUFFICIENT_RESOURCES;
  2064. }
  2065. if (Ccb->ClientInfo != NULL) {
  2066. NpFreePool (Ccb->ClientInfo);
  2067. }
  2068. Ccb->ClientInfo = ClientInfo;
  2069. //
  2070. // Copy over the client process ID
  2071. //
  2072. ClientInfo->ClientSession = ClientProcessBuffer->ClientSession;
  2073. Ccb->ClientProcess = ClientProcessBuffer->ClientProcess;
  2074. ClientInfo->ClientComputerNameLength = ClientProcessBuffer->ClientComputerNameLength;
  2075. RtlCopyMemory( ClientInfo->ClientComputerBuffer,
  2076. ClientProcessBuffer->ClientComputerBuffer,
  2077. ClientProcessBuffer->ClientComputerNameLength );
  2078. DebugTrace(-1, Dbg, "NpSetClientProcess -> STATUS_SUCCESS\n", 0);
  2079. return STATUS_SUCCESS;
  2080. }
  2081. //
  2082. // Internal support routine
  2083. //
  2084. NTSTATUS
  2085. NpCompleteTransceiveIrp (
  2086. IN PDEVICE_OBJECT DeviceObject,
  2087. IN PIRP Irp,
  2088. IN PVOID Context
  2089. )
  2090. /*++
  2091. Routine Description:
  2092. This is a local i/o completion routine used to complete the special
  2093. Irps allocated for transcieve. This routine simply deallocate the
  2094. irp and return status more processing
  2095. Arguments:
  2096. DeviceObject - Supplies the device object
  2097. Irp - Supplies the Irp to complete
  2098. Context - Supplies the context for the Irp
  2099. Return Value:
  2100. NTSTATUS - STATUS_MORE_PROCESSING_REQUIRED
  2101. --*/
  2102. {
  2103. UNREFERENCED_PARAMETER( DeviceObject );
  2104. UNREFERENCED_PARAMETER( Context );
  2105. PAGED_CODE();
  2106. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  2107. NpFreePool( Irp->AssociatedIrp.SystemBuffer );
  2108. }
  2109. IoFreeIrp( Irp );
  2110. return STATUS_MORE_PROCESSING_REQUIRED;
  2111. }