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

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module registry.cxx | Implementation of CVssRegistryKey
  6. @end
  7. Author:
  8. Adi Oltean [aoltean] 03/14/2001
  9. Revision History:
  10. Name Date Comments
  11. aoltean 03/14/2001 Created
  12. --*/
  13. /////////////////////////////////////////////////////////////////////////////
  14. // Includes
  15. #include "stdafx.hxx"
  16. #include "memory"
  17. #include <safeboot.h>
  18. #include "vs_inc.hxx"
  19. #include "vs_reg.hxx"
  20. #include "vs_reg.hxx"
  21. #include "vss.h"
  22. #include "vswriter.h"
  23. ////////////////////////////////////////////////////////////////////////
  24. // Standard foo for file name aliasing. This code block must be after
  25. // all includes of VSS header files.
  26. //
  27. #ifdef VSS_FILE_ALIAS
  28. #undef VSS_FILE_ALIAS
  29. #endif
  30. #define VSS_FILE_ALIAS "REGREGSC"
  31. //
  32. ////////////////////////////////////////////////////////////////////////
  33. /////////////////////////////////////////////////////////////////////////////
  34. // CVssRegistryKey implementation
  35. // Creates the registry key.
  36. // Throws an error if the key already exists
  37. void CVssRegistryKey::Create(
  38. IN HKEY hAncestorKey,
  39. IN LPCWSTR pwszPathFormat,
  40. IN ...
  41. ) throw(HRESULT)
  42. {
  43. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Create" );
  44. BS_ASSERT(hAncestorKey);
  45. BS_ASSERT(pwszPathFormat);
  46. // Build the path to the key
  47. WCHAR wszKeyPath[x_nVssMaxRegBuffer];
  48. va_list marker;
  49. va_start( marker, pwszPathFormat );
  50. ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
  51. va_end( marker );
  52. if (ft.HrFailed())
  53. ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
  54. // Create the key
  55. BS_ASSERT( (m_samDesired & KEY_WRITE) == KEY_WRITE);
  56. DWORD dwDisposition = 0;
  57. HKEY hRegKey = NULL;
  58. LONG lRes = ::RegCreateKeyExW(
  59. hAncestorKey, // IN HKEY hKey,
  60. wszKeyPath, // IN LPCWSTR lpSubKey,
  61. 0, // IN DWORD Reserved,
  62. REG_NONE, // IN LPWSTR lpClass,
  63. m_dwKeyCreateOptions, // IN DWORD dwOptions,
  64. m_samDesired, // IN REGSAM samDesired,
  65. NULL, // IN LPSECURITY_ATTRIBUTES lpSecurityAttributes,
  66. &hRegKey, // OUT PHKEY phkResult,
  67. &dwDisposition // OUT LPDWORD lpdwDisposition
  68. );
  69. if ( lRes != ERROR_SUCCESS )
  70. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegCreateKeyExW(%ld,%s,...)",
  71. hAncestorKey, wszKeyPath);
  72. // Check whether we created or opened the key
  73. switch ( dwDisposition )
  74. {
  75. case REG_CREATED_NEW_KEY:
  76. if (!m_awszKeyPath.CopyFrom(wszKeyPath)) {
  77. ::RegCloseKey( hRegKey );
  78. ft.Throw( VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
  79. }
  80. Close();
  81. m_hRegKey = hRegKey;
  82. break;
  83. case REG_OPENED_EXISTING_KEY:
  84. ::RegCloseKey( hRegKey );
  85. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_ALREADY_EXISTS, L"Key %s already exists", wszKeyPath);
  86. default:
  87. BS_ASSERT( false );
  88. if (hRegKey && (hRegKey != INVALID_HANDLE_VALUE))
  89. ::RegCloseKey( hRegKey );
  90. ft.TranslateGenericError(VSSDBG_GEN, E_UNEXPECTED, L"RegCreateKeyExW(%ld,%s,...,[%lu])",
  91. hAncestorKey, wszKeyPath, dwDisposition);
  92. }
  93. }
  94. // Opens a registry key.
  95. bool CVssRegistryKey::Open(
  96. IN HKEY hAncestorKey,
  97. IN LPCWSTR pwszPathFormat,
  98. IN ...
  99. ) throw(HRESULT)
  100. {
  101. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Open" );
  102. BS_ASSERT(hAncestorKey);
  103. BS_ASSERT(pwszPathFormat);
  104. // Build the path to the key
  105. WCHAR wszKeyPath[x_nVssMaxRegBuffer];
  106. va_list marker;
  107. va_start( marker, pwszPathFormat );
  108. ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
  109. va_end( marker );
  110. if (ft.HrFailed())
  111. ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
  112. // Open the key
  113. HKEY hRegKey = NULL;
  114. LONG lRes = ::RegOpenKeyExW(
  115. hAncestorKey, // IN HKEY hKey,
  116. wszKeyPath, // IN LPCWSTR lpSubKey,
  117. 0, // IN DWORD dwOptions,
  118. m_samDesired, // IN REGSAM samDesired,
  119. &hRegKey // OUT PHKEY phkResult
  120. );
  121. if ( lRes == ERROR_FILE_NOT_FOUND )
  122. return false;
  123. if ( lRes != ERROR_SUCCESS )
  124. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegOpenKeyExW(%ld,%s,...)",
  125. hAncestorKey, wszKeyPath);
  126. if (!m_awszKeyPath.CopyFrom(wszKeyPath)) {
  127. ::RegCloseKey( hRegKey );
  128. ft.Throw( VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
  129. }
  130. Close();
  131. m_hRegKey = hRegKey;
  132. return true;
  133. }
  134. // Recursively deletes a subkey.
  135. // Throws an error if the subkey does not exist
  136. void CVssRegistryKey::DeleteSubkey(
  137. IN LPCWSTR pwszPathFormat,
  138. IN ...
  139. ) throw(HRESULT)
  140. {
  141. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::DeleteSubkey" );
  142. BS_ASSERT(pwszPathFormat);
  143. // Build the path to the key
  144. WCHAR wszKeyPath[x_nVssMaxRegBuffer];
  145. va_list marker;
  146. va_start( marker, pwszPathFormat );
  147. ft.hr = StringCchVPrintfW( STRING_CCH_PARAM(wszKeyPath), pwszPathFormat, marker );
  148. va_end( marker );
  149. if (ft.HrFailed())
  150. ft.TranslateGenericError(VSSDBG_GEN, ft.hr, L"StringCchVPrintfW()");
  151. // Recursively delete the key
  152. DWORD dwRes = ::SHDeleteKey(
  153. m_hRegKey, // IN HKEY hKey,
  154. wszKeyPath // IN LPCTSTR pszSubKey
  155. );
  156. if ( dwRes == ERROR_FILE_NOT_FOUND )
  157. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Key with path %s\\%s not found",
  158. m_awszKeyPath.GetRef(), wszKeyPath);
  159. if ( dwRes != ERROR_SUCCESS )
  160. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(dwRes), L"SHDeleteKey(%ld[%s],%s)",
  161. m_hRegKey, m_awszKeyPath.GetRef(), wszKeyPath);
  162. }
  163. // Deletes a value.
  164. // Throws an error if the value does not exist
  165. void CVssRegistryKey::DeleteValue(
  166. IN LPCWSTR pwszValueName
  167. ) throw(HRESULT)
  168. {
  169. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::DeleteValue" );
  170. BS_ASSERT(pwszValueName);
  171. // Recursively delete the key
  172. LONG lRes = ::RegDeleteValue(
  173. m_hRegKey, // IN HKEY hKey,
  174. pwszValueName // IN LPCTSTR pwszValueName
  175. );
  176. if ( lRes == ERROR_FILE_NOT_FOUND )
  177. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Value %s\\%s not found",
  178. m_awszKeyPath.GetRef(), pwszValueName);
  179. if ( lRes != ERROR_SUCCESS )
  180. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegDeleteValue(%ld[%s],%s)",
  181. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName);
  182. }
  183. // Adds a LONGLONG value to the registry key
  184. void CVssRegistryKey::SetValue(
  185. IN LPCWSTR pwszValueName,
  186. IN LONGLONG llValue
  187. ) throw(HRESULT)
  188. {
  189. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_LONGLONG" );
  190. // Convert the value to a string
  191. WCHAR wszValue[x_nVssMaxRegNumBuffer];
  192. ft.hr = StringCchPrintfW( STRING_CCH_PARAM(wszValue),
  193. L"%I64d", llValue );
  194. if (ft.HrFailed())
  195. ft.TranslateGenericError( VSSDBG_GEN, ft.hr, L"StringCchPrintfW()");
  196. // Set the value as string
  197. SetValue(pwszValueName, wszValue);
  198. }
  199. // Adds a REG_SZ value to the registry key
  200. void CVssRegistryKey::SetValue(
  201. IN LPCWSTR pwszValueName,
  202. IN LPCWSTR pwszValue,
  203. IN REGSAM eSzType /* = REG_SZ */
  204. ) throw(HRESULT)
  205. {
  206. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_PWSZ" );
  207. // Assert paramters
  208. BS_ASSERT(pwszValueName);
  209. BS_ASSERT(pwszValue);
  210. BS_ASSERT(m_hRegKey);
  211. BS_ASSERT((eSzType == REG_SZ) || (eSzType == REG_EXPAND_SZ));
  212. // Set the value
  213. DWORD dwLength = ::lstrlenW( pwszValue );
  214. LONG lRes = ::RegSetValueExW(
  215. m_hRegKey, // IN HKEY hKey,
  216. pwszValueName, // IN LPCWSTR lpValueName,
  217. 0, // IN DWORD Reserved,
  218. eSzType, // IN DWORD dwType,
  219. (CONST BYTE*)pwszValue, // IN CONST BYTE* lpData,
  220. (dwLength + 1) * sizeof(WCHAR) // IN DWORD cbData
  221. );
  222. if ( lRes != ERROR_SUCCESS )
  223. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
  224. L"RegSetValueExW(0x%08lx,%s,0,REG_SZ,%s.%d)",
  225. m_hRegKey, m_awszKeyPath.GetRef(), pwszValue, (dwLength + 1) * sizeof(WCHAR));
  226. }
  227. // Adds a REG_DWORD value to the registry key
  228. void CVssRegistryKey::SetValue(
  229. IN LPCWSTR pwszValueName,
  230. IN DWORD dwValue
  231. ) throw(HRESULT)
  232. {
  233. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetValue_DWORD" );
  234. // Assert paramters
  235. BS_ASSERT(pwszValueName);
  236. BS_ASSERT(m_hRegKey);
  237. // Set the value
  238. LONG lRes = ::RegSetValueExW(
  239. m_hRegKey, // IN HKEY hKey,
  240. pwszValueName, // IN LPCWSTR lpValueName,
  241. 0, // IN DWORD Reserved,
  242. REG_DWORD, // IN DWORD dwType,
  243. (CONST BYTE*)&dwValue, // IN CONST BYTE* lpData,
  244. sizeof(DWORD) // IN DWORD cbData
  245. );
  246. if ( lRes != ERROR_SUCCESS )
  247. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
  248. L"RegSetValueExW(0x%08lx,%s,0,REG_DWORD,%ld)",
  249. m_hRegKey, m_awszKeyPath.GetRef(), dwValue);
  250. }
  251. // Adds a REG_MULTI_SZ value to the registry key
  252. // WARNING: do not call this routine for a REG_SZ value!
  253. // (Intentionally this is a different function so that it won't
  254. // be confused with CVssRegistryKey::SetValue)
  255. void CVssRegistryKey::SetMultiszValue(
  256. IN LPCWSTR pwszValueName,
  257. IN LPCWSTR pwszValue
  258. ) throw(HRESULT)
  259. {
  260. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetMultiszValue" );
  261. // Assert paramters
  262. BS_ASSERT(pwszValueName);
  263. BS_ASSERT(pwszValue);
  264. BS_ASSERT(m_hRegKey);
  265. // Get the length of the multi-sz string, including the zero character for each string
  266. DWORD dwLength = 0;
  267. LPCWSTR pwszCurrent = pwszValue;
  268. do
  269. {
  270. // Add the zero character
  271. LONG dwCurrentLength = ::lstrlenW(pwszCurrent) + 1;
  272. dwLength += dwCurrentLength;
  273. pwszCurrent += dwCurrentLength;
  274. }
  275. while(pwszCurrent[0]);
  276. // Add the final zero character
  277. dwLength += 1;
  278. // Set the value
  279. LONG lRes = ::RegSetValueExW(
  280. m_hRegKey, // IN HKEY hKey,
  281. pwszValueName, // IN LPCWSTR lpValueName,
  282. 0, // IN DWORD Reserved,
  283. REG_MULTI_SZ, // IN DWORD dwType,
  284. (CONST BYTE*)pwszValue, // IN CONST BYTE* lpData,
  285. (dwLength) * sizeof(WCHAR) // IN DWORD cbData
  286. );
  287. if ( lRes != ERROR_SUCCESS )
  288. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
  289. L"RegSetValueExW(0x%08lx,%s,0,REG_SZ,%s.%d)",
  290. m_hRegKey, m_awszKeyPath.GetRef(), pwszValue, (dwLength) * sizeof(WCHAR));
  291. }
  292. // Adds a binary value to the registry key
  293. void CVssRegistryKey::SetBinaryValue(
  294. IN LPCWSTR pwszValueName,
  295. IN BYTE * pbData,
  296. IN DWORD dwSize
  297. ) throw(HRESULT)
  298. {
  299. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::SetBinaryValue" );
  300. // Assert paramters
  301. BS_ASSERT(pwszValueName);
  302. BS_ASSERT(pbData);
  303. BS_ASSERT(dwSize);
  304. BS_ASSERT(m_hRegKey);
  305. // Set the value
  306. LONG lRes = ::RegSetValueExW(
  307. m_hRegKey, // IN HKEY hKey,
  308. pwszValueName, // IN LPCWSTR lpValueName,
  309. 0, // IN DWORD Reserved,
  310. REG_BINARY, // IN DWORD dwType,
  311. pbData, // IN CONST BYTE* lpData,
  312. dwSize // IN DWORD cbData
  313. );
  314. if ( lRes != ERROR_SUCCESS )
  315. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lRes),
  316. L"RegSetValueExW(0x%08lx,%s,0,REG_BINARY,%p.%lu)",
  317. m_hRegKey, m_awszKeyPath.GetRef(), pbData, dwSize);
  318. }
  319. // Reads a VSS_PWSZ value from the registry key
  320. bool CVssRegistryKey::GetValue(
  321. IN LPCWSTR pwszValueName,
  322. OUT VSS_PWSZ & pwszValue,
  323. IN bool bThrowIfNotFound /* = true */
  324. ) throw(HRESULT)
  325. {
  326. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_PWSZ" );
  327. // Assert parameters
  328. BS_ASSERT(pwszValueName);
  329. BS_ASSERT(pwszValue == NULL);
  330. // Reset the OUT parameter
  331. pwszValue = NULL;
  332. // Get the value length (we suppose that doesn't change)
  333. DWORD dwType = 0;
  334. DWORD dwSizeInBytes = 0;
  335. LONG lResult = ::RegQueryValueExW(
  336. m_hRegKey,
  337. pwszValueName,
  338. NULL,
  339. &dwType,
  340. NULL,
  341. &dwSizeInBytes);
  342. if (lResult == ERROR_FILE_NOT_FOUND)
  343. {
  344. if (bThrowIfNotFound)
  345. {
  346. ft.LogGenericWarning(VSSDBG_GEN,
  347. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
  348. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  349. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
  350. }
  351. else
  352. return ft.Exit(false);
  353. }
  354. if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
  355. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  356. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  357. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  358. // Check the type and the size
  359. if (dwType != REG_SZ && dwType != REG_EXPAND_SZ)
  360. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a string value 0x%08lx(%s),%s",
  361. dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
  362. BS_ASSERT(dwSizeInBytes);
  363. // Allocate the buffer
  364. CVssAutoPWSZ awszValue;
  365. DWORD dwSizeOfString = dwSizeInBytes/sizeof(WCHAR);
  366. awszValue.Allocate(dwSizeOfString);
  367. // Get the string contents
  368. DWORD dwType2 = 0;
  369. DWORD dwSizeInBytes2 = dwSizeOfString * (sizeof(WCHAR));
  370. BS_ASSERT( dwSizeInBytes2 == dwSizeInBytes);
  371. lResult = ::RegQueryValueExW(
  372. m_hRegKey,
  373. pwszValueName,
  374. NULL,
  375. &dwType2,
  376. (LPBYTE)awszValue.GetRef(),
  377. &dwSizeInBytes2);
  378. if (lResult != ERROR_SUCCESS)
  379. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  380. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  381. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
  382. BS_ASSERT(dwType2 == REG_SZ || dwType2 == REG_EXPAND_SZ);
  383. BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
  384. (awszValue.GetRef())[dwSizeOfString] = L'\0';
  385. // Set the OUT parameter
  386. pwszValue = awszValue.Detach();
  387. return ft.Exit(true);
  388. }
  389. // Reads a LONGLONG value from the registry key
  390. bool CVssRegistryKey::GetValue(
  391. IN LPCWSTR pwszValueName,
  392. OUT LONGLONG & llValue,
  393. IN bool bThrowIfNotFound /* = true */
  394. ) throw(HRESULT)
  395. {
  396. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_LONGLONG" );
  397. // Assert parameters
  398. BS_ASSERT(pwszValueName);
  399. CVssAutoPWSZ awszValue;
  400. bool bResult = GetValue(pwszValueName, awszValue.GetRef(), bThrowIfNotFound);
  401. if (!bResult)
  402. {
  403. BS_ASSERT(!bThrowIfNotFound);
  404. return ft.Exit(false);
  405. }
  406. BS_ASSERT(awszValue.GetRef());
  407. BS_ASSERT(awszValue.GetRef()[0]);
  408. // Read the LONGLONG string
  409. llValue = ::_wtoi64(awszValue);
  410. return ft.Exit(true);
  411. }
  412. // Reads a DWORD value from the registry key
  413. bool CVssRegistryKey::GetValue(
  414. IN LPCWSTR pwszValueName,
  415. OUT DWORD & dwValue,
  416. IN bool bThrowIfNotFound /* = true */
  417. ) throw(HRESULT)
  418. {
  419. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetValue_DWORD" );
  420. // Assert parameters
  421. BS_ASSERT(pwszValueName);
  422. // Reset the OUT parameter
  423. dwValue = 0;
  424. // Get the value length (we suppose that doesn't change)
  425. DWORD dwType = 0;
  426. DWORD dwSizeInBytes = 0;
  427. LONG lResult = ::RegQueryValueExW(
  428. m_hRegKey,
  429. pwszValueName,
  430. NULL,
  431. &dwType,
  432. NULL,
  433. &dwSizeInBytes);
  434. if (lResult == ERROR_FILE_NOT_FOUND)
  435. {
  436. if (bThrowIfNotFound)
  437. {
  438. ft.LogGenericWarning(VSSDBG_GEN,
  439. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
  440. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  441. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
  442. }
  443. else
  444. return ft.Exit(false);
  445. }
  446. if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
  447. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  448. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  449. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  450. // Check the type and the size
  451. if (dwType != REG_DWORD)
  452. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a DWORD value 0x%08lx(%s),%s",
  453. dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
  454. BS_ASSERT(dwSizeInBytes == sizeof(DWORD));
  455. // Get the string contents
  456. DWORD dwType2 = 0;
  457. DWORD dwSizeInBytes2 = dwSizeInBytes;
  458. DWORD dwReadValue = 0;
  459. lResult = ::RegQueryValueExW(
  460. m_hRegKey,
  461. pwszValueName,
  462. NULL,
  463. &dwType2,
  464. (LPBYTE)&dwReadValue,
  465. &dwSizeInBytes2);
  466. if (lResult != ERROR_SUCCESS)
  467. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  468. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  469. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
  470. BS_ASSERT(dwType2 == REG_DWORD);
  471. BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
  472. dwValue = dwReadValue;
  473. return ft.Exit(true);
  474. }
  475. // Reads a REG_BINARY value from the registry key
  476. bool CVssRegistryKey::GetBinaryValue(
  477. IN LPCWSTR pwszValueName,
  478. OUT BYTE* & pbData,
  479. OUT DWORD & dwSize,
  480. IN bool bThrowIfNotFound /* = true */
  481. ) throw(HRESULT)
  482. {
  483. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::GetBinaryValue" );
  484. // Assert parameters
  485. BS_ASSERT(pwszValueName);
  486. BS_ASSERT(pbData == NULL);
  487. BS_ASSERT(dwSize == NULL);
  488. // Reset the OUT parameters
  489. pbData = NULL;
  490. dwSize = 0;
  491. // Get the value length (we suppose that doesn't change)
  492. DWORD dwType = 0;
  493. DWORD dwSizeInBytes = 0;
  494. LONG lResult = ::RegQueryValueExW(
  495. m_hRegKey,
  496. pwszValueName,
  497. NULL,
  498. &dwType,
  499. NULL,
  500. &dwSizeInBytes);
  501. if (lResult == ERROR_FILE_NOT_FOUND)
  502. {
  503. if (bThrowIfNotFound)
  504. {
  505. ft.LogGenericWarning(VSSDBG_GEN,
  506. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu]) => ERROR_FILE_NOT_FOUND",
  507. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  508. ft.Throw( VSSDBG_GEN, VSS_E_OBJECT_NOT_FOUND, L"Registry key not found");
  509. }
  510. else
  511. return ft.Exit(false);
  512. }
  513. if ((lResult != ERROR_SUCCESS) && (lResult != ERROR_MORE_DATA))
  514. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  515. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  516. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType, dwSizeInBytes);
  517. // Check the type and the size
  518. if (dwType != REG_BINARY)
  519. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected type %lu for a binary value 0x%08lx(%s),%s",
  520. dwType, m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName );
  521. BS_ASSERT(dwSizeInBytes);
  522. // Allocate the buffer
  523. BS_ASSERT(dwSizeInBytes != 0);
  524. std::auto_ptr<BYTE> pBuffer(new BYTE[dwSizeInBytes]);
  525. if (pBuffer.get() == NULL)
  526. ft.Throw(VSSDBG_GEN, E_OUTOFMEMORY, L"Memory allocation error");
  527. // Get the binary value contents
  528. DWORD dwType2 = 0;
  529. DWORD dwSizeInBytes2 = dwSizeInBytes;
  530. lResult = ::RegQueryValueExW(
  531. m_hRegKey,
  532. pwszValueName,
  533. NULL,
  534. &dwType2,
  535. pBuffer.get(),
  536. &dwSizeInBytes2);
  537. if (lResult != ERROR_SUCCESS)
  538. ft.TranslateGenericError(VSSDBG_GEN, HRESULT_FROM_WIN32(lResult),
  539. L"RegQueryValueExW(0x%08lx(%s),%s,0,[%lx],0,[%lu])",
  540. m_hRegKey, m_awszKeyPath.GetRef(), pwszValueName, dwType2, dwSizeInBytes2);
  541. BS_ASSERT(dwType2 == REG_BINARY);
  542. BS_ASSERT(dwSizeInBytes2 == dwSizeInBytes);
  543. // Set the OUT parameters
  544. pbData = pBuffer.release();
  545. dwSize = dwSizeInBytes;
  546. return ft.Exit(true);
  547. }
  548. // Closes the registry key
  549. void CVssRegistryKey::Close()
  550. {
  551. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKey::Close" );
  552. if (m_hRegKey) {
  553. // Close the opened key
  554. LONG lRes = ::RegCloseKey( m_hRegKey );
  555. if (lRes != ERROR_SUCCESS) {
  556. BS_ASSERT(false);
  557. ft.Trace( VSSDBG_GEN, L"%s: Error on closing key with name %s. lRes == 0x%08lx", (VSS_PWSZ)m_awszKeyPath, lRes );
  558. }
  559. m_hRegKey = NULL;
  560. }
  561. m_awszKeyPath.Clear();
  562. }
  563. // Standard constructor
  564. CVssRegistryKey::CVssRegistryKey(
  565. IN REGSAM samDesired, /* = KEY_ALL_ACCESS */
  566. IN DWORD dwKeyCreateOptions /* = REG_OPTION_NON_VOLATILE */
  567. )
  568. {
  569. m_hRegKey = NULL;
  570. m_dwKeyCreateOptions = dwKeyCreateOptions;
  571. m_samDesired = samDesired;
  572. }
  573. // Standard destructor
  574. CVssRegistryKey::~CVssRegistryKey()
  575. {
  576. Close();
  577. }
  578. /////////////////////////////////////////////////////////////////////////////
  579. // CVssRegistryKeyIterator implementation
  580. // Standard constructor
  581. CVssRegistryKeyIterator::CVssRegistryKeyIterator()
  582. {
  583. // Initialize data members
  584. Detach();
  585. }
  586. // Returns the name of the current key.
  587. // The returned key is always non-NULL (or the function will throw E_UNEXPECTED).
  588. VSS_PWSZ CVssRegistryKeyIterator::GetCurrentKeyName() throw(HRESULT)
  589. {
  590. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKeyIterator::GetCurrentKeyName" );
  591. if (!m_bAttached || !m_awszSubKeyName.GetRef()) {
  592. BS_ASSERT(false);
  593. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: noninitialized iterator");
  594. }
  595. // Fill wszSubKeyName with the name of the subkey
  596. FILETIME time;
  597. DWORD dwSize = m_dwMaxSubKeyLen;
  598. LONG lRes = ::RegEnumKeyExW(
  599. m_hParentKey, // IN HKEY hKey,
  600. m_dwCurrentKeyIndex, // IN DWORD dwIndex,
  601. m_awszSubKeyName, // OUT LPWSTR lpName,
  602. &dwSize, // IN OUT LPDWORD lpcbName,
  603. NULL, // IN LPDWORD lpReserved,
  604. NULL, // IN OUT LPWSTR lpClass,
  605. NULL, // IN OUT LPDWORD lpcbClass,
  606. &time); // OUT PFILETIME lpftLastWriteTime
  607. switch(lRes)
  608. {
  609. case ERROR_SUCCESS:
  610. BS_ASSERT(dwSize != 0);
  611. break; // Go to Next key
  612. default:
  613. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumKeyExW(%p,%lu,%p,%lu ...)",
  614. m_hParentKey, m_dwCurrentKeyIndex, m_awszSubKeyName.GetRef(), dwSize);
  615. case ERROR_NO_MORE_ITEMS:
  616. BS_ASSERT(false);
  617. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentKeyIndex, m_dwKeyCount);
  618. }
  619. return m_awszSubKeyName.GetRef();
  620. }
  621. // Standard constructor
  622. void CVssRegistryKeyIterator::Attach(
  623. IN CVssRegistryKey & key
  624. ) throw(HRESULT)
  625. {
  626. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryKeyIterator::Attach" );
  627. // Reset all members
  628. Detach();
  629. m_hParentKey = key.GetHandle();
  630. BS_ASSERT(m_hParentKey);
  631. // Get the number of subkeys and the max subkey length
  632. DWORD dwKeyCount = 0;
  633. DWORD dwMaxSubKeyLen = 0;
  634. LONG lRes = ::RegQueryInfoKeyW(
  635. m_hParentKey, // handle to key
  636. NULL, // class buffer
  637. NULL, // size of class buffer
  638. NULL, // reserved
  639. &dwKeyCount, // number of subkeys
  640. &dwMaxSubKeyLen, // longest subkey name
  641. NULL, // longest class string
  642. NULL, // number of value entries
  643. NULL, // longest value name
  644. NULL, // longest value data
  645. NULL, // descriptor length
  646. NULL); // last write time
  647. if (lRes != ERROR_SUCCESS)
  648. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegQueryInfoKeyW(%p, ...)", m_hParentKey);
  649. // Allocate the key name with a sufficient length.
  650. // We assume that the key length cannot change during the ennumeration).
  651. if (dwMaxSubKeyLen)
  652. m_awszSubKeyName.Allocate(dwMaxSubKeyLen);
  653. // Setting the number of subkeys
  654. m_dwKeyCount = dwKeyCount;
  655. m_dwMaxSubKeyLen = dwMaxSubKeyLen + 1;
  656. // Attachment completed
  657. m_bAttached = true;
  658. }
  659. void CVssRegistryKeyIterator::Detach()
  660. {
  661. // Initialize data members
  662. m_hParentKey = NULL;
  663. m_dwKeyCount = 0;
  664. m_dwCurrentKeyIndex = 0;
  665. m_dwMaxSubKeyLen = 0;
  666. m_awszSubKeyName.Clear();
  667. m_bAttached = false;
  668. }
  669. // Tells if the current key is still valid
  670. bool CVssRegistryKeyIterator::IsEOF()
  671. {
  672. return (m_dwCurrentKeyIndex >= m_dwKeyCount);
  673. }
  674. // Return the number of subkeys at the moment of attaching
  675. DWORD CVssRegistryKeyIterator::GetSubkeysCount()
  676. {
  677. return (m_dwKeyCount);
  678. }
  679. // Set the next key as being the current one in the enumeration
  680. void CVssRegistryKeyIterator::MoveNext()
  681. {
  682. if (!IsEOF())
  683. m_dwCurrentKeyIndex++;
  684. else
  685. BS_ASSERT(false);
  686. }
  687. /////////////////////////////////////////////////////////////////////////////
  688. // CVssRegistryValueIterator implementation
  689. // Standard constructor
  690. CVssRegistryValueIterator::CVssRegistryValueIterator()
  691. {
  692. // Initialize data members
  693. Detach();
  694. }
  695. // Returns the name of the current value.
  696. // The returned value is always non-NULL (or the function will throw E_UNEXPECTED).
  697. VSS_PWSZ CVssRegistryValueIterator::GetCurrentValueName() throw(HRESULT)
  698. {
  699. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueName" );
  700. ReadCurrentValueDetails();
  701. BS_ASSERT(m_bSeekDone);
  702. return m_awszValueName.GetRef();
  703. }
  704. // Returns the type of the current value.
  705. DWORD CVssRegistryValueIterator::GetCurrentValueType() throw(HRESULT)
  706. {
  707. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueType" );
  708. ReadCurrentValueDetails();
  709. BS_ASSERT(m_bSeekDone);
  710. return m_dwCurrentValueType;
  711. }
  712. // Reads a VSS_PWSZ value from the registry key
  713. void CVssRegistryValueIterator::GetCurrentValueContent(
  714. OUT VSS_PWSZ & pwszValue
  715. ) throw(HRESULT)
  716. {
  717. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
  718. ReadCurrentValueDetails();
  719. BS_ASSERT(m_bSeekDone);
  720. if (m_dwCurrentValueType != REG_SZ) {
  721. BS_ASSERT(false);
  722. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: attempting to read a value of the wrong type");
  723. }
  724. // Allocate the output buffer
  725. DWORD cchStringSize = m_cbValueDataSize / sizeof(WCHAR);
  726. CVssAutoPWSZ awszBuffer;
  727. awszBuffer.Allocate(cchStringSize + 1);
  728. // Fill awszBuffer with the string contents
  729. DWORD cchNameSize = m_cchMaxValueNameLen;
  730. DWORD dwCurrentValueType = 0;
  731. DWORD cbValueSize = m_cbValueDataSize;
  732. LONG lRes = ::RegEnumValue(
  733. m_hKey, // IN HKEY hKey,
  734. m_dwCurrentValueIndex, // IN DWORD dwIndex,
  735. m_awszValueName, // OUT LPWSTR lpName,
  736. &cchNameSize, // IN OUT LPDWORD lpcbName,
  737. NULL, // IN LPDWORD lpReserved,
  738. &dwCurrentValueType, // IN OUT LPDWORD lpType,
  739. (LPBYTE)awszBuffer.GetRef(),// IN OUT LPBYTE lpData,
  740. &cbValueSize); // IN OUT LPDWORD lpcbData
  741. switch(lRes)
  742. {
  743. case ERROR_SUCCESS:
  744. BS_ASSERT(cchNameSize != 0);
  745. BS_ASSERT(cbValueSize != 0);
  746. if (dwCurrentValueType != m_dwCurrentValueType)
  747. ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
  748. L"Unexpected error: current value type changed in the meantime %lu %lu",
  749. dwCurrentValueType, m_dwCurrentValueType);
  750. break;
  751. case ERROR_NO_MORE_ITEMS:
  752. BS_ASSERT(false);
  753. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
  754. default:
  755. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
  756. m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
  757. }
  758. awszBuffer.GetRef()[cchStringSize] = L'\0';
  759. pwszValue = awszBuffer.Detach();
  760. }
  761. // Reads a DWORD value from the registry key
  762. void CVssRegistryValueIterator::GetCurrentValueContent(
  763. OUT DWORD & dwValue
  764. ) throw(HRESULT)
  765. {
  766. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
  767. ReadCurrentValueDetails();
  768. BS_ASSERT(m_bSeekDone);
  769. if (m_dwCurrentValueType != REG_DWORD)
  770. ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
  771. L"Unexpected error: attempting to read a value of the wrong type");
  772. // Allocate the output buffer
  773. if (m_cbValueDataSize != sizeof(DWORD))
  774. ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
  775. L"Unexpected error: unexpected DWORD size [%ld, %ld]", m_cbValueDataSize, sizeof(DWORD));
  776. // Fill dwInternalValue with the DWORD value
  777. DWORD dwInternalValue = 0;
  778. DWORD cchNameSize = m_cchMaxValueNameLen;
  779. DWORD dwCurrentValueType = 0;
  780. DWORD cbValueSize = m_cbValueDataSize;
  781. LONG lRes = ::RegEnumValue(
  782. m_hKey, // IN HKEY hKey,
  783. m_dwCurrentValueIndex, // IN DWORD dwIndex,
  784. m_awszValueName, // OUT LPWSTR lpName,
  785. &cchNameSize, // IN OUT LPDWORD lpcbName,
  786. NULL, // IN LPDWORD lpReserved,
  787. &dwCurrentValueType, // IN OUT LPDWORD lpType,
  788. (LPBYTE)&dwInternalValue, // IN OUT LPBYTE lpData,
  789. &cbValueSize); // IN OUT LPDWORD lpcbData
  790. switch(lRes)
  791. {
  792. case ERROR_SUCCESS:
  793. BS_ASSERT(cchNameSize != 0);
  794. BS_ASSERT(cbValueSize != 0);
  795. if (dwCurrentValueType != m_dwCurrentValueType)
  796. ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
  797. L"Unexpected error: current value type changed in the meantime %lu %lu",
  798. dwCurrentValueType, m_dwCurrentValueType);
  799. break;
  800. case ERROR_NO_MORE_ITEMS:
  801. BS_ASSERT(false);
  802. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
  803. default:
  804. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
  805. m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
  806. }
  807. dwValue = dwInternalValue;
  808. }
  809. // Reads a REG_BINARY value from the registry key
  810. void CVssRegistryValueIterator::GetCurrentValueContent(
  811. OUT PBYTE & pbValue, // Must be deleted with "delete[]"
  812. OUT DWORD & cbSize
  813. ) throw(HRESULT)
  814. {
  815. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::GetCurrentValueContent" );
  816. ReadCurrentValueDetails();
  817. BS_ASSERT(m_bSeekDone);
  818. if (m_dwCurrentValueType != REG_BINARY) {
  819. BS_ASSERT(false);
  820. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: attempting to read a value of the wrong type");
  821. }
  822. // Allocate the output buffer
  823. DWORD cbValueSize = m_cbValueDataSize;
  824. CVssAutoCppPtr<PBYTE> awszBuffer;
  825. awszBuffer.AllocateBytes(cbValueSize);
  826. // Fill awszBuffer with the string contents
  827. DWORD cchNameSize = m_cchMaxValueNameLen;
  828. DWORD dwCurrentValueType = 0;
  829. LONG lRes = ::RegEnumValue(
  830. m_hKey, // IN HKEY hKey,
  831. m_dwCurrentValueIndex, // IN DWORD dwIndex,
  832. m_awszValueName, // OUT LPWSTR lpName,
  833. &cchNameSize, // IN OUT LPDWORD lpcbName,
  834. NULL, // IN LPDWORD lpReserved,
  835. &dwCurrentValueType, // IN OUT LPDWORD lpType,
  836. (LPBYTE)awszBuffer.Get(), // IN OUT LPBYTE lpData,
  837. &cbValueSize); // IN OUT LPDWORD lpcbData
  838. switch(lRes)
  839. {
  840. case ERROR_SUCCESS:
  841. BS_ASSERT(cchNameSize != 0);
  842. BS_ASSERT(cbValueSize != 0);
  843. if (dwCurrentValueType != m_dwCurrentValueType)
  844. ft.Throw(VSSDBG_GEN, E_UNEXPECTED,
  845. L"Unexpected error: current value type changed in the meantime %lu %lu",
  846. dwCurrentValueType, m_dwCurrentValueType);
  847. break;
  848. case ERROR_NO_MORE_ITEMS:
  849. BS_ASSERT(false);
  850. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
  851. default:
  852. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
  853. m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
  854. }
  855. pbValue = awszBuffer.Detach();
  856. cbSize = cbValueSize;
  857. }
  858. // Returns the name and the type of the current value.
  859. void CVssRegistryValueIterator::ReadCurrentValueDetails() throw(HRESULT)
  860. {
  861. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::ReadCurrentValueDetails" );
  862. if (!m_bAttached || !m_awszValueName.GetRef()) {
  863. BS_ASSERT(false);
  864. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: noninitialized iterator");
  865. }
  866. // Do not load twice the same value
  867. if (m_bSeekDone)
  868. return;
  869. // Fill wszSubKeyName with the name of the subkey
  870. DWORD cchNameSize = m_cchMaxValueNameLen;
  871. LONG lRes = ::RegEnumValue(
  872. m_hKey, // IN HKEY hKey,
  873. m_dwCurrentValueIndex, // IN DWORD dwIndex,
  874. m_awszValueName, // OUT LPWSTR lpName,
  875. &cchNameSize, // IN OUT LPDWORD lpcbName,
  876. NULL, // IN LPDWORD lpReserved,
  877. &m_dwCurrentValueType, // IN OUT LPDWORD lpType,
  878. NULL, // IN OUT LPBYTE lpData,
  879. &m_cbValueDataSize); // IN OUT LPDWORD lpcbData
  880. switch(lRes)
  881. {
  882. case ERROR_SUCCESS:
  883. BS_ASSERT(cchNameSize != 0);
  884. BS_ASSERT(m_cbValueDataSize != 0);
  885. break; // Go to Next key
  886. default:
  887. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegEnumValue(%p,%lu,%p,%lu ...)",
  888. m_hKey, m_dwCurrentValueIndex, m_awszValueName.GetRef(), cchNameSize);
  889. case ERROR_NO_MORE_ITEMS:
  890. BS_ASSERT(false);
  891. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L"Unexpected error: dwIndex out of scope %lu %lu", m_dwCurrentValueIndex, m_dwValuesCount);
  892. }
  893. m_bSeekDone = true;
  894. }
  895. // Attaches the iterator to a registry key
  896. void CVssRegistryValueIterator::Attach(
  897. IN CVssRegistryKey & key
  898. ) throw(HRESULT)
  899. {
  900. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssRegistryValueIterator::Attach" );
  901. // Reset all members
  902. Detach();
  903. m_hKey = key.GetHandle();
  904. BS_ASSERT(m_hKey);
  905. // Get the number of values and the max value name length
  906. DWORD dwValuesCount = 0;
  907. DWORD dwMaxValueNameLen = 0;
  908. LONG lRes = ::RegQueryInfoKeyW(
  909. m_hKey, // handle to key
  910. NULL, // class buffer
  911. NULL, // size of class buffer
  912. NULL, // reserved
  913. NULL, // number of subkeys
  914. NULL, // longest subkey name
  915. NULL, // longest class string
  916. &dwValuesCount, // number of value entries
  917. &dwMaxValueNameLen, // longest value name
  918. NULL, // longest value data
  919. NULL, // descriptor length
  920. NULL); // last write time
  921. if (lRes != ERROR_SUCCESS)
  922. ft.TranslateGenericError( VSSDBG_GEN, HRESULT_FROM_WIN32(lRes), L"RegQueryInfoKeyW(%p, ...)", m_hKey);
  923. // Allocate the key name with a sufficient length.
  924. // We assume that the key length cannot change during the ennumeration).
  925. if (dwMaxValueNameLen)
  926. m_awszValueName.Allocate(dwMaxValueNameLen);
  927. // Setting the number of subkeys
  928. m_dwValuesCount = dwValuesCount;
  929. m_cchMaxValueNameLen = dwMaxValueNameLen + 1;
  930. // Attachment completed
  931. m_bAttached = true;
  932. }
  933. void CVssRegistryValueIterator::Detach()
  934. {
  935. // Initialize data members
  936. m_hKey = NULL;
  937. m_dwValuesCount = 0;
  938. m_dwCurrentValueIndex = 0;
  939. m_cchMaxValueNameLen = 0;
  940. m_awszValueName.Clear();
  941. m_dwCurrentValueType = 0;
  942. m_cbValueDataSize = 0;
  943. m_bSeekDone = false;
  944. m_bAttached = false;
  945. }
  946. // Tells if the current key is still valid
  947. bool CVssRegistryValueIterator::IsEOF()
  948. {
  949. return (m_dwCurrentValueIndex >= m_dwValuesCount);
  950. }
  951. // Return the number of subkeys at the moment of attaching
  952. DWORD CVssRegistryValueIterator::GetValuesCount()
  953. {
  954. return (m_dwValuesCount);
  955. }
  956. // Set the next key as being the current one in the enumeration
  957. void CVssRegistryValueIterator::MoveNext()
  958. {
  959. if (!IsEOF())
  960. {
  961. m_bSeekDone = false;
  962. m_dwCurrentValueType = 0;
  963. m_cbValueDataSize = 0;
  964. m_dwCurrentValueIndex++;
  965. }
  966. else
  967. BS_ASSERT(false);
  968. }
  969. /////////////////////////////////////////////////////////////////////////////
  970. // CVssDiag implementation
  971. void CVssDiag::Initialize(
  972. IN LPCWSTR pwszStaticContext
  973. )
  974. {
  975. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::Initialize" );
  976. try
  977. {
  978. ft.Trace( VSSDBG_GEN, L"Parameters %s", pwszStaticContext);
  979. if ((pwszStaticContext == NULL) || (pwszStaticContext[0] == L'\0')) {
  980. BS_ASSERT(false); // Programming error
  981. ft.Throw(VSSDBG_GEN, E_UNEXPECTED, L" NULL or empty parameter");
  982. }
  983. // If not initialized, return
  984. if (m_bInitialized)
  985. return;
  986. // If not enabled, return
  987. if(!m_key.Open(HKEY_LOCAL_MACHINE, x_wszVssDiagPath)) {
  988. ft.Trace(VSSDBG_GEN, L"Diagnose not enabled (%s)", pwszStaticContext);
  989. return;
  990. }
  991. // Try to read the "Enabled" flag. If not present, return.
  992. CVssAutoPWSZ awszValue;
  993. if (m_key.GetValue(L"", awszValue.GetRef(), false))
  994. {
  995. if (!awszValue.GetRef()) {
  996. BS_ASSERT(false);
  997. return;
  998. }
  999. if (wcscmp(awszValue, x_wszVssDiagEnabledValue) != 0)
  1000. return;
  1001. // Open the key, if exists. If not, create it.
  1002. if (!m_key.Open(HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVssDiagPath, pwszStaticContext))
  1003. m_key.Create(HKEY_LOCAL_MACHINE, L"%s\\%s", x_wszVssDiagPath, pwszStaticContext);
  1004. ft.Trace(VSSDBG_GEN, L"Diagnose enabled for (%s)", pwszStaticContext);
  1005. // Zero out the queued diag data
  1006. ::VssZeroOut(m_QueuedDiagData);
  1007. // Mark the object as "initialized"
  1008. m_bInitialized = true;
  1009. }
  1010. }
  1011. VSS_STANDARD_CATCH(ft)
  1012. }
  1013. void CVssDiag::RecordWriterEvent(
  1014. IN VSS_OPERATION eOperation,
  1015. IN DWORD dwEventContext,
  1016. IN DWORD dwCurrentState,
  1017. IN HRESULT hrLastError,
  1018. IN GUID guidSnapshotSetID /* = GUID_NULL */
  1019. )
  1020. {
  1021. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::RecordWriterEvent" );
  1022. RecordGenericEvent(
  1023. eOperation,
  1024. dwEventContext,
  1025. dwCurrentState,
  1026. hrLastError,
  1027. guidSnapshotSetID
  1028. );
  1029. }
  1030. void CVssDiag::RecordGenericEvent(
  1031. IN DWORD dwEventID,
  1032. IN DWORD dwEventContext,
  1033. IN DWORD dwCurrentState,
  1034. IN HRESULT hrLastError,
  1035. IN GUID guidSnapshotSetID /* = GUID_NULL */
  1036. )
  1037. {
  1038. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::RecordGenericEvent" );
  1039. try
  1040. {
  1041. ft.Trace( VSSDBG_GEN, L"Parameters %ld, %ld, %ld, 0x%08lx, " WSTR_GUID_FMT,
  1042. dwEventID, dwEventContext, dwCurrentState, hrLastError,
  1043. GUID_PRINTF_ARG(guidSnapshotSetID));
  1044. // If not initialized, return
  1045. if (!m_bInitialized)
  1046. return;
  1047. if (dwEventContext & CVssDiag::VSS_DIAG_IGNORE_LEAVE)
  1048. return;
  1049. // Get new event parameters
  1050. bool bInOperation = !!(dwEventContext & VSS_DIAG_ENTER_OPERATION);
  1051. LPCWSTR pwszEventName = GetStringFromOperation(bInOperation, dwEventID);
  1052. // Some events do not require logging
  1053. if (NULL == pwszEventName)
  1054. return;
  1055. ft.Trace(VSSDBG_GEN, L"Event name: %s", pwszEventName);
  1056. // Fill out event data
  1057. CVssDiagData data;
  1058. data.m_dwSize = sizeof(data); // For future compatibility
  1059. data.m_dwReserved = 0;
  1060. CVsFileTime filetime;
  1061. data.m_llTimestamp = filetime;
  1062. data.m_dwProcessID = GetCurrentProcessId();
  1063. data.m_dwThreadID = GetCurrentThreadId();
  1064. data.m_dwEventID = dwEventID;
  1065. data.m_dwEventContext = dwEventContext;
  1066. data.m_dwCurrentState = dwCurrentState;
  1067. data.m_hrLastErrorCode = hrLastError;
  1068. data.m_guidSnapshotSetID = guidSnapshotSetID;
  1069. data.m_pReserved1 = NULL;
  1070. data.m_pReserved2 = NULL;
  1071. // If we are in queued mode, then add the element to the queue
  1072. if (IsQueuedMode(dwEventID, dwEventContext))
  1073. {
  1074. if (m_dwQueuedElements < x_nMaxQueuedDiagData)
  1075. {
  1076. m_QueuedDiagData[m_dwQueuedElements].m_pwszEventName = pwszEventName;
  1077. m_QueuedDiagData[m_dwQueuedElements].m_diag = data;
  1078. m_dwQueuedElements++;
  1079. }
  1080. }
  1081. else
  1082. {
  1083. // Flush the queue
  1084. FlushQueue();
  1085. // Write the current data as a binary block
  1086. m_key.SetBinaryValue(pwszEventName, (BYTE *) &data, sizeof(data));
  1087. }
  1088. }
  1089. VSS_STANDARD_CATCH(ft)
  1090. }
  1091. // Flush the queued elements in registry
  1092. void CVssDiag::FlushQueue()
  1093. {
  1094. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssDiag::FlushQueue" );
  1095. try
  1096. {
  1097. DWORD dwQueuedElements = m_dwQueuedElements;
  1098. m_dwQueuedElements = 0;
  1099. for ( DWORD dwIndex = 0; dwIndex < dwQueuedElements; dwIndex++)
  1100. {
  1101. // Write the data as a binary block
  1102. LPCWSTR pwszEventName = m_QueuedDiagData[dwIndex].m_pwszEventName;
  1103. CVssDiagData* pDiagData = &(m_QueuedDiagData[dwIndex].m_diag);
  1104. m_key.SetBinaryValue(pwszEventName, (BYTE *) pDiagData, sizeof(CVssDiagData));
  1105. }
  1106. }
  1107. VSS_STANDARD_CATCH(ft)
  1108. }
  1109. // Size of the L"VSS_IN_" string, without the zero character
  1110. const x_VssPrefixSize = SIZEOF_ARRAY(L"VSS_IN_") - 1;
  1111. // Define for simplifying hte case statement below
  1112. #define VSS_OPERATION_CASE_STMT(operation) \
  1113. case operation: \
  1114. if (bInOperation) \
  1115. return x_VssPrefixSize + VSS_WSTRINGIZE(operation) L" (Enter)" ; \
  1116. else \
  1117. return x_VssPrefixSize + VSS_WSTRINGIZE(operation) L" (Leave)" ;
  1118. // Define for simplifying hte case statement below
  1119. #define VSS_WRITERSTATE_CASE_STMT(state) \
  1120. case state: \
  1121. if (bInOperation) \
  1122. return VSS_WSTRINGIZE(state) L" (SetCurrentState)" ; \
  1123. else \
  1124. return NULL;
  1125. // Define for simplifying hte case statement below
  1126. #define VSS_HRESULT_CASE_STMT(hresult) \
  1127. case hresult: \
  1128. if (bInOperation) \
  1129. return VSS_WSTRINGIZE(hresult) L" (SetCurrentFailure)" ; \
  1130. else \
  1131. return NULL;
  1132. // Convert a writer status into a string
  1133. LPCWSTR CVssDiag::GetStringFromOperation(
  1134. IN bool bInOperation,
  1135. IN DWORD dwOperation
  1136. )
  1137. {
  1138. switch (dwOperation)
  1139. {
  1140. // Writer operations
  1141. VSS_OPERATION_CASE_STMT(VSS_IN_IDENTIFY)
  1142. VSS_OPERATION_CASE_STMT(VSS_IN_PREPAREBACKUP)
  1143. VSS_OPERATION_CASE_STMT(VSS_IN_PREPARESNAPSHOT)
  1144. VSS_OPERATION_CASE_STMT(VSS_IN_FREEZE)
  1145. VSS_OPERATION_CASE_STMT(VSS_IN_THAW)
  1146. VSS_OPERATION_CASE_STMT(VSS_IN_POSTSNAPSHOT)
  1147. VSS_OPERATION_CASE_STMT(VSS_IN_BACKUPCOMPLETE)
  1148. VSS_OPERATION_CASE_STMT(VSS_IN_PRERESTORE)
  1149. VSS_OPERATION_CASE_STMT(VSS_IN_POSTRESTORE)
  1150. VSS_OPERATION_CASE_STMT(VSS_IN_GETSTATE)
  1151. VSS_OPERATION_CASE_STMT(VSS_IN_ABORT)
  1152. VSS_OPERATION_CASE_STMT(VSS_IN_BACKUPSHUTDOWN)
  1153. VSS_OPERATION_CASE_STMT(VSS_IN_BKGND_FREEZE_THREAD)
  1154. // Other Event IDs
  1155. VSS_OPERATION_CASE_STMT(VSS_IN_OPEN_VOLUME_HANDLE)
  1156. VSS_OPERATION_CASE_STMT(VSS_IN_IOCTL_FLUSH_AND_HOLD)
  1157. VSS_OPERATION_CASE_STMT(VSS_IN_IOCTL_RELEASE)
  1158. // Writer State changes.
  1159. // These values are coming from SetCurrentState
  1160. VSS_WRITERSTATE_CASE_STMT(VSS_WS_UNKNOWN)
  1161. VSS_WRITERSTATE_CASE_STMT(VSS_WS_STABLE)
  1162. VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_FREEZE)
  1163. VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_THAW)
  1164. VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_POST_SNAPSHOT)
  1165. VSS_WRITERSTATE_CASE_STMT(VSS_WS_WAITING_FOR_BACKUP_COMPLETE)
  1166. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_IDENTIFY)
  1167. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PREPARE_BACKUP)
  1168. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PREPARE_SNAPSHOT)
  1169. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_FREEZE)
  1170. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_THAW)
  1171. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_POST_SNAPSHOT)
  1172. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_BACKUP_COMPLETE)
  1173. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_PRE_RESTORE)
  1174. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_POST_RESTORE)
  1175. VSS_WRITERSTATE_CASE_STMT(VSS_WS_FAILED_AT_BACKUPSHUTDOWN)
  1176. // Writer error codes
  1177. // These values are coming from SetCurrentFailure
  1178. VSS_HRESULT_CASE_STMT(VSS_S_OK)
  1179. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_INCONSISTENTSNAPSHOT)
  1180. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_OUTOFRESOURCES)
  1181. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_TIMEOUT)
  1182. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_RETRYABLE)
  1183. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_NONRETRYABLE)
  1184. VSS_HRESULT_CASE_STMT(VSS_E_WRITERERROR_RECOVERY_FAILED)
  1185. VSS_HRESULT_CASE_STMT(VSS_E_WRITER_NOT_RESPONDING)
  1186. default:
  1187. {
  1188. static WCHAR wszBuffer[80];
  1189. ::StringCchPrintfW(STRING_CCH_PARAM(wszBuffer),
  1190. L"UNKNOWN_EVENT[0x%08lx] %s",
  1191. dwOperation, bInOperation? L"(Enter)": L"(Leave)");
  1192. return wszBuffer;
  1193. }
  1194. }
  1195. }
  1196. // Returns true if the diagnose must operate in queued mode
  1197. // (i.e. without writing to registry)
  1198. bool CVssDiag::IsQueuedMode(
  1199. IN DWORD dwEventID,
  1200. IN DWORD dwEventContext
  1201. )
  1202. {
  1203. switch (dwEventID)
  1204. {
  1205. case VSS_IN_IOCTL_FLUSH_AND_HOLD:
  1206. // Always in Queued mode (since we don't know the order for parallel F&H ioctls)
  1207. return true;
  1208. case VSS_IN_IOCTL_RELEASE:
  1209. // If we are in ENTER then we are still in queued mode
  1210. return !!(dwEventContext & VSS_DIAG_ENTER_OPERATION);
  1211. default:
  1212. return false;
  1213. }
  1214. }
  1215. bool CVssMachineInformation::IsDuringSetup()
  1216. {
  1217. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssMachineInformation::IsDuringSetup" );
  1218. CRegKey cRegKeySetup;
  1219. DWORD dwRes = cRegKeySetup.Open(HKEY_LOCAL_MACHINE, x_SetupKey, KEY_READ);
  1220. if (dwRes == ERROR_SUCCESS)
  1221. {
  1222. DWORD dwValue;
  1223. dwRes = cRegKeySetup.QueryValue(dwValue, x_SystemSetupInProgress);
  1224. if (dwRes == ERROR_SUCCESS && dwValue > 0)
  1225. return true;
  1226. dwRes = cRegKeySetup.QueryValue(dwValue, x_UpgradeInProgress);
  1227. if (dwRes == ERROR_SUCCESS && dwValue > 0)
  1228. return true;
  1229. }
  1230. return false;
  1231. }
  1232. bool CVssMachineInformation::IsDuringSafeMode()
  1233. {
  1234. CVssFunctionTracer ft( VSSDBG_GEN, L"CVssMachineInformation::IsDuringSafeMode" );
  1235. CRegKey cRegKeySetup;
  1236. DWORD dwRes = cRegKeySetup.Open(HKEY_LOCAL_MACHINE, x_SafebootKey, KEY_READ);
  1237. if (dwRes == ERROR_SUCCESS)
  1238. {
  1239. DWORD dwValue;
  1240. dwRes = cRegKeySetup.QueryValue(dwValue, x_SafebootOptionValue);
  1241. if (dwRes == ERROR_SUCCESS)
  1242. {
  1243. ft.Trace(VSSDBG_GEN, L"SafeBoot option 0x%08lx", dwValue);
  1244. switch(dwValue)
  1245. {
  1246. case SAFEBOOT_MINIMAL:
  1247. case SAFEBOOT_NETWORK:
  1248. return true;
  1249. case SAFEBOOT_DSREPAIR:
  1250. // Writers are allowed in DS Repair
  1251. // (That's the only way for the AD Writer to do its job on restore).
  1252. return false;
  1253. default:
  1254. ft.Trace(VSSDBG_GEN, L"Unrecognized safe mode option %ud", dwValue);
  1255. return true;
  1256. }
  1257. }
  1258. }
  1259. return false;
  1260. }