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.

967 lines
26 KiB

  1. /*++
  2. Copyright (c) 1989 Microsoft Corporation
  3. Module Name:
  4. Dir.c
  5. Abstract:
  6. This module implements the File Directory routines for the Named Pipe
  7. file system by the dispatch driver.
  8. Author:
  9. Gary Kimura [GaryKi] 28-Dec-1989
  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_DIR)
  17. //
  18. // Local debug trace level
  19. //
  20. #define Dbg (DEBUG_TRACE_DIR)
  21. #ifdef ALLOC_PRAGMA
  22. #pragma alloc_text(PAGE, NpCheckForNotify)
  23. #pragma alloc_text(PAGE, NpCommonDirectoryControl)
  24. #pragma alloc_text(PAGE, NpFsdDirectoryControl)
  25. #pragma alloc_text(PAGE, NpQueryDirectory)
  26. #pragma alloc_text(PAGE, NpNotifyChangeDirectory)
  27. #endif
  28. NTSTATUS
  29. NpFsdDirectoryControl (
  30. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  31. IN PIRP Irp
  32. )
  33. /*++
  34. Routine Description:
  35. This routine is the FSD routine that handles directory control
  36. functions (i.e., query and notify).
  37. Arguments:
  38. NpfsDeviceObject - Supplies the device object for the directory function.
  39. Irp - Supplies the IRP to process
  40. Return Value:
  41. NTSTATUS - The appropriate result status
  42. --*/
  43. {
  44. NTSTATUS Status;
  45. PAGED_CODE();
  46. DebugTrace(+1, Dbg, "NpFsdDirectoryControl\n", 0);
  47. //
  48. // Call the common Direcotry Control routine.
  49. //
  50. FsRtlEnterFileSystem();
  51. NpAcquireExclusiveVcb( );
  52. Status = NpCommonDirectoryControl( NpfsDeviceObject, Irp );
  53. NpReleaseVcb();
  54. FsRtlExitFileSystem();
  55. if (Status != STATUS_PENDING) {
  56. NpCompleteRequest (Irp, Status);
  57. }
  58. //
  59. // And return to our caller
  60. //
  61. DebugTrace(-1, Dbg, "NpFsdDirectoryControl -> %08lx\n", Status );
  62. return Status;
  63. }
  64. VOID
  65. NpCheckForNotify (
  66. IN PDCB Dcb,
  67. IN BOOLEAN CheckAllOutstandingIrps,
  68. IN PLIST_ENTRY DeferredList
  69. )
  70. /*++
  71. Routine Description:
  72. This routine checks the notify queues of a dcb and completes any
  73. outstanding IRPS.
  74. Note that the caller of this procedure must guarantee that the DCB
  75. is acquired for exclusive access.
  76. Arguments:
  77. Dcb - Supplies the Dcb to check if is has any notify Irps outstanding
  78. CheckAllOutstandingIrps - Indicates if only the NotifyFullQueue should be
  79. checked. If TRUE then all notify queues are checked, and if FALSE
  80. then only the NotifyFullQueue is checked.
  81. Return Value:
  82. None.
  83. --*/
  84. {
  85. PLIST_ENTRY Links;
  86. PIRP Irp;
  87. PAGED_CODE();
  88. //
  89. // We'll always signal the notify full queue entries. They want
  90. // to be notified if every any change is made to a directory
  91. //
  92. while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyFullQueue )) {
  93. //
  94. // Remove the Irp from the head of the queue, and complete it
  95. // with success.
  96. //
  97. Links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyFullQueue );
  98. Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  99. if (IoSetCancelRoutine (Irp, NULL) != NULL) {
  100. NpDeferredCompleteRequest( Irp, STATUS_SUCCESS, DeferredList );
  101. } else {
  102. InitializeListHead (&Irp->Tail.Overlay.ListEntry);
  103. }
  104. }
  105. //
  106. // Now check if we should also do the partial notify queue.
  107. //
  108. if (CheckAllOutstandingIrps) {
  109. while (!IsListEmpty( &Dcb->Specific.Dcb.NotifyPartialQueue )) {
  110. //
  111. // Remove the Irp from the head of the queue, and complete it
  112. // with success.
  113. //
  114. Links = RemoveHeadList( &Dcb->Specific.Dcb.NotifyPartialQueue );
  115. Irp = CONTAINING_RECORD( Links, IRP, Tail.Overlay.ListEntry );
  116. if (IoSetCancelRoutine (Irp, NULL) != NULL) {
  117. NpDeferredCompleteRequest( Irp, STATUS_SUCCESS, DeferredList );
  118. } else {
  119. InitializeListHead (&Irp->Tail.Overlay.ListEntry);
  120. }
  121. }
  122. }
  123. return;
  124. }
  125. //
  126. // Local Support Routine
  127. //
  128. NTSTATUS
  129. NpCommonDirectoryControl (
  130. IN PNPFS_DEVICE_OBJECT NpfsDeviceObject,
  131. IN PIRP Irp
  132. )
  133. /*++
  134. Routine Description:
  135. This routine does the common code for directory control functions.
  136. Arguments:
  137. NpfsDeviceObject - Supplies the named pipe device object
  138. Irp - Supplies the Irp being processed
  139. Return Value:
  140. NTSTATUS - The return status for the operation
  141. --*/
  142. {
  143. NTSTATUS Status;
  144. PIO_STACK_LOCATION IrpSp;
  145. PFCB Fcb;
  146. PROOT_DCB_CCB Ccb;
  147. PAGED_CODE();
  148. //
  149. // Get the current stack location
  150. //
  151. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  152. DebugTrace(+1, Dbg, "NpCommonDirectoryControl...\n", 0);
  153. DebugTrace( 0, Dbg, "Irp = %08lx\n", Irp);
  154. //
  155. // Decode the file object to figure out who we are. If the result
  156. // is not the root dcb then its an illegal parameter.
  157. //
  158. if (NpDecodeFileObject( IrpSp->FileObject,
  159. &Fcb,
  160. (PCCB *)&Ccb,
  161. NULL ) != NPFS_NTC_ROOT_DCB) {
  162. DebugTrace(0, Dbg, "Not a directory\n", 0);
  163. Status = STATUS_INVALID_PARAMETER;
  164. DebugTrace(-1, Dbg, "NpCommonDirectoryControl -> %08lx\n", Status );
  165. return Status;
  166. }
  167. //
  168. // We know this is a directory control so we'll case on the
  169. // minor function, and call the appropriate work routines.
  170. //
  171. switch (IrpSp->MinorFunction) {
  172. case IRP_MN_QUERY_DIRECTORY:
  173. Status = NpQueryDirectory( Fcb, Ccb, Irp );
  174. break;
  175. case IRP_MN_NOTIFY_CHANGE_DIRECTORY:
  176. Status = NpNotifyChangeDirectory( Fcb, Ccb, Irp );
  177. break;
  178. default:
  179. //
  180. // For all other minor function codes we say they're invalid
  181. // and complete the request.
  182. //
  183. DebugTrace(0, DEBUG_TRACE_ERROR, "Invalid FS Control Minor Function Code %08lx\n", IrpSp->MinorFunction);
  184. Status = STATUS_INVALID_DEVICE_REQUEST;
  185. break;
  186. }
  187. DebugTrace(-1, Dbg, "NpCommonDirectoryControl -> %08lx\n", Status);
  188. return Status;
  189. }
  190. //
  191. // Internal support routine
  192. //
  193. NTSTATUS
  194. NpQueryDirectory (
  195. IN PROOT_DCB RootDcb,
  196. IN PROOT_DCB_CCB Ccb,
  197. IN PIRP Irp
  198. )
  199. /*++
  200. Routine Description:
  201. This is the work routine for querying a directory.
  202. Arugments:
  203. RootDcb - Supplies the dcb being queried
  204. Ccb - Supplies the context of the caller
  205. Irp - Supplies the Irp being processed
  206. Return Value:
  207. NTSTATUS - The return status for the operation.
  208. --*/
  209. {
  210. NTSTATUS Status;
  211. PIO_STACK_LOCATION IrpSp;
  212. PUCHAR Buffer;
  213. CLONG SystemBufferLength;
  214. UNICODE_STRING FileName;
  215. ULONG FileIndex;
  216. FILE_INFORMATION_CLASS FileInformationClass;
  217. BOOLEAN RestartScan;
  218. BOOLEAN ReturnSingleEntry;
  219. BOOLEAN IndexSpecified;
  220. static WCHAR Star = L'*';
  221. BOOLEAN CaseInsensitive = TRUE; //*** Make searches case insensitive
  222. ULONG CurrentIndex;
  223. ULONG LastEntry;
  224. ULONG NextEntry;
  225. PLIST_ENTRY Links;
  226. PFCB Fcb;
  227. PFILE_DIRECTORY_INFORMATION DirInfo;
  228. PFILE_NAMES_INFORMATION NamesInfo;
  229. PAGED_CODE();
  230. //
  231. // Get the current stack location
  232. //
  233. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  234. DebugTrace(+1, Dbg, "NpQueryDirectory\n", 0 );
  235. DebugTrace( 0, Dbg, "RootDcb = %08lx\n", RootDcb);
  236. DebugTrace( 0, Dbg, "Ccb = %08lx\n", Ccb);
  237. DebugTrace( 0, Dbg, "SystemBuffer = %08lx\n", Irp->AssociatedIrp.SystemBuffer);
  238. DebugTrace( 0, Dbg, "Length = %08lx\n", IrpSp->Parameters.QueryDirectory.Length);
  239. DebugTrace( 0, Dbg, "FileName = %Z\n", IrpSp->Parameters.QueryDirectory.FileName);
  240. DebugTrace( 0, Dbg, "FileIndex = %08lx\n", IrpSp->Parameters.QueryDirectory.FileIndex);
  241. DebugTrace( 0, Dbg, "FileInformationClass = %08lx\n", IrpSp->Parameters.QueryDirectory.FileInformationClass);
  242. DebugTrace( 0, Dbg, "RestartScan = %08lx\n", FlagOn(IrpSp->Flags, SL_RESTART_SCAN));
  243. DebugTrace( 0, Dbg, "ReturnSingleEntry = %08lx\n", FlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY));
  244. DebugTrace( 0, Dbg, "IndexSpecified = %08lx\n", FlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED));
  245. //
  246. // Save references to the input parameters within the Irp
  247. //
  248. SystemBufferLength = IrpSp->Parameters.QueryDirectory.Length;
  249. FileIndex = IrpSp->Parameters.QueryDirectory.FileIndex;
  250. FileInformationClass = IrpSp->Parameters.QueryDirectory.FileInformationClass;
  251. RestartScan = BooleanFlagOn(IrpSp->Flags, SL_RESTART_SCAN);
  252. ReturnSingleEntry = BooleanFlagOn(IrpSp->Flags, SL_RETURN_SINGLE_ENTRY);
  253. IndexSpecified = BooleanFlagOn(IrpSp->Flags, SL_INDEX_SPECIFIED);
  254. if (IrpSp->Parameters.QueryDirectory.FileName != NULL) {
  255. FileName = *(IrpSp->Parameters.QueryDirectory.FileName);
  256. //
  257. // Make sure that the user called us with a proper unicode string.
  258. // We will reject odd length file names (i.e., lengths with the low
  259. // bit set)
  260. //
  261. if (FileName.Length & 0x1) {
  262. return STATUS_INVALID_PARAMETER;
  263. }
  264. } else {
  265. FileName.Length = 0;
  266. FileName.Buffer = NULL;
  267. }
  268. //
  269. // Check if the ccb already has a query template attached. If it
  270. // does not already have one then we either use the string we are
  271. // given or we attach our own containing "*"
  272. //
  273. if (Ccb->QueryTemplate == NULL) {
  274. //
  275. // This is our first time calling query directory so we need
  276. // to either set the query template to the user specified string
  277. // or to "*"
  278. //
  279. if (FileName.Buffer == NULL) {
  280. DebugTrace(0, Dbg, "Set template to *\n", 0);
  281. FileName.Length = 2;
  282. FileName.Buffer = ⋆
  283. }
  284. DebugTrace(0, Dbg, "Set query template -> %Z\n", &FileName);
  285. //
  286. // Allocate space for the query template
  287. //
  288. Ccb->QueryTemplate = NpAllocatePagedPoolWithQuota(sizeof(UNICODE_STRING) + FileName.Length, 'qFpN' );
  289. if (Ccb->QueryTemplate == NULL) {
  290. return STATUS_INSUFFICIENT_RESOURCES;
  291. }
  292. //
  293. // Initialize the query template and copy over the string
  294. //
  295. Ccb->QueryTemplate->Length = FileName.Length;
  296. Ccb->QueryTemplate->Buffer = (PWCH)Ccb->QueryTemplate +
  297. sizeof(UNICODE_STRING) / sizeof(WCHAR);
  298. RtlCopyMemory( Ccb->QueryTemplate->Buffer,
  299. FileName.Buffer,
  300. FileName.Length );
  301. //
  302. // Now zero out the FileName so we won't think we're to use it
  303. // as a subsearch string.
  304. //
  305. FileName.Length = 0;
  306. FileName.Buffer = NULL;
  307. }
  308. //
  309. // Check if we were given an index to start with or if we need to
  310. // restart the scan or if we should use the index that was saved in
  311. // the ccb
  312. //
  313. if (RestartScan) {
  314. FileIndex = 0;
  315. } else if (!IndexSpecified) {
  316. FileIndex = Ccb->IndexOfLastCcbReturned + 1;
  317. }
  318. //
  319. // Now we are committed to completing the Irp, we do that in
  320. // the finally clause of the following try.
  321. //
  322. try {
  323. ULONG BaseLength;
  324. ULONG LengthAdded;
  325. BOOLEAN Match;
  326. //
  327. // Map the user buffer
  328. //
  329. Buffer = NpMapUserBuffer( Irp );
  330. //
  331. // At this point we are about to enter our query loop. We have
  332. // already decided which Fcb index we need to return. The variables
  333. // LastEntry and NextEntry are used to index into the user buffer.
  334. // LastEntry is the last entry we added to the user buffer, and
  335. // NextEntry is the current one we're working on. CurrentIndex
  336. // is the Fcb index that we are looking at next. Logically the
  337. // way the loop works is as follows.
  338. //
  339. // Scan all of the Fcb in the directory
  340. //
  341. // if the Fcb matches the query template then
  342. //
  343. // if the CurrentIndex is >= the FileIndex then
  344. //
  345. // process this fcb, and decide if we should
  346. // continue the main loop
  347. //
  348. // end if
  349. //
  350. // Increment the current index
  351. //
  352. // end if
  353. //
  354. // end scan
  355. //
  356. CurrentIndex = 0;
  357. LastEntry = 0;
  358. NextEntry =0;
  359. switch (FileInformationClass) {
  360. case FileDirectoryInformation:
  361. BaseLength = FIELD_OFFSET( FILE_DIRECTORY_INFORMATION,
  362. FileName[0] );
  363. break;
  364. case FileFullDirectoryInformation:
  365. BaseLength = FIELD_OFFSET( FILE_FULL_DIR_INFORMATION,
  366. FileName[0] );
  367. break;
  368. case FileNamesInformation:
  369. BaseLength = FIELD_OFFSET( FILE_NAMES_INFORMATION,
  370. FileName[0] );
  371. break;
  372. case FileBothDirectoryInformation:
  373. BaseLength = FIELD_OFFSET( FILE_BOTH_DIR_INFORMATION,
  374. FileName[0] );
  375. break;
  376. default:
  377. try_return( Status = STATUS_INVALID_INFO_CLASS );
  378. }
  379. for (Links = RootDcb->Specific.Dcb.ParentDcbQueue.Flink;
  380. Links != &RootDcb->Specific.Dcb.ParentDcbQueue;
  381. Links = Links->Flink) {
  382. Fcb = CONTAINING_RECORD(Links, FCB, ParentDcbLinks);
  383. ASSERT(Fcb->NodeTypeCode == NPFS_NTC_FCB);
  384. DebugTrace(0, Dbg, "Top of Loop\n", 0);
  385. DebugTrace(0, Dbg, "Fcb = %08lx\n", Fcb);
  386. DebugTrace(0, Dbg, "CurrentIndex = %08lx\n", CurrentIndex);
  387. DebugTrace(0, Dbg, "FileIndex = %08lx\n", FileIndex);
  388. DebugTrace(0, Dbg, "LastEntry = %08lx\n", LastEntry);
  389. DebugTrace(0, Dbg, "NextEntry = %08lx\n", NextEntry);
  390. //
  391. // Check if the Fcb represents a named pipe that is part of
  392. // our query template
  393. //
  394. try {
  395. Match = FsRtlIsNameInExpression( Ccb->QueryTemplate,
  396. &Fcb->LastFileName,
  397. CaseInsensitive,
  398. NULL );
  399. } except (EXCEPTION_EXECUTE_HANDLER) {
  400. try_return( Status = GetExceptionCode ());
  401. }
  402. if (Match) {
  403. //
  404. // The fcb is in the query template so now check if
  405. // this is the index we should start returning
  406. //
  407. if (CurrentIndex >= FileIndex) {
  408. ULONG BytesToCopy;
  409. ULONG BytesRemainingInBuffer;
  410. //
  411. // Here are the rules concerning filling up the buffer:
  412. //
  413. // 1. The Io system garentees that there will always be
  414. // enough room for at least one base record.
  415. //
  416. // 2. If the full first record (including file name) cannot
  417. // fit, as much of the name as possible is copied and
  418. // STATUS_BUFFER_OVERFLOW is returned.
  419. //
  420. // 3. If a subsequent record cannot completely fit into the
  421. // buffer, none of it (as in 0 bytes) is copied, and
  422. // STATUS_SUCCESS is returned. A subsequent query will
  423. // pick up with this record.
  424. //
  425. BytesRemainingInBuffer = SystemBufferLength - NextEntry;
  426. if ( (NextEntry != 0) &&
  427. ( (BaseLength + Fcb->LastFileName.Length > BytesRemainingInBuffer) ||
  428. (SystemBufferLength < NextEntry) ) ) {
  429. DebugTrace(0, Dbg, "Next entry won't fit\n", 0);
  430. try_return( Status = STATUS_SUCCESS );
  431. }
  432. ASSERT( BytesRemainingInBuffer >= BaseLength );
  433. //
  434. // See how much of the name we will be able to copy into
  435. // the system buffer. This also dictates out return
  436. // value.
  437. //
  438. if ( BaseLength + Fcb->LastFileName.Length <=
  439. BytesRemainingInBuffer ) {
  440. BytesToCopy = Fcb->LastFileName.Length;
  441. Status = STATUS_SUCCESS;
  442. } else {
  443. BytesToCopy = BytesRemainingInBuffer - BaseLength;
  444. Status = STATUS_BUFFER_OVERFLOW;
  445. }
  446. //
  447. // Note how much of buffer we are consuming and zero
  448. // the base part of the structure. Protect our access
  449. // because it is the user's buffer.
  450. //
  451. LengthAdded = BaseLength + BytesToCopy;
  452. try {
  453. RtlZeroMemory( &Buffer[NextEntry], BaseLength );
  454. } except (EXCEPTION_EXECUTE_HANDLER) {
  455. try_return (Status = GetExceptionCode ());
  456. }
  457. //
  458. // Now fill the base parts of the strucure that are
  459. // applicable.
  460. //
  461. switch (FileInformationClass) {
  462. case FileBothDirectoryInformation:
  463. //
  464. // We don't need short name
  465. //
  466. DebugTrace(0, Dbg, "Getting directory full information\n", 0);
  467. case FileFullDirectoryInformation:
  468. //
  469. // We don't use EaLength, so fill in nothing here.
  470. //
  471. DebugTrace(0, Dbg, "Getting directory full information\n", 0);
  472. case FileDirectoryInformation:
  473. DebugTrace(0, Dbg, "Getting directory information\n", 0);
  474. //
  475. // The eof indicates the number of instances and
  476. // allocation size is the maximum allowed. Protect
  477. // our access because it is the user's buffer.
  478. //
  479. DirInfo = (PFILE_DIRECTORY_INFORMATION)&Buffer[NextEntry];
  480. try {
  481. DirInfo->EndOfFile.QuadPart = Fcb->OpenCount;
  482. DirInfo->AllocationSize.QuadPart = Fcb->Specific.Fcb.MaximumInstances;
  483. DirInfo->FileAttributes = FILE_ATTRIBUTE_NORMAL;
  484. DirInfo->FileNameLength = Fcb->LastFileName.Length;
  485. } except (EXCEPTION_EXECUTE_HANDLER) {
  486. try_return (Status = GetExceptionCode ());
  487. }
  488. break;
  489. case FileNamesInformation:
  490. DebugTrace(0, Dbg, "Getting names information\n", 0);
  491. //
  492. // Proctect our access because it is the user's buffer
  493. //
  494. NamesInfo = (PFILE_NAMES_INFORMATION)&Buffer[NextEntry];
  495. try {
  496. NamesInfo->FileNameLength = Fcb->LastFileName.Length;
  497. } except (EXCEPTION_EXECUTE_HANDLER) {
  498. try_return (Status = GetExceptionCode ());
  499. }
  500. break;
  501. default:
  502. NpBugCheck( FileInformationClass, 0, 0 );
  503. }
  504. //
  505. // Protect our access because it is the user's buffer
  506. //
  507. try {
  508. RtlCopyMemory( &Buffer[NextEntry + BaseLength],
  509. Fcb->LastFileName.Buffer,
  510. BytesToCopy );
  511. } except (EXCEPTION_EXECUTE_HANDLER) {
  512. try_return (Status = GetExceptionCode ());
  513. }
  514. //
  515. // Update the ccb to the index we've just used
  516. //
  517. Ccb->IndexOfLastCcbReturned = CurrentIndex;
  518. //
  519. // And indicate how much of the system buffer we have
  520. // currently used up. We must compute this value before
  521. // we long align outselves for the next entry
  522. //
  523. Irp->IoStatus.Information = NextEntry + LengthAdded;
  524. //
  525. // Setup the previous next entry offset. Protect our
  526. // access because it is the user's buffer.
  527. //
  528. try {
  529. *((PULONG)(&Buffer[LastEntry])) = NextEntry - LastEntry;
  530. } except (EXCEPTION_EXECUTE_HANDLER) {
  531. try_return (Status = GetExceptionCode ());
  532. }
  533. //
  534. // Check if the last entry didn't completely fit
  535. //
  536. if ( Status == STATUS_BUFFER_OVERFLOW ) {
  537. try_return( NOTHING );
  538. }
  539. //
  540. // Check if we are only to return a single entry
  541. //
  542. if (ReturnSingleEntry) {
  543. try_return( Status = STATUS_SUCCESS );
  544. }
  545. //
  546. // Set ourselves up for the next iteration
  547. //
  548. LastEntry = NextEntry;
  549. NextEntry += (ULONG)QuadAlign( LengthAdded );
  550. }
  551. //
  552. // Increment the current index by one
  553. //
  554. CurrentIndex += 1;
  555. }
  556. }
  557. //
  558. // At this point we've scanned the entire list of Fcb so if
  559. // the NextEntry is zero then we haven't found anything so we
  560. // will return no more files, otherwise we return success.
  561. //
  562. if (NextEntry == 0) {
  563. Status = STATUS_NO_MORE_FILES;
  564. } else {
  565. Status = STATUS_SUCCESS;
  566. }
  567. try_exit: NOTHING;
  568. } finally {
  569. DebugTrace(-1, Dbg, "NpQueryDirectory -> %08lx\n", Status);
  570. }
  571. return Status;
  572. }
  573. //
  574. // Internal support routine
  575. //
  576. NTSTATUS
  577. NpNotifyChangeDirectory (
  578. IN PROOT_DCB RootDcb,
  579. IN PROOT_DCB_CCB Ccb,
  580. IN PIRP Irp
  581. )
  582. /*++
  583. Routine Description:
  584. This is the common routine for doing the notify change directory.
  585. Arugments:
  586. RootDcb - Supplies the dcb being queried
  587. Ccb - Supplies the context of the caller
  588. Irp - Supplies the Irp being processed
  589. Return Value:
  590. NTSTATUS - STATUS_PENDING
  591. --*/
  592. {
  593. PIO_STACK_LOCATION IrpSp;
  594. PLIST_ENTRY Head;
  595. UNREFERENCED_PARAMETER( Ccb );
  596. PAGED_CODE();
  597. //
  598. // Get the current stack location
  599. //
  600. IrpSp = IoGetCurrentIrpStackLocation( Irp );
  601. DebugTrace(+1, Dbg, "NpNotifyChangeDirectory\n", 0 );
  602. DebugTrace( 0, Dbg, "RootDcb = %08lx", RootDcb);
  603. DebugTrace( 0, Dbg, "Ccb = %08lx", Ccb);
  604. if (IrpSp->Parameters.NotifyDirectory.CompletionFilter &
  605. ~FILE_NOTIFY_CHANGE_NAME) {
  606. Head = &RootDcb->Specific.Dcb.NotifyFullQueue;
  607. } else {
  608. Head = &RootDcb->Specific.Dcb.NotifyPartialQueue;
  609. }
  610. IoSetCancelRoutine( Irp, NpCancelChangeNotifyIrp );
  611. if (Irp->Cancel && IoSetCancelRoutine( Irp, NULL ) != NULL) {
  612. return STATUS_CANCELLED;
  613. } else {
  614. //
  615. // Mark the Irp pending and insert into list.
  616. //
  617. IoMarkIrpPending( Irp );
  618. InsertTailList( Head,
  619. &Irp->Tail.Overlay.ListEntry );
  620. return STATUS_PENDING;
  621. }
  622. }
  623. //
  624. // Local support routine
  625. //
  626. VOID
  627. NpCancelChangeNotifyIrp (
  628. IN PDEVICE_OBJECT DeviceObject,
  629. IN PIRP Irp
  630. )
  631. /*++
  632. Routine Description:
  633. This routine implements the cancel function for an IRP saved in a change notify
  634. queue
  635. Arguments:
  636. DeviceObject - ignored
  637. Irp - Supplies the Irp being cancelled. A pointer to the proper dcb queue
  638. is stored in the information field of the Irp Iosb field.
  639. Return Value:
  640. None.
  641. --*/
  642. {
  643. PLIST_ENTRY ListHead;
  644. UNREFERENCED_PARAMETER( DeviceObject );
  645. IoReleaseCancelSpinLock( Irp->CancelIrql );
  646. //
  647. // Get exclusive access to the named pipe vcb so we can now do our work
  648. //
  649. FsRtlEnterFileSystem();
  650. NpAcquireExclusiveVcb();
  651. RemoveEntryList( &Irp->Tail.Overlay.ListEntry );
  652. NpReleaseVcb();
  653. FsRtlExitFileSystem();
  654. NpCompleteRequest( Irp, STATUS_CANCELLED );
  655. //
  656. // And return to our caller
  657. //
  658. return;
  659. }