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.

1808 lines
52 KiB

  1. //+---------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. // Copyright (C) Microsoft Corporation, 1992 - 2000.
  5. //
  6. // File: notifmgr.cxx
  7. //
  8. // Contents: Registry and file system change notifications
  9. //
  10. // History: 14-Jul-97 SitaramR Created from dlnotify.cxx
  11. //
  12. // Notes : For lock hierarchy and order of acquiring locks, please see
  13. // cicat.cxx
  14. //
  15. //----------------------------------------------------------------------------
  16. #include <pch.cxx>
  17. #pragma hdrstop
  18. #include <ciregkey.hxx>
  19. #include <cistore.hxx>
  20. #include <rcstxact.hxx>
  21. #include <imprsnat.hxx>
  22. #include <eventlog.hxx>
  23. #include <docstore.hxx>
  24. #include "cicat.hxx"
  25. #include "update.hxx"
  26. #include "notifmgr.hxx"
  27. #include "scanmgr.hxx"
  28. #include "scopetbl.hxx"
  29. BOOL AreIdenticalPaths( WCHAR const * pwcsPath1, WCHAR const * pwcsPath2 )
  30. {
  31. ULONG len1 = wcslen( pwcsPath1 );
  32. ULONG len2 = wcslen( pwcsPath2 );
  33. return len1 == len2 &&
  34. RtlEqualMemory( pwcsPath1, pwcsPath2, len1*sizeof(WCHAR) );
  35. }
  36. //+---------------------------------------------------------------------------
  37. //
  38. // Member: CCiNotify::CCiNotify
  39. //
  40. // Synopsis: Constructor of the single scope notification object CCiNotify.
  41. //
  42. // Arguments: [notifyMgr] -- Notification manager.
  43. // [wcsScope] -- Scope of the notification.
  44. // [cwcScope] -- Length in chars of [wcsScope]
  45. // [volumeId] -- Volume id
  46. // [ftlastScan] -- Last scan time
  47. // [usn] -- Usn
  48. // [fDeep] -- Set to TRUE if deep notifications are enabled.
  49. //
  50. // History: 1-17-96 srikants Created
  51. //
  52. //----------------------------------------------------------------------------
  53. CCiNotify::CCiNotify( CCiNotifyMgr & notifyMgr,
  54. WCHAR const * wcsScope,
  55. unsigned cwcScope,
  56. VOLUMEID volumeId,
  57. ULONGLONG const & VolumeCreationTime,
  58. ULONG VolumeSerialNumber,
  59. FILETIME const & ftLastScan,
  60. USN usn,
  61. ULONGLONG const & JournalId,
  62. BOOL fUsnTreeScan,
  63. BOOL fDeep )
  64. : CGenericNotify( & notifyMgr.GetCatalog(), wcsScope, cwcScope, fDeep, TRUE ),
  65. _sigCiNotify(sigCiNotify),
  66. _notifyMgr(notifyMgr),
  67. _volumeId(volumeId),
  68. _VolumeCreationTime( VolumeCreationTime ),
  69. _VolumeSerialNumber( VolumeSerialNumber ),
  70. _fUsnTreeScan(fUsnTreeScan)
  71. {
  72. if ( volumeId == CI_VOLID_USN_NOT_ENABLED )
  73. _ftLastScan = ftLastScan;
  74. else
  75. {
  76. _usn = usn;
  77. _JournalId = JournalId;
  78. }
  79. _notifyMgr.AddRef();
  80. XInterface<CCiNotifyMgr> xNotify( &notifyMgr );
  81. if ( volumeId == CI_VOLID_USN_NOT_ENABLED )
  82. {
  83. //
  84. // Enable file system notifications for non-usn volumes
  85. //
  86. EnableNotification();
  87. }
  88. xNotify.Acquire();
  89. } //CCiNotify
  90. //+---------------------------------------------------------------------------
  91. //
  92. // Member: CCiNotify::~CCiNotify
  93. //
  94. // Synopsis: Destructor
  95. //
  96. // History: 05-07-97 SitaramR Added Header
  97. //
  98. //----------------------------------------------------------------------------
  99. CCiNotify::~CCiNotify()
  100. {
  101. _notifyMgr.Release();
  102. }
  103. //+---------------------------------------------------------------------------
  104. //
  105. // Member: CCiNotify::Abort
  106. //
  107. // Synopsis: Marks that an abort is in progress. Also disables further
  108. // notifications for this scope.
  109. //
  110. // History: 1-17-96 srikants Created
  111. //
  112. //----------------------------------------------------------------------------
  113. void CCiNotify::Abort()
  114. {
  115. _fAbort = TRUE;
  116. if ( _volumeId == CI_VOLID_USN_NOT_ENABLED )
  117. {
  118. //
  119. // Notifications are enabled only for those volumes that
  120. // do not support usns.
  121. //
  122. DisableNotification();
  123. }
  124. else
  125. {
  126. //
  127. // Ctor of CGenericNotify does an AddRef, which is released by
  128. // the APC for non-usn volumes. For usn volumes do the Release here.
  129. //
  130. Release();
  131. }
  132. }
  133. //+---------------------------------------------------------------------------
  134. //
  135. // Member: CCiNotify::IsMatch
  136. //
  137. // Synopsis: Checks if the given path is within the scope of the notifi-
  138. // cations. If deep notifications are enabled, it is sufficient
  139. // for the notification scope to be a subset of the given path.
  140. // Otherwise, there must be an exact match.
  141. //
  142. // Arguments: [wcsPath] - Path to be tested.
  143. // [len] - Length of wcsPath.
  144. //
  145. // Returns: TRUE if there is a match. FALSE o/w
  146. //
  147. // History: 1-18-96 srikants Created
  148. //
  149. //----------------------------------------------------------------------------
  150. BOOL CCiNotify::IsMatch( WCHAR const * wcsPath, ULONG len ) const
  151. {
  152. CScopeMatch match( GetScope(), ScopeLength() );
  153. return match.IsInScope( wcsPath, len );
  154. }
  155. //+---------------------------------------------------------------------------
  156. //
  157. // Member: CCiNotifyMgr::QueryAsyncWorkItem
  158. //
  159. // Synopsis: Creates an async work item to process notifications.
  160. //
  161. // Arguments: [pbChanges] - Buffer of changes
  162. // [cbChanges] - Number of bytes in pbChanges
  163. // [pwcsRoot] - The directory root where the change happened.
  164. //
  165. // Returns: A pointer to an async work item
  166. //
  167. // History: 1-03-97 srikants Moved from hxx file to use the new
  168. // CWorkManager.
  169. //
  170. //----------------------------------------------------------------------------
  171. CCiAsyncProcessNotify * CCiNotifyMgr::QueryAsyncWorkItem(
  172. BYTE const * pbChanges,
  173. ULONG cbChanges,
  174. WCHAR const * pwcsRoot )
  175. {
  176. XArray<BYTE> xChanges( cbChanges );
  177. RtlCopyMemory( xChanges.GetPointer(), pbChanges, cbChanges );
  178. CWorkManager & workMan = _cicat.GetWorkMan();
  179. return new CCiAsyncProcessNotify( workMan,
  180. _cicat,
  181. _scanMgr,
  182. xChanges,
  183. pwcsRoot );
  184. }
  185. //+---------------------------------------------------------------------------
  186. //
  187. // Member: CCiNotify::DoIt()
  188. //
  189. // Synopsis: Called from APC.
  190. //
  191. // History: 1-17-96 srikants Created
  192. //
  193. //----------------------------------------------------------------------------
  194. void CCiNotify::DoIt()
  195. {
  196. BOOL fNotifyReEnabled = FALSE; // Indicates if the notification was reenabled
  197. // successfully
  198. NTSTATUS status = STATUS_SUCCESS;
  199. TRY
  200. {
  201. #if 0
  202. XPtr<CCiAsyncProcessNotify> xWorker;
  203. #endif // 0
  204. if ( _fAbort )
  205. ciDebugOut(( DEB_ITRACE, "CiNotification APC: ABORT (IGNORE) 0x%x\n", this ));
  206. else
  207. {
  208. if ( !BufferOverflow() )
  209. {
  210. ciDebugOut(( DEB_ITRACE, "CiNotification APC: CHANGES 0x%x\n", this ));
  211. #if 0
  212. xWorker.Set( _notifyMgr.QueryAsyncWorkItem( GetBuf(),
  213. BufLength(),
  214. GetScope()) );
  215. #else
  216. _notifyMgr.ProcessChanges( GetBuf(),
  217. GetScope() );
  218. #endif // 0
  219. }
  220. // ==================================================
  221. {
  222. //
  223. // Re-enable the notification for this scope.
  224. //
  225. CLock lock(_notifyMgr.GetMutex());
  226. StartNotification(&status);
  227. fNotifyReEnabled = SUCCEEDED(status);
  228. }
  229. // ==================================================
  230. if ( BufferOverflow() )
  231. _notifyMgr.SetupScan( GetScope() );
  232. }
  233. #if 0
  234. if ( 0 != xWorker.GetPointer() )
  235. {
  236. _notifyMgr.ProcessChanges( xWorker );
  237. }
  238. #endif // 0
  239. }
  240. CATCH(CException, e)
  241. {
  242. ciDebugOut(( DEB_ERROR, "CiNotification APC: CATCH 0x%x\n", e.GetErrorCode() ));
  243. status = e.GetErrorCode();
  244. }
  245. END_CATCH;
  246. if ( !_fAbort && !fNotifyReEnabled )
  247. {
  248. LogNotificationsFailed( status );
  249. CLock lock( _notifyMgr.GetMutex() );
  250. LokClearNotifyEnabled();
  251. }
  252. }
  253. //+---------------------------------------------------------------------------
  254. //
  255. // Member: CCiNotify::ClearNotifyEnabled
  256. //
  257. // Synopsis: Clears the flag to indicate that notifications are disabled
  258. // for this scope. This will permit periodic scanning of scopes
  259. // by the scan thread.
  260. //
  261. // History: 5-03-96 srikants Created
  262. //
  263. // Notes: The operation must be done under a lock.
  264. //
  265. //----------------------------------------------------------------------------
  266. void CCiNotify::ClearNotifyEnabled()
  267. {
  268. CLock lock( _notifyMgr.GetMutex() );
  269. LokClearNotifyEnabled();
  270. }
  271. //+---------------------------------------------------------------------------
  272. //
  273. // Member: CVRootNotify::CVRootNotify, public
  274. //
  275. // Synopsis: Constructor for object to watch IIS vroot changes
  276. //
  277. // Arguments: [cat] -- Catalog
  278. // [eType] -- Type of vroot
  279. // [Instance] -- Instance # of the vserver
  280. // [notifyMgr] -- Notify manager controller
  281. //
  282. // History: 2-20-96 KyleP Created
  283. //
  284. //----------------------------------------------------------------------------
  285. CVRootNotify::CVRootNotify(
  286. CiCat & cat,
  287. CiVRootTypeEnum eType,
  288. ULONG Instance,
  289. CCiNotifyMgr & notifyMgr )
  290. : _type( eType ),
  291. _cat( cat ),
  292. _notifyMgr( notifyMgr ),
  293. _mdMgr( FALSE, eType, Instance )
  294. {
  295. _mdMgr.EnableVPathNotify( this );
  296. }
  297. //+---------------------------------------------------------------------------
  298. //
  299. // Member: CRegistryScopesNotify::CRegistryScopesNotify
  300. //
  301. // Synopsis: Constructor for object to watch ci scopes
  302. //
  303. // Arguments: [cat] -- Catalog
  304. //
  305. // History: 10-16-96 dlee Created
  306. //
  307. //----------------------------------------------------------------------------
  308. CRegistryScopesNotify::CRegistryScopesNotify(
  309. CiCat & cat,
  310. CCiNotifyMgr & notifyMgr )
  311. : _cat( cat ),
  312. _notifyMgr( notifyMgr ),
  313. CRegNotify( cat.GetScopesKey() )
  314. {
  315. _notifyMgr.AddRef();
  316. }
  317. //+---------------------------------------------------------------------------
  318. //
  319. // Member: CCiRegistryNotify::CCiRegistryNotify
  320. //
  321. // Synopsis: Constructor for the CCiRegistryNotify.
  322. //
  323. // Arguments: [cat] -
  324. // [notifyMgr] -
  325. //
  326. // History: 12-12-96 srikants Created
  327. //
  328. //----------------------------------------------------------------------------
  329. CCiRegistryNotify::CCiRegistryNotify(
  330. CiCat & cat,
  331. CCiNotifyMgr & notifyMgr )
  332. : _cat( cat ),
  333. _notifyMgr( notifyMgr ),
  334. CRegNotify( wcsRegAdminTree )
  335. {
  336. _notifyMgr.AddRef();
  337. }
  338. //+---------------------------------------------------------------------------
  339. //
  340. // Member: CVRootNotify::DisableNotification, public
  341. //
  342. // Synopsis: Turns off notifications (if on )
  343. //
  344. // History: 2-13-97 dlee Created
  345. //
  346. //----------------------------------------------------------------------------
  347. void CVRootNotify::DisableNotification()
  348. {
  349. // Need TRY since RPC may access violate if iisadmin has gone down
  350. TRY
  351. {
  352. _mdMgr.DisableVPathNotify();
  353. }
  354. CATCH( CException, e )
  355. {
  356. ciDebugOut(( DEB_WARN,
  357. "CVRootNotify::DisableNotification caught exception 0x%x\n",
  358. e.GetErrorCode() ));
  359. }
  360. END_CATCH
  361. }
  362. //+---------------------------------------------------------------------------
  363. //
  364. // Member: CRegistryScopesNotify::~CRegistryScopesNotify
  365. //
  366. // Synopsis: Destructor.
  367. //
  368. // History: 10-16-96 dlee Created
  369. //
  370. //----------------------------------------------------------------------------
  371. CRegistryScopesNotify::~CRegistryScopesNotify()
  372. {
  373. _notifyMgr.Release();
  374. }
  375. //+---------------------------------------------------------------------------
  376. //
  377. // Member: CCiRegistryNotify::~CCiRegistryNotify
  378. //
  379. // Synopsis: Destructor
  380. //
  381. // History: 12-12-96 srikants Created
  382. //
  383. //----------------------------------------------------------------------------
  384. CCiRegistryNotify::~CCiRegistryNotify()
  385. {
  386. _notifyMgr.Release();
  387. }
  388. //+---------------------------------------------------------------------------
  389. //
  390. // Member: CVRootNotify::CallBack, public
  391. //
  392. // Synopsis: Callback from metabase connection point
  393. //
  394. // Arguments: [fCancel] -- If TRUE, iisadmin is going down, so cancel
  395. // notifications and poll for it to come back up.
  396. //
  397. // History: 2-20-96 KyleP Created
  398. // 2-13-97 dlee Updated for metabase
  399. //
  400. //----------------------------------------------------------------------------
  401. SCODE CVRootNotify::CallBack( BOOL fCancel )
  402. {
  403. if ( fCancel )
  404. {
  405. ciDebugOut(( DEB_WARN,
  406. "Scheduling worker for '%ws' shutdown...\n",
  407. GetVRootService( _type ) ));
  408. _notifyMgr.CancelIISVRootNotify( _type );
  409. // note: we may be deleted by now, don't access private data
  410. }
  411. else
  412. {
  413. ciDebugOut(( DEB_WARN,
  414. "Scheduling worker thread for VRoot registry change...\n" ));
  415. CWorkManager & workMan = _cat.GetWorkMan();
  416. XInterface<CIISVRootAsyncNotify> xNotify(
  417. new CIISVRootAsyncNotify( _cat, workMan ) );
  418. workMan.AddToWorkList( xNotify.GetPointer() );
  419. xNotify->AddToWorkQueue();
  420. }
  421. return S_OK;
  422. } //CallBack
  423. //+---------------------------------------------------------------------------
  424. //
  425. // Member: CRegistryScopesNotify::DoIt, public
  426. //
  427. // Synopsis: Callback from APC
  428. //
  429. // History: 10-16-96 dlee Created
  430. //
  431. //----------------------------------------------------------------------------
  432. void CRegistryScopesNotify::DoIt()
  433. {
  434. ciDebugOut(( DEB_WARN,
  435. "Scheduling worker thread for RegistryScopes registry change...\n" ));
  436. CWorkManager & workMan = _cat.GetWorkMan();
  437. CRegistryScopesAsyncNotify * pNotify = new CRegistryScopesAsyncNotify(_cat, workMan);
  438. workMan.AddToWorkList( pNotify );
  439. pNotify->AddToWorkQueue();
  440. pNotify->Release();
  441. }
  442. //+---------------------------------------------------------------------------
  443. //
  444. // Member: CCiRegistryNotify::DoIt
  445. //
  446. // Synopsis: Refreshes the registry parameters
  447. //
  448. // History: 12-12-96 srikants Created
  449. //
  450. //----------------------------------------------------------------------------
  451. void CCiRegistryNotify::DoIt()
  452. {
  453. //
  454. // We don't need a worker thread to do this because it is very
  455. // quick and simple.
  456. //
  457. _cat.RefreshRegistryParams();
  458. }
  459. //+---------------------------------------------------------------------------
  460. //
  461. // Member: CCiNotifyMgr::CCiNotifyMgr
  462. //
  463. // Synopsis: ctor of the CI notification manager.
  464. //
  465. // Arguments: [cicat] - Catalog
  466. // [scanMgr] - Scan thread manager
  467. //
  468. // History: 1-18-96 srikants Created
  469. //
  470. //----------------------------------------------------------------------------
  471. CCiNotifyMgr::CCiNotifyMgr( CiCat & cicat, CCiScanMgr & scanMgr )
  472. : _cicat(cicat),
  473. _scanMgr(scanMgr),
  474. _nUpdates(0),
  475. _fAbort(FALSE),
  476. _evtType(eNone),
  477. _pRegistryScopesNotify(0),
  478. _fIISAdminAlive( TRUE ),
  479. _fTrackW3Svc( FALSE ),
  480. _fTrackNNTPSvc( FALSE ),
  481. _fTrackIMAPSvc( FALSE ),
  482. _W3SvcInstance( 1 ),
  483. _NNTPSvcInstance( 1 ),
  484. _IMAPSvcInstance( 1 ),
  485. _pCiRegistryNotify(0),
  486. #pragma warning( disable : 4355 ) // this used in base initialization
  487. _thrNotify( NotifyThread, this, TRUE ) // create suspended
  488. #pragma warning( default : 4355 )
  489. {
  490. _evt.Reset();
  491. RtlZeroMemory( &_ftLastNetPathScan, sizeof(_ftLastNetPathScan) );
  492. _thrNotify.SetPriority( THREAD_PRIORITY_ABOVE_NORMAL );
  493. }
  494. //+---------------------------------------------------------------------------
  495. //
  496. // Member: CCiNotifyMgr::~CCiNotifyMgr
  497. //
  498. // Synopsis: dtor of the CI notification manager.
  499. //
  500. // History: 17 Dec 1997 AlanW Created
  501. //
  502. //----------------------------------------------------------------------------
  503. CCiNotifyMgr::~CCiNotifyMgr( )
  504. {
  505. // Be sure the thread will die...
  506. if (_thrNotify.IsRunning())
  507. _KillThread();
  508. }
  509. //+---------------------------------------------------------------------------
  510. //
  511. // Member: CCiNotifyMgr::TrackIISVRoots
  512. //
  513. // Synopsis: Registers for notification of VRoot registry changes
  514. //
  515. // Arguments: [fTrackW3Svc] -- TRUE if W3 should be tracked
  516. // [W3SvcInstance] -- W3 instance # to be tracked.
  517. // [fTrackNNTPSvc] -- TRUE if NNTP should be tracked
  518. // [NNTPSvcInstance] -- NNTP instance # to be tracked.
  519. // [fTrackIMAPSvc] -- TRUE if IMAP should be tracked
  520. // [IMAPSvcInstance] -- IMAP instance # to be tracked.
  521. //
  522. // History: 2-21-96 KyleP Created
  523. // 2-13-97 dlee converted to metabase
  524. //
  525. //----------------------------------------------------------------------------
  526. void CCiNotifyMgr::TrackIISVRoots(
  527. BOOL fTrackW3Svc,
  528. ULONG W3SvcInstance,
  529. BOOL fTrackNNTPSvc,
  530. ULONG NNTPSvcInstance,
  531. BOOL fTrackIMAPSvc,
  532. ULONG IMAPSvcInstance )
  533. {
  534. CLock lock(_mutex);
  535. Win4Assert( _xW3SvcVRootNotify.IsNull() );
  536. Win4Assert( _xNNTPSvcVRootNotify.IsNull() );
  537. Win4Assert( _xIMAPSvcVRootNotify.IsNull() );
  538. _fTrackW3Svc = fTrackW3Svc;
  539. _W3SvcInstance = W3SvcInstance;
  540. _fTrackNNTPSvc = fTrackNNTPSvc;
  541. _NNTPSvcInstance = NNTPSvcInstance;
  542. _fTrackIMAPSvc = fTrackIMAPSvc;
  543. _IMAPSvcInstance = IMAPSvcInstance;
  544. _evtType |= eWatchIISVRoots;
  545. _evt.Set();
  546. } //TrackIISVRoots
  547. //+---------------------------------------------------------------------------
  548. //
  549. // Member: CCiNotifyMgr::TrackScopesInRegistry
  550. //
  551. // Synopsis: Registers for notification of scope registry changes
  552. //
  553. // History: 10/17/96 dlee Created
  554. //
  555. //----------------------------------------------------------------------------
  556. void CCiNotifyMgr::TrackScopesInRegistry()
  557. {
  558. CLock lock(_mutex);
  559. Win4Assert( 0 == _pRegistryScopesNotify );
  560. _evtType |= eWatchRegistryScopes;
  561. _evt.Set();
  562. }
  563. //+---------------------------------------------------------------------------
  564. //
  565. // Member: CCiNotifyMgr::TrackCiRegistry
  566. //
  567. // Synopsis: Registers for notifications of CI registry changes.
  568. //
  569. // History: 12-12-96 srikants Created
  570. //
  571. //----------------------------------------------------------------------------
  572. void CCiNotifyMgr::TrackCiRegistry()
  573. {
  574. CLock lock(_mutex);
  575. Win4Assert( 0 == _pCiRegistryNotify );
  576. _evtType |= eWatchCiRegistry;
  577. _evt.Set();
  578. }
  579. //+---------------------------------------------------------------------------
  580. //
  581. // Member: CCiNotifyMgr::CancelIISVRootNotify
  582. //
  583. // Synopsis: Cancels notifications on iisadmin since it's going down
  584. //
  585. // History: 2-13-97 dlee Created
  586. //
  587. //----------------------------------------------------------------------------
  588. void CCiNotifyMgr::CancelIISVRootNotify( CiVRootTypeEnum eType )
  589. {
  590. // after this, we'll poll for the iisadmin svc to start again
  591. CLock lock( _mutex );
  592. if ( W3VRoot == eType )
  593. _evtType |= eUnWatchW3VRoots;
  594. else if ( NNTPVRoot == eType )
  595. _evtType |= eUnWatchNNTPVRoots;
  596. else if ( IMAPVRoot == eType )
  597. _evtType |= eUnWatchIMAPVRoots;
  598. else
  599. {
  600. Win4Assert( !"invalid IIS vroot notify type!" );
  601. }
  602. _evt.Set();
  603. } //CancelIISVRootNotify
  604. //+---------------------------------------------------------------------------
  605. //
  606. // Member: CCiNotifyMgr::LokUnWatchIISVServerNoThrow
  607. //
  608. // Synopsis: Turns off notifications on W3, NNTP, or IMAP
  609. //
  610. // History: 2-Sep-97 dlee created
  611. //
  612. //----------------------------------------------------------------------------
  613. void CCiNotifyMgr::LokUnWatchIISVServerNoThrow(
  614. CVRootNotify * pNotify )
  615. {
  616. ciDebugOut(( DEB_WARN, "LokUnWatchIISVServer\n" ));
  617. TRY
  618. {
  619. delete pNotify;
  620. }
  621. CATCH(CException, e)
  622. {
  623. _fIISAdminAlive = FALSE;
  624. ciDebugOut(( DEB_WARN,
  625. "caught exception while tearing down IIS tracking\n" ));
  626. }
  627. END_CATCH;
  628. } //LokUnWatchIISVServerNoThrow
  629. //+---------------------------------------------------------------------------
  630. //
  631. // Member: CCiNotifyMgr::LokWatchIISVServerNoThrow
  632. //
  633. // Synopsis: Registers for notification of IIS VRoot changes
  634. //
  635. // History: 2-21-96 KyleP Created
  636. // 2-13-97 dlee converted to metabase
  637. //
  638. //----------------------------------------------------------------------------
  639. void CCiNotifyMgr::LokWatchIISVServerNoThrow()
  640. {
  641. ciDebugOut(( DEB_WARN,
  642. "LokWatchIISVServer w3 %d:%d, nntp %d:%d, imap %d:%d\n",
  643. _fTrackW3Svc,
  644. _W3SvcInstance,
  645. _fTrackNNTPSvc,
  646. _NNTPSvcInstance,
  647. _fTrackIMAPSvc,
  648. _IMAPSvcInstance ));
  649. Win4Assert( _fTrackW3Svc || _fTrackNNTPSvc || _fTrackIMAPSvc );
  650. BOOL fWasAlive = _fIISAdminAlive;
  651. // Assume iisadmin is alive and we can get notifications
  652. _fIISAdminAlive = TRUE;
  653. TRY
  654. {
  655. if ( _fTrackW3Svc && _xW3SvcVRootNotify.IsNull() )
  656. _xW3SvcVRootNotify.Set( new CVRootNotify( _cicat,
  657. W3VRoot,
  658. _W3SvcInstance,
  659. *this ) );
  660. if ( _fTrackNNTPSvc && _xNNTPSvcVRootNotify.IsNull() )
  661. _xNNTPSvcVRootNotify.Set( new CVRootNotify( _cicat,
  662. NNTPVRoot,
  663. _NNTPSvcInstance,
  664. *this ) );
  665. if ( _fTrackIMAPSvc && _xIMAPSvcVRootNotify.IsNull() )
  666. _xIMAPSvcVRootNotify.Set( new CVRootNotify( _cicat,
  667. IMAPVRoot,
  668. _IMAPSvcInstance,
  669. *this ) );
  670. }
  671. CATCH(CException, e)
  672. {
  673. _fIISAdminAlive = FALSE;
  674. ciDebugOut(( DEB_WARN,
  675. "caught exception while setting up iis tracking\n" ));
  676. }
  677. END_CATCH;
  678. // did we miss notifications but can catch up now?
  679. if ( !fWasAlive && _fIISAdminAlive )
  680. {
  681. TRY
  682. {
  683. ciDebugOut(( DEB_WARN, "Polling IIS: iisadmin woke up\n" ));
  684. CWorkManager & workMan = _cicat.GetWorkMan();
  685. XInterface<CIISVRootAsyncNotify> xNotify(
  686. new CIISVRootAsyncNotify( _cicat, workMan ) );
  687. workMan.AddToWorkList( xNotify.GetPointer() );
  688. xNotify->AddToWorkQueue();
  689. }
  690. CATCH(CException, e)
  691. {
  692. ciDebugOut(( DEB_WARN,
  693. "caught exception while setting up iis enumeration\n" ));
  694. // try again after the timeout
  695. _fIISAdminAlive = FALSE;
  696. }
  697. END_CATCH;
  698. }
  699. } //LokWatchIISVServerNoThrow
  700. //+---------------------------------------------------------------------------
  701. //
  702. // Member: CCiNotifyMgr::LokWatchRegistryScopesNoThrow
  703. //
  704. // Synopsis: Registers for notification of RegistryScopes registry changes
  705. //
  706. // History: 2-21-96 KyleP Created
  707. //
  708. // Notes: This must be done from thread waiting in alertable mode
  709. //
  710. //----------------------------------------------------------------------------
  711. void CCiNotifyMgr::LokWatchRegistryScopesNoThrow()
  712. {
  713. TRY
  714. {
  715. Win4Assert( 0 == _pRegistryScopesNotify );
  716. _pRegistryScopesNotify = new CRegistryScopesNotify( _cicat, *this );
  717. }
  718. CATCH( CException, e )
  719. {
  720. ciDebugOut(( DEB_WARN, "_LokWatchRegistryScopesNoThrow caught 0x%x\n",
  721. e.GetErrorCode() ));
  722. }
  723. END_CATCH
  724. } //LokWatchRegistryScopesNoThrow
  725. //+---------------------------------------------------------------------------
  726. //
  727. // Member: CCiNotifyMgr::LokWatchCiRegistryNoThrow
  728. //
  729. // Synopsis: Watches for changes in CI registry.
  730. //
  731. // History: 12-12-96 srikants Created
  732. //
  733. //----------------------------------------------------------------------------
  734. void CCiNotifyMgr::LokWatchCiRegistryNoThrow()
  735. {
  736. TRY
  737. {
  738. Win4Assert( 0 == _pCiRegistryNotify );
  739. _pCiRegistryNotify = new CCiRegistryNotify( _cicat, *this );
  740. }
  741. CATCH( CException, e )
  742. {
  743. ciDebugOut(( DEB_WARN, "_LokWatchCiRegistryNoThrow caught 0x%x\n",
  744. e.GetErrorCode() ));
  745. }
  746. END_CATCH
  747. } //LokWatchCiRegistryNoThrow
  748. //+---------------------------------------------------------------------------
  749. //
  750. // Member: CCiNotifyMgr::_KillThread
  751. //
  752. // Synopsis: Asks the notification thread to die and waits for its death.
  753. //
  754. // History: 1-18-96 srikants Created
  755. //
  756. //----------------------------------------------------------------------------
  757. void CCiNotifyMgr::_KillThread()
  758. {
  759. {
  760. CLock lock(_mutex);
  761. _evtType |= eKillThread;
  762. _evt.Set();
  763. }
  764. ciDebugOut(( DEB_ITRACE, "Waiting for death of notify thread\n" ));
  765. _thrNotify.WaitForDeath();
  766. }
  767. //+---------------------------------------------------------------------------
  768. //
  769. // Member: CCiNotifyMgr::Shutdown
  770. //
  771. // Synopsis: Shut down notification thread.
  772. //
  773. // History: 1-30-96 srikants Created
  774. //
  775. //----------------------------------------------------------------------------
  776. void CCiNotifyMgr::WaitForShutdown()
  777. {
  778. //
  779. // If we never started running, then just bail out.
  780. //
  781. if ( _thrNotify.IsRunning() )
  782. {
  783. //
  784. // must wait until all the APCs are aborted.
  785. //
  786. _refCount.Wait();
  787. //
  788. // Kill the notification thread.
  789. //
  790. _KillThread();
  791. }
  792. }
  793. //+---------------------------------------------------------------------------
  794. //
  795. // Member: CCiNotifyMgr::InitiateShutdown
  796. //
  797. // Synopsis: Turns off notifications
  798. //
  799. // History: 1-18-96 srikants Created
  800. //
  801. //----------------------------------------------------------------------------
  802. void CCiNotifyMgr::InitiateShutdown()
  803. {
  804. {
  805. CLock lock(_mutex);
  806. _fAbort = TRUE;
  807. }
  808. //
  809. // Abort registry notification (if any)
  810. //
  811. if ( !_xW3SvcVRootNotify.IsNull() )
  812. {
  813. _xW3SvcVRootNotify->DisableNotification();
  814. _xW3SvcVRootNotify.Free();
  815. }
  816. if ( !_xNNTPSvcVRootNotify.IsNull() )
  817. {
  818. _xNNTPSvcVRootNotify->DisableNotification();
  819. _xNNTPSvcVRootNotify.Free();
  820. }
  821. if ( !_xIMAPSvcVRootNotify.IsNull() )
  822. {
  823. _xIMAPSvcVRootNotify->DisableNotification();
  824. _xIMAPSvcVRootNotify.Free();
  825. }
  826. // these are refcounted and needn't be freed
  827. if ( 0 != _pRegistryScopesNotify )
  828. _pRegistryScopesNotify->DisableNotification();
  829. if ( 0 != _pCiRegistryNotify )
  830. _pCiRegistryNotify->DisableNotification();
  831. //
  832. // Abort all the notifications and the APCs queued for that.
  833. //
  834. {
  835. CLock lock(_mutex);
  836. for ( CCiNotify * pNotify = _list.Pop();
  837. 0 != pNotify;
  838. pNotify = _list.Pop() )
  839. {
  840. pNotify->Close();
  841. pNotify->Abort();
  842. }
  843. }
  844. }
  845. //+---------------------------------------------------------------------------
  846. //
  847. // Member: CCiNotifyMgr::_LokTellThreadToAddScope
  848. //
  849. // Synopsis: Sets the event type to add a scope for notifications and
  850. // wakes up the notification thread.
  851. //
  852. // History: 1-18-96 srikants Created
  853. //
  854. //----------------------------------------------------------------------------
  855. void CCiNotifyMgr::_LokTellThreadToAddScope()
  856. {
  857. if ( 0 == (eKillThread & _evtType) )
  858. {
  859. _evtType |= eAddScopes;
  860. _evt.Set();
  861. }
  862. }
  863. //+---------------------------------------------------------------------------
  864. //
  865. // Member: CCiNotifyMgr::AddPath
  866. //
  867. // Synopsis: Adds a scope for ci notifications. If the given scope (wcsScope)
  868. // is a superset of any existing scopes, they are removed from
  869. // the notification list.
  870. //
  871. // Arguments: [wcsScope] - Scope to be added.
  872. // [fSubscopesRemoved] - Set to TRUE if sub-scopes of wcsScope
  873. // were removed as a result of adding wcsScope.
  874. // [volumeId] - Volume id
  875. // [ftLastScan] - Last scan time
  876. // [usn] - Usn
  877. //
  878. // History: 1-17-96 srikants Created
  879. //
  880. //----------------------------------------------------------------------------
  881. void CCiNotifyMgr::AddPath( CScopeInfo const & scopeInfo, BOOL & fSubscopesRemoved )
  882. {
  883. fSubscopesRemoved = FALSE;
  884. //
  885. // Allocate storage for the string and terminate it with the
  886. // backslash character.
  887. //
  888. ULONG len = wcslen( scopeInfo.GetPath() );
  889. if ( L'\\' != scopeInfo.GetPath()[len-1] )
  890. len++;
  891. Win4Assert( len < MAX_PATH );
  892. XArray<WCHAR> xPath(len+1);
  893. WCHAR * pwcsPath = xPath.Get();
  894. wcscpy( pwcsPath, scopeInfo.GetPath() );
  895. pwcsPath[len-1] = L'\\';
  896. pwcsPath[len] = 0;
  897. CLock lock(_mutex);
  898. //
  899. // First see if notifications are already enabled on this path
  900. // in some other scope.
  901. //
  902. for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
  903. {
  904. if (iter1->IsMatch( pwcsPath, len ) )
  905. {
  906. Win4Assert( iter1->VolumeId() == scopeInfo.VolumeId() );
  907. //
  908. // there is an entry for this scope already. Just enable/start
  909. // the notification if not already done so.
  910. //
  911. if ( iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
  912. iter1->LokEnableIf();
  913. return;
  914. }
  915. }
  916. //
  917. // We have to create a new notification object for this scope.
  918. //
  919. XPtr<CScopeInfo> xScopeInfo;
  920. if ( CI_VOLID_USN_NOT_ENABLED == scopeInfo.VolumeId() )
  921. xScopeInfo.Set( new CScopeInfo( xPath,
  922. scopeInfo.VolumeCreationTime(),
  923. scopeInfo.VolumeSerialNumber(),
  924. scopeInfo.GetLastScanTime() ) );
  925. else
  926. xScopeInfo.Set( new CScopeInfo( xPath,
  927. scopeInfo.VolumeCreationTime(),
  928. scopeInfo.VolumeSerialNumber(),
  929. scopeInfo.VolumeId(),
  930. scopeInfo.Usn(),
  931. scopeInfo.JournalId(),
  932. scopeInfo.FUsnTreeScan() ) );
  933. _stkScopes.Push( xScopeInfo.GetPointer() );
  934. xScopeInfo.Acquire();
  935. //
  936. // If the new path is going to be a superset of the existing paths,
  937. // they must be removed.
  938. //
  939. CScopeMatch superScope( pwcsPath, len );
  940. for ( CFwdCiNotifyIter iter2(_list); !_list.AtEnd(iter2); )
  941. {
  942. CCiNotify * pNotify = iter2.GetEntry();
  943. _list.Advance(iter2);
  944. //
  945. // See if the current node is a subset of the new path.
  946. // If so, remove the current node from the list.
  947. //
  948. if ( superScope.IsInScope( pNotify->GetScope(), pNotify->ScopeLength()) )
  949. {
  950. fSubscopesRemoved = TRUE;
  951. pNotify->LokRemove();
  952. }
  953. }
  954. //
  955. // Wake up the notification thread to add this scope.
  956. //
  957. _LokTellThreadToAddScope();
  958. } //AddPath
  959. //+---------------------------------------------------------------------------
  960. //
  961. // Member: CCiNotifyMgr::GetLastScanTime
  962. //
  963. // Synopsis: Gets the time of the last successful scan for the given scope.
  964. //
  965. // Arguments: [wcsScope] - Scope to check. If there is no entry for the
  966. // given scope, the time of the last successful scan of the
  967. // super scope of wcsScope will be returned.
  968. // [ft] - The filetime of the last successful scan
  969. // encompassing the given scope.
  970. //
  971. // Returns: TRUE if found; FALSE o/w. In case FALSE is returned, ft will
  972. // be zero filled.
  973. //
  974. // History: 4-19-96 srikants Created
  975. //
  976. //----------------------------------------------------------------------------
  977. BOOL CCiNotifyMgr::GetLastScanTime( WCHAR const * wcsScope, FILETIME & ft )
  978. {
  979. RtlZeroMemory( &ft, sizeof(FILETIME) );
  980. Win4Assert( 0 != wcsScope );
  981. ULONG len = wcslen( wcsScope );
  982. Win4Assert( L'\\' == wcsScope[len-1] );
  983. CLock lock(_mutex);
  984. //
  985. // Look for a scope which encompasses the given scope.
  986. //
  987. for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
  988. {
  989. if (iter1->IsMatch( wcsScope, len ) )
  990. {
  991. ft = iter1->GetLastScanTime();
  992. return TRUE;
  993. }
  994. }
  995. return FALSE;
  996. }
  997. //+---------------------------------------------------------------------------
  998. //
  999. // Member: CCiNotifyMgr::UpdateLastScanTimes
  1000. //
  1001. // Synopsis: Updates the last scan time of all the paths that have
  1002. // notifications enabled to the time given.
  1003. //
  1004. // Arguments: [ft] - Last successful scan time (all updates until this time
  1005. // are known for all the scopes with notifications enabled).
  1006. // [usnFlushInfoList] - Usn info list
  1007. //
  1008. // History: 4-21-96 srikants Created
  1009. // 05-07-97 SitaramR Usns
  1010. //
  1011. //----------------------------------------------------------------------------
  1012. void CCiNotifyMgr::UpdateLastScanTimes( FILETIME const & ft,
  1013. CUsnFlushInfoList & usnFlushInfoList )
  1014. {
  1015. CLock lock(_mutex);
  1016. for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
  1017. {
  1018. if ( iter1->LokIsNotifyEnabled() && iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
  1019. {
  1020. if ( ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0 )
  1021. iter1->SetLastScanTime( ft );
  1022. }
  1023. else if ( iter1->VolumeId() != CI_VOLID_USN_NOT_ENABLED
  1024. && !iter1->FUsnTreeScan() )
  1025. {
  1026. //
  1027. // If an usn tree traversal is going on, then we shouldn't move the usn
  1028. // watermark because if there is a crash now, then we should
  1029. // restart the usn tree traversal from usn 0.
  1030. //
  1031. USN usnCurrent = usnFlushInfoList.GetUsn( iter1->VolumeId() );
  1032. ciDebugOut(( DEB_ITRACE,
  1033. "CCiNotifyMgr::UpdateLastScanTimes drive %wc, old %#I64x, current %#I64x\n",
  1034. (WCHAR) iter1->VolumeId(),
  1035. iter1->Usn(),
  1036. usnCurrent ));
  1037. if ( usnCurrent != 0 && usnCurrent > iter1->Usn() )
  1038. {
  1039. //
  1040. // Win4Assert( usnCurrent >= iter1->Usn() );
  1041. //
  1042. // We cannot assert the above because after the initial usn tree
  1043. // scan is done, the maxUsn is written to iter1 (CiCat::SetUsnTreeComplete),
  1044. // and there can be usn notifications prior to usn tree scan, i.e. there can
  1045. // be usn's less than maxUsn.
  1046. //
  1047. iter1->SetUsn( usnCurrent );
  1048. }
  1049. }
  1050. }
  1051. } //UpdateLastScanTimes
  1052. //+---------------------------------------------------------------------------
  1053. //
  1054. // Member: CCiNotifyMgr::ForceNetPathScansIf
  1055. //
  1056. // Synopsis: Forces the scan of network paths with no notifications if
  1057. // the interval for such scans has expired.
  1058. //
  1059. // History: 4-21-96 srikants Created
  1060. //
  1061. // Notes: If the remote machine is running networking software without
  1062. // notifications, we have to periodically scan for changes. This
  1063. // method identifies such paths and schedules scans for them if
  1064. // the minimum interval has expired since the last such scan.
  1065. //
  1066. // THIS METHOD MUST BE CALLED ONLY FROM THE SCAN THREAD. IT IS
  1067. // CALLED WHEN THE SCAN THREAD HAS DETECTED THAT THERE ARE NO
  1068. // OUTSTANDING SCANS AND SO IS A GOOD TIME TO SCAN NET PATHS.
  1069. //
  1070. //----------------------------------------------------------------------------
  1071. void CCiNotifyMgr::ForceNetPathScansIf()
  1072. {
  1073. CLock lock(_mutex);
  1074. Win4Assert( sizeof(FILETIME) == sizeof(LONGLONG) );
  1075. LONGLONG ftZero;
  1076. RtlZeroMemory( &ftZero, sizeof(ftZero) );
  1077. LONGLONG ftNow;
  1078. GetSystemTimeAsFileTime( (FILETIME *) &ftNow );
  1079. if ( 0 == CompareFileTime( (FILETIME *) &_ftLastNetPathScan,
  1080. (FILETIME *) &ftZero ) )
  1081. {
  1082. //
  1083. // We havent't yet started tracking the interval. Just initialize
  1084. // the _ftLastNetPathScan to the current time.
  1085. //
  1086. _ftLastNetPathScan = ftNow;
  1087. return;
  1088. }
  1089. if ( ftNow < _ftLastNetPathScan )
  1090. {
  1091. ciDebugOut(( DEB_WARN, "Time has been set back\n" ));
  1092. _ftLastNetPathScan = ftNow;
  1093. return;
  1094. }
  1095. //
  1096. // See if the interval for force scans has exceeded.
  1097. //
  1098. //
  1099. // Compute the interval in 100 nanosecond interval
  1100. //
  1101. const LONGLONG llInterval =
  1102. _cicat.GetRegParams()->GetForcedNetPathScanInterval() * 60 * 1000 * 10000;
  1103. if ( ftNow - _ftLastNetPathScan >= llInterval )
  1104. {
  1105. ciDebugOut(( DEB_ITRACE, "Forcing scan of net paths with no notifcations\n" ));
  1106. _LokForceScanNetPaths();
  1107. //
  1108. // Reset the last scan time for network paths.
  1109. //
  1110. RtlZeroMemory( &_ftLastNetPathScan, sizeof(_ftLastNetPathScan) );
  1111. }
  1112. }
  1113. //+---------------------------------------------------------------------------
  1114. //
  1115. // Member: CCiNotifyMgr::_LokForceScanNetPaths
  1116. //
  1117. // Synopsis: Forces incremental scans of net paths with no notifications.
  1118. //
  1119. // History: 4-21-96 srikants Created
  1120. //
  1121. // Notes: This method must be called only in the context of the scan
  1122. // thread.
  1123. //
  1124. //----------------------------------------------------------------------------
  1125. void CCiNotifyMgr::_LokForceScanNetPaths()
  1126. {
  1127. for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
  1128. {
  1129. if ( !iter1->LokIsNotifyEnabled() && iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
  1130. {
  1131. //
  1132. // Usn paths have their notifications disabled, but they should not be scanned
  1133. //
  1134. ciDebugOut(( DEB_WARN,
  1135. "Forcing an incremental scan of path (%ws)\n",
  1136. iter1->GetScope() ));
  1137. _cicat.ReScanPath( iter1->GetScope(), FALSE );
  1138. }
  1139. }
  1140. } //_LokForceScanNetPaths
  1141. //+---------------------------------------------------------------------------
  1142. //
  1143. // Member: CCiNotifyMgr::_LokAddScopesNoThrow
  1144. //
  1145. // Synopsis: Takes scopes from the stack and enables notifications for
  1146. // those scopes.
  1147. //
  1148. // History: 1-18-96 srikants Created
  1149. //
  1150. //----------------------------------------------------------------------------
  1151. void CCiNotifyMgr::_LokAddScopesNoThrow()
  1152. {
  1153. TRY
  1154. {
  1155. for ( unsigned i = 0; i < _stkScopes.Count(); i++ )
  1156. {
  1157. CScopeInfo & scopeInfo = *_stkScopes.Get(i);
  1158. if ( !scopeInfo.IsValid() )
  1159. continue;
  1160. WCHAR const * pwcsPath = scopeInfo.GetPath();
  1161. CCiNotify * pNotify = new CCiNotify( *this,
  1162. pwcsPath,
  1163. wcslen(pwcsPath),
  1164. scopeInfo.VolumeId(),
  1165. scopeInfo.VolumeCreationTime(),
  1166. scopeInfo.VolumeSerialNumber(),
  1167. scopeInfo.GetLastScanTime(),
  1168. scopeInfo.Usn(),
  1169. scopeInfo.JournalId(),
  1170. scopeInfo.FUsnTreeScan() );
  1171. //
  1172. // Acquire the path as a sign that we shouldn't try to use it
  1173. // again to add another notification object.
  1174. //
  1175. delete [] scopeInfo.AcquirePath();
  1176. _list.Push( pNotify );
  1177. }
  1178. // empty the stack now
  1179. while ( _stkScopes.Count() > 0 )
  1180. {
  1181. _stkScopes.DeleteTop();
  1182. }
  1183. }
  1184. CATCH( CException, e )
  1185. {
  1186. ciDebugOut(( DEB_WARN, "_LokAddScopesNoThrow caught 0x%x\n",
  1187. e.GetErrorCode() ));
  1188. }
  1189. END_CATCH
  1190. } //_LokAddScopesNoThrow
  1191. //+---------------------------------------------------------------------------
  1192. //
  1193. // Member: CCiNotifyMgr::_DoNotifications
  1194. //
  1195. // Synopsis: The thread which is responsible for adding notification scopes
  1196. // and processing the notifications. The notification APC will
  1197. // execute in this thread's context.
  1198. //
  1199. // History: 1-18-96 srikants Created
  1200. //
  1201. //----------------------------------------------------------------------------
  1202. void CCiNotifyMgr::_DoNotifications()
  1203. {
  1204. while ( TRUE )
  1205. {
  1206. //
  1207. // Don't do any work until the system has booted
  1208. //
  1209. while ( GetTickCount() < _cicat.GetRegParams()->GetStartupDelay() )
  1210. {
  1211. Sleep( 200 );
  1212. if ( _fAbort )
  1213. break;
  1214. }
  1215. BOOL fWait = FALSE;
  1216. CVRootNotify * pW3Notify = 0;
  1217. CVRootNotify * pNNTPNotify = 0;
  1218. CVRootNotify * pIMAPNotify = 0;
  1219. // ++++++++++++++++ lock obtained +++++++++++++++++++
  1220. {
  1221. CLock lock(_mutex);
  1222. _evt.Reset();
  1223. Win4Assert( 0 == ( _evtType &
  1224. ~(eKillThread|eAddScopes|eWatchIISVRoots|
  1225. eWatchRegistryScopes|eWatchCiRegistry|eUnWatchW3VRoots|
  1226. eUnWatchNNTPVRoots|eUnWatchIMAPVRoots)) );
  1227. if ( eKillThread & _evtType )
  1228. return;
  1229. if ( _fAbort )
  1230. {
  1231. _evtType = eNone;
  1232. }
  1233. else
  1234. {
  1235. if ( eAddScopes & _evtType )
  1236. {
  1237. _LokAddScopesNoThrow();
  1238. _evtType &= ~eAddScopes;
  1239. }
  1240. if ( eWatchIISVRoots & _evtType )
  1241. {
  1242. LokWatchIISVServerNoThrow();
  1243. _evtType &= ~eWatchIISVRoots;
  1244. }
  1245. if ( eUnWatchW3VRoots & _evtType )
  1246. {
  1247. pW3Notify = _xW3SvcVRootNotify.Acquire();
  1248. _evtType &= ~eUnWatchW3VRoots;
  1249. }
  1250. if ( eUnWatchNNTPVRoots & _evtType )
  1251. {
  1252. pNNTPNotify = _xNNTPSvcVRootNotify.Acquire();
  1253. _evtType &= ~eUnWatchNNTPVRoots;
  1254. }
  1255. if ( eUnWatchIMAPVRoots & _evtType )
  1256. {
  1257. pIMAPNotify = _xIMAPSvcVRootNotify.Acquire();
  1258. _evtType &= ~eUnWatchIMAPVRoots;
  1259. }
  1260. if ( eWatchRegistryScopes & _evtType )
  1261. {
  1262. LokWatchRegistryScopesNoThrow();
  1263. _evtType &= ~eWatchRegistryScopes;
  1264. }
  1265. if ( eWatchCiRegistry & _evtType )
  1266. {
  1267. LokWatchCiRegistryNoThrow();
  1268. _evtType &= ~eWatchCiRegistry;
  1269. }
  1270. }
  1271. fWait = ( eNone == _evtType );
  1272. }
  1273. // ---------------- lock released --------------------
  1274. //
  1275. // Free these without holding the lock to avoid a deadlock
  1276. // with iisadmin.
  1277. //
  1278. if ( 0 != pW3Notify )
  1279. LokUnWatchIISVServerNoThrow( pW3Notify );
  1280. if ( 0 != pNNTPNotify )
  1281. LokUnWatchIISVServerNoThrow( pNNTPNotify );
  1282. if ( 0 != pIMAPNotify )
  1283. LokUnWatchIISVServerNoThrow( pIMAPNotify );
  1284. //
  1285. // If we're not watching, turn the flag off
  1286. //
  1287. if ( _xW3SvcVRootNotify.IsNull() &&
  1288. _xNNTPSvcVRootNotify.IsNull() &&
  1289. _xIMAPSvcVRootNotify.IsNull() )
  1290. _fIISAdminAlive = FALSE;
  1291. if ( fWait )
  1292. {
  1293. const DWORD dwFiveMinutes = 1000 * 60 * 5;
  1294. DWORD dwWait = ( ( !_fIISAdminAlive ) &&
  1295. ( _fTrackW3Svc || _fTrackNNTPSvc || _fTrackIMAPSvc ) ) ?
  1296. dwFiveMinutes : INFINITE;
  1297. // TRUE: important to get APCs
  1298. ULONG res = _evt.Wait( dwWait, TRUE );
  1299. if ( WAIT_TIMEOUT == res )
  1300. {
  1301. // try again to talk to the iisadmin svc
  1302. CLock lock( _mutex );
  1303. _evtType |= eWatchIISVRoots;
  1304. }
  1305. }
  1306. }
  1307. }
  1308. //+---------------------------------------------------------------------------
  1309. //
  1310. // Member: CCiNotifyMgr::NotifyThread
  1311. //
  1312. // Arguments: [self] -
  1313. //
  1314. // History: 1-18-96 srikants Created
  1315. //
  1316. //----------------------------------------------------------------------------
  1317. DWORD CCiNotifyMgr::NotifyThread( void * self )
  1318. {
  1319. SCODE sc = CoInitializeEx( 0, COINIT_MULTITHREADED );
  1320. ((CCiNotifyMgr *) self)->_DoNotifications();
  1321. CoUninitialize();
  1322. ciDebugOut(( DEB_ITRACE, "Terminating notify thread\n" ));
  1323. //
  1324. // This is only necessary if thread is terminated from DLL_PROCESS_DETACH.
  1325. //
  1326. //TerminateThread( ((CCiNotifyMgr *) self)->_thrNotify.GetHandle(), 0 );
  1327. return 0;
  1328. }
  1329. //+---------------------------------------------------------------------------
  1330. //
  1331. // Member: CCiNotifyMgr::ProcessChanges
  1332. //
  1333. // Synopsis: Processes the changes to files.
  1334. //
  1335. // Arguments: [changes] -
  1336. //
  1337. // History: 1-17-96 srikants Created
  1338. //
  1339. //----------------------------------------------------------------------------
  1340. void CCiNotifyMgr::ProcessChanges( XPtr<CCiAsyncProcessNotify> & xWorker )
  1341. {
  1342. CWorkManager & workMan = _cicat.GetWorkMan();
  1343. workMan.AddToWorkList( xWorker.GetPointer() );
  1344. CCiAsyncProcessNotify *pAsyncNotify = xWorker.Acquire();
  1345. #if 0
  1346. //
  1347. // NTRAID#DB-NTBUG9-83784-2000/07/31-dlee FAT notifications don't use APCs -- they are handled by the notification thread
  1348. // There is a problem with lockups in NT. Until we figure
  1349. // that out, don't use worker threads. Just process the notifications
  1350. // in-line in the notification thread.
  1351. //
  1352. pAsyncNotify->AddToWorkQueue();
  1353. #else
  1354. pAsyncNotify->DoIt( 0 );
  1355. #endif
  1356. pAsyncNotify->Release();
  1357. }
  1358. //+---------------------------------------------------------------------------
  1359. //
  1360. // Member: CCiNotifyMgr::ProcessChanges
  1361. //
  1362. // Synopsis:
  1363. //
  1364. // Arguments: [pbChanges] -
  1365. // [wcsScope] -
  1366. //
  1367. // Returns:
  1368. //
  1369. // Modifies:
  1370. //
  1371. // History: 3-07-96 srikants Created
  1372. //
  1373. //----------------------------------------------------------------------------
  1374. void CCiNotifyMgr::ProcessChanges( BYTE const * pbChanges,
  1375. WCHAR const * wcsScope )
  1376. {
  1377. CCiSyncProcessNotify notify(_cicat, _scanMgr, pbChanges, wcsScope, _fAbort );
  1378. notify.DoIt();
  1379. }
  1380. //+---------------------------------------------------------------------------
  1381. //
  1382. // Member: CCiNotifyMgr::SetupScan
  1383. //
  1384. // Synopsis: Schedules the given path for background scan in the scan
  1385. // thread.
  1386. //
  1387. // Arguments: [pwcsPath] - The path to be scanned.
  1388. //
  1389. // History: 1-19-96 srikants Created
  1390. //
  1391. // Notes: This method is invoked when the notification buffer overflowed
  1392. // and hence some updates are lost. A rescan is needed to figure
  1393. // out the changed documents.
  1394. //
  1395. //----------------------------------------------------------------------------
  1396. void CCiNotifyMgr::SetupScan( WCHAR const * pwcsPath )
  1397. {
  1398. _cicat.ReScanPath( pwcsPath, TRUE );
  1399. }
  1400. //+---------------------------------------------------------------------------
  1401. //
  1402. // Member: CCiNotifyMgr::IsInScope
  1403. //
  1404. // Synopsis: Tests if the given scope is already in the list of scopes
  1405. // being watched for notifications.
  1406. //
  1407. // Arguments: [pwcsPath] - Input path to check.
  1408. //
  1409. // Returns: TRUE if the path is already in a notification scope.
  1410. // FALSE o/w
  1411. //
  1412. // History: 1-21-96 srikants Created
  1413. //
  1414. //----------------------------------------------------------------------------
  1415. BOOL CCiNotifyMgr::IsInScope( WCHAR const * pwcsPath )
  1416. {
  1417. Win4Assert( 0 != pwcsPath );
  1418. ULONG len = wcslen( pwcsPath );
  1419. CLock lock(_mutex);
  1420. //
  1421. // First check if it is in the list of paths to be added.
  1422. //
  1423. for ( unsigned i = 0;
  1424. i < _stkScopes.Count();
  1425. i++ )
  1426. {
  1427. if ( !_stkScopes.Get(i)->IsValid() )
  1428. continue;
  1429. WCHAR const * pwcsTmp = _stkScopes.Get(i)->GetPath();
  1430. CScopeMatch match( pwcsTmp, wcslen( pwcsTmp ) );
  1431. if ( match.IsInScope( pwcsPath, len ) )
  1432. return TRUE;
  1433. }
  1434. // next check in the list of notifications
  1435. for ( CFwdCiNotifyIter iter(_list); !_list.AtEnd(iter); _list.Advance(iter) )
  1436. {
  1437. if ( iter->IsMatch( pwcsPath, len ) )
  1438. return TRUE;
  1439. }
  1440. return FALSE;
  1441. } //IsInScope
  1442. //+---------------------------------------------------------------------------
  1443. //
  1444. // Member: CCiNotifyMgr::RemoveScope
  1445. //
  1446. // Synopsis: If there is an exact match for the given scope, it will be
  1447. // removed from the notification list.
  1448. //
  1449. // Arguments: [pwcsPath] - The scope to be removed.
  1450. //
  1451. // Returns: TRUE if the scope was found.
  1452. // FALSE if it was not found.
  1453. //
  1454. // History: 1-25-96 srikants Created
  1455. //
  1456. //----------------------------------------------------------------------------
  1457. BOOL CCiNotifyMgr::RemoveScope( WCHAR const * pwcsPath )
  1458. {
  1459. Win4Assert( 0 != pwcsPath );
  1460. ULONG len = wcslen( pwcsPath );
  1461. CLock lock(_mutex);
  1462. BOOL fFound = FALSE;
  1463. //
  1464. // First see if there is a match in the list of paths still
  1465. // to be added.
  1466. //
  1467. for ( unsigned i = 0; i < _stkScopes.Count(); i++ )
  1468. {
  1469. CScopeInfo & scopeInfo = *_stkScopes.Get(i);
  1470. if ( !scopeInfo.IsValid() )
  1471. continue;
  1472. if ( AreIdenticalPaths( pwcsPath, scopeInfo.GetPath() ) )
  1473. {
  1474. scopeInfo.Invalidate();
  1475. fFound = TRUE;
  1476. }
  1477. }
  1478. //
  1479. // Next remove from the list of notifications.
  1480. //
  1481. for ( CFwdCiNotifyIter iter(_list); !_list.AtEnd(iter); )
  1482. {
  1483. CCiNotify * pNotify = iter.GetEntry();
  1484. _list.Advance(iter);
  1485. if ( AreIdenticalPaths(pwcsPath, pNotify->GetScope()) )
  1486. {
  1487. ciDebugOut(( DEB_ITRACE,
  1488. "Removing path (%ws) from notification list\n",
  1489. pNotify->GetScope() ));
  1490. pNotify->LokRemove();
  1491. return TRUE;
  1492. }
  1493. }
  1494. return FALSE;
  1495. }
  1496. //+---------------------------------------------------------------------------
  1497. //
  1498. // Member: CCiNotifyIter::SetTreeScanComplete, public
  1499. //
  1500. // Synopsis: Mark a scope as scanned. Used to update volume version info.
  1501. //
  1502. // History: 13-Apr-1998 KyleP Created
  1503. //
  1504. //----------------------------------------------------------------------------
  1505. void CCiNotifyIter::SetTreeScanComplete()
  1506. {
  1507. Win4Assert( !AtEnd() );
  1508. ULONGLONG const & VolumeCreationTime = _notifyMgr._cicat.GetVolumeCreationTime( Get() );
  1509. ULONG VolumeSerialNumber = _notifyMgr._cicat.GetVolumeSerialNumber( Get() );
  1510. if ( _iNotAdded < _stack.Count() )
  1511. _stack.Get(_iNotAdded)->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
  1512. else
  1513. _iter->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
  1514. }
  1515. //+---------------------------------------------------------------------------
  1516. //
  1517. // Member: CCiNotifyIter::SetUsnTreeScanComplete, public
  1518. //
  1519. // Synopsis: Same as SetTreeScanComplete, but also updates USN info.
  1520. //
  1521. // Arguments: [usnMax] -- New high-water mark.
  1522. //
  1523. // History: 13-Apr-1998 KyleP Created
  1524. //
  1525. //----------------------------------------------------------------------------
  1526. void CCiNotifyIter::SetUsnTreeScanComplete( USN usnMax )
  1527. {
  1528. Win4Assert( !AtEnd() );
  1529. ULONGLONG const & JournalId = _notifyMgr._cicat.GetJournalId( Get() );
  1530. ULONGLONG const & VolumeCreationTime = _notifyMgr._cicat.GetVolumeCreationTime( Get() );
  1531. ULONG VolumeSerialNumber = _notifyMgr._cicat.GetVolumeSerialNumber( Get() );
  1532. if ( _iNotAdded < _stack.Count() )
  1533. {
  1534. _stack.Get(_iNotAdded)->SetUsnTreeScanComplete( usnMax );
  1535. _stack.Get(_iNotAdded)->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
  1536. _stack.Get(_iNotAdded)->SetJournalId( JournalId );
  1537. }
  1538. else
  1539. {
  1540. _iter->SetUsnTreeScanComplete( usnMax );
  1541. _iter->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
  1542. _iter->SetJournalId( JournalId );
  1543. }
  1544. }