1714 lines
50 KiB
C++
1714 lines
50 KiB
C++
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 1999.
|
|
//
|
|
// File: scopetbl.cxx
|
|
//
|
|
// Contents: Persistent scope table
|
|
//
|
|
// History: 14-Jul-97 SitaramR Created from dlnotify.cxx
|
|
//
|
|
// Notes : For lock hierarchy and order of acquiring locks, please see
|
|
// cicat.cxx
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
#include <pch.cxx>
|
|
#pragma hdrstop
|
|
|
|
#include <ciregkey.hxx>
|
|
#include <cistore.hxx>
|
|
#include <rcstxact.hxx>
|
|
#include <imprsnat.hxx>
|
|
#include <eventlog.hxx>
|
|
|
|
#include <docstore.hxx>
|
|
|
|
#include "cicat.hxx"
|
|
#include "update.hxx"
|
|
#include "notifmgr.hxx"
|
|
#include "scanmgr.hxx"
|
|
#include "scopetbl.hxx"
|
|
|
|
//
|
|
// Local constants
|
|
//
|
|
|
|
WCHAR const wcVirtualShadow = L'3'; // 3 --> Virtual, Indexed
|
|
WCHAR const wcsVirtualShadow[] = L",,3"; // ,,3 --> No UNC alias, Virtual, Indexed
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: DeleteIfShadow, private
|
|
//
|
|
// Synopsis: Deletes shadow scope registry entry
|
|
//
|
|
// Arguments: [pwcsScope] -- Scope to delete
|
|
// [hkey] -- Registry key to catalog
|
|
//
|
|
// History: 15-May-97 KyleP Created
|
|
//
|
|
// Notes: Only deletes exact matches (as stored by system)
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void DeleteIfShadow( WCHAR const * pwcsScope, HKEY hkey )
|
|
{
|
|
//
|
|
// See if this is a shadow entry (flags == 2)
|
|
//
|
|
|
|
WCHAR wcsData[MAX_PATH];
|
|
|
|
DWORD dwType;
|
|
DWORD dwSize = sizeof(wcsData);
|
|
|
|
DWORD dwError = RegQueryValueEx( hkey, // Key handle
|
|
pwcsScope, // Name
|
|
0, // Reserved
|
|
&dwType, // Datatype
|
|
(BYTE *)wcsData, // Data returned here
|
|
&dwSize ); // Size of data
|
|
|
|
if ( ERROR_SUCCESS == dwError &&
|
|
REG_SZ == dwType &&
|
|
dwSize >= 8 && // 8 --> ,,#<null>
|
|
wcVirtualShadow == wcsData[dwSize/sizeof(WCHAR) - 2] )
|
|
{
|
|
dwError = RegDeleteValue( hkey, pwcsScope );
|
|
|
|
if ( ERROR_SUCCESS != dwError ) {
|
|
ciDebugOut(( DEB_ERROR, "Error %d deleting %ws\n", dwError, pwcsScope ));
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: AddShadow, private
|
|
//
|
|
// Synopsis: Adds shadow scope registry entry
|
|
//
|
|
// Arguments: [pwcsScope] -- Scope to add
|
|
// [hkey] -- Registry key to catalog
|
|
//
|
|
// History: 15-May-97 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void AddShadow( WCHAR const * pwcsScope, HKEY hkey )
|
|
{
|
|
//
|
|
// Build string: NAME: ,,3
|
|
//
|
|
|
|
DWORD dwError = RegSetValueEx( hkey, // Key
|
|
pwcsScope, // Value name
|
|
0, // Reserved
|
|
REG_SZ, // Type
|
|
(BYTE *)wcsVirtualShadow, // Data
|
|
sizeof(wcsVirtualShadow) ); // Size (in bytes)
|
|
|
|
if ( ERROR_SUCCESS != dwError ) {
|
|
ciDebugOut(( DEB_ERROR, "Error %d writing %ws\n", dwError, pwcsScope ));
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Method: RefreshIfShadow, private
|
|
//
|
|
// Synopsis: Refresh shadow scope registry entry (if blank)
|
|
//
|
|
// Arguments: [pwcsScope] -- Scope to refresh
|
|
// [hkey] -- Registry key to catalog
|
|
//
|
|
// History: 11-Oct-97 KyleP Created
|
|
//
|
|
// Notes: Only refresh blank (missing) entries
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void RefreshIfShadow( WCHAR const * pwcsScope, HKEY hkey )
|
|
{
|
|
//
|
|
// See if this is a missing entry
|
|
//
|
|
|
|
WCHAR wcsData[MAX_PATH];
|
|
|
|
DWORD dwType;
|
|
DWORD dwSize = sizeof(wcsData);
|
|
|
|
DWORD dwError = RegQueryValueEx( hkey, // Key handle
|
|
pwcsScope, // Name
|
|
0, // Reserved
|
|
&dwType, // Datatype
|
|
(BYTE *)wcsData, // Data returned here
|
|
&dwSize ); // Size of data
|
|
|
|
//
|
|
// It is, so we should re-add it.
|
|
//
|
|
|
|
if ( ERROR_FILE_NOT_FOUND == dwError )
|
|
AddShadow( pwcsScope, hkey );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::~CCiScopeTable
|
|
//
|
|
// Synopsis: ~dtor of the persistent scope table.
|
|
//
|
|
// History: 1-21-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiScopeTable::~CCiScopeTable()
|
|
{
|
|
delete _pTable;
|
|
}
|
|
|
|
void CCiScopeTable::_FatalCorruption()
|
|
{
|
|
PStorage & storage = _cicat.GetStorage();
|
|
Win4Assert( !"Corrupt scope table" );
|
|
storage.ReportCorruptComponent( L"ScopeTable1" );
|
|
|
|
THROW( CException( CI_CORRUPT_CATALOG ) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::Empty
|
|
//
|
|
// Synopsis: Empties out the in-memory contents of the scope table for
|
|
// a later re-init.
|
|
//
|
|
// History: 3-21-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::Empty()
|
|
{
|
|
delete _pTable; _pTable = 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::FastInit
|
|
//
|
|
// Synopsis: Quickly initializes the scope table.
|
|
//
|
|
// History: 3-21-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::FastInit()
|
|
{
|
|
CiStorage * pStorage = (CiStorage *) &_cicat.GetStorage();
|
|
Win4Assert( 0 != pStorage );
|
|
|
|
_pTable = pStorage->QueryScopeList(0);
|
|
|
|
CRcovStorageHdr & storageHdr = _pTable->GetHeader();
|
|
|
|
//
|
|
// read the last scan time.
|
|
//
|
|
storageHdr.GetUserHdr( storageHdr.GetPrimary(), _usrHdr );
|
|
if ( !_hdr.IsInitialized() )
|
|
_hdr.Initialize();
|
|
|
|
if ( _hdr.IsFullScanNeeded() )
|
|
_state = eFullScanNeeded;
|
|
} //FastInit
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Class: CNullAdvise
|
|
//
|
|
// Purpose: Null implementation of ICiCAdviseStatus, for use in opening
|
|
// a CiStorage when advise isn't needed.
|
|
//
|
|
// History: 4-6-99 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
class CNullAdvise : public ICiCAdviseStatus
|
|
{
|
|
public:
|
|
STDMETHOD(QueryInterface)( REFIID riid, LPVOID *ppiuk ) { return E_NOINTERFACE; }
|
|
|
|
|
|
STDMETHOD_(ULONG, AddRef) () { return 1; }
|
|
|
|
STDMETHOD_(ULONG, Release)() { return 0; }
|
|
|
|
STDMETHOD(SetPerfCounterValue)( CI_PERF_COUNTER_NAME name,
|
|
long value ) { return S_OK; }
|
|
|
|
STDMETHOD(IncrementPerfCounterValue)( CI_PERF_COUNTER_NAME name ) { return S_OK; }
|
|
|
|
STDMETHOD(DecrementPerfCounterValue)( CI_PERF_COUNTER_NAME name ) { return S_OK; }
|
|
|
|
STDMETHOD(GetPerfCounterValue)( CI_PERF_COUNTER_NAME name,
|
|
long * pValue ) { return S_OK; }
|
|
|
|
STDMETHOD(NotifyEvent)( WORD fType,
|
|
DWORD eventId,
|
|
ULONG nParams,
|
|
const PROPVARIANT *aParams,
|
|
ULONG cbData = 0,
|
|
void* data = 0) { return S_OK; }
|
|
|
|
STDMETHOD(NotifyStatus)( CI_NOTIFY_STATUS_VALUE status,
|
|
ULONG nParams,
|
|
const PROPVARIANT *aParams ) { return S_OK; }
|
|
};
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Function: GetDriveLetterOfAnyScope
|
|
//
|
|
// Synopsis: Returns the drive letter of the first scope in the catalog or
|
|
// 0 on error
|
|
//
|
|
// History: 4-6-99 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
WCHAR GetDriveLetterOfAnyScope( WCHAR const * pwcCatalog )
|
|
{
|
|
TRY
|
|
{
|
|
CNullAdvise adviseStatus;
|
|
CiStorage store( pwcCatalog,
|
|
adviseStatus,
|
|
0,
|
|
FSCI_VERSION_STAMP,
|
|
TRUE );
|
|
|
|
XPtr<PRcovStorageObj> xTable( store.QueryScopeList( 0 ) );
|
|
CRcovStorageHdr & hdr = xTable->GetHeader();
|
|
ULONG cPaths = hdr.GetCount( hdr.GetPrimary() );
|
|
|
|
if ( 0 == cPaths )
|
|
return 0;
|
|
|
|
// read the last scan start time for the scope
|
|
|
|
CRcovStrmReadTrans xact( xTable.GetReference() );
|
|
xact.Seek(0);
|
|
|
|
LONGLONG llSig;
|
|
ULONG cbRead = xact.Read( &llSig, sizeof(llSig) );
|
|
if ( cbRead != sizeof(llSig) )
|
|
return 0;
|
|
|
|
if ( eSigCiScopeTable != llSig )
|
|
return 0;
|
|
|
|
//
|
|
// Get Volume ID
|
|
//
|
|
|
|
VOLUMEID volumeId;
|
|
cbRead = xact.Read( &volumeId, sizeof(VOLUMEID) );
|
|
if ( cbRead != sizeof(VOLUMEID) )
|
|
return 0;
|
|
|
|
//
|
|
// And Volume Creation Time
|
|
//
|
|
|
|
ULONGLONG VolumeCreationTime = 0;
|
|
cbRead = xact.Read( &VolumeCreationTime, sizeof(VolumeCreationTime) );
|
|
if ( cbRead != sizeof(VolumeCreationTime) )
|
|
return 0;
|
|
|
|
//
|
|
// And Volume Serial Number
|
|
//
|
|
|
|
ULONG VolumeSerialNumber = 0;
|
|
cbRead = xact.Read( &VolumeSerialNumber, sizeof(VolumeSerialNumber) );
|
|
if ( cbRead != sizeof(VolumeSerialNumber) )
|
|
return 0;
|
|
|
|
//
|
|
// Filesystem-Specific stuff.
|
|
//
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == volumeId )
|
|
{
|
|
//
|
|
// Read filetime for non-usn volumes
|
|
//
|
|
FILETIME ft;
|
|
cbRead = xact.Read( &ft, sizeof(FILETIME) );
|
|
if ( cbRead != sizeof(FILETIME) )
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Read usn for usn volumes
|
|
//
|
|
|
|
USN usn;
|
|
cbRead = xact.Read( &usn, sizeof(USN) );
|
|
if ( cbRead != sizeof(USN) )
|
|
return 0;
|
|
|
|
//
|
|
// And Journal ID
|
|
//
|
|
|
|
ULONGLONG JournalId = 0;
|
|
cbRead = xact.Read( &JournalId, sizeof(JournalId) );
|
|
if ( cbRead != sizeof(JournalId) )
|
|
return 0;
|
|
}
|
|
|
|
ULONG cchPath;
|
|
cbRead = xact.Read( &cchPath, sizeof(ULONG) );
|
|
if ( cbRead != sizeof(ULONG) )
|
|
return 0;
|
|
|
|
if ( 0 == cchPath || cchPath > MAX_PATH )
|
|
return 0;
|
|
|
|
WCHAR wcsPath[MAX_PATH+1];
|
|
cbRead = xact.Read( wcsPath, cchPath*sizeof(WCHAR) );
|
|
if ( cchPath*sizeof(WCHAR) != cbRead )
|
|
return 0;
|
|
|
|
return wcsPath[0];
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
// ignore failure -- just fall out returning 0
|
|
}
|
|
END_CATCH;
|
|
|
|
return 0;
|
|
} //GetDriveOfFirstScope
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::_DeSerialize
|
|
//
|
|
// Synopsis: Reads the scopes from the persistent scope table and adds
|
|
// them to the stack.
|
|
//
|
|
// Arguments: [stk] - (out) - Will have all the paths from the table.
|
|
//
|
|
// History: 30-Jan-96 srikants Created
|
|
// 07-May-97 SitaramR Usns
|
|
// 11-Mar-98 KyleP USN Journal ID
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::_DeSerialize( CScopeInfoStack & stk )
|
|
{
|
|
Win4Assert( 0 != _pTable );
|
|
|
|
if ( 0 == _pTable )
|
|
_FatalCorruption();
|
|
|
|
CImpersonateSystem impersonate;
|
|
CLock lock(_mutex);
|
|
|
|
CRcovStorageHdr & hdr = _pTable->GetHeader();
|
|
|
|
//
|
|
// read the last scan time.
|
|
//
|
|
|
|
ULONG nPaths = hdr.GetCount( hdr.GetPrimary() );
|
|
|
|
ciDebugOut(( DEB_ITRACE, "CCiScopeTable::_DeSerialize nPaths: %d\n", nPaths ));
|
|
|
|
if ( nPaths == 0 )
|
|
return;
|
|
|
|
// We have to iterate over the paths and add them to our list
|
|
//
|
|
WCHAR wcsPath[MAX_PATH+1];
|
|
CRcovStrmReadTrans xact( *_pTable );
|
|
xact.Seek(0);
|
|
|
|
|
|
XPtr<CScopeInfo> xScopeInfo;
|
|
|
|
for ( ULONG i = 0; i < nPaths; i++ )
|
|
{
|
|
VOLUMEID volumeId;
|
|
FILETIME ft;
|
|
USN usn;
|
|
ULONGLONG JournalId = 0;
|
|
ULONGLONG VolumeCreationTime = 0;
|
|
ULONG VolumeSerialNumber = 0;
|
|
|
|
LONGLONG llSig;
|
|
|
|
// read the last scan start time for the scope
|
|
ULONG cbRead;
|
|
|
|
cbRead = xact.Read( &llSig, sizeof(llSig) );
|
|
if ( cbRead != sizeof(llSig) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead, sizeof(llSig) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
if ( eSigCiScopeTable != llSig )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Signature mismatch 0x%X:0x%X\n",
|
|
lltoLowPart( llSig ), lltoHighPart( llSig ) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
//
|
|
// Get Volume ID
|
|
//
|
|
|
|
cbRead = xact.Read( &volumeId, sizeof(VOLUMEID) );
|
|
if ( cbRead != sizeof(VOLUMEID) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead,
|
|
sizeof(VOLUMEID) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
//
|
|
// And Volume Creation Time
|
|
//
|
|
|
|
cbRead = xact.Read( &VolumeCreationTime, sizeof(VolumeCreationTime) );
|
|
if ( cbRead != sizeof(VolumeCreationTime) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead,
|
|
sizeof(VolumeCreationTime) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
//
|
|
// And Volume Serial Number
|
|
//
|
|
|
|
cbRead = xact.Read( &VolumeSerialNumber, sizeof(VolumeSerialNumber) );
|
|
if ( cbRead != sizeof(VolumeSerialNumber) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead,
|
|
sizeof(VolumeSerialNumber) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
//
|
|
// Filesystem-Specific stuff.
|
|
//
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == volumeId )
|
|
{
|
|
//
|
|
// Read filetime for non-usn volumes
|
|
//
|
|
cbRead = xact.Read( &ft, sizeof(FILETIME) );
|
|
if ( cbRead != sizeof(FILETIME) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead, sizeof(FILETIME) ));
|
|
_FatalCorruption();
|
|
}
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Read usn for usn volumes
|
|
//
|
|
cbRead = xact.Read( &usn, sizeof(USN) );
|
|
if ( cbRead != sizeof(USN) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead,
|
|
sizeof(USN) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
//
|
|
// And Journal ID
|
|
//
|
|
|
|
cbRead = xact.Read( &JournalId, sizeof(JournalId) );
|
|
if ( cbRead != sizeof(JournalId) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead,
|
|
sizeof(JournalId) ));
|
|
_FatalCorruption();
|
|
}
|
|
}
|
|
|
|
ULONG cchPath;
|
|
cbRead = xact.Read( &cchPath, sizeof(ULONG) );
|
|
if ( cbRead != sizeof(ULONG) )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Read %d bytes instead of %d \n",
|
|
cbRead, sizeof(ULONG) ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
if ( 0 == cchPath || cchPath > MAX_PATH )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Illegal path length %d\n", cchPath ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
cbRead = xact.Read( wcsPath, cchPath*sizeof(WCHAR) );
|
|
if ( cchPath*sizeof(WCHAR) != cbRead )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Requested %d bytes. Read %d bytes\n",
|
|
cchPath*sizeof(WCHAR), cbRead ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
cchPath--; // includes the length of the terminating 0
|
|
if ( 0 != wcsPath[cchPath] || L'\\' != wcsPath[cchPath-1] )
|
|
{
|
|
ciDebugOut(( DEB_ERROR,
|
|
"CCiScopeTable::_DeSerialize - Illegaly formed path %ws \n", wcsPath ));
|
|
_FatalCorruption();
|
|
}
|
|
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == volumeId )
|
|
xScopeInfo.Set( new CScopeInfo( wcsPath,
|
|
VolumeCreationTime,
|
|
VolumeSerialNumber,
|
|
ft ) );
|
|
else
|
|
xScopeInfo.Set( new CScopeInfo( wcsPath,
|
|
VolumeCreationTime,
|
|
VolumeSerialNumber,
|
|
volumeId,
|
|
usn,
|
|
JournalId,
|
|
(0 == usn) ) );
|
|
|
|
stk.Push( xScopeInfo.GetPointer() ); // Push can throw
|
|
xScopeInfo.Acquire();
|
|
}
|
|
} //_DeSerialize
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::_Serialize
|
|
//
|
|
// Synopsis: Writes the given stack of scopes to the persistent table.
|
|
//
|
|
// Arguments: [stk] - Stack of scopes to write.
|
|
//
|
|
// History: 1-30-96 srikants Created
|
|
// 28-Jul-1996 AlanW Allow for invalid scopes, e.g., when
|
|
// one is removed in middle of stack
|
|
// 05-May-1997 SitaramR Usns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::_Serialize( CScopeInfoStack const & stk )
|
|
{
|
|
if ( 0 == _pTable )
|
|
{
|
|
_FatalCorruption();
|
|
}
|
|
|
|
CLock lock(_mutex);
|
|
|
|
CRcovStorageHdr & hdr = _pTable->GetHeader();
|
|
CRcovStrmWriteTrans xact( *_pTable );
|
|
|
|
xact.Empty();
|
|
|
|
ULONG nPaths = 0;
|
|
FILETIME ft;
|
|
RtlZeroMemory( &ft, sizeof(ft) );
|
|
LONGLONG llSig = eSigCiScopeTable; // Signature for corruption detection
|
|
|
|
for ( unsigned i = 0; i < stk.Count(); i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *stk.Get(i);
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
WCHAR const * pwszScope = scopeInfo.GetPath();
|
|
|
|
ULONG cchPath = wcslen( pwszScope ) + 1;
|
|
Win4Assert( cchPath <= MAX_PATH );
|
|
|
|
#if CIDBG == 1
|
|
if ( wcschr( pwszScope, L'~' ) )
|
|
{
|
|
// Possible shortnames in scope path. We must only use long names.
|
|
CLowerFunnyPath lowerFunnyPath( pwszScope );
|
|
|
|
if ( lowerFunnyPath.IsShortPath( ) )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"CCiScopeTable::_Seiralize: possible shortname path %ws\n",
|
|
lowerFunnyPath.GetActualPath() ));
|
|
}
|
|
}
|
|
#endif // CIDBG == 1
|
|
|
|
xact.Append( &llSig, sizeof(llSig) );
|
|
|
|
VOLUMEID volumeId = scopeInfo.VolumeId();
|
|
xact.Append( &volumeId, sizeof(VOLUMEID) );
|
|
|
|
ULONGLONG const & VolumeCreationTime = scopeInfo.VolumeCreationTime();
|
|
xact.Append( &VolumeCreationTime, sizeof(VolumeCreationTime) );
|
|
|
|
ULONG VolumeSerialNumber = scopeInfo.VolumeSerialNumber();
|
|
xact.Append( &VolumeSerialNumber, sizeof(VolumeSerialNumber) );
|
|
|
|
if ( scopeInfo.VolumeId() == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
//
|
|
// Write filetime for non-usn volumes
|
|
//
|
|
ft = scopeInfo.GetLastScanTime();
|
|
xact.Append( &ft, sizeof(ft) );
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Write usn for usn volumes
|
|
//
|
|
USN usn = scopeInfo.Usn();
|
|
xact.Append( &usn, sizeof(USN) );
|
|
|
|
ULONGLONG JournalId = scopeInfo.JournalId();
|
|
xact.Append( &JournalId, sizeof(JournalId) );
|
|
}
|
|
|
|
xact.Append( &cchPath, sizeof(cchPath) );
|
|
xact.Append( pwszScope, cchPath*sizeof(WCHAR) );
|
|
nPaths++;
|
|
}
|
|
|
|
ciDebugOut(( DEB_ITRACE, "_Serialize, nPaths %d\n", nPaths ));
|
|
|
|
hdr.SetCount ( hdr.GetBackup(), nPaths );
|
|
hdr.SetUserHdr( hdr.GetBackup(), _usrHdr );
|
|
|
|
xact.Commit();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::_LokScheduleScans
|
|
//
|
|
// Synopsis: Schedules all the scopes for either full or incremental
|
|
// scan depending upon the header information.
|
|
//
|
|
// History: 4-15-96 srikants Moved out of StartUp
|
|
// 7-May-97 SitaramR Usns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::_LokScheduleScans( PARTITIONID partId,
|
|
BOOL & fSerializeNotifyList )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "in CCiScopeTable::_LokScheduleScans\n" ));
|
|
fSerializeNotifyList = FALSE;
|
|
|
|
{
|
|
//
|
|
// Read the persistent scope list
|
|
//
|
|
|
|
CRcovStorageHdr & storageHdr = _pTable->GetHeader();
|
|
|
|
//
|
|
// read the last scan time.
|
|
//
|
|
storageHdr.GetUserHdr( storageHdr.GetPrimary(), _usrHdr );
|
|
if ( !_hdr.IsInitialized() )
|
|
_hdr.Initialize();
|
|
|
|
CScopeInfoStack stk;
|
|
|
|
_DeSerialize( stk );
|
|
|
|
ciDebugOut(( DEB_ITRACE, "scope stack count: %d\n", stk.Count() ));
|
|
|
|
if ( 0 == stk.Count() )
|
|
return;
|
|
|
|
//
|
|
// Enable batch processing in the scan manager. This will result in
|
|
// all the scopes being processed at once and avoid the scan of
|
|
// the property store once per scope.
|
|
//
|
|
XBatchScan xBatchScans( _scanMgr );
|
|
XBatchUsnProcessing xBatchUsns( _usnMgr );
|
|
|
|
for ( ULONG i = 0; i < stk.Count(); i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *stk.Get(i);
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
ciDebugOut(( DEB_ITRACE, "Adding path %ws to CI\n",
|
|
scopeInfo.GetPath() ));
|
|
BOOL fSubScopesRemoved;
|
|
|
|
//
|
|
// Check if there has been a volume format change, e.g.
|
|
// from a non-usn-enabled volume to an usn-enabled
|
|
// volume.
|
|
//
|
|
|
|
BOOL fUsnEnabledNow = _cicat.VolumeSupportsUsns( scopeInfo.GetPath()[0] );
|
|
BOOL fUsnEnabledPrev = scopeInfo.VolumeId() != CI_VOLID_USN_NOT_ENABLED;
|
|
if ( fUsnEnabledNow != fUsnEnabledPrev )
|
|
{
|
|
//
|
|
// Volume format has changed, so reset scopeInfo to simulate a fresh
|
|
// scan using the appropriate method for new format.
|
|
//
|
|
|
|
ciDebugOut(( DEB_WARN,
|
|
"Switching monitoring method for path %ws, due to format change\n",
|
|
scopeInfo.GetPath() ));
|
|
|
|
if ( fUsnEnabledNow )
|
|
{
|
|
VOLUMEID volId = _cicat.MapPathToVolumeId( scopeInfo.GetPath() );
|
|
scopeInfo.ResetForUsns( volId );
|
|
}
|
|
else
|
|
scopeInfo.ResetForScans();
|
|
}
|
|
|
|
//
|
|
// Check if a USN-enabled volume has been opened in NT4.
|
|
//
|
|
|
|
if ( fUsnEnabledNow )
|
|
{
|
|
ULONGLONG jidNow = _cicat.GetJournalId( scopeInfo.GetPath() );
|
|
ULONGLONG jidPrev = scopeInfo.JournalId();
|
|
|
|
if ( jidNow != jidPrev )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"Scanning USN-enabled volume %ws due to downlevel (NT4) open.\n",
|
|
scopeInfo.GetPath() ));
|
|
|
|
scopeInfo.ResetForUsns( scopeInfo.VolumeId(), fUsnEnabledPrev ? scopeInfo.Usn() : 0 );
|
|
}
|
|
}
|
|
|
|
//
|
|
// Check to see if the volume has been reformatted.
|
|
//
|
|
|
|
BOOL fReformatted = (_cicat.GetVolumeCreationTime( scopeInfo.GetPath() ) != scopeInfo.VolumeCreationTime()) ||
|
|
(_cicat.GetVolumeSerialNumber( scopeInfo.GetPath() ) != scopeInfo.VolumeSerialNumber());
|
|
|
|
if ( fReformatted || IsFullScanNeeded() )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "Scanning newly formatted/trashed volume %ws\n", scopeInfo.GetPath() ));
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == scopeInfo.VolumeId() )
|
|
scopeInfo.ResetForScans();
|
|
else
|
|
{
|
|
scopeInfo.SetScanNeeded( TRUE ); // Full scan
|
|
scopeInfo.ResetForUsns( scopeInfo.VolumeId() ); // From USN = 0
|
|
}
|
|
}
|
|
|
|
ciDebugOut(( DEB_ITRACE, "_LokScheduleScans, '%ws'\n",
|
|
scopeInfo.GetPath() ));
|
|
|
|
_notifyMgr.AddPath( scopeInfo, fSubScopesRemoved );
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == scopeInfo.VolumeId() )
|
|
{
|
|
ULONG updFlag;
|
|
if ( fReformatted || fUsnEnabledNow != fUsnEnabledPrev )
|
|
{
|
|
//
|
|
// Do a full scan if there has been a format change
|
|
//
|
|
updFlag = UPD_FULL;
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Use scan info from persistent header of scopetable
|
|
//
|
|
if ( IsFullScanNeeded() )
|
|
updFlag = UPD_FULL;
|
|
else
|
|
updFlag = UPD_INCREM;
|
|
}
|
|
|
|
_scanMgr.ScanScope( scopeInfo.GetPath(),
|
|
partId,
|
|
updFlag, // Full or increm update
|
|
TRUE, // do deletions,
|
|
TRUE // delayed scanning
|
|
);
|
|
}
|
|
else
|
|
{
|
|
Win4Assert( (0 == scopeInfo.Usn() && scopeInfo.FUsnTreeScan()) ||
|
|
0 != scopeInfo.Usn() );
|
|
|
|
if ( scopeInfo.FUsnTreeScan() )
|
|
{
|
|
//
|
|
// An usn of 0 indicates that a scan and subsequent
|
|
// CheckPointChangesFlushed for this volume id has not
|
|
// completed successfully, and hence a scan is needed
|
|
//
|
|
|
|
ciDebugOut(( DEB_ITRACE, "_LokScheduleScans, AddScope\n" ));
|
|
_usnMgr.AddScope( scopeInfo.GetPath(),
|
|
scopeInfo.VolumeId(),
|
|
TRUE, // Do deletions
|
|
scopeInfo.Usn(), // Starting USN
|
|
scopeInfo.IsFullScan() ); // TRUE --> delete everything first
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Start monitoring for usn notifications. This is the main
|
|
// performance advantage of usns when compared with the
|
|
// _scanMgr.ScanScope above --- no scan is needed.
|
|
//
|
|
ciDebugOut(( DEB_ITRACE, "_LokScheduleScans, MonitorScope\n" ));
|
|
_usnMgr.MonitorScope( scopeInfo.GetPath(),
|
|
scopeInfo.VolumeId(),
|
|
scopeInfo.Usn() );
|
|
}
|
|
}
|
|
|
|
if ( fSubScopesRemoved )
|
|
fSerializeNotifyList = TRUE;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::StartUp
|
|
//
|
|
// Synopsis: Starts up the contentIndex scope scanning and notification
|
|
// mechanism for all the scopes that are registered with the
|
|
// content index.
|
|
//
|
|
// Arguments: [notifyMgr] - The notification manager.
|
|
// [scanMgr] - The scan manager.
|
|
// [partId] - PartitionId.
|
|
//
|
|
// History: 1-21-96 srikants Created
|
|
//
|
|
// Notes: MUST BE UNDER CICAT LOCK
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::StartUp( CClientDocStore & docStore ,
|
|
PARTITIONID partId )
|
|
{
|
|
Win4Assert( 0 != _pTable );
|
|
|
|
if ( _fInitialized )
|
|
return;
|
|
|
|
// ============================ ScopeTable lock ===================
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// If there was no full scan needed when it was shutdown last,
|
|
// set up for an incremental scan.
|
|
//
|
|
if ( eNoScan == _state )
|
|
RecordIncrScanNeeded( TRUE ); // fStartup is TRUE
|
|
|
|
ScheduleScansIfNeeded( docStore );
|
|
|
|
_fInitialized = TRUE;
|
|
// ============================ ScopeTable lock ===================
|
|
|
|
}
|
|
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::AddScope
|
|
//
|
|
// Synopsis: Registers a scope persistently with CI for scanning and
|
|
// notification.
|
|
//
|
|
// Arguments: [volumeId] -- Volume id
|
|
// [pwcsScope] -- The scope to be registered.
|
|
// [pwcsCatScope] -- If non-zero, name of catalog key under
|
|
// which a shadow registry entry should be
|
|
// created.
|
|
//
|
|
// History: 1-21-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::AddScope( VOLUMEID volumeId,
|
|
WCHAR const * pwszScope,
|
|
WCHAR const * pwszCatScope )
|
|
{
|
|
ULONG ccPath = wcslen( pwszScope );
|
|
|
|
Win4Assert( ccPath < MAX_PATH );
|
|
Win4Assert( L'\\' == pwszScope[ccPath-1] );
|
|
|
|
#if CIDBG == 1
|
|
if ( wcschr( pwszScope, L'~' ) )
|
|
{
|
|
// Possible shortnames in scope path. We must only use long names.
|
|
CLowerFunnyPath lowerFunnyPath( pwszScope );
|
|
|
|
if ( lowerFunnyPath.IsShortPath( ) )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"CCiScopeTable::AddScope: possible shortname path %ws\n",
|
|
lowerFunnyPath.GetActualPath() ));
|
|
}
|
|
}
|
|
#endif // CIDBG == 1
|
|
Win4Assert( 0 != _pTable );
|
|
|
|
if ( 0 == _pTable )
|
|
{
|
|
_FatalCorruption();
|
|
}
|
|
|
|
CLock lock(_mutex);
|
|
|
|
CRcovStorageHdr & hdr = _pTable->GetHeader();
|
|
CRcovStrmAppendTrans xact( *_pTable );
|
|
|
|
ULONG nPaths = hdr.GetCount( hdr.GetPrimary() );
|
|
ccPath++; // increment to include the trailing 0
|
|
|
|
LONGLONG llSig = eSigCiScopeTable; // Signature for corruption detection.
|
|
|
|
xact.Append( &llSig, sizeof(llSig) );
|
|
xact.Append( &volumeId, sizeof(VOLUMEID) );
|
|
|
|
ULONGLONG VolumeCreationTime = _cicat.GetVolumeCreationTime(pwszScope);
|
|
xact.Append( &VolumeCreationTime, sizeof(VolumeCreationTime) );
|
|
|
|
ULONG VolumeSerialNumber = _cicat.GetVolumeSerialNumber(pwszScope);
|
|
xact.Append( &VolumeSerialNumber, sizeof(VolumeSerialNumber) );
|
|
|
|
if ( volumeId == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
FILETIME ft;
|
|
RtlZeroMemory( &ft, sizeof(ft) );
|
|
xact.Append( &ft, sizeof(ft) );
|
|
}
|
|
else
|
|
{
|
|
USN usn = 0;
|
|
xact.Append( &usn, sizeof(USN) );
|
|
|
|
ULONGLONG JournalId = _cicat.GetJournalId( pwszScope );
|
|
xact.Append( &JournalId, sizeof(JournalId) );
|
|
}
|
|
|
|
xact.Append( &ccPath, sizeof(ccPath) );
|
|
xact.Append( pwszScope, ccPath*sizeof(WCHAR) );
|
|
|
|
nPaths++;
|
|
hdr.SetCount( hdr.GetBackup(), nPaths );
|
|
|
|
xact.Commit();
|
|
|
|
if ( 0 != pwszCatScope )
|
|
{
|
|
//
|
|
// Build string: NAME: ,,3 --> Virtual, Indexed
|
|
//
|
|
|
|
WCHAR wcsScope[] = L",,3";
|
|
|
|
HKEY hkey;
|
|
DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, pwszCatScope, &hkey );
|
|
|
|
if ( ERROR_SUCCESS != dwError )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, pwszCatScope ));
|
|
}
|
|
else
|
|
{
|
|
AddShadow( pwszScope, hkey );
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::_Serialize
|
|
//
|
|
// Synopsis: Serializes the scopes in the notification manager.
|
|
//
|
|
// History: 1-25-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::_Serialize()
|
|
{
|
|
if ( 0 == _pTable )
|
|
{
|
|
_FatalCorruption();
|
|
}
|
|
|
|
CScopeInfoStack stk;
|
|
|
|
// ====================== NOTIFY MGR LOCK =========================
|
|
{
|
|
for ( CCiNotifyIter iter( _notifyMgr );
|
|
!iter.AtEnd() && 0 != iter.Get();
|
|
iter.Advance() )
|
|
{
|
|
WCHAR const * pwszScope = iter.Get();
|
|
ULONG ccPath = wcslen( pwszScope );
|
|
ccPath++; // increment to include trailing 0
|
|
|
|
FILETIME ft;
|
|
iter.GetLastScanTime( ft );
|
|
|
|
XPtr<CScopeInfo> xScopeInfo;
|
|
|
|
if ( iter.IsDownlevelVolume() )
|
|
xScopeInfo.Set( new CScopeInfo( pwszScope,
|
|
iter.VolumeCreationTime(),
|
|
iter.VolumeSerialNumber(),
|
|
ft ) );
|
|
else
|
|
xScopeInfo.Set( new CScopeInfo( pwszScope,
|
|
iter.VolumeCreationTime(),
|
|
iter.VolumeSerialNumber(),
|
|
iter.VolumeId(),
|
|
iter.Usn(),
|
|
iter.JournalId(),
|
|
iter.FUsnTreeScan() ) );
|
|
|
|
stk.Push( xScopeInfo.GetPointer() ); // Push can throw
|
|
xScopeInfo.Acquire();
|
|
}
|
|
}
|
|
// ====================== NOTIFY MGR LOCK =========================
|
|
|
|
//
|
|
// If the notification manager is shutting down, it probably gave
|
|
// us an incomplete list of scopes
|
|
//
|
|
|
|
if ( _notifyMgr.IsRunning() )
|
|
_Serialize( stk );
|
|
else
|
|
ciDebugOut(( DEB_WARN, "Not serializing scopes; notifymgr is shutdown\n" ));
|
|
} //_Serialize
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::_UpdateHeader
|
|
//
|
|
// Synopsis: Updates the on-disk header information based on the in-memory
|
|
// version.
|
|
//
|
|
// History: 4-15-96 srikants Moved into a separate function
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::_UpdateHeader()
|
|
{
|
|
|
|
Win4Assert( sizeof(CCiScopeUsrHdr) <= sizeof(CRcovUserHdr) );
|
|
|
|
if ( 0 == _pTable )
|
|
{
|
|
_FatalCorruption();
|
|
}
|
|
|
|
CRcovStorageHdr & storageHdr = _pTable->GetHeader();
|
|
CRcovStrmAppendTrans xact( *_pTable );
|
|
|
|
if ( !_hdr.IsInitialized() )
|
|
_hdr.Initialize();
|
|
|
|
storageHdr.SetUserHdr( storageHdr.GetBackup(), _usrHdr );
|
|
|
|
xact.Commit();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::ProcessChangesFlush
|
|
//
|
|
// Synopsis: Flushes the scope table, which will
|
|
// write the latest flush time and usn flush info to disk.
|
|
//
|
|
// History: 1-26-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::ProcessChangesFlush( )
|
|
{
|
|
_Serialize();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RemoveScope
|
|
//
|
|
// Synopsis: Removes the specified scope from the persistent table.
|
|
//
|
|
// Arguments: [pwcsScope] -- Scope to be removed.
|
|
// [pwcsCatScope] -- If non-zero, name of catalog key under
|
|
// which a shadow registry entry should be
|
|
// created.
|
|
//
|
|
// History: 1-30-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RemoveScope( WCHAR const * pwcsScope,
|
|
WCHAR const * pwcsCatScope )
|
|
{
|
|
CScopeInfoStack scopes;
|
|
_DeSerialize( scopes );
|
|
|
|
for ( unsigned i = 0; i < scopes.Count(); i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *scopes.Get(i);
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
if ( AreIdenticalPaths(pwcsScope, scopeInfo.GetPath()) )
|
|
scopeInfo.Invalidate();
|
|
}
|
|
|
|
_Serialize( scopes );
|
|
|
|
//
|
|
// Delete any remnant in registry.
|
|
//
|
|
|
|
HKEY hkey;
|
|
DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, pwcsCatScope, &hkey );
|
|
|
|
if ( ERROR_SUCCESS != dwError )
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, pwcsCatScope ));
|
|
}
|
|
else
|
|
{
|
|
DeleteIfShadow( pwcsScope, hkey );
|
|
RegCloseKey( hkey );
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RemoveSubScopes
|
|
//
|
|
// Synopsis: Removes only the sub-scopes of the given scope. The scope
|
|
// itself is NOT removed.
|
|
//
|
|
// Arguments: [pwcsScope] -- Sub-scopes of the scope to be removed.
|
|
// [pwcsCatScope] -- If non-zero, name of catalog key under
|
|
// which a shadow registry entry should be
|
|
// created.
|
|
//
|
|
// History: 1-30-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RemoveSubScopes( WCHAR const * pwcsScope,
|
|
WCHAR const * pwcsCatScope )
|
|
{
|
|
//
|
|
// Open key for reg deletes.
|
|
//
|
|
|
|
HKEY hkey = 0;
|
|
DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, pwcsCatScope, &hkey );
|
|
|
|
if ( ERROR_SUCCESS != dwError ) {
|
|
ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, pwcsCatScope ));
|
|
}
|
|
|
|
SRegKey xKey( hkey );
|
|
|
|
//
|
|
// Search for sub-scopes
|
|
//
|
|
|
|
CScopeInfoStack scopes;
|
|
_DeSerialize( scopes );
|
|
|
|
CScopeMatch match( pwcsScope, wcslen(pwcsScope) );
|
|
|
|
for ( unsigned i = 0;
|
|
i < scopes.Count();
|
|
i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *scopes.Get(i);
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
if ( match.IsInScope( scopeInfo.GetPath(), wcslen(scopeInfo.GetPath()) ) &&
|
|
!AreIdenticalPaths( scopeInfo.GetPath(), pwcsScope ) )
|
|
{
|
|
scopeInfo.Invalidate();
|
|
|
|
//
|
|
// Delete any remnant in registry.
|
|
//
|
|
|
|
if ( 0 != hkey )
|
|
DeleteIfShadow( scopeInfo.GetPath(), hkey );
|
|
}
|
|
}
|
|
|
|
_Serialize( scopes );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RefreshShadow, public
|
|
//
|
|
// Synopsis: Re-adds missing shadow (virtual) scopes to registry.
|
|
//
|
|
// Arguments: [pwcsPScope] -- Physical scope to re-add (if doesn't exist)
|
|
// [pwcsCatScope] -- Name of catalog key under which a shadow
|
|
// registry entry should be created.
|
|
//
|
|
// History: 12-10-1997 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RefreshShadow( WCHAR const * pwcsPScope, WCHAR const * pwcsCatScope )
|
|
{
|
|
//
|
|
// Open key for reg refresh.
|
|
//
|
|
|
|
HKEY hkey = 0;
|
|
DWORD dwError = RegOpenKey( HKEY_LOCAL_MACHINE, pwcsCatScope, &hkey );
|
|
|
|
if ( ERROR_SUCCESS != dwError ) {
|
|
ciDebugOut(( DEB_ERROR, "Error %d opening %ws\n", dwError, pwcsCatScope ));
|
|
}
|
|
|
|
SRegKey xKey( hkey );
|
|
|
|
//
|
|
// Try the refresh
|
|
//
|
|
|
|
if ( 0 != hkey )
|
|
RefreshIfShadow( pwcsPScope, hkey );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::ProcessDiskFull
|
|
//
|
|
// Synopsis: Processes disk full condition.
|
|
//
|
|
// Arguments: [scanMgr] -
|
|
// [cci] -
|
|
// [partId] -
|
|
//
|
|
// History: 4-17-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::ProcessDiskFull( CClientDocStore & docStore,
|
|
PARTITIONID partId )
|
|
{
|
|
CLock lock(_mutex);
|
|
|
|
if ( !_fInitialized )
|
|
return;
|
|
|
|
RecordIncrScanNeeded( FALSE ); // fStartup is FALSE
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::ClearDiskFull
|
|
//
|
|
// Synopsis: Processes the clearing of the disk full situation. If there
|
|
// was in incremental scan scheduled, it will be processed.
|
|
//
|
|
// Arguments: [partId] - PartitionId.
|
|
//
|
|
// History: 4-21-96 srikants Created
|
|
//
|
|
// Notes:
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::ClearDiskFull( CClientDocStore &docStore )
|
|
{
|
|
|
|
if ( !_fInitialized )
|
|
return;
|
|
|
|
ScheduleScansIfNeeded( docStore );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::MarkCiDataCorrupt, public
|
|
//
|
|
// Synopsis: Persistently marks catalog as corrupt.
|
|
//
|
|
// History: 06-May-1998 KyleP Added header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::MarkCiDataCorrupt()
|
|
{
|
|
//
|
|
// Abort any in-progress scans and usn updates
|
|
//
|
|
|
|
_scanMgr.DisableScan();
|
|
_usnMgr.DisableUpdates();
|
|
|
|
//
|
|
// And persistently mark the corruption.
|
|
//
|
|
|
|
_hdr.SetCiDataCorrupt();
|
|
_UpdateHeader();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RecordFullScanNeeded
|
|
//
|
|
// Synopsis: Records that a full scan is needed in memory and persistently.
|
|
//
|
|
// History: 1-27-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RecordFullScanNeeded()
|
|
{
|
|
// =============================================================
|
|
|
|
//
|
|
// Note that we call into scan manager from here which will need that
|
|
// to acquire the lock but scan manager never calls into the scope
|
|
// table with the lock held. So, we are okay.
|
|
//
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// Abort any in-progress scans and usn updates
|
|
//
|
|
_scanMgr.DisableScan();
|
|
_usnMgr.DisableUpdates();
|
|
|
|
//
|
|
// Mark that we need a full scan.
|
|
//
|
|
_state = eFullScanNeeded;
|
|
|
|
_hdr.SetFullScanNeeded();
|
|
_UpdateHeader();
|
|
|
|
// =============================================================
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RecordIncrScanNeeded
|
|
//
|
|
// Synopsis: If there is no full scan, it records that an incremental
|
|
// scan is needed.
|
|
//
|
|
// Arguments: [fStartup] -- Is it startup time ?
|
|
//
|
|
// History: 1-27-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RecordIncrScanNeeded( BOOL fStartup )
|
|
{
|
|
|
|
|
|
//
|
|
// Note that we call into scan manager from here which will need that
|
|
// to acquire the lock but scan manager never calls into the scope
|
|
// table with the lock held. So, we are okay.
|
|
//
|
|
|
|
// =============================================================
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// Abort any in-progress scans and usn updates
|
|
//
|
|
_scanMgr.DisableScan();
|
|
|
|
if ( !fStartup )
|
|
{
|
|
//
|
|
// An incremental scan needs to be persistently written at startup,
|
|
// but there is no need to disable updates at startup
|
|
//
|
|
_usnMgr.DisableUpdates();
|
|
}
|
|
|
|
|
|
//
|
|
// If there is full scan needed or a full scan is going on,
|
|
// we have to do a full scan later. Otherwise, record an
|
|
// incremental scan.
|
|
//
|
|
if ( eFullScanNeeded == _state || eDoingFullScan == _state )
|
|
{
|
|
_state = eFullScanNeeded;
|
|
}
|
|
else
|
|
{
|
|
_state = eIncrScanNeeded;
|
|
}
|
|
// =============================================================
|
|
|
|
//
|
|
// We don't have to update the persistent state about incremental
|
|
// scans because we always do an incremental scan on startup.
|
|
//
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::RecordScansComplete
|
|
//
|
|
// Synopsis: Records that any in-progress scan has been completed.
|
|
//
|
|
// History: 1-27-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::RecordScansComplete()
|
|
{
|
|
// =============================================================
|
|
CLock lock(_mutex);
|
|
|
|
if ( eDoingIncrScan == _state || eDoingFullScan == _state )
|
|
{
|
|
_hdr.ClearFullScanNeeded();
|
|
_UpdateHeader();
|
|
|
|
_state = eNoScan;
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::ScheduleScansIfNeeded
|
|
//
|
|
// Synopsis: If there is a pending scan and the disk is not full, it
|
|
// schedules the appropriate scan.
|
|
//
|
|
// Arguments: [docStore] - DocStore to use for checking disk space
|
|
// situation.
|
|
//
|
|
// History: 1-27-97 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::ScheduleScansIfNeeded( CClientDocStore & docStore )
|
|
{
|
|
Win4Assert( _state >= eNoScan && _state <= eDoingIncrScan );
|
|
ciDebugOut(( DEB_ITRACE, "schedulescansifneeded, _state: %#x\n", _state ));
|
|
|
|
BOOL fSerializeNotifyList = TRUE;
|
|
|
|
// =============================================================
|
|
{
|
|
//
|
|
// Note that we call into scan manager from here which will need that
|
|
// to acquire the lock but scan manager never calls into the scope
|
|
// table with the lock held. So, we are okay.
|
|
//
|
|
CLock lock(_mutex);
|
|
|
|
if ( eDoingFullScan == _state ||
|
|
eDoingIncrScan == _state ||
|
|
eNoScan == _state )
|
|
{
|
|
//
|
|
// There is nothing to do.
|
|
//
|
|
return;
|
|
}
|
|
|
|
BOOL fLowOnDisk = docStore.VerifyIfLowOnDiskSpace();
|
|
|
|
if ( !fLowOnDisk )
|
|
{
|
|
_scanMgr.EnableScan();
|
|
_usnMgr.EnableUpdates();
|
|
_LokScheduleScans( 1, fSerializeNotifyList );
|
|
|
|
if ( _state == eFullScanNeeded )
|
|
{
|
|
_state = eDoingFullScan;
|
|
ciDebugOut(( DEB_WARN, "CCiScopeTable - Scheduled a full content scan\n" ));
|
|
}
|
|
else
|
|
{
|
|
_state = eDoingIncrScan;
|
|
ciDebugOut(( DEB_WARN, "CCiScopeTable - Scheduled an incremental content scan\n" ));
|
|
}
|
|
}
|
|
}
|
|
// =============================================================
|
|
|
|
if ( fSerializeNotifyList )
|
|
_Serialize();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::Enumerate, public
|
|
//
|
|
// Synopsis: Enumerates entries in the scope table
|
|
//
|
|
// Arguments: [pwcScope] - Buffer into which scope is written
|
|
// [partId] - bookmark for enumeration, 0 to rewind
|
|
//
|
|
// History: 10/17/96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCiScopeTable::Enumerate(
|
|
WCHAR * pwcScope,
|
|
unsigned cwc,
|
|
unsigned & iBmk )
|
|
{
|
|
CScopeInfoStack scopes;
|
|
_DeSerialize( scopes );
|
|
|
|
do
|
|
{
|
|
if ( iBmk >= scopes.Count() )
|
|
return FALSE;
|
|
|
|
CScopeInfo & scopeInfo = *scopes.Get( iBmk );
|
|
|
|
iBmk++;
|
|
|
|
if ( scopeInfo.IsValid() )
|
|
{
|
|
if ( cwc < ( wcslen( scopeInfo.GetPath() ) + 1 ) )
|
|
THROW( CException( STATUS_INVALID_PARAMETER ) );
|
|
|
|
wcscpy( pwcScope, scopeInfo.GetPath() );
|
|
return TRUE;
|
|
}
|
|
} while ( TRUE );
|
|
|
|
return FALSE;
|
|
} //Enumerate
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::ClearCiDataCorrupt, public
|
|
//
|
|
// Synopsis: Clears corrupted data if the catalog is not read-only
|
|
//
|
|
// History: 02/20/98 kitmanh Moved from scopetbl.hxx
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
void CCiScopeTable::ClearCiDataCorrupt()
|
|
{
|
|
if (!_cicat.IsReadOnly())
|
|
{
|
|
_hdr.ClearCiDataCorrupt();
|
|
_UpdateHeader();
|
|
}
|
|
}
|
|
|
|
//+----------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiScopeTable::Dump, public
|
|
//
|
|
// Synopsis: dumps scope table
|
|
//
|
|
// History: 3-1-98 mohamedn created
|
|
//
|
|
//-----------------------------------------------------------------------------
|
|
|
|
#if CIDBG==1
|
|
|
|
void CCiScopeTable::Dump()
|
|
{
|
|
CScopeInfoStack scopes;
|
|
_DeSerialize( scopes );
|
|
|
|
ciDebugOut(( DEB_ERROR, "========= Start ScopesTable =============\n" ));
|
|
|
|
for ( unsigned i = 0; i < scopes.Count(); i++ )
|
|
{
|
|
ciDebugOut((DEB_ERROR,"scopetable: %ws\n", (scopes.Get(i))->GetPath() ));
|
|
|
|
}
|
|
|
|
ciDebugOut(( DEB_ERROR, "========= End ScopesTable =============\n" ));
|
|
}
|
|
|
|
#endif
|