//+--------------------------------------------------------------------------- // // Microsoft Windows // Copyright (C) Microsoft Corporation, 1991 - 1999. // // File: FILTMAN.CXX // // Contents: Filter Manager // // Classes: CFilterManager // // History: 03-Jan-95 BartoszM Created from parts of CResMan // //---------------------------------------------------------------------------- #include #pragma hdrstop #include #include #include #include #include "filtman.hxx" #include "resman.hxx" #include "fltstate.hxx" //+--------------------------------------------------------------------------- // // Member: CFilterAgent::CFilterAgent, public // // Synopsis: Initialize the agent, register it with ResMan // // History: 05-Jan-95 BartoszM Created // //---------------------------------------------------------------------------- CFilterAgent::CFilterAgent (CFilterManager& filterMan, CResManager& resman ) : _sigFilterAgent(eSigFilterAgent), _resman (resman), _filterMan (filterMan), _eventUpdate(FALSE), // start reset _fStopFilter(FALSE) { _resman.RegisterFilterAgent (this); } //+--------------------------------------------------------------------------- // // Member: CFilterAgent::~CFilterAgent, public // // Synopsis: Stop filtering // // History: 05-Jan-95 BartoszM Created // //---------------------------------------------------------------------------- CFilterAgent::~CFilterAgent () { if ( !_fStopFilter ) { StopFiltering(); } } void CFilterAgent::StopFiltering() { CLock lock(_mutex); _fStopFilter = TRUE; _eventUpdate.Set(); } //+--------------------------------------------------------------------------- // // Member: CFilterAgent::FilterThread, public // // Synopsis: Entry point for the thread responsible // for filtering // // History: 05-Jan-95 BartoszM Created // //---------------------------------------------------------------------------- DWORD WINAPI CFilterAgent::FilterThread( void* p ) { return S_OK; } //+--------------------------------------------------------------------------- // // Function: PutToSleep // // Synopsis: Resets the update event unless filtering is stopped // // History: Feb-08-95 BartoszM Created // //---------------------------------------------------------------------------- BOOL CFilterAgent::PutToSleep () { CLock lock(_mutex); if (_fStopFilter) return FALSE; _eventUpdate.Reset(); return TRUE; } //+--------------------------------------------------------------------------- // // Function: LokWakeUp // // Synopsis: Completes an asynchronous pending I/O request, if any. // // History: 19-Nov-94 DwightKr Moved into a method // // Notes: If a corrupt content scan is detected, this routine // will persistently record the event to disk. This may not // throw. // //---------------------------------------------------------------------------- void CFilterAgent::LokWakeUp () { _eventUpdate.Set(); } //+--------------------------------------------------------------------------- // // Member: CFilterAgent::LokCancel, public // // Synopsis: Cancel any connections to the CI Filter service. // // History: 09-Jan-95 BartoszM Created // //---------------------------------------------------------------------------- void CFilterAgent::LokCancel () { _eventUpdate.Set(); // wake up } //+--------------------------------------------------------------------------- // // Member: CFilterManager::CFilterManager, public // // Arguments: [resman] -- resource manager // // Requires: resman to be fully constructed // // History: 03-Jan-95 BartoszM Created // //---------------------------------------------------------------------------- CFilterManager::CFilterManager(CResManager& resman) : _sigFiltMan(eSigFiltMan), _resman (resman), _docList(resman.GetDocList()), #pragma warning( disable : 4355 ) // this used in base initialization _filterAgent (*this, resman ), #pragma warning( default : 4355 ) _fPushFiltering( resman.FPushFiltering() ), _LastResourceStatus( TRUE ) { LARGE_INTEGER CurrentTime; NtQuerySystemTime( &CurrentTime ); _LastResourceCheck = CurrentTime.QuadPart; _fWaitOnNoDocs = FALSE; } NTSTATUS CFilterManager::Dismount() { _filterAgent.StopFiltering(); return STATUS_SUCCESS; } //+--------------------------------------------------------------------------- // // Function: CleanupPartialWordList // // Synopsis: If there is any previous wordlist, it will cleanup the // wordlist by considering all the documents as failed with // FILTER_EXCEPTION. If the retry count has exceeded the // maximum for a document, it will be considered as UNFILTERED // and marked accordingly in the wordlist. // // This handling is necessary to deal with the case of a // repeatedly failing filter daemon on a document and to limit // the number of retries. Just refiling the documents will // lead to infinite looping. // // History: 6-16-94 srikants Separated from FilterReady for making // kernel mode call Asynchronous. // //---------------------------------------------------------------------------- void CFilterManager::CleanupPartialWordList() { if ( !_pWordList.IsNull() ) { // // We have to consider the filtering failed due to a problem in // the filter daemon and mark ALL these documents as FAILED. // ciDebugOut(( DEB_WARN, "CFilterManager::CleanupPartialWordList. " "Partially complete wordlist committed.\n" )); Win4Assert( 0 != _docList.Count() ); STATUS aStatus[CI_MAX_DOCS_IN_WORDLIST]; for ( unsigned i = 0; i < _docList.Count(); i++ ) { aStatus[i] = FILTER_EXCEPTION; } FilterDone( aStatus, _docList.Count() ); Win4Assert( _pWordList.IsNull() ); Win4Assert( 0 == _docList.Count() ); } else { Win4Assert( 0 == _docList.Count() ); } } //+--------------------------------------------------------------------------- // // Function: FilterReady // // Synopsis: User mode (down level) filter ready handler. The main // difference from the kernel mode one is that the caller // is made to WAIT for an event in this call where as in the // kernel mode call, it will be returned STATUS_PENDING if there // are no documents. // // Arguments: [docBuffer] -- // [cb] -- // [cMaxDocs] -- // // History: 6-16-94 srikants For user-mode synchronous call. // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterReady ( BYTE * docBuffer, ULONG & cb, ULONG cMaxDocs ) { CleanupPartialWordList(); SCODE scode = S_OK; ULONG cbMax = cb; TRY { ciDebugOut(( DEB_ITRACE, "# CFilterManager::FilterReady.\n" )); Win4Assert( _docList.Count() == 0 ); ULONG cDocs = 0; CGetFilterDocsState stateInfo; // loop until there are enough resources to filter and there are documents // to filter. do { // // Have at least reasonable confidence that there is // enough free memory to build the wordlist. The minimum // free space and sleep time are parameterized by size // and sleep respectively. // BOOL fRetry = FALSE; Win4Assert( _pWordList.IsNull() ); Win4Assert( _docList.Count() == 0 ); cb = 0; BOOL fGoodTimeToFilter = FALSE; _resman.SampleUserActivity(); // ================================================= { CPriLock lock(_resman.GetMutex()); fGoodTimeToFilter = LokIsGoodTimeToFilter(); } // ================================================== if ( fGoodTimeToFilter ) fGoodTimeToFilter = IsGoodTimeToFilter(); // Don't call this under lock. if ( !fGoodTimeToFilter ) { ciDebugOut(( DEB_ITRACE, "Not a good time to filter.\n" )); } // // If the disk is getting full, don't give any more documents to // be filtered. // if ( fGoodTimeToFilter ) fRetry = _resman.GetFilterDocs ( cMaxDocs, cDocs, stateInfo ); if ( 0 == cDocs ) { if (!_filterAgent.PutToSleep()) return CI_E_SHUTDOWN; if ( fRetry ) continue; // otherwise wait ciDebugOut (( DEB_ITRACE, "\t|Waiting For Event\n" )); _filterAgent.Wait( fGoodTimeToFilter ? INFINITE : _resman.GetRegParams().GetLowResourceSleep() * 1000 ); stateInfo.Reset(); ciDebugOut (( DEB_ITRACE, "\t|Wakeup!\n" )); _fWaitOnNoDocs = FALSE; } else { cb = cbMax; _resman.FillDocBuffer( docBuffer, cb, cDocs, stateInfo ); if ( cb > cbMax ) { // we need more space Win4Assert ( 0 == cDocs ); break; } } } while ( cDocs == 0 ); // There are documents to filter ciFAILTEST(STATUS_NO_MEMORY); if ( cb <= cbMax ) { Win4Assert( _docList.Count() != 0 ); NewWordList(); } } CATCH( CException, e ) { scode = e.GetErrorCode(); if ( 0 != _docList.Count() ) { // // We need to add these documents back to the change log // so that they will get filtered later. // Win4Assert( _pWordList.IsNull() ); // // Lock will be obtained by NoFailReFile before mucking with // the doclist. // if (!_resman.NoFailReFile ( _resman.GetDocList() )) scode = STATUS_CANCELLED; } } END_CATCH _fWaitOnNoDocs = FALSE; return scode; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::LokIsGoodTimeToFilter // // Synopsis: Checks to see if this is a good time to filter. // // Returns: TRUE if okay to filter now. // FALSE o/w // // History: 4-12-96 srikants Made a version for user space. // //---------------------------------------------------------------------------- BOOL CFilterManager::LokIsGoodTimeToFilter() { // // If a content scan is required, setup the returned // status. // if ( _resman.IsEmpty() ) { // // The content index is being emptied. Don't give any // more documents to daemon. // return FALSE; } else if ( _resman.IsLowOnDiskSpace() ) { // // Check if the disk status has improved and ask the // merge thread to do any book-keeping work. // if ( !_resman.LokCheckLowOnDiskSpace() ) _resman.LokWakeupMergeThread(); return FALSE; } else if ( _resman.LokCheckWordlistQuotas() ) { // // We're already at our limit, so it's not a good idea to create more. // _resman.LokWakeupMergeThread(); return FALSE; } else if ( _resman.LokIsScanNeeded() ) { // // A scan is needed if we either lost an update or we are corrupt. // _resman.LokWakeupMergeThread(); return FALSE; } return TRUE; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::IsGoodTimeToFilter // // Synopsis: Checks to see if this is a good time to filter. // // Returns: TRUE if okay to filter now. // FALSE o/w // // History: 12-Apr-96 srikants Made a version for user space. // 10-Dec-97 KyleP Make NoLok version // //---------------------------------------------------------------------------- BOOL CFilterManager::IsGoodTimeToFilter() { // // Don't do any work until the system has booted // if ( GetTickCount() < _resman.GetRegParams().GetStartupDelay() ) return FALSE; LARGE_INTEGER CurrentTime; NTSTATUS Status = NtQuerySystemTime( &CurrentTime ); if ( NT_SUCCESS(Status) ) { // Check user activity at 5 s. intervals if ( CurrentTime.QuadPart - _LastResourceCheck > 5 * 10000000i64 ) { if ( _resman.IsUserActive(FALSE) ) { // // If someone is typing on the keyboard, don't get in the way. // _LastResourceStatus = FALSE; _resman.ReportFilteringState( CIF_STATE_USER_ACTIVE ); return _LastResourceStatus; } } ULONG ulDelay = _LastResourceStatus ? _resman.GetRegParams().GetWordlistResourceCheckInterval() : _resman.GetRegParams().GetLowResourceSleep(); if ( CurrentTime.QuadPart - _LastResourceCheck > ulDelay * 10000000i64 ) { _LastResourceCheck = CurrentTime.QuadPart; DWORD dwFilterState; if ( _resman.IsMemoryLow() ) { // // If we're low on memory, don't eat up more with word lists // _LastResourceStatus = FALSE; dwFilterState = CIF_STATE_LOW_MEMORY; } else if ( _resman.IsBatteryLow() ) { _LastResourceStatus = FALSE; dwFilterState = CIF_STATE_BATTERY_POWER; } else if ( _resman.IsIoHigh() ) { // // If someone else is doing a lot of I/O, then we shouldn't add // to the problem. // _LastResourceStatus = FALSE; dwFilterState = CIF_STATE_HIGH_IO; } else if ( _resman.IsUserActive(TRUE) ) { // // If someone is typing on the keyboard, don't get in the way. // This check is done after the Hi I/O check because the user // activity is sampled over 5 seconds there. // _LastResourceStatus = FALSE; dwFilterState = CIF_STATE_USER_ACTIVE; } else { _LastResourceStatus = TRUE; dwFilterState = 0; } _resman.ReportFilteringState( dwFilterState ); } } return _LastResourceStatus; } #pragma warning( disable : 4756 ) // overflow in constant arithmetic //+--------------------------------------------------------------------------- // // Member: CFilterManager::FilterDataReady, public // // Synopsis: Adds the contents of entryBuf to the current Word List. // // Returns: Whether the word list is full. // // Arguments: [pEntryBuf] -- pointer to data to be added to Word List // [cb] -- count of bytes in buffer // // History: 22-Mar-93 AmyA Created. // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterDataReady( const BYTE * pEntryBuf, ULONG cb ) { if ( _pWordList.IsNull() ) { ciDebugOut(( DEB_WARN, "CFilterManager::FilterDataReady. No wordlist active.\n" )); return FDAEMON_E_NOWORDLIST; } ciDebugOut(( DEB_ITRACE, "# CFilterManager::FilterDataReady.\n" )); SCODE sc = S_OK; TRY { _resman.SampleUserActivity(); while (!_pWordList->MakeChunk( pEntryBuf, cb )) continue; if ( _pWordList->Size() >= _resman.GetRegParams().GetMaxWordlistSize() ) { ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDataReady -- Wordlist full\n" )); sc = FDAEMON_W_WORDLISTFULL; } if ( _resman.IsMemoryLow() ) { ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDataReady -- Running low on memory\n" )); sc = FDAEMON_W_WORDLISTFULL; // // Try forcing a merge to free things up. // _resman.ForceMerge( partidInvalid, CI_ANY_MERGE ); } } CATCH( CException, e ) { ciDebugOut(( DEB_ERROR, "Exception 0x%x caught during filtering. " "Rescheduling/aborting documents for filtering.\n", e.GetErrorCode() )); if ( e.GetErrorCode() == STATUS_INSUFFICIENT_RESOURCES ) sc = FDAEMON_E_LOWRESOURCE; else sc = FDAEMON_E_FATALERROR; #if CIDBG == 1 for ( unsigned cWid = 0; cWid < _docList.Count(); cWid++ ) { ciDebugOut(( DEB_ITRACE, "Reschedule/aborting filtering of wid %d\n", _docList.Wid(cWid) )); } #endif // CIDBG == 1 _pWordList.Delete(); // // No refiling in push filtering, hence abort wids. Refile docList // in pull filtering. // if ( _fPushFiltering ) _resman.NoFailAbortWidsInDocList(); else _resman.NoFailReFile( _resman.GetDocList() ); ciDebugOut(( DEB_ITRACE, "CFilterManager::FilterDataReady " "deleting wordlist and clearing doclist\n" )); } END_CATCH if ( sc == FDAEMON_E_LOWRESOURCE ) _resman.NoFailFreeResources(); #if CIDBG==1 { CPriLock lock(_resman.GetMutex()); Win4Assert( 0 == _docList.Count() && _pWordList.IsNull() || 0 != _docList.Count() && !_pWordList.IsNull() ); } #endif // CIDBG == 1 return sc; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::FilterDone, public // // Synopsis: Commits the current wordlist. // // Arguments: [aStatus] -- array of STATUS for current document list // [count] -- count for array // // History: 22-Mar-93 AmyA Created from MakeWordList // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterDone( const STATUS * aStatus, ULONG count ) { if ( _pWordList.IsNull() ) { Win4Assert( 0 == _docList.Count() ); ciDebugOut(( DEB_WARN, "CFilterManager::FilterDone. No wordlist active.\n" )); return( FDAEMON_E_NOWORDLIST ); } ciDebugOut(( DEB_ITRACE, "# CFilterManager::FilterDone.\n" )); _resman.SampleUserActivity(); // add statuses to _docList unsigned cDocuments = _docList.Count(); Win4Assert( cDocuments <= count ); for ( unsigned i = 0; i < cDocuments; i++ ) { // // Note - we are modifying the status on the _docList in resman // without obtaining the resman lock. This is okay as we need a lock // only to protect the count in doclist. // Note: retries are 1-based, so the first filter attempt is 1. // if ( _docList.Retries(i) > _resman.GetRegParams().GetFilterRetries() ) { _resman.GetDocList().SetStatus( i, TOO_MANY_RETRIES ); } else if ( CI_SHARING_VIOLATION == aStatus[i] && _docList.SecQRetries(i) >= _resman.GetRegParams().GetSecQFilterRetries() ) { // Documents are put in sec Q only in case of sharing violation. // Hence the above check. ciDebugOut(( DEB_IWARN, "TOO_MANY_SECQ_RETRIES Doc Wid = %ld, SecQRetries = %d\n", _docList.Wid(i), _docList.SecQRetries(i) )); _resman.GetDocList().SetStatus( i, TOO_MANY_SECQ_RETRIES ); } else if ( _docList.Status(i) != DELETED) { if ( _pWordList->IsEmpty() && ( WL_IGNORE != aStatus[i] && WL_NULL != aStatus[i] ) && CI_SHARING_VIOLATION != aStatus[i] ) { if ( CI_NOT_REACHABLE == aStatus[i] ) { ciDebugOut (( DEB_WARN, "Wid %ld is UNREACHABLE\n", _docList.Wid(i) )); _resman.GetDocList().SetStatus( i, TOO_MANY_RETRIES ); _resman.MarkUnReachable( _docList.Wid(i) ); } else { // // If the wordlist is emtpy, it means the filter did not // give us any data but still called FilterDone. We should // treat all the documents as "exceptions". // ciDebugOut (( DEB_IWARN, "setting %d'th document" " with wid %ld, status %d to exception status\n", i, _docList.Wid(i), aStatus[i] )); // // Okay not to obtain the lock - only modifying the status. // _resman.GetDocList().SetStatus( i, FILTER_EXCEPTION ); } } else { _resman.GetDocList().SetStatus( i, aStatus[i] ); } } } PARTITIONID partid = _docList.PartId(); INDEXID iid = _pWordList->GetId(); SCODE sc = 0; BOOL fRetryFailures = FALSE; BOOL fDone = TRUE; // This is so FilterMore doesn't // get messed up. Eventually, FilterDone // should be split into FilterDone and // CommitWordList. { //============================================= CPriLock lock ( _resman.GetMutex() ); // Resman is under lock till the end of block //============================================= if ( _resman.IsEmpty() ) // Content index empty { _resman.GetDocList().LokClear(); return STATUS_CANCELLED; } // Special cases: // 1. partition has been deleted // - entries in changes and fresh have been removed // - delete wordlist and return // 2. wordlist is empty // - delete wordlist // - update changes // 3. no available index id's // - put docList back into changes // - delete word list // - force merge // 4. no success statuses // - delete word list iid = _resman.LokMakeWordlistId (partid); if (iid == iidInvalid) { ciDebugOut (( DEB_IWARN, "Invalid partition, Deleting wordlist\n" )); _pWordList.Delete(); _resman.GetDocList().LokClear(); return( FDAEMON_E_PARTITIONDELETED ); } ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDone " "new wordlist id %lx\n", iid )); Win4Assert( iid != iidInvalid ); _pWordList->SetId ( iid ); BOOL successes = FALSE; for ( unsigned iDoc = 0; iDoc < cDocuments; iDoc++ ) { switch ( _docList.Status(iDoc) ) { case TOO_MANY_RETRIES: case TOO_MANY_SECQ_RETRIES: if ( !fRetryFailures ) { // // Save the state of the retry failures in the retry // fail list before they are overwritten. // _retryFailList = _docList; fRetryFailures = TRUE; } // NOTE: fall through case TOO_MANY_BLOCKS_TO_FILTER: successes = TRUE; _pWordList->MarkWidUnfiltered(iDoc); _resman.GetDocList().SetStatus( iDoc, SUCCESS ); break; case SUCCESS: _resman.IncrementFilteredDocumentCount(); successes = TRUE; break; case CI_SHARING_VIOLATION: // // If push filtering, abort the wid. If pull filtering, // add the wid to the sec queue so that filtering can be // re-attempted later. // if ( _fPushFiltering ) _resman.NoFailAbortWid( _docList.Wid(iDoc), _docList.Usn(iDoc) ); else { _resman.GetDocList().LokIncrementSecQRetryCount(iDoc); _resman.LokAddToSecQueue( partid, _docList.Wid(iDoc), _docList.VolumeId( iDoc ), _docList.SecQRetries( iDoc ) ); } _resman.GetDocList().SetStatus( iDoc, WL_NULL ); // WL_NULL is returned when the filter deliberately does // not return any data. Like DELETED, but we need to also // delete any existing data in the index. case WL_NULL: _pWordList->DeleteWidData(iDoc); // NOTE: fall through case DELETED: successes = TRUE; break; case WL_IGNORE: _pWordList->DeleteWidData(iDoc); if ( iDoc == cDocuments - 1 ) { ciDebugOut (( DEB_ITRACE, ">> Not all filtered\n" )); fDone = FALSE; } break; case PENDING: Win4Assert( !"Ci Daemon Still returning Pending" ); // // NOTE: Fall through is deliberate - should remove PENDING // when we find out we don't need it. // case PREEMPTED: // // NOTE: Fall through is deliberate. // default: ciDebugOut (( DEB_ITRACE,"++++ %d'th document" " with fake wid %d and wid %ld failed: status %d\n", iDoc, iDocToFakeWid(iDoc), _docList.Wid(iDoc), _docList.Status(iDoc) )); // // something went wrong during filtering. Delete all data // associated with this workid. // _resman.GetDocList().LokIncrementRetryCount(iDoc); _pWordList->DeleteWidData(iDoc); Win4Assert( _docList.Retries(iDoc) <= (_resman.GetRegParams().GetFilterRetries()+1) ); // // If push filtering abort the wid. If pull filtering add it back // to the change log for re-filtering at a later time. // if ( _fPushFiltering ) _resman.NoFailAbortWid( _docList.Wid(iDoc), _docList.Usn(iDoc) ); else _resman.LokReFileDocument( partid, _docList.Wid(iDoc), _docList.Usn(iDoc), _docList.VolumeId(iDoc), _docList.Retries(iDoc), _docList.SecQRetries(iDoc) ); break; } } if ( !successes ) // only invalid data in word list { ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDone " "deleting wordlist with invalid data\n" )); _pWordList.Delete(); sc = FDAEMON_W_EMPTYWORDLIST; } else if ( !_resman.LokTransferWordlist ( _pWordList ) ) { // // If push filtering, abort all wids. If pull filtering, // refile all wids. // if ( _fPushFiltering) _resman.NoFailAbortWidsInDocList(); else _resman.NoFailReFile( _resman.GetDocList() ); _pWordList.Delete(); return( FDAEMON_E_WORDLISTCOMMITFAILED ); } if ( fDone && (WL_IGNORE != aStatus[cDocuments-1]) ) { ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterDone " "clearing doclist\n" )); _resman.GetDocList().LokClear(); } _resman.LokUpdateCounters(); // Update # filtred documents } //========================================== // // Notification of failed docs cannot be done under lock. // if ( fRetryFailures ) { for ( unsigned iDoc = 0; iDoc < cDocuments; iDoc++ ) { if ( ( _retryFailList.Status(iDoc) == TOO_MANY_RETRIES || _retryFailList.Status(iDoc) == TOO_MANY_SECQ_RETRIES ) && CI_NOT_REACHABLE != aStatus[iDoc] ) _resman.ReportFilterFailure (_retryFailList.Wid(iDoc)); } } return sc; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::StoreValue // // Synopsis: Store a property value. // // Arguments: [widFake] -- Fake wid of object. // [prop] -- Property descriptor // [var] -- Value // [fCanStore] -- Returns TRUE if this is a storable property // // History: 21-Dec-95 KyleP Created // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterStoreValue( WORKID widFake, CFullPropSpec const & ps, CStorageVariant const & var, BOOL & fCanStore ) { fCanStore = TRUE; Win4Assert( widFake > 0 ); if ( widFake <= 0 ) return STATUS_INVALID_PARAMETER; widFake = FakeWidToIndex( widFake ); if ( widFake >= _docList.Count() ) return STATUS_INVALID_PARAMETER; return _resman.StoreValue( _docList.Wid( widFake ), ps, var, fCanStore ); } //+--------------------------------------------------------------------------- // // Member: CFilterManager::StoreSecurity // // Synopsis: Store a file's security descriptor. // // Arguments: [widFake] -- Fake wid of object. // [pSD] -- pointer to security descriptor // [cbSD] -- size in bytes of pSD // [fCanStore] -- Returns TRUE if storae succeeded // // Notes: Used only for downlevel index // // History: 21-Dec-95 KyleP Created // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterStoreSecurity( WORKID widFake, PSECURITY_DESCRIPTOR pSD, ULONG cbSD, BOOL & fCanStore ) { fCanStore = FALSE; Win4Assert( widFake > 0 ); if ( widFake <= 0 ) return STATUS_INVALID_PARAMETER; widFake = FakeWidToIndex( widFake ); if ( widFake >= _docList.Count() ) return STATUS_INVALID_PARAMETER; fCanStore = _resman.StoreSecurity( _docList.Wid( widFake ), pSD, cbSD ); return S_OK; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::FPSToPROPID, public // // Synopsis: Converts FULLPROPSPEC property to PROPID // // Arguments: [fps] -- FULLPROPSPEC representation of property // [pid] -- PROPID written here on success // // Returns: S_OK on success // // History: 29-Dec-1997 KyleP Created. // //---------------------------------------------------------------------------- SCODE CFilterManager::FPSToPROPID( CFullPropSpec const & fps, PROPID & pid ) { return _resman.FPSToPROPID( fps, pid ); } #pragma warning( default : 4756 ) // overflow in constant arithmetic //+--------------------------------------------------------------------------- // // Member: CFilterManager::FilterMore, public // // Synopsis: Commits the current wordlist and creates a new one. // // Arguments: [aStatus] -- array of STATUS for the current document list // [count] -- count for array // // History: 03-May-93 AmyA Created. // //---------------------------------------------------------------------------- SCODE CFilterManager::FilterMore( const STATUS * aStatus, ULONG count ) { ciDebugOut (( DEB_ITRACE, "# CFilterManager::FilterMore\n" )); if ( _pWordList.IsNull() ) { ciDebugOut(( DEB_WARN, "FilterMore: No wordlist active.\n" )); return( FDAEMON_E_NOWORDLIST ); } SCODE sc = FilterDone( aStatus, count ); // Commits Word List if ( SUCCEEDED(sc) ) // No problems occured { // _docList may have been cleared for an error condition. ciDebugOut (( DEB_ITRACE, "CFilterManager::FilterMore " "_docList.Count() = %d\n", _docList.Count() )); TRY { ciFAILTEST(STATUS_NO_MEMORY); if ( _docList.Count() != 0 ) NewWordList(); // Creates New Word List } CATCH( CException, e ) { sc = e.GetErrorCode(); Win4Assert( _pWordList.IsNull() ); // // If push filtering, abort wids. In pull filtering add these documents // back to the change log so that they will get filtered later. // if ( _fPushFiltering ) _resman.NoFailAbortWidsInDocList(); else { if (!_resman.NoFailReFile ( _resman.GetDocList() )) sc = STATUS_CANCELLED; } } END_CATCH } #if CIDBG==1 { CPriLock lock(_resman.GetMutex()); Win4Assert( 0 == _docList.Count() && _pWordList.IsNull() || 0 != _docList.Count() && !_pWordList.IsNull() ); } #endif // CIDBG == 1 return sc; } //+--------------------------------------------------------------------------- // // Member: CFilterManager::NewWordList, public // // Synopsis: Creates word list // // History: 08-Apr-91 BartoszM Created // 24-Nov-92 KyleP Retry pending documents // 22-Mar-93 AmyA Split into NewWordList and // CommitWordList // //---------------------------------------------------------------------------- void CFilterManager::NewWordList() { unsigned cDocuments = _docList.Count(); Win4Assert ( cDocuments != 0 ); PARTITIONID partid = _docList.PartId(); WORKID widMax = _docList.WidMax(); CIndexId iid ( iidInvalid, partid ); ciDebugOut (( DEB_ITRACE, "NewWordlist. Temporary iid %lx\n", iid )); _pWordList.Initialize ( iid, widMax ); // initialize the wid translation table for ( unsigned i = 0; i < cDocuments; i++ ) _pWordList->AddWid( _docList.Wid(i), _docList.VolumeId(i) ); }