|
|
//******************************************************************************
//
// Microsoft Confidential. Copyright (c) Microsoft Corporation 1999. All rights reserved
//
// File: Collect.cpp
//
// Description: Support for Namespace Garbage Collection
//
// History: 12-01-99 leonardm Created
//
//******************************************************************************
#include "uenv.h"
#include "collect.h"
#include "..\rsoputil\smartptr.h"
#include "..\rsoputil\rsoputil.h"
#include "..\rsoputil\wbemtime.h"
//******************************************************************************
//
// Function: GetMinutesElapsed
//
// Description: Returns the number of minutes elapsed between a time represented
// in a BSTR in WBEM format and the present time.
// It expects a string in WBEM datetime format: "yyyymmddhhmmss.000000+000"
// where yyyy=year, mm=month, dd=day, hh=hour, mm=minutes, ss=seconds
//
//
// Parameters: xbstrOldTime - Reference to XBStr representing the time from which
// calculate the time span.
//
// pMinutesElapsed - Pointer to a ULONG that receives the minutes elapsed
// between xbstrOldTime and the present time.
//
// Return: S_OK on success. An HRESULT error code on failure.
//
// History: 12/01/99 leonardm Created.
//
//******************************************************************************
HRESULT GetMinutesElapsed(XBStr& xbstrOldTime, ULONG* pMinutesElapsed) {
//
// Convert the WbemTime value to a SYSTEMTIME value.
//
SYSTEMTIME systemTime_Old;
HRESULT hr = WbemTimeToSystemTime(xbstrOldTime, systemTime_Old); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: WbemTimeToSystemTime failed. hr=0x%08X."), hr)); return hr; }
//
// Convert the SYSTEMTIME value to a FILETIME value.
//
BOOL bRes; FILETIME fileTime_Old;
bRes = SystemTimeToFileTime(&systemTime_Old, &fileTime_Old); if(!bRes) { DWORD dwLastError = GetLastError(); DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: SystemTimeToFileTime failed. LastError=0x%08X."), dwLastError)); return E_FAIL; }
unsigned __int64 old = fileTime_Old.dwHighDateTime; old <<= 32; old |= fileTime_Old.dwLowDateTime;
//
// Get the current time in SYSTEMTIME format
//
SYSTEMTIME systemTime_Current; GetSystemTime(&systemTime_Current);
//
// Convert the current time from a SYSTEMTIME to a FILETIME value
//
FILETIME fileTime_Current; bRes = SystemTimeToFileTime(&systemTime_Current, &fileTime_Current); if(!bRes) { DWORD dwLastError = GetLastError(); DebugMsg((DM_WARNING, TEXT("GetMinutesElapsed: SystemTimeToFileTime failed. LastError=0x%08X."), dwLastError)); return E_FAIL; }
//
// The time passed in as a parameter must precede the current time
//
unsigned __int64 current = fileTime_Current.dwHighDateTime; current <<= 32; current |= fileTime_Current.dwLowDateTime;
if(old > current) { return WBEM_E_INVALID_PARAMETER; }
//
// We have converted SYSTEMTIMEs to FILETIMEs.
// "The FILETIME structure is a 64-bit value representing the number
// of 100-nanosecond intervals since January 1, 1601."
// Therefore we need to divide by ten million to obtain seconds
// and by sixty to obtain minutes.
//
*pMinutesElapsed = (ULONG) (( current - old ) / (60 * 10 * 1000 * 1000));
return S_OK; }
//******************************************************************************
//
// Function: IsNamespaceStale
//
// Description: Check if namespace is stale Sub-namespaces 'User' and 'Computer' are expected to have
// RSOP_Session. The data member 'creationTime' of that instance is examined when
// evaluating whether the sub-namespace should be deleted. For some failures treat the
// namespace as garbage-collectable because we don't clean up properly when an error is
// encountered during the creation of the namespace, and setting up security etc.
//
//
// Parameters: pChildNamespace - Pointer to IWbemServices associated with child namespace
// TTLMinutes - ULONG variable that represents the maximum number of
// minutes that may have elapsed before a sub-namespace is
// deleted.
//
// Return: True if namespace is stale, false otherwise
//
//******************************************************************************
BOOL IsNamespaceStale( IWbemServices *pChildNamespace, ULONG TTLMinutes ) { //
// compute TTL
// To do so compare the "creationTime" data member of class RSOP_Session with
// the current time. If the time span exceeds the threshold (as found in the
// registry), the namespace is to be deleted.
//
XBStr xbstrInstancePath = L"RSOP_Session.id=\"Session1\""; if(!xbstrInstancePath) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return FALSE; }
XInterface<IWbemClassObject>xpInstance = NULL; HRESULT hr = pChildNamespace->GetObject(xbstrInstancePath, 0, NULL, &xpInstance, NULL);
if(FAILED(hr)) { DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: GetObject failed. hr=0x%08X"), hr)); return TRUE; }
XBStr xbstrPropertyName = L"creationTime"; if(!xbstrPropertyName) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return TRUE; }
VARIANT var; VariantInit(&var); XVariant xVar(&var);
hr = xpInstance->Get(xbstrPropertyName, 0, &var, NULL, NULL);
if(FAILED(hr)) { DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Get failed. hr=0x%08X."), hr)); return TRUE; }
if ( var.vt == VT_NULL ) return TRUE;
XBStr xbstrPropertyValue = var.bstrVal;
if(!xbstrPropertyValue) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return FALSE; }
ULONG minutesElapsed = 10;
hr = GetMinutesElapsed(xbstrPropertyValue, &minutesElapsed); if(FAILED(hr)) { DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: GetMinutesElapsed failed. hr=0x%08X."), hr)); return TRUE; }
if(minutesElapsed > TTLMinutes) return TRUE; else return FALSE; }
//******************************************************************************
//
// Function: GarbageCollectNamespace
//
// Description: Garabage-collects the namespace passed in as a parameter.
// If no sub-namespaces are found or if all sub-namespaces
// are deleted, it deletes the parent namespace as well.
// It deletes sub-namespaces whose TTL has expired.
// It computes the TTL from the 'creationTime' data member of the only
// instance of class RSOP_Session as defined in rsop.mof.
//
// Any of the sub-namespaces that is older than TTLMinutes will be deleted.
// If no sub-namespaces are left, then the parent namespace is deleted as well.
//
// Garbage-collectable are those namespaces which satisfy a set of
// criteria which at the present time is based solely on the naming convention
// as follows: namespaces under root\rsop whose name starts with "NS"
//
// Sub-namespaces 'User' and 'Computer' are expected to have an instance of class
// RSOP_Session. The data member 'creationTime' of that instance is examined when
// evaluating whether the sub-namespace should be deleted.
//
//
// Parameters: bstrNamespace - Name of the namesapce to garbage collect.
// pWbemServices - Pointer to IWbemServices associated with
// the parent of bstrNamespace (root\rsop)
// TTLMinutes - ULONG variable that represents the maximum number of
// minutes that may have elapsed before a sub-namespace is
// deleted.
//
// Return: S_OK on success. An HRESULT error code on failure.
//
// History: 12/01/99 leonardm Created.
//
//******************************************************************************
HRESULT GarbageCollectNamespace(BSTR bstrNamespace, IWbemServices* pWbemServices, ULONG TTLMinutes) { if(!bstrNamespace || !pWbemServices) { return E_FAIL; }
//
// Connect to that namespace and enumerate instances of __namespace.
// It's assumed that there will be at most 2 namespaces:
// "User" and "Computer".
//
XInterface<IWbemServices> xpParentNamespace; HRESULT hr = pWbemServices->OpenNamespace( bstrNamespace, 0, NULL, &xpParentNamespace, NULL);
if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: OpenNamespace failed. hr=0x%08X"), hr)); return hr; }
//
// Enumerate all instances of __namespace.
//
XInterface<IEnumWbemClassObject> xpEnum; XBStr xbstrClass = L"__namespace"; if(!xbstrClass) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory"))); return E_OUTOFMEMORY; }
hr = xpParentNamespace->CreateInstanceEnum( xbstrClass, WBEM_FLAG_SHALLOW | WBEM_FLAG_FORWARD_ONLY, NULL, &xpEnum); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: CreateInstanceEnum failed. hr=0x%08X" ), hr )); return hr; }
//
// We re interested in data member "Name" of class __namespace.
//
XBStr xbstrProperty = L"Name"; if(!xbstrProperty) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory"))); return E_FAIL; }
//
// This pointer will be used to iterate through every instance
// in the enumeration.
//
XInterface<IWbemClassObject>xpInstance = NULL;
ULONG ulReturned = 0; long namespacesFound = 0; long namespacesDeleted = 0;
while(1) { //
// Retrieve the next instance in the enumeration.
//
hr = xpEnum->Next( WBEM_NO_WAIT, 1, &xpInstance, &ulReturned); if (hr != WBEM_S_NO_ERROR || !ulReturned) { //
// Either the end of the enumeration has been reached or an error
// ocurred. We will find out outside the loop.
//
break; }
namespacesFound++;
//
// Get the namespace name.
//
VARIANT var; VariantInit(&var);
hr = xpInstance->Get(xbstrProperty, 0L, &var, NULL, NULL);
//
// Release the pointer to the current element of the enumeration..
//
xpInstance = NULL;
if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Get failed. hr=0x%x" ), hr )); return E_FAIL; }
//
// Use the name of the namespace to connect to it.
//
XBStr xbstrChildNamespace = var.bstrVal; VariantClear( &var );
if(!xbstrChildNamespace) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory" ))); return E_FAIL; }
XInterface<IWbemServices> xpChildNamespace = NULL; hr = xpParentNamespace->OpenNamespace( xbstrChildNamespace, 0, NULL, &xpChildNamespace, NULL);
if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: OpenNamespace returned 0x%x"), hr)); return hr; }
BOOL bStale = IsNamespaceStale( xpChildNamespace, TTLMinutes ); xpChildNamespace = NULL;
if ( bStale ) { //
// DeleteInstance
//
CWString sNamespaceToDelete = L"__namespace.name=\""; sNamespaceToDelete += (WCHAR*)xbstrChildNamespace; sNamespaceToDelete += L"\"";
if(!sNamespaceToDelete.ValidString()) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
XBStr xbstrInstancePath = sNamespaceToDelete; if(!xbstrInstancePath) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = xpParentNamespace->DeleteInstance(xbstrInstancePath, 0, NULL, NULL); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: DeleteInstance returned 0x%x"), hr)); return hr; }
DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Deleted namespace:%ws\\%ws\n"), (WCHAR*)bstrNamespace, (WCHAR*)xbstrChildNamespace ));
namespacesDeleted++; }
}
//
// Check to find out whther the loop was exited because the end of the
// enumeration was reached or because an error ocurred.
//
if(hr != (HRESULT) WBEM_S_FALSE || ulReturned) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Get failed. hr=0x%x" ), hr )); return E_FAIL; }
//
// If no namespaces are found or if namespaces in enumeration
// equal deleted namespaces delete the parent namespace as well.
//
if((!namespacesFound) || (namespacesDeleted == namespacesFound)) { xpParentNamespace = NULL;
CWString sNamespaceToDelete = L"__namespace.name=\""; sNamespaceToDelete += (WCHAR*)bstrNamespace; sNamespaceToDelete += L"\"";
if(!sNamespaceToDelete.ValidString()) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
XBStr xbstrInstancePath = sNamespaceToDelete; if(!xbstrInstancePath) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = pWbemServices->DeleteInstance(xbstrInstancePath, 0, NULL, NULL); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespace: DeleteInstance returned 0x%x"), hr)); return hr; }
DebugMsg((DM_VERBOSE, TEXT("GarbageCollectNamespace: Deleted namespace %ws\n"), (WCHAR*)bstrNamespace )); }
return S_OK; }
//******************************************************************************
//
// Function: IsGarbageCollectable
//
// Description: Determines whether a namespace is garbage-collectable.
// Garbage-collectable are those namespaces which satisfy a set of
// criteria which at the present time is based solely on the naming convention
// as follows: namespaces under root\rsop whose name starts with "NS"
//
//
// Parameters: bstrNamespace - BSTR that represents the namespace name.
//
// Return: 'true' or 'false'.
//
// History: 12/01/99 leonardm Created.
//
//******************************************************************************
bool IsGarbageCollectable(BSTR bstrNamespace) { if(bstrNamespace && wcslen(bstrNamespace) > 1 && _wcsnicmp(bstrNamespace, L"NS", 2) == 0) { return true; }
return false; }
//******************************************************************************
//
// Function: GarbageCollectNamespaces
//
// Description: Iterates through namespaces under root\rsop and for each of those
// that are determined to be garbage-collectable, it connects to
// sub-namespaces 'User' and 'Computer'.
//
// Any of the sub-namespaces that is older than TTLMinutes will be deleted.
// If no sub-namespaces are left, then the parent namespace is deleted as well.
//
// Garbage-collectable are those namespaces which satisfy a set of
// criteria which at the present time is based solely on the naming convention
// as follows: namespaces under root\rsop whose name starts with "NS"
//
// Sub-namespaces 'User' and 'Computer' are expected to have an instance of class
// RSOP_Session. The data member 'creationTime' of that instance is examined when
// evaluating whether the sub-namespace should be deleted.
//
//
// Parameters: TTLMinutes - The maximum number of minutes that may have
// elapsed since the creation of a sub-namespace
//
// Return:
//
// History: 12/01/99 leonardm Created.
//
//******************************************************************************
HRESULT GarbageCollectNamespaces(ULONG TTLMinutes) { XInterface<IWbemLocator> xpWbemLocator = NULL;
//
// Connect to namespace ROOT\RSOP
//
HRESULT hr = CoCreateInstance( CLSID_WbemLocator, NULL, CLSCTX_INPROC_SERVER, IID_IWbemLocator, (LPVOID*) &xpWbemLocator); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: CoCreateInstance returned 0x%x"), hr)); return hr; }
XInterface<IWbemServices> xpWbemServices = NULL;
XBStr xbstrNamespace = L"root\\rsop";
if(!xbstrNamespace) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = xpWbemLocator->ConnectServer(xbstrNamespace, NULL, NULL, 0L, 0L, NULL, NULL, &xpWbemServices); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: ConnectServer failed. hr=0x%x" ), hr )); return hr; }
//
// Enumerate all instances of __namespace at the root\rsop level.
//
XInterface<IEnumWbemClassObject> xpEnum; XBStr xbstrClass = L"__namespace"; if(!xbstrClass) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory."))); return E_OUTOFMEMORY; }
hr = xpWbemServices->CreateInstanceEnum( xbstrClass, WBEM_FLAG_SHALLOW | WBEM_FLAG_FORWARD_ONLY, NULL, &xpEnum); if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: CreateInstanceEnum failed. hr=0x%x" ), hr )); return hr; }
XBStr xbstrProperty = L"Name"; if(!xbstrProperty) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory"))); return E_FAIL; }
XInterface<IWbemClassObject>xpInstance = NULL; ULONG ulReturned = 1;
while(1) { hr = xpEnum->Next( WBEM_NO_WAIT, 1, &xpInstance, &ulReturned); if (hr != WBEM_S_NO_ERROR || !ulReturned) { break; }
VARIANT var; VariantInit(&var);
hr = xpInstance->Get(xbstrProperty, 0L, &var, NULL, NULL); xpInstance = NULL; if(FAILED(hr)) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Get failed. hr=0x%x" ), hr )); return E_FAIL; }
XBStr xbstrGCNamespace = var.bstrVal;
VariantClear( &var );
if(!xbstrGCNamespace) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Failed to allocate memory."))); return E_OUTOFMEMORY; }
//
// For every instance of __namespace under ROOT\RSOP
// find out whether it is garbage-collectable.
//
if(IsGarbageCollectable(xbstrGCNamespace)) { //
// If it is garbage-collectable, delete it if it
// was created more than 'TTLMinutes' minutes ago.
// In case of failure, continue with next namespace
// in the enumeration.
//
GarbageCollectNamespace(xbstrGCNamespace, xpWbemServices, TTLMinutes); } }
if(hr != (HRESULT) WBEM_S_FALSE || ulReturned) { DebugMsg((DM_WARNING, TEXT("GarbageCollectNamespaces: Get failed. hr=0x%x" ), hr )); return E_FAIL; }
return S_OK; }
|