Leaked source code of windows server 2003
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.
 
 
 
 
 
 

1516 lines
51 KiB

/*++
Copyright (c) 1999 Microsoft Corporation
Abstract:
@doc
@module registry.cxx | Implementation of CVssRegistryKey
@end
Author:
Adi Oltean [aoltean] 03/14/2001
Revision History:
Name Date Comments
aoltean 03/14/2001 Created
--*/
/////////////////////////////////////////////////////////////////////////////
// Includes
#include "stdafx.hxx"
#include "memory"
#include <safeboot.h>
#include "vs_inc.hxx"
#include "vs_reg.hxx"
#include "vs_reg.hxx"
#include "vss.h"
#include "vswriter.h"
////////////////////////////////////////////////////////////////////////
// Standard foo for file name aliasing. This code block must be after
// all includes of VSS header files.
//
#ifdef VSS_FILE_ALIAS
#undef VSS_FILE_ALIAS
#endif
#define VSS_FILE_ALIAS "REGREGSC"
//
////////////////////////////////////////////////////////////////////////
/////////////////////////////////////////////////////////////////////////////
// CVssRegistryKey implementation
// Creates the registry key.
// Throws an error if the key already exists
void CVssRegistryKey::Create(
IN HKEY hAncestorKey,
IN LPCWSTR pwszPathFormat,
IN ...
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Create" );
BS_ASSERT(hAncestorKey);
BS_ASSERT(pwszPathFormat);
// Build the path to the key
WCHAR wszKeyPath[x_nVssMaxRegBuffer];
va_list marker;
va_start( marker, pwszPathFormat );
ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
va_end( marker );
if (ft.HrFailed())
ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
// Create the key
BS_ASSERT( (m_samDesired & KEY_WRITE) == KEY_WRITE);
DWORD dwDisposition = 0;
HKEY hRegKey = NULL;
LONG lRes = ::RegCreateKeyExW(
hAncestorKey, // IN HKEY hKey,
wszKeyPath, // IN LPCWSTR lpSubKey,
0, // IN DWORD Reserved,
REG_NONE, // IN LPWSTR lpClass,
m_dwKeyCreateOptions, // IN DWORD dwOptions,
m_samDesired, // IN REGSAM samDesired,
NULL, // IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
&hRegKey, // OUT PHKEY phkResult,
&dwDisposition // OUT LPDWORD lpdwDisposition
);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegCreateKeyExW(%ld,%s,...)",
hAncestorKey, wszKeyPath);
// Check whether we created or opened the key
switch ( dwDisposition )
{
case REG_CREATED_NEW_KEY:
if (!m_awszKeyPath.CopyFrom(wszKeyPath)) {
::RegCloseKey( hRegKey );
ft.Throw( VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
}
Close();
m_hRegKey = hRegKey;
break;
case REG_OPENED_EXISTING_KEY:
::RegCloseKey( hRegKey );
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_ALREADY_EXISTS, L"Key %s already exists", wszKeyPath);
default:
BS_ASSERT( false );
if (hRegKey && (hRegKey != INVALID_HANDLE_VALUE))
::RegCloseKey( hRegKey );
ft.TranslateGenericError(VSSDBG_GEN, E_UNEXPECTED, L"RegCreateKeyExW(%ld,%s,...,[%lu])",
hAncestorKey, wszKeyPath, dwDisposition);
}
}
// Opens a registry key.
bool CVssRegistryKey::Open(
IN HKEY hAncestorKey,
IN LPCWSTR pwszPathFormat,
IN ...
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Open" );
BS_ASSERT(hAncestorKey);
BS_ASSERT(pwszPathFormat);
// Build the path to the key
WCHAR wszKeyPath[x_nVssMaxRegBuffer];
va_list marker;
va_start( marker, pwszPathFormat );
ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
va_end( marker );
if (ft.HrFailed())
ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
// Open the key
HKEY hRegKey = NULL;
LONG lRes = ::RegOpenKeyExW(
hAncestorKey, // IN HKEY hKey,
wszKeyPath, // IN LPCWSTR lpSubKey,
0, // IN DWORD dwOptions,
m_samDesired, // IN REGSAM samDesired,
&hRegKey // OUT PHKEY phkResult
);
if ( lRes == ERROR_FILE_NOT_FOUND )
return false;
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegOpenKeyExW(%ld,%s,...)",
hAncestorKey, wszKeyPath);
if (!m_awszKeyPath.CopyFrom(wszKeyPath)) {
::RegCloseKey( hRegKey );
ft.Throw( VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
}
Close();
m_hRegKey = hRegKey;
return true;
}
// Recursively deletes a subkey.
// Throws an error if the subkey does not exist
void CVssRegistryKey::DeleteSubkey(
IN LPCWSTR pwszPathFormat,
IN ...
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::DeleteSubkey" );
BS_ASSERT(pwszPathFormat);
// Build the path to the key
WCHAR wszKeyPath[x_nVssMaxRegBuffer];
va_list marker;
va_start( marker, pwszPathFormat );
ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
va_end( marker );
if (ft.HrFailed())
ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
// Recursively delete the key
DWORD dwRes = ::SHDeleteKey(
m_hRegKey, // IN HKEY hKey,
wszKeyPath // IN LPCTSTR pszSubKey
);
if ( dwRes == ERROR_FILE_NOT_FOUND )
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Key with path %s\\%s not found",
m_awszKeyPath.GetRef(), wszKeyPath);
if ( dwRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(dwRes), L"SHDeleteKey(%ld[%s],%s)",
m_hRegKey, m_awszKeyPath.GetRef(), wszKeyPath);
}
// Deletes a value.
// Throws an error if the value does not exist
void CVssRegistryKey::DeleteValue(
IN LPCWSTR pwszValueName
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::DeleteValue" );
BS_ASSERT(pwszValueName);
// Recursively delete the key
LONG lRes = ::RegDeleteValue(
m_hRegKey, // IN HKEY hKey,
pwszValueName // IN LPCTSTR pwszValueName
);
if ( lRes == ERROR_FILE_NOT_FOUND )
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Value %s\\%s not found",
m_awszKeyPath.GetRef(), pwszValueName);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegDeleteValue(%ld[%s],%s)",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName);
}
// Adds a LONGLONG value to the registry key
void CVssRegistryKey::SetValue(
IN LPCWSTR pwszValueName,
IN LONGLONG llValue
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_LONGLONG" );
// Convert the value to a string
WCHAR wszValue[x_nVssMaxRegNumBuffer];
ft.hr = StringCchPrintfW( STRING_CCH_PARAM(wszValue),
L"%I64d", llValue );
if (ft.HrFailed())
ft.TranslateGenericError( VSSDBG_GEN, ft.hr, L"StringCchPrintfW()");
// Set the value as string
SetValue(pwszValueName, wszValue);
}
// Adds a REG_SZ value to the registry key
void CVssRegistryKey::SetValue(
IN LPCWSTR pwszValueName,
IN LPCWSTR pwszValue,
IN REGSAM eSzType /* = REG_SZ */
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_PWSZ" );
// Assert paramters
BS_ASSERT(pwszValueName);
BS_ASSERT(pwszValue);
BS_ASSERT(m_hRegKey);
BS_ASSERT((eSzType == REG_SZ) || (eSzType == REG_EXPAND_SZ));
// Set the value
DWORD dwLength = ::lstrlenW( pwszValue );
LONG lRes = ::RegSetValueExW(
m_hRegKey, // IN HKEY hKey,
pwszValueName, // IN LPCWSTR lpValueName,
0, // IN DWORD Reserved,
eSzType, // IN DWORD dwType,
(CONST BYTE*)pwszValue, // IN CONST BYTE* lpData,
(dwLength + 1) * sizeof(WCHAR) // IN DWORD cbData
);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
L"RegSetValueExW(0x%08lx,%s,0,REG_SZ,%s.%d)",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValue, (dwLength + 1) * sizeof(WCHAR));
}
// Adds a REG_DWORD value to the registry key
void CVssRegistryKey::SetValue(
IN LPCWSTR pwszValueName,
IN DWORD dwValue
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_DWORD" );
// Assert paramters
BS_ASSERT(pwszValueName);
BS_ASSERT(m_hRegKey);
// Set the value
LONG lRes = ::RegSetValueExW(
m_hRegKey, // IN HKEY hKey,
pwszValueName, // IN LPCWSTR lpValueName,
0, // IN DWORD Reserved,
REG_DWORD, // IN DWORD dwType,
(CONST BYTE*)&dwValue, // IN CONST BYTE* lpData,
sizeof(DWORD) // IN DWORD cbData
);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
L"RegSetValueExW(0x%08lx,%s,0,REG_DWORD,%ld)",
m_hRegKey, m_awszKeyPath.GetRef(), dwValue);
}
// Adds a REG_MULTI_SZ value to the registry key
// WARNING: do not call this routine for a REG_SZ value!
// (Intentionally this is a different function so that it won't
// be confused with CVssRegistryKey::SetValue)
void CVssRegistryKey::SetMultiszValue(
IN LPCWSTR pwszValueName,
IN LPCWSTR pwszValue
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetMultiszValue" );
// Assert paramters
BS_ASSERT(pwszValueName);
BS_ASSERT(pwszValue);
BS_ASSERT(m_hRegKey);
// Get the length of the multi-sz string, including the zero character for each string
DWORD dwLength = 0;
LPCWSTR pwszCurrent = pwszValue;
do
{
// Add the zero character
LONG dwCurrentLength = ::lstrlenW(pwszCurrent) + 1;
dwLength += dwCurrentLength;
pwszCurrent += dwCurrentLength;
}
while(pwszCurrent[0]);
// Add the final zero character
dwLength += 1;
// Set the value
LONG lRes = ::RegSetValueExW(
m_hRegKey, // IN HKEY hKey,
pwszValueName, // IN LPCWSTR lpValueName,
0, // IN DWORD Reserved,
REG_MULTI_SZ, // IN DWORD dwType,
(CONST BYTE*)pwszValue, // IN CONST BYTE* lpData,
(dwLength) * sizeof(WCHAR) // IN DWORD cbData
);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
L"RegSetValueExW(0x%08lx,%s,0,REG_SZ,%s.%d)",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValue, (dwLength) * sizeof(WCHAR));
}
// Adds a binary value to the registry key
void CVssRegistryKey::SetBinaryValue(
IN LPCWSTR pwszValueName,
IN BYTE * pbData,
IN DWORD dwSize
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetBinaryValue" );
// Assert paramters
BS_ASSERT(pwszValueName);
BS_ASSERT(pbData);
BS_ASSERT(dwSize);
BS_ASSERT(m_hRegKey);
// Set the value
LONG lRes = ::RegSetValueExW(
m_hRegKey, // IN HKEY hKey,
pwszValueName, // IN LPCWSTR lpValueName,
0, // IN DWORD Reserved,
REG_BINARY, // IN DWORD dwType,
pbData, // IN CONST BYTE* lpData,
dwSize // IN DWORD cbData
);
if ( lRes != ERROR_SUCCESS )
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
L"RegSetValueExW(0x%08lx,%s,0,REG_BINARY,%p.%lu)",
m_hRegKey, m_awszKeyPath.GetRef(), pbData, dwSize);
}
// Reads a VSS_PWSZ value from the registry key
bool CVssRegistryKey::GetValue(
IN LPCWSTR pwszValueName,
OUT VSS_PWSZ & pwszValue,
IN bool bThrowIfNotFound /* = true */
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_PWSZ" );
// Assert parameters
BS_ASSERT(pwszValueName);
BS_ASSERT(pwszValue == NULL);
// Reset the OUT parameter
pwszValue = NULL;
// Get the value length (we suppose that doesn't change)
DWORD dwType = 0;
DWORD dwSizeInBytes = 0;
LONG lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType,
NULL,
&dwSizeInBytes);
if (lResult == ERROR_FILE_NOT_FOUND)
{
if (bThrowIfNotFound)
{
ft.LogGenericWarning(VSSDBG_GEN,
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
}
else
return ft.Exit(false);
}
if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
// Check the type and the size
if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a string value 0x%08lx(%s),%s",
dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
BS_ASSERT(dwSizeInBytes);
// Allocate the buffer
CVssAutoPWSZ awszValue;
DWORD dwSizeOfString = dwSizeInBytes/sizeof(WCHAR);
awszValue.Allocate(dwSizeOfString);
// Get the string contents
DWORD dwType2 = 0;
DWORD dwSizeInBytes2 = dwSizeOfString * (sizeof(WCHAR));
BS_ASSERT( dwSizeInBytes2 == dwSizeInBytes);
lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType2,
(LPBYTE)awszValue.GetRef(),
&dwSizeInBytes2);
if (lResult != ERROR_SUCCESS)
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
BS_ASSERT(dwType2 == REG_SZ || dwType2 == REG_EXPAND_SZ);
BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
(awszValue.GetRef())[dwSizeOfString] = L'\0';
// Set the OUT parameter
pwszValue = awszValue.Detach();
return ft.Exit(true);
}
// Reads a LONGLONG value from the registry key
bool CVssRegistryKey::GetValue(
IN LPCWSTR pwszValueName,
OUT LONGLONG & llValue,
IN bool bThrowIfNotFound /* = true */
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_LONGLONG" );
// Assert parameters
BS_ASSERT(pwszValueName);
CVssAutoPWSZ awszValue;
bool bResult = GetValue(pwszValueName, awszValue.GetRef(), bThrowIfNotFound);
if (!bResult)
{
BS_ASSERT(!bThrowIfNotFound);
return ft.Exit(false);
}
BS_ASSERT(awszValue.GetRef());
BS_ASSERT(awszValue.GetRef()[0]);
// Read the LONGLONG string
llValue = ::_wtoi64(awszValue);
return ft.Exit(true);
}
// Reads a DWORD value from the registry key
bool CVssRegistryKey::GetValue(
IN LPCWSTR pwszValueName,
OUT DWORD & dwValue,
IN bool bThrowIfNotFound /* = true */
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_DWORD" );
// Assert parameters
BS_ASSERT(pwszValueName);
// Reset the OUT parameter
dwValue = 0;
// Get the value length (we suppose that doesn't change)
DWORD dwType = 0;
DWORD dwSizeInBytes = 0;
LONG lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType,
NULL,
&dwSizeInBytes);
if (lResult == ERROR_FILE_NOT_FOUND)
{
if (bThrowIfNotFound)
{
ft.LogGenericWarning(VSSDBG_GEN,
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
}
else
return ft.Exit(false);
}
if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
// Check the type and the size
if (dwType != REG_DWORD)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a DWORD value 0x%08lx(%s),%s",
dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
BS_ASSERT(dwSizeInBytes == sizeof(DWORD));
// Get the string contents
DWORD dwType2 = 0;
DWORD dwSizeInBytes2 = dwSizeInBytes;
DWORD dwReadValue = 0;
lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType2,
(LPBYTE)&dwReadValue,
&dwSizeInBytes2);
if (lResult != ERROR_SUCCESS)
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
BS_ASSERT(dwType2 == REG_DWORD);
BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
dwValue = dwReadValue;
return ft.Exit(true);
}
// Reads a REG_BINARY value from the registry key
bool CVssRegistryKey::GetBinaryValue(
IN LPCWSTR pwszValueName,
OUT BYTE* & pbData,
OUT DWORD & dwSize,
IN bool bThrowIfNotFound /* = true */
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetBinaryValue" );
// Assert parameters
BS_ASSERT(pwszValueName);
BS_ASSERT(pbData == NULL);
BS_ASSERT(dwSize == NULL);
// Reset the OUT parameters
pbData = NULL;
dwSize = 0;
// Get the value length (we suppose that doesn't change)
DWORD dwType = 0;
DWORD dwSizeInBytes = 0;
LONG lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType,
NULL,
&dwSizeInBytes);
if (lResult == ERROR_FILE_NOT_FOUND)
{
if (bThrowIfNotFound)
{
ft.LogGenericWarning(VSSDBG_GEN,
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
}
else
return ft.Exit(false);
}
if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
// Check the type and the size
if (dwType != REG_BINARY)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a binary value 0x%08lx(%s),%s",
dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
BS_ASSERT(dwSizeInBytes);
// Allocate the buffer
BS_ASSERT(dwSizeInBytes != 0);
std::auto_ptr<BYTE> pBuffer(new BYTE[dwSizeInBytes]);
if (pBuffer.get() == NULL)
ft.Throw(VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
// Get the binary value contents
DWORD dwType2 = 0;
DWORD dwSizeInBytes2 = dwSizeInBytes;
lResult = ::RegQueryValueExW(
m_hRegKey,
pwszValueName,
NULL,
&dwType2,
pBuffer.get(),
&dwSizeInBytes2);
if (lResult != ERROR_SUCCESS)
ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
BS_ASSERT(dwType2 == REG_BINARY);
BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
// Set the OUT parameters
pbData = pBuffer.release();
dwSize = dwSizeInBytes;
return ft.Exit(true);
}
// Closes the registry key
void CVssRegistryKey::Close()
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Close" );
if (m_hRegKey) {
// Close the opened key
LONG lRes = ::RegCloseKey( m_hRegKey );
if (lRes != ERROR_SUCCESS) {
BS_ASSERT(false);
ft.Trace( VSSDBG_GEN, L"%s: Error on closing key with name %s. lRes == 0x%08lx", (VSS_PWSZ)m_awszKeyPath, lRes );
}
m_hRegKey = NULL;
}
m_awszKeyPath.Clear();
}
// Standard constructor
CVssRegistryKey::CVssRegistryKey(
IN REGSAM samDesired, /* = KEY_ALL_ACCESS */
IN DWORD dwKeyCreateOptions /* = REG_OPTION_NON_VOLATILE */
)
{
m_hRegKey = NULL;
m_dwKeyCreateOptions = dwKeyCreateOptions;
m_samDesired = samDesired;
}
// Standard destructor
CVssRegistryKey::~CVssRegistryKey()
{
Close();
}
/////////////////////////////////////////////////////////////////////////////
// CVssRegistryKeyIterator implementation
// Standard constructor
CVssRegistryKeyIterator::CVssRegistryKeyIterator()
{
// Initialize data members
Detach();
}
// Returns the name of the current key.
// The returned key is always non-NULL (or the function will throw E_UNEXPECTED).
VSS_PWSZ CVssRegistryKeyIterator::GetCurrentKeyName() throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKeyIterator::GetCurrentKeyName" );
if (!m_bAttached || !m_awszSubKeyName.GetRef()) {
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: noninitialized iterator");
}
// Fill wszSubKeyName with the name of the subkey
FILETIME time;
DWORD dwSize = m_dwMaxSubKeyLen;
LONG lRes = ::RegEnumKeyExW(
m_hParentKey, // IN HKEY hKey,
m_dwCurrentKeyIndex, // IN DWORD dwIndex,
m_awszSubKeyName, // OUT LPWSTR lpName,
&dwSize, // IN OUT LPDWORD lpcbName,
NULL, // IN LPDWORD lpReserved,
NULL, // IN OUT LPWSTR lpClass,
NULL, // IN OUT LPDWORD lpcbClass,
&time); // OUT PFILETIME lpftLastWriteTime
switch(lRes)
{
case ERROR_SUCCESS:
BS_ASSERT(dwSize != 0);
break; // Go to Next key
default:
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumKeyExW(%p,%lu,%p,%lu ...)",
m_hParentKey, m_dwCurrentKeyIndex, m_awszSubKeyName.GetRef(), dwSize);
case ERROR_NO_MORE_ITEMS:
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentKeyIndex, m_dwKeyCount);
}
return m_awszSubKeyName.GetRef();
}
// Standard constructor
void CVssRegistryKeyIterator::Attach(
IN CVssRegistryKey & key
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKeyIterator::Attach" );
// Reset all members
Detach();
m_hParentKey = key.GetHandle();
BS_ASSERT(m_hParentKey);
// Get the number of subkeys and the max subkey length
DWORD dwKeyCount = 0;
DWORD dwMaxSubKeyLen = 0;
LONG lRes = ::RegQueryInfoKeyW(
m_hParentKey, // handle to key
NULL, // class buffer
NULL, // size of class buffer
NULL, // reserved
&dwKeyCount, // number of subkeys
&dwMaxSubKeyLen, // longest subkey name
NULL, // longest class string
NULL, // number of value entries
NULL, // longest value name
NULL, // longest value data
NULL, // descriptor length
NULL); // last write time
if (lRes != ERROR_SUCCESS)
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegQueryInfoKeyW(%p, ...)", m_hParentKey);
// Allocate the key name with a sufficient length.
// We assume that the key length cannot change during the ennumeration).
if (dwMaxSubKeyLen)
m_awszSubKeyName.Allocate(dwMaxSubKeyLen);
// Setting the number of subkeys
m_dwKeyCount = dwKeyCount;
m_dwMaxSubKeyLen = dwMaxSubKeyLen + 1;
// Attachment completed
m_bAttached = true;
}
void CVssRegistryKeyIterator::Detach()
{
// Initialize data members
m_hParentKey = NULL;
m_dwKeyCount = 0;
m_dwCurrentKeyIndex = 0;
m_dwMaxSubKeyLen = 0;
m_awszSubKeyName.Clear();
m_bAttached = false;
}
// Tells if the current key is still valid
bool CVssRegistryKeyIterator::IsEOF()
{
return (m_dwCurrentKeyIndex >= m_dwKeyCount);
}
// Return the number of subkeys at the moment of attaching
DWORD CVssRegistryKeyIterator::GetSubkeysCount()
{
return (m_dwKeyCount);
}
// Set the next key as being the current one in the enumeration
void CVssRegistryKeyIterator::MoveNext()
{
if (!IsEOF())
m_dwCurrentKeyIndex++;
else
BS_ASSERT(false);
}
/////////////////////////////////////////////////////////////////////////////
// CVssRegistryValueIterator implementation
// Standard constructor
CVssRegistryValueIterator::CVssRegistryValueIterator()
{
// Initialize data members
Detach();
}
// Returns the name of the current value.
// The returned value is always non-NULL (or the function will throw E_UNEXPECTED).
VSS_PWSZ CVssRegistryValueIterator::GetCurrentValueName() throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueName" );
ReadCurrentValueDetails();
BS_ASSERT(m_bSeekDone);
return m_awszValueName.GetRef();
}
// Returns the type of the current value.
DWORD CVssRegistryValueIterator::GetCurrentValueType() throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueType" );
ReadCurrentValueDetails();
BS_ASSERT(m_bSeekDone);
return m_dwCurrentValueType;
}
// Reads a VSS_PWSZ value from the registry key
void CVssRegistryValueIterator::GetCurrentValueContent(
OUT VSS_PWSZ & pwszValue
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
ReadCurrentValueDetails();
BS_ASSERT(m_bSeekDone);
if (m_dwCurrentValueType != REG_SZ) {
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: attempting to read a value of the wrong type");
}
// Allocate the output buffer
DWORD cchStringSize = m_cbValueDataSize / sizeof(WCHAR);
CVssAutoPWSZ awszBuffer;
awszBuffer.Allocate(cchStringSize + 1);
// Fill awszBuffer with the string contents
DWORD cchNameSize = m_cchMaxValueNameLen;
DWORD dwCurrentValueType = 0;
DWORD cbValueSize = m_cbValueDataSize;
LONG lRes = ::RegEnumValue(
m_hKey, // IN HKEY hKey,
m_dwCurrentValueIndex, // IN DWORD dwIndex,
m_awszValueName, // OUT LPWSTR lpName,
&cchNameSize, // IN OUT LPDWORD lpcbName,
NULL, // IN LPDWORD lpReserved,
&dwCurrentValueType, // IN OUT LPDWORD lpType,
(LPBYTE)awszBuffer.GetRef(),// IN OUT LPBYTE lpData,
&cbValueSize); // IN OUT LPDWORD lpcbData
switch(lRes)
{
case ERROR_SUCCESS:
BS_ASSERT(cchNameSize != 0);
BS_ASSERT(cbValueSize != 0);
if (dwCurrentValueType != m_dwCurrentValueType)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
L"Unexpected error: current value type changed in the meantime %lu %lu",
dwCurrentValueType, m_dwCurrentValueType);
break;
case ERROR_NO_MORE_ITEMS:
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
default:
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
}
awszBuffer.GetRef()[cchStringSize] = L'\0';
pwszValue = awszBuffer.Detach();
}
// Reads a DWORD value from the registry key
void CVssRegistryValueIterator::GetCurrentValueContent(
OUT DWORD & dwValue
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
ReadCurrentValueDetails();
BS_ASSERT(m_bSeekDone);
if (m_dwCurrentValueType != REG_DWORD)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
L"Unexpected error: attempting to read a value of the wrong type");
// Allocate the output buffer
if (m_cbValueDataSize != sizeof(DWORD))
ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
L"Unexpected error: unexpected DWORD size [%ld, %ld]", m_cbValueDataSize, sizeof(DWORD));
// Fill dwInternalValue with the DWORD value
DWORD dwInternalValue = 0;
DWORD cchNameSize = m_cchMaxValueNameLen;
DWORD dwCurrentValueType = 0;
DWORD cbValueSize = m_cbValueDataSize;
LONG lRes = ::RegEnumValue(
m_hKey, // IN HKEY hKey,
m_dwCurrentValueIndex, // IN DWORD dwIndex,
m_awszValueName, // OUT LPWSTR lpName,
&cchNameSize, // IN OUT LPDWORD lpcbName,
NULL, // IN LPDWORD lpReserved,
&dwCurrentValueType, // IN OUT LPDWORD lpType,
(LPBYTE)&dwInternalValue, // IN OUT LPBYTE lpData,
&cbValueSize); // IN OUT LPDWORD lpcbData
switch(lRes)
{
case ERROR_SUCCESS:
BS_ASSERT(cchNameSize != 0);
BS_ASSERT(cbValueSize != 0);
if (dwCurrentValueType != m_dwCurrentValueType)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
L"Unexpected error: current value type changed in the meantime %lu %lu",
dwCurrentValueType, m_dwCurrentValueType);
break;
case ERROR_NO_MORE_ITEMS:
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
default:
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
}
dwValue = dwInternalValue;
}
// Reads a REG_BINARY value from the registry key
void CVssRegistryValueIterator::GetCurrentValueContent(
OUT PBYTE & pbValue, // Must be deleted with "delete[]"
OUT DWORD & cbSize
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
ReadCurrentValueDetails();
BS_ASSERT(m_bSeekDone);
if (m_dwCurrentValueType != REG_BINARY) {
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: attempting to read a value of the wrong type");
}
// Allocate the output buffer
DWORD cbValueSize = m_cbValueDataSize;
CVssAutoCppPtr<PBYTE> awszBuffer;
awszBuffer.AllocateBytes(cbValueSize);
// Fill awszBuffer with the string contents
DWORD cchNameSize = m_cchMaxValueNameLen;
DWORD dwCurrentValueType = 0;
LONG lRes = ::RegEnumValue(
m_hKey, // IN HKEY hKey,
m_dwCurrentValueIndex, // IN DWORD dwIndex,
m_awszValueName, // OUT LPWSTR lpName,
&cchNameSize, // IN OUT LPDWORD lpcbName,
NULL, // IN LPDWORD lpReserved,
&dwCurrentValueType, // IN OUT LPDWORD lpType,
(LPBYTE)awszBuffer.Get(), // IN OUT LPBYTE lpData,
&cbValueSize); // IN OUT LPDWORD lpcbData
switch(lRes)
{
case ERROR_SUCCESS:
BS_ASSERT(cchNameSize != 0);
BS_ASSERT(cbValueSize != 0);
if (dwCurrentValueType != m_dwCurrentValueType)
ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
L"Unexpected error: current value type changed in the meantime %lu %lu",
dwCurrentValueType, m_dwCurrentValueType);
break;
case ERROR_NO_MORE_ITEMS:
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
default:
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
}
pbValue = awszBuffer.Detach();
cbSize = cbValueSize;
}
// Returns the name and the type of the current value.
void CVssRegistryValueIterator::ReadCurrentValueDetails() throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::ReadCurrentValueDetails" );
if (!m_bAttached || !m_awszValueName.GetRef()) {
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: noninitialized iterator");
}
// Do not load twice the same value
if (m_bSeekDone)
return;
// Fill wszSubKeyName with the name of the subkey
DWORD cchNameSize = m_cchMaxValueNameLen;
LONG lRes = ::RegEnumValue(
m_hKey, // IN HKEY hKey,
m_dwCurrentValueIndex, // IN DWORD dwIndex,
m_awszValueName, // OUT LPWSTR lpName,
&cchNameSize, // IN OUT LPDWORD lpcbName,
NULL, // IN LPDWORD lpReserved,
&m_dwCurrentValueType, // IN OUT LPDWORD lpType,
NULL, // IN OUT LPBYTE lpData,
&m_cbValueDataSize); // IN OUT LPDWORD lpcbData
switch(lRes)
{
case ERROR_SUCCESS:
BS_ASSERT(cchNameSize != 0);
BS_ASSERT(m_cbValueDataSize != 0);
break; // Go to Next key
default:
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
case ERROR_NO_MORE_ITEMS:
BS_ASSERT(false);
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
}
m_bSeekDone = true;
}
// Attaches the iterator to a registry key
void CVssRegistryValueIterator::Attach(
IN CVssRegistryKey & key
) throw(HRESULT)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::Attach" );
// Reset all members
Detach();
m_hKey = key.GetHandle();
BS_ASSERT(m_hKey);
// Get the number of values and the max value name length
DWORD dwValuesCount = 0;
DWORD dwMaxValueNameLen = 0;
LONG lRes = ::RegQueryInfoKeyW(
m_hKey, // handle to key
NULL, // class buffer
NULL, // size of class buffer
NULL, // reserved
NULL, // number of subkeys
NULL, // longest subkey name
NULL, // longest class string
&dwValuesCount, // number of value entries
&dwMaxValueNameLen, // longest value name
NULL, // longest value data
NULL, // descriptor length
NULL); // last write time
if (lRes != ERROR_SUCCESS)
ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegQueryInfoKeyW(%p, ...)", m_hKey);
// Allocate the key name with a sufficient length.
// We assume that the key length cannot change during the ennumeration).
if (dwMaxValueNameLen)
m_awszValueName.Allocate(dwMaxValueNameLen);
// Setting the number of subkeys
m_dwValuesCount = dwValuesCount;
m_cchMaxValueNameLen = dwMaxValueNameLen + 1;
// Attachment completed
m_bAttached = true;
}
void CVssRegistryValueIterator::Detach()
{
// Initialize data members
m_hKey = NULL;
m_dwValuesCount = 0;
m_dwCurrentValueIndex = 0;
m_cchMaxValueNameLen = 0;
m_awszValueName.Clear();
m_dwCurrentValueType = 0;
m_cbValueDataSize = 0;
m_bSeekDone = false;
m_bAttached = false;
}
// Tells if the current key is still valid
bool CVssRegistryValueIterator::IsEOF()
{
return (m_dwCurrentValueIndex >= m_dwValuesCount);
}
// Return the number of subkeys at the moment of attaching
DWORD CVssRegistryValueIterator::GetValuesCount()
{
return (m_dwValuesCount);
}
// Set the next key as being the current one in the enumeration
void CVssRegistryValueIterator::MoveNext()
{
if (!IsEOF())
{
m_bSeekDone = false;
m_dwCurrentValueType = 0;
m_cbValueDataSize = 0;
m_dwCurrentValueIndex++;
}
else
BS_ASSERT(false);
}
/////////////////////////////////////////////////////////////////////////////
// CVssDiag implementation
void CVssDiag::Initialize(
IN LPCWSTR pwszStaticContext
)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::Initialize" );
try
{
ft.Trace( VSSDBG_GEN, L"Parameters %s", pwszStaticContext);
if ((pwszStaticContext == NULL) || (pwszStaticContext[0] == L'\0')) {
BS_ASSERT(false); // Programming error
ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L" NULL or empty parameter");
}
// If not initialized, return
if (m_bInitialized)
return;
// If not enabled, return
if(!m_key.Open(HKEY_LOCAL_MACHINE, x_wszVssDiagPath)) {
ft.Trace(VSSDBG_GEN, L"Diagnose not enabled (%s)", pwszStaticContext);
return;
}
// Try to read the "Enabled" flag. If not present, return.
CVssAutoPWSZ awszValue;
if (m_key.GetValue(L"", awszValue.GetRef(), false))
{
if (!awszValue.GetRef()) {
BS_ASSERT(false);
return;
}
if (wcscmp(awszValue, x_wszVssDiagEnabledValue) != 0)
return;
// Open the key, if exists. If not, create it.
if (!m_key.Open(HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVssDiagPath, pwszStaticContext))
m_key.Create(HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVssDiagPath, pwszStaticContext);
ft.Trace(VSSDBG_GEN, L"Diagnose enabled for (%s)", pwszStaticContext);
// Zero out the queued diag data
::VssZeroOut(m_QueuedDiagData);
// Mark the object as "initialized"
m_bInitialized = true;
}
}
VSS_STANDARD_CATCH(ft)
}
void CVssDiag::RecordWriterEvent(
IN VSS_OPERATION eOperation,
IN DWORD dwEventContext,
IN DWORD dwCurrentState,
IN HRESULT hrLastError,
IN GUID guidSnapshotSetID /* = GUID_NULL */
)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::RecordWriterEvent" );
RecordGenericEvent(
eOperation,
dwEventContext,
dwCurrentState,
hrLastError,
guidSnapshotSetID
);
}
void CVssDiag::RecordGenericEvent(
IN DWORD dwEventID,
IN DWORD dwEventContext,
IN DWORD dwCurrentState,
IN HRESULT hrLastError,
IN GUID guidSnapshotSetID /* = GUID_NULL */
)
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::RecordGenericEvent" );
try
{
ft.Trace( VSSDBG_GEN, L"Parameters %ld, %ld, %ld, 0x%08lx, " WSTR_GUID_FMT,
dwEventID, dwEventContext, dwCurrentState, hrLastError,
GUID_PRINTF_ARG(guidSnapshotSetID));
// If not initialized, return
if (!m_bInitialized)
return;
if (dwEventContext & CVssDiag::VSS_DIAG_IGNORE_LEAVE)
return;
// Get new event parameters
bool bInOperation = !!(dwEventContext & VSS_DIAG_ENTER_OPERATION);
LPCWSTR pwszEventName = GetStringFromOperation(bInOperation, dwEventID);
// Some events do not require logging
if (NULL == pwszEventName)
return;
ft.Trace(VSSDBG_GEN, L"Event name: %s", pwszEventName);
// Fill out event data
CVssDiagData data;
data.m_dwSize = sizeof(data); // For future compatibility
data.m_dwReserved = 0;
CVsFileTime filetime;
data.m_llTimestamp = filetime;
data.m_dwProcessID = GetCurrentProcessId();
data.m_dwThreadID = GetCurrentThreadId();
data.m_dwEventID = dwEventID;
data.m_dwEventContext = dwEventContext;
data.m_dwCurrentState = dwCurrentState;
data.m_hrLastErrorCode = hrLastError;
data.m_guidSnapshotSetID = guidSnapshotSetID;
data.m_pReserved1 = NULL;
data.m_pReserved2 = NULL;
// If we are in queued mode, then add the element to the queue
if (IsQueuedMode(dwEventID, dwEventContext))
{
if (m_dwQueuedElements < x_nMaxQueuedDiagData)
{
m_QueuedDiagData[m_dwQueuedElements].m_pwszEventName = pwszEventName;
m_QueuedDiagData[m_dwQueuedElements].m_diag = data;
m_dwQueuedElements++;
}
}
else
{
// Flush the queue
FlushQueue();
// Write the current data as a binary block
m_key.SetBinaryValue(pwszEventName, (BYTE *) &data, sizeof(data));
}
}
VSS_STANDARD_CATCH(ft)
}
// Flush the queued elements in registry
void CVssDiag::FlushQueue()
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::FlushQueue" );
try
{
DWORD dwQueuedElements = m_dwQueuedElements;
m_dwQueuedElements = 0;
for ( DWORD dwIndex = 0; dwIndex < dwQueuedElements; dwIndex++)
{
// Write the data as a binary block
LPCWSTR pwszEventName = m_QueuedDiagData[dwIndex].m_pwszEventName;
CVssDiagData* pDiagData = &(m_QueuedDiagData[dwIndex].m_diag);
m_key.SetBinaryValue(pwszEventName, (BYTE *) pDiagData, sizeof(CVssDiagData));
}
}
VSS_STANDARD_CATCH(ft)
}
// Size of the L"VSS_IN_" string, without the zero character
const x_VssPrefixSize = SIZEOF_ARRAY(L"VSS_IN_") - 1;
// Define for simplifying hte case statement below
#define VSS_OPERATION_CASE_STMT(operation) \
case operation: \
if (bInOperation) \
return x_VssPrefixSize + VSS_WSTRINGIZE(operation) L" (Enter)" ; \
else \
return x_VssPrefixSize + VSS_WSTRINGIZE(operation) L" (Leave)" ;
// Define for simplifying hte case statement below
#define VSS_WRITERSTATE_CASE_STMT(state) \
case state: \
if (bInOperation) \
return VSS_WSTRINGIZE(state) L" (SetCurrentState)" ; \
else \
return NULL;
// Define for simplifying hte case statement below
#define VSS_HRESULT_CASE_STMT(hresult) \
case hresult: \
if (bInOperation) \
return VSS_WSTRINGIZE(hresult) L" (SetCurrentFailure)" ; \
else \
return NULL;
// Convert a writer status into a string
LPCWSTR CVssDiag::GetStringFromOperation(
IN bool bInOperation,
IN DWORD dwOperation
)
{
switch (dwOperation)
{
// Writer operations
VSS_OPERATION_CASE_STMT(VSS_IN_IDENTIFY)
VSS_OPERATION_CASE_STMT(VSS_IN_PREPAREBACKUP)
VSS_OPERATION_CASE_STMT(VSS_IN_PREPARESNAPSHOT)
VSS_OPERATION_CASE_STMT(VSS_IN_FREEZE)
VSS_OPERATION_CASE_STMT(VSS_IN_THAW)
VSS_OPERATION_CASE_STMT(VSS_IN_POSTSNAPSHOT)
VSS_OPERATION_CASE_STMT(VSS_IN_BACKUPCOMPLETE)
VSS_OPERATION_CASE_STMT(VSS_IN_PRERESTORE)
VSS_OPERATION_CASE_STMT(VSS_IN_POSTRESTORE)
VSS_OPERATION_CASE_STMT(VSS_IN_GETSTATE)
VSS_OPERATION_CASE_STMT(VSS_IN_ABORT)
VSS_OPERATION_CASE_STMT(VSS_IN_BACKUPSHUTDOWN)
VSS_OPERATION_CASE_STMT(VSS_IN_BKGND_FREEZE_THREAD)
// Other Event IDs
VSS_OPERATION_CASE_STMT(VSS_IN_OPEN_VOLUME_HANDLE)
VSS_OPERATION_CASE_STMT(VSS_IN_IOCTL_FLUSH_AND_HOLD)
VSS_OPERATION_CASE_STMT(VSS_IN_IOCTL_RELEASE)
// Writer State changes.
// These values are coming from SetCurrentState
VSS_WRITERSTATE_CASE_STMT(VSS_WS_UNKNOWN)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_STABLE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_FREEZE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_THAW)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_POST_SNAPSHOT)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_IDENTIFY)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PREPARE_BACKUP)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_FREEZE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_THAW)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_POST_SNAPSHOT)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_BACKUP_COMPLETE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PRE_RESTORE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_POST_RESTORE)
VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_BACKUPSHUTDOWN)
// Writer error codes
// These values are coming from SetCurrentFailure
VSS_HRESULT_CASE_STMT(VSS_S_OK)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_OUTOFRESOURCES)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_TIMEOUT)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_RETRYABLE)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_NONRETRYABLE)
VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_RECOVERY_FAILED)
VSS_HRESULT_CASE_STMT(VSS_E_WRITER_NOT_RESPONDING)
default:
{
static WCHAR wszBuffer[80];
::StringCchPrintfW(STRING_CCH_PARAM(wszBuffer),
L"UNKNOWN_EVENT[0x%08lx] %s",
dwOperation, bInOperation? L"(Enter)": L"(Leave)");
return wszBuffer;
}
}
}
// Returns true if the diagnose must operate in queued mode
// (i.e. without writing to registry)
bool CVssDiag::IsQueuedMode(
IN DWORD dwEventID,
IN DWORD dwEventContext
)
{
switch (dwEventID)
{
case VSS_IN_IOCTL_FLUSH_AND_HOLD:
// Always in Queued mode (since we don't know the order for parallel F&H ioctls)
return true;
case VSS_IN_IOCTL_RELEASE:
// If we are in ENTER then we are still in queued mode
return !!(dwEventContext & VSS_DIAG_ENTER_OPERATION);
default:
return false;
}
}
bool CVssMachineInformation::IsDuringSetup()
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssMachineInformation::IsDuringSetup" );
CRegKey cRegKeySetup;
DWORD dwRes = cRegKeySetup.Open(HKEY_LOCAL_MACHINE, x_SetupKey, KEY_READ);
if (dwRes == ERROR_SUCCESS)
{
DWORD dwValue;
dwRes = cRegKeySetup.QueryValue(dwValue, x_SystemSetupInProgress);
if (dwRes == ERROR_SUCCESS && dwValue > 0)
return true;
dwRes = cRegKeySetup.QueryValue(dwValue, x_UpgradeInProgress);
if (dwRes == ERROR_SUCCESS && dwValue > 0)
return true;
}
return false;
}
bool CVssMachineInformation::IsDuringSafeMode()
{
CVssFunctionTracer ft( VSSDBG_GEN, L"CVssMachineInformation::IsDuringSafeMode" );
CRegKey cRegKeySetup;
DWORD dwRes = cRegKeySetup.Open(HKEY_LOCAL_MACHINE, x_SafebootKey, KEY_READ);
if (dwRes == ERROR_SUCCESS)
{
DWORD dwValue;
dwRes = cRegKeySetup.QueryValue(dwValue, x_SafebootOptionValue);
if (dwRes == ERROR_SUCCESS)
{
ft.Trace(VSSDBG_GEN, L"SafeBoot option 0x%08lx", dwValue);
switch(dwValue)
{
case SAFEBOOT_MINIMAL:
case SAFEBOOT_NETWORK:
return true;
case SAFEBOOT_DSREPAIR:
// Writers are allowed in DS Repair
// (That's the only way for the AD Writer to do its job on restore).
return false;
default:
ft.Trace(VSSDBG_GEN, L"Unrecognized safe mode option %ud", dwValue);
return true;
}
}
}
return false;
}