You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
1823 lines
55 KiB
1823 lines
55 KiB
//+---------------------------------------------------------------------------
|
|
//
|
|
// Microsoft Windows
|
|
// Copyright (C) Microsoft Corporation, 1992 - 2002.
|
|
//
|
|
// File: notifmgr.cxx
|
|
//
|
|
// Contents: Registry and file system change notifications
|
|
//
|
|
// 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 <svcutil.hxx>
|
|
|
|
#include "cicat.hxx"
|
|
#include "update.hxx"
|
|
#include "notifmgr.hxx"
|
|
#include "scanmgr.hxx"
|
|
#include "scopetbl.hxx"
|
|
|
|
BOOL AreIdenticalPaths( WCHAR const * pwcsPath1, WCHAR const * pwcsPath2 )
|
|
{
|
|
ULONG len1 = wcslen( pwcsPath1 );
|
|
ULONG len2 = wcslen( pwcsPath2 );
|
|
|
|
return len1 == len2 &&
|
|
RtlEqualMemory( pwcsPath1, pwcsPath2, len1*sizeof(WCHAR) );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::CCiNotify
|
|
//
|
|
// Synopsis: Constructor of the single scope notification object CCiNotify.
|
|
//
|
|
// Arguments: [notifyMgr] -- Notification manager.
|
|
// [wcsScope] -- Scope of the notification.
|
|
// [cwcScope] -- Length in chars of [wcsScope]
|
|
// [volumeId] -- Volume id
|
|
// [ftlastScan] -- Last scan time
|
|
// [usn] -- Usn
|
|
// [fDeep] -- Set to TRUE if deep notifications are enabled.
|
|
//
|
|
// History: 1-17-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiNotify::CCiNotify( CCiNotifyMgr & notifyMgr,
|
|
WCHAR const * wcsScope,
|
|
unsigned cwcScope,
|
|
VOLUMEID volumeId,
|
|
ULONGLONG const & VolumeCreationTime,
|
|
ULONG VolumeSerialNumber,
|
|
FILETIME const & ftLastScan,
|
|
USN usn,
|
|
ULONGLONG const & JournalId,
|
|
BOOL fUsnTreeScan,
|
|
BOOL fDeep )
|
|
: CGenericNotify( & notifyMgr.GetCatalog(), wcsScope, cwcScope, fDeep, TRUE ),
|
|
_sigCiNotify(sigCiNotify),
|
|
_notifyMgr(notifyMgr),
|
|
_volumeId(volumeId),
|
|
_VolumeCreationTime( VolumeCreationTime ),
|
|
_VolumeSerialNumber( VolumeSerialNumber ),
|
|
_fUsnTreeScan(fUsnTreeScan)
|
|
{
|
|
if ( volumeId == CI_VOLID_USN_NOT_ENABLED )
|
|
_ftLastScan = ftLastScan;
|
|
else
|
|
{
|
|
_usn = usn;
|
|
_JournalId = JournalId;
|
|
}
|
|
|
|
_notifyMgr.AddRef();
|
|
|
|
XInterface<CCiNotifyMgr> xNotify( ¬ifyMgr );
|
|
|
|
if ( volumeId == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
//
|
|
// Enable file system notifications for non-usn volumes
|
|
//
|
|
EnableNotification();
|
|
}
|
|
|
|
xNotify.Acquire();
|
|
} //CCiNotify
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::~CCiNotify
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
// History: 05-07-97 SitaramR Added Header
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiNotify::~CCiNotify()
|
|
{
|
|
_notifyMgr.Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::Abort
|
|
//
|
|
// Synopsis: Marks that an abort is in progress. Also disables further
|
|
// notifications for this scope.
|
|
//
|
|
// History: 1-17-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotify::Abort()
|
|
{
|
|
CLock lock(_notifyMgr.GetMutex());
|
|
_fAbort = TRUE;
|
|
|
|
if ( _volumeId == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
//
|
|
// Notifications are enabled only for those volumes that
|
|
// do not support usns.
|
|
//
|
|
DisableNotification();
|
|
}
|
|
else
|
|
{
|
|
//
|
|
// Ctor of CGenericNotify does an AddRef, which is released by
|
|
// the APC for non-usn volumes. For usn volumes do the Release here.
|
|
//
|
|
Release();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::IsMatch
|
|
//
|
|
// Synopsis: Checks if the given path is within the scope of the notifi-
|
|
// cations. If deep notifications are enabled, it is sufficient
|
|
// for the notification scope to be a subset of the given path.
|
|
// Otherwise, there must be an exact match.
|
|
//
|
|
// Arguments: [wcsPath] - Path to be tested.
|
|
// [len] - Length of wcsPath.
|
|
//
|
|
// Returns: TRUE if there is a match. FALSE o/w
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCiNotify::IsMatch( WCHAR const * wcsPath, ULONG len ) const
|
|
{
|
|
|
|
CScopeMatch match( GetScope(), ScopeLength() );
|
|
return match.IsInScope( wcsPath, len );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::QueryAsyncWorkItem
|
|
//
|
|
// Synopsis: Creates an async work item to process notifications.
|
|
//
|
|
// Arguments: [pbChanges] - Buffer of changes
|
|
// [cbChanges] - Number of bytes in pbChanges
|
|
// [pwcsRoot] - The directory root where the change happened.
|
|
//
|
|
// Returns: A pointer to an async work item
|
|
//
|
|
// History: 1-03-97 srikants Moved from hxx file to use the new
|
|
// CWorkManager.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
CCiAsyncProcessNotify * CCiNotifyMgr::QueryAsyncWorkItem(
|
|
BYTE const * pbChanges,
|
|
ULONG cbChanges,
|
|
WCHAR const * pwcsRoot )
|
|
{
|
|
XArray<BYTE> xChanges( cbChanges );
|
|
RtlCopyMemory( xChanges.GetPointer(), pbChanges, cbChanges );
|
|
|
|
CWorkManager & workMan = _cicat.GetWorkMan();
|
|
|
|
return new CCiAsyncProcessNotify( workMan,
|
|
_cicat,
|
|
_scanMgr,
|
|
xChanges,
|
|
pwcsRoot );
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::DoIt()
|
|
//
|
|
// Synopsis: Called from APC.
|
|
//
|
|
// History: 1-17-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotify::DoIt()
|
|
{
|
|
BOOL fNotifyReEnabled = FALSE; // Indicates if the notification was reenabled
|
|
// successfully
|
|
NTSTATUS status = STATUS_SUCCESS;
|
|
|
|
TRY
|
|
{
|
|
|
|
#if 0
|
|
XPtr<CCiAsyncProcessNotify> xWorker;
|
|
#endif // 0
|
|
|
|
if ( _fAbort )
|
|
ciDebugOut(( DEB_ITRACE, "CiNotification APC: ABORT (IGNORE) 0x%x\n", this ));
|
|
else
|
|
{
|
|
if ( !BufferOverflow() )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "CiNotification APC: CHANGES 0x%x\n", this ));
|
|
#if 0
|
|
xWorker.Set( _notifyMgr.QueryAsyncWorkItem( GetBuf(),
|
|
BufLength(),
|
|
GetScope()) );
|
|
#else
|
|
_notifyMgr.ProcessChanges( GetBuf(),
|
|
GetScope() );
|
|
#endif // 0
|
|
}
|
|
|
|
// ==================================================
|
|
{
|
|
//
|
|
// Re-enable the notification for this scope.
|
|
//
|
|
CLock lock(_notifyMgr.GetMutex());
|
|
StartNotification(&status);
|
|
fNotifyReEnabled = SUCCEEDED(status);
|
|
}
|
|
// ==================================================
|
|
|
|
if ( BufferOverflow() )
|
|
_notifyMgr.SetupScan( GetScope() );
|
|
}
|
|
|
|
#if 0
|
|
if ( 0 != xWorker.GetPointer() )
|
|
{
|
|
_notifyMgr.ProcessChanges( xWorker );
|
|
}
|
|
|
|
#endif // 0
|
|
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
ciDebugOut(( DEB_ERROR, "CiNotification APC: CATCH 0x%x\n", e.GetErrorCode() ));
|
|
status = e.GetErrorCode();
|
|
}
|
|
END_CATCH;
|
|
|
|
if ( !_fAbort && !fNotifyReEnabled )
|
|
{
|
|
LogNotificationsFailed( status );
|
|
|
|
CLock lock( _notifyMgr.GetMutex() );
|
|
LokClearNotifyEnabled();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotify::ClearNotifyEnabled
|
|
//
|
|
// Synopsis: Clears the flag to indicate that notifications are disabled
|
|
// for this scope. This will permit periodic scanning of scopes
|
|
// by the scan thread.
|
|
//
|
|
// History: 5-03-96 srikants Created
|
|
//
|
|
// Notes: The operation must be done under a lock.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotify::ClearNotifyEnabled()
|
|
{
|
|
CLock lock( _notifyMgr.GetMutex() );
|
|
LokClearNotifyEnabled();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CVRootNotify::CVRootNotify, public
|
|
//
|
|
// Synopsis: Constructor for object to watch IIS vroot changes
|
|
//
|
|
// Arguments: [cat] -- Catalog
|
|
// [eType] -- Type of vroot
|
|
// [Instance] -- Instance # of the vserver
|
|
// [notifyMgr] -- Notify manager controller
|
|
//
|
|
// History: 2-20-96 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CVRootNotify::CVRootNotify(
|
|
CiCat & cat,
|
|
CiVRootTypeEnum eType,
|
|
ULONG Instance,
|
|
CCiNotifyMgr & notifyMgr )
|
|
: _type( eType ),
|
|
_cat( cat ),
|
|
_notifyMgr( notifyMgr ),
|
|
_mdMgr( FALSE, eType, Instance )
|
|
{
|
|
_mdMgr.EnableVPathNotify( this );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CRegistryScopesNotify::CRegistryScopesNotify
|
|
//
|
|
// Synopsis: Constructor for object to watch ci scopes
|
|
//
|
|
// Arguments: [cat] -- Catalog
|
|
//
|
|
// History: 10-16-96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRegistryScopesNotify::CRegistryScopesNotify(
|
|
CiCat & cat,
|
|
CCiNotifyMgr & notifyMgr )
|
|
: _cat( cat ),
|
|
_notifyMgr( notifyMgr ),
|
|
CRegNotify( cat.GetScopesKey() )
|
|
{
|
|
_notifyMgr.AddRef();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiRegistryNotify::CCiRegistryNotify
|
|
//
|
|
// Synopsis: Constructor for the CCiRegistryNotify.
|
|
//
|
|
// Arguments: [cat] -
|
|
// [notifyMgr] -
|
|
//
|
|
// History: 12-12-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiRegistryNotify::CCiRegistryNotify(
|
|
CiCat & cat,
|
|
CCiNotifyMgr & notifyMgr )
|
|
: _cat( cat ),
|
|
_notifyMgr( notifyMgr ),
|
|
CRegNotify( wcsRegAdminTree )
|
|
{
|
|
_notifyMgr.AddRef();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CVRootNotify::DisableNotification, public
|
|
//
|
|
// Synopsis: Turns off notifications (if on )
|
|
//
|
|
// History: 2-13-97 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CVRootNotify::DisableNotification()
|
|
{
|
|
// Need TRY since RPC may access violate if iisadmin has gone down
|
|
|
|
TRY
|
|
{
|
|
_mdMgr.DisableVPathNotify();
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"CVRootNotify::DisableNotification caught exception 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CRegistryScopesNotify::~CRegistryScopesNotify
|
|
//
|
|
// Synopsis: Destructor.
|
|
//
|
|
// History: 10-16-96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CRegistryScopesNotify::~CRegistryScopesNotify()
|
|
{
|
|
_notifyMgr.Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiRegistryNotify::~CCiRegistryNotify
|
|
//
|
|
// Synopsis: Destructor
|
|
//
|
|
// History: 12-12-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
CCiRegistryNotify::~CCiRegistryNotify()
|
|
{
|
|
_notifyMgr.Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CVRootNotify::CallBack, public
|
|
//
|
|
// Synopsis: Callback from metabase connection point
|
|
//
|
|
// Arguments: [fCancel] -- If TRUE, iisadmin is going down, so cancel
|
|
// notifications and poll for it to come back up.
|
|
//
|
|
// History: 2-20-96 KyleP Created
|
|
// 2-13-97 dlee Updated for metabase
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
SCODE CVRootNotify::CallBack( BOOL fCancel )
|
|
{
|
|
if ( fCancel )
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"Scheduling worker for '%ws' shutdown...\n",
|
|
GetVRootService( _type ) ));
|
|
|
|
_notifyMgr.CancelIISVRootNotify( _type );
|
|
|
|
// note: we may be deleted by now, don't access private data
|
|
}
|
|
else
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"Scheduling worker thread for VRoot registry change...\n" ));
|
|
|
|
CWorkManager & workMan = _cat.GetWorkMan();
|
|
XInterface<CIISVRootAsyncNotify> xNotify(
|
|
new CIISVRootAsyncNotify( _cat, workMan ) );
|
|
|
|
workMan.AddToWorkList( xNotify.GetPointer() );
|
|
xNotify->AddToWorkQueue();
|
|
}
|
|
|
|
return S_OK;
|
|
} //CallBack
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CRegistryScopesNotify::DoIt, public
|
|
//
|
|
// Synopsis: Callback from APC
|
|
//
|
|
// History: 10-16-96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CRegistryScopesNotify::DoIt()
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"Scheduling worker thread for RegistryScopes registry change...\n" ));
|
|
|
|
CWorkManager & workMan = _cat.GetWorkMan();
|
|
|
|
CRegistryScopesAsyncNotify * pNotify = new CRegistryScopesAsyncNotify(_cat, workMan);
|
|
workMan.AddToWorkList( pNotify );
|
|
|
|
pNotify->AddToWorkQueue();
|
|
pNotify->Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiRegistryNotify::DoIt
|
|
//
|
|
// Synopsis: Refreshes the registry parameters
|
|
//
|
|
// History: 12-12-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiRegistryNotify::DoIt()
|
|
{
|
|
//
|
|
// We don't need a worker thread to do this because it is very
|
|
// quick and simple.
|
|
//
|
|
_cat.RefreshRegistryParams();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::CCiNotifyMgr
|
|
//
|
|
// Synopsis: ctor of the CI notification manager.
|
|
//
|
|
// Arguments: [cicat] - Catalog
|
|
// [scanMgr] - Scan thread manager
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiNotifyMgr::CCiNotifyMgr( CiCat & cicat, CCiScanMgr & scanMgr )
|
|
: _cicat(cicat),
|
|
_scanMgr(scanMgr),
|
|
_nUpdates(0),
|
|
_fAbort(FALSE),
|
|
_evtType(eNone),
|
|
_pRegistryScopesNotify(0),
|
|
_fIISAdminAlive( TRUE ),
|
|
_fTrackW3Svc( FALSE ),
|
|
_fTrackNNTPSvc( FALSE ),
|
|
_fTrackIMAPSvc( FALSE ),
|
|
_W3SvcInstance( 1 ),
|
|
_NNTPSvcInstance( 1 ),
|
|
_IMAPSvcInstance( 1 ),
|
|
_pCiRegistryNotify(0),
|
|
#pragma warning( disable : 4355 ) // this used in base initialization
|
|
_thrNotify( NotifyThread, this, TRUE ) // create suspended
|
|
#pragma warning( default : 4355 )
|
|
{
|
|
_evt.Reset();
|
|
|
|
RtlZeroMemory( &_ftLastNetPathScan, sizeof(_ftLastNetPathScan) );
|
|
|
|
_thrNotify.SetPriority( THREAD_PRIORITY_ABOVE_NORMAL );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::~CCiNotifyMgr
|
|
//
|
|
// Synopsis: dtor of the CI notification manager.
|
|
//
|
|
// History: 17 Dec 1997 AlanW Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
CCiNotifyMgr::~CCiNotifyMgr( )
|
|
{
|
|
// Be sure the thread will die...
|
|
if (_thrNotify.IsRunning())
|
|
_KillThread();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::TrackIISVRoots
|
|
//
|
|
// Synopsis: Registers for notification of VRoot registry changes
|
|
//
|
|
// Arguments: [fTrackW3Svc] -- TRUE if W3 should be tracked
|
|
// [W3SvcInstance] -- W3 instance # to be tracked.
|
|
// [fTrackNNTPSvc] -- TRUE if NNTP should be tracked
|
|
// [NNTPSvcInstance] -- NNTP instance # to be tracked.
|
|
// [fTrackIMAPSvc] -- TRUE if IMAP should be tracked
|
|
// [IMAPSvcInstance] -- IMAP instance # to be tracked.
|
|
//
|
|
// History: 2-21-96 KyleP Created
|
|
// 2-13-97 dlee converted to metabase
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::TrackIISVRoots(
|
|
BOOL fTrackW3Svc,
|
|
ULONG W3SvcInstance,
|
|
BOOL fTrackNNTPSvc,
|
|
ULONG NNTPSvcInstance,
|
|
BOOL fTrackIMAPSvc,
|
|
ULONG IMAPSvcInstance )
|
|
{
|
|
CLock lock(_mutex);
|
|
Win4Assert( _xW3SvcVRootNotify.IsNull() );
|
|
Win4Assert( _xNNTPSvcVRootNotify.IsNull() );
|
|
Win4Assert( _xIMAPSvcVRootNotify.IsNull() );
|
|
|
|
_fTrackW3Svc = fTrackW3Svc;
|
|
_W3SvcInstance = W3SvcInstance;
|
|
_fTrackNNTPSvc = fTrackNNTPSvc;
|
|
_NNTPSvcInstance = NNTPSvcInstance;
|
|
_fTrackIMAPSvc = fTrackIMAPSvc;
|
|
_IMAPSvcInstance = IMAPSvcInstance;
|
|
|
|
_evtType |= eWatchIISVRoots;
|
|
_evt.Set();
|
|
} //TrackIISVRoots
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::TrackScopesInRegistry
|
|
//
|
|
// Synopsis: Registers for notification of scope registry changes
|
|
//
|
|
// History: 10/17/96 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::TrackScopesInRegistry()
|
|
{
|
|
CLock lock(_mutex);
|
|
Win4Assert( 0 == _pRegistryScopesNotify );
|
|
|
|
_evtType |= eWatchRegistryScopes;
|
|
_evt.Set();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::TrackCiRegistry
|
|
//
|
|
// Synopsis: Registers for notifications of CI registry changes.
|
|
//
|
|
// History: 12-12-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::TrackCiRegistry()
|
|
{
|
|
CLock lock(_mutex);
|
|
Win4Assert( 0 == _pCiRegistryNotify );
|
|
|
|
_evtType |= eWatchCiRegistry;
|
|
_evt.Set();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::CancelIISVRootNotify
|
|
//
|
|
// Synopsis: Cancels notifications on iisadmin since it's going down
|
|
//
|
|
// History: 2-13-97 dlee Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::CancelIISVRootNotify( CiVRootTypeEnum eType )
|
|
{
|
|
// after this, we'll poll for the iisadmin svc to start again
|
|
|
|
CLock lock( _mutex );
|
|
|
|
if ( W3VRoot == eType )
|
|
_evtType |= eUnWatchW3VRoots;
|
|
else if ( NNTPVRoot == eType )
|
|
_evtType |= eUnWatchNNTPVRoots;
|
|
else if ( IMAPVRoot == eType )
|
|
_evtType |= eUnWatchIMAPVRoots;
|
|
else
|
|
{
|
|
Win4Assert( !"invalid IIS vroot notify type!" );
|
|
}
|
|
|
|
_evt.Set();
|
|
} //CancelIISVRootNotify
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::LokUnWatchIISVServerNoThrow
|
|
//
|
|
// Synopsis: Turns off notifications on W3, NNTP, or IMAP
|
|
//
|
|
// History: 2-Sep-97 dlee created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::LokUnWatchIISVServerNoThrow(
|
|
CVRootNotify * pNotify )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "LokUnWatchIISVServer\n" ));
|
|
|
|
TRY
|
|
{
|
|
delete pNotify;
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
_fIISAdminAlive = FALSE;
|
|
ciDebugOut(( DEB_WARN,
|
|
"caught exception while tearing down IIS tracking\n" ));
|
|
}
|
|
END_CATCH;
|
|
} //LokUnWatchIISVServerNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::LokWatchIISVServerNoThrow
|
|
//
|
|
// Synopsis: Registers for notification of IIS VRoot changes
|
|
//
|
|
// History: 2-21-96 KyleP Created
|
|
// 2-13-97 dlee converted to metabase
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::LokWatchIISVServerNoThrow()
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"LokWatchIISVServer w3 %d:%d, nntp %d:%d, imap %d:%d\n",
|
|
_fTrackW3Svc,
|
|
_W3SvcInstance,
|
|
_fTrackNNTPSvc,
|
|
_NNTPSvcInstance,
|
|
_fTrackIMAPSvc,
|
|
_IMAPSvcInstance ));
|
|
|
|
Win4Assert( _fTrackW3Svc || _fTrackNNTPSvc || _fTrackIMAPSvc );
|
|
|
|
//
|
|
// If iisadmin isn't running and it wasn't running before, don't
|
|
// ping the metabase. Doing a CoCreateInstance() on the metabase
|
|
// object when iisadmin is disabled results in a DCOM error in
|
|
// the eventlog. Since we check every 5 minutes this can fill
|
|
// the log.
|
|
//
|
|
|
|
if ( !_fIISAdminAlive )
|
|
{
|
|
if ( ! IsServiceRunning( L"iisadmin" ) )
|
|
return;
|
|
}
|
|
|
|
// Assume iisadmin is alive and we can get notifications
|
|
|
|
BOOL fWasAlive = _fIISAdminAlive;
|
|
|
|
_fIISAdminAlive = TRUE;
|
|
|
|
TRY
|
|
{
|
|
if ( _fTrackW3Svc && _xW3SvcVRootNotify.IsNull() )
|
|
_xW3SvcVRootNotify.Set( new CVRootNotify( _cicat,
|
|
W3VRoot,
|
|
_W3SvcInstance,
|
|
*this ) );
|
|
|
|
if ( _fTrackNNTPSvc && _xNNTPSvcVRootNotify.IsNull() )
|
|
_xNNTPSvcVRootNotify.Set( new CVRootNotify( _cicat,
|
|
NNTPVRoot,
|
|
_NNTPSvcInstance,
|
|
*this ) );
|
|
|
|
if ( _fTrackIMAPSvc && _xIMAPSvcVRootNotify.IsNull() )
|
|
_xIMAPSvcVRootNotify.Set( new CVRootNotify( _cicat,
|
|
IMAPVRoot,
|
|
_IMAPSvcInstance,
|
|
*this ) );
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
_fIISAdminAlive = FALSE;
|
|
ciDebugOut(( DEB_WARN,
|
|
"caught exception while setting up iis tracking\n" ));
|
|
}
|
|
END_CATCH;
|
|
|
|
// did we miss notifications but can catch up now?
|
|
|
|
if ( !fWasAlive && _fIISAdminAlive )
|
|
{
|
|
TRY
|
|
{
|
|
ciDebugOut(( DEB_WARN, "Polling IIS: iisadmin woke up\n" ));
|
|
|
|
CWorkManager & workMan = _cicat.GetWorkMan();
|
|
|
|
XInterface<CIISVRootAsyncNotify> xNotify(
|
|
new CIISVRootAsyncNotify( _cicat, workMan ) );
|
|
|
|
workMan.AddToWorkList( xNotify.GetPointer() );
|
|
xNotify->AddToWorkQueue();
|
|
}
|
|
CATCH(CException, e)
|
|
{
|
|
ciDebugOut(( DEB_WARN,
|
|
"caught exception while setting up iis enumeration\n" ));
|
|
|
|
// try again after the timeout
|
|
|
|
_fIISAdminAlive = FALSE;
|
|
}
|
|
END_CATCH;
|
|
}
|
|
} //LokWatchIISVServerNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::LokWatchRegistryScopesNoThrow
|
|
//
|
|
// Synopsis: Registers for notification of RegistryScopes registry changes
|
|
//
|
|
// History: 2-21-96 KyleP Created
|
|
//
|
|
// Notes: This must be done from thread waiting in alertable mode
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::LokWatchRegistryScopesNoThrow()
|
|
{
|
|
TRY
|
|
{
|
|
Win4Assert( 0 == _pRegistryScopesNotify );
|
|
_pRegistryScopesNotify = new CRegistryScopesNotify( _cicat, *this );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "_LokWatchRegistryScopesNoThrow caught 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
} //LokWatchRegistryScopesNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::LokWatchCiRegistryNoThrow
|
|
//
|
|
// Synopsis: Watches for changes in CI registry.
|
|
//
|
|
// History: 12-12-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
|
|
void CCiNotifyMgr::LokWatchCiRegistryNoThrow()
|
|
{
|
|
TRY
|
|
{
|
|
Win4Assert( 0 == _pCiRegistryNotify );
|
|
_pCiRegistryNotify = new CCiRegistryNotify( _cicat, *this );
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "_LokWatchCiRegistryNoThrow caught 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
} //LokWatchCiRegistryNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::_KillThread
|
|
//
|
|
// Synopsis: Asks the notification thread to die and waits for its death.
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::_KillThread()
|
|
{
|
|
{
|
|
CLock lock(_mutex);
|
|
_evtType |= eKillThread;
|
|
_evt.Set();
|
|
}
|
|
|
|
ciDebugOut(( DEB_ITRACE, "Waiting for death of notify thread\n" ));
|
|
_thrNotify.WaitForDeath();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::Shutdown
|
|
//
|
|
// Synopsis: Shut down notification thread.
|
|
//
|
|
// History: 1-30-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::WaitForShutdown()
|
|
{
|
|
//
|
|
// If we never started running, then just bail out.
|
|
//
|
|
|
|
if ( _thrNotify.IsRunning() )
|
|
{
|
|
//
|
|
// must wait until all the APCs are aborted.
|
|
//
|
|
_refCount.Wait();
|
|
|
|
//
|
|
// Kill the notification thread.
|
|
//
|
|
_KillThread();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::InitiateShutdown
|
|
//
|
|
// Synopsis: Turns off notifications
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::InitiateShutdown()
|
|
{
|
|
{
|
|
CLock lock(_mutex);
|
|
_fAbort = TRUE;
|
|
}
|
|
|
|
//
|
|
// Abort registry notification (if any)
|
|
//
|
|
|
|
if ( !_xW3SvcVRootNotify.IsNull() )
|
|
{
|
|
_xW3SvcVRootNotify->DisableNotification();
|
|
_xW3SvcVRootNotify.Free();
|
|
}
|
|
|
|
if ( !_xNNTPSvcVRootNotify.IsNull() )
|
|
{
|
|
_xNNTPSvcVRootNotify->DisableNotification();
|
|
_xNNTPSvcVRootNotify.Free();
|
|
}
|
|
|
|
if ( !_xIMAPSvcVRootNotify.IsNull() )
|
|
{
|
|
_xIMAPSvcVRootNotify->DisableNotification();
|
|
_xIMAPSvcVRootNotify.Free();
|
|
}
|
|
|
|
// these are refcounted and needn't be freed
|
|
|
|
if ( 0 != _pRegistryScopesNotify )
|
|
_pRegistryScopesNotify->DisableNotification();
|
|
|
|
if ( 0 != _pCiRegistryNotify )
|
|
_pCiRegistryNotify->DisableNotification();
|
|
|
|
//
|
|
// Abort all the notifications and the APCs queued for that.
|
|
//
|
|
{
|
|
CLock lock(_mutex);
|
|
|
|
for ( CCiNotify * pNotify = _list.Pop();
|
|
0 != pNotify;
|
|
pNotify = _list.Pop() )
|
|
{
|
|
pNotify->Close();
|
|
pNotify->Abort();
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::_LokTellThreadToAddScope
|
|
//
|
|
// Synopsis: Sets the event type to add a scope for notifications and
|
|
// wakes up the notification thread.
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::_LokTellThreadToAddScope()
|
|
{
|
|
if ( 0 == (eKillThread & _evtType) )
|
|
{
|
|
_evtType |= eAddScopes;
|
|
_evt.Set();
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::AddPath
|
|
//
|
|
// Synopsis: Adds a scope for ci notifications. If the given scope (wcsScope)
|
|
// is a superset of any existing scopes, they are removed from
|
|
// the notification list.
|
|
//
|
|
// Arguments: [wcsScope] - Scope to be added.
|
|
// [fSubscopesRemoved] - Set to TRUE if sub-scopes of wcsScope
|
|
// were removed as a result of adding wcsScope.
|
|
// [volumeId] - Volume id
|
|
// [ftLastScan] - Last scan time
|
|
// [usn] - Usn
|
|
//
|
|
// History: 1-17-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::AddPath( CScopeInfo const & scopeInfo, BOOL & fSubscopesRemoved )
|
|
{
|
|
fSubscopesRemoved = FALSE;
|
|
|
|
//
|
|
// Allocate storage for the string and terminate it with the
|
|
// backslash character.
|
|
//
|
|
|
|
ULONG len = wcslen( scopeInfo.GetPath() );
|
|
if ( L'\\' != scopeInfo.GetPath()[len-1] )
|
|
len++;
|
|
|
|
Win4Assert( len < MAX_PATH );
|
|
|
|
XArray<WCHAR> xPath(len+1);
|
|
WCHAR * pwcsPath = xPath.Get();
|
|
|
|
wcscpy( pwcsPath, scopeInfo.GetPath() );
|
|
pwcsPath[len-1] = L'\\';
|
|
pwcsPath[len] = 0;
|
|
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// First see if notifications are already enabled on this path
|
|
// in some other scope.
|
|
//
|
|
|
|
for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
|
|
{
|
|
if (iter1->IsMatch( pwcsPath, len ) )
|
|
{
|
|
Win4Assert( iter1->VolumeId() == scopeInfo.VolumeId() );
|
|
|
|
//
|
|
// there is an entry for this scope already. Just enable/start
|
|
// the notification if not already done so.
|
|
//
|
|
if ( iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
|
|
iter1->LokEnableIf();
|
|
|
|
return;
|
|
}
|
|
}
|
|
|
|
//
|
|
// We have to create a new notification object for this scope.
|
|
//
|
|
|
|
XPtr<CScopeInfo> xScopeInfo;
|
|
|
|
if ( CI_VOLID_USN_NOT_ENABLED == scopeInfo.VolumeId() )
|
|
xScopeInfo.Set( new CScopeInfo( xPath,
|
|
scopeInfo.VolumeCreationTime(),
|
|
scopeInfo.VolumeSerialNumber(),
|
|
scopeInfo.GetLastScanTime() ) );
|
|
else
|
|
xScopeInfo.Set( new CScopeInfo( xPath,
|
|
scopeInfo.VolumeCreationTime(),
|
|
scopeInfo.VolumeSerialNumber(),
|
|
scopeInfo.VolumeId(),
|
|
scopeInfo.Usn(),
|
|
scopeInfo.JournalId(),
|
|
scopeInfo.FUsnTreeScan() ) );
|
|
|
|
_stkScopes.Push( xScopeInfo.GetPointer() );
|
|
xScopeInfo.Acquire();
|
|
|
|
//
|
|
// If the new path is going to be a superset of the existing paths,
|
|
// they must be removed.
|
|
//
|
|
CScopeMatch superScope( pwcsPath, len );
|
|
|
|
for ( CFwdCiNotifyIter iter2(_list); !_list.AtEnd(iter2); )
|
|
{
|
|
CCiNotify * pNotify = iter2.GetEntry();
|
|
_list.Advance(iter2);
|
|
|
|
//
|
|
// See if the current node is a subset of the new path.
|
|
// If so, remove the current node from the list.
|
|
//
|
|
if ( superScope.IsInScope( pNotify->GetScope(), pNotify->ScopeLength()) )
|
|
{
|
|
fSubscopesRemoved = TRUE;
|
|
pNotify->LokRemove();
|
|
}
|
|
}
|
|
|
|
//
|
|
// Wake up the notification thread to add this scope.
|
|
//
|
|
_LokTellThreadToAddScope();
|
|
} //AddPath
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::GetLastScanTime
|
|
//
|
|
// Synopsis: Gets the time of the last successful scan for the given scope.
|
|
//
|
|
// Arguments: [wcsScope] - Scope to check. If there is no entry for the
|
|
// given scope, the time of the last successful scan of the
|
|
// super scope of wcsScope will be returned.
|
|
// [ft] - The filetime of the last successful scan
|
|
// encompassing the given scope.
|
|
//
|
|
// Returns: TRUE if found; FALSE o/w. In case FALSE is returned, ft will
|
|
// be zero filled.
|
|
//
|
|
// History: 4-19-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCiNotifyMgr::GetLastScanTime( WCHAR const * wcsScope, FILETIME & ft )
|
|
{
|
|
|
|
RtlZeroMemory( &ft, sizeof(FILETIME) );
|
|
Win4Assert( 0 != wcsScope );
|
|
|
|
ULONG len = wcslen( wcsScope );
|
|
Win4Assert( L'\\' == wcsScope[len-1] );
|
|
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// Look for a scope which encompasses the given scope.
|
|
//
|
|
|
|
for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
|
|
{
|
|
if (iter1->IsMatch( wcsScope, len ) )
|
|
{
|
|
ft = iter1->GetLastScanTime();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::UpdateLastScanTimes
|
|
//
|
|
// Synopsis: Updates the last scan time of all the paths that have
|
|
// notifications enabled to the time given.
|
|
//
|
|
// Arguments: [ft] - Last successful scan time (all updates until this time
|
|
// are known for all the scopes with notifications enabled).
|
|
// [usnFlushInfoList] - Usn info list
|
|
//
|
|
// History: 4-21-96 srikants Created
|
|
// 05-07-97 SitaramR Usns
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::UpdateLastScanTimes( FILETIME const & ft,
|
|
CUsnFlushInfoList & usnFlushInfoList )
|
|
{
|
|
CLock lock(_mutex);
|
|
|
|
for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
|
|
{
|
|
if ( iter1->LokIsNotifyEnabled() && iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
if ( ft.dwLowDateTime != 0 || ft.dwHighDateTime != 0 )
|
|
iter1->SetLastScanTime( ft );
|
|
}
|
|
else if ( iter1->VolumeId() != CI_VOLID_USN_NOT_ENABLED
|
|
&& !iter1->FUsnTreeScan() )
|
|
{
|
|
//
|
|
// If an usn tree traversal is going on, then we shouldn't move the usn
|
|
// watermark because if there is a crash now, then we should
|
|
// restart the usn tree traversal from usn 0.
|
|
//
|
|
|
|
USN usnCurrent = usnFlushInfoList.GetUsn( iter1->VolumeId() );
|
|
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"CCiNotifyMgr::UpdateLastScanTimes drive %wc, old %#I64x, current %#I64x\n",
|
|
(WCHAR) iter1->VolumeId(),
|
|
iter1->Usn(),
|
|
usnCurrent ));
|
|
|
|
if ( usnCurrent != 0 && usnCurrent > iter1->Usn() )
|
|
{
|
|
//
|
|
// Win4Assert( usnCurrent >= iter1->Usn() );
|
|
//
|
|
// We cannot assert the above because after the initial usn tree
|
|
// scan is done, the maxUsn is written to iter1 (CiCat::SetUsnTreeComplete),
|
|
// and there can be usn notifications prior to usn tree scan, i.e. there can
|
|
// be usn's less than maxUsn.
|
|
//
|
|
|
|
iter1->SetUsn( usnCurrent );
|
|
}
|
|
}
|
|
}
|
|
} //UpdateLastScanTimes
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::ForceNetPathScansIf
|
|
//
|
|
// Synopsis: Forces the scan of network paths with no notifications if
|
|
// the interval for such scans has expired.
|
|
//
|
|
// History: 4-21-96 srikants Created
|
|
//
|
|
// Notes: If the remote machine is running networking software without
|
|
// notifications, we have to periodically scan for changes. This
|
|
// method identifies such paths and schedules scans for them if
|
|
// the minimum interval has expired since the last such scan.
|
|
//
|
|
// THIS METHOD MUST BE CALLED ONLY FROM THE SCAN THREAD. IT IS
|
|
// CALLED WHEN THE SCAN THREAD HAS DETECTED THAT THERE ARE NO
|
|
// OUTSTANDING SCANS AND SO IS A GOOD TIME TO SCAN NET PATHS.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::ForceNetPathScansIf()
|
|
{
|
|
CLock lock(_mutex);
|
|
|
|
Win4Assert( sizeof(FILETIME) == sizeof(LONGLONG) );
|
|
|
|
LONGLONG ftZero;
|
|
RtlZeroMemory( &ftZero, sizeof(ftZero) );
|
|
|
|
LONGLONG ftNow;
|
|
GetSystemTimeAsFileTime( (FILETIME *) &ftNow );
|
|
|
|
if ( 0 == CompareFileTime( (FILETIME *) &_ftLastNetPathScan,
|
|
(FILETIME *) &ftZero ) )
|
|
{
|
|
//
|
|
// We havent't yet started tracking the interval. Just initialize
|
|
// the _ftLastNetPathScan to the current time.
|
|
//
|
|
_ftLastNetPathScan = ftNow;
|
|
return;
|
|
}
|
|
|
|
if ( ftNow < _ftLastNetPathScan )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "Time has been set back\n" ));
|
|
_ftLastNetPathScan = ftNow;
|
|
return;
|
|
}
|
|
|
|
//
|
|
// See if the interval for force scans has exceeded.
|
|
//
|
|
//
|
|
// Compute the interval in 100 nanosecond interval
|
|
//
|
|
const LONGLONG llInterval =
|
|
_cicat.GetRegParams()->GetForcedNetPathScanInterval() * 60 * 1000 * 10000;
|
|
|
|
if ( ftNow - _ftLastNetPathScan >= llInterval )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE, "Forcing scan of net paths with no notifcations\n" ));
|
|
_LokForceScanNetPaths();
|
|
|
|
//
|
|
// Reset the last scan time for network paths.
|
|
//
|
|
RtlZeroMemory( &_ftLastNetPathScan, sizeof(_ftLastNetPathScan) );
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::_LokForceScanNetPaths
|
|
//
|
|
// Synopsis: Forces incremental scans of net paths with no notifications.
|
|
//
|
|
// History: 4-21-96 srikants Created
|
|
//
|
|
// Notes: This method must be called only in the context of the scan
|
|
// thread.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::_LokForceScanNetPaths()
|
|
{
|
|
for ( CFwdCiNotifyIter iter1(_list); !_list.AtEnd(iter1); _list.Advance(iter1) )
|
|
{
|
|
if ( !iter1->LokIsNotifyEnabled() && iter1->VolumeId() == CI_VOLID_USN_NOT_ENABLED )
|
|
{
|
|
//
|
|
// Usn paths have their notifications disabled, but they should not be scanned
|
|
//
|
|
ciDebugOut(( DEB_WARN,
|
|
"Forcing an incremental scan of path (%ws)\n",
|
|
iter1->GetScope() ));
|
|
_cicat.ReScanPath( iter1->GetScope(), FALSE );
|
|
}
|
|
}
|
|
} //_LokForceScanNetPaths
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::_LokAddScopesNoThrow
|
|
//
|
|
// Synopsis: Takes scopes from the stack and enables notifications for
|
|
// those scopes.
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::_LokAddScopesNoThrow()
|
|
{
|
|
TRY
|
|
{
|
|
for ( unsigned i = 0; i < _stkScopes.Count(); i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *_stkScopes.Get(i);
|
|
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
WCHAR const * pwcsPath = scopeInfo.GetPath();
|
|
|
|
CCiNotify * pNotify = new CCiNotify( *this,
|
|
pwcsPath,
|
|
wcslen(pwcsPath),
|
|
scopeInfo.VolumeId(),
|
|
scopeInfo.VolumeCreationTime(),
|
|
scopeInfo.VolumeSerialNumber(),
|
|
scopeInfo.GetLastScanTime(),
|
|
scopeInfo.Usn(),
|
|
scopeInfo.JournalId(),
|
|
scopeInfo.FUsnTreeScan() );
|
|
|
|
//
|
|
// Acquire the path as a sign that we shouldn't try to use it
|
|
// again to add another notification object.
|
|
//
|
|
|
|
delete [] scopeInfo.AcquirePath();
|
|
|
|
_list.Push( pNotify );
|
|
}
|
|
|
|
// empty the stack now
|
|
|
|
while ( _stkScopes.Count() > 0 )
|
|
{
|
|
_stkScopes.DeleteTop();
|
|
}
|
|
}
|
|
CATCH( CException, e )
|
|
{
|
|
ciDebugOut(( DEB_WARN, "_LokAddScopesNoThrow caught 0x%x\n",
|
|
e.GetErrorCode() ));
|
|
}
|
|
END_CATCH
|
|
} //_LokAddScopesNoThrow
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::_DoNotifications
|
|
//
|
|
// Synopsis: The thread which is responsible for adding notification scopes
|
|
// and processing the notifications. The notification APC will
|
|
// execute in this thread's context.
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::_DoNotifications()
|
|
{
|
|
while ( TRUE )
|
|
{
|
|
//
|
|
// Don't do any work until the system has booted
|
|
//
|
|
|
|
while ( GetTickCount() < _cicat.GetRegParams()->GetStartupDelay() )
|
|
{
|
|
Sleep( 200 );
|
|
if ( _fAbort )
|
|
break;
|
|
}
|
|
|
|
BOOL fWait = FALSE;
|
|
|
|
CVRootNotify * pW3Notify = 0;
|
|
CVRootNotify * pNNTPNotify = 0;
|
|
CVRootNotify * pIMAPNotify = 0;
|
|
|
|
// ++++++++++++++++ lock obtained +++++++++++++++++++
|
|
{
|
|
CLock lock(_mutex);
|
|
_evt.Reset();
|
|
|
|
Win4Assert( 0 == ( _evtType &
|
|
~(eKillThread|eAddScopes|eWatchIISVRoots|
|
|
eWatchRegistryScopes|eWatchCiRegistry|eUnWatchW3VRoots|
|
|
eUnWatchNNTPVRoots|eUnWatchIMAPVRoots)) );
|
|
|
|
if ( eKillThread & _evtType )
|
|
return;
|
|
|
|
if ( _fAbort )
|
|
{
|
|
_evtType = eNone;
|
|
}
|
|
else
|
|
{
|
|
if ( eAddScopes & _evtType )
|
|
{
|
|
_LokAddScopesNoThrow();
|
|
_evtType &= ~eAddScopes;
|
|
}
|
|
|
|
if ( eWatchIISVRoots & _evtType )
|
|
{
|
|
LokWatchIISVServerNoThrow();
|
|
_evtType &= ~eWatchIISVRoots;
|
|
}
|
|
|
|
if ( eUnWatchW3VRoots & _evtType )
|
|
{
|
|
pW3Notify = _xW3SvcVRootNotify.Acquire();
|
|
_evtType &= ~eUnWatchW3VRoots;
|
|
}
|
|
|
|
if ( eUnWatchNNTPVRoots & _evtType )
|
|
{
|
|
pNNTPNotify = _xNNTPSvcVRootNotify.Acquire();
|
|
_evtType &= ~eUnWatchNNTPVRoots;
|
|
}
|
|
|
|
if ( eUnWatchIMAPVRoots & _evtType )
|
|
{
|
|
pIMAPNotify = _xIMAPSvcVRootNotify.Acquire();
|
|
_evtType &= ~eUnWatchIMAPVRoots;
|
|
}
|
|
|
|
if ( eWatchRegistryScopes & _evtType )
|
|
{
|
|
LokWatchRegistryScopesNoThrow();
|
|
_evtType &= ~eWatchRegistryScopes;
|
|
}
|
|
|
|
if ( eWatchCiRegistry & _evtType )
|
|
{
|
|
LokWatchCiRegistryNoThrow();
|
|
_evtType &= ~eWatchCiRegistry;
|
|
}
|
|
}
|
|
|
|
fWait = ( eNone == _evtType );
|
|
}
|
|
// ---------------- lock released --------------------
|
|
|
|
//
|
|
// Free these without holding the lock to avoid a deadlock
|
|
// with iisadmin.
|
|
//
|
|
|
|
if ( 0 != pW3Notify )
|
|
LokUnWatchIISVServerNoThrow( pW3Notify );
|
|
|
|
if ( 0 != pNNTPNotify )
|
|
LokUnWatchIISVServerNoThrow( pNNTPNotify );
|
|
|
|
if ( 0 != pIMAPNotify )
|
|
LokUnWatchIISVServerNoThrow( pIMAPNotify );
|
|
|
|
//
|
|
// If we're not watching, turn the flag off
|
|
//
|
|
|
|
if ( _xW3SvcVRootNotify.IsNull() &&
|
|
_xNNTPSvcVRootNotify.IsNull() &&
|
|
_xIMAPSvcVRootNotify.IsNull() )
|
|
_fIISAdminAlive = FALSE;
|
|
|
|
if ( fWait )
|
|
{
|
|
const DWORD dwFiveMinutes = 1000 * 60 * 5;
|
|
|
|
DWORD dwWait = ( ( !_fIISAdminAlive ) &&
|
|
( _fTrackW3Svc || _fTrackNNTPSvc || _fTrackIMAPSvc ) ) ?
|
|
dwFiveMinutes : INFINITE;
|
|
|
|
// TRUE: important to get APCs
|
|
|
|
ULONG res = _evt.Wait( dwWait, TRUE );
|
|
|
|
if ( WAIT_TIMEOUT == res )
|
|
{
|
|
// try again to talk to the iisadmin svc
|
|
|
|
CLock lock( _mutex );
|
|
_evtType |= eWatchIISVRoots;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::NotifyThread
|
|
//
|
|
// Arguments: [self] -
|
|
//
|
|
// History: 1-18-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
DWORD CCiNotifyMgr::NotifyThread( void * self )
|
|
{
|
|
SCODE sc = CoInitializeEx( 0, COINIT_MULTITHREADED );
|
|
|
|
((CCiNotifyMgr *) self)->_DoNotifications();
|
|
|
|
CoUninitialize();
|
|
|
|
ciDebugOut(( DEB_ITRACE, "Terminating notify thread\n" ));
|
|
|
|
//
|
|
// This is only necessary if thread is terminated from DLL_PROCESS_DETACH.
|
|
//
|
|
//TerminateThread( ((CCiNotifyMgr *) self)->_thrNotify.GetHandle(), 0 );
|
|
|
|
return 0;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::ProcessChanges
|
|
//
|
|
// Synopsis: Processes the changes to files.
|
|
//
|
|
// Arguments: [changes] -
|
|
//
|
|
// History: 1-17-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::ProcessChanges( XPtr<CCiAsyncProcessNotify> & xWorker )
|
|
{
|
|
CWorkManager & workMan = _cicat.GetWorkMan();
|
|
|
|
workMan.AddToWorkList( xWorker.GetPointer() );
|
|
CCiAsyncProcessNotify *pAsyncNotify = xWorker.Acquire();
|
|
|
|
#if 0
|
|
//
|
|
// NTRAID#DB-NTBUG9-83784-2000/07/31-dlee FAT notifications don't use APCs -- they are handled by the notification thread
|
|
// There is a problem with lockups in NT. Until we figure
|
|
// that out, don't use worker threads. Just process the notifications
|
|
// in-line in the notification thread.
|
|
//
|
|
pAsyncNotify->AddToWorkQueue();
|
|
#else
|
|
pAsyncNotify->DoIt( 0 );
|
|
#endif
|
|
|
|
pAsyncNotify->Release();
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::ProcessChanges
|
|
//
|
|
// Synopsis:
|
|
//
|
|
// Arguments: [pbChanges] -
|
|
// [wcsScope] -
|
|
//
|
|
// Returns:
|
|
//
|
|
// Modifies:
|
|
//
|
|
// History: 3-07-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::ProcessChanges( BYTE const * pbChanges,
|
|
WCHAR const * wcsScope )
|
|
{
|
|
|
|
CCiSyncProcessNotify notify(_cicat, _scanMgr, pbChanges, wcsScope, _fAbort );
|
|
notify.DoIt();
|
|
}
|
|
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::SetupScan
|
|
//
|
|
// Synopsis: Schedules the given path for background scan in the scan
|
|
// thread.
|
|
//
|
|
// Arguments: [pwcsPath] - The path to be scanned.
|
|
//
|
|
// History: 1-19-96 srikants Created
|
|
//
|
|
// Notes: This method is invoked when the notification buffer overflowed
|
|
// and hence some updates are lost. A rescan is needed to figure
|
|
// out the changed documents.
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyMgr::SetupScan( WCHAR const * pwcsPath )
|
|
{
|
|
_cicat.ReScanPath( pwcsPath, TRUE );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::IsInScope
|
|
//
|
|
// Synopsis: Tests if the given scope is already in the list of scopes
|
|
// being watched for notifications.
|
|
//
|
|
// Arguments: [pwcsPath] - Input path to check.
|
|
//
|
|
// Returns: TRUE if the path is already in a notification scope.
|
|
// FALSE o/w
|
|
//
|
|
// History: 1-21-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCiNotifyMgr::IsInScope( WCHAR const * pwcsPath )
|
|
{
|
|
Win4Assert( 0 != pwcsPath );
|
|
ULONG len = wcslen( pwcsPath );
|
|
|
|
CLock lock(_mutex);
|
|
|
|
//
|
|
// First check if it is in the list of paths to be added.
|
|
//
|
|
for ( unsigned i = 0;
|
|
i < _stkScopes.Count();
|
|
i++ )
|
|
{
|
|
if ( !_stkScopes.Get(i)->IsValid() )
|
|
continue;
|
|
|
|
WCHAR const * pwcsTmp = _stkScopes.Get(i)->GetPath();
|
|
|
|
CScopeMatch match( pwcsTmp, wcslen( pwcsTmp ) );
|
|
if ( match.IsInScope( pwcsPath, len ) )
|
|
return TRUE;
|
|
}
|
|
|
|
// next check in the list of notifications
|
|
for ( CFwdCiNotifyIter iter(_list); !_list.AtEnd(iter); _list.Advance(iter) )
|
|
{
|
|
if ( iter->IsMatch( pwcsPath, len ) )
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
} //IsInScope
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyMgr::RemoveScope
|
|
//
|
|
// Synopsis: If there is an exact match for the given scope, it will be
|
|
// removed from the notification list.
|
|
//
|
|
// Arguments: [pwcsPath] - The scope to be removed.
|
|
//
|
|
// Returns: TRUE if the scope was found.
|
|
// FALSE if it was not found.
|
|
//
|
|
// History: 1-25-96 srikants Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
BOOL CCiNotifyMgr::RemoveScope( WCHAR const * pwcsPath )
|
|
{
|
|
Win4Assert( 0 != pwcsPath );
|
|
ULONG len = wcslen( pwcsPath );
|
|
|
|
CLock lock(_mutex);
|
|
|
|
BOOL fFound = FALSE;
|
|
|
|
//
|
|
// First see if there is a match in the list of paths still
|
|
// to be added.
|
|
//
|
|
for ( unsigned i = 0; i < _stkScopes.Count(); i++ )
|
|
{
|
|
CScopeInfo & scopeInfo = *_stkScopes.Get(i);
|
|
if ( !scopeInfo.IsValid() )
|
|
continue;
|
|
|
|
if ( AreIdenticalPaths( pwcsPath, scopeInfo.GetPath() ) )
|
|
{
|
|
scopeInfo.Invalidate();
|
|
fFound = TRUE;
|
|
}
|
|
}
|
|
|
|
//
|
|
// Next remove from the list of notifications.
|
|
//
|
|
for ( CFwdCiNotifyIter iter(_list); !_list.AtEnd(iter); )
|
|
{
|
|
CCiNotify * pNotify = iter.GetEntry();
|
|
_list.Advance(iter);
|
|
|
|
if ( AreIdenticalPaths(pwcsPath, pNotify->GetScope()) )
|
|
{
|
|
ciDebugOut(( DEB_ITRACE,
|
|
"Removing path (%ws) from notification list\n",
|
|
pNotify->GetScope() ));
|
|
pNotify->LokRemove();
|
|
return TRUE;
|
|
}
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyIter::SetTreeScanComplete, public
|
|
//
|
|
// Synopsis: Mark a scope as scanned. Used to update volume version info.
|
|
//
|
|
// History: 13-Apr-1998 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyIter::SetTreeScanComplete()
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
|
|
ULONGLONG const & VolumeCreationTime = _notifyMgr._cicat.GetVolumeCreationTime( Get() );
|
|
ULONG VolumeSerialNumber = _notifyMgr._cicat.GetVolumeSerialNumber( Get() );
|
|
|
|
if ( _iNotAdded < _stack.Count() )
|
|
_stack.Get(_iNotAdded)->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
|
|
else
|
|
_iter->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
|
|
}
|
|
|
|
//+---------------------------------------------------------------------------
|
|
//
|
|
// Member: CCiNotifyIter::SetUsnTreeScanComplete, public
|
|
//
|
|
// Synopsis: Same as SetTreeScanComplete, but also updates USN info.
|
|
//
|
|
// Arguments: [usnMax] -- New high-water mark.
|
|
//
|
|
// History: 13-Apr-1998 KyleP Created
|
|
//
|
|
//----------------------------------------------------------------------------
|
|
|
|
void CCiNotifyIter::SetUsnTreeScanComplete( USN usnMax )
|
|
{
|
|
Win4Assert( !AtEnd() );
|
|
|
|
ULONGLONG const & JournalId = _notifyMgr._cicat.GetJournalId( Get() );
|
|
ULONGLONG const & VolumeCreationTime = _notifyMgr._cicat.GetVolumeCreationTime( Get() );
|
|
ULONG VolumeSerialNumber = _notifyMgr._cicat.GetVolumeSerialNumber( Get() );
|
|
|
|
if ( _iNotAdded < _stack.Count() )
|
|
{
|
|
_stack.Get(_iNotAdded)->SetUsnTreeScanComplete( usnMax );
|
|
_stack.Get(_iNotAdded)->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
|
|
_stack.Get(_iNotAdded)->SetJournalId( JournalId );
|
|
}
|
|
else
|
|
{
|
|
_iter->SetUsnTreeScanComplete( usnMax );
|
|
_iter->SetVolumeInfo( VolumeCreationTime, VolumeSerialNumber );
|
|
_iter->SetJournalId( JournalId );
|
|
}
|
|
}
|