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.

1964 lines
56 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. context.c
  5. Abstract:
  6. This module contains all of the routines for tracking names using
  7. the new Stream Context feature. It does this by attaching a context
  8. structure to a stream whenever a new name is requested. It does
  9. properly handle when files and directories are renamed.
  10. Note that StreamContexts are a new feature in the system and are not
  11. supported by all file systems. All of the standard Microsoft file
  12. systems support them (ntfs, fat, cdfs, udfs, rdr2) but there may be 3rd
  13. party file systems that do not. This is one of the main reasons why
  14. track names by stream contexts is not enabled by default.
  15. Environment:
  16. Kernel mode
  17. // @@BEGIN_DDKSPLIT
  18. Author:
  19. Neal Christiansen (nealch) 27-Dec-2000
  20. Revision History:
  21. Ravisankar Pudipeddi (ravisp) 07-May-2002
  22. Make it work on IA64
  23. // @@END_DDKSPLIT
  24. --*/
  25. #include <ntifs.h>
  26. #include "filespy.h"
  27. #include "fspyKern.h"
  28. #if USE_STREAM_CONTEXTS
  29. #if WINVER < 0x0501
  30. #error Stream contexts on only supported on Windows XP or later.
  31. #endif
  32. ////////////////////////////////////////////////////////////////////////
  33. //
  34. // Local prototypes
  35. //
  36. ////////////////////////////////////////////////////////////////////////
  37. VOID
  38. SpyDeleteContextCallback(
  39. IN PVOID Context
  40. );
  41. //
  42. // linker commands
  43. //
  44. #ifdef ALLOC_PRAGMA
  45. #pragma alloc_text( PAGE, SpyInitDeviceNamingEnvironment )
  46. #pragma alloc_text( PAGE, SpyCleanupDeviceNamingEnvironment )
  47. #pragma alloc_text( PAGE, SpyDeleteAllContexts )
  48. #pragma alloc_text( PAGE, SpyDeleteContext )
  49. #pragma alloc_text( PAGE, SpyDeleteContextCallback )
  50. #pragma alloc_text( PAGE, SpyLinkContext )
  51. #pragma alloc_text( PAGE, SpyCreateContext )
  52. #pragma alloc_text( PAGE, SpyFindExistingContext )
  53. #pragma alloc_text( PAGE, SpyReleaseContext )
  54. #endif // ALLOC_PRAGMA
  55. ///////////////////////////////////////////////////////////////////////////
  56. //
  57. // Context support routines
  58. //
  59. ///////////////////////////////////////////////////////////////////////////
  60. VOID
  61. SpyInitNamingEnvironment(
  62. VOID
  63. )
  64. /*++
  65. Routine Description:
  66. Init global variables
  67. Arguments:
  68. None
  69. Return Value:
  70. None.
  71. --*/
  72. {
  73. }
  74. VOID
  75. SpyLogIrp (
  76. IN PIRP Irp,
  77. OUT PRECORD_LIST RecordList
  78. )
  79. /*++
  80. Routine Description:
  81. Records the Irp necessary information according to LoggingFlags in
  82. RecordList. For any activity on the Irp path of a device being
  83. logged, this function should get called twice: once on the Irp's
  84. originating path and once on the Irp's completion path.
  85. Arguments:
  86. Irp - The Irp that contains the information we want to record.
  87. LoggingFlags - The flags that say what to log.
  88. RecordList - The PRECORD_LIST in which the Irp information is stored.
  89. Context - if non-zero, an existing context record for this entry.
  90. Return Value:
  91. None.
  92. --*/
  93. {
  94. PRECORD_IRP pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
  95. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
  96. PDEVICE_OBJECT deviceObject;
  97. PFILESPY_DEVICE_EXTENSION devExt;
  98. PSPY_STREAM_CONTEXT pContext;
  99. NAME_LOOKUP_FLAGS lookupFlags = 0;
  100. NTSTATUS status;
  101. FILE_STANDARD_INFORMATION standardInformation;
  102. //
  103. // Init locals
  104. //
  105. deviceObject = pIrpStack->DeviceObject;
  106. devExt = deviceObject->DeviceExtension;
  107. //
  108. // Record the information we use for an originating Irp. We first
  109. // need to initialize some of the RECORD_LIST and RECORD_IRP fields.
  110. // Then get the interesting information from the Irp.
  111. //
  112. SetFlag( RecordList->LogRecord.RecordType, RECORD_TYPE_IRP );
  113. pRecordIrp->IrpMajor = pIrpStack->MajorFunction;
  114. pRecordIrp->IrpMinor = pIrpStack->MinorFunction;
  115. pRecordIrp->IrpFlags = Irp->Flags;
  116. pRecordIrp->FileObject = (FILE_ID)pIrpStack->FileObject;
  117. pRecordIrp->DeviceObject = (FILE_ID)deviceObject;
  118. pRecordIrp->ProcessId = (FILE_ID)PsGetCurrentProcessId();
  119. pRecordIrp->ThreadId = (FILE_ID)PsGetCurrentThreadId();
  120. pRecordIrp->Argument1 = pIrpStack->Parameters.Others.Argument1;
  121. pRecordIrp->Argument2 = pIrpStack->Parameters.Others.Argument2;
  122. pRecordIrp->Argument3 = pIrpStack->Parameters.Others.Argument3;
  123. pRecordIrp->Argument4 = pIrpStack->Parameters.Others.Argument4;
  124. KeQuerySystemTime( &pRecordIrp->OriginatingTime );
  125. //
  126. // Do different things based on the operation
  127. //
  128. switch (pIrpStack->MajorFunction) {
  129. case IRP_MJ_CREATE:
  130. //
  131. // OPEN/CREATE file
  132. //
  133. // Only record the desired access if this is a CREATE irp.
  134. //
  135. pRecordIrp->DesiredAccess = pIrpStack->Parameters.Create.SecurityContext->DesiredAccess;
  136. //
  137. // Set out name lookup state
  138. //
  139. SetFlag( lookupFlags, NLFL_IN_CREATE );
  140. //
  141. // Flag if opening the directory of the given file
  142. //
  143. if (FlagOn( pIrpStack->Flags, SL_OPEN_TARGET_DIRECTORY )) {
  144. SetFlag( lookupFlags, NLFL_OPEN_TARGET_DIR );
  145. }
  146. //
  147. // Set if opening by ID
  148. //
  149. if (FlagOn( pIrpStack->Parameters.Create.Options, FILE_OPEN_BY_FILE_ID )) {
  150. SetFlag( lookupFlags, NLFL_OPEN_BY_ID );
  151. }
  152. //
  153. // We are in pre-create, we can not attach a context to the file
  154. // object yet so simply create a context. If it fails no name
  155. // will be logged.
  156. // Note: We may already have a context on this file but we can't
  157. // find it yet because the FsContext field is not setup yet.
  158. // We go ahead and get a context so we will have a name if
  159. // the operations fails. We will detect the duplicate
  160. // context during the post-create and delete the new one.
  161. //
  162. status = SpyCreateContext( deviceObject,
  163. pIrpStack->FileObject,
  164. lookupFlags,
  165. &pContext );
  166. if (NT_SUCCESS(status)) {
  167. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  168. ("FileSpy!SpyLogIrp: Created (%p) Fl=%02x Use=%d \"%wZ\"\n",
  169. pContext,
  170. pContext->Flags,
  171. pContext->UseCount,
  172. &pContext->Name) );
  173. //
  174. // If a context was found save it and mark that to sync back
  175. // to the dispatch routine to complete this operation.
  176. //
  177. ASSERT(RecordList->NewContext == NULL);
  178. RecordList->NewContext = pContext;
  179. SetFlag( RecordList->Flags, RLFL_SYNC_TO_DISPATCH );
  180. }
  181. break;
  182. case IRP_MJ_CLOSE:
  183. //
  184. // CLOSE FILE
  185. //
  186. // If this is a close we can only look up the name in the name
  187. // cache. It is possible that the close could be occurring
  188. // during a cleanup operation in the file system (i.e., before we
  189. // have received the cleanup completion) and requesting the name
  190. // would cause a deadlock in the file system.
  191. //
  192. SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
  193. break;
  194. case IRP_MJ_SET_INFORMATION:
  195. if (FileRenameInformation ==
  196. pIrpStack->Parameters.SetFile.FileInformationClass)
  197. {
  198. //
  199. // RENAME FILE
  200. //
  201. // We are doing a rename. First get a context for the
  202. // given file. If this fails, mark that we don't want to
  203. // try and lookup a name.
  204. //
  205. status = SpyGetContext( deviceObject,
  206. pIrpStack->FileObject,
  207. lookupFlags,
  208. &pContext );
  209. if (!NT_SUCCESS(status)) {
  210. //
  211. // If we couldn't get a context simply delete all
  212. // existing ones (since we don't know what this rename
  213. // will change) and mark not to do a lookup.
  214. //
  215. SetFlag( lookupFlags, NLFL_NO_LOOKUP );
  216. SpyDeleteAllContexts( deviceObject );
  217. break;
  218. }
  219. //
  220. // We retrieved a context, save it in the record and mark
  221. // that we want to handle this during post rename.
  222. //
  223. ASSERT(RecordList->NewContext == NULL);
  224. RecordList->NewContext = pContext;
  225. SetFlag( RecordList->Flags, RLFL_SYNC_TO_DISPATCH );
  226. //
  227. // We need to decide if we are renaming a file or a
  228. // directory because we need to handle this differently
  229. //
  230. status = SpyQueryInformationFile( devExt->AttachedToDeviceObject,
  231. pIrpStack->FileObject,
  232. &standardInformation,
  233. sizeof( standardInformation ),
  234. FileStandardInformation,
  235. NULL );
  236. if (!NT_SUCCESS(status)) {
  237. //
  238. // We can't tell if it is a file or directory, assume
  239. // the worst case and handle it like a directory.
  240. //
  241. InterlockedIncrement( &devExt->AllContextsTemporary );
  242. SpyDeleteAllContexts( deviceObject );
  243. SetFlag( RecordList->Flags, RLFL_IS_DIRECTORY );
  244. break;
  245. }
  246. if (standardInformation.Directory) {
  247. //
  248. // Renaming a directory. Mark that any contexts
  249. // created while the rename is in progress should be
  250. // temporary. This way there is no window where
  251. // we may get an old stale name. Then delete all
  252. // existing contexts. NOTE: the context we hold will
  253. // not actually be deleted until we release it.
  254. //
  255. InterlockedIncrement( &devExt->AllContextsTemporary );
  256. SpyDeleteAllContexts( deviceObject );
  257. SetFlag( RecordList->Flags, RLFL_IS_DIRECTORY );
  258. } else {
  259. //
  260. // We are renaming a file. Mark the context so it will
  261. // not be used. This way if someone accesses this file
  262. // while it is being renamed they will lookup the
  263. // name again so we will always get an accurate name.
  264. // This context will be deleted during post rename
  265. // processing
  266. //
  267. SetFlag( pContext->Flags, CTXFL_DoNotUse);
  268. }
  269. }
  270. break;
  271. }
  272. //
  273. // If the flag IRP_PAGING_IO is set in this IRP, we cannot query the name
  274. // because it can lead to deadlocks. Therefore, add in the flag so that
  275. // we will only try to find the name in our cache.
  276. //
  277. if (FlagOn( Irp->Flags, IRP_PAGING_IO )) {
  278. ASSERT( !FlagOn( lookupFlags, NLFL_NO_LOOKUP ) );
  279. SetFlag( lookupFlags, NLFL_ONLY_CHECK_CACHE );
  280. }
  281. SpySetName( RecordList,
  282. deviceObject,
  283. pIrpStack->FileObject,
  284. lookupFlags,
  285. (PSPY_STREAM_CONTEXT)RecordList->NewContext );
  286. }
  287. VOID
  288. SpyLogIrpCompletion(
  289. IN PIRP Irp,
  290. PRECORD_LIST RecordList
  291. )
  292. /*++
  293. Routine Description:
  294. This routine performs post-operation logging of the IRP.
  295. Arguments:
  296. DeviceObject - Pointer to device object FileSpy attached to the file system
  297. filter stack for the volume receiving this I/O request.
  298. Irp - Pointer to the request packet representing the I/O request.
  299. Record - RecordList
  300. Return Value:
  301. None.
  302. --*/
  303. {
  304. PIO_STACK_LOCATION pIrpStack = IoGetCurrentIrpStackLocation(Irp);
  305. PRECORD_IRP pRecordIrp;
  306. PDEVICE_OBJECT deviceObject;
  307. PFILESPY_DEVICE_EXTENSION devExt;
  308. PSPY_STREAM_CONTEXT pContext;
  309. //
  310. // Init locals
  311. //
  312. deviceObject = pIrpStack->DeviceObject;
  313. devExt = deviceObject->DeviceExtension;
  314. ASSERT(deviceObject ==
  315. (PDEVICE_OBJECT)RecordList->LogRecord.Record.RecordIrp.DeviceObject);
  316. //
  317. // Do completion processing based on the operation
  318. //
  319. switch (pIrpStack->MajorFunction) {
  320. case IRP_MJ_CREATE:
  321. //
  322. // CREATE FILE
  323. //
  324. // NOTE: When processing CREATE completion IRPS this completion
  325. // routine is never called at DISPATCH level, it is always
  326. // synchronized back to the dispatch routine. This is
  327. // controlled by the setting of the RLFL_SYNC_TO_DISPATCH
  328. // flag in the log record.
  329. //
  330. if (NULL != (pContext = RecordList->NewContext)) {
  331. //
  332. // Mark context field so it won't be freed later
  333. //
  334. RecordList->NewContext = NULL;
  335. //
  336. // If the operation succeeded and an FsContext is defined,
  337. // then attach the context. Else when the context is
  338. // released it will be freed.
  339. //
  340. if (NT_SUCCESS(Irp->IoStatus.Status) &&
  341. (NULL != pIrpStack->FileObject->FsContext)) {
  342. SpyLinkContext( deviceObject,
  343. pIrpStack->FileObject,
  344. &pContext );
  345. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  346. ("FileSpy!SpyLogIrpCompletion: Link (%p) Fl=%02x Use=%d \"%wZ\"\n",
  347. pContext,
  348. pContext->Flags,
  349. pContext->UseCount,
  350. &pContext->Name) );
  351. }
  352. //
  353. // Now release the context
  354. //
  355. SpyReleaseContext( pContext );
  356. }
  357. break;
  358. case IRP_MJ_SET_INFORMATION:
  359. if (FileRenameInformation ==
  360. pIrpStack->Parameters.SetFile.FileInformationClass)
  361. {
  362. //
  363. // RENAMING FILE
  364. //
  365. // NOTE: When processing RENAME completion IRPS this
  366. // completion routine is never called at DISPATCH level,
  367. // it is always synchronized back to the dispatch
  368. // routine. This is controlled by the setting of the
  369. // RLFL_SYNC_TO_DISPATCH flag in the log record.
  370. //
  371. if (NULL != (pContext = RecordList->NewContext)) {
  372. //
  373. // Mark context field so it won't be freed later
  374. //
  375. RecordList->NewContext = NULL;
  376. //
  377. // See if renaming a directory
  378. //
  379. if (FlagOn(RecordList->Flags,RLFL_IS_DIRECTORY)) {
  380. //
  381. // We were renaming a directory, decrement the
  382. // AllContexts temporary flag. We need to always
  383. // do this, even on a failure
  384. //
  385. ASSERT(devExt->AllContextsTemporary > 0);
  386. InterlockedDecrement( &devExt->AllContextsTemporary );
  387. ASSERT(!FlagOn(pContext->Flags,CTXFL_DoNotUse));
  388. } else {
  389. //
  390. // We were renaming a file, delete the given context
  391. // if the operation was successful
  392. //
  393. ASSERT(FlagOn(pContext->Flags,CTXFL_DoNotUse));
  394. if (NT_SUCCESS(Irp->IoStatus.Status)) {
  395. SpyDeleteContext( deviceObject, pContext );
  396. }
  397. }
  398. SpyReleaseContext( pContext );
  399. }
  400. }
  401. break;
  402. default:
  403. //
  404. // Validate this field isn't set for anything else
  405. //
  406. ASSERT(RecordList->NewContext == NULL);
  407. break;
  408. }
  409. //
  410. // Process the log record
  411. //
  412. if (SHOULD_LOG( deviceObject )) {
  413. pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
  414. //
  415. // Record the information we use for a completion Irp.
  416. //
  417. pRecordIrp->ReturnStatus = Irp->IoStatus.Status;
  418. pRecordIrp->ReturnInformation = Irp->IoStatus.Information;
  419. KeQuerySystemTime(&pRecordIrp->CompletionTime);
  420. //
  421. // Add recordList to our gOutputBufferList so that it gets up to
  422. // the user
  423. //
  424. SpyLog( RecordList );
  425. } else {
  426. if (RecordList) {
  427. //
  428. // Context is set with a RECORD_LIST, but we are no longer
  429. // logging so free this record.
  430. //
  431. SpyFreeRecord( RecordList );
  432. }
  433. }
  434. }
  435. VOID
  436. SpySetName (
  437. IN PRECORD_LIST RecordList,
  438. IN PDEVICE_OBJECT DeviceObject,
  439. IN PFILE_OBJECT FileObject,
  440. IN NAME_LOOKUP_FLAGS LookupFlags,
  441. IN PSPY_STREAM_CONTEXT Context OPTIONAL
  442. )
  443. /*++
  444. Routine Description:
  445. This routine is used to set the file name. This routine first tries to
  446. locate a context structure associated with the given stream. If one is
  447. found the name is used from it. If not found the name is looked up, and
  448. a context structure is created and attached to the given stream.
  449. In all cases some sort of name will be set.
  450. Arguments:
  451. RecordList - RecordList to copy name to.
  452. LookupFlags - holds state flags for the lookup
  453. Context - optional context parameter. If not defined one will be looked
  454. up.
  455. Return Value:
  456. None.
  457. --*/
  458. {
  459. PRECORD_IRP pRecordIrp = &RecordList->LogRecord.Record.RecordIrp;
  460. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  461. BOOLEAN releaseContext = FALSE;
  462. UNICODE_STRING fileName;
  463. WCHAR fileNameBuffer[MAX_PATH];
  464. ASSERT(IS_FILESPY_DEVICE_OBJECT( DeviceObject ));
  465. if (!ARGUMENT_PRESENT(Context) &&
  466. !FlagOn(LookupFlags,NLFL_NO_LOOKUP)) {
  467. //
  468. // If no FileObject, just return
  469. //
  470. if (NULL == FileObject) {
  471. return;
  472. }
  473. //
  474. // This will set the return context to NULL if no context
  475. // could be created.
  476. //
  477. SpyGetContext( DeviceObject,
  478. FileObject,
  479. LookupFlags,
  480. &Context );
  481. //
  482. // Mark that we need to release this context (since we grabbed it)
  483. //
  484. releaseContext = TRUE;
  485. }
  486. //
  487. // If we got a context, use the name from it. If we didn't, at least
  488. // put the device name out there
  489. //
  490. if (NULL != Context) {
  491. SpyCopyFileNameToLogRecord( &RecordList->LogRecord,
  492. &Context->Name );
  493. } else {
  494. SPY_LOG_PRINT( SPYDEBUG_TRACE_DETAILED_CONTEXT_OPS,
  495. ("FileSpy!SpySetName: NoCtx \"%wZ\"\n",
  496. &devExt->UserNames) );
  497. RtlInitEmptyUnicodeString( &fileName,
  498. fileNameBuffer,
  499. sizeof(fileNameBuffer) );
  500. RtlCopyUnicodeString( &fileName, &devExt->UserNames );
  501. RtlAppendUnicodeToString( &fileName,
  502. L"[-=Context Allocate Failed=-]" );
  503. SpyCopyFileNameToLogRecord( &RecordList->LogRecord,
  504. &fileName );
  505. }
  506. //
  507. // Release the context if we grabbed it in this routine
  508. //
  509. if ((NULL != Context) && releaseContext) {
  510. SpyReleaseContext( Context );
  511. }
  512. }
  513. VOID
  514. SpyNameDeleteAllNames()
  515. /*++
  516. Routine Description:
  517. This routine will walk through all attaches volumes and delete all
  518. contexts in each volume.
  519. Arguments:
  520. None
  521. Return Value:
  522. None
  523. --*/
  524. {
  525. PLIST_ENTRY link;
  526. PFILESPY_DEVICE_EXTENSION devExt;
  527. ExAcquireFastMutex( &gSpyDeviceExtensionListLock );
  528. for (link = gSpyDeviceExtensionList.Flink;
  529. link != &gSpyDeviceExtensionList;
  530. link = link->Flink)
  531. {
  532. devExt = CONTAINING_RECORD(link, FILESPY_DEVICE_EXTENSION, NextFileSpyDeviceLink);
  533. SpyDeleteAllContexts( devExt->ThisDeviceObject );
  534. }
  535. ExReleaseFastMutex( &gSpyDeviceExtensionListLock );
  536. }
  537. ///////////////////////////////////////////////////////////////////////////
  538. //
  539. // Context support routines
  540. //
  541. ///////////////////////////////////////////////////////////////////////////
  542. VOID
  543. SpyInitDeviceNamingEnvironment (
  544. IN PDEVICE_OBJECT DeviceObject
  545. )
  546. /*++
  547. Routine Description:
  548. Initializes context information for a given device
  549. Arguments:
  550. DeviceObject - Device to init
  551. Return Value:
  552. None.
  553. --*/
  554. {
  555. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  556. PAGED_CODE();
  557. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  558. InitializeListHead( &devExt->CtxList );
  559. ExInitializeResourceLite( &devExt->CtxLock );
  560. SetFlag( devExt->Flags, ContextsInitialized );
  561. }
  562. VOID
  563. SpyCleanupDeviceNamingEnvironment (
  564. IN PDEVICE_OBJECT DeviceObject
  565. )
  566. /*++
  567. Routine Description:
  568. Cleans up the context information for a given device
  569. Arguments:
  570. DeviceObject - Device to cleanup
  571. Return Value:
  572. None.
  573. --*/
  574. {
  575. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  576. PAGED_CODE();
  577. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  578. //
  579. // Cleanup if initialized
  580. //
  581. if (FlagOn(devExt->Flags,ContextsInitialized)) {
  582. //
  583. // Delete all existing contexts
  584. //
  585. SpyDeleteAllContexts( DeviceObject );
  586. ASSERT(IsListEmpty( &devExt->CtxList ));
  587. //
  588. // Release resource
  589. //
  590. ExDeleteResourceLite( &devExt->CtxLock );
  591. //
  592. // Flag not initialized
  593. //
  594. ClearFlag( devExt->Flags, ContextsInitialized );
  595. }
  596. }
  597. VOID
  598. SpyDeleteAllContexts (
  599. IN PDEVICE_OBJECT DeviceObject
  600. )
  601. /*++
  602. Routine Description:
  603. This will free all existing contexts for the given device
  604. Arguments:
  605. DeviceObject - Device to operate on
  606. Return Value:
  607. None.
  608. --*/
  609. {
  610. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  611. PLIST_ENTRY link;
  612. PSPY_STREAM_CONTEXT pContext;
  613. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  614. LIST_ENTRY localHead;
  615. ULONG deleteNowCount = 0;
  616. ULONG deleteDeferredCount = 0;
  617. ULONG deleteInCallbackCount = 0;
  618. PAGED_CODE();
  619. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  620. INC_STATS(TotalContextDeleteAlls);
  621. InitializeListHead( &localHead );
  622. try {
  623. //
  624. // Acquire list lock
  625. //
  626. SpyAcquireContextLockExclusive( devExt );
  627. //
  628. // Walk the list of contexts and release each one
  629. //
  630. while (!IsListEmpty( &devExt->CtxList )) {
  631. //
  632. // Unlink from top of list
  633. //
  634. link = RemoveHeadList( &devExt->CtxList );
  635. pContext = CONTAINING_RECORD( link, SPY_STREAM_CONTEXT, ExtensionLink );
  636. //
  637. // Mark that we are unlinked from the list. We need to do this
  638. // because of the race condition between this routine and the
  639. // deleteCallback from the FS.
  640. //
  641. ASSERT(FlagOn(pContext->Flags,CTXFL_InExtensionList));
  642. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InExtensionList);
  643. //
  644. // Try and remove ourselves from the File Systems context control
  645. // structure. Note that the file system could be trying to tear
  646. // down their context control right now. If they are then we
  647. // will get a NULL back from this call. This is OK because it
  648. // just means that they are going to free the memory, not us.
  649. // NOTE: This will be safe because we are holding the ContextLock
  650. // exclusively. If this were happening then they would be
  651. // blocked in the callback routine on this lock which
  652. // means the file system has not freed the memory for
  653. // this yet.
  654. //
  655. if (FlagOn(pContext->Flags,CTXFL_InStreamList)) {
  656. ctxCtrl = FsRtlRemovePerStreamContext( pContext->Stream,
  657. devExt,
  658. NULL );
  659. //
  660. // Always clear the flag wether we found it in the list or
  661. // not. We can have the flag set and not be in the list if
  662. // after we acquired the context list lock we context swapped
  663. // and the file system is right now in SpyDeleteContextCallback
  664. // waiting on the list lock.
  665. //
  666. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InStreamList);
  667. //
  668. // Handle wether we were still attached to the file or not.
  669. //
  670. if (NULL != ctxCtrl) {
  671. ASSERT(pContext == CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl));
  672. //
  673. // To save time we don't do the free now (with the lock
  674. // held). We link into a local list and then free it
  675. // later (in this routine). We can do this because it
  676. // is no longer on any list.
  677. //
  678. InsertHeadList( &localHead, &pContext->ExtensionLink );
  679. } else {
  680. //
  681. // The context is in the process of being freed by the file
  682. // system. Don't do anything with it here, it will be
  683. // freed in the callback.
  684. //
  685. INC_STATS(TotalContextsNotFoundInStreamList);
  686. INC_LOCAL_STATS(deleteInCallbackCount);
  687. }
  688. }
  689. }
  690. } finally {
  691. SpyReleaseContextLock( devExt );
  692. }
  693. //
  694. // We have removed everything from the list and released the list lock.
  695. // Go through and figure out what entries we can free and then do it.
  696. //
  697. while (!IsListEmpty( &localHead )) {
  698. //
  699. // Get next entry of the list and get our context back
  700. //
  701. link = RemoveHeadList( &localHead );
  702. pContext = CONTAINING_RECORD( link, SPY_STREAM_CONTEXT, ExtensionLink );
  703. //
  704. // Decrement the USE count and see if we can free it now
  705. //
  706. ASSERT(pContext->UseCount > 0);
  707. if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
  708. //
  709. // No one is using it, free it now
  710. //
  711. SpyFreeContext( pContext );
  712. INC_STATS(TotalContextNonDeferredFrees);
  713. INC_LOCAL_STATS(deleteNowCount);
  714. } else {
  715. //
  716. // Someone still has a pointer to it, it will get deleted
  717. // later when they release
  718. //
  719. INC_LOCAL_STATS(deleteDeferredCount);
  720. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  721. ("FileSpy!SpyDeleteAllContexts: DEFERRED (%p) Fl=%02x Use=%d \"%wZ\"\n",
  722. pContext,
  723. pContext->Flags,
  724. pContext->UseCount,
  725. &pContext->Name) );
  726. }
  727. }
  728. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  729. ("FileSpy!SpyDeleteAllContexts: %3d deleted now, %3d deferred, %3d close contention \"%wZ\"\n",
  730. deleteNowCount,
  731. deleteDeferredCount,
  732. deleteInCallbackCount,
  733. &devExt->DeviceName) );
  734. }
  735. VOID
  736. SpyDeleteContext (
  737. IN PDEVICE_OBJECT DeviceObject,
  738. IN PSPY_STREAM_CONTEXT pContext
  739. )
  740. /*++
  741. Routine Description:
  742. Unlink and release the given context.
  743. Arguments:
  744. DeviceObject - Device to operate on
  745. pContext - The context to delete
  746. Return Value:
  747. None.
  748. --*/
  749. {
  750. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  751. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  752. PAGED_CODE();
  753. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  754. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  755. ("FileSpy!SpyDeleteContext: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  756. pContext,
  757. pContext->Flags,
  758. pContext->UseCount,
  759. &pContext->Name));
  760. //
  761. // Acquire list lock
  762. //
  763. SpyAcquireContextLockExclusive( devExt );
  764. //
  765. // Remove from extension list (if still in it)
  766. //
  767. if (FlagOn(pContext->Flags,CTXFL_InExtensionList)) {
  768. RemoveEntryList( &pContext->ExtensionLink );
  769. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InExtensionList);
  770. }
  771. //
  772. // See if still in stream list.
  773. //
  774. if (!FlagOn(pContext->Flags,CTXFL_InStreamList)) {
  775. //
  776. // Not in stream list, release lock and return
  777. //
  778. SpyReleaseContextLock( devExt );
  779. } else {
  780. //
  781. // Remove from Stream list
  782. //
  783. ctxCtrl = FsRtlRemovePerStreamContext( pContext->Stream,
  784. devExt,
  785. NULL );
  786. //
  787. // Always clear the flag wether we found it in the list or not. We
  788. // can have the flag set and not be in the list if after we acquired
  789. // the context list lock we context swapped and the file system
  790. // is right now in SpyDeleteContextCallback waiting on the list lock.
  791. //
  792. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InStreamList);
  793. //
  794. // Release list lock
  795. //
  796. SpyReleaseContextLock( devExt );
  797. //
  798. // The context is now deleted from all of the lists and the lock is
  799. // removed. We need to see if we found this entry on the systems context
  800. // list. If not that means the callback was in the middle of trying
  801. // to free this (while we were) and has already deleted it.
  802. // If we found a structure then delete it now ourselves.
  803. //
  804. if (NULL != ctxCtrl) {
  805. ASSERT(pContext == CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl));
  806. //
  807. // Decrement USE count, free context if zero
  808. //
  809. ASSERT(pContext->UseCount > 0);
  810. if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
  811. INC_STATS(TotalContextNonDeferredFrees);
  812. SpyFreeContext( pContext );
  813. } else {
  814. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  815. ("FileSpy!SpyDeleteContext: DEFERRED (%p) Fl=%02x Use=%d \"%wZ\"\n",
  816. pContext,
  817. pContext->Flags,
  818. pContext->UseCount,
  819. &pContext->Name));
  820. }
  821. } else {
  822. INC_STATS(TotalContextsNotFoundInStreamList);
  823. }
  824. }
  825. }
  826. VOID
  827. SpyDeleteContextCallback (
  828. IN PVOID Context
  829. )
  830. /*++
  831. Routine Description:
  832. This is called by base file systems when a context needs to be deleted.
  833. Arguments:
  834. Context - The context structure being deleted
  835. Return Value:
  836. None.
  837. --*/
  838. {
  839. PSPY_STREAM_CONTEXT pContext = Context;
  840. PFILESPY_DEVICE_EXTENSION devExt;
  841. PAGED_CODE();
  842. devExt = (PFILESPY_DEVICE_EXTENSION)pContext->ContextCtrl.OwnerId;
  843. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  844. ("FileSpy!SpyDeleteContextCallback: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  845. pContext,
  846. pContext->Flags,
  847. pContext->UseCount,
  848. &pContext->Name) );
  849. //
  850. // When we get here we have already been removed from the stream list (by
  851. // the calling file system), flag that this has happened.
  852. //
  853. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InStreamList);
  854. //
  855. // Lock the context list lock in the extension
  856. //
  857. SpyAcquireContextLockExclusive( devExt );
  858. //
  859. // See if we are still linked into the extension list. If not then skip
  860. // the unlinking. This can happen if someone is trying to delete this
  861. // context at the same time as we are.
  862. //
  863. if (FlagOn(pContext->Flags,CTXFL_InExtensionList)) {
  864. RemoveEntryList( &pContext->ExtensionLink );
  865. RtlInterlockedClearBitsDiscardReturn(&pContext->Flags,CTXFL_InExtensionList);
  866. }
  867. SpyReleaseContextLock( devExt );
  868. //
  869. // Decrement USE count, free context if zero
  870. //
  871. ASSERT(pContext->UseCount > 0);
  872. if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
  873. INC_STATS(TotalContextCtxCallbackFrees);
  874. SpyFreeContext( pContext );
  875. } else {
  876. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  877. ("FileSpy!SpyDeleteContextCB: DEFFERED (%p) Fl=%02x Use=%d \"%wZ\"\n",
  878. pContext,
  879. pContext->Flags,
  880. pContext->UseCount,
  881. &pContext->Name) );
  882. }
  883. }
  884. VOID
  885. SpyLinkContext (
  886. IN PDEVICE_OBJECT DeviceObject,
  887. IN PFILE_OBJECT FileObject,
  888. IN OUT PSPY_STREAM_CONTEXT *ppContext
  889. )
  890. /*++
  891. Routine Description:
  892. This will link the given context into the context list for the given
  893. device as well as into the given stream.
  894. NOTE: It is possible for this entry to already exist in the table since
  895. between the time we initially looked and the time we inserted
  896. (which is now) someone else may have inserted one. If we find an
  897. entry that already exists we will free the entry passed in and
  898. return the entry found.
  899. Arguments:
  900. DeviceObject - Device we are operating on
  901. FileObject - Represents the stream to link the context into
  902. ppContext - Enters with the context to link, returns with the context
  903. to use. They may be different if the given context already
  904. exists.
  905. Return Value:
  906. None.
  907. --*/
  908. {
  909. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  910. NTSTATUS status;
  911. PSPY_STREAM_CONTEXT pContext = *ppContext;
  912. PSPY_STREAM_CONTEXT ctx;
  913. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  914. PAGED_CODE();
  915. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  916. ASSERT(FileObject->FsContext != NULL);
  917. ASSERT(pContext != NULL);
  918. //
  919. // If this is marked as a temporary context, return now. Because we
  920. // don't bump the reference count, when it is release it to be freed.
  921. //
  922. if (FlagOn(pContext->Flags,CTXFL_Temporary)) {
  923. ASSERT(!FlagOn(pContext->Flags,CTXFL_InExtensionList));
  924. return;
  925. }
  926. //
  927. // We need to figure out if a duplicate entry already exists on
  928. // the context list for this file object. Acquire our list lock
  929. // and then see if it exists. If not, insert into the stream and
  930. // volume lists. If so, then simply free this new entry and return
  931. // the original.
  932. //
  933. // This can happen when:
  934. // - Someone created an entry at the exact same time as we were
  935. // creating an entry.
  936. // - When someone does a create with overwrite or supersede we
  937. // do not have the information yet to see if a context already
  938. // exists. Because of this we have to create a new context
  939. // every time. During post-create we then see if one already
  940. // exists.
  941. //
  942. //
  943. // Initialize the context control structure. We do this now so we
  944. // don't have to do it while the lock is held (even if we might
  945. // have to free it because of a duplicate found)
  946. //
  947. FsRtlInitPerStreamContext( &pContext->ContextCtrl,
  948. devExt,
  949. NULL,
  950. SpyDeleteContextCallback );
  951. //
  952. // Save the stream we are associated with.
  953. //
  954. pContext->Stream = FsRtlGetPerStreamContextPointer(FileObject);
  955. //
  956. // Acquire list lock exclusively
  957. //
  958. SpyAcquireContextLockExclusive( devExt );
  959. ASSERT(pContext->UseCount == 1);
  960. ASSERT(!FlagOn(pContext->Flags,CTXFL_InExtensionList));
  961. ASSERT(!FlagOn(pContext->Flags,CTXFL_Temporary));
  962. //
  963. // See if we have an entry already on the list
  964. //
  965. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
  966. devExt,
  967. NULL );
  968. if (NULL != ctxCtrl) {
  969. //
  970. // The context already exists so free the new one we just
  971. // created. First increment the use count on the one we found in
  972. // the list.
  973. //
  974. ctx = CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl);
  975. ASSERT(ctx->Stream == FsRtlGetPerStreamContextPointer(FileObject));
  976. ASSERT(FlagOn(ctx->Flags,CTXFL_InExtensionList));
  977. ASSERT(ctx->UseCount > 0);
  978. //
  979. // Bump ref count and release lock
  980. //
  981. InterlockedIncrement( &ctx->UseCount );
  982. SpyReleaseContextLock( devExt );
  983. //
  984. // Since this cache is across opens on the same stream there are
  985. // cases where the names will be different even though they are the
  986. // same file. These cases are:
  987. // - One open could be by short name where another open
  988. // is by long name.
  989. // - This does not presently strip extended stream names like
  990. // :$DATA
  991. // When enabled this will display to the debugger screen when the
  992. // names don't exactly match. You can also break on this difference.
  993. //
  994. if (!RtlEqualUnicodeString( &pContext->Name,&ctx->Name,TRUE )) {
  995. SPY_LOG_PRINT( SPYDEBUG_TRACE_MISMATCHED_NAMES,
  996. ("FileSpy!SpyLinkContext: Old Name: (%p) Fl=%02x Use=%d \"%wZ\"\n"
  997. " New Name: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  998. ctx,
  999. ctx->Flags,
  1000. ctx->UseCount,
  1001. &ctx->Name,
  1002. pContext,
  1003. pContext->Flags,
  1004. pContext->UseCount,
  1005. &pContext->Name) );
  1006. if (FlagOn(gFileSpyDebugLevel,SPYDEBUG_ASSERT_MISMATCHED_NAMES)) {
  1007. DbgBreakPoint();
  1008. }
  1009. }
  1010. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1011. ("FileSpy!SpyLinkContext: Rel Dup: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1012. pContext,
  1013. pContext->Flags,
  1014. pContext->UseCount,
  1015. &pContext->Name) );
  1016. //
  1017. // Free the new structure because it was already resident. Note
  1018. // that this entry has never been linked into any lists so we know
  1019. // no one else has a reference to it. Decrement use count to keep
  1020. // the ASSERTS happy then free the memory.
  1021. //
  1022. INC_STATS(TotalContextDuplicateFrees);
  1023. pContext->UseCount--;
  1024. SpyFreeContext( pContext );
  1025. //
  1026. // Return the one we found in the list
  1027. //
  1028. *ppContext = ctx;
  1029. } else {
  1030. //
  1031. // The new context did not exist, insert this new one.
  1032. //
  1033. //
  1034. // Link into Stream context. This can fail for the following
  1035. // reasons:
  1036. // This is a paging file
  1037. // This is a volume open
  1038. // If this happens then don't bump the reference count and it will be
  1039. // freed when the caller is done with it.
  1040. //
  1041. status = FsRtlInsertPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
  1042. &pContext->ContextCtrl );
  1043. if (NT_SUCCESS(status)) {
  1044. //
  1045. // Increment the USE count (because it is added to the stream)
  1046. //
  1047. InterlockedIncrement( &pContext->UseCount );
  1048. //
  1049. // Link into Device extension
  1050. //
  1051. InsertHeadList( &devExt->CtxList, &pContext->ExtensionLink );
  1052. //
  1053. // Mark that we have been inserted into both lists. We don't have
  1054. // to do this interlocked because no one can access this entry
  1055. // until we release the context lock.
  1056. //
  1057. SetFlag( pContext->Flags, CTXFL_InExtensionList|CTXFL_InStreamList );
  1058. }
  1059. //
  1060. // Release lock
  1061. //
  1062. SpyReleaseContextLock( devExt );
  1063. }
  1064. }
  1065. /***************************************************************************++
  1066. Routine Description:
  1067. This will allocate and initialize a context structure but it does NOT
  1068. link it into the context hash list.
  1069. Arguments:
  1070. Return Value:
  1071. --***************************************************************************/
  1072. NTSTATUS
  1073. SpyCreateContext (
  1074. IN PDEVICE_OBJECT DeviceObject,
  1075. IN PFILE_OBJECT FileObject,
  1076. IN NAME_LOOKUP_FLAGS LookupFlags,
  1077. OUT PSPY_STREAM_CONTEXT *pRetContext
  1078. )
  1079. /*++
  1080. Routine Description:
  1081. Allocate and initialize a context structure including retrieving the name.
  1082. Arguments:
  1083. DeviceObject - Device to operate on
  1084. FileObject - The stream the context is being created for
  1085. LookupFlags - Flag telling how to do this create
  1086. pRetContext - Receives the created context
  1087. Return Value:
  1088. Status of the operation
  1089. --*/
  1090. {
  1091. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  1092. PSPY_STREAM_CONTEXT ctx;
  1093. ULONG contextSize;
  1094. UNICODE_STRING fileName;
  1095. WCHAR fileNameBuffer[MAX_PATH];
  1096. BOOLEAN getNameResult;
  1097. PAGED_CODE();
  1098. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  1099. //
  1100. // Setup locals
  1101. //
  1102. *pRetContext = NULL;
  1103. RtlInitEmptyUnicodeString( &fileName,
  1104. fileNameBuffer,
  1105. sizeof(fileNameBuffer) );
  1106. //
  1107. // Get the filename string
  1108. //
  1109. getNameResult = SpyGetFullPathName( FileObject,
  1110. &fileName,
  1111. devExt,
  1112. LookupFlags );
  1113. //
  1114. // Allocate the context structure with space for the name
  1115. // added to the end.
  1116. //
  1117. contextSize = sizeof(SPY_STREAM_CONTEXT) + fileName.Length;
  1118. ctx = ExAllocatePoolWithTag( NonPagedPool,
  1119. contextSize,
  1120. FILESPY_CONTEXT_TAG );
  1121. if (!ctx) {
  1122. return STATUS_INSUFFICIENT_RESOURCES;
  1123. }
  1124. //
  1125. // Init the context structure
  1126. //
  1127. RtlZeroMemory( ctx, sizeof(SPY_STREAM_CONTEXT) );
  1128. ctx->UseCount = 1;
  1129. //
  1130. // Insert the file name
  1131. //
  1132. RtlInitEmptyUnicodeString( &ctx->Name,
  1133. (PWCHAR)(ctx + 1),
  1134. contextSize - sizeof(SPY_STREAM_CONTEXT) );
  1135. RtlCopyUnicodeString( &ctx->Name, &fileName );
  1136. //
  1137. // If they don't want to keep this context, mark it temporary
  1138. //
  1139. if (!getNameResult) {
  1140. SetFlag(ctx->Flags, CTXFL_Temporary);
  1141. INC_STATS(TotalContextTemporary);
  1142. }
  1143. //
  1144. // Return the object context
  1145. //
  1146. INC_STATS(TotalContextCreated);
  1147. *pRetContext = ctx;
  1148. //
  1149. // Cleanup the local nameControl structure
  1150. //
  1151. return STATUS_SUCCESS;
  1152. }
  1153. NTSTATUS
  1154. SpyGetContext (
  1155. IN PDEVICE_OBJECT DeviceObject,
  1156. IN PFILE_OBJECT FileObject,
  1157. IN NAME_LOOKUP_FLAGS LookupFlags,
  1158. OUT PSPY_STREAM_CONTEXT *pRetContext
  1159. )
  1160. /*++
  1161. Routine Description:
  1162. This will see if a given context already exists. If not it will create
  1163. one and return it. Note: the return context pointer is NULL on a
  1164. failure.
  1165. This will also see if all contexts are to be temporary (global flag in
  1166. the extension). If so, a temporary context is always created. It also
  1167. sees if the found context is marked temporary (because it is being
  1168. renamed). If so, a temporary context is also created and returned.
  1169. Arguments:
  1170. DeviceObject - Device to operate on
  1171. FileObject - The stream the context is being looked up/created for
  1172. LookupFlags - State flags incase a context is created
  1173. pRetContext - Receives the found/created context
  1174. Return Value:
  1175. Status of the operation
  1176. --*/
  1177. {
  1178. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  1179. PSPY_STREAM_CONTEXT pContext;
  1180. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  1181. NTSTATUS status;
  1182. BOOLEAN makeTemporary = FALSE;
  1183. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  1184. //
  1185. // Bump total search count
  1186. //
  1187. INC_STATS(TotalContextSearches);
  1188. //
  1189. // See if the all-contexts-temporary state is on. If not then do
  1190. // the normal search.
  1191. //
  1192. if (devExt->AllContextsTemporary != 0) {
  1193. //
  1194. // Mark that we want this context to be temporary
  1195. //
  1196. makeTemporary = TRUE;
  1197. } else {
  1198. //
  1199. // NOT-TEMPORARY
  1200. // Try and locate the context structure. We acquire the list lock
  1201. // so that we can guarantee that the context will not go away between
  1202. // the time when we find it and can increment the use count
  1203. //
  1204. SpyAcquireContextLockShared( devExt );
  1205. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
  1206. devExt,
  1207. NULL );
  1208. if (NULL != ctxCtrl) {
  1209. //
  1210. // A context was attached to the given stream
  1211. //
  1212. pContext = CONTAINING_RECORD( ctxCtrl,
  1213. SPY_STREAM_CONTEXT,
  1214. ContextCtrl );
  1215. ASSERT(pContext->Stream == FsRtlGetPerStreamContextPointer(FileObject));
  1216. ASSERT(FlagOn(pContext->Flags,CTXFL_InExtensionList));
  1217. ASSERT(!FlagOn(pContext->Flags,CTXFL_Temporary));
  1218. ASSERT(pContext->UseCount > 0);
  1219. //
  1220. // See if this is marked that we should not use it (happens when a
  1221. // file is being renamed).
  1222. //
  1223. if (FlagOn(pContext->Flags,CTXFL_DoNotUse)) {
  1224. //
  1225. // We should not use this context, unlock and set flag so we
  1226. // will create a temporary context.
  1227. //
  1228. SpyReleaseContextLock( devExt );
  1229. makeTemporary = TRUE;
  1230. } else {
  1231. //
  1232. // We want this context so bump the use count and release
  1233. // the lock
  1234. //
  1235. InterlockedIncrement( &pContext->UseCount );
  1236. SpyReleaseContextLock( devExt );
  1237. INC_STATS(TotalContextFound);
  1238. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1239. ("FileSpy!SpyGetContext: Found: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1240. pContext,
  1241. pContext->Flags,
  1242. pContext->UseCount,
  1243. &pContext->Name) );
  1244. //
  1245. // Return the found context
  1246. //
  1247. *pRetContext = pContext;
  1248. return STATUS_SUCCESS;
  1249. }
  1250. } else {
  1251. //
  1252. // We didn't find a context, release the lock
  1253. //
  1254. SpyReleaseContextLock( devExt );
  1255. }
  1256. }
  1257. //
  1258. // For whatever reason, we did not find a context.
  1259. // See if contexts are supported for this particular file. Note that
  1260. // NTFS does not presently support contexts on paging files.
  1261. //
  1262. if (!FsRtlSupportsPerStreamContexts(FileObject)) {
  1263. INC_STATS(TotalContextsNotSupported);
  1264. *pRetContext = NULL;
  1265. return STATUS_NOT_SUPPORTED;
  1266. }
  1267. //
  1268. // If we get here we need to create a context, do it
  1269. //
  1270. status = SpyCreateContext( DeviceObject,
  1271. FileObject,
  1272. LookupFlags,
  1273. &pContext );
  1274. if (!NT_SUCCESS( status )) {
  1275. *pRetContext = NULL;
  1276. return status;
  1277. }
  1278. //
  1279. // Mark context temporary (if requested)
  1280. //
  1281. if (makeTemporary) {
  1282. SetFlag(pContext->Flags,CTXFL_Temporary);
  1283. INC_STATS(TotalContextTemporary);
  1284. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1285. ("FileSpy!SpyGetContext: RenAllTmp: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1286. pContext,
  1287. pContext->Flags,
  1288. pContext->UseCount,
  1289. &pContext->Name) );
  1290. } else {
  1291. //
  1292. // Insert the context into the linked list. Note that the
  1293. // link routine will see if this entry has already been added to
  1294. // the list (could happen while we were building it). If so it
  1295. // will release the one we created and use the one it found in
  1296. // the list. It will return the new entry (if it was changed).
  1297. // The link routine properly handles temporary contexts.
  1298. //
  1299. SpyLinkContext( DeviceObject,
  1300. FileObject,
  1301. &pContext );
  1302. }
  1303. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1304. ("FileSpy!SrGetContext: Created%s (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1305. (FlagOn(pContext->Flags,CTXFL_Temporary) ? "Tmp:" : ": "),
  1306. pContext,
  1307. pContext->Flags,
  1308. pContext->UseCount,
  1309. &pContext->Name) );
  1310. //
  1311. // Return the context
  1312. //
  1313. ASSERT(pContext->UseCount > 0);
  1314. *pRetContext = pContext;
  1315. return STATUS_SUCCESS;
  1316. }
  1317. PSPY_STREAM_CONTEXT
  1318. SpyFindExistingContext (
  1319. IN PDEVICE_OBJECT DeviceObject,
  1320. IN PFILE_OBJECT FileObject
  1321. )
  1322. /*++
  1323. Routine Description:
  1324. See if a context for the given stream already exists. If so it will
  1325. bump the reference count and return the context. If not, NULL
  1326. is returned.
  1327. Arguments:
  1328. DeviceObject - Device to operate on
  1329. FileObject - The stream the context is being looked up for
  1330. Return Value:
  1331. Returns the found context
  1332. --*/
  1333. {
  1334. PFILESPY_DEVICE_EXTENSION devExt = DeviceObject->DeviceExtension;
  1335. PSPY_STREAM_CONTEXT pContext;
  1336. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  1337. PAGED_CODE();
  1338. ASSERT(IS_FILESPY_DEVICE_OBJECT(DeviceObject));
  1339. //
  1340. // Try and locate the context structure. We acquire the list lock
  1341. // so that we can guarantee that the context will not go away between
  1342. // the time when we find it and can increment the use count
  1343. //
  1344. INC_STATS(TotalContextSearches);
  1345. SpyAcquireContextLockShared( devExt );
  1346. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(FileObject),
  1347. devExt,
  1348. NULL );
  1349. if (NULL != ctxCtrl) {
  1350. //
  1351. // We found the entry, increment use count
  1352. //
  1353. pContext = CONTAINING_RECORD(ctxCtrl,SPY_STREAM_CONTEXT,ContextCtrl);
  1354. ASSERT(pContext->Stream == FsRtlGetPerStreamContextPointer(FileObject));
  1355. ASSERT(pContext->UseCount > 0);
  1356. InterlockedIncrement( &pContext->UseCount );
  1357. //
  1358. // Release the list lock
  1359. //
  1360. SpyReleaseContextLock( devExt );
  1361. INC_STATS(TotalContextFound);
  1362. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1363. ("FileSpy!SpyFindExistingContext:Found: (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1364. pContext,
  1365. pContext->Flags,
  1366. pContext->UseCount,
  1367. &pContext->Name) );
  1368. } else {
  1369. //
  1370. // Release the list lock while we create the new context.
  1371. //
  1372. SpyReleaseContextLock( devExt );
  1373. pContext = NULL;
  1374. }
  1375. return pContext;
  1376. }
  1377. VOID
  1378. SpyReleaseContext (
  1379. IN PSPY_STREAM_CONTEXT pContext
  1380. )
  1381. /*++
  1382. Routine Description:
  1383. Decrement the use count for the given context. If it goes to zero, free it
  1384. Arguments:
  1385. pContext - The context to operate on
  1386. Return Value:
  1387. None.
  1388. --*/
  1389. {
  1390. PAGED_CODE();
  1391. SPY_LOG_PRINT( SPYDEBUG_TRACE_DETAILED_CONTEXT_OPS,
  1392. ("FileSpy!SpyReleaseContext: Release (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1393. pContext,
  1394. pContext->Flags,
  1395. pContext->UseCount,
  1396. &pContext->Name) );
  1397. //
  1398. // Decrement USE count, free context if zero
  1399. //
  1400. ASSERT(pContext->UseCount > 0);
  1401. if (InterlockedDecrement( &pContext->UseCount ) <= 0) {
  1402. ASSERT(!FlagOn(pContext->Flags,CTXFL_InExtensionList));
  1403. //
  1404. // Free the memory
  1405. //
  1406. SPY_LOG_PRINT( SPYDEBUG_TRACE_CONTEXT_OPS,
  1407. ("FileSpy!SpyReleaseContext: Freeing (%p) Fl=%02x Use=%d \"%wZ\"\n",
  1408. pContext,
  1409. pContext->Flags,
  1410. pContext->UseCount,
  1411. &pContext->Name) );
  1412. INC_STATS(TotalContextDeferredFrees);
  1413. SpyFreeContext( pContext );
  1414. }
  1415. }
  1416. #endif