Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

1640 lines
51 KiB

  1. /*++
  2. Copyright (c) 1998-1999 Microsoft Corporation
  3. Module Name:
  4. context.c
  5. Abstract:
  6. This module contains the context handling routines
  7. Author:
  8. Neal Christiansen (nealch) 27-Dec-2000
  9. Revision History:
  10. --*/
  11. #include "precomp.h"
  12. //
  13. // Local prototypes
  14. //
  15. VOID
  16. SrpDeleteContextCallback(
  17. IN PVOID Context
  18. );
  19. //
  20. // linker commands
  21. //
  22. #ifdef ALLOC_PRAGMA
  23. #pragma alloc_text( PAGE, SrInitContextCtrl )
  24. #pragma alloc_text( PAGE, SrCleanupContextCtrl )
  25. #pragma alloc_text( PAGE, SrDeleteAllContexts )
  26. #pragma alloc_text( PAGE, SrDeleteContext )
  27. #pragma alloc_text( PAGE, SrpDeleteContextCallback )
  28. #pragma alloc_text( PAGE, SrLinkContext )
  29. #pragma alloc_text( PAGE, SrCreateContext )
  30. #pragma alloc_text( PAGE, SrGetContext )
  31. #pragma alloc_text( PAGE, SrFindExistingContext )
  32. #pragma alloc_text( PAGE, SrReleaseContext )
  33. #endif // ALLOC_PRAGMA
  34. ///////////////////////////////////////////////////////////////////////////
  35. //
  36. // Context support routines
  37. //
  38. ///////////////////////////////////////////////////////////////////////////
  39. /***************************************************************************++
  40. Routine Description:
  41. This initializes the context control information for a given volume
  42. Arguments:
  43. pExtension - Contains context to init
  44. Return Value:
  45. None
  46. --***************************************************************************/
  47. VOID
  48. SrInitContextCtrl (
  49. IN PSR_DEVICE_EXTENSION pExtension
  50. )
  51. {
  52. PAGED_CODE();
  53. InitializeListHead( &pExtension->ContextCtrl.List );
  54. ExInitializeResourceLite( &pExtension->ContextCtrl.Lock );
  55. }
  56. /***************************************************************************++
  57. Routine Description:
  58. This cleans up the context control information for a given volume
  59. Arguments:
  60. pExtension - Contains context to cleanup
  61. Return Value:
  62. None
  63. --***************************************************************************/
  64. VOID
  65. SrCleanupContextCtrl (
  66. IN PSR_DEVICE_EXTENSION pExtension
  67. )
  68. {
  69. PAGED_CODE();
  70. //
  71. // Remove all contexts they may still exist
  72. //
  73. SrDeleteAllContexts( pExtension );
  74. ExDeleteResourceLite( &pExtension->ContextCtrl.Lock );
  75. }
  76. /***************************************************************************++
  77. Routine Description:
  78. This will free all existing contexts for the given device extension.
  79. We don't worry about holding the mutex lock for a long time because
  80. nobody else should be using this extension anyway.
  81. Arguments:
  82. pExtension - Contains contexts to cleanup
  83. Return Value:
  84. None
  85. --***************************************************************************/
  86. VOID
  87. SrDeleteAllContexts (
  88. IN PSR_DEVICE_EXTENSION pExtension
  89. )
  90. {
  91. PLIST_ENTRY link;
  92. PSR_STREAM_CONTEXT pFileContext;
  93. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  94. LIST_ENTRY localHead;
  95. #if DBG
  96. ULONG deleteNowCount = 0;
  97. ULONG deleteDeferredCount = 0;
  98. ULONG deleteInCallbackCount = 0;
  99. #endif
  100. PAGED_CODE();
  101. INC_STATS(TotalContextDeleteAlls);
  102. InitializeListHead( &localHead );
  103. try
  104. {
  105. //
  106. // Acquire list lock
  107. //
  108. SrAcquireContextLockExclusive( pExtension );
  109. //
  110. // Walk the list of contexts and release each one
  111. //
  112. while (!IsListEmpty( &pExtension->ContextCtrl.List ))
  113. {
  114. //
  115. // Unlink from top of list
  116. //
  117. link = RemoveHeadList( &pExtension->ContextCtrl.List );
  118. pFileContext = CONTAINING_RECORD( link, SR_STREAM_CONTEXT, ExtensionLink );
  119. //
  120. // Mark that we are unlinked from the list. We need to do this
  121. // because of the race condition between this routine and the
  122. // deleteCallback from the FS.
  123. //
  124. ASSERT(FlagOn(pFileContext->Flags,CTXFL_InExtensionList));
  125. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InExtensionList);
  126. //
  127. // Try and remove ourselves from the File Systems context control
  128. // structure. Note that the file system could be trying to tear
  129. // down their context control right now. If they are then we
  130. // will get a NULL back from this call. This is OK because it
  131. // just means that they are going to free the memory, not us.
  132. // NOTE: This will be safe becase we are holding the ContextLock
  133. // exclusivly. If this were happening then they would be
  134. // blocked in the callback routine on this lock which
  135. // means the file system has not freed the memory for
  136. // this yet.
  137. //
  138. if (FlagOn(pFileContext->Flags,CTXFL_InStreamList))
  139. {
  140. ctxCtrl = FsRtlRemovePerStreamContext( pFileContext->ContextCtrl.InstanceId,
  141. pExtension,
  142. pFileContext->ContextCtrl.InstanceId );
  143. //
  144. // Always clear the flag wether we found it in the list or
  145. // not. We can have the flag set and not be in the list if
  146. // after we acquired the context list lock we context swapped
  147. // and the file system is right now in SrpDeleteContextCallback
  148. // waiting on the list lock.
  149. //
  150. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InStreamList);
  151. //
  152. // Handle wether we were still attached to the file or not.
  153. //
  154. if (NULL != ctxCtrl)
  155. {
  156. ASSERT(pFileContext == CONTAINING_RECORD(ctxCtrl,SR_STREAM_CONTEXT,ContextCtrl));
  157. //
  158. // To save time we don't do the free now (with the lock
  159. // held). We link into a local list and then free it
  160. // later (in this routine). We can do this because it
  161. // is no longer on any list.
  162. //
  163. InsertHeadList( &localHead, &pFileContext->ExtensionLink );
  164. }
  165. else
  166. {
  167. //
  168. // The context is in the process of being freed by the file
  169. // system. Don't do anything with it here, it will be
  170. // freed in the callback.
  171. //
  172. INC_STATS(TotalContextsNotFoundInStreamList);
  173. INC_LOCAL_STATS(deleteInCallbackCount);
  174. }
  175. }
  176. }
  177. }
  178. finally
  179. {
  180. SrReleaseContextLock( pExtension );
  181. }
  182. //
  183. // We have removed everything from the list and release the list lock.
  184. // Go through and figure out what entries we can free and then do it.
  185. //
  186. SrTrace(CONTEXT_LOG, ("Sr!SrDeleteAllContexts: Starting (%p)\n",
  187. &localHead ));
  188. while (!IsListEmpty( &localHead ))
  189. {
  190. //
  191. // Get next entry of the list and get our context back
  192. //
  193. link = RemoveHeadList( &localHead );
  194. pFileContext = CONTAINING_RECORD( link, SR_STREAM_CONTEXT, ExtensionLink );
  195. //
  196. // Decrement the USE count and see if we can free it now
  197. //
  198. ASSERT(pFileContext->UseCount > 0);
  199. if (InterlockedDecrement( &pFileContext->UseCount ) <= 0)
  200. {
  201. //
  202. // No one is using it, free it now
  203. //
  204. SrFreeContext( pFileContext );
  205. INC_STATS(TotalContextNonDeferredFrees);
  206. INC_LOCAL_STATS(deleteNowCount);
  207. }
  208. else
  209. {
  210. //
  211. // Someone still has a pointer to it, it will get deleted
  212. // later when they release
  213. //
  214. INC_LOCAL_STATS(deleteDeferredCount);
  215. SrTrace( CONTEXT_LOG, ("Sr!SrDeleteAllContexts: DEFERRED (%p) Fl=%03x Use=%d \"%.*S\"\n",
  216. pFileContext,
  217. pFileContext->Flags,
  218. pFileContext->UseCount,
  219. (pFileContext->FileName.Length+
  220. pFileContext->StreamNameLength)/
  221. sizeof(WCHAR),
  222. pFileContext->FileName.Buffer));
  223. }
  224. }
  225. SrTrace(CONTEXT_LOG, ("Sr!SrDeleteAllContexts: For \"%wZ\" %d deleted now, %d deferred, %d close contention\n",
  226. pExtension->pNtVolumeName,
  227. deleteNowCount,
  228. deleteDeferredCount,
  229. deleteInCallbackCount ));
  230. }
  231. /***************************************************************************++
  232. Routine Description:
  233. This will unlink and release the given context.
  234. Arguments:
  235. Return Value:
  236. None
  237. --***************************************************************************/
  238. VOID
  239. SrDeleteContext (
  240. IN PSR_DEVICE_EXTENSION pExtension,
  241. IN PSR_STREAM_CONTEXT pFileContext
  242. )
  243. {
  244. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  245. BOOLEAN releaseLock = FALSE;
  246. PAGED_CODE();
  247. SrTrace( CONTEXT_LOG, ("Sr!SrDeleteContext: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  248. pFileContext,
  249. pFileContext->Flags,
  250. pFileContext->UseCount,
  251. (pFileContext->FileName.Length+
  252. pFileContext->StreamNameLength)/
  253. sizeof(WCHAR),
  254. pFileContext->FileName.Buffer));
  255. try {
  256. //
  257. // Acquire list lock
  258. //
  259. SrAcquireContextLockExclusive( pExtension );
  260. releaseLock = TRUE;
  261. //
  262. // Remove from extension list (if still in it)
  263. //
  264. if (FlagOn(pFileContext->Flags,CTXFL_InExtensionList))
  265. {
  266. RemoveEntryList( &pFileContext->ExtensionLink );
  267. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InExtensionList);
  268. }
  269. //
  270. // See if still in stream list.
  271. //
  272. if (!FlagOn(pFileContext->Flags,CTXFL_InStreamList))
  273. {
  274. //
  275. // Not in stream list, release lock and return
  276. //
  277. leave;
  278. }
  279. else
  280. {
  281. //
  282. // Remove from Stream list
  283. //
  284. ctxCtrl = FsRtlRemovePerStreamContext( pFileContext->ContextCtrl.InstanceId,
  285. pExtension,
  286. pFileContext->ContextCtrl.InstanceId );
  287. //
  288. // Always clear the flag wether we found it in the list or not. We
  289. // can have the flag set and not be in the list if after we acquired
  290. // the context list lock we context swapped and the file system
  291. // is right now in SrpDeleteContextCallback waiting on the list lock.
  292. //
  293. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InStreamList);
  294. //
  295. //
  296. //
  297. // Release list lock
  298. //
  299. SrReleaseContextLock( pExtension );
  300. releaseLock = FALSE;
  301. //
  302. // The context is now deleted from all of the lists and the lock is
  303. // removed. We need to see if we found this entry on the systems context
  304. // list. If not that means the callback was in the middle of trying
  305. // to free this (while we were) and has already deleted it.
  306. // If we found a structure then delete it now ourselves.
  307. //
  308. if (NULL != ctxCtrl)
  309. {
  310. ASSERT(pFileContext == CONTAINING_RECORD(ctxCtrl,SR_STREAM_CONTEXT,ContextCtrl));
  311. //
  312. // Decrement USE count, free context if zero
  313. //
  314. ASSERT(pFileContext->UseCount > 0);
  315. if (InterlockedDecrement( &pFileContext->UseCount ) <= 0)
  316. {
  317. INC_STATS(TotalContextNonDeferredFrees);
  318. SrFreeContext( pFileContext );
  319. }
  320. else
  321. {
  322. SrTrace( CONTEXT_LOG, ("Sr!SrDeleteContext: DEFERRED (%p) Fl=%03x Use=%d \"%.*S\"\n",
  323. pFileContext,
  324. pFileContext->Flags,
  325. pFileContext->UseCount,
  326. (pFileContext->FileName.Length+
  327. pFileContext->StreamNameLength)/
  328. sizeof(WCHAR),
  329. pFileContext->FileName.Buffer));
  330. }
  331. }
  332. else
  333. {
  334. INC_STATS(TotalContextsNotFoundInStreamList);
  335. }
  336. }
  337. }finally {
  338. if (releaseLock)
  339. {
  340. SrReleaseContextLock( pExtension );
  341. }
  342. }
  343. }
  344. /***************************************************************************++
  345. Routine Description:
  346. This is called by base file systems when a context needs to be deleted.
  347. Arguments:
  348. Return Value:
  349. --***************************************************************************/
  350. VOID
  351. SrpDeleteContextCallback (
  352. IN PVOID Context
  353. )
  354. {
  355. PSR_STREAM_CONTEXT pFileContext = Context;
  356. PSR_DEVICE_EXTENSION pExtension;
  357. PAGED_CODE();
  358. pExtension = (PSR_DEVICE_EXTENSION)pFileContext->ContextCtrl.OwnerId;
  359. ASSERT(IS_VALID_SR_DEVICE_EXTENSION(pExtension));
  360. ASSERT(pFileContext->ContextCtrl.OwnerId == pExtension);
  361. SrTrace( CONTEXT_LOG, ("Sr!SrpDeleteContextCB: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  362. pFileContext,
  363. pFileContext->Flags,
  364. pFileContext->UseCount,
  365. (pFileContext->FileName.Length+
  366. pFileContext->StreamNameLength)/
  367. sizeof(WCHAR),
  368. pFileContext->FileName.Buffer));
  369. //
  370. // When we get here we have already been removed from the stream list,
  371. // flag that this has happened.
  372. //
  373. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InStreamList);
  374. //
  375. // Lock the context list lock in the extension
  376. //
  377. SrAcquireContextLockExclusive( pExtension );
  378. //
  379. // See if we are still linked into the extension list. If not then skip
  380. // the unlinking. This can happen if someone is trying to delete this
  381. // context at the same time as we are.
  382. //
  383. if (FlagOn(pFileContext->Flags,CTXFL_InExtensionList))
  384. {
  385. RemoveEntryList( &pFileContext->ExtensionLink );
  386. RtlInterlockedClearBitsDiscardReturn(&pFileContext->Flags,CTXFL_InExtensionList);
  387. }
  388. SrReleaseContextLock( pExtension );
  389. //
  390. // Decrement USE count, free context if zero
  391. //
  392. ASSERT(pFileContext->UseCount > 0);
  393. if (InterlockedDecrement( &pFileContext->UseCount ) <= 0)
  394. {
  395. INC_STATS(TotalContextCtxCallbackFrees);
  396. SrFreeContext( pFileContext );
  397. }
  398. else
  399. {
  400. SrTrace( CONTEXT_LOG, ("Sr!SrpDeleteContextCB: DEFFERED (%p) Fl=%03x Use=%d \"%.*S\"\n",
  401. pFileContext,
  402. pFileContext->Flags,
  403. pFileContext->UseCount,
  404. (pFileContext->FileName.Length+
  405. pFileContext->StreamNameLength)/
  406. sizeof(WCHAR),
  407. pFileContext->FileName.Buffer));
  408. }
  409. }
  410. /***************************************************************************++
  411. Routine Description:
  412. This will link the given context into the context hash table for the
  413. given volume.
  414. NOTE: It is possible for this entry to already exist in the table (since
  415. between the time we initially looked and the time we inserted
  416. (which is now) someone else may have inserted one. If we find an
  417. entry that already exists we will free the entry passed in and
  418. return the entry found.
  419. Arguments:
  420. Return Value:
  421. --***************************************************************************/
  422. VOID
  423. SrLinkContext (
  424. IN PSR_DEVICE_EXTENSION pExtension,
  425. IN PFILE_OBJECT pFileObject,
  426. IN OUT PSR_STREAM_CONTEXT *ppFileContext
  427. )
  428. {
  429. NTSTATUS status;
  430. PSR_STREAM_CONTEXT pFileContext = *ppFileContext;
  431. PSR_STREAM_CONTEXT ctx;
  432. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  433. PAGED_CODE();
  434. ASSERT(pFileObject->FsContext != NULL);
  435. ASSERT(pFileContext != NULL);
  436. //
  437. // If this is flagged as a temporary context then don't link it in
  438. // and return now
  439. //
  440. if (FlagOn(pFileContext->Flags,CTXFL_Temporary))
  441. {
  442. INC_STATS(TotalContextTemporary);
  443. SrTrace( CONTEXT_LOG, ("Sr!SrpLinkContext: Tmp: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  444. pFileContext,
  445. pFileContext->Flags,
  446. pFileContext->UseCount,
  447. (pFileContext->FileName.Length+
  448. pFileContext->StreamNameLength)/
  449. sizeof(WCHAR),
  450. pFileContext->FileName.Buffer));
  451. return;
  452. }
  453. //
  454. // See if this should be a temporary context
  455. //
  456. if (pExtension->ContextCtrl.AllContextsTemporary != 0)
  457. {
  458. //
  459. // yes, don't link into list, mark as temporary
  460. //
  461. SetFlag(pFileContext->Flags,CTXFL_Temporary);
  462. INC_STATS(TotalContextTemporary);
  463. SrTrace( CONTEXT_LOG, ("Sr!SrpLinkContext: AllTmp: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  464. pFileContext,
  465. pFileContext->Flags,
  466. pFileContext->UseCount,
  467. (pFileContext->FileName.Length+
  468. pFileContext->StreamNameLength)/
  469. sizeof(WCHAR),
  470. pFileContext->FileName.Buffer));
  471. return;
  472. }
  473. //
  474. // See if we need to query the link count.
  475. //
  476. if (FlagOn(pFileContext->Flags,CTXFL_QueryLinkCount))
  477. {
  478. FILE_STANDARD_INFORMATION standardInformation;
  479. ClearFlag(pFileContext->Flags,CTXFL_QueryLinkCount);
  480. //
  481. // Retrieve the information to determine if this is a directory or not
  482. //
  483. status = SrQueryInformationFile( pExtension->pTargetDevice,
  484. pFileObject,
  485. &standardInformation,
  486. sizeof( standardInformation ),
  487. FileStandardInformation,
  488. NULL );
  489. if (!NT_SUCCESS( status ))
  490. {
  491. //
  492. // If we hit some error querying this link count here, just
  493. // assume that we need to make this context temporary and don't
  494. // link it into the lists since that is the conservative
  495. // assumption.
  496. //
  497. SetFlag(pFileContext->Flags,CTXFL_Temporary);
  498. return;
  499. }
  500. pFileContext->LinkCount = standardInformation.NumberOfLinks;
  501. if (standardInformation.NumberOfLinks > 1)
  502. {
  503. //
  504. // This file has more than one link to it, therefore to avoid
  505. // aliasing problems, mark this context temporary.
  506. //
  507. SetFlag(pFileContext->Flags,CTXFL_Temporary);
  508. return;
  509. }
  510. //
  511. // This file does not have more than 1 link on it, so we can go ahead
  512. // and try to put this context into the list for others to use.
  513. //
  514. }
  515. //
  516. // We need to figure out if a duplicate entry already exists on
  517. // the context list for this file object. Acquire our list lock
  518. // and then see if it exists. If not insert into all the lists.
  519. // If so then simply free this new entry and return the duplicate.
  520. //
  521. // This can happen for 2 reasons:
  522. // - Someone created an entry at the exact same time as we were
  523. // creating an entry.
  524. // - When someone does a create with overwrite or supersede we
  525. // do not have the information yet to see if a context already
  526. // exists. Because of this we have to create a new context
  527. // everytime. During post-create we then see if one already
  528. // exists.
  529. //
  530. //
  531. // Initalize the context control structure. We do this now so we
  532. // don't have to do it while the lock is held (even if we might
  533. // have to free it because of a duplicate found)
  534. //
  535. FsRtlInitPerStreamContext( &pFileContext->ContextCtrl,
  536. pExtension,
  537. pFileObject->FsContext,
  538. SrpDeleteContextCallback );
  539. //
  540. // Acquire list lock exclusivly
  541. //
  542. SrAcquireContextLockExclusive( pExtension );
  543. ASSERT(pFileContext->UseCount == 1);
  544. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_InExtensionList));
  545. //
  546. // See if we have an entry already on the list
  547. //
  548. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(pFileObject),
  549. pExtension,
  550. NULL );
  551. if (NULL != ctxCtrl)
  552. {
  553. //
  554. // The context already exists so free the new one we just
  555. // created. First increment the use count on the one we found
  556. //
  557. ctx = CONTAINING_RECORD(ctxCtrl,SR_STREAM_CONTEXT,ContextCtrl);
  558. ASSERT(FlagOn(ctx->Flags,CTXFL_InExtensionList));
  559. ASSERT(!FlagOn(ctx->Flags,CTXFL_Temporary));
  560. ASSERT(ctx->UseCount > 0);
  561. //
  562. // See if we should use the found context?
  563. //
  564. if (FlagOn(ctx->Flags,CTXFL_DoNotUse))
  565. {
  566. //
  567. // The found context should not be used so use our current
  568. // context and mark it as temporary. Free the lock.
  569. //
  570. INC_STATS(TotalContextTemporary);
  571. RtlInterlockedSetBitsDiscardReturn(&pFileContext->Flags,CTXFL_Temporary);
  572. SrReleaseContextLock( pExtension );
  573. SrTrace( CONTEXT_LOG, ("Sr!SrpLinkContext: Tmp: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  574. pFileContext,
  575. pFileContext->Flags,
  576. pFileContext->UseCount,
  577. (pFileContext->FileName.Length+
  578. pFileContext->StreamNameLength)/
  579. sizeof(WCHAR),
  580. pFileContext->FileName.Buffer));
  581. }
  582. else
  583. {
  584. //
  585. // Bump ref count and release lock
  586. //
  587. InterlockedIncrement( &ctx->UseCount );
  588. SrReleaseContextLock( pExtension );
  589. //
  590. // Verify the found entry
  591. //
  592. ASSERT(RtlEqualUnicodeString( &pFileContext->FileName,
  593. &ctx->FileName,
  594. TRUE ));
  595. ASSERT(FlagOn(pFileContext->Flags,CTXFL_IsDirectory) == FlagOn(ctx->Flags,CTXFL_IsDirectory));
  596. ASSERT(FlagOn(pFileContext->Flags,CTXFL_IsInteresting) == FlagOn(ctx->Flags,CTXFL_IsInteresting));
  597. SrTrace( CONTEXT_LOG, ("Sr!SrpLinkContext: Rel Dup: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  598. pFileContext,
  599. pFileContext->Flags,
  600. pFileContext->UseCount,
  601. (pFileContext->FileName.Length+
  602. pFileContext->StreamNameLength)/
  603. sizeof(WCHAR),
  604. pFileContext->FileName.Buffer));
  605. //
  606. // Free the new structure because it was already resident. Note
  607. // that this entry has never been linked into any lists so we know
  608. // no one else has a refrence to it. Decrement use count to keep
  609. // the ASSERTS happy then free the memory.
  610. //
  611. INC_STATS(TotalContextDuplicateFrees);
  612. pFileContext->UseCount--;
  613. SrFreeContext( pFileContext );
  614. //
  615. // Return the one we found in the list
  616. //
  617. *ppFileContext = ctx;
  618. }
  619. return;
  620. }
  621. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_Temporary));
  622. //
  623. // Increment the USE count
  624. //
  625. InterlockedIncrement( &pFileContext->UseCount );
  626. //
  627. // Link into Stream context
  628. //
  629. status = FsRtlInsertPerStreamContext( FsRtlGetPerStreamContextPointer(pFileObject),
  630. &pFileContext->ContextCtrl );
  631. ASSERT(status == STATUS_SUCCESS);
  632. //
  633. // Link into Device extension
  634. //
  635. InsertHeadList( &pExtension->ContextCtrl.List, &pFileContext->ExtensionLink );
  636. //
  637. // Mark that we have been inserted into both lists
  638. //
  639. RtlInterlockedSetBitsDiscardReturn( &pFileContext->Flags,
  640. CTXFL_InExtensionList|CTXFL_InStreamList );
  641. //
  642. // Release lock
  643. //
  644. SrReleaseContextLock( pExtension );
  645. }
  646. /***************************************************************************++
  647. Routine Description:
  648. This will allocate and initialize a context structure but it does NOT
  649. link it into the context hash list.
  650. Arguments:
  651. pExtension - The SR device extension for this volume.
  652. pFileObject - The file object for the file on which we are creating a
  653. context.
  654. EventType - The event that is causing us to create this context. This
  655. may also contain other flags that we will use to control our context
  656. creation process.
  657. FileAttributes - Will only be non-zero if the SrEventInPreCreate flag
  658. is set in the EventType field.
  659. pRetContext - Gets set to the context that is generated.
  660. Return Value:
  661. --***************************************************************************/
  662. NTSTATUS
  663. SrCreateContext (
  664. IN PSR_DEVICE_EXTENSION pExtension,
  665. IN PFILE_OBJECT pFileObject,
  666. IN SR_EVENT_TYPE EventType,
  667. IN USHORT FileAttributes,
  668. OUT PSR_STREAM_CONTEXT *pRetContext
  669. )
  670. {
  671. NTSTATUS status = STATUS_SUCCESS;
  672. SRP_NAME_CONTROL nameControl;
  673. FILE_STANDARD_INFORMATION standardInformation;
  674. PSR_STREAM_CONTEXT ctx;
  675. BOOLEAN isDirectory;
  676. ULONG linkCount = 0;
  677. BOOLEAN isInteresting;
  678. BOOLEAN reasonableErrorInPreCreate = FALSE;
  679. ULONG contextSize;
  680. USHORT fileAttributes;
  681. BOOLEAN isVolumeOpen = FALSE;
  682. PAGED_CODE();
  683. //
  684. // initialize to NULL pointer
  685. //
  686. *pRetContext = NULL;
  687. //
  688. // The nameControl structure is used for retrieving file names
  689. // efficiently. It contains a small buffer for holding names. If this
  690. // buffer is not big enough we will dynamically allocate a bigger buffer.
  691. // The goal is to have most names fit in the buffer on the stack.
  692. //
  693. SrpInitNameControl( &nameControl );
  694. //
  695. // See if they have explicitly told us if this is a directory or not. If
  696. // neither then query for the directory.
  697. //
  698. if (FlagOn(EventType,SrEventIsDirectory))
  699. {
  700. isDirectory = TRUE;
  701. #if DBG
  702. //
  703. // Verify this really is a directory
  704. //
  705. status = SrQueryInformationFile( pExtension->pTargetDevice,
  706. pFileObject,
  707. &standardInformation,
  708. sizeof( standardInformation ),
  709. FileStandardInformation,
  710. NULL );
  711. ASSERT(!NT_SUCCESS_NO_DBGBREAK(status) || standardInformation.Directory);
  712. #endif
  713. }
  714. else if (FlagOn(EventType,SrEventIsNotDirectory))
  715. {
  716. isDirectory = FALSE;
  717. #if DBG
  718. //
  719. // Verify this really is NOT a directory. We can not do this check
  720. // if we are in pre-create.
  721. //
  722. if (!FlagOn( EventType, SrEventInPreCreate ))
  723. {
  724. status = SrQueryInformationFile( pExtension->pTargetDevice,
  725. pFileObject,
  726. &standardInformation,
  727. sizeof( standardInformation ),
  728. FileStandardInformation,
  729. NULL );
  730. ASSERT(!NT_SUCCESS_NO_DBGBREAK(status) || !standardInformation.Directory);
  731. }
  732. else
  733. {
  734. ASSERT(FlagOn(EventType,SrEventStreamOverwrite));
  735. }
  736. #endif
  737. }
  738. else
  739. {
  740. ASSERT(pFileObject->FsContext != NULL);
  741. //
  742. // Retrieve the information to determine if this is a directory or not
  743. //
  744. status = SrQueryInformationFile( pExtension->pTargetDevice,
  745. pFileObject,
  746. &standardInformation,
  747. sizeof( standardInformation ),
  748. FileStandardInformation,
  749. NULL );
  750. if (status == STATUS_INVALID_PARAMETER)
  751. {
  752. //
  753. // pFileObject represents an open to the volume. The file system
  754. // won't let us query information on volume opens.
  755. //
  756. // Any operations on this file object won't be of interest to us
  757. // and there is no need for us to do any of our name generation
  758. // work, so initialize the appropriate variables and jump down
  759. // to the context creation.
  760. //
  761. status = STATUS_SUCCESS;
  762. isInteresting = FALSE;
  763. isDirectory = FALSE;
  764. isVolumeOpen = TRUE;
  765. goto InitContext;
  766. }
  767. else if (!NT_SUCCESS( status ))
  768. {
  769. goto Cleanup;
  770. }
  771. //
  772. // Flag if this is a directory or not
  773. //
  774. INC_STATS(TotalContextDirectoryQuerries);
  775. isDirectory = standardInformation.Directory;
  776. linkCount = standardInformation.NumberOfLinks;
  777. SrTrace( CONTEXT_LOG_DETAILED,
  778. ("Sr!SrpCreateContext: QryDir: Event=%06x Dir=%d\n",
  779. EventType,
  780. isDirectory) );
  781. }
  782. if (FlagOn( EventType, SrEventInPreCreate ))
  783. {
  784. fileAttributes = FileAttributes;
  785. }
  786. else
  787. {
  788. FILE_BASIC_INFORMATION basicInformation;
  789. status = SrQueryInformationFile( pExtension->pTargetDevice,
  790. pFileObject,
  791. &basicInformation,
  792. sizeof( basicInformation ),
  793. FileBasicInformation,
  794. NULL );
  795. if (!NT_SUCCESS( status ))
  796. {
  797. goto Cleanup;
  798. }
  799. fileAttributes = (USHORT) basicInformation.FileAttributes;
  800. }
  801. //
  802. // We are interested in all directories, but we are not interested in
  803. // files that have the following attributes:
  804. // FILE_ATTRIBUTE_SPARSE_FILE
  805. // FILE_ATTRIBUTE_REPARSE_POINT
  806. //
  807. // If either of these are set, the file is not interesting.
  808. //
  809. if (!isDirectory &&
  810. FlagOn( fileAttributes,
  811. (FILE_ATTRIBUTE_SPARSE_FILE | FILE_ATTRIBUTE_REPARSE_POINT) ))
  812. {
  813. isInteresting = FALSE;
  814. #if DBG
  815. //
  816. // For debug purposes, we may still want to keep the name for
  817. // file.
  818. //
  819. if (FlagOn(_globals.DebugControl,SR_DEBUG_KEEP_CONTEXT_NAMES))
  820. {
  821. BOOLEAN temp;
  822. status = SrIsFileEligible( pExtension,
  823. pFileObject,
  824. isDirectory,
  825. EventType,
  826. &nameControl,
  827. &temp,
  828. &reasonableErrorInPreCreate );
  829. if (!NT_SUCCESS_NO_DBGBREAK( status ))
  830. {
  831. goto Cleanup;
  832. }
  833. }
  834. #endif
  835. }
  836. else
  837. {
  838. //
  839. // Determine if this file is interesting or not. Note that this
  840. // returns the full name of the file if it is interesting.
  841. //
  842. status = SrIsFileEligible( pExtension,
  843. pFileObject,
  844. isDirectory,
  845. EventType,
  846. &nameControl,
  847. &isInteresting,
  848. &reasonableErrorInPreCreate );
  849. if (!NT_SUCCESS_NO_DBGBREAK( status ))
  850. {
  851. goto Cleanup;
  852. }
  853. }
  854. InitContext:
  855. //
  856. // now allocate a new context structure. Note that we do this even
  857. // if the file is not interesting. If this is a NON-DEBUG OS then
  858. // we will not store the names. In the DEBUG OS we always store the
  859. // name.
  860. //
  861. contextSize = sizeof(SR_STREAM_CONTEXT);
  862. if (isInteresting ||
  863. FlagOn(_globals.DebugControl,SR_DEBUG_KEEP_CONTEXT_NAMES))
  864. {
  865. contextSize += (nameControl.Name.Length +
  866. nameControl.StreamNameLength +
  867. sizeof(WCHAR));
  868. }
  869. ctx = ExAllocatePoolWithTag( PagedPool,
  870. contextSize,
  871. SR_STREAM_CONTEXT_TAG );
  872. if (!ctx)
  873. {
  874. status = STATUS_INSUFFICIENT_RESOURCES;
  875. goto Cleanup;
  876. }
  877. #if DBG
  878. INC_STATS(TotalContextCreated);
  879. if (isDirectory) INC_STATS(TotalContextDirectories);
  880. if (isInteresting) INC_STATS(TotalContextIsEligible);
  881. #endif
  882. //
  883. // Initialize the context structure indcluding setting of the name
  884. //
  885. RtlZeroMemory(ctx,sizeof(SR_STREAM_CONTEXT));
  886. ctx->UseCount = 1;
  887. //ctx->Flags = 0; //zeroed with structure just above
  888. if (isDirectory) SetFlag(ctx->Flags,CTXFL_IsDirectory);
  889. if (isInteresting) SetFlag(ctx->Flags,CTXFL_IsInteresting);
  890. if (isVolumeOpen) SetFlag(ctx->Flags,CTXFL_IsVolumeOpen);
  891. //
  892. // ISSUE-2001-02-16-NealCh When SR is ported to the FilterMgr the
  893. // contexts need to be made FILE contexts instead of STREAM
  894. // contexts.
  895. //
  896. // Because contexts are tracked per stream instead of per file we need
  897. // to mark all contexts associated with a stream as temporary. This
  898. // problem showed up when renaming a file into/out of monitored
  899. // space and we were not properly updating the stream contexts. When a
  900. // file is renamed, we need to invalid all stream contexts for the file,
  901. // but we cannot easily do this in the current model.
  902. //
  903. if (nameControl.StreamNameLength != 0)
  904. {
  905. SetFlag(ctx->Flags,CTXFL_Temporary);
  906. }
  907. //
  908. // If this file has more than link, we need to mark the context
  909. // as temporary to avoid aliasing problems.
  910. //
  911. // Also note that if the file is being deleted, the link count has already
  912. // been decremented for the pending removal of that link. Therefore, if
  913. // this is for an SrEventFileDelete event, we must use a temporary context
  914. // if the linkCount > 0.
  915. //
  916. if ((linkCount > 1) ||
  917. (FlagOn( EventType, SrEventFileDelete ) && (linkCount > 0)))
  918. {
  919. SetFlag(ctx->Flags,CTXFL_Temporary);
  920. }
  921. else if (linkCount == 0 && !isDirectory && !isVolumeOpen)
  922. {
  923. //
  924. // We only have to query the link count for files and
  925. // there are some paths where we don't know the link count and cannot
  926. // determine it yet (for example, in the pre-create path, we don't
  927. // have a valid file object to use to query the file sytem for this
  928. // information). In this case, flag the context as such and we will
  929. // do the query when we link the context into FilterContexts.
  930. //
  931. SetFlag(ctx->Flags,CTXFL_QueryLinkCount);
  932. }
  933. //
  934. // In all cases, store the current link count in the context.
  935. //
  936. ctx->LinkCount = linkCount;
  937. //
  938. // We normally only keep the name if it is interesting. If the debug
  939. // flag to keep the name is on, keep that name also. Note also that
  940. // we try to keep the name of the stream seperate (so we can see it)
  941. // but it is not part of the actual name
  942. //
  943. if (isInteresting ||
  944. FlagOn(_globals.DebugControl,SR_DEBUG_KEEP_CONTEXT_NAMES))
  945. {
  946. //
  947. // Insert the file name (include the stream name if they want it)
  948. //
  949. RtlInitEmptyUnicodeString( &ctx->FileName,
  950. (PWCHAR)(ctx + 1),
  951. contextSize - sizeof(SR_STREAM_CONTEXT) );
  952. //
  953. // We use this routine (instead of copy unicode string) because
  954. // we want to copy the stream name in as well
  955. //
  956. RtlCopyMemory( ctx->FileName.Buffer,
  957. nameControl.Name.Buffer,
  958. nameControl.Name.Length + nameControl.StreamNameLength );
  959. ctx->FileName.Length = nameControl.Name.Length;
  960. ctx->StreamNameLength = nameControl.StreamNameLength;
  961. }
  962. else
  963. {
  964. //
  965. // Set a NULL filename
  966. //
  967. /*RtlInitEmptyUnicodeString( &ctx->FileName,
  968. NULL,
  969. 0 );*/ //zeroed above with structure
  970. //ctx->StreamNameLength = 0; //zeroed above with structure
  971. }
  972. //
  973. // Return the object context
  974. //
  975. *pRetContext = ctx;
  976. //
  977. // Cleanup the local nameControl structure
  978. //
  979. Cleanup:
  980. //
  981. // See if we need to disable logging. We will in the following
  982. // situations:
  983. // - We are in PRE-CREATE and we got an unreasonable error.
  984. // - We get an out of memory error at any time
  985. // - We are in all other operations and we get a non-volume related error
  986. //
  987. if (((!FlagOn(EventType, SrEventInPreCreate)) ||
  988. !reasonableErrorInPreCreate ||
  989. (STATUS_INSUFFICIENT_RESOURCES == status)) &&
  990. CHECK_FOR_VOLUME_ERROR(status))
  991. {
  992. //
  993. // Trigger the failure notification to the service.
  994. //
  995. NTSTATUS tempStatus = SrNotifyVolumeError( pExtension,
  996. &nameControl.Name,
  997. status,
  998. EventType );
  999. CHECK_STATUS(tempStatus);
  1000. }
  1001. SrpCleanupNameControl( &nameControl );
  1002. return status;
  1003. }
  1004. /***************************************************************************++
  1005. Routine Description:
  1006. This will see if a given context already exists. If not it will create
  1007. one and return it. Note: the return context pointer is NULL on a
  1008. failure.
  1009. This will also see if all contexts are to be temporary (global flag in
  1010. the extension). If so, a temproary context is always created. It also
  1011. see if the context that is found is being renamed. If so then a
  1012. temporary context is also created and returned.
  1013. Arguments:
  1014. Return Value:
  1015. --***************************************************************************/
  1016. NTSTATUS
  1017. SrGetContext (
  1018. IN PSR_DEVICE_EXTENSION pExtension,
  1019. IN PFILE_OBJECT pFileObject,
  1020. IN SR_EVENT_TYPE EventType,
  1021. OUT PSR_STREAM_CONTEXT *pRetContext
  1022. )
  1023. {
  1024. PSR_STREAM_CONTEXT pFileContext;
  1025. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  1026. NTSTATUS status;
  1027. BOOLEAN makeTemporary = FALSE;
  1028. PAGED_CODE();
  1029. //
  1030. // Bump total search count
  1031. //
  1032. INC_STATS(TotalContextSearches);
  1033. //
  1034. // See if the all-contexts-temporary state is on. If not then do
  1035. // the normal search.
  1036. //
  1037. if (pExtension->ContextCtrl.AllContextsTemporary == 0)
  1038. {
  1039. //
  1040. // Try and locate the context structure. We acquire the list lock
  1041. // so that we can gurantee that the context will not go away between
  1042. // the time when we find it and can increment the use count
  1043. //
  1044. SrAcquireContextLockShared( pExtension );
  1045. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(pFileObject),
  1046. pExtension,
  1047. NULL );
  1048. if (NULL != ctxCtrl)
  1049. {
  1050. //
  1051. // We found and entry
  1052. //
  1053. pFileContext = CONTAINING_RECORD(ctxCtrl,SR_STREAM_CONTEXT,ContextCtrl);
  1054. ASSERT(FlagOn(pFileContext->Flags,CTXFL_InExtensionList));
  1055. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_Temporary));
  1056. ASSERT(pFileContext->UseCount > 0);
  1057. //
  1058. // See if this file is in the middle of an operation that makes
  1059. // the name possibly stale (e.g., rename, hardlink creation)
  1060. //
  1061. if (FlagOn(pFileContext->Flags,CTXFL_DoNotUse))
  1062. {
  1063. //
  1064. // We should not use this context, unlock and set flag so we
  1065. // will create a temporary context.
  1066. //
  1067. SrReleaseContextLock( pExtension );
  1068. makeTemporary = TRUE;
  1069. NULLPTR(pFileContext);
  1070. }
  1071. else
  1072. {
  1073. //
  1074. // We want this context so bump the use count and release
  1075. // the lock
  1076. //
  1077. InterlockedIncrement( &pFileContext->UseCount );
  1078. SrReleaseContextLock( pExtension );
  1079. INC_STATS(TotalContextFound);
  1080. SrTrace( CONTEXT_LOG, ("Sr!SrGetContext: Found: (%p) Event=%06x Fl=%03x Use=%d \"%.*S\"\n",
  1081. pFileContext,
  1082. EventType,
  1083. pFileContext->Flags,
  1084. pFileContext->UseCount,
  1085. (pFileContext->FileName.Length+
  1086. pFileContext->StreamNameLength)/
  1087. sizeof(WCHAR),
  1088. pFileContext->FileName.Buffer ));
  1089. //
  1090. // Return the found context
  1091. //
  1092. *pRetContext = pFileContext;
  1093. return STATUS_SUCCESS;
  1094. }
  1095. }
  1096. else
  1097. {
  1098. //
  1099. // We didn't find a context, release the lock
  1100. //
  1101. SrReleaseContextLock( pExtension );
  1102. }
  1103. }
  1104. //
  1105. // See if contexts are supported for this particular file. Note that
  1106. // NTFS does not support contexts on paging files.
  1107. //
  1108. ASSERT(FsRtlGetPerStreamContextPointer(pFileObject) != NULL);
  1109. if (!FlagOn(FsRtlGetPerStreamContextPointer(pFileObject)->Flags2,FSRTL_FLAG2_SUPPORTS_FILTER_CONTEXTS))
  1110. {
  1111. INC_STATS(TotalContextsNotSupported);
  1112. *pRetContext = NULL;
  1113. return SR_STATUS_CONTEXT_NOT_SUPPORTED;
  1114. }
  1115. //
  1116. // If we get here we need to create a context, do it
  1117. //
  1118. ASSERT( !FlagOn( EventType, SrEventInPreCreate ) );
  1119. status = SrCreateContext( pExtension,
  1120. pFileObject,
  1121. EventType,
  1122. 0,
  1123. &pFileContext );
  1124. if (!NT_SUCCESS_NO_DBGBREAK( status ))
  1125. {
  1126. *pRetContext = NULL;
  1127. return status;
  1128. }
  1129. //
  1130. // Mark context temporary (if requested)
  1131. //
  1132. if (makeTemporary)
  1133. {
  1134. RtlInterlockedSetBitsDiscardReturn(&pFileContext->Flags,CTXFL_Temporary);
  1135. INC_STATS(TotalContextTemporary);
  1136. SrTrace( CONTEXT_LOG, ("Sr!SrpLinkContext: RenAllTmp: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  1137. pFileContext,
  1138. pFileContext->Flags,
  1139. pFileContext->UseCount,
  1140. (pFileContext->FileName.Length+
  1141. pFileContext->StreamNameLength)/
  1142. sizeof(WCHAR),
  1143. pFileContext->FileName.Buffer));
  1144. }
  1145. else
  1146. {
  1147. //
  1148. // Insert the context into the linked list. Note that the
  1149. // link routine will see if this entry has already been added to
  1150. // the list (could happen while we were building it). If so it
  1151. // will release the one we created and use the one it found in
  1152. // the list. It will return the new entry (if it was changed).
  1153. // The link routine properly handles temporary contexts.
  1154. //
  1155. SrLinkContext( pExtension,
  1156. pFileObject,
  1157. &pFileContext );
  1158. }
  1159. SrTrace( CONTEXT_LOG, ("Sr!SrGetContext: Created%s (%p) Event=%06x Fl=%03x Use=%d \"%.*S\"\n",
  1160. (FlagOn(pFileContext->Flags,CTXFL_Temporary) ? "Tmp:" : ": "),
  1161. pFileContext,
  1162. EventType,
  1163. pFileContext->Flags,
  1164. pFileContext->UseCount,
  1165. (pFileContext->FileName.Length+
  1166. pFileContext->StreamNameLength)/
  1167. sizeof(WCHAR),
  1168. pFileContext->FileName.Buffer));
  1169. //
  1170. // Return the context
  1171. //
  1172. ASSERT(pFileContext->UseCount > 0);
  1173. *pRetContext = pFileContext;
  1174. return STATUS_SUCCESS;
  1175. }
  1176. /***************************************************************************++
  1177. Routine Description:
  1178. This will see if the given context already exists. If so it will
  1179. bump the refrence count and return the context. If not, NULL
  1180. is returned.
  1181. oArguments:
  1182. Return Value:
  1183. --***************************************************************************/
  1184. PSR_STREAM_CONTEXT
  1185. SrFindExistingContext (
  1186. IN PSR_DEVICE_EXTENSION pExtension,
  1187. IN PFILE_OBJECT pFileObject
  1188. )
  1189. {
  1190. PSR_STREAM_CONTEXT pFileContext;
  1191. PFSRTL_PER_STREAM_CONTEXT ctxCtrl;
  1192. PAGED_CODE();
  1193. //
  1194. // Try and locate the context structure. We acquire the list lock
  1195. // so that we can gurantee that the context will not go away between
  1196. // the time when we find it and can increment the use count
  1197. //
  1198. INC_STATS(TotalContextSearches);
  1199. SrAcquireContextLockShared( pExtension );
  1200. ctxCtrl = FsRtlLookupPerStreamContext( FsRtlGetPerStreamContextPointer(pFileObject),
  1201. pExtension,
  1202. NULL );
  1203. if (NULL != ctxCtrl)
  1204. {
  1205. //
  1206. // We found the entry, increment use count
  1207. //
  1208. pFileContext = CONTAINING_RECORD(ctxCtrl,SR_STREAM_CONTEXT,ContextCtrl);
  1209. InterlockedIncrement( &pFileContext->UseCount );
  1210. //
  1211. // Release the list lock
  1212. //
  1213. SrReleaseContextLock( pExtension );
  1214. INC_STATS(TotalContextFound);
  1215. //
  1216. // arbitrary test to see if there are too many concurrent accesses
  1217. // to this context.
  1218. //
  1219. ASSERT(pFileContext->UseCount < 10);
  1220. SrTrace( CONTEXT_LOG, ("Sr!FindExistingContext: Found: (%p) Fl=%03x Use=%d \"%.*S\"\n",
  1221. pFileContext,
  1222. pFileContext->Flags,
  1223. pFileContext->UseCount,
  1224. (pFileContext->FileName.Length+
  1225. pFileContext->StreamNameLength)/
  1226. sizeof(WCHAR),
  1227. pFileContext->FileName.Buffer));
  1228. }
  1229. else
  1230. {
  1231. //
  1232. // Release the list lock while we create the new context.
  1233. //
  1234. SrReleaseContextLock( pExtension );
  1235. pFileContext = NULL;
  1236. }
  1237. return pFileContext;
  1238. }
  1239. /***************************************************************************++
  1240. Routine Description:
  1241. This routine takes a context and does the necessary work to make it
  1242. uninteresting. This can happen when a file is renamed into the store.
  1243. Arguments:
  1244. Return Value:
  1245. --***************************************************************************/
  1246. VOID
  1247. SrMakeContextUninteresting (
  1248. IN PSR_STREAM_CONTEXT pFileContext
  1249. )
  1250. {
  1251. RtlInterlockedClearBitsDiscardReturn( &pFileContext->Flags,
  1252. CTXFL_IsInteresting );
  1253. }
  1254. /***************************************************************************++
  1255. Routine Description:
  1256. This decrements the use count for the given context. If it goes to zero
  1257. it frees the memory.
  1258. Arguments:
  1259. Return Value:
  1260. --***************************************************************************/
  1261. VOID
  1262. SrReleaseContext (
  1263. IN PSR_STREAM_CONTEXT pFileContext
  1264. )
  1265. {
  1266. PAGED_CODE();
  1267. SrTrace( CONTEXT_LOG_DETAILED, ("Sr!SrReleaseContext: Release (%p) Fl=%03x Use=%d \"%.*S\"\n",
  1268. pFileContext,
  1269. pFileContext->Flags,
  1270. pFileContext->UseCount,
  1271. (pFileContext->FileName.Length+
  1272. pFileContext->StreamNameLength)/
  1273. sizeof(WCHAR),
  1274. pFileContext->FileName.Buffer));
  1275. //
  1276. // Decrement USE count, free context if zero
  1277. //
  1278. ASSERT(pFileContext->UseCount > 0);
  1279. if (InterlockedDecrement( &pFileContext->UseCount ) <= 0)
  1280. {
  1281. ASSERT(!FlagOn(pFileContext->Flags,CTXFL_InExtensionList));
  1282. //
  1283. // Free the memory
  1284. //
  1285. SrTrace( CONTEXT_LOG, ("Sr!SrReleaseContext: Freeing (%p) Fl=%03x Use=%d \"%.*S\"\n",
  1286. pFileContext,
  1287. pFileContext->Flags,
  1288. pFileContext->UseCount,
  1289. (pFileContext->FileName.Length+
  1290. pFileContext->StreamNameLength)/
  1291. sizeof(WCHAR),
  1292. pFileContext->FileName.Buffer));
  1293. INC_STATS(TotalContextDeferredFrees);
  1294. SrFreeContext( pFileContext );
  1295. }
  1296. }