windows-nt/Source/XPSP1/NT/inetsrv/query/fsci/indexing/dslookup.cxx
2020-09-26 16:20:57 +08:00

779 lines
26 KiB
C++

//+---------------------------------------------------------------------------
//
// Microsoft Windows
// Copyright (C) Microsoft Corporation, 1992 - 1999.
//
// File: dslookup.cxx
//
// Contents: DocStoreLookUp code
//
// Classes: CClientDocStoreLocator
//
// History: 1-16-97 srikants Created
//
//----------------------------------------------------------------------------
#include <pch.cxx>
#pragma hdrstop
// for definition of CRequestQueue
#include <query.hxx>
#include <srequest.hxx>
#include <dslookup.hxx>
#include <dbprputl.hxx>
#include <catarray.hxx>
#include <docstore.hxx>
#include <imprsnat.hxx>
#include <lang.hxx>
#include <ciole.hxx>
#include <fsci.hxx>
#include <acinotfy.hxx>
#include <cicat.hxx>
#include <regacc.hxx>
#include <ciregkey.hxx>
#include <drvnotif.hxx>
#include <driveinf.hxx>
#include <regscp.hxx>
#include <catreg.hxx>
#include <removcat.hxx>
extern CCatArray Catalogs;
extern void OpenCatalogsInRegistry( BOOL fOpenForReadyOnly = FALSE );
//+---------------------------------------------------------------------------
//
// Member: CClientDocStore::QueryInterface
//
// Synopsis: Supports IID_IUnknown
// IID_ICiCDocStoreLocator
//
// History: 12-03-96 srikants Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::QueryInterface(
REFIID riid,
void **ppvObject)
{
Win4Assert( 0 != ppvObject );
if ( IID_ICiCDocStoreLocator == riid )
*ppvObject = (void *)((ICiCDocStoreLocator *)this);
else if ( IID_IUnknown == riid )
*ppvObject = (void *)((IUnknown *) (ICiCDocStore *)this);
else
{
*ppvObject = 0;
return E_NOINTERFACE;
}
AddRef();
return S_OK;
} //QueryInterface
//+---------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::AddRef
//
// History: 12-03-96 srikants Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CClientDocStoreLocator::AddRef()
{
return InterlockedIncrement(&_refCount);
} //AddRef
//+---------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::Release
//
// History: 12-03-96 srikants Created
//
//----------------------------------------------------------------------------
STDMETHODIMP_(ULONG) CClientDocStoreLocator::Release()
{
Win4Assert( _refCount > 0 );
ciDebugOut(( DEB_ITRACE, "DocStoreLocator::Release.. _refCount == %d\n", _refCount ));
LONG refCount = InterlockedDecrement(&_refCount);
if ( refCount <= 0 )
delete this;
return refCount;
} //Release
//+---------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::LookUpDocStore
//
// Synopsis: Locates the docStore that is specified in the db properties
// and returns its pointer (if located).
//
// Arguments: [pIDBProperties] -
// [ppICiCDocStore] -
// [fMustAlreadyExist] -- If TRUE, the docstore must already
// be opened, or the call fails.
//
// Returns: S_OK if found;
// CI_E_DOCSTORE_NOT_FOUND if not located.
//
// History: 1-16-97 srikants Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::LookUpDocStore(
IDBProperties * pIDBProperties,
ICiCDocStore ** ppICiCDocStore,
BOOL fMustAlreadyExist )
{
SCODE sc = S_OK;
TRY
{
CGetDbProps connectProps;
connectProps.GetProperties( pIDBProperties,
CGetDbProps::eCatalog|
CGetDbProps::eScopesAndDepths );
// if a catalog was passed (as a guess or actual), try to open it
WCHAR const * pwcCatalog = connectProps.GetCatalog();
//
// Prevent a hacker from passing a bogus path name -- we trash
// stack and/or AV in this circumstance!
//
if ( 0 == pwcCatalog )
THROW( CException( CI_E_NOT_FOUND ) );
unsigned cwc = wcslen( pwcCatalog );
if ( ( 0 == cwc ) || ( cwc >= ( MAX_PATH - 1 ) ) )
THROW( CException( CI_E_NOT_FOUND ) );
CClientDocStore * pDocStore = 0;
if ( 0 != pwcCatalog )
pDocStore = Catalogs.GetDocStore( pwcCatalog, fMustAlreadyExist );
if ( 0 != pDocStore )
{
sc = pDocStore->QueryInterface( IID_ICiCDocStore,
(void **) ppICiCDocStore );
}
else
{
// special case: adminstration connection without a docstore associated
if ( !wcscmp(CIADMIN, pwcCatalog) )
{
ciDebugOut(( DEB_ITRACE,
"CClientDocStoreLocator::LookUpDocStore.. ADMINSTRATION connection is requested\n" ));
sc = CI_S_NO_DOCSTORE;
}
else
sc = CI_E_NOT_FOUND;
}
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //LookUpDocStore
//+---------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::Shutdown
//
// Synopsis: Shuts down the content index by closing all open catalogs.
//
// History: 1-29-97 srikants Created
//
//----------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::Shutdown()
{
ciDebugOut(( DEB_ITRACE, "DocStoreLocator::Shutdown is called\n" ));
return FsCiShutdown();
}
//+---------------------------------------------------------------------------
//
// Function: FsCiShutdown
//
// Synopsis: Does shutdown processing for the FsCi component.
//
// History: 2-27-97 srikants Created
//
//----------------------------------------------------------------------------
SCODE FsCiShutdown()
{
SCODE sc = S_OK;
TRY
{
Catalogs.Flush();
CCiOle::Shutdown();
g_LogonList.Empty();
TheFrameworkClientWorkQueue.Shutdown();
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
// If this assert hits, we took an exception while releasing
// resources, which isn't allowed to happen. It's a bug elsewhere.
Win4Assert( !"FsCiShutdown failed, and it isn't allowed to" );
}
END_CATCH
return sc;
} //FsCiShutdown
//+-------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::OpenAllDocStores
//
// Synopsis: Opens all the catalogs in the registry
//
// History: 06-May-98 kitmanh Created.
//
//--------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::OpenAllDocStores()
{
SCODE sc = S_OK;
TRY
{
OpenCatalogsInRegistry();
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //OpenAllDocStores
//+-------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::GetDocStoreState
//
// Synopsis: Gets the state of a docstore
// (used when restarting a stopped catalog) or the directory is
// unwritable
//
// Arguments: [pwcDocStore] -- Name of the catalog
// [ppICiDocStore] -- Returns the docstore
// [pdwState] -- Returns the state
//
// History: 06-May-98 kitmanh Created.
//
//--------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::GetDocStoreState(
WCHAR const * pwcDocStore,
ICiCDocStore ** ppICiCDocStore,
DWORD * pdwState )
{
SCODE sc = S_OK;
TRY
{
if ( Catalogs.IsCatStopped( pwcDocStore ) )
{
*pdwState = CICAT_STOPPED;
sc = CI_S_CAT_STOPPED;
return sc;
}
CClientDocStore * pDocStore = 0;
if ( 0 != pwcDocStore )
pDocStore = Catalogs.GetDocStore( pwcDocStore );
if ( 0 != pDocStore )
{
Win4Assert( pDocStore );
// get the interface
sc = pDocStore->QueryInterface( IID_ICiCDocStore,
(void **) ppICiCDocStore );
// get the oldstate and flag
CiCat * pCiCat = pDocStore->GetCiCat();
// Is this the null catalog?
if ( 0 == pCiCat )
THROW( CException( CI_E_NOT_FOUND ) );
if ( pCiCat->IsReadOnly() )
{
ciDebugOut(( DEB_ITRACE, "CClientDocStoreLocator::GetDocStoreState.. CiCatReadOnly == %d\n",
pCiCat->IsReadOnly() ));
*pdwState = CICAT_READONLY;
}
else
*pdwState = CICAT_WRITABLE;
BOOL fNoQuery;
pDocStore->IsNoQuery( &fNoQuery );
if ( fNoQuery )
*pdwState |= CICAT_NO_QUERY;
}
else
sc = CI_E_NOT_FOUND; //or some other error?
}
CATCH( CException, e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //GetDocStoreState
BOOL IsDirectoryWritable( WCHAR const * pwcPath );
//+-------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::IsMarkedReadOnly
//
// Synopsis: Check if the catalog is marked for readonly in the registry
// (used when restarting a stopped catalog) or the directory is
// unwritable
//
// Arguments: [wcsCat] -- Name of the catalog
// [pfReadOnly] -- output
//
// History: 06-May-98 kitmanh Created.
//
//--------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::IsMarkedReadOnly( WCHAR const * wcsCat, BOOL * pfReadOnly )
{
SCODE sc = S_OK;
TRY
{
unsigned cwcNeeded = wcslen( wcsRegJustCatalogsSubKey );
cwcNeeded += 2; // "\\" + null termination
cwcNeeded += wcslen( wcsCat );
XArray<WCHAR> xKey( cwcNeeded );
wcscpy( xKey.Get(), wcsRegJustCatalogsSubKey );
wcscat( xKey.Get(), L"\\" );
wcscat( xKey.Get(), wcsCat );
CRegAccess reg( RTL_REGISTRY_CONTROL, xKey.Get() );
BOOL fReadOnly = FALSE;
*pfReadOnly = reg.Read(wcsIsReadOnly, fReadOnly );
ciDebugOut(( DEB_ITRACE, "IsMarkedReadOnly is %d\n", *pfReadOnly ));
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //IsMarkedReadOnly
//+-------------------------------------------------------------------------
//
// Member: IsVolumeOrDirRO
//
// Synopsis: Check if the volume and the directory are unwritable
//
// Arguments: [wcsCat] -- Name of the catalog
// [pfReadOnly] -- output
//
// History: 07-May-98 kitmanh Created.
//
//--------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::IsVolumeOrDirRO( WCHAR const * wcsCat,
BOOL * pfReadOnly )
{
SCODE sc = S_OK;
*pfReadOnly = FALSE;
TRY
{
WCHAR wcsKey[MAX_PATH];
wcscpy( wcsKey, wcsRegCatalogsSubKey );
wcscat( wcsKey, L"\\" );
unsigned cwc = wcslen( wcsKey ) + wcslen( wcsCat );
if ( cwc >= MAX_PATH )
THROW( CException( E_INVALIDARG ) );
wcscat( wcsKey, wcsCat );
HKEY hKey;
if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
wcsKey,
0,
KEY_QUERY_VALUE,
&hKey ) )
{
SRegKey xKey( hKey );
WCHAR awcPath[MAX_PATH];
DWORD cbPath = sizeof awcPath;
if ( ERROR_SUCCESS == RegQueryValueEx( hKey,
wcsCatalogLocation,
0,
0,
(BYTE *)awcPath,
&cbPath ) )
{
CDriveInfo driveInfo ( awcPath, 0 );
wcscat( awcPath, L"Catalog.wci" ); //is there a constant for this?
ciDebugOut(( DEB_ITRACE, "IsVolumeOrDirRO.. awcPath == %ws\n", awcPath ));
ciDebugOut(( DEB_ITRACE, "Volume Writeprotected is %d\n", driveInfo.IsWriteProtected() ));
ciDebugOut(( DEB_ITRACE, "Diretory Writable is %d\n", IsDirectoryWritable( awcPath ) ));
*pfReadOnly = ( driveInfo.IsWriteProtected() || !( IsDirectoryWritable( awcPath ) ) );
}
}
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //IsVolumeOrDirRO
//+---------------------------------------------------------------------------
//
// Member: StopCatalogsOnVol
//
// Synopsis: Stops all catalogs on the volume specified.
//
// Arguments: [wcVol] -- Volume letter
// [pRequestQ] -- Pointer to the RequestQueue
//
// History: 07-05-98 kitmanh Created
// 07-20-98 kitmanh Stop the catalogs with scopes on
// volume being locked too
//
//----------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::StopCatalogsOnVol( WCHAR wcVol,
void * pRequestQ )
{
ciDebugOut(( DEB_ITRACE, "StopCatalogsOnVol %wc\n", wcVol ));
//enumerate reg to find out who needs to stop
//add a workitem for all of them
ciDebugOut(( DEB_ITRACE, "StopCatalogsOnVol is called\n" ));
Win4Assert( 0 != pRequestQ );
CRequestQueue * pRequestQueue = (CRequestQueue *)pRequestQ;
SCWorkItem newItem;
HKEY hKey;
SCODE sc = S_OK;
BOOL fFiledWorkItem = FALSE;
TRY
{
if ( ERROR_SUCCESS == RegOpenKeyEx( HKEY_LOCAL_MACHINE,
wcsRegCatalogsSubKey,
0,
KEY_QUERY_VALUE |
KEY_ENUMERATE_SUB_KEYS,
&hKey ) )
{
SRegKey xKey( hKey );
DWORD iSubKey = 0;
do
{
FILETIME ft;
WCHAR awcName[MAX_PATH];
DWORD cwcName = sizeof awcName / sizeof WCHAR;
LONG err = RegEnumKeyEx( hKey,
iSubKey,
awcName,
&cwcName,
0, 0, 0, &ft );
// either error or end of enumeration
if ( ERROR_SUCCESS != err )
break;
iSubKey++;
HKEY hCatName;
if ( ERROR_SUCCESS == RegOpenKeyEx( hKey,
awcName,
0,
KEY_QUERY_VALUE,
&hCatName ) )
{
// enumerate the location registries
SRegKey xCatNameKey( hCatName );
// Check if the catalog is inactive and can be ignored
WCHAR awcKey[MAX_PATH];
wcscpy( awcKey, wcsRegJustCatalogsSubKey );
wcscat( awcKey, L"\\" );
unsigned cwc = wcslen( awcKey ) + wcslen( awcName );
if ( cwc >= MAX_PATH )
THROW( CException( E_INVALIDARG ) );
wcscat( awcKey, awcName );
CRegAccess reg( RTL_REGISTRY_CONTROL, awcKey );
BOOL fInactive = reg.Read( wcsCatalogInactive,
CI_CATALOG_INACTIVE_DEFAULT );
BOOL fIsAutoMount = reg.Read( wcsIsRemovableCatalog, (ULONG) FALSE );
if ( !fInactive )
{
WCHAR awcPath[MAX_PATH];
DWORD cbPath = sizeof awcPath;
if ( ERROR_SUCCESS == RegQueryValueEx( hCatName,
wcsCatalogLocation,
0,
0,
(BYTE *)awcPath,
&cbPath ) )
{
if ( toupper(awcPath[0]) == toupper(wcVol) )
{
//check old state of docstore
DWORD dwOldState;
XInterface<ICiCDocStore> xDocStore;
sc = GetDocStoreState( awcName,
xDocStore.GetPPointer(),
&dwOldState );
if ( SUCCEEDED(sc) )
{
ciDebugOut(( DEB_ITRACE, "StopCatalogsOnVol: dwOldState is %d for catalog %ws\n",
dwOldState, awcName ));
if ( 0 == (CICAT_STOPPED & dwOldState) )
{
ciDebugOut(( DEB_ITRACE, "CATALOG %ws WAS NOT STOPPED BEFORE\n", awcName ));
ciDebugOut(( DEB_ITRACE, "Add old state %d\n", dwOldState ));
if ( !fIsAutoMount )
Catalogs.AddStoppedCat( dwOldState, awcName, wcVol );
newItem.type = eStopCat;
newItem.pDocStore = xDocStore.GetPointer();
pRequestQueue->AddSCItem( &newItem , 0 );
fFiledWorkItem = TRUE;
}
else
{
ciDebugOut(( DEB_ITRACE, "CATALOG %ws WAS STOPPED BEFORE\n", awcName ));
BOOL fSucceeded = Catalogs.IncStopCount( awcName, wcVol );
Win4Assert( fSucceeded );
}
}
}
else // enumerate the scopes to see if this catalog needs to stop
{
unsigned cwcNeeded = wcslen( wcsRegJustCatalogsSubKey );
cwcNeeded += 3; // "\\" x 2 + null termination
cwcNeeded += wcslen( awcName );
cwcNeeded += wcslen( wcsCatalogScopes );
XArray<WCHAR> xKey( cwcNeeded );
wcscpy( xKey.Get(), wcsRegJustCatalogsSubKey );
wcscat( xKey.Get(), L"\\" );
wcscat( xKey.Get(), awcName );
wcscat( xKey.Get(), L"\\" );
wcscat( xKey.Get(), wcsCatalogScopes );
CRegAccess regScopes( RTL_REGISTRY_CONTROL, xKey.Get() );
CRegistryScopesCallBackToDismount callback( wcVol );
regScopes.EnumerateValues( 0, callback );
if ( callback.WasFound() )
{
//check old state of docstore
DWORD dwOldState;
XInterface<ICiCDocStore> xDocStore;
sc = GetDocStoreState( awcName,
xDocStore.GetPPointer(),
&dwOldState );
if ( SUCCEEDED(sc) )
{
if ( 0 == (CICAT_STOPPED & dwOldState) )
{
ciDebugOut(( DEB_ITRACE, "CATALOG %ws WAS NOT STOPPED BEFORE\n", awcName ));
ciDebugOut(( DEB_ITRACE, "Creating an SCItem\n" ));
if ( !fIsAutoMount )
Catalogs.AddStoppedCat( dwOldState, awcName, wcVol );
newItem.type = eStopCat;
newItem.pDocStore = xDocStore.GetPointer();
pRequestQueue->AddSCItem( &newItem , 0 );
fFiledWorkItem = TRUE;
}
else
{
ciDebugOut(( DEB_ITRACE, "CATALOG %ws WAS STOPPED BEFORE\n", awcName ));
BOOL fSucceeded = Catalogs.IncStopCount( awcName, wcVol );
Win4Assert( fSucceeded );
}
}
}
}
}
}
}
} while ( TRUE );
}
//
// If we filed a workitem to close a temporary catalog, delete
// its registry entries.
//
if ( fFiledWorkItem )
{
//
// If this is an auto-mount catalog, delete the temporary
// registry entries.
//
if ( IsRemovableDrive( wcVol ) )
{
CRemovableCatalog cat( wcVol );
cat.Destroy();
}
}
else
{
ciDebugOut(( DEB_ITRACE, "no catalogs to stop on %wc\n", wcVol ));
//
// File a fake work item so we don't force closeed connections on
// all docstores. Otherwise queries will be aborted for no
// reason.
//
newItem.type = eNoCatWork;
newItem.pDocStore = (ICiCDocStore*)(~0);
pRequestQueue->AddSCItem( &newItem , 0 );
}
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //StopCatalogsOnVol
//+---------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::StartCatalogsOnVol
//
// Synopsis: Restore all catalogs on the volume specified to its previous
// state before the volume was locked.
//
// Arguments: [wcVol] -- Volume letter
// [pRequestQ] -- Pointer to the RequestQueue
//
// History: 07-07-98 kitmanh Created
// 07-23-98 kitmanh Restores catalogs from StoppedArray,
// instead of enumerating registry
// 09-03-98 kitmanh Delegated the work to CatArray
//
//----------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::StartCatalogsOnVol( WCHAR wcVol,
void * pRequestQ )
{
Win4Assert( 0 != pRequestQ );
CRequestQueue * pRequestQueue = (CRequestQueue *)pRequestQ;
SCODE sc = S_OK;
TRY
{
Catalogs.StartCatalogsOnVol( wcVol, pRequestQueue );
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //StartCatalogsOnVol
//+-------------------------------------------------------------------------
//
// Member: CClientDocStoreLocator::AddStoppedCat, public
//
// Synopsis: Add an item of COldCatState into the _aStopCatalogs array
//
// Arguments: [dwOldState] -- Old state of a docstore
// [wcsCatName] -- Catalog name of the docstore
//
// History: 16-July-98 KitmanH Created
//
//--------------------------------------------------------------------------
STDMETHODIMP CClientDocStoreLocator::AddStoppedCat( DWORD dwOldState,
WCHAR const * wcsCatName )
{
SCODE sc = S_OK;
TRY
{
Catalogs.AddStoppedCat( dwOldState, wcsCatName, 0 );
}
CATCH( CException,e )
{
sc = e.GetErrorCode();
}
END_CATCH
return sc;
} //AddStoppedCat