Source code of Windows XP (NT5)
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.

702 lines
16 KiB

  1. #include "stdinc.h"
  2. #include "util.h"
  3. #include "fusionhandle.h"
  4. BOOL
  5. FusionpRegQueryBinaryValueEx(
  6. DWORD dwFlags,
  7. HKEY hKey,
  8. PCWSTR lpValueName,
  9. CFusionArray<BYTE> &rbBuffer,
  10. DWORD &rdwLastError,
  11. SIZE_T cExceptionalLastErrors,
  12. ...
  13. )
  14. {
  15. FN_PROLOG_WIN32
  16. LONG lResult;
  17. DWORD dwType = 0;
  18. rdwLastError = ERROR_SUCCESS;
  19. PARAMETER_CHECK((dwFlags & ~FUSIONP_REG_QUERY_BINARY_NO_FAIL_IF_NON_BINARY) == 0);
  20. PARAMETER_CHECK(hKey != NULL);
  21. PARAMETER_CHECK(lpValueName != NULL);
  22. for (;;)
  23. {
  24. DWORD dwDataSize = rbBuffer.GetSizeAsDWORD();
  25. LPBYTE pvData = rbBuffer.GetArrayPtr();
  26. lResult = ::RegQueryValueExW(
  27. hKey,
  28. lpValueName,
  29. NULL,
  30. &dwType,
  31. pvData,
  32. &dwDataSize);
  33. // If we are to fail because the type is wrong (ie: don't magically convert
  34. // from a reg-sz to a binary blob), then fail.
  35. //
  36. // HACKHACK: This is to get around a spectacular bug in RegQueryValueEx,
  37. // which is even documented as 'correct' in MSDN.
  38. //
  39. // RegQueryValueEx returns ERROR_SUCCESS when the data target pointer
  40. // was NULL but the size value was "too small." So, we'll just claim
  41. // ERROR_MORE_DATA instead, and go around again, letting the buffer
  42. // get resized.
  43. //
  44. if ( ( pvData == NULL ) && ( lResult == ERROR_SUCCESS ) )
  45. {
  46. //
  47. // Yes, but if there's no data we need to stop and quit looking -
  48. // zero-length binary strings are a gotcha here.
  49. //
  50. if ( dwDataSize == 0 )
  51. break;
  52. lResult = ERROR_MORE_DATA;
  53. }
  54. if (lResult == ERROR_SUCCESS)
  55. {
  56. if ((dwFlags & FUSIONP_REG_QUERY_BINARY_NO_FAIL_IF_NON_BINARY) == 0)
  57. PARAMETER_CHECK(dwType == REG_BINARY);
  58. break;
  59. }
  60. else if (lResult == ERROR_MORE_DATA)
  61. {
  62. IFW32FALSE_EXIT(
  63. rbBuffer.Win32SetSize(
  64. dwDataSize,
  65. CFusionArray<BYTE>::eSetSizeModeExact));
  66. }
  67. else
  68. {
  69. break; // must break from for loop
  70. }
  71. }
  72. if ( ( lResult != ERROR_SUCCESS ) && ( lResult != ERROR_MORE_DATA ) )
  73. {
  74. SIZE_T i;
  75. va_list ap;
  76. va_start(ap, cExceptionalLastErrors);
  77. ::SetLastError(lResult);
  78. rdwLastError = lResult;
  79. for (i=0; i<cExceptionalLastErrors; i++)
  80. {
  81. if (lResult == va_arg(ap, LONG))
  82. break;
  83. }
  84. va_end(ap);
  85. if (i == cExceptionalLastErrors)
  86. {
  87. ::FusionpDbgPrintEx(
  88. FUSION_DBG_LEVEL_ERROR,
  89. "SXS.DLL: %s(%ls)\n",
  90. __FUNCTION__,
  91. lpValueName
  92. );
  93. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegQueryValueExW, lResult);
  94. }
  95. }
  96. FN_EPILOG
  97. }
  98. /*
  99. BOOL
  100. FusionpRegQueryBinaryValueEx(
  101. DWORD dwFlags,
  102. HKEY hKey,
  103. PCWSTR lpValueName,
  104. CFusionArray<BYTE> &rbBuffer,
  105. DWORD &rdwLastError,
  106. SIZE_T cExceptionalLastErrors,
  107. ...
  108. )
  109. {
  110. va_list ap;
  111. va_start(ap, cExceptionalLastErrors);
  112. BOOL fSuccess = ::FusionpRegQueryBinaryValueEx(dwFlags, hKey, lpValueName, rbBuffer, rdwLastError, cExceptionalLastErrors, ap);
  113. va_end(ap);
  114. return fSuccess;
  115. }
  116. */
  117. BOOL
  118. FusionpRegQueryBinaryValueEx(
  119. DWORD dwFlags,
  120. HKEY hKey,
  121. PCWSTR lpValueName,
  122. CFusionArray<BYTE> &rbBuffer
  123. )
  124. {
  125. DWORD dwLastError;
  126. return ::FusionpRegQueryBinaryValueEx(dwFlags, hKey, lpValueName, rbBuffer, dwLastError, 0);
  127. }
  128. BOOL
  129. FusionpRegQuerySzValueEx(
  130. DWORD dwFlags,
  131. HKEY hKey,
  132. PCWSTR lpValueName,
  133. CBaseStringBuffer &rBuffer,
  134. DWORD &rdwLastError,
  135. SIZE_T cExceptionalLastErrorValues,
  136. ...
  137. )
  138. {
  139. FN_PROLOG_WIN32
  140. LONG lResult;
  141. CStringBufferAccessor acc;
  142. DWORD cbBuffer;
  143. DWORD dwType = 0;
  144. va_list ap;
  145. SIZE_T i;
  146. rdwLastError = ERROR_SUCCESS;
  147. PARAMETER_CHECK((dwFlags & ~(FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING)) == 0);
  148. acc.Attach(&rBuffer);
  149. if (acc.GetBufferCb() > MAXDWORD)
  150. {
  151. cbBuffer = MAXDWORD;
  152. }
  153. else
  154. {
  155. cbBuffer = static_cast<DWORD>(acc.GetBufferCb());
  156. }
  157. lResult = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (LPBYTE) acc.GetBufferPtr(), &cbBuffer);
  158. if ((lResult == ERROR_FILE_NOT_FOUND) && (dwFlags & FUSIONP_REG_QUERY_SZ_VALUE_EX_MISSING_GIVES_NULL_STRING))
  159. {
  160. acc[0] = acc.NullCharacter();
  161. }
  162. else
  163. {
  164. va_start(ap, cExceptionalLastErrorValues);
  165. for (i=0; i<cExceptionalLastErrorValues; i++)
  166. {
  167. if (lResult == (LONG) va_arg(ap, DWORD))
  168. {
  169. rdwLastError = lResult;
  170. break;
  171. }
  172. }
  173. va_end(ap);
  174. if (rdwLastError != ERROR_SUCCESS)
  175. FN_SUCCESSFUL_EXIT();
  176. if (lResult == ERROR_MORE_DATA)
  177. {
  178. acc.Detach();
  179. IFW32FALSE_EXIT(rBuffer.Win32ResizeBuffer((cbBuffer + 1) / sizeof(CStringBufferAccessor::TChar), eDoNotPreserveBufferContents));
  180. acc.Attach(&rBuffer);
  181. if (acc.GetBufferCb() > MAXDWORD)
  182. {
  183. cbBuffer = MAXDWORD;
  184. }
  185. else
  186. {
  187. cbBuffer = static_cast<DWORD>(acc.GetBufferCb());
  188. }
  189. lResult = ::RegQueryValueExW(hKey, lpValueName, NULL, &dwType, (LPBYTE) acc.GetBufferPtr(), &cbBuffer);
  190. }
  191. if (lResult != ERROR_SUCCESS)
  192. {
  193. ::SetLastError(lResult);
  194. TRACE_WIN32_FAILURE_ORIGINATION(RegQueryValueExW);
  195. goto Exit;
  196. }
  197. if (dwType != REG_SZ)
  198. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegistryValueNotREG_SZ, ERROR_INVALID_DATA);
  199. }
  200. FN_EPILOG
  201. }
  202. BOOL
  203. FusionpRegQuerySzValueEx(
  204. DWORD dwFlags,
  205. HKEY hKey,
  206. PCWSTR lpValueName,
  207. CBaseStringBuffer &rBuffer
  208. )
  209. {
  210. DWORD dw;
  211. return ::FusionpRegQuerySzValueEx(dwFlags, hKey, lpValueName, rBuffer, dw, 0);
  212. }
  213. BOOL
  214. FusionpRegQueryDwordValueEx(
  215. DWORD dwFlags,
  216. HKEY hKey,
  217. PCWSTR wszValueName,
  218. PDWORD pdwValue,
  219. DWORD dwDefaultValue
  220. )
  221. {
  222. BOOL fSuccess = FALSE;
  223. BOOL bMissingValueOk = TRUE;
  224. DWORD dwType;
  225. DWORD dwSize;
  226. ULONG ulResult;
  227. FN_TRACE_WIN32(fSuccess);
  228. if (pdwValue != NULL)
  229. *pdwValue = dwDefaultValue;
  230. PARAMETER_CHECK(pdwValue != NULL);
  231. PARAMETER_CHECK(
  232. (dwFlags == 0) ||
  233. (dwFlags & FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE));
  234. PARAMETER_CHECK(hKey != NULL);
  235. bMissingValueOk = ((dwFlags & FUSIONP_REG_QUERY_DWORD_MISSING_VALUE_IS_FAILURE) != 0);
  236. ulResult = ::RegQueryValueExW(
  237. hKey,
  238. wszValueName,
  239. NULL,
  240. &dwType,
  241. (PBYTE)pdwValue,
  242. &(dwSize = sizeof(*pdwValue)));
  243. if (((ulResult == ERROR_SUCCESS) && (dwType == REG_DWORD)) ||
  244. ((ulResult == ERROR_FILE_NOT_FOUND) && bMissingValueOk))
  245. {
  246. fSuccess = TRUE;
  247. ::SetLastError(ERROR_SUCCESS);
  248. }
  249. else
  250. {
  251. ::SetLastError(ulResult);
  252. }
  253. Exit:
  254. return fSuccess;
  255. }
  256. BOOL
  257. CRegKey::DestroyKeyTree()
  258. {
  259. FN_PROLOG_WIN32
  260. CStringBuffer buffTemp;
  261. //
  262. // First go down and delete all our child subkeys
  263. //
  264. while (true)
  265. {
  266. BOOL fFlagTemp;
  267. CRegKey hkSubKey;
  268. IFW32FALSE_EXIT( this->EnumKey( 0, buffTemp, NULL, &fFlagTemp ) );
  269. if ( fFlagTemp )
  270. break;
  271. //
  272. // There's more to delete than meets the eye!
  273. //
  274. IFW32FALSE_EXIT( this->OpenSubKey(
  275. hkSubKey,
  276. buffTemp, KEY_ALL_ACCESS | FUSIONP_KEY_WOW64_64KEY) );
  277. if (hkSubKey == this->GetInvalidValue())
  278. {
  279. continue;
  280. }
  281. IFW32FALSE_EXIT( hkSubKey.DestroyKeyTree() );
  282. //
  283. // Delete the key, ignore errors
  284. //
  285. IFW32FALSE_EXIT_UNLESS( this->DeleteKey( buffTemp ),
  286. ( ::FusionpGetLastWin32Error() == ERROR_PATH_NOT_FOUND ) ||
  287. ( ::FusionpGetLastWin32Error() == ERROR_FILE_NOT_FOUND ),
  288. fFlagTemp );
  289. }
  290. // Clear out the entries in the key as well - values as well
  291. while ( true )
  292. {
  293. BOOL fFlagTemp;
  294. IFW32FALSE_EXIT( this->EnumValue( 0, buffTemp, NULL, NULL, NULL, &fFlagTemp ) );
  295. if ( fFlagTemp )
  296. {
  297. break;
  298. }
  299. IFW32FALSE_EXIT_UNLESS( this->DeleteValue( buffTemp ),
  300. ( ::FusionpGetLastWin32Error() == ERROR_PATH_NOT_FOUND ) ||
  301. ( ::FusionpGetLastWin32Error() == ERROR_FILE_NOT_FOUND ),
  302. fFlagTemp );
  303. }
  304. FN_EPILOG
  305. }
  306. BOOL
  307. CRegKey::DeleteValue(
  308. IN PCWSTR pcwszValueName,
  309. OUT DWORD &rdwWin32Error,
  310. IN SIZE_T cExceptionalWin32Errors,
  311. ...
  312. ) const
  313. {
  314. FN_PROLOG_WIN32
  315. va_list ap;
  316. SIZE_T i;
  317. rdwWin32Error = ERROR_SUCCESS;
  318. LONG l = ::RegDeleteValueW(*this, pcwszValueName);
  319. if (l != ERROR_SUCCESS)
  320. {
  321. va_start(ap, cExceptionalWin32Errors);
  322. for (i=0; i<cExceptionalWin32Errors; i++)
  323. {
  324. if (((DWORD) l) == va_arg(ap, DWORD))
  325. {
  326. rdwWin32Error = l;
  327. break;
  328. }
  329. }
  330. va_end(ap);
  331. if (rdwWin32Error == ERROR_SUCCESS)
  332. ORIGINATE_WIN32_FAILURE_AND_EXIT(RegDeleteValueW, (DWORD) l);
  333. }
  334. FN_EPILOG
  335. }
  336. BOOL
  337. CRegKey::DeleteValue(
  338. IN PCWSTR pcwszValueName
  339. ) const
  340. {
  341. DWORD dw;
  342. return this->DeleteValue(pcwszValueName, dw, 0);
  343. }
  344. BOOL
  345. CRegKey::SetValue(
  346. IN PCWSTR pcwszValueName,
  347. IN DWORD dwValue
  348. ) const
  349. {
  350. return this->SetValue(pcwszValueName, REG_DWORD, (PBYTE) &dwValue, sizeof(dwValue));
  351. }
  352. BOOL
  353. CRegKey::SetValue(
  354. IN PCWSTR pcwszValueName,
  355. IN const CBaseStringBuffer &rcbuffValueValue
  356. ) const
  357. {
  358. // EVIL EVIL EVIL:
  359. // Doing sizeof(WCHAR) to get the count of bytes in the
  360. // string is patently the wrong way of doing this, but
  361. // the stringbuffer API doesn't expose a method to find
  362. // out how many bytes the contained string contains.
  363. return this->SetValue(
  364. pcwszValueName,
  365. REG_SZ,
  366. (PBYTE) (static_cast<PCWSTR>(rcbuffValueValue)),
  367. rcbuffValueValue.Cch() * sizeof(WCHAR));
  368. }
  369. BOOL
  370. CRegKey::SetValue(
  371. IN PCWSTR pcwszValueName,
  372. IN DWORD dwRegType,
  373. IN const BYTE *pbData,
  374. IN SIZE_T cbData
  375. ) const
  376. {
  377. FN_PROLOG_WIN32
  378. IFREGFAILED_ORIGINATE_AND_EXIT(
  379. ::RegSetValueExW(
  380. *this,
  381. pcwszValueName,
  382. 0,
  383. dwRegType,
  384. pbData,
  385. (DWORD)cbData));
  386. FN_EPILOG
  387. }
  388. BOOL
  389. CRegKey::EnumValue(
  390. IN DWORD dwIndex,
  391. OUT CBaseStringBuffer& rbuffValueName,
  392. OUT LPDWORD lpdwType,
  393. OUT PBYTE pbData,
  394. OUT PDWORD pdwcbData,
  395. OUT PBOOL pfDone
  396. )
  397. {
  398. FN_PROLOG_WIN32
  399. DWORD dwMaxRequiredValueNameLength = 0;
  400. CStringBufferAccessor sbaValueNameAccess;
  401. BOOL fDone;
  402. if ( pfDone != NULL )
  403. *pfDone = FALSE;
  404. IFW32FALSE_EXIT( this->LargestSubItemLengths( NULL, &dwMaxRequiredValueNameLength ) );
  405. if ( dwMaxRequiredValueNameLength >= rbuffValueName.GetBufferCb() )
  406. IFW32FALSE_EXIT( rbuffValueName.Win32ResizeBuffer( dwMaxRequiredValueNameLength / sizeof(WCHAR), eDoNotPreserveBufferContents ) );
  407. sbaValueNameAccess.Attach( &rbuffValueName );
  408. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2(
  409. ::RegEnumValueW(
  410. *this,
  411. dwIndex,
  412. sbaValueNameAccess.GetBufferPtr(),
  413. &(dwMaxRequiredValueNameLength = sbaValueNameAccess.GetBufferCbAsDWORD()),
  414. NULL,
  415. lpdwType,
  416. pbData,
  417. pdwcbData),
  418. {ERROR_NO_MORE_ITEMS},
  419. fDone);
  420. if ( fDone && ( pfDone != NULL ) )
  421. {
  422. *pfDone = TRUE;
  423. }
  424. FN_EPILOG
  425. }
  426. BOOL
  427. CRegKey::LargestSubItemLengths(
  428. PDWORD pdwSubkeyLength,
  429. PDWORD pdwValueLength
  430. ) const
  431. {
  432. FN_PROLOG_WIN32
  433. IFREGFAILED_ORIGINATE_AND_EXIT( ::RegQueryInfoKeyW(
  434. *this, // hkey
  435. NULL, // lpclass
  436. NULL, // lpcbclass
  437. NULL, // lpreserved
  438. NULL, // lpcSubKeys
  439. pdwSubkeyLength, // lpcbMaxSubkeyLength
  440. NULL, // lpcbMaxClassLength
  441. NULL, // lpcValues
  442. pdwValueLength, // lpcbMaxValueNameLength
  443. NULL,
  444. NULL,
  445. NULL));
  446. FN_EPILOG
  447. }
  448. BOOL
  449. CRegKey::EnumKey(
  450. IN DWORD dwIndex,
  451. OUT CBaseStringBuffer &rbuffKeyName,
  452. OUT PFILETIME pftLastWriteTime,
  453. OUT PBOOL pfDone
  454. ) const
  455. {
  456. FN_PROLOG_WIN32
  457. CStringBufferAccessor sba;
  458. DWORD dwLargestKeyName = 0;
  459. BOOL fOutOfItems;
  460. if (pfDone != NULL)
  461. *pfDone = FALSE;
  462. IFW32FALSE_EXIT(this->LargestSubItemLengths(&dwLargestKeyName, NULL));
  463. if (dwLargestKeyName >= rbuffKeyName.GetBufferCb())
  464. IFW32FALSE_EXIT(
  465. rbuffKeyName.Win32ResizeBuffer(
  466. (dwLargestKeyName + 1) / sizeof(WCHAR),
  467. eDoNotPreserveBufferContents));
  468. sba.Attach(&rbuffKeyName);
  469. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2(
  470. ::RegEnumKeyExW(
  471. *this,
  472. dwIndex,
  473. sba.GetBufferPtr(),
  474. &(dwLargestKeyName = sba.GetBufferCbAsDWORD()),
  475. NULL,
  476. NULL,
  477. NULL,
  478. pftLastWriteTime ),
  479. {ERROR_NO_MORE_ITEMS},
  480. fOutOfItems );
  481. if ( fOutOfItems && ( pfDone != NULL ) )
  482. {
  483. *pfDone = TRUE;
  484. }
  485. FN_EPILOG
  486. }
  487. BOOL
  488. CRegKey::OpenOrCreateSubKey(
  489. OUT CRegKey& Target,
  490. IN PCWSTR SubKeyName,
  491. IN REGSAM rsDesiredAccess,
  492. IN DWORD dwOptions,
  493. IN PDWORD pdwDisposition,
  494. IN PWSTR pwszClass
  495. ) const
  496. {
  497. FN_PROLOG_WIN32
  498. HKEY hKeyNew = NULL;
  499. IFREGFAILED_ORIGINATE_AND_EXIT(
  500. ::RegCreateKeyExW(
  501. *this,
  502. SubKeyName,
  503. 0,
  504. pwszClass,
  505. dwOptions,
  506. rsDesiredAccess | FUSIONP_KEY_WOW64_64KEY,
  507. NULL,
  508. &hKeyNew,
  509. pdwDisposition));
  510. Target = hKeyNew;
  511. FN_EPILOG
  512. }
  513. BOOL
  514. CRegKey::OpenSubKey(
  515. OUT CRegKey& Target,
  516. IN PCWSTR SubKeyName,
  517. IN REGSAM rsDesiredAccess,
  518. IN DWORD ulOptions
  519. ) const
  520. {
  521. FN_PROLOG_WIN32
  522. BOOL fFilePathNotFound;
  523. HKEY hKeyNew = NULL;
  524. IFREGFAILED_ORIGINATE_AND_EXIT_UNLESS2( ::RegOpenKeyExW(
  525. *this,
  526. SubKeyName,
  527. ulOptions,
  528. rsDesiredAccess | FUSIONP_KEY_WOW64_64KEY,
  529. &hKeyNew),
  530. LIST_2(ERROR_FILE_NOT_FOUND, ERROR_PATH_NOT_FOUND),
  531. fFilePathNotFound );
  532. if (fFilePathNotFound)
  533. hKeyNew = this->GetInvalidValue();
  534. Target = hKeyNew;
  535. FN_EPILOG
  536. }
  537. BOOL
  538. CRegKey::DeleteKey(
  539. IN PCWSTR pcwszSubkeyName
  540. )
  541. {
  542. FN_PROLOG_WIN32
  543. #if !defined(FUSION_WIN)
  544. IFREGFAILED_ORIGINATE_AND_EXIT(::RegDeleteKeyW(*this, pcwszSubkeyName));
  545. #else
  546. //
  547. // Be sure to delete out of the native (64bit) registry.
  548. // The Win32 call doesn't have a place to pass the flag.
  549. //
  550. CRegKey ChildKey;
  551. NTSTATUS Status = STATUS_SUCCESS;
  552. IFW32FALSE_EXIT(this->OpenSubKey(ChildKey, pcwszSubkeyName, DELETE));
  553. //
  554. // make sure that the Key does exist, OpenSubKey return TRUE for non-existed Key
  555. //
  556. if (ChildKey != this->GetInvalidValue())
  557. {
  558. if (!NT_SUCCESS(Status = NtDeleteKey(ChildKey)))
  559. {
  560. RtlSetLastWin32ErrorAndNtStatusFromNtStatus(Status);
  561. goto Exit;
  562. }
  563. }
  564. #endif
  565. FN_EPILOG
  566. }
  567. BOOL
  568. CRegKey::Save(
  569. IN PCWSTR pcwszTargetFilePath,
  570. IN DWORD dwFlags,
  571. IN LPSECURITY_ATTRIBUTES pSAttrs
  572. )
  573. {
  574. FN_PROLOG_WIN32
  575. IFREGFAILED_ORIGINATE_AND_EXIT(::RegSaveKeyExW(*this, pcwszTargetFilePath, pSAttrs, dwFlags));
  576. FN_EPILOG
  577. }
  578. BOOL
  579. CRegKey::Restore(
  580. IN PCWSTR pcwszSourceFileName,
  581. IN DWORD dwFlags
  582. )
  583. {
  584. FN_PROLOG_WIN32
  585. IFREGFAILED_ORIGINATE_AND_EXIT(::RegRestoreKeyW(*this, pcwszSourceFileName, dwFlags));
  586. FN_EPILOG
  587. }