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.

630 lines
19 KiB

  1. /*++
  2. Copyright (c) 2001 Microsoft Corporation
  3. Abstract:
  4. @doc
  5. @module regwriter.cxx | Implementation of the Registry Writer
  6. @end
  7. Author:
  8. Stefan Steiner [SSteiner] 07/23/2001
  9. TBD:
  10. Revision History:
  11. Name Date Comments
  12. ssteiner 07/23/2001 created
  13. --*/
  14. #include "stdafx.h"
  15. #include "vs_idl.hxx"
  16. #include "vs_hash.hxx"
  17. #include <vswriter.h>
  18. #include "vs_seh.hxx"
  19. #include "vs_trace.hxx"
  20. #include "vs_debug.hxx"
  21. #include "regwriter.hxx"
  22. #include "allerror.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 "WRTREGRC"
  31. //
  32. ////////////////////////////////////////////////////////////////////////
  33. static GUID s_writerId =
  34. {
  35. 0xAFBAB4A2, 0x367D, 0x4D15, 0xA5, 0x86, 0x71, 0xDB, 0xB1, 0x8F, 0x84, 0x85
  36. };
  37. // The display name of the registry writer.
  38. static LPCWSTR s_wszWriterName = L"Registry Writer";
  39. // The file group component name for the system registry hives
  40. static LPCWSTR s_wszComponentName = L"Registry";
  41. #define VALUE_NAME_MACHINE L"\\REGISTRY\\MACHINE\\"
  42. #define VALUE_NAME_USER L"\\REGISTRY\\USER\\"
  43. struct SRegistryHiveEntry
  44. {
  45. LPCWSTR wszHiveFileName;
  46. HKEY hKey;
  47. LPCWSTR wszHiveName;
  48. };
  49. // The list of system registry hives that are handled by this writer
  50. static SRegistryHiveEntry s_sSystemRegistryHives[] =
  51. {
  52. { L"default", HKEY_USERS, L".DEFAULT" },
  53. { L"SAM", HKEY_LOCAL_MACHINE, L"SAM" },
  54. { L"SECURITY", HKEY_LOCAL_MACHINE, L"SECURITY" },
  55. { L"software", HKEY_LOCAL_MACHINE, L"SOFTWARE" },
  56. { L"system", HKEY_LOCAL_MACHINE, L"SYSTEM" },
  57. { NULL, HKEY_LOCAL_MACHINE, NULL }
  58. };
  59. // The list of extensions found on registry hive files that will be placed in the exclude list if they are found.
  60. static LPCWSTR s_wszRegistryExt[] =
  61. {
  62. L"", // Causes the hive file itself to be excluded
  63. L".LOG",
  64. L".sav",
  65. L".tmp.LOG",
  66. L".alt",
  67. NULL
  68. };
  69. // The location of where the registry hives will be copied.
  70. static CBsString s_cwsRegistryTargetDir = ROOT_BACKUP_DIR BOOTABLE_STATE_SUBDIR L"\\Registry";
  71. // The location of the system registry hives
  72. static CBsString s_cwsSystemRegistryHiveDir = L"%SystemRoot%\\system32\\config";
  73. // The location of the repair directory where the spit hives will be copied during thaw
  74. static CBsString s_cwsRepairDir = L"%SystemRoot%\\repair";
  75. // Class wide member variables
  76. CRegistryWriter *CRegistryWriter::sm_pWriter;
  77. HRESULT CRegistryWriter::sm_hrInitialize;
  78. HRESULT STDMETHODCALLTYPE CRegistryWriter::Initialize()
  79. {
  80. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::Initialize");
  81. try
  82. {
  83. m_bPerformSnapshot = FALSE;
  84. m_bSnapshotSuccessful = FALSE;
  85. ft.hr = CVssWriter::Initialize
  86. (
  87. s_writerId,
  88. s_wszWriterName,
  89. VSS_UT_BOOTABLESYSTEMSTATE,
  90. VSS_ST_OTHER,
  91. VSS_APP_SYSTEM,
  92. 60000
  93. );
  94. if (ft.HrFailed())
  95. ft.Throw
  96. (
  97. VSSDBG_WRITER,
  98. E_UNEXPECTED,
  99. L"Failed to initialize the Registry writer. hr = 0x%08lx",
  100. ft.hr
  101. );
  102. ft.hr = Subscribe();
  103. if (ft.HrFailed())
  104. ft.Throw
  105. (
  106. VSSDBG_WRITER,
  107. E_UNEXPECTED,
  108. L"Subscribing the Registry server writer failed. hr = %0x08lx",
  109. ft.hr
  110. );
  111. }
  112. VSS_STANDARD_CATCH(ft)
  113. return ft.hr;
  114. }
  115. HRESULT STDMETHODCALLTYPE CRegistryWriter::Uninitialize()
  116. {
  117. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::Uninitialize");
  118. return Unsubscribe();
  119. }
  120. // handle request for WRITER_METADATA
  121. // implements CVssWriter::OnIdentify
  122. bool STDMETHODCALLTYPE CRegistryWriter::OnIdentify(IVssCreateWriterMetadata *pMetadata)
  123. {
  124. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnIdentify");
  125. try
  126. {
  127. //
  128. // Set up common path strings if OnIdentify hasn't been called before.
  129. //
  130. if ( m_cwsExpandedConfigDir.IsEmpty() )
  131. {
  132. if ( !m_cwsExpandedConfigDir.ExpandEnvironmentStrings( s_cwsSystemRegistryHiveDir ) )
  133. {
  134. ft.TranslateError( VSSDBG_WRITER, HRESULT_FROM_WIN32( ::GetLastError() ), L"CBsString::ExpandEnvironmentStrings" );
  135. }
  136. }
  137. if ( m_cwsExpandedRegistryTargetDir.IsEmpty() )
  138. {
  139. if ( !m_cwsExpandedRegistryTargetDir.ExpandEnvironmentStrings( s_cwsRegistryTargetDir ) )
  140. {
  141. ft.TranslateError( VSSDBG_WRITER, HRESULT_FROM_WIN32( ::GetLastError() ), L"CBsString::ExpandEnvironmentStrings" );
  142. }
  143. }
  144. //
  145. // Set the restore method for the writer
  146. //
  147. ft.hr = pMetadata->SetRestoreMethod
  148. (
  149. VSS_RME_CUSTOM,
  150. NULL,
  151. NULL,
  152. VSS_WRE_NEVER,
  153. true
  154. );
  155. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::SetRestoreMethod");
  156. //
  157. // Add the one file component
  158. //
  159. ft.hr = pMetadata->AddComponent
  160. (
  161. VSS_CT_FILEGROUP,
  162. NULL,
  163. s_wszComponentName,
  164. s_wszComponentName,
  165. NULL, // icon
  166. 0,
  167. false,
  168. false,
  169. true
  170. );
  171. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddComponent");
  172. //
  173. // Add a file group file entry for each hive
  174. //
  175. INT iHive;
  176. for ( iHive = 0 ; s_sSystemRegistryHives[ iHive ].wszHiveFileName != NULL ; ++iHive )
  177. {
  178. ft.hr = pMetadata->AddFilesToFileGroup
  179. (
  180. NULL,
  181. s_wszComponentName,
  182. s_cwsRegistryTargetDir,
  183. s_sSystemRegistryHives[ iHive ].wszHiveFileName,
  184. false,
  185. NULL
  186. );
  187. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddFilesToFileGroup");
  188. }
  189. //
  190. // Determine list of auxiliary registry files that are to be excluded in the metadata. Sniff the
  191. // config directory for each file.
  192. //
  193. for ( iHive = 0 ; s_sSystemRegistryHives[ iHive ].wszHiveFileName != NULL ; ++iHive )
  194. {
  195. CBsString cwsHivePath = m_cwsExpandedConfigDir + L'\\';
  196. cwsHivePath += s_sSystemRegistryHives[ iHive ].wszHiveFileName;
  197. for ( INT iExt = 0 ; s_wszRegistryExt[ iExt ] != NULL ; ++iExt )
  198. {
  199. CBsString cwsFilePath = cwsHivePath + s_wszRegistryExt[ iExt ];
  200. // Test for existence.
  201. if ( ::GetFileAttributesW( cwsFilePath ) != 0xFFFFFFFF )
  202. {
  203. // File exists, add it to the exclude list
  204. ft.hr = pMetadata->AddExcludeFiles
  205. (
  206. s_cwsSystemRegistryHiveDir,
  207. CBsString( s_sSystemRegistryHives[ iHive ].wszHiveFileName ) + s_wszRegistryExt[ iExt ],
  208. false
  209. );
  210. ft.CheckForErrorInternal(VSSDBG_WRITER, L"IVssCreateWriterMetadata::AddExcludeFiles");
  211. }
  212. }
  213. }
  214. }
  215. VSS_STANDARD_CATCH(ft)
  216. TranslateWriterError(ft.hr);
  217. return ft.HrSucceeded();
  218. }
  219. bool STDMETHODCALLTYPE CRegistryWriter::OnPrepareBackup(
  220. IN IVssWriterComponents *pWriterComponents
  221. )
  222. {
  223. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnPrepareBackup");
  224. try
  225. {
  226. //
  227. // If the requestor has selected components, see if the Registry component
  228. // has been selected.
  229. //
  230. if ( AreComponentsSelected() )
  231. {
  232. UINT cComponents;
  233. m_bPerformSnapshot = FALSE;
  234. ft.hr = pWriterComponents->GetComponentCount( &cComponents );
  235. ft.CheckForErrorInternal( VSSDBG_WRITER, L"IVssWriterComponents::GetComponentCount" );
  236. for( UINT iComponent = 0; iComponent < cComponents; iComponent++ )
  237. {
  238. // Check to make sure the Registry component is selected.
  239. CComPtr<IVssComponent> pComponent;
  240. ft.hr = pWriterComponents->GetComponent( iComponent, &pComponent );
  241. ft.CheckForErrorInternal( VSSDBG_WRITER, L"IVssWriterComponents::GetComponent" );
  242. CComBSTR bstrComponentName;
  243. ft.hr = pComponent->GetComponentName( &bstrComponentName);
  244. ft.CheckForErrorInternal( VSSDBG_WRITER, L"IVssComponent::GetComponentName" );
  245. if ( ::_wcsicmp( s_wszComponentName, bstrComponentName ) == 0 )
  246. {
  247. // The registry component has been selected
  248. ft.Trace( VSSDBG_WRITER, L"Registry writer 'Registry' component selected, writer will copy registry hives" );
  249. m_bPerformSnapshot = TRUE;
  250. break;
  251. }
  252. }
  253. }
  254. else
  255. {
  256. ft.Trace( VSSDBG_WRITER, L"No Registry writer components selected" );
  257. }
  258. }
  259. VSS_STANDARD_CATCH( ft );
  260. TranslateWriterError(ft.hr);
  261. return ft.HrSucceeded();
  262. }
  263. bool STDMETHODCALLTYPE CRegistryWriter::OnPrepareSnapshot()
  264. {
  265. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnPrepareSnapshot");
  266. DWORD winStatus;
  267. HKEY hKeyBackup;
  268. try
  269. {
  270. m_bSnapshotSuccessful = FALSE;
  271. //
  272. // First make sure the spit directory is empty. If not, we must fail.
  273. // Even if Registry is not selected, avoid backing up old staff so there's no confusion
  274. //
  275. ft.hr = ::RemoveDirectoryTree( m_cwsExpandedRegistryTargetDir );
  276. ft.CheckForError( VSSDBG_WRITER, L"RemoveDirectoryTree" );
  277. //
  278. // If the registry component has not already been selected, check to see if Bootable state is selected
  279. //
  280. if ( !m_bPerformSnapshot && IsBootableSystemStateBackedUp() )
  281. {
  282. ft.Trace( VSSDBG_WRITER, L"Bootable system state snapshot, writer will copy registry hives" );
  283. m_bPerformSnapshot = TRUE;
  284. }
  285. if ( m_bPerformSnapshot )
  286. {
  287. //
  288. // Now let's create the base target directory.
  289. //
  290. ft.hr = ::CreateTargetPath( m_cwsExpandedRegistryTargetDir );
  291. ft.CheckForErrorInternal( VSSDBG_WRITER, L"CreateTargetPath" );
  292. ft.Trace( VSSDBG_WRITER, L"Extacting system registry hives from: '%s'", m_cwsExpandedConfigDir.c_str() );
  293. ft.Trace( VSSDBG_WRITER, L"Placing copied hives in: '%s'", m_cwsExpandedRegistryTargetDir.c_str() );
  294. //
  295. // Iterate through the hives and copy them to the spit directory
  296. //
  297. for ( INT iHive = 0 ; s_sSystemRegistryHives[ iHive ].wszHiveFileName != NULL ; ++iHive )
  298. {
  299. CBsString cwsHivePath = m_cwsExpandedConfigDir + L'\\';
  300. cwsHivePath += s_sSystemRegistryHives[ iHive ].wszHiveFileName;
  301. CBsString cwsHiveTargetPath = m_cwsExpandedRegistryTargetDir + L'\\';
  302. cwsHiveTargetPath += s_sSystemRegistryHives[ iHive ].wszHiveFileName;
  303. ft.Trace( VSSDBG_WRITER, L"Copying %s hive from %s to: %s", s_sSystemRegistryHives[ iHive ].wszHiveFileName,
  304. cwsHivePath.c_str(), cwsHiveTargetPath.c_str() );
  305. winStatus = ::RegCreateKeyExW(
  306. s_sSystemRegistryHives[ iHive ].hKey,
  307. s_sSystemRegistryHives[ iHive ].wszHiveName,
  308. 0,
  309. NULL,
  310. REG_OPTION_BACKUP_RESTORE,
  311. MAXIMUM_ALLOWED,
  312. NULL,
  313. &hKeyBackup,
  314. NULL
  315. );
  316. ft.hr = HRESULT_FROM_WIN32 (winStatus);
  317. ft.CheckForError( VSSDBG_WRITER, L"RegCreateKeyExW" );
  318. //
  319. // Use the new RegSaveKeyExW with REG_NO_COMPRESSION option to
  320. // quickly spit out the hives.
  321. //
  322. winStatus = ::RegSaveKeyExW(
  323. hKeyBackup,
  324. cwsHiveTargetPath,
  325. NULL,
  326. REG_NO_COMPRESSION
  327. );
  328. ::RegCloseKey( hKeyBackup );
  329. ft.hr = HRESULT_FROM_WIN32( winStatus );
  330. ft.CheckForError( VSSDBG_WRITER, L"RegSaveKeyExW" );
  331. }
  332. // BUG 456075: Mark the snapshot as being performed only if the hive was succesfully saved.
  333. // This member is used to decide when to move the saved hive
  334. // into teh %systemroot%\repair directory.
  335. if ( ft.HrSucceeded() )
  336. m_bSnapshotSuccessful = TRUE;
  337. }
  338. }
  339. VSS_STANDARD_CATCH(ft)
  340. TranslateWriterError(ft.hr);
  341. return ft.HrSucceeded();
  342. }
  343. bool STDMETHODCALLTYPE CRegistryWriter::OnFreeze()
  344. {
  345. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnFreeze");
  346. try
  347. {
  348. }
  349. VSS_STANDARD_CATCH(ft)
  350. TranslateWriterError(ft.hr);
  351. return ft.HrSucceeded();
  352. }
  353. bool STDMETHODCALLTYPE CRegistryWriter::OnThaw()
  354. {
  355. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnThaw");
  356. try
  357. {
  358. if ( m_bSnapshotSuccessful )
  359. {
  360. // Move the registry hives to the repair directory
  361. CBsString cwsExpandedRepairDir;
  362. cwsExpandedRepairDir.ExpandEnvironmentStrings( s_cwsRepairDir );
  363. ft.hr = ::MoveFilesInDirectory( m_cwsExpandedRegistryTargetDir, cwsExpandedRepairDir );
  364. if ( ft.HrFailed() )
  365. {
  366. ft.Trace( VSSDBG_WRITER, L"Warning, unable to move the registry hive from '%s' to '%s', hr: 0x08x",
  367. m_cwsExpandedRegistryTargetDir.c_str(), cwsExpandedRepairDir.c_str(), ft.hr );
  368. ft.hr = S_OK;
  369. }
  370. m_bSnapshotSuccessful = FALSE;
  371. }
  372. if ( m_bPerformSnapshot )
  373. {
  374. // Now remove the registry directory tree.
  375. ft.hr = ::RemoveDirectoryTree( m_cwsExpandedRegistryTargetDir );
  376. if ( ft.HrFailed() )
  377. {
  378. ft.Trace( VSSDBG_WRITER, L"Warning, unable to remove the registry backup directory: %s, hr: 0x08x",
  379. m_cwsExpandedRegistryTargetDir.c_str(), ft.hr );
  380. ft.hr = S_OK;
  381. }
  382. m_bPerformSnapshot = FALSE;
  383. }
  384. }
  385. VSS_STANDARD_CATCH( ft )
  386. TranslateWriterError( ft.hr );
  387. return ft.HrSucceeded();
  388. }
  389. bool STDMETHODCALLTYPE CRegistryWriter::OnAbort()
  390. {
  391. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::OnAbort");
  392. try
  393. {
  394. if ( m_bPerformSnapshot )
  395. {
  396. // Do not clean up spit directory on Abort since abort may be sent
  397. // after cancellation. Then it can interfere with the Simulate code
  398. // (used by NtBackup after cancellation) that invokes a Registry mini-writer
  399. //
  400. // RemoveDirectoryTree is being called in OnPrepareSnapshot such that there
  401. // is no danger of backing up old data
  402. m_bPerformSnapshot = FALSE;
  403. m_bSnapshotSuccessful = FALSE;
  404. }
  405. }
  406. VSS_STANDARD_CATCH(ft)
  407. TranslateWriterError( ft.hr );
  408. return ft.HrSucceeded();
  409. }
  410. bool CRegistryWriter::IsPathInSnapshot(const WCHAR *wszPath) throw()
  411. {
  412. return IsPathAffected(wszPath);
  413. }
  414. // translate a sql writer error code into a writer error
  415. void CRegistryWriter::TranslateWriterError(HRESULT hr)
  416. {
  417. switch(hr)
  418. {
  419. default:
  420. SetWriterFailure(VSS_E_WRITERERROR_NONRETRYABLE);
  421. break;
  422. case S_OK:
  423. break;
  424. case E_OUTOFMEMORY:
  425. case HRESULT_FROM_WIN32(ERROR_DISK_FULL):
  426. case HRESULT_FROM_WIN32(ERROR_TOO_MANY_OPEN_FILES):
  427. case HRESULT_FROM_WIN32(ERROR_NOT_ENOUGH_MEMORY):
  428. case HRESULT_FROM_WIN32(ERROR_NO_MORE_USER_HANDLES):
  429. SetWriterFailure(VSS_E_WRITERERROR_OUTOFRESOURCES);
  430. break;
  431. }
  432. }
  433. // Creates one instance of the Registry writer class. If one already exists, it simple returns.
  434. // static
  435. HRESULT CRegistryWriter::CreateWriter()
  436. {
  437. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::CreateWriter");
  438. if ( sm_pWriter != NULL )
  439. return S_OK;
  440. //
  441. // OK, spin up a thread to do the subscription in.
  442. //
  443. try
  444. {
  445. sm_pWriter = new CRegistryWriter;
  446. if (sm_pWriter == NULL)
  447. ft.Throw(VSSDBG_WRITER, E_OUTOFMEMORY, L"Allocation of CRegistryWriter object failed.");
  448. DWORD tid;
  449. HANDLE hThread = ::CreateThread
  450. (
  451. NULL,
  452. 256* 1024,
  453. InitializeThreadFunc,
  454. NULL,
  455. 0,
  456. &tid
  457. );
  458. if (hThread == NULL)
  459. ft.Throw
  460. (
  461. VSSDBG_WRITER,
  462. E_UNEXPECTED,
  463. L"CreateThread failed with error %d",
  464. ::GetLastError()
  465. );
  466. // wait for thread to complete
  467. ::WaitForSingleObject( hThread, INFINITE );
  468. ::CloseHandle( hThread );
  469. ft.hr = sm_hrInitialize;
  470. }
  471. VSS_STANDARD_CATCH(ft)
  472. if (ft.HrFailed() && sm_pWriter)
  473. {
  474. delete sm_pWriter;
  475. sm_pWriter = NULL;
  476. }
  477. return ft.hr;
  478. }
  479. // static
  480. DWORD CRegistryWriter::InitializeThreadFunc(VOID *pv)
  481. {
  482. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::InitializeThreadFunc");
  483. BOOL fCoinitializeSucceeded = false;
  484. try
  485. {
  486. // intialize MTA thread
  487. ft.hr = ::CoInitializeEx(NULL, COINIT_MULTITHREADED);
  488. if (ft.HrFailed())
  489. ft.Throw
  490. (
  491. VSSDBG_WRITER,
  492. E_UNEXPECTED,
  493. L"CoInitializeEx failed 0x%08lx", ft.hr
  494. );
  495. fCoinitializeSucceeded = true;
  496. // Now initialize the base class and subscribe
  497. ft.hr = sm_pWriter->Initialize();
  498. }
  499. VSS_STANDARD_CATCH(ft)
  500. if (fCoinitializeSucceeded)
  501. CoUninitialize();
  502. sm_hrInitialize = ft.hr;
  503. return 0;
  504. UNREFERENCED_PARAMETER( pv );
  505. }
  506. // static
  507. void CRegistryWriter::DestroyWriter()
  508. {
  509. CVssFunctionTracer ft(VSSDBG_WRITER, L"CRegistryWriter::DestroyWriter");
  510. if (sm_pWriter)
  511. {
  512. sm_pWriter->Uninitialize();
  513. delete sm_pWriter;
  514. sm_pWriter = NULL;
  515. }
  516. }