//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1992 - 2000. // // File: scanmgr.cxx // // Contents: Scan manager // // History: 14-Jul-97 SitaramR Created from dlnotify.cxx // // Notes : For lock hierarchy and order of acquiring locks, please see // cicat.cxx // // DISKFULL HANDLING // // The disk full situation is either detected in RESMAN and information sent // up to CICAT or a DISKFULL error is first detected in CICAT and then // propagated to RESMAN. As part of diskfull processing in the scope table, // existing scans are aborted in scanmanager and future scans are disabled // until the diskfull gets cleared up. If DISKFULL is detected at startup // time, the scope table enters a "incremental scan required" state and doesn't // schedule any scans/notifications until the situation improves. // // If the changelog loses a notification, a DisableUpdates notification is sent // to the DocStore. The scan is deferred until an EnableUpdates notification // is sent to DocStore. // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include #include #include "cicat.hxx" #include "update.hxx" #include "notifmgr.hxx" #include "scanmgr.hxx" #include "scopetbl.hxx" //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::CCiScanMgr // // Synopsis: ~ctor of the scan manager for downlevel CI. It starts a // background thread for doing the scans. // // Arguments: [cicat] - // // History: 1-19-96 srikants Created // 3-03-98 kitmanh Initialized member _fIsReadOnly with // cicat.IsReadOnly // // Notes: // //---------------------------------------------------------------------------- CCiScanMgr::CCiScanMgr( CiCat & cicat ) : _cicat(cicat), _fAbort(FALSE), _fSerializeChanges(FALSE), _state(eStart), #pragma warning( disable : 4355 ) // this used in base initialization _thrScan( ScanThread, this, TRUE ), // create suspended #pragma warning( default : 4355 ) _fBatch(FALSE), // disable batch processing _fAbortScan(FALSE), _fScanDisabled(FALSE), _fIsReadOnly(cicat.IsReadOnly()), _dwLastShareSynch( 0 ) { _evtScan.Reset(); _thrScan.SetPriority( THREAD_PRIORITY_BELOW_NORMAL ); } CCiScanMgr::~CCiScanMgr() { InitiateShutdown(); WaitForShutdown(); // delete any in-progress scan info CLock lock( _mutex ); while ( !_scansInProgress.IsEmpty() ) { delete _scansInProgress.RemoveLast(); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::StartRecovery // // Synopsis: Sets the state to indicate that recovery must be done // and wakes up the scan thread. // // History: 3-06-96 srikants Created // //---------------------------------------------------------------------------- void CCiScanMgr::StartRecovery() { CLock lock(_mutex); Win4Assert( eStart == _state ); _state = eDoRecovery; _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::StartScansAndNotifies // // Synopsis: Initiates scans and notifications in the document store. // // History: 12-09-96 srikants Created // //---------------------------------------------------------------------------- void CCiScanMgr::StartScansAndNotifies() { CLock lock(_mutex); Win4Assert( eRecovered == _state ); _state = eStartScans; _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_LokIsScanScheduled // // Synopsis: Tests if the given scope is already scheduled for a scan. // // Arguments: [xScanInfo] - Smart pointer to scaninfo // // History: 2-26-96 srikants Created // //---------------------------------------------------------------------------- BOOL CCiScanMgr::_LokIsScanScheduled( const XPtr & xScanInfo ) { WCHAR const * pwszNewScope = xScanInfo->GetPath(); unsigned lenNewScope = wcslen( pwszNewScope ); for ( CFwdScanInfoIter scanInfoIter(_scansToDo); !_scansToDo.AtEnd(scanInfoIter); _scansToDo.Advance(scanInfoIter) ) { if ( xScanInfo->LokGetWorkType() == scanInfoIter->LokGetWorkType() ) { WCHAR const * pwszPath = scanInfoIter->GetPath(); CScopeMatch scope( pwszPath, wcslen(pwszPath) ); if (scope.IsInScope( pwszNewScope, lenNewScope )) { ciDebugOut(( DEB_ITRACE,"Scan already scheduled for (%ws)\n", pwszNewScope )); return TRUE; } } } return FALSE; } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::ScanScope // // Synopsis: Adds the given scope to the list of scopes to scan. // // Arguments: [xScanInfo] - Will be acquired from the safe pointer if // successfully taken over. // [fDelayed] - Set to TRUE if the scan must not be done // immediately. // [fRefiled] - Set to TRUE if this is a refile or retry scan // // History: 1-23-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::ScanScope( XPtr & xScanInfo, BOOL fDelayed, BOOL fRefiled ) { CLock lock( _mutex ); if ( xScanInfo->GetRetries() <= CCiScanInfo::MAX_RETRIES && !_LokIsScanScheduled( xScanInfo ) ) { Win4Assert( !xScanInfo->LokIsInFinalState() ); Win4Assert( xScanInfo->LokIsInScan() || xScanInfo->LokIsDelScope() || xScanInfo->LokIsRenameDir() ); if ( fRefiled ) { // // A scan that has been refiled should be done before new scans // to ensure that all scans are done in FIFO order. // _scansToDo.Push( xScanInfo.GetPointer() ); } else _scansToDo.Queue( xScanInfo.GetPointer() ); xScanInfo.Acquire(); if ( !fDelayed ) _evtScan.Set(); } else { xScanInfo.Free(); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::DirAddNotification // // Synopsis: Schedules the scan of a new directory // // Arguments: [pwcsDirName] - Directory added // // History: 20-Mar-96 SitaramR Added header // //---------------------------------------------------------------------------- void CCiScanMgr::DirAddNotification( WCHAR const *pwcsDirName ) { // // Force a full scan of the direcotry, because the directory is new and so // it cannot have been scanned before // XPtr xScanInfo( _QueryScanInfo( pwcsDirName, _cicat.GetPartition(), UPD_FULL, FALSE ) ); xScanInfo->SetScan(); xScanInfo->SetProcessRoot(); //--------------------------------------------------------- { CLock lock( _mutex ); _scansToDo.Queue( xScanInfo.GetPointer() ); xScanInfo.Acquire(); _evtScan.Set(); // Wake up the scan thread } //--------------------------------------------------------- } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::DirRenameNotification // // Synopsis: Schedules the scan of a rename directory notification // // Arguments: [pwcsDirOldName] - Previous name of irectory // [pwcsDirNewName] - New name of directory // // History: 20-Mar-96 SitaramR Added header // //---------------------------------------------------------------------------- void CCiScanMgr::DirRenameNotification( WCHAR const *pwcsDirOldName, WCHAR const *pwcsDirNewName ) { BOOL fRenameScheduled = FALSE; CLock lock( _mutex ); for ( CFwdScanInfoIter scanInfoIter( _scansToDo ); !_scansToDo.AtEnd( scanInfoIter ); _scansToDo.Advance( scanInfoIter ) ) { // // if dirA is renamed to dirB, and then dirB is renamed to dirC, then it is // the same as dirA being renamed to dirC. // // Note: if dirA is renamed to dirB, and then dirB is renamed to dirA, we don't // cancel the two renames because it may not yield the same original state. For // example, after the first rename if a file, say file1, below dirB is deleted, and // then dirB is renamed to dirA, then since the strings table is not aware of the // file dirB\file1, no action will be taken, ie the file won't be deleted. By // scheduling the two renames one after another the wid corresponding to dirB\file1 // will be correctly deleted. // if ( scanInfoIter->LokIsRenameDir() && AreIdenticalPaths( scanInfoIter->GetPath(), pwcsDirOldName ) && !AreIdenticalPaths( scanInfoIter->GetDirOldName(), pwcsDirNewName ) ) // See note above { // // By overwriting dirC over dirB (see example above), we have combined the two rename // operations into one rename operation // scanInfoIter->LokSetPath( pwcsDirNewName ); fRenameScheduled = TRUE; break; } } if ( !fRenameScheduled ) { XPtr xScanInfo( _QueryScanInfo( pwcsDirNewName, _cicat.GetPartition(), UPD_INCREM, FALSE ) ); xScanInfo->SetRenameDir(); xScanInfo->SetDirOldName( pwcsDirOldName ); ScanScope( xScanInfo, TRUE, FALSE ); // // If this rename operation is interrupted in the middle (because of a // subsequent delete or rename) then files/wids under the old directory may // still be lying around in the property store. To ensure that all such // files/wids are removed, schedule a remove operation for the old directory // name. // _LokScheduleRemove( pwcsDirOldName ); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_QueryScanInfo // // Synopsis: Returns a new instance of CCiScanInfo // // Arguments: [pwcsScope] -- Scope // [partId] -- Partition id // [updFlag] -- Incremental or full update // [fDoDeletions] -- Shoud deletions be done ? // [fNewScope] -- TRUE if a new scope // // History: 20-Mar-96 SitaramR Added header // //---------------------------------------------------------------------------- CCiScanInfo * CCiScanMgr::_QueryScanInfo( WCHAR const * pwcsScope, PARTITIONID partId, ULONG updFlag, BOOL fDoDeletions, BOOL fNewScope ) { Win4Assert( 0 != pwcsScope ); ULONG len = wcslen( pwcsScope ); Win4Assert( pwcsScope[len-1] == L'\\' ); XArray xPath( len+1 ); RtlCopyMemory( xPath.Get(), pwcsScope, xPath.SizeOf() ); return new CCiScanInfo( xPath, partId, updFlag, fDoDeletions, CI_VOLID_USN_NOT_ENABLED, 0, FALSE, fNewScope ); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::ScanScope // // Synopsis: Adds the given scope with given characteristics to the list // of paths to be scanned. // // Arguments: [pwcsScope] - path name of scope to be added // [partId] - partition ID // [updFlag] - // [fDoDeletions] - // [fDelayed] - // [fNewScope] - TRUE if a new scope // // History: 1-19-96 srikants Created // //---------------------------------------------------------------------------- void CCiScanMgr::ScanScope( WCHAR const * pwcsScope, PARTITIONID partId, ULONG updFlag, BOOL fDoDeletions, BOOL fDelayed, BOOL fNewScope ) { Win4Assert( wcslen(pwcsScope) < MAX_PATH ); XPtr xScanInfo( _QueryScanInfo( pwcsScope, partId, updFlag, fDoDeletions, fNewScope ) ); xScanInfo->SetScan(); xScanInfo->SetProcessRoot(); ScanScope( xScanInfo, fDelayed, FALSE ); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::ScheduleSerializeChanges // // Synopsis: Schedules a serialize-changes task // // History: 20-Aug-97 SitaramR Created // //---------------------------------------------------------------------------- void CCiScanMgr::ScheduleSerializeChanges() { CLock lock(_mutex); _fSerializeChanges = TRUE; _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::InitiateShutdown // // Synopsis: Initiates the shutdown process. // // History: 2-28-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::InitiateShutdown() { CLock lock(_mutex); _fAbort = TRUE; _fAbortScan = TRUE; // // collect all the paths from the to-do stack. // while ( _scansToDo.Count() > 0 ) { // // delete any pending scans. // delete _scansToDo.Pop(); } _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::WaitForShutdown // // Synopsis: Waits for the shutdown to complete. // // History: 2-28-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::WaitForShutdown() { // // If we never started running, then just bail out. // if ( _thrScan.IsRunning() ) { ciDebugOut(( DEB_ITRACE, "Waiting for death of scan thread\n" )); _thrScan.WaitForDeath(); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::SetBatch // // Synopsis: Sets the flag that batch processing of scans is in progress. // Until the flag is turned off, the scan thread will not look // at the scopes for scanning. // // History: 1-23-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::SetBatch() { CLock lock(_mutex); _fBatch = TRUE; } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::ClearBatch // // Synopsis: Clears the batch processing flag and wakes up the scan // thread. All the accumulated scopes for scanning will be // retrieved by the scan thread and processed. // // History: 1-23-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::ClearBatch() { CLock lock(_mutex); _fBatch = FALSE; _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::WakeUp // // Synopsis: Wakes up the scan thread. // // History: 1-23-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::WakeUp() { CLock lock(_mutex); _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::ScanThread // // Synopsis: // // Arguments: [self] - // // History: 1-19-96 srikants Created // 3-03-98 kitmanh Don't _DoScans if catalog is read-only // //---------------------------------------------------------------------------- DWORD CCiScanMgr::ScanThread( void * self ) { SCODE sc = CoInitializeEx( 0, COINIT_MULTITHREADED ); ((CCiScanMgr *) self)->_DoScans(); CoUninitialize(); ciDebugOut(( DEB_ITRACE, "Terminating scan thread\n" )); // // This is only necessary if thread is terminated from DLL_PROCESS_DETACH. // //TerminateThread( ((CCiScanMgr *) self)->_thrScan.GetHandle(), 0 ); return 0; } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::SetScanSuccess, public // // Synopsis: Called on successful completion of scan. // // Arguments: [pScanInfo] -- Scope that was scanned. // // History: 13-Apr-1998 KyleP Moved to .cxx and added cicat callback. // //---------------------------------------------------------------------------- void CCiScanMgr::SetScanSuccess( CCiScanInfo * pScanInfo ) { Win4Assert( 0 != pScanInfo ); CLock lock(_mutex); if ( !_fAbort && !_fAbortScan ) { pScanInfo->LokSetDone(); _cicat.SetTreeScanComplete( pScanInfo->GetPath() ); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_DoScans // // Synopsis: // // History: 1-19-96 srikants Created // 3-25-98 kitmanh Just set the initialized event and return // if cat is r/o // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::_DoScans() { if ( IsReadOnly() ) { _cicat.SetEvtInitialized(); _cicat.SetEvtPh2Init(); _cicat.SynchWithRegistryScopes(); return; } BOOL fContinue = TRUE; BOOL fScanned = FALSE; // set to TRUE if a scan is performed while ( fContinue ) { BOOL fWait = FALSE; // flag set to TRUE if a wait must be done EState workType = eStart; BOOL fShortWait = FALSE; BOOL fSerializeChanges = FALSE; // No serialize-changes tasks yet NTSTATUS status = STATUS_SUCCESS; // // Don't do any work until the system has booted // while ( ( GetTickCount() < _cicat.GetRegParams()->GetStartupDelay() ) && ( eStart != _state ) && ( eDoRecovery != _state ) ) { Sleep( 200 ); if ( _fAbort ) break; } TRY { XPtr xScanInfo; // ========================================= { CLock lock(_mutex); if ( _fAbort ) break; if ( !_fBatch && _LokIsOkToScan() ) { // // refile any incomplete paths that could not be // refiled due to low resources. // if ( _scansInProgress.Count() > 0 ) { _LokEmptyInProgressScans(); } // // collect all the paths from the to-do stack. // while ( _scansToDo.Count() > 0 ) { // should first save in a safe pointer because the // push can fail. xScanInfo.Set( _scansToDo.Pop() ); if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() ) { _scansInProgress.Queue( xScanInfo.GetPointer() ); xScanInfo.Acquire(); } else { // this scope is deleted xScanInfo.Free(); } } if ( 0 == _scansInProgress.Count() ) _evtScan.Reset(); if ( 0 == _scansInProgress.Count() && _fSerializeChanges ) { // // Make local copy of fSerializeChanges for use outside lock. Also // reset _fSerializeChanges since a flush task will be scheduled below. // fSerializeChanges = TRUE; _fSerializeChanges = FALSE; } } else if ( _LokIsDoRecovery() ) { _evtScan.Reset(); workType = eDoRecovery; } else if ( _LokIsStartScans() ) { _evtScan.Reset(); workType = eStartScans; } } // ========================================= // // Update fixups. We have to do this at regular // intervals because there is no notification API for // share changes. Check no more often than every 15 // minutes; this drags in 13 DLLs. // DWORD cmsDifference = GetTickCount() - _dwLastShareSynch; if ( cmsDifference > ( _cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 ) ) { // // Don't do this in resource-bound situations // CI_STATE State; State.cbStruct = sizeof( State ); SCODE sc = _cicat.CiState( State ); if ( SUCCEEDED( sc ) && ( 0 == ( State.eState & ( CI_STATE_HIGH_IO | CI_STATE_LOW_MEMORY | CI_STATE_USER_ACTIVE ) ) ) ) { _cicat.SynchShares(); // // it is OK to modify this outside the class lock because // only one thread performs scans for a catalog at any moment // and there is one CCiScanMgr object per catalog. // _dwLastShareSynch = GetTickCount(); } } if ( eDoRecovery == workType ) { // // Do the long running initialization. // Win4Assert( !IsReadOnly() ); // Note: recovery is now synchronous, but this must be // done asynchronously, since the callback to the docstore // must be done by a worker thread. //_cicat.DoRecovery(); // // Set the state of the scan manager as recovered. // // ====================================== { CLock lock(_mutex); _state = eRecovered; } // ====================================== ciDebugOut(( DEB_WARN, "Setting CiCat recovery done...\n" )); _cicat.SetRecoveryCompleted(); } else if ( eStartScans == workType ) { _cicat.StartScansAndNotifies(); CLock lock(_mutex); _state = eNormal; } else if ( _scansInProgress.Count() > 0 ) { fScanned = TRUE; _Scan(); Win4Assert( 0 == _scansInProgress.Count() || _fAbort ); } else if ( fSerializeChanges ) { _cicat.SerializeChangesInfo(); fWait = TRUE; } else { fWait = TRUE; } // // Do scans complete processing if appropriate. // if ( fWait && eNormal == _state && !_fScanDisabled && !fSerializeChanges ) { _cicat.ProcessScansComplete( fScanned, fShortWait ); } } CATCH (CException, e) { status = e.GetErrorCode(); ciDebugOut(( DEB_ERROR, "CCiScanMgr::_DoScans. Caught exception 0x%X\n", status )); if ( CiCat::IsDiskLowError( status ) || STATUS_INSUFFICIENT_RESOURCES == status || STATUS_NO_MEMORY == status ) { // delay the execution of the thread until resources are // available. fWait = TRUE; } else { _cicat.HandleError( status ); fContinue = FALSE; } // We did not successfully complete recovery, but we need to signal that // phase 2 init is complete (albeit unsuccessfully) // fix for bug 151799 if (_cicat.IsCorrupt() && eDoRecovery == workType) _cicat.SignalPhase2Completion(); } END_CATCH if ( fWait ) { fScanned = FALSE; // // If we are waiting during long initialization, then have a // shorter wait time to see if the error condition has cleared // up. // DWORD dwWaitTime = ( (eStart != workType) || fShortWait) ? PREINIT_WAIT : AUTOSCAN_WAIT; dwWaitTime = min( dwWaitTime, _cicat.GetRegParams()->GetForcedNetPathScanInterval() * 60 * 1000 ); dwWaitTime = min( dwWaitTime, _cicat.GetRegParams()->MaxAutoAliasRefresh() * 1000 * 60 ); _evtScan.Wait( dwWaitTime ); } } } //_DoScans //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_LokEmptyInProgressScans // // Synopsis: Removes all the scans from the "in-progress stack" and either // deletes them or re-schedules them. If the scan is in its // "terminal state", the scan is deleted. If there is a retry // it will be re-scheduled. // // History: 1-25-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::_LokEmptyInProgressScans() { // // refile any scopes that still need to be worked on. // while ( _scansInProgress.Count() > 0 ) { if ( _fAbort ) break; XPtr xScanInfo( _scansInProgress.RemoveLast() ); if ( !_fScanDisabled && !xScanInfo->LokIsInFinalState() ) { #if CIDBG==1 if ( xScanInfo->LokIsDelScope() ) { ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for removal\n", xScanInfo->GetPath() )); } else if ( xScanInfo->LokIsRenameDir() ) { ciDebugOut(( DEB_ITRACE, "Requeing scope (%ws) for rename\n", xScanInfo->GetPath() )); } else { ciDebugOut(( DEB_ITRACE, "Requeuing scope (%ws) for scan\n", xScanInfo->GetPath() )); } #endif // CIDBG==1 ScanScope( xScanInfo, xScanInfo->LokIsRetry(), // delay for retry TRUE ); // It's a refiled scan } else { xScanInfo.Free(); } } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_Scan // // Synopsis: // // Returns: // // Modifies: // // History: 1-25-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::_Scan() { // does not THROW _cicat.DoUpdate( _scansInProgress, *this, _fAbortScan ); // ============================================================= { CLock lock(_mutex); _LokEmptyInProgressScans(); _fAbortScan = FALSE; } // ============================================================= } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::_LokScheduleRemove // // Synopsis: Schedules a path for removal. // // Arguments: [pwscScope] - Scope to be removed from CiCat. // // History: 1-26-96 srikants Created // // Notes: // //---------------------------------------------------------------------------- void CCiScanMgr::_LokScheduleRemove( WCHAR const * pwcsScope ) { CCiScanInfo * pScanInfo = _QueryScanInfo( pwcsScope, _cicat.GetPartition(), UPD_INCREM, TRUE ); XPtr xScanInfo( pScanInfo ); pScanInfo->LokSetDelScope(); ScanScope( xScanInfo, FALSE, FALSE ); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::RemoveScope // // Synopsis: Removes the scope from any active or in-progress scans and // marks it for "deletions". If there is no active or in-progress // scan for the scope, a new "deletion scan" will be scheduled. // // Arguments: [pwcsScope] - The scope to be removed. // // History: 1-25-96 srikants Created // // Notes: This method must not only remove the scope from the scheduled // scans but also from any currently in-progress scans. It is // possible that the scan thread is currently working on the // path to be removed. In that case, we set the state of the // scope to indicate that it must be aborted. // //---------------------------------------------------------------------------- void CCiScanMgr::RemoveScope( WCHAR const * pwcsScope ) { // // if the given scope is in the list of paths being currently // scanned, we must mark it deleted. // BOOL fRemoved = FALSE; // =========================================================== { CLock lock(_mutex); if ( _fAbort ) return; for ( CFwdScanInfoIter scanInfoIter1( _scansToDo ); !_scansToDo.AtEnd( scanInfoIter1 ); _scansToDo.Advance( scanInfoIter1 ) ) { WCHAR const * pwcsPath = scanInfoIter1->GetPath(); if ( AreIdenticalPaths( pwcsScope, pwcsPath ) ) { fRemoved = TRUE; if ( !scanInfoIter1->LokIsDelScope() ) scanInfoIter1->LokSetDelScope(); } } // // Next see in the list of paths being currently scanned. // for ( CFwdScanInfoIter scanInfoIter2( _scansInProgress ); !_scansInProgress.AtEnd( scanInfoIter2 ); _scansInProgress.Advance( scanInfoIter2 ) ) { WCHAR const * pwcsPath = scanInfoIter2->GetPath(); if ( AreIdenticalPaths( pwcsScope, pwcsPath ) ) { fRemoved = TRUE; if ( !scanInfoIter2->LokIsDelScope() ) { _fAbortScan = TRUE; scanInfoIter2->LokSetDelScope(); } } } if ( !fRemoved ) { _LokScheduleRemove( pwcsScope ); fRemoved = TRUE; } _evtScan.Set(); // wake up the scan thread. Win4Assert( fRemoved ); } // =========================================================== } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::DisableScan // // Synopsis: Disables further scans and aborts any in progress. // // History: 4-16-96 srikants Created // //---------------------------------------------------------------------------- void CCiScanMgr::DisableScan() { CLock lock(_mutex); _fAbortScan = TRUE; _fScanDisabled = TRUE; _evtScan.Set(); } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::EnableScan // // Synopsis: Re-enables scanning if scanning is currently disabled. // // History: 4-16-96 srikants Created // //---------------------------------------------------------------------------- void CCiScanMgr::EnableScan() { CLock lock(_mutex); if ( _fScanDisabled ) { _fScanDisabled = FALSE; _evtScan.Set(); } } //+--------------------------------------------------------------------------- // // Member: CCiScanMgr::AnyInitialScans // // Synopsis: Checks if any scans are the result of a new scope // // Returns: TRUE if any scans are for new scopes // // History: 3-Aug-98 dlee Created // //---------------------------------------------------------------------------- BOOL CCiScanMgr::AnyInitialScans() { for ( CFwdScanInfoIter iter1( _scansToDo ); !_scansToDo.AtEnd( iter1 ); _scansToDo.Advance( iter1 ) ) { if ( iter1->IsNewScope() ) return TRUE; } for ( CFwdScanInfoIter iter2( _scansInProgress ); !_scansInProgress.AtEnd( iter2 ); _scansInProgress.Advance( iter2 ) ) { if ( iter2->IsNewScope() ) return TRUE; } return FALSE; } //AnyInitialScans