//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: notifmgr.hxx // // Contents: Classes to deal with registry and file system change notifications // // Classes: CCiNotify // CCiNotifyMgr // // History: 14-Jul-97 SitaramR Created from dlnotify.hxx // //---------------------------------------------------------------------------- #pragma once #include #include #include #include #include #include "scaninfo.hxx" #include "acinotfy.hxx" #include "usnlist.hxx" #include "usnmgr.hxx" class CiCat; class CCiNotifyMgr; class CClientDocStore; const LONGLONG sigCiNotify = 0x594649544F4E4943i64; // "CINOTIFY" //+--------------------------------------------------------------------------- // // Class: CCiNotify // // Purpose: A single scope to watch for notifications. // // History: 1-17-96 srikants Created // //---------------------------------------------------------------------------- class CCiNotify : public CGenericNotify { public: CCiNotify( CCiNotifyMgr & notifyMgr, WCHAR const * wcsScope, unsigned cwcScope, VOLUMEID volumeId, ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber, FILETIME const & ftLastScan, USN usn, ULONGLONG const & JournalId, BOOL fUsnTreeScan, BOOL fDeep = TRUE ); ~CCiNotify(); BOOL IsMatch( const WCHAR * wcsPath, ULONG len ) const; # ifdef CIEXTMODE void CiExtDump(void *ciExtSelf); # endif BOOL IsValidSig() { return sigCiNotify == _sigCiNotify; } CCiNotifyMgr & GetNotifyMgr() { return _notifyMgr; } void LokRemove() { Unlink(); Close(); Abort(); } void Abort(); virtual void DoIt(); virtual void ClearNotifyEnabled(); void SetLastScanTime( FILETIME const & ft ) { _ftLastScan = ft; } FILETIME const & GetLastScanTime() const { return _ftLastScan; } USN Usn() { return _usn; } void SetUsn( USN usn ) { _usn = usn; } ULONGLONG const & JournalId() const { return _JournalId; } void SetJournalId( ULONGLONG const & JournalId ) { _JournalId = JournalId; } VOLUMEID VolumeId() { return _volumeId; } ULONGLONG const & VolumeCreationTime() const { return _VolumeCreationTime; } ULONG VolumeSerialNumber() const { return _VolumeSerialNumber; } void SetVolumeInfo( ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber ) { _VolumeCreationTime = VolumeCreationTime; _VolumeSerialNumber = VolumeSerialNumber; } BOOL FUsnTreeScan() { return _fUsnTreeScan; } void InitUsnTreeScan() { _fUsnTreeScan = TRUE; _usn = 0; } void SetUsnTreeScanComplete( USN usnMax ) { // bogus assert: Win4Assert( _fUsnTreeScan ); _fUsnTreeScan = FALSE; _usn = usnMax; } private: const LONGLONG _sigCiNotify; // signature for debugging ULONGLONG _VolumeCreationTime; union { FILETIME _ftLastScan; // Time of the last successful scan struct { ULONGLONG _JournalId; // Usn Journal Id USN _usn; // Max usn persisted for this volumeId }; }; ULONG _VolumeSerialNumber; CCiNotifyMgr & _notifyMgr; // CI Notification manager VOLUMEID _volumeId; // Volume id BOOL _fUsnTreeScan; // True if a usn tree traversal is going // on this scope }; //+--------------------------------------------------------------------------- // // Class: CVRootNotify // // Purpose: Notification on IIS VRoot changes // // History: 1-20-96 KyleP Created // //---------------------------------------------------------------------------- class CVRootNotify : public CMetaDataVPathChangeCallBack { public: CVRootNotify( CiCat & cat, CiVRootTypeEnum eType, ULONG Instance, CCiNotifyMgr & notifyMgr ); ~CVRootNotify() { DisableNotification(); } SCODE CallBack( BOOL fCancel ); void DisableNotification(); private: CiVRootTypeEnum _type; CiCat & _cat; CCiNotifyMgr & _notifyMgr; CMetaDataMgr _mdMgr; }; //+--------------------------------------------------------------------------- // // Class: CRegistryScopesNotify // // Purpose: Notification on Scopes registry changes // // History: 10-16-96 dlee Created // //---------------------------------------------------------------------------- class CRegistryScopesNotify : public CRegNotify { public: CRegistryScopesNotify( CiCat & cat, CCiNotifyMgr & notifyMgr ); ~CRegistryScopesNotify(); void DoIt(); private: CiCat & _cat; CCiNotifyMgr & _notifyMgr; }; //+--------------------------------------------------------------------------- // // Class: CCiRegistryNotify // // Purpose: A notification class for tracking ContentIndex registry // changes. // // History: 12-12-96 srikants Created // //---------------------------------------------------------------------------- class CCiRegistryNotify : public CRegNotify { public: CCiRegistryNotify( CiCat & cat, CCiNotifyMgr & notifyMgr ); ~CCiRegistryNotify(); void DoIt(); private: CiCat & _cat; CCiNotifyMgr & _notifyMgr; }; typedef class TDoubleList CCiNotifyList; typedef class TFwdListIter CFwdCiNotifyIter; //+--------------------------------------------------------------------------- // // Class: CScopeInfo // // Purpose: Class that holds a scope and the last scan time. // // History: 4-19-96 srikants Created // //---------------------------------------------------------------------------- class CScopeInfo { public: CScopeInfo( XArray & xPath, ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber, FILETIME const & ftLastScan ) : _volumeId(CI_VOLID_USN_NOT_ENABLED), _VolumeCreationTime( VolumeCreationTime ), _VolumeSerialNumber( VolumeSerialNumber ), _ftLastScan( ftLastScan ), _fUsnTreeScan(FALSE) { _pwszScope = xPath.Acquire(); _scanType = eNoScan; } CScopeInfo( XArray & xPath, ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber, VOLUMEID volumeId, USN usn, ULONGLONG const & JournalId, BOOL fScan ) : _volumeId(volumeId), _VolumeCreationTime( VolumeCreationTime ), _VolumeSerialNumber( VolumeSerialNumber ), _fUsnTreeScan( fScan ), _JournalId( JournalId ), _usn( usn ) { _pwszScope = xPath.Acquire(); _scanType = eNoScan; } CScopeInfo( WCHAR const * pwszPath, ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber, FILETIME const & ftLastScan ) : _volumeId(CI_VOLID_USN_NOT_ENABLED), _VolumeCreationTime( VolumeCreationTime ), _VolumeSerialNumber( VolumeSerialNumber ), _ftLastScan( ftLastScan ), _fUsnTreeScan( FALSE ) { Win4Assert( 0 != pwszPath ); ULONG len = wcslen( pwszPath ); _pwszScope = new WCHAR [len+1]; RtlCopyMemory( _pwszScope, pwszPath, (len+1) * sizeof(WCHAR) ); _scanType = eNoScan; } CScopeInfo( WCHAR const * pwszPath, ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber, VOLUMEID volumeId, USN usn, ULONGLONG const & JournalId, BOOL fScan ) : _volumeId(volumeId), _VolumeCreationTime( VolumeCreationTime ), _VolumeSerialNumber( VolumeSerialNumber ), _fUsnTreeScan( fScan ), _JournalId( JournalId ), _usn( usn ) { Win4Assert( 0 != pwszPath ); ULONG len = wcslen( pwszPath ); _pwszScope = new WCHAR [len+1]; RtlCopyMemory( _pwszScope, pwszPath, (len+1) * sizeof(WCHAR) ); _scanType = eNoScan; } ~CScopeInfo() { delete [] _pwszScope; } WCHAR const * GetPath() const { return _pwszScope; } WCHAR * AcquirePath() { WCHAR * pwszTemp = _pwszScope; _pwszScope = 0; return pwszTemp; } void Invalidate() { delete [] _pwszScope; _pwszScope = 0; } BOOL IsValid() const { return 0 != _pwszScope; } FILETIME const & GetLastScanTime() const { return _ftLastScan; } void SetLastScanTime( FILETIME const & ft ) { _ftLastScan = ft; } VOLUMEID VolumeId() const { return _volumeId; } USN Usn() const { return _usn; } void SetUsn( USN usn ) { _usn = usn; } ULONGLONG const & JournalId() const { return _JournalId; } void SetJournalId( ULONGLONG const & JournalId ) { _JournalId = JournalId; } ULONGLONG const & VolumeCreationTime() const { return _VolumeCreationTime; } ULONG VolumeSerialNumber() const { return _VolumeSerialNumber; } void SetVolumeInfo( ULONGLONG const & VolumeCreationTime, ULONG VolumeSerialNumber ) { _VolumeCreationTime = VolumeCreationTime; _VolumeSerialNumber = VolumeSerialNumber; } BOOL IsScanNeeded() const { return eNoScan != _scanType; } BOOL IsFullScan() const { return eFullScan == _scanType; } BOOL IsIncrScan() const { return eIncrScan == _scanType; } void ClearScanNeeded() { _scanType = eNoScan; } void SetScanNeeded( BOOL fFull ) { if ( fFull ) { _scanType = eFullScan; } else if ( eNoScan == _scanType ) { _scanType = eIncrScan; } } BOOL FUsnTreeScan() const { return _fUsnTreeScan; } void InitUsnTreeScan() { _fUsnTreeScan = TRUE; _usn = 0; } void SetUsnTreeScanComplete( USN usnMax ) { Win4Assert( _fUsnTreeScan ); Win4Assert( _usn == 0 ); _fUsnTreeScan = FALSE; _usn = usnMax; } void ResetForScans() { _volumeId = CI_VOLID_USN_NOT_ENABLED; RtlZeroMemory( &_ftLastScan, sizeof(_ftLastScan) ); _scanType = eFullScan; } void ResetForUsns( VOLUMEID volId, USN const & usnStart = 0 ) { Win4Assert( volId != CI_VOLID_USN_NOT_ENABLED ); _volumeId = volId; _usn = usnStart; _fUsnTreeScan = TRUE; } private: CScopeInfo( CScopeInfo const & src ) { Win4Assert( !"Don't call me!" ); } enum EScanType { eNoScan, eIncrScan, eFullScan }; ULONGLONG _VolumeCreationTime; union { struct { ULONGLONG _JournalId; USN _usn; }; FILETIME _ftLastScan; }; ULONG _VolumeSerialNumber; WCHAR * _pwszScope; VOLUMEID _volumeId; BOOL _fUsnTreeScan; // True if a usn tree traversal is going // on this scope EScanType _scanType; }; DECL_DYNSTACK( CScopeInfoStack, CScopeInfo ); //+--------------------------------------------------------------------------- // // Class: CCiNotifyMgr // // Purpose: Manages multiple scope notifications for content index. A // single content index can have multiple scopes and each scope // needs separate notifications. // // History: 1-17-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- #if CIDBG==1 const LONGLONG eForceNetScanInterval = 2 * 60 * 1000 * 10000; // 2 mins for testing #endif // CIDBG==1 class CCiNotifyMgr { enum EEventType { eNone=0x0, eKillThread=0x1, eAddScopes=0x2, eWatchIISVRoots=0x4, eWatchRegistryScopes=0x8, eWatchCiRegistry=0x10, eUnWatchW3VRoots=0x20, eUnWatchNNTPVRoots=0x40, eUnWatchIMAPVRoots=0x80 }; friend class CCiNotifyIter; public: CCiNotifyMgr( CiCat & cicat, CCiScanMgr & scanMgr ); ~CCiNotifyMgr( ); void Resume() { _thrNotify.Resume(); } void AddPath( CScopeInfo const & scopeInfo, BOOL & fSubScopesRemoved ); BOOL RemoveScope( const WCHAR * wcsPath ); BOOL IsInScope( WCHAR const * pwcsRoot ); CMutexSem & GetMutex() { return _mutex; } void AddRef() { _refCount.AddRef(); } void Release() { _refCount.Release(); } void ProcessChanges( XPtr & xWorker ); void ProcessChanges( BYTE const * pbChanges, WCHAR const * pwcsRoot ); CCiAsyncProcessNotify * QueryAsyncWorkItem( BYTE const * pbChanges, ULONG cbChanges, WCHAR const * pwcsRoot ); void SetupScan( WCHAR const * pwcsRoot ); unsigned GetUpdateCount() { CLock lock(_mutex); return _nUpdates; } void IncrementUpdateCount( ULONG nUpdates ) { CLock lock(_mutex); _nUpdates += nUpdates; } void ResetUpdateCount() { CLock lock(_mutex); _nUpdates = 0; } void InitiateShutdown(); void WaitForShutdown(); void CancelIISVRootNotify( CiVRootTypeEnum eType ); void TrackIISVRoots( BOOL fTrackW3Svc, ULONG W3SvcInstance, BOOL fTrackNNTPSvc, ULONG NNTPSvcInstance, BOOL fTrackIMAPSvc, ULONG IMAPSvcInstance ); void TrackScopesInRegistry(); void TrackCiRegistry(); BOOL GetLastScanTime( WCHAR const * pwcsRoot, FILETIME & ft ); void UpdateLastScanTimes( FILETIME const & ft, CUsnFlushInfoList & usnFlushInfoList ); void ForceNetPathScansIf(); CiCat & GetCatalog() { return _cicat; } BOOL IsRunning() const { return !_fAbort; } private: // methods to deal with notifications. static DWORD WINAPI NotifyThread( void * self ); void _DoNotifications(); void _KillThread(); void _LokTellThreadToAddScope(); void _LokAddScopesNoThrow(); void LokWatchIISVServerNoThrow(); void LokUnWatchIISVServerNoThrow( CVRootNotify * pNotify ); void LokWatchRegistryScopesNoThrow(); void LokWatchCiRegistryNoThrow(); void _LokIncrementUpdateCount() { _nUpdates++; } void _LokForceScanNetPaths(); CiCat & _cicat; CCiScanMgr & _scanMgr; CMutexSem _mutex; // Serialize access to the data. CCiNotifyList _list; // List of scopes being watched for // notifications. CRefCount _refCount; unsigned _nUpdates; // Count of updates since the last time // scantime is written. BOOL _fAbort; // Flag set to TRUE if should abort LONGLONG _ftLastNetPathScan; // Time of the last force scan on // network drives with no notifications // // Notification thread management. System executes the APC in the context // of the thread that makes the notification request. // ULONG _evtType; CEventSem _evt; CThread _thrNotify; CScopeInfoStack _stkScopes; // // For processing changes to IIS VRoots // XPtr _xW3SvcVRootNotify; XPtr _xNNTPSvcVRootNotify; XPtr _xIMAPSvcVRootNotify; BOOL _fTrackW3Svc; BOOL _fTrackNNTPSvc; BOOL _fTrackIMAPSvc; ULONG _W3SvcInstance; ULONG _NNTPSvcInstance; ULONG _IMAPSvcInstance; BOOL _fIISAdminAlive; CRegistryScopesNotify * _pRegistryScopesNotify; CCiRegistryNotify * _pCiRegistryNotify; }; //+--------------------------------------------------------------------------- // // Class: CCiNotifyIter // // Purpose: An iterator to give successive scopes that are being watched // for notifications. // // History: 1-25-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- class CCiNotifyIter { public: CCiNotifyIter( CCiNotifyMgr & notifyMgr ) : _notifyMgr(notifyMgr), _lock(notifyMgr.GetMutex()), _iNotAdded(0), _stack(notifyMgr._stkScopes), _list(notifyMgr._list), _iter(_list) { _UpdateAtEnd(); } BOOL AtEnd() const { return _fAtEnd; } WCHAR const * Get() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->GetPath(); else return _iter->GetScope(); } void GetLastScanTime( FILETIME & ft ) { if ( _iNotAdded < _stack.Count() ) RtlZeroMemory( &ft, sizeof(FILETIME) ); else ft = _iter->GetLastScanTime(); } VOLUMEID VolumeId() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->VolumeId(); else return _iter->VolumeId(); } ULONGLONG const & VolumeCreationTime() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->VolumeCreationTime(); else return _iter->VolumeCreationTime(); } ULONG VolumeSerialNumber() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->VolumeSerialNumber(); else return _iter->VolumeSerialNumber(); } BOOL IsDownlevelVolume() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return ( CI_VOLID_USN_NOT_ENABLED == _stack.Get(_iNotAdded)->VolumeId() ); else return ( CI_VOLID_USN_NOT_ENABLED == _iter->VolumeId() ); } USN Usn() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->Usn(); else return _iter->Usn(); } ULONGLONG const & JournalId() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->JournalId(); else return _iter->JournalId(); } BOOL FUsnTreeScan() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) return _stack.Get(_iNotAdded)->FUsnTreeScan(); else return _iter->FUsnTreeScan(); } void InitUsnTreeScan() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) _stack.Get(_iNotAdded)->InitUsnTreeScan(); else _iter->InitUsnTreeScan(); } void SetTreeScanComplete(); void SetUsnTreeScanComplete( USN usnMax ); void Advance() { Win4Assert( !AtEnd() ); if ( _iNotAdded < _stack.Count() ) _iNotAdded++; else _list.Advance(_iter); _UpdateAtEnd(); } private: CCiNotifyMgr & _notifyMgr; CLock _lock; unsigned _iNotAdded; BOOL _fAtEnd; CScopeInfoStack & _stack; CCiNotifyList & _list; CFwdCiNotifyIter _iter; void _UpdateAtEnd() { Win4Assert( _iNotAdded <= _stack.Count() ); _fAtEnd = _iNotAdded == _stack.Count() && _list.AtEnd(_iter); } }; BOOL AreIdenticalPaths( WCHAR const * pwcsPath1, WCHAR const * pwcsPath2 );