|
|
//+---------------------------------------------------------------------------
//
// 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
|