Windows-Server-2003/inetsrv/query/fdriver/fdaemon.cxx

855 lines
25 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1991 - 2000.
//
// File: FDAEMON.CXX
//
// Contents: Filter driver
//
// History: 23-Mar-93 AmyA Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
#include <fdaemon.hxx>
#include <widtab.hxx>
#include <lang.hxx>
#include <drep.hxx>
#include <cci.hxx>
#include <pfilter.hxx>
#include <pageman.hxx>
#include <propspec.hxx>
#include <pidmap.hxx>
#include <imprsnat.hxx>
#include <frmutils.hxx>
#include <ntopen.hxx>
#include <ciguid.hxx>
#include "fdriver.hxx"
#include "ebufhdlr.hxx"
#include "ikrep.hxx"
#if DEVL==1
void DebugPrintStatus( STATUS stat );
#endif // DEVL
const GUID guidHtmlMeta = HTMLMetaGuid;
//+---------------------------------------------------------------------------
//
// Class: CDocBufferIter
//
// Purpose: To iterate through a docBuffer passed back from the
// FilterDataReady call
//
//----------------------------------------------------------------------------
class CDocBufferIter
{
public:
CDocBufferIter( const BYTE *pBuffer, int cbBuffer );
BOOL AtEnd();
const BYTE * GetCurrent(unsigned & iDoc, ULONG & cbDoc );
void Next();
unsigned GetCount() const { return _iDoc; }
private:
const BYTE * _pCurrent;
const BYTE * _pEnd;
USHORT _cDocs; // Document Count
USHORT _iDoc; // Current document
USHORT _cbCurrDoc; // Number of bytes in the current doc
};
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
CDocBufferIter::CDocBufferIter(const BYTE *pBuffer, int cbBuffer) :
_pCurrent(pBuffer+sizeof USHORT),
_pEnd(pBuffer+cbBuffer),
_iDoc(0),
_cbCurrDoc(0)
{
Win4Assert( cbBuffer >= sizeof USHORT );
RtlCopyMemory( &_cDocs, pBuffer, sizeof USHORT );
Win4Assert( _cDocs <= CI_MAX_DOCS_IN_WORDLIST );
//
// Setup for the first document.
//
if ( _cDocs > 0 )
{
Win4Assert( _pCurrent + sizeof USHORT <= _pEnd );
RtlCopyMemory( &_cbCurrDoc, _pCurrent, sizeof USHORT );
_pCurrent += sizeof USHORT;
}
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
BOOL CDocBufferIter::AtEnd()
{
Win4Assert( _iDoc <= _cDocs );
Win4Assert( _pCurrent <= _pEnd );
return (_iDoc == _cDocs);
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
const BYTE * CDocBufferIter::GetCurrent(unsigned & iDoc, ULONG & cbDoc )
{
Win4Assert( !AtEnd() );
iDoc = _iDoc; // Number of current document
Win4Assert( iDoc < CI_MAX_DOCS_IN_WORDLIST );
cbDoc = _cbCurrDoc;
return _pCurrent;
}
//+---------------------------------------------------------------------------
//----------------------------------------------------------------------------
void CDocBufferIter::Next()
{
//
// Setup next document
//
if ( !AtEnd() )
{
_pCurrent += _cbCurrDoc;
if ( _pCurrent < _pEnd )
{
Win4Assert( _pCurrent + sizeof USHORT <= _pEnd );
RtlCopyMemory( &_cbCurrDoc, _pCurrent, sizeof USHORT );
_pCurrent += sizeof USHORT;
}
else
{
Win4Assert( _pCurrent == _pEnd );
_cbCurrDoc = 0;
}
_iDoc++;
}
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::CFilterDaemon, public
//
// History: 23-Mar-93 AmyA Created.
//
//----------------------------------------------------------------------------
CFilterDaemon::CFilterDaemon ( CiProxy & proxy,
CCiFrameworkParams & params,
CLangList & LangList,
BYTE * buf,
ULONG cbMax,
ICiCFilterClient *pICiCFilterClient )
: _proxy( proxy ),
_params( params ),
_cFilteredDocuments( 0 ),
_cFilteredBlocks( 0 ),
_pbCurrentDocument( NULL ),
_cbCurrentDocument( 0 ),
_fStopFilter( FALSE ),
_fWaitingForDocument( FALSE ),
_fOwned( FALSE ),
_entryBuffer( buf ),
_cbMax( cbMax ),
_xFilterClient( pICiCFilterClient ),
_LangList( LangList ),
_pidmap( &_proxy )
{
//
// Even though we've saved pICiCFilterClient in a safe pointer, it is
// NOT correctly referenced by the caller. That is our responsibility
//
_xFilterClient->AddRef( );
//
// get ICiCAdviseStatus interface pointer
//
SCODE sc = _xFilterClient->QueryInterface( IID_ICiCAdviseStatus, _xAdviseStatus.GetQIPointer() );
if ( S_OK != sc )
{
THROW( CException(sc) );
}
//
// Get optional filter status interface.
//
sc = _xFilterClient->QueryInterface( IID_ICiCFilterStatus, _xFilterStatus.GetQIPointer() );
Win4Assert( ( SUCCEEDED(sc) && !_xFilterStatus.IsNull() ) ||
( FAILED(sc) && _xFilterStatus.IsNull() ) );
//
// Get config info
//
sc = _xFilterClient->GetConfigInfo( &_configInfo );
if ( FAILED(sc) )
{
ciDebugOut(( DEB_ERROR, "GetConfigInfo failed. Error 0x%X\n", sc ));
THROW( CException(sc) );
}
//
//
//
if ( 0 == buf )
{
_cbMax = _params.GetFilterBufferSize() * 1024;
_entryBuffer = (BYTE *)VirtualAlloc(
0, // Requested position.
_cbMax, // Size (in bytes)
MEM_COMMIT, // We want it now.
PAGE_READWRITE ); // Full access, please.
_fOwned = TRUE;
}
_docBuffer = (BYTE *)(CPageManager::GetPage());
_cbTotal = PAGE_SIZE;
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::~CFilterDaemon, public
//
// History: 17-May-93 AmyA Created.
//
//----------------------------------------------------------------------------
CFilterDaemon::~CFilterDaemon()
{
if ( _fOwned )
VirtualFree( _entryBuffer, 0, MEM_RELEASE );
CPageManager::FreePage( _docBuffer );
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::DoUpdates, private
//
// Synopsis: Filters Documents and creates word lists
//
// History: 18-Apr-93 AmyA Created
//
// Notes: This interface is exported across query.DLL, and hence can not
// throw an exception. If this routine ever returns, it is
// the result of an error.
//
//----------------------------------------------------------------------------
SCODE CFilterDaemon::DoUpdates()
{
SCODE scode = STATUS_SUCCESS;
TRY
{
ULONG cLoops = 0;
while (STATUS_SUCCESS == scode)
{
cLoops++;
// Trim our working set every n docs
if ( 20 == cLoops )
{
SetProcessWorkingSetSize( GetCurrentProcess(), -1, -1 );
cLoops = 0;
}
ULONG cbNeeded = _cbTotal;
_cbHdr = sizeof(ULONG);
Win4Assert( _cbTotal > _cbHdr );
_cbDocBuffer = _cbTotal-_cbHdr;
{
CLock lock( _mutex );
if ( _fStopFilter )
{
ciDebugOut(( DEB_ITRACE, "Quitting filtering\n" ));
return STATUS_REQUEST_ABORTED;
}
else
_fWaitingForDocument = TRUE;
}
scode = _proxy.FilterReady( _docBuffer, cbNeeded,
CI_MAX_DOCS_IN_WORDLIST );
while ( STATUS_SUCCESS == scode && cbNeeded > _cbTotal )
{
// need more memory
CPageManager::FreePage( _docBuffer );
unsigned ccPages = cbNeeded / PAGE_SIZE;
if ( ccPages * PAGE_SIZE < cbNeeded )
{
ccPages++;
}
_docBuffer = (BYTE *)(CPageManager::GetPage( ccPages ));
_cbTotal = cbNeeded = ccPages * PAGE_SIZE;
scode = _proxy.FilterReady( _docBuffer, cbNeeded,
CI_MAX_DOCS_IN_WORDLIST );
}
{
CLock lock( _mutex );
if ( _fStopFilter )
{
ciDebugOut(( DEB_ITRACE, "Quitting filtering\n" ));
return STATUS_REQUEST_ABORTED;
}
else
_fWaitingForDocument = FALSE;
}
if ( NT_SUCCESS( scode ) && (_cbTotal > _cbHdr) )
{
_cbDocBuffer = _cbTotal-_cbHdr;
//
// SLM_HACK
//
//
// If the number of remaining documents (after this
// doc buffer) is less than a threshold value,
// then wait for some time before continuing
//
ULONG cDocsLeft;
RtlCopyMemory( &cDocsLeft, _docBuffer, sizeof(ULONG) );
if ( cDocsLeft < _params.GetFilterRemainingThreshold() )
{
ciDebugOut(( DEB_ITRACE,
"CiFilterDaemon. Number of Docs Left %d < %d. Sleep %d s.\n",
cDocsLeft,
_params.GetFilterRemainingThreshold(),
_params.GetFilterDelayInterval() ));
Sleep(_params.GetFilterDelayInterval()*1000);
}
FilterDocs();
}
}
}
CATCH (CException, e)
{
scode = e.GetErrorCode();
}
END_CATCH
return scode;
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::FilterDataReady, public
//
// Synopsis: Sends a buffer to be added to the current word list
//
// Arguments:
// [pEntryBuf] -- pointer to the entry buffer
// [cb] -- count of bytes in the buffer
//
// History: 31-Mar-93 AmyA Created.
//
//----------------------------------------------------------------------------
SCODE CFilterDaemon::FilterDataReady ( const BYTE * pEntryBuf, ULONG cb )
{
return _proxy.FilterDataReady ( pEntryBuf, cb );
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::StopFiltering
//
// History: 12-Sep-93 SitaramR Created.
//
//----------------------------------------------------------------------------
VOID CFilterDaemon::StopFiltering()
{
CLock lock( _mutex );
_fStopFilter = TRUE;
}
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::IsWaitingForDocument
//
// Returns: Whether we are waiting for documents to update
//
// History: 12-Sep-93 SitaramR Created.
//
//----------------------------------------------------------------------------
BOOL CFilterDaemon::IsWaitingForDocument()
{
CLock lock( _mutex );
return _fWaitingForDocument;
}
//+---------------------------------------------------------------------------
//
// Class: CFilterDocument
//
// Purpose: A class to filter a document by retrying different impersonation
// contexts if necessary.
//
// History: 7-18-96 srikants Created
//
//----------------------------------------------------------------------------
class CFilterDocument
{
public:
CFilterDocument( CDataRepository & drep,
CFilterDaemon & fDaemon,
CCiFrameworkParams & params,
CI_CLIENT_FILTER_CONFIG_INFO const & configInfo,
STATUS * aStatus,
ULONG iDoc,
CNonStoredProps & NonStoredProps,
ULONG cbBuf )
: _drep(drep),
_fDaemon(fDaemon),
_params(params),
_configInfo(configInfo),
_aStatus(aStatus),
_iDoc(iDoc),
_NonStoredProps( NonStoredProps ),
_cbBuf( cbBuf )
{
}
ULONG DoIt();
private:
CDataRepository & _drep;
CFilterDaemon & _fDaemon;
CCiFrameworkParams & _params;
CI_CLIENT_FILTER_CONFIG_INFO const & _configInfo;
STATUS * _aStatus;
ULONG _iDoc;
CNonStoredProps & _NonStoredProps;
ULONG _cbBuf;
};
//+---------------------------------------------------------------------------
//
// Member: CFilterDocument::DoIt
//
// Synopsis: Tries to filter the file in the current impersonation context.
//
// Returns: Count of bytes filtered.
//
// History: 7-18-96 srikants Created
//
//----------------------------------------------------------------------------
ULONG CFilterDocument::DoIt()
{
CFilterDriver filterDriver ( &_drep,
_fDaemon._xAdviseStatus.GetPointer( ),
_fDaemon._xFilterClient.GetPointer( ),
_params,
_configInfo,
_fDaemon._cFilteredBlocks,
_NonStoredProps,
_cbBuf );
if ( _fDaemon._fStopFilter )
{
ciDebugOut(( DEB_ITRACE, "Aborting filtering\n" ));
THROW( CException(STATUS_TOO_LATE) );
}
_aStatus[_iDoc] = filterDriver.FillEntryBuffer( _fDaemon._pbCurrentDocument,
_fDaemon._cbCurrentDocument );
// In case we filtered a monster file, just round down to 4 gig.
if ( 0 != filterDriver.GetFileSize().HighPart )
return 0xffffffff;
return filterDriver.GetFileSize().LowPart;
} //DoIt
//+---------------------------------------------------------------------------
//
// Member: CFilterDaemon::FilterDocs, private
//
// Synopsis: Creates a Filter Driver and filters documents in _docBuffer
//
// History: 21-Apr-93 AmyA Created.
// 05-Nov-93 DwightKr Removed PROP_ALL code - we'll determine
// what to filter after opening the object
//
//----------------------------------------------------------------------------
void CFilterDaemon::FilterDocs()
{
ciAssert ( _docBuffer != 0 );
ciDebugOut (( DEB_ITRACE, "CFilterDaemon::FilterDocs\n" ));
CEntryBufferHandler entryBufHandler ( _cbMax,
_entryBuffer,
*this,
_proxy,
_pidmap );
// STACK: this is a big object.
CIndexKeyRepository krep( entryBufHandler );
CDataRepository drep( krep, 0, FALSE, 0, _pidmap, _LangList );
STATUS aStatus [CI_MAX_DOCS_IN_WORDLIST];
for( unsigned i=0; i<CI_MAX_DOCS_IN_WORDLIST; i++ ) // set array
aStatus[i] = WL_IGNORE;
unsigned iDoc;
CDocBufferIter iter(_docBuffer+_cbHdr, _cbTotal-_cbHdr);
while ( !iter.AtEnd() )
{
_pbCurrentDocument = iter.GetCurrent(iDoc, _cbCurrentDocument);
iter.Next();
Win4Assert (iDoc < CI_MAX_DOCS_IN_WORDLIST );
ciDebugOut((DEB_ITRACE, "\t%2d 0x%X\n",
iDocToFakeWid(iDoc), _pbCurrentDocument ));
drep.PutWorkId ( iDocToFakeWid(iDoc) );
_cFilteredDocuments++;
_cFilteredBlocks = 0;
if ( 0 == _cbCurrentDocument )
{
// This represents a deleted document.
ciDebugOut(( DEB_IWARN, "Null document name 0x%x\n", _pbCurrentDocument ));
aStatus[iDoc] = SUCCESS;
continue;
}
BOOL fTookException = FALSE;
CFwPerfTime filterTotalCounter( _xAdviseStatus.GetPointer(),
CI_PERF_FILTER_TIME_TOTAL,
1024*1024, 1000*60*60 );
ULONG cbLow = 0;
TRY
{
//
// Filter time in Mb / hr
//
filterTotalCounter.TStart();
if ( !_xFilterStatus.IsNull() )
{
SCODE sc = _xFilterStatus->PreFilter( _pbCurrentDocument, _cbCurrentDocument );
if ( FAILED(sc) )
{
ciDebugOut(( DEB_WARN, "Failing filtering because PreFilter returned 0x%x\n", sc ));
THROW( CException( sc ) );
}
}
//
// If necessary impersonate for accessing this file
//
CFilterDocument filterDocument( drep,
*this,
_params,
_configInfo,
aStatus,
iDoc,
_NonStoredProps,
_cbMax );
cbLow = filterDocument.DoIt();
}
CATCH ( CException, e )
{
fTookException = TRUE;
ciDebugOut(( DEB_ITRACE,
"FilterDriver exception 0x%x filtering %d caught in FilterDocs.\n",
e.GetErrorCode(), iDoc ));
if ( !_xFilterStatus.IsNull() )
_xFilterStatus->PostFilter( _pbCurrentDocument,
_cbCurrentDocument,
e.GetErrorCode() );
if ( IsSharingViolation( e.GetErrorCode()) )
{
aStatus[iDoc] = CI_SHARING_VIOLATION;
}
else if ( IsNetDisconnect( e.GetErrorCode()) ||
CI_NOT_REACHABLE == e.GetErrorCode() )
{
aStatus[iDoc] = CI_NOT_REACHABLE;
}
else
{
aStatus[iDoc] = FILTER_EXCEPTION;
}
//
// Certain errors occuring while filtering are fatal. They
// will cause the filter daemon to terminate.
if ( (e.GetErrorCode() == FDAEMON_E_FATALERROR) ||
(e.GetErrorCode() == STATUS_ACCESS_VIOLATION) ||
(e.GetErrorCode() == STATUS_NO_MEMORY) ||
(e.GetErrorCode() == STATUS_INSUFFICIENT_RESOURCES) ||
(e.GetErrorCode() == STATUS_DATATYPE_MISALIGNMENT) ||
(e.GetErrorCode() == STATUS_INSTRUCTION_MISALIGNMENT)
)
{
RETHROW();
}
}
END_CATCH
if ( !_xFilterStatus.IsNull() && !fTookException )
_xFilterStatus->PostFilter( _pbCurrentDocument,
_cbCurrentDocument,
S_OK );
filterTotalCounter.TStop( cbLow );
if ( entryBufHandler.WordListFull() ) // finish current word list
{
//
// Does not throw
//
entryBufHandler.Done();
#if CIDBG == 1
for (unsigned j=0; j<CI_MAX_DOCS_IN_WORDLIST; j++)
{
DebugPrintStatus( aStatus[j] );
}
#endif // CIDBG == 1
//
// If we have filled the buffer, and there are no more documents
// to filter then don't call FilterMore. Exit the loop so that
// FilterDone can be called to finish this docList.
//
if ( iter.AtEnd() )
break;
SCODE scode = _proxy.FilterMore( aStatus, CI_MAX_DOCS_IN_WORDLIST );
if ( FAILED(scode) )
{
ciDebugOut (( DEB_IERROR, "FilterMore returned with error 0x%x\n", scode ));
THROW( CException( scode ) );
}
for( unsigned i = 0; i <= iDoc; i++ ) // reset array
aStatus[i] = WL_IGNORE;
entryBufHandler.Init();
}
} // end of for loop
_pbCurrentDocument = 0;
_cbCurrentDocument = 0;
//
// Does not throw
//
entryBufHandler.Done();
#if CIDBG == 1
for (i = 0; i < CI_MAX_DOCS_IN_WORDLIST; i++)
{
DebugPrintStatus(aStatus[i]);
}
#endif // CIDBG == 1
if ( iter.GetCount() > 0 )
{
SCODE scode = _proxy.FilterDone( aStatus, CI_MAX_DOCS_IN_WORDLIST );
if ( FAILED( scode ) )
{
ciDebugOut (( DEB_IERROR, "FilterDone returned with error 0x%x\n", scode ));
THROW( CException( scode ) );
}
}
}
//+---------------------------------------------------------------------------
//
// Method: CNonStoredProps::Add
//
// Synopsis: Adds the property to the list of properties that shouldn't
// be stored.
//
// Arguments: [ps] -- Property ID
//
// History: 9-Feb-97 dlee Created.
//
//----------------------------------------------------------------------------
void CNonStoredProps::Add( CFullPropSpec const & ps )
{
if ( ( guidStorage == ps.GetPropSet() ) &&
( ps.IsPropertyPropid() ) &&
( ps.GetPropertyPropid() < CSTORAGEPROPERTY ) )
{
Win4Assert( ps.GetPropertyPropid() != PID_STG_SIZE );
_afStgPropNonStored[ ps.GetPropertyPropid() ] = TRUE;
}
else if ( guidHtmlMeta == ps.GetPropSet() )
{
if ( _cMetaSpecs < maxCachedSpecs )
_aMetaSpecs[ _cMetaSpecs++ ] = ps;
}
else
{
if ( _cSpecs < maxCachedSpecs )
_aSpecs[ _cSpecs++ ] = ps;
}
} //Add
//+---------------------------------------------------------------------------
//
// Method: CNonStoredProps::IsNonStored
//
// Synopsis: Returns TRUE if the property shouldn't be stored
//
// Arguments: [ps] -- Property ID
//
// History: 9-Feb-97 dlee Created.
//
//----------------------------------------------------------------------------
BOOL CNonStoredProps::IsNonStored( CFullPropSpec const & ps )
{
if ( ( guidStorage == ps.GetPropSet() ) &&
( ps.IsPropertyPropid() ) &&
( ps.GetPropertyPropid() < CSTORAGEPROPERTY ) )
{
return _afStgPropNonStored[ ps.GetPropertyPropid() ];
}
else if ( guidHtmlMeta == ps.GetPropSet() )
{
for ( int x = 0; x < _cMetaSpecs; x++ )
if ( ps == _aMetaSpecs[ x ] )
return TRUE;
}
else
{
for ( int x = 0; x < _cSpecs; x++ )
if ( ps == _aSpecs[ x ] )
return TRUE;
}
return FALSE;
} //IsNonStored
#if CIDBG == 1
void DebugPrintStatus( STATUS stat )
{
switch(stat)
{
case SUCCESS:
// ciDebugOut((DEB_ITRACE, "Status: SUCCESS\n"));
break;
case PREEMPTED:
ciDebugOut((DEB_ITRACE, "Status: PREEMPTED\n"));
break;
case BIND_FAILED:
ciDebugOut((DEB_ITRACE, "Status: BIND_FAILED\n"));
break;
case CORRUPT_OBJECT:
ciDebugOut((DEB_ITRACE, "Status: CORRUPT_OBJECT\n"));
break;
case MISSING_PROTOCOL:
ciDebugOut((DEB_ITRACE, "Status: MISSING_PROTOCOL\n"));
break;
case CANNOT_OPEN_STREAM:
ciDebugOut((DEB_ITRACE, "Status: CANNOT_OPEN_STREAM\n"));
break;
case DELETED:
ciDebugOut((DEB_ITRACE, "Status: DELETED\n"));
break;
case ENCRYPTED:
ciDebugOut((DEB_ITRACE, "Status: ENCRYPTED\n"));
break;
case FILTER_EXCEPTION:
ciDebugOut((DEB_ITRACE, "Status: FILTER_EXCEPTION\n"));
break;
case OUT_OF_MEMORY:
ciDebugOut((DEB_ITRACE, "Status: OUT_OF_MEMORY\n"));
break;
case PENDING:
ciDebugOut((DEB_ITRACE, "Status: PENDING\n"));
break;
case WL_IGNORE:
// ciDebugOut((DEB_ITRACE, "Status: WL_IGNORE\n"));
break;
case WL_NULL:
// ciDebugOut((DEB_ITRACE, "Status: WL_NULL\n"));
break;
case CI_SHARING_VIOLATION:
ciDebugOut(( DEB_ITRACE, "Status: CI_SHARING_VIOLATION\n" ));
break;
case CI_NOT_REACHABLE:
ciDebugOut(( DEB_ITRACE, "Status: CI_NOT_REACHABLE\n" ));
break;
default:
ciDebugOut((DEB_ITRACE, "This status is incorrect\n"));
break;
}
}
#endif // CIDBG == 1