Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3107 lines
81 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. NAMED_PIPE_END NamedPipeEnd;
  1068. PLIST_ENTRY Links;
  1069. BOOLEAN CaseInsensitive = TRUE; //**** Make all searches case insensitive
  1070. UNICODE_STRING RemainingPart;
  1071. BOOLEAN Translated;
  1072. PAGED_CODE();
  1073. //
  1074. // Get the current stack location
  1075. //
  1076. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1077. DebugTrace(+1, Dbg, "NpWaitForNamedPipe...\n", 0);
  1078. //
  1079. // Extract the important fields from the IrpSp
  1080. //
  1081. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1082. FsControlCode = IrpSp->Parameters.FileSystemControl.FsControlCode;
  1083. Name.Buffer = NULL;
  1084. LocalBuffer = NULL;
  1085. try {
  1086. //
  1087. // Decode the file object to figure out who we are. If the result
  1088. // is an error if the we weren't given a Vcb.
  1089. //
  1090. if (NpDecodeFileObject( IrpSp->FileObject,
  1091. NULL,
  1092. &Ccb,
  1093. &NamedPipeEnd ) != NPFS_NTC_ROOT_DCB) {
  1094. DebugTrace(0, Dbg, "File Object is not for the named pipe root directory\n", 0);
  1095. try_return( Status = STATUS_ILLEGAL_FUNCTION );
  1096. }
  1097. //
  1098. // Reference the system buffer as a wait for buffer and make
  1099. // sure it's large enough
  1100. //
  1101. if (InputBufferLength < sizeof(FILE_PIPE_WAIT_FOR_BUFFER)) {
  1102. DebugTrace(0, Dbg, "System buffer size is too small\n", 0);
  1103. try_return( Status = STATUS_INVALID_PARAMETER );
  1104. }
  1105. WaitBuffer = Irp->AssociatedIrp.SystemBuffer;
  1106. //
  1107. // Check for an invalid buffer. The Name Length cannot be greater than
  1108. // MAXUSHORT minus the backslash otherwise it will overflow the buffer.
  1109. // We don't need to check for less than 0 because it is unsigned.
  1110. //
  1111. if ((WaitBuffer->NameLength > (MAXUSHORT - 2)) ||
  1112. (FIELD_OFFSET(FILE_PIPE_WAIT_FOR_BUFFER, Name[0]) + WaitBuffer->NameLength > InputBufferLength)) {
  1113. DebugTrace(0, Dbg, "System buffer size or name length is too small\n", 0);
  1114. try_return( Status = STATUS_INVALID_PARAMETER );
  1115. }
  1116. //
  1117. // Set up the local variable Name to be the name we're looking
  1118. // for
  1119. //
  1120. Name.Length = (USHORT)(WaitBuffer->NameLength + 2);
  1121. Name.Buffer = LocalBuffer = NpAllocatePagedPool( Name.Length, 'WFpN' );
  1122. if (LocalBuffer == NULL) {
  1123. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  1124. }
  1125. Name.Buffer[0] = L'\\';
  1126. RtlCopyMemory( &Name.Buffer[1],
  1127. &WaitBuffer->Name[0],
  1128. WaitBuffer->NameLength );
  1129. //
  1130. // If the name is an alias, translate it
  1131. //
  1132. Status = NpTranslateAlias( &Name );
  1133. if ( !NT_SUCCESS(Status) ) {
  1134. try_return( NOTHING );
  1135. }
  1136. //
  1137. // Now check to see if we can find a named pipe with the right
  1138. // name
  1139. //
  1140. Fcb = NpFindPrefix( &Name, CaseInsensitive, &RemainingPart );
  1141. //
  1142. // If the Fcb is null then we can't wait for it, Also if the
  1143. // Fcb is not an Fcb then we also have nothing to wait for
  1144. //
  1145. if (NodeType(Fcb) != NPFS_NTC_FCB) {
  1146. DebugTrace(0, Dbg, "Bad nonexistent named pipe name", 0);
  1147. try_return( Status = STATUS_OBJECT_NAME_NOT_FOUND );
  1148. }
  1149. //
  1150. // If translated then Name.Buffer would point to the translated buffer
  1151. //
  1152. Translated = (Name.Buffer != LocalBuffer);
  1153. //
  1154. // Now we need to search to see if we find a ccb already in the
  1155. // listening state
  1156. // First try and find a ccb that is in the listening state
  1157. // If we exit the loop with ccb null then we haven't found
  1158. // one
  1159. //
  1160. Ccb = NULL;
  1161. for (Links = Fcb->Specific.Fcb.CcbQueue.Flink;
  1162. Links != &Fcb->Specific.Fcb.CcbQueue;
  1163. Links = Links->Flink) {
  1164. Ccb = CONTAINING_RECORD( Links, CCB, CcbLinks );
  1165. if (Ccb->NamedPipeState == FILE_PIPE_LISTENING_STATE) {
  1166. break;
  1167. }
  1168. Ccb = NULL;
  1169. }
  1170. //
  1171. // Check if we found one
  1172. //
  1173. if (Ccb != NULL) {
  1174. DebugTrace(0, Dbg, "Found a ccb in listening state\n", 0);
  1175. try_return( Status = STATUS_SUCCESS );
  1176. }
  1177. //
  1178. // We weren't able to find one so we need to add a new waiter
  1179. //
  1180. Status = NpAddWaiter( &NpVcb->WaitQueue,
  1181. Fcb->Specific.Fcb.DefaultTimeOut,
  1182. Irp,
  1183. Translated ? &Name : NULL);
  1184. try_exit: NOTHING;
  1185. } finally {
  1186. if (LocalBuffer != NULL) {
  1187. NpFreePool( LocalBuffer );
  1188. }
  1189. }
  1190. DebugTrace(-1, Dbg, "NpWaitForNamedPipe -> %08lx\n", Status);
  1191. return Status;
  1192. }
  1193. //
  1194. // Local Support Routine
  1195. //
  1196. NTSTATUS
  1197. NpImpersonate (
  1198. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1199. IN PIRP Irp
  1200. )
  1201. /*++
  1202. Routine Description:
  1203. This routine does the impersonate of the named pipe
  1204. Arguments:
  1205. NpfsDeviceObject - Supplies our device object
  1206. Irp - Supplies the being processed
  1207. Return Value:
  1208. NTSTATUS - An apprropriate return status
  1209. --*/
  1210. {
  1211. NTSTATUS Status;
  1212. PIO_STACK_LOCATION IrpSp;
  1213. PCCB Ccb;
  1214. NAMED_PIPE_END NamedPipeEnd;
  1215. UNREFERENCED_PARAMETER( NpfsDeviceObject );
  1216. PAGED_CODE();
  1217. //
  1218. // Get the current stack location
  1219. //
  1220. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1221. DebugTrace(+1, Dbg, "NpImpersonate...\n", 0);
  1222. //
  1223. // Decode the file object to figure out who we are. If the result
  1224. // is an error if the we weren't given a Vcb.
  1225. //
  1226. if (NpDecodeFileObject( IrpSp->FileObject,
  1227. NULL,
  1228. &Ccb,
  1229. &NamedPipeEnd ) != NPFS_NTC_CCB) {
  1230. DebugTrace(0, Dbg, "File Object is not a named pipe\n", 0);
  1231. DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  1232. return STATUS_ILLEGAL_FUNCTION;
  1233. }
  1234. //
  1235. // Make sure that we are the server end and not the client end
  1236. //
  1237. if (NamedPipeEnd != FILE_PIPE_SERVER_END) {
  1238. DebugTrace(0, Dbg, "Not the server end\n", 0);
  1239. DebugTrace(-1, Dbg, "NpImpersonate -> STATUS_ILLEGAL_FUNCTION\n", 0 );
  1240. return STATUS_ILLEGAL_FUNCTION;
  1241. }
  1242. //
  1243. // set up the impersonation
  1244. //
  1245. Status = NpImpersonateClientContext( Ccb );
  1246. DebugTrace(-1, Dbg, "NpImpersonate -> %08lx\n", Status);
  1247. return Status;
  1248. }
  1249. //
  1250. // Local Support Routine
  1251. //
  1252. NTSTATUS
  1253. NpInternalRead (
  1254. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1255. IN PIRP Irp,
  1256. IN BOOLEAN ReadOverflowOperation,
  1257. IN PLIST_ENTRY DeferredList
  1258. )
  1259. /*++
  1260. Routine Description:
  1261. This routine does the unbuffered read named pipe control function
  1262. Arguments:
  1263. NpfsDeviceObject - Supplies our device object
  1264. Irp - Supplies the being processed
  1265. ReadOverflowOperation - Used to indicate if the read being processed is a read overflow
  1266. operation.
  1267. DeferredList - List of IRP's to be completed later after we drop the locks
  1268. Return Value:
  1269. NTSTATUS - An apprropriate return status
  1270. --*/
  1271. {
  1272. NTSTATUS Status;
  1273. PIO_STACK_LOCATION IrpSp;
  1274. NODE_TYPE_CODE NodeTypeCode;
  1275. PCCB Ccb;
  1276. PNONPAGED_CCB NonpagedCcb;
  1277. NAMED_PIPE_END NamedPipeEnd;
  1278. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1279. PIRP ReadIrp;
  1280. PUCHAR ReadBuffer;
  1281. ULONG ReadLength;
  1282. ULONG ReadRemaining;
  1283. READ_MODE ReadMode;
  1284. COMPLETION_MODE CompletionMode;
  1285. PDATA_QUEUE ReadQueue;
  1286. PEVENT_TABLE_ENTRY Event;
  1287. PAGED_CODE();
  1288. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1289. DebugTrace(+1, Dbg, "NpInternalRead\n", 0);
  1290. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1291. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1292. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1293. //
  1294. // Get the Ccb and figure out who we are, and make sure we're not
  1295. // disconnected
  1296. //
  1297. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1298. NULL,
  1299. &Ccb,
  1300. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1301. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1302. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1303. return STATUS_PIPE_DISCONNECTED;
  1304. }
  1305. //
  1306. // Now we only will allow Read operations on the pipe and not a directory
  1307. // or the device
  1308. //
  1309. if (NodeTypeCode != NPFS_NTC_CCB) {
  1310. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1311. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
  1312. return STATUS_INVALID_PARAMETER;
  1313. }
  1314. NonpagedCcb = Ccb->NonpagedCcb;
  1315. NpAcquireExclusiveCcb(Ccb);
  1316. //
  1317. // Check if the pipe is not in the connected state.
  1318. //
  1319. switch (Ccb->NamedPipeState) {
  1320. case FILE_PIPE_DISCONNECTED_STATE:
  1321. DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
  1322. NpReleaseCcb(Ccb);
  1323. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1324. return STATUS_PIPE_DISCONNECTED;
  1325. case FILE_PIPE_LISTENING_STATE:
  1326. DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
  1327. NpReleaseCcb(Ccb);
  1328. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_PIPE_LISTENING\n", 0 );
  1329. return STATUS_PIPE_LISTENING;
  1330. case FILE_PIPE_CONNECTED_STATE:
  1331. case FILE_PIPE_CLOSING_STATE:
  1332. break;
  1333. default:
  1334. DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
  1335. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  1336. }
  1337. //
  1338. // We only allow a read by the server on a non outbound only pipe
  1339. // and by the client on a non inbound only pipe
  1340. //
  1341. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1342. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  1343. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))
  1344. ||
  1345. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  1346. (NamedPipeConfiguration == FILE_PIPE_INBOUND))) {
  1347. DebugTrace(0, Dbg, "Trying to read to the wrong pipe configuration\n", 0);
  1348. NpReleaseCcb(Ccb);
  1349. DebugTrace(-1, Dbg, "NpInternalRead -> STATUS_INVALID_PARAMETER\n", 0 );
  1350. return STATUS_INVALID_PARAMETER;
  1351. }
  1352. //
  1353. // Reference our input parameters to make things easier, and
  1354. // initialize our main variables that describe the Read command
  1355. //
  1356. ReadIrp = Irp;
  1357. ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
  1358. ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1359. ReadRemaining = ReadLength;
  1360. ReadMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].ReadMode;
  1361. CompletionMode = Ccb->ReadCompletionMode[ NamedPipeEnd ].CompletionMode;
  1362. if (ReadOverflowOperation == TRUE && ReadMode != FILE_PIPE_MESSAGE_MODE) {
  1363. NpReleaseCcb(Ccb);
  1364. return STATUS_INVALID_READ_MODE;
  1365. }
  1366. //
  1367. // Now the data queue that we read from into and the event that we signal
  1368. // are based on the named pipe end. The server read from the inbound
  1369. // queue and signals the client event. The client does just the
  1370. // opposite.
  1371. //
  1372. switch (NamedPipeEnd) {
  1373. case FILE_PIPE_SERVER_END:
  1374. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1375. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1376. break;
  1377. case FILE_PIPE_CLIENT_END:
  1378. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1379. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1380. break;
  1381. default:
  1382. NpBugCheck( NamedPipeEnd, 0, 0 );
  1383. }
  1384. DebugTrace(0, Dbg, "ReadBuffer = %08lx\n", ReadBuffer);
  1385. DebugTrace(0, Dbg, "ReadLength = %08lx\n", ReadLength);
  1386. DebugTrace(0, Dbg, "ReadMode = %08lx\n", ReadMode);
  1387. DebugTrace(0, Dbg, "CompletionMode = %08lx\n", CompletionMode);
  1388. DebugTrace(0, Dbg, "ReadQueue = %08lx\n", ReadQueue);
  1389. DebugTrace(0, Dbg, "Event = %08lx\n", Event);
  1390. //
  1391. // if the read queue does not contain any write entries
  1392. // then we either need to enqueue this operation or
  1393. // fail immediately
  1394. //
  1395. if (!NpIsDataQueueWriters( ReadQueue )) {
  1396. //
  1397. // Check if the other end of the pipe is closing, and if
  1398. // so then we complete it with end of file.
  1399. // Otherwise check to see if we should enqueue the irp
  1400. // or complete the operation and tell the user the pipe is empty.
  1401. //
  1402. if (Ccb->NamedPipeState == FILE_PIPE_CLOSING_STATE) {
  1403. DebugTrace(0, Dbg, "Complete the irp with eof\n", 0);
  1404. Status = STATUS_PIPE_BROKEN;
  1405. } else if (CompletionMode == FILE_PIPE_QUEUE_OPERATION) {
  1406. DebugTrace(0, Dbg, "Put the irp into the read queue\n", 0);
  1407. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1408. Ccb,
  1409. ReadQueue,
  1410. ReadEntries,
  1411. Unbuffered,
  1412. ReadLength,
  1413. ReadIrp,
  1414. NULL,
  1415. 0 );
  1416. } else {
  1417. DebugTrace(0, Dbg, "Complete the irp with pipe empty\n", 0);
  1418. Status = STATUS_PIPE_EMPTY;
  1419. }
  1420. } else {
  1421. //
  1422. // otherwise there we have a read irp against a read queue
  1423. // that contains one or more write entries.
  1424. //
  1425. ReadIrp->IoStatus = NpReadDataQueue( ReadQueue,
  1426. FALSE,
  1427. ReadOverflowOperation,
  1428. ReadBuffer,
  1429. ReadLength,
  1430. ReadMode,
  1431. Ccb,
  1432. DeferredList );
  1433. Status = ReadIrp->IoStatus.Status;
  1434. //
  1435. // Now set the remaining byte count in the allocation size of
  1436. // the Irp.
  1437. //
  1438. ReadIrp->Overlay.AllocationSize.QuadPart = ReadQueue->BytesInQueue - ReadQueue->NextByteOffset;
  1439. //
  1440. // Finish up the read irp.
  1441. //
  1442. }
  1443. //
  1444. // And because we've done something we need to signal the
  1445. // other ends event
  1446. //
  1447. NpSignalEventTableEntry( Event );
  1448. NpReleaseCcb(Ccb);
  1449. DebugTrace(-1, Dbg, "NpInternalRead -> %08lx\n", Status);
  1450. return Status;
  1451. }
  1452. //
  1453. // Local Support Routine
  1454. //
  1455. NTSTATUS
  1456. NpInternalWrite (
  1457. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1458. IN PIRP Irp,
  1459. IN PLIST_ENTRY DeferredList
  1460. )
  1461. /*++
  1462. Routine Description:
  1463. This routine does the unbuffered write named pipe control function
  1464. Arguments:
  1465. NpfsDeviceObject - Supplies our device object
  1466. Irp - Supplies the being processed
  1467. Return Value:
  1468. NTSTATUS - An apprropriate return status
  1469. --*/
  1470. {
  1471. NTSTATUS Status;
  1472. PIO_STACK_LOCATION IrpSp;
  1473. PETHREAD UserThread;
  1474. NODE_TYPE_CODE NodeTypeCode;
  1475. PCCB Ccb;
  1476. PNONPAGED_CCB NonpagedCcb;
  1477. NAMED_PIPE_END NamedPipeEnd;
  1478. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1479. PIRP WriteIrp;
  1480. PUCHAR WriteBuffer;
  1481. ULONG WriteLength;
  1482. ULONG WriteRemaining;
  1483. PDATA_QUEUE WriteQueue;
  1484. PEVENT_TABLE_ENTRY Event;
  1485. READ_MODE ReadMode;
  1486. PAGED_CODE();
  1487. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1488. DebugTrace(+1, Dbg, "NpInternalWrite\n", 0);
  1489. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1490. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1491. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1492. //
  1493. // This is a FSCTL path being used as a write. Make sure we can set the .Information field to the number
  1494. // of bytes written.
  1495. //
  1496. NpConvertFsctlToWrite (Irp);
  1497. //
  1498. // Get the Ccb and figure out who we are, and make sure we're not
  1499. // disconnected
  1500. //
  1501. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1502. NULL,
  1503. &Ccb,
  1504. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1505. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1506. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1507. return STATUS_PIPE_DISCONNECTED;
  1508. }
  1509. //
  1510. // Now we only will allow write operations on the pipe and not a directory
  1511. // or the device
  1512. //
  1513. if (NodeTypeCode != NPFS_NTC_CCB) {
  1514. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1515. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
  1516. return STATUS_PIPE_DISCONNECTED;
  1517. }
  1518. NonpagedCcb = Ccb->NonpagedCcb;
  1519. NpAcquireExclusiveCcb(Ccb);
  1520. //
  1521. // We only allow a write by the server on a non inbound only pipe
  1522. // and by the client on a non outbound only pipe
  1523. //
  1524. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1525. if (((NamedPipeEnd == FILE_PIPE_SERVER_END) &&
  1526. (NamedPipeConfiguration == FILE_PIPE_INBOUND))
  1527. ||
  1528. ((NamedPipeEnd == FILE_PIPE_CLIENT_END) &&
  1529. (NamedPipeConfiguration == FILE_PIPE_OUTBOUND))) {
  1530. DebugTrace(0, Dbg, "Trying to write to the wrong pipe configuration\n", 0);
  1531. NpReleaseCcb(Ccb);
  1532. DebugTrace(-1, Dbg, "NpInternalWrite -> STATUS_PIPE_DISCONNECTED\n", 0);
  1533. return STATUS_PIPE_DISCONNECTED;
  1534. }
  1535. //
  1536. // Reference our input parameters to make things easier, and
  1537. // initialize our main variables that describe the write command
  1538. //
  1539. WriteIrp = Irp;
  1540. WriteBuffer = Irp->AssociatedIrp.SystemBuffer;
  1541. WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1542. //
  1543. // Set up the amount of data we will have written by the time this
  1544. // irp gets completed
  1545. //
  1546. WriteIrp->IoStatus.Information = WriteLength;
  1547. //
  1548. // Now the data queue that we write into and the event that we signal
  1549. // are based on the named pipe end. The server writes to the outbound
  1550. // queue and signals the client event. The client does just the
  1551. // opposite. We also need to figure out the read mode for the opposite
  1552. // end of the pipe.
  1553. //
  1554. switch (NamedPipeEnd) {
  1555. case FILE_PIPE_SERVER_END:
  1556. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1557. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1558. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  1559. break;
  1560. case FILE_PIPE_CLIENT_END:
  1561. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1562. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1563. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  1564. break;
  1565. default:
  1566. NpBugCheck( NamedPipeEnd, 0, 0 );
  1567. }
  1568. //
  1569. // Check if the pipe is not in the connected state.
  1570. //
  1571. switch (Ccb->NamedPipeState) {
  1572. case FILE_PIPE_DISCONNECTED_STATE:
  1573. DebugTrace(0, Dbg, "Pipe in disconnected state\n", 0);
  1574. NpReleaseCcb(Ccb);
  1575. return STATUS_PIPE_DISCONNECTED;
  1576. case FILE_PIPE_LISTENING_STATE:
  1577. DebugTrace(0, Dbg, "Pipe in listening state\n", 0);
  1578. NpReleaseCcb(Ccb);
  1579. return STATUS_PIPE_LISTENING;
  1580. case FILE_PIPE_CONNECTED_STATE:
  1581. break;
  1582. case FILE_PIPE_CLOSING_STATE:
  1583. DebugTrace(0, Dbg, "Pipe in closing state\n", 0);
  1584. NpReleaseCcb(Ccb);
  1585. return STATUS_PIPE_CLOSING;
  1586. default:
  1587. DebugTrace(0, Dbg, "Illegal pipe state = %08lx\n", Ccb->NamedPipeState);
  1588. NpBugCheck( Ccb->NamedPipeState, 0, 0 );
  1589. }
  1590. //
  1591. // Check if this is a message type pipe and the operation type is complete
  1592. // operation, If so then we also check that the queued reads is enough to
  1593. // complete the message otherwise we need to abort the write irp immediately.
  1594. //
  1595. if ((Ccb->Fcb->Specific.Fcb.NamedPipeType == FILE_PIPE_MESSAGE_TYPE) &&
  1596. (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION)) {
  1597. //
  1598. // If the pipe contains readers and amount to read is less than the write
  1599. // length then we cannot do it the write.
  1600. // Or if pipe does not contain reads then we also cannot do the write.
  1601. //
  1602. if ((NpIsDataQueueReaders( WriteQueue ) &&
  1603. (WriteQueue->BytesInQueue < WriteLength))
  1604. ||
  1605. (!NpIsDataQueueReaders( WriteQueue ))) {
  1606. DebugTrace(0, Dbg, "Cannot complete the message without blocking\n", 0);
  1607. NpReleaseCcb(Ccb);
  1608. Irp->IoStatus.Information = 0;
  1609. return STATUS_SUCCESS;
  1610. }
  1611. }
  1612. //
  1613. // Now we'll call our common write data queue routine to
  1614. // transfer data out of our write buffer into the data queue.
  1615. // If the result of the call is FALSE then we still have some
  1616. // write data to put into the write queue.
  1617. //
  1618. UserThread = Irp->Tail.Overlay.Thread;
  1619. Status = NpWriteDataQueue( WriteQueue,
  1620. ReadMode,
  1621. WriteBuffer,
  1622. WriteLength,
  1623. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  1624. &WriteRemaining,
  1625. Ccb,
  1626. NamedPipeEnd,
  1627. UserThread,
  1628. DeferredList );
  1629. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1630. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  1631. //
  1632. // Check if the operation is not to block and if so then we
  1633. // will complete the operation now with what we're written, if what is
  1634. // left will not fit in the quota for the file
  1635. //
  1636. if (Ccb->ReadCompletionMode[NamedPipeEnd].CompletionMode == FILE_PIPE_COMPLETE_OPERATION) {
  1637. DebugTrace(0, Dbg, "Complete the byte stream write immediately\n", 0);
  1638. Irp->IoStatus.Information = WriteLength - WriteRemaining;
  1639. Status = STATUS_SUCCESS;
  1640. } else {
  1641. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  1642. //
  1643. // Add this write request to the write queue
  1644. //
  1645. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1646. Ccb,
  1647. WriteQueue,
  1648. WriteEntries,
  1649. Unbuffered,
  1650. WriteLength,
  1651. Irp,
  1652. NULL,
  1653. WriteLength - WriteRemaining);
  1654. }
  1655. } else {
  1656. DebugTrace(0, Dbg, "Complete the Write Irp\n", 0);
  1657. //
  1658. // The write irp is finished so we can complete it now
  1659. //
  1660. }
  1661. //
  1662. // And because we've done something we need to signal the
  1663. // other ends event
  1664. //
  1665. NpSignalEventTableEntry( Event );
  1666. NpReleaseCcb(Ccb);
  1667. DebugTrace(-1, Dbg, "NpInternalWrite -> %08lx\n", Status);
  1668. return Status;
  1669. }
  1670. //
  1671. // Local Support Routine
  1672. //
  1673. NTSTATUS
  1674. NpInternalTransceive (
  1675. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1676. IN PIRP Irp,
  1677. IN PLIST_ENTRY DeferredList
  1678. )
  1679. /*++
  1680. Routine Description:
  1681. This routine does the internal (i.e., unbuffered) transceive named pipe
  1682. control function
  1683. Arguments:
  1684. NpfsDeviceObject - Supplies our device object
  1685. Irp - Supplies the being processed
  1686. DeferredList - List of IRP's to be completed once we drop our locks.
  1687. Return Value:
  1688. NTSTATUS - An apprropriate return status
  1689. --*/
  1690. {
  1691. static IO_STATUS_BLOCK Iosb;
  1692. NTSTATUS Status;
  1693. PIO_STACK_LOCATION IrpSp;
  1694. PETHREAD UserThread;
  1695. PUCHAR WriteBuffer;
  1696. ULONG WriteLength;
  1697. PUCHAR ReadBuffer;
  1698. ULONG ReadLength;
  1699. NODE_TYPE_CODE NodeTypeCode;
  1700. PCCB Ccb;
  1701. PNONPAGED_CCB NonpagedCcb;
  1702. NAMED_PIPE_END NamedPipeEnd;
  1703. PDATA_QUEUE ReadQueue;
  1704. PDATA_QUEUE WriteQueue;
  1705. PEVENT_TABLE_ENTRY Event;
  1706. READ_MODE ReadMode;
  1707. NAMED_PIPE_CONFIGURATION NamedPipeConfiguration;
  1708. ULONG WriteRemaining;
  1709. PIRP WriteIrp;
  1710. //
  1711. // The following variable is used for abnormal unwind
  1712. //
  1713. PVOID UnwindStorage = NULL;
  1714. PAGED_CODE();
  1715. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1716. DebugTrace(+1, Dbg, "NpInternalTransceive\n", 0);
  1717. DebugTrace( 0, Dbg, "NpfsDeviceObject = %08lx\n", NpfsDeviceObject);
  1718. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  1719. DebugTrace( 0, Dbg, "FileObject = %08lx\n", IrpSp->FileObject);
  1720. WriteLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  1721. WriteBuffer = IrpSp->Parameters.FileSystemControl.Type3InputBuffer;
  1722. ReadLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1723. ReadBuffer = Irp->AssociatedIrp.SystemBuffer;
  1724. //
  1725. // Get the Ccb and figure out who we are, and make sure we're not
  1726. // disconnected
  1727. //
  1728. if ((NodeTypeCode = NpDecodeFileObject( IrpSp->FileObject,
  1729. NULL,
  1730. &Ccb,
  1731. &NamedPipeEnd )) == NTC_UNDEFINED) {
  1732. DebugTrace(0, Dbg, "Pipe is disconnected from us\n", 0);
  1733. DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_PIPE_DISCONNECTED\n", 0 );
  1734. return STATUS_PIPE_DISCONNECTED;
  1735. }
  1736. //
  1737. // Now we only will allow transceive operations on the pipe and not a
  1738. // directory or the device
  1739. //
  1740. if (NodeTypeCode != NPFS_NTC_CCB) {
  1741. DebugTrace(0, Dbg, "FileObject is not for a named pipe\n", 0);
  1742. DebugTrace(-1, Dbg, "NpInternalTransceive -> STATUS_INVALID_PARAMETER\n", 0 );
  1743. return STATUS_INVALID_PARAMETER;
  1744. }
  1745. NonpagedCcb = Ccb->NonpagedCcb;
  1746. WriteIrp = NULL;
  1747. NpAcquireExclusiveCcb(Ccb);
  1748. try {
  1749. //
  1750. // Check that the pipe is in the connected state
  1751. //
  1752. if (Ccb->NamedPipeState != FILE_PIPE_CONNECTED_STATE) {
  1753. DebugTrace(0, Dbg, "Pipe not connected\n", 0);
  1754. try_return( Status = STATUS_INVALID_PIPE_STATE );
  1755. }
  1756. //
  1757. // Figure out the read/write queue, read mode, and event based
  1758. // on the end of the named pipe doing the transceive.
  1759. //
  1760. switch (NamedPipeEnd) {
  1761. case FILE_PIPE_SERVER_END:
  1762. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1763. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1764. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_CLIENT_END ];
  1765. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_SERVER_END ].ReadMode;
  1766. break;
  1767. case FILE_PIPE_CLIENT_END:
  1768. ReadQueue = &Ccb->DataQueue[ FILE_PIPE_OUTBOUND ];
  1769. WriteQueue = &Ccb->DataQueue[ FILE_PIPE_INBOUND ];
  1770. Event = NonpagedCcb->EventTableEntry[ FILE_PIPE_SERVER_END ];
  1771. ReadMode = Ccb->ReadCompletionMode[ FILE_PIPE_CLIENT_END ].ReadMode;
  1772. break;
  1773. default:
  1774. NpBugCheck( NamedPipeEnd, 0, 0 );
  1775. }
  1776. //
  1777. // We only allow a transceive on a message mode, full duplex pipe.
  1778. //
  1779. NamedPipeConfiguration = Ccb->Fcb->Specific.Fcb.NamedPipeConfiguration;
  1780. if ((NamedPipeConfiguration != FILE_PIPE_FULL_DUPLEX) ||
  1781. (ReadMode != FILE_PIPE_MESSAGE_MODE)) {
  1782. DebugTrace(0, Dbg, "Bad pipe configuration or read mode\n", 0);
  1783. try_return( Status = STATUS_INVALID_READ_MODE );
  1784. }
  1785. //
  1786. // Check that the read queue is empty.
  1787. //
  1788. if (!NpIsDataQueueEmpty( ReadQueue )) {
  1789. DebugTrace(0, Dbg, "Read queue is not empty\n", 0);
  1790. try_return( Status = STATUS_PIPE_BUSY );
  1791. }
  1792. //
  1793. // Do the transceive write operation. We first try and push the data
  1794. // from the write buffer into any waiting readers in the write queue
  1795. // and if that succeeds then we can go on and do the read operation
  1796. // otherwise we need to make a copy of irp and to enqueue as
  1797. // a data entry into the write queue.
  1798. //
  1799. // Now we'll call our common write data queue routine to
  1800. // transfer data out of our write buffer into the data queue.
  1801. // If the result of the call is FALSE then we still have some
  1802. // write data to put into the write queue.
  1803. //
  1804. UserThread = Irp->Tail.Overlay.Thread;
  1805. Status = NpWriteDataQueue( WriteQueue,
  1806. ReadMode,
  1807. WriteBuffer,
  1808. WriteLength,
  1809. Ccb->Fcb->Specific.Fcb.NamedPipeType,
  1810. &WriteRemaining,
  1811. Ccb,
  1812. NamedPipeEnd,
  1813. UserThread,
  1814. DeferredList );
  1815. if (Status == STATUS_MORE_PROCESSING_REQUIRED) {
  1816. PIO_STACK_LOCATION WriteIrpSp;
  1817. ASSERT( !NpIsDataQueueReaders( WriteQueue ));
  1818. DebugTrace(0, Dbg, "Add write to data queue\n", 0);
  1819. //
  1820. // We need to do some more write processing. So to handle
  1821. // this case we'll allocate a new irp and set its system
  1822. // buffer to be the remaining part of the write buffer
  1823. //
  1824. if ((WriteIrp = IoAllocateIrp( NpfsDeviceObject->DeviceObject.StackSize, TRUE )) == NULL) {
  1825. try_return( Status = STATUS_INSUFFICIENT_RESOURCES );
  1826. }
  1827. IoSetCompletionRoutine( WriteIrp, NpCompleteTransceiveIrp, NULL, TRUE, TRUE, TRUE );
  1828. WriteIrpSp = IoGetNextIrpStackLocation( WriteIrp );
  1829. if (WriteRemaining > 0) {
  1830. WriteIrp->AssociatedIrp.SystemBuffer = NpAllocatePagedPoolWithQuota( WriteRemaining, 'wFpN' );
  1831. if (WriteIrp->AssociatedIrp.SystemBuffer == NULL) {
  1832. IoFreeIrp (WriteIrp);
  1833. try_return (Status = STATUS_INSUFFICIENT_RESOURCES);
  1834. }
  1835. //
  1836. // Safely do the copy
  1837. //
  1838. try {
  1839. RtlCopyMemory( WriteIrp->AssociatedIrp.SystemBuffer,
  1840. &WriteBuffer[ WriteLength - WriteRemaining ],
  1841. WriteRemaining );
  1842. WriteIrp->Flags = IRP_BUFFERED_IO | IRP_DEALLOCATE_BUFFER;
  1843. } except(EXCEPTION_EXECUTE_HANDLER) {
  1844. NpFreePool (WriteIrp->AssociatedIrp.SystemBuffer);
  1845. IoFreeIrp (WriteIrp);
  1846. try_return (Status = GetExceptionCode ());
  1847. }
  1848. } else {
  1849. WriteIrp->AssociatedIrp.SystemBuffer = NULL;
  1850. }
  1851. //
  1852. // Set the current stack location
  1853. //
  1854. WriteIrp->CurrentLocation -= 1;
  1855. WriteIrp->Tail.Overlay.CurrentStackLocation = WriteIrpSp;
  1856. WriteIrp->Tail.Overlay.Thread = UserThread;
  1857. WriteIrpSp->MajorFunction = IRP_MJ_WRITE;
  1858. WriteIrp->UserIosb = &Iosb;
  1859. //
  1860. // Add this write request to the write queue
  1861. //
  1862. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1863. Ccb,
  1864. WriteQueue,
  1865. WriteEntries,
  1866. Unbuffered,
  1867. WriteRemaining,
  1868. WriteIrp,
  1869. NULL,
  1870. 0 );
  1871. if (Status != STATUS_PENDING) {
  1872. NpDeferredCompleteRequest (WriteIrp, Status, DeferredList);
  1873. }
  1874. }
  1875. if (!NT_SUCCESS (Status)) {
  1876. try_return (NOTHING)
  1877. }
  1878. //
  1879. // And because we've done something we need to signal the
  1880. // other ends event
  1881. //
  1882. NpSignalEventTableEntry( Event );
  1883. //
  1884. // Do the transceive read operation. This is just like an
  1885. // unbuffered read.
  1886. //
  1887. // Now we know that the read queue is empty so we'll enqueue this
  1888. // Irp to the read queue and return status pending, also mark the
  1889. // irp pending
  1890. //
  1891. ASSERT( NpIsDataQueueEmpty( ReadQueue ));
  1892. Status = NpAddDataQueueEntry( NamedPipeEnd,
  1893. Ccb,
  1894. ReadQueue,
  1895. ReadEntries,
  1896. Unbuffered,
  1897. ReadLength,
  1898. Irp,
  1899. NULL,
  1900. 0 );
  1901. if (!NT_SUCCESS (Status)) {
  1902. try_return (Status);
  1903. }
  1904. //
  1905. // And because we've done something we need to signal the
  1906. // other ends event
  1907. //
  1908. NpSignalEventTableEntry( Event );
  1909. try_exit: NOTHING;
  1910. } finally {
  1911. NpReleaseCcb(Ccb);
  1912. }
  1913. DebugTrace(-1, Dbg, "NpInternalTransceive -> %08lx\n", Status);
  1914. return Status;
  1915. }
  1916. //
  1917. // Internal support routine
  1918. //
  1919. NTSTATUS
  1920. NpQueryClientProcess (
  1921. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  1922. IN PIRP Irp
  1923. )
  1924. /*++
  1925. Routine Description:
  1926. This routine does the query client process named pipe control function
  1927. The output buffer may be either a FILE_PIPE_CLIENT_PROCESS_BUFFER or a
  1928. FILE_PIPE_CLIENT_PROCESS_BUFFER_EX.
  1929. Arguments:
  1930. NpfsDeviceObject - Supplies our device object
  1931. Irp - Supplies the being processed
  1932. Return Value:
  1933. NTSTATUS - An apprropriate return status
  1934. --*/
  1935. {
  1936. PIO_STACK_LOCATION IrpSp;
  1937. ULONG OutputBufferLength;
  1938. PCCB Ccb;
  1939. PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer;
  1940. PCLIENT_INFO ClientInfo;
  1941. CLIENT_INFO NullInfo = {0};
  1942. PAGED_CODE();
  1943. //
  1944. // Get the current stack location
  1945. //
  1946. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  1947. DebugTrace(+1, Dbg, "NpQueryClientProcess\n", 0);
  1948. OutputBufferLength = IrpSp->Parameters.FileSystemControl.OutputBufferLength;
  1949. //
  1950. // Decode the file object to figure out who we are.
  1951. //
  1952. if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
  1953. DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
  1954. return STATUS_PIPE_DISCONNECTED;
  1955. }
  1956. //
  1957. // Make sure the output buffer is large enough
  1958. //
  1959. if (OutputBufferLength < sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER)) {
  1960. DebugTrace(0, Dbg, "Output System buffer size is too small\n", 0);
  1961. return STATUS_INVALID_PARAMETER;
  1962. }
  1963. NpAcquireExclusiveCcb(Ccb);
  1964. //
  1965. // Copy over the client process ID
  1966. //
  1967. ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
  1968. ClientProcessBuffer->ClientProcess = Ccb->ClientProcess;
  1969. ClientInfo = Ccb->ClientInfo;
  1970. if (ClientInfo == NULL) {
  1971. ClientInfo = &NullInfo;
  1972. }
  1973. ClientProcessBuffer->ClientSession = ClientInfo->ClientSession;
  1974. //
  1975. // Return extended client information if so requested
  1976. // Set the information field to the size of the client process
  1977. // buffer
  1978. //
  1979. if (OutputBufferLength >= sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
  1980. ClientProcessBuffer->ClientComputerNameLength =
  1981. ClientInfo->ClientComputerNameLength;
  1982. RtlCopyMemory( ClientProcessBuffer->ClientComputerBuffer,
  1983. ClientInfo->ClientComputerBuffer,
  1984. ClientInfo->ClientComputerNameLength );
  1985. ClientProcessBuffer->ClientComputerBuffer[
  1986. ClientProcessBuffer->ClientComputerNameLength / sizeof(WCHAR)] = L'\0';
  1987. Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX);
  1988. } else {
  1989. Irp->IoStatus.Information = sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER);
  1990. }
  1991. NpReleaseCcb(Ccb);
  1992. DebugTrace(-1, Dbg, "NpQueryClientProcess -> STATUS_SUCCESS\n", 0);
  1993. return STATUS_SUCCESS;
  1994. }
  1995. //
  1996. // Internal support routine
  1997. //
  1998. NTSTATUS
  1999. NpSetClientProcess (
  2000. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  2001. IN PIRP Irp
  2002. )
  2003. /*++
  2004. Routine Description:
  2005. This routine does the set client process named pipe control function
  2006. Note that we expect a FILE_PIPE_CLIENT_PROCESS_BUFFER_EX structure to be
  2007. passed in to us.
  2008. Arguments:
  2009. NpfsDeviceObject - Supplies our device object
  2010. Irp - Supplies the being processed
  2011. Return Value:
  2012. NTSTATUS - An apprropriate return status
  2013. --*/
  2014. {
  2015. PIO_STACK_LOCATION IrpSp;
  2016. PCLIENT_INFO ClientInfo;
  2017. ULONG InputBufferLength;
  2018. PCCB Ccb;
  2019. PFILE_PIPE_CLIENT_PROCESS_BUFFER_EX ClientProcessBuffer;
  2020. PAGED_CODE();
  2021. //
  2022. // Get the current stack location
  2023. //
  2024. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  2025. DebugTrace(+1, Dbg, "NpSetClientProcess\n", 0);
  2026. //
  2027. // Only allow kernel callers for this API as RPC relies on this info being solid.
  2028. //
  2029. if (IrpSp->MinorFunction != IRP_MN_KERNEL_CALL) {
  2030. return STATUS_ACCESS_DENIED;
  2031. }
  2032. InputBufferLength = IrpSp->Parameters.FileSystemControl.InputBufferLength;
  2033. //
  2034. // Decode the file object to figure out who we are.
  2035. //
  2036. if (NpDecodeFileObject( IrpSp->FileObject, NULL, &Ccb, NULL ) != NPFS_NTC_CCB) {
  2037. DebugTrace(0, Dbg, "Pipe is disconnected\n", 0);
  2038. return STATUS_PIPE_DISCONNECTED;
  2039. }
  2040. //
  2041. // Make sure the input buffer is large enough
  2042. //
  2043. if (InputBufferLength != sizeof(FILE_PIPE_CLIENT_PROCESS_BUFFER_EX)) {
  2044. DebugTrace(0, Dbg, "Input System buffer size is too small\n", 0);
  2045. return STATUS_INVALID_PARAMETER;
  2046. }
  2047. ClientProcessBuffer = Irp->AssociatedIrp.SystemBuffer;
  2048. //
  2049. // Make verify input length is valid
  2050. //
  2051. if (ClientProcessBuffer->ClientComputerNameLength >
  2052. FILE_PIPE_COMPUTER_NAME_LENGTH * sizeof (WCHAR)) {
  2053. DebugTrace(0, Dbg, "Computer Name length is too large\n", 0);
  2054. return STATUS_INVALID_PARAMETER;
  2055. }
  2056. ClientInfo = NpAllocatePagedPoolWithQuota (FIELD_OFFSET (CLIENT_INFO, ClientComputerBuffer) +
  2057. ClientProcessBuffer->ClientComputerNameLength,
  2058. 'iFpN');
  2059. if (ClientInfo == NULL) {
  2060. return STATUS_INSUFFICIENT_RESOURCES;
  2061. }
  2062. if (Ccb->ClientInfo != NULL) {
  2063. NpFreePool (Ccb->ClientInfo);
  2064. }
  2065. Ccb->ClientInfo = ClientInfo;
  2066. //
  2067. // Copy over the client process ID
  2068. //
  2069. ClientInfo->ClientSession = ClientProcessBuffer->ClientSession;
  2070. Ccb->ClientProcess = ClientProcessBuffer->ClientProcess;
  2071. ClientInfo->ClientComputerNameLength = ClientProcessBuffer->ClientComputerNameLength;
  2072. RtlCopyMemory( ClientInfo->ClientComputerBuffer,
  2073. ClientProcessBuffer->ClientComputerBuffer,
  2074. ClientProcessBuffer->ClientComputerNameLength );
  2075. DebugTrace(-1, Dbg, "NpSetClientProcess -> STATUS_SUCCESS\n", 0);
  2076. return STATUS_SUCCESS;
  2077. }
  2078. //
  2079. // Internal support routine
  2080. //
  2081. NTSTATUS
  2082. NpCompleteTransceiveIrp (
  2083. IN PDEVICE_OBJECT DeviceObject,
  2084. IN PIRP Irp,
  2085. IN PVOID Context
  2086. )
  2087. /*++
  2088. Routine Description:
  2089. This is a local i/o completion routine used to complete the special
  2090. Irps allocated for transcieve. This routine simply deallocate the
  2091. irp and return status more processing
  2092. Arguments:
  2093. DeviceObject - Supplies the device object
  2094. Irp - Supplies the Irp to complete
  2095. Context - Supplies the context for the Irp
  2096. Return Value:
  2097. NTSTATUS - STATUS_MORE_PROCESSING_REQUIRED
  2098. --*/
  2099. {
  2100. UNREFERENCED_PARAMETER( DeviceObject );
  2101. UNREFERENCED_PARAMETER( Context );
  2102. PAGED_CODE();
  2103. if (Irp->AssociatedIrp.SystemBuffer != NULL) {
  2104. NpFreePool( Irp->AssociatedIrp.SystemBuffer );
  2105. }
  2106. IoFreeIrp( Irp );
  2107. return STATUS_MORE_PROCESSING_REQUIRED;
  2108. }