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.

2476 lines
77 KiB

  1. /******************************************************************************
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. romgr.cpp
  5. Abstract:
  6. This file contains the implementation of CRestoreOperationManager class and
  7. ::CreateRestoreOperationManager.
  8. Revision History:
  9. Seong Kook Khang (SKKhang) 06/20/00
  10. created
  11. ******************************************************************************/
  12. #include "stdwin.h"
  13. #include "rstrcore.h"
  14. #include "resource.h"
  15. #include "srdefs.h"
  16. #include "utils.h"
  17. #include "..\snapshot\snappatch.h"
  18. //
  19. // global variable for mfex marker
  20. //
  21. DWORD g_dwExistingMFEXMarker;
  22. CSRClientLoader g_CSRClientLoader;
  23. #define STR_REGPATH_SESSIONMANAGER L"System\\CurrentControlSet\\Control\\Session Manager"
  24. #define STR_REGVAL_MOVEFILEEX L"PendingFileRenameOperations"
  25. void SetRestoreStatusFailed()
  26. {
  27. TraceFunctEnter("SetRestoreStatusFailed");
  28. if (!::SRSetRegDword(HKEY_LOCAL_MACHINE,s_cszSRRegKey,s_cszRestoreStatus,0))
  29. {
  30. // ignore the error since this is not a fatal error
  31. ErrorTrace(0,"SRSetRegDword failed.ec=%d", GetLastError());
  32. }
  33. TraceFunctLeave();
  34. }
  35. DWORD RestoreRIDs (WCHAR *pszSamPath);
  36. /////////////////////////////////////////////////////////////////////////////
  37. // CRestoreOperationManager construction / destruction
  38. CRestoreOperationManager::CRestoreOperationManager()
  39. {
  40. m_fFullRestore = TRUE;
  41. m_szMapFile[0] = L'\0';
  42. m_pLogFile = NULL;
  43. m_pProgress = NULL;
  44. m_dwRPNum = 0;
  45. m_paryEnt = NULL;
  46. m_fRebuildCatalogDb = FALSE;
  47. }
  48. /////////////////////////////////////////////////////////////////////////////
  49. CRestoreOperationManager::~CRestoreOperationManager()
  50. {
  51. SAFE_RELEASE(m_pLogFile);
  52. SAFE_RELEASE(m_pProgress);
  53. }
  54. /////////////////////////////////////////////////////////////////////////////
  55. // CRestoreOperationManager - methods
  56. #define TIMEOUT_RESTORETHREAD 5000
  57. BOOL
  58. CRestoreOperationManager::Run( BOOL fFull )
  59. {
  60. TraceFunctEnter("CRestoreOperationManager::Run");
  61. BOOL fRet = FALSE;
  62. HANDLE hThread;
  63. DWORD dwRet;
  64. // Create progress window
  65. if ( !m_pProgress->Create() )
  66. goto Exit;
  67. m_fFullRestore = fFull;
  68. // Create secondary thread for main restore operation
  69. hThread = ::CreateThread( NULL, 0, ExtThreadProc, this, 0, NULL );
  70. if ( hThread == NULL )
  71. {
  72. LPCWSTR cszErr = ::GetSysErrStr();
  73. ErrorTrace(0, "::CreateThread failed - %ls", cszErr);
  74. //NOTE: should I try to run restore in the context of current thread?
  75. //
  76. goto Exit;
  77. }
  78. // Message loop, wait until restore thread closes progress window
  79. if ( !m_pProgress->Run() )
  80. goto Exit;
  81. // Double check if thread has been terminated
  82. dwRet = ::WaitForSingleObject( hThread, TIMEOUT_RESTORETHREAD );
  83. if ( dwRet == WAIT_FAILED )
  84. {
  85. LPCWSTR cszErr = ::GetSysErrStr();
  86. ErrorTrace(0, "::WaitForSingleObject failed - %ls", cszErr);
  87. goto Exit;
  88. }
  89. else if ( dwRet == WAIT_TIMEOUT )
  90. {
  91. ErrorTrace(0, "Timeout while waiting for the restore thread finishes...");
  92. goto Exit;
  93. }
  94. ::CloseHandle( hThread );
  95. fRet = TRUE;
  96. Exit:
  97. // Close method is safe to call even if window is not open, so calling it
  98. // unconditionally.
  99. m_pProgress->Close();
  100. TraceFunctLeave();
  101. return( fRet );
  102. }
  103. /////////////////////////////////////////////////////////////////////////////
  104. //
  105. // If fChecKSrc is TRUE, it means the dependency is for the result of the
  106. // original operation (e.g. delete, rename FROM, etc.). If it's FALSE, it
  107. // means the dependency is for the location which is being free'ed by the
  108. // original operation (e.g. add, rename TO, etc.).
  109. //
  110. BOOL
  111. CRestoreOperationManager::FindDependentMapEntry( LPCWSTR cszPath, BOOL fCheckObj, CRestoreMapEntry **ppEnt )
  112. {
  113. TraceFunctEnter("CRestoreOperationManager::FindDependentMapEntry");
  114. BOOL fRet = FALSE;
  115. int nEntAll;
  116. int nEnt;
  117. CRestoreMapEntry *pEnt;
  118. DWORD dwOpr;
  119. LPCWSTR cszDep;
  120. if ( ppEnt != NULL )
  121. *ppEnt = NULL;
  122. nEntAll = m_paryEnt[m_nDrv].GetSize();
  123. for ( nEnt = m_nEnt+1; nEnt < nEntAll; nEnt++ )
  124. {
  125. pEnt = m_paryEnt[m_nDrv][nEnt];
  126. dwOpr = pEnt->GetOpCode();
  127. cszDep = NULL;
  128. if ( fCheckObj )
  129. {
  130. switch ( dwOpr )
  131. {
  132. case OPR_DIR_RENAME :
  133. case OPR_FILE_RENAME :
  134. cszDep = pEnt->GetPath2();
  135. break;
  136. case OPR_DIR_DELETE :
  137. case OPR_FILE_DELETE :
  138. case OPR_FILE_MODIFY :
  139. //
  140. // ISSUE: SetAttrib and SetAcl cannot be processed by Session Manager.
  141. // In order to properly handle them, there should be post processing
  142. // just before displaying the result page. However, it might be
  143. // possible that the target file/dir is in use at that moment.
  144. //
  145. case OPR_SETATTRIB :
  146. case OPR_SETACL :
  147. cszDep = pEnt->GetPath1();
  148. break;
  149. }
  150. }
  151. else
  152. {
  153. switch ( dwOpr )
  154. {
  155. case OPR_DIR_CREATE :
  156. case OPR_DIR_RENAME :
  157. case OPR_FILE_ADD :
  158. case OPR_FILE_RENAME :
  159. cszDep = pEnt->GetPath1();
  160. break;
  161. }
  162. }
  163. if ( cszDep != NULL )
  164. if ( ::StrCmpI( cszPath, cszDep ) == 0 )
  165. break;
  166. }
  167. if ( nEnt >= nEntAll )
  168. goto Exit;
  169. // Dependent Node Found
  170. if ( ppEnt != NULL )
  171. *ppEnt = pEnt;
  172. fRet = TRUE;
  173. Exit:
  174. TraceFunctLeave();
  175. return( fRet );
  176. }
  177. /////////////////////////////////////////////////////////////////////////////
  178. BOOL
  179. CRestoreOperationManager::GetNextMapEntry( CRestoreMapEntry **ppEnt )
  180. {
  181. TraceFunctEnter("CRestoreOperationManager::GetNextMapEntry");
  182. BOOL fRet = FALSE;
  183. if ( ppEnt != NULL )
  184. *ppEnt = NULL;
  185. if ( m_nEnt >= m_paryEnt[m_nDrv].GetUpperBound() )
  186. goto Exit;
  187. if ( ppEnt != NULL )
  188. *ppEnt = m_paryEnt[m_nDrv][m_nEnt+1];
  189. fRet = TRUE;
  190. Exit:
  191. TraceFunctLeave();
  192. return( fRet );
  193. }
  194. /////////////////////////////////////////////////////////////////////////////
  195. BOOL
  196. CRestoreOperationManager::Release()
  197. {
  198. TraceFunctEnter("CRestoreOperationManager::Release");
  199. delete this;
  200. TraceFunctLeave();
  201. return( TRUE );
  202. }
  203. /////////////////////////////////////////////////////////////////////////////
  204. // CRestoreOperationManager operations
  205. static LPCWSTR s_cszMapFile = L"%SystemRoot%\\system32\\restore\\rstrmap.dat";
  206. BOOL
  207. CRestoreOperationManager::Init()
  208. {
  209. TraceFunctEnter("CRestoreOperationManager::Init");
  210. BOOL fRet = FALSE;
  211. SRstrLogHdrV3 sRPInfo;
  212. // Construct internal file pathes
  213. if ( ::ExpandEnvironmentStrings( s_cszMapFile, m_szMapFile, MAX_PATH ) == 0 )
  214. {
  215. LPCWSTR cszErr = ::GetSysErrStr();
  216. ErrorTrace(0, "::ExpandEnvironmentStrings failed - %s", cszErr);
  217. goto Exit;
  218. }
  219. // Open the log file and read restore point info
  220. if ( !::OpenRestoreLogFile( &m_pLogFile ) )
  221. goto Exit;
  222. if ( !m_pLogFile->ReadHeader( &sRPInfo, m_aryDrv ) )
  223. goto Exit;
  224. m_dwRPNum = sRPInfo.dwRPNum;
  225. m_dwRPNew = sRPInfo.dwRPNew;
  226. // Create progress window object
  227. if ( !::CreateRestoreProgressWindow( &m_pProgress ) )
  228. goto Exit;
  229. fRet = TRUE;
  230. Exit:
  231. if ( !fRet )
  232. {
  233. SAFE_RELEASE(m_pLogFile);
  234. SAFE_RELEASE(m_pProgress);
  235. }
  236. TraceFunctLeave();
  237. return( fRet );
  238. }
  239. /////////////////////////////////////////////////////////////////////////////
  240. // CRestoreOperationManager operations - worker thread
  241. DWORD WINAPI
  242. CRestoreOperationManager::ExtThreadProc( LPVOID lpParam )
  243. {
  244. TraceFunctEnter("CRestoreOperationManager::ExtThreadProc");
  245. DWORD dwRet;
  246. CRestoreOperationManager *pROMgr;
  247. pROMgr = (CRestoreOperationManager*)lpParam;
  248. dwRet = pROMgr->ROThreadProc();
  249. TraceFunctLeave();
  250. return( dwRet );
  251. }
  252. /////////////////////////////////////////////////////////////////////////////
  253. DWORD
  254. CRestoreOperationManager::ROThreadProc()
  255. {
  256. TraceFunctEnter("CRestoreOperationManager::ROThreadProc");
  257. DWORD dwRes;
  258. CSRLockFile cLock; // Lock/load designated files/dirs during a restore.
  259. // In order to simulate it as realistic as possible,
  260. // locking will be in effect during the entire
  261. // restoration.
  262. CSnapshot cSS;
  263. WCHAR szSysDrv[MAX_SYS_DRIVE]; // System Drive
  264. WCHAR szRPDir[MAX_RP_PATH]; // Restore Point Directory ("RPn")
  265. WCHAR szSSPath[MAX_PATH]; // Full path of Restore Point Directory
  266. // 1. Initialization.
  267. dwRes = T2Initialize();
  268. if ( dwRes != ERROR_SUCCESS )
  269. goto Exit;
  270. // 2. Create restore map and read it.
  271. m_pProgress->SetStage( RPS_PREPARE, 0 );
  272. dwRes = T2CreateMap();
  273. if ( dwRes != ERROR_SUCCESS )
  274. goto Exit;
  275. // 3. Preprocessing. (?)
  276. //
  277. // Do snapshot init here to prevent low disk conditions after
  278. // restore is done.
  279. //
  280. ::GetSystemDrive( szSysDrv );
  281. ::wsprintf( szRPDir, L"%s%d", s_cszRPDir, m_dwRPNum );
  282. ::MakeRestorePath( szSSPath, szSysDrv, szRPDir );
  283. //
  284. // unpatch the snapshot if need be
  285. // if the snapshot has not been patched, this should be a no-op
  286. //
  287. lstrcat(szSSPath, SNAPSHOT_DIR_NAME);
  288. dwRes = PatchReconstructOriginal(szSSPath, // original/patched snapshot path
  289. szSSPath); // reconstruct in same directory
  290. if ( dwRes != ERROR_SUCCESS )
  291. {
  292. ErrorTrace(0, "! PatchReconstructOriginal : %ld", dwRes);
  293. goto Exit;
  294. }
  295. ::MakeRestorePath( szSSPath, szSysDrv, szRPDir );
  296. dwRes = cSS.InitRestoreSnapshot( szSSPath );
  297. if ( dwRes != ERROR_SUCCESS )
  298. {
  299. LPCWSTR cszErr = NULL;
  300. cszErr = ::GetSysErrStr( dwRes );
  301. ErrorTrace(0, "cSS.InitResourceSnapshot failed - %ls", cszErr);
  302. goto Exit;
  303. }
  304. // 4. Restore.
  305. m_pProgress->SetStage( RPS_RESTORE, m_dwTotalEntry );
  306. dwRes = T2DoRestore( FALSE );
  307. if ( dwRes != ERROR_SUCCESS )
  308. {
  309. goto Exit;
  310. }
  311. // 5. Postprocessing. (?)
  312. // 6. Snapshot handling.
  313. m_pProgress->SetStage( RPS_SNAPSHOT, 0 );
  314. if ( m_fFullRestore )
  315. {
  316. dwRes = T2HandleSnapshot( cSS, szSSPath );
  317. if ( dwRes != ERROR_SUCCESS )
  318. {
  319. m_pLogFile->WriteMarker(RSTRLOGID_SNAPSHOTFAIL, dwRes);
  320. T2UndoForFail();
  321. goto Exit;
  322. }
  323. }
  324. Exit:
  325. // Regardless of whether the restore succeeded or failed, give
  326. // the user the impression that system restore is done with all
  327. // the things it had to do. So call SetStage to set the progress
  328. // bar to 90%. After that we will call Increment to make it go to
  329. // 100%
  330. m_pProgress->SetStage( RPS_SNAPSHOT, 0 );
  331. m_pProgress->Increment();
  332. Sleep(1000);
  333. T2CleanUp();
  334. m_pLogFile->WriteMarker( RSTRLOGID_ENDOFMAP, 0 ); // ignore error...
  335. m_pLogFile->Close();
  336. m_pProgress->Close();
  337. if (dwRes != ERROR_SUCCESS)
  338. SetRestoreStatusFailed();
  339. TraceFunctLeave();
  340. return( dwRes );
  341. }
  342. /////////////////////////////////////////////////////////////////////////////
  343. DWORD
  344. CRestoreOperationManager::T2Initialize()
  345. {
  346. TraceFunctEnter("CRestoreOperationManager::T2Initialize");
  347. // Reset the registry flag to clear the disk full error
  348. _VERIFY(TRUE==SetRestoreError(ERROR_SUCCESS)); // clear this error
  349. TraceFunctLeave();
  350. return( ERROR_SUCCESS );
  351. }
  352. /////////////////////////////////////////////////////////////////////////////
  353. /*
  354. // NOTE - 8/1/00 - skkhang
  355. //
  356. // Commented out to incorporate excluding restore map logic.
  357. // But DO NOT delete this until we are comfortable 100% about removing
  358. // restore map.
  359. //
  360. DWORD
  361. CRestoreOperationManager::T2CreateMap()
  362. {
  363. TraceFunctEnter("CRestoreOperationManager::T2CreateMap");
  364. DWORD dwRet = ERROR_INTERNAL_ERROR;
  365. LPCWSTR cszErr;
  366. DWORD dwLE;
  367. HANDLE hfMap = INVALID_HANDLE_VALUE;
  368. DWORD dwLastPos = 0;
  369. LPCWSTR cszDrv;
  370. WCHAR szDSPath[MAX_PATH];
  371. RestoreMapEntry *pRME = NULL;
  372. CRestoreMapEntry *pEnt = NULL;
  373. int i;
  374. SRstrLogHdrV3Ex sHdrEx;
  375. hfMap = ::CreateFile( m_szMapFile, GENERIC_READ|GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, 0, NULL );
  376. if ( hfMap == INVALID_HANDLE_VALUE )
  377. {
  378. dwRet = ::GetLastError();
  379. //LOGLOG - CreateFile failed...
  380. goto Exit;
  381. }
  382. for ( i = 0; i < m_aryDrv.GetSize(); i++ )
  383. {
  384. if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsFrozen() || m_aryDrv[i]->IsExcluded() )
  385. continue;
  386. // set cszDrv to proper drive letters...
  387. cszDrv = m_aryDrv[i]->GetMount();
  388. ::MakeRestorePath( szDSPath, cszDrv, NULL );
  389. DebugTrace(0, "Drive #%d: Drv='%ls', DS='%ls'", i, cszDrv, szDSPath);
  390. dwLastPos = ::SetFilePointer( hfMap, 0, NULL, FILE_CURRENT );
  391. //??? should I check error from this???
  392. dwLE = ::CreateRestoreMap( (LPWSTR)cszDrv, m_dwRPNum, hfMap );
  393. if ( dwLE != ERROR_SUCCESS )
  394. {
  395. if ( dwLE != ERROR_NO_MORE_ITEMS )
  396. {
  397. cszErr = ::GetSysErrStr( dwLE );
  398. ErrorTrace(0, "::CreateRestoreMap failed - %ls", cszErr);
  399. dwRet = dwLE;
  400. goto Exit;
  401. }
  402. DebugTrace(0, "Nothing to restore in this drive...");
  403. // Some drive might not have any changes in there.
  404. // So gracefully ignore and move to the next drive.
  405. continue;
  406. }
  407. ::SetFilePointer( hfMap, dwLastPos, NULL, FILE_BEGIN );
  408. dwLE = ::GetLastError();
  409. if ( dwLE != NO_ERROR )
  410. {
  411. cszErr = ::GetSysErrStr( dwLE );
  412. ErrorTrace(0, "::SetFilePointer failed - %ls", cszErr);
  413. dwRet = dwLE;
  414. goto Exit;
  415. }
  416. while ( ::ReadRestoreMapEntry( hfMap, &pRME ) == ERROR_SUCCESS )
  417. {
  418. pEnt = ::CreateRestoreMapEntry( pRME, cszDrv, szDSPath );
  419. if ( pEnt == NULL )
  420. goto Exit;
  421. if ( !m_aryEnt.AddItem( pEnt ) )
  422. goto Exit;
  423. pEnt = NULL;
  424. }
  425. }
  426. ::FreeRestoreMapEntry(pRME);
  427. pRME = NULL;
  428. //sHdrEx.dwCount = m_aryEnt.GetSize();
  429. //m_pLogFile->AppendHeader( &sHdrEx );
  430. dwRet = ERROR_SUCCESS;
  431. Exit:
  432. // clean up the list if necessary...
  433. if ( dwRet != ERROR_SUCCESS )
  434. if ( pRME != NULL )
  435. ::FreeRestoreMapEntry(pRME);
  436. if ( hfMap != INVALID_HANDLE_VALUE )
  437. ::CloseHandle( hfMap );
  438. TraceFunctLeave();
  439. return( dwRet );
  440. }
  441. */
  442. DWORD
  443. CRestoreOperationManager::T2CreateMap()
  444. {
  445. TraceFunctEnter("CRestoreOperationManager::T2CreateMap");
  446. DWORD dwRet = ERROR_INTERNAL_ERROR;
  447. LPCWSTR cszErr;
  448. int nDrv;
  449. WCHAR szDrv[MAX_PATH];
  450. WCHAR szDSPath[MAX_PATH];
  451. int i;
  452. m_dwTotalEntry = 0;
  453. nDrv = m_aryDrv.GetSize();
  454. if ( nDrv > 0 )
  455. {
  456. m_paryEnt = new CRMEArray[nDrv];
  457. if ( m_paryEnt == NULL )
  458. {
  459. FatalTrace(0, "Insufficient memory...");
  460. dwRet = ERROR_NOT_ENOUGH_MEMORY;
  461. goto Exit;
  462. }
  463. }
  464. for ( i = 0; i < m_aryDrv.GetSize(); i++ )
  465. {
  466. if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsFrozen() || m_aryDrv[i]->IsExcluded() )
  467. continue;
  468. // use the volume guid for each volume
  469. // we cannot use mountpoint paths because
  470. // restore might delete mount points before
  471. // the operations on that volume are restored
  472. ::lstrcpy( szDrv, m_aryDrv[i]->GetID() );
  473. //cszDrv = m_aryDrv[i]->GetMount();
  474. ::MakeRestorePath( szDSPath, szDrv, NULL );
  475. DebugTrace(0, "Drive #%d: Drv='%ls', DS='%ls'", i, szDrv, szDSPath);
  476. // Following code assumes descructor of CChangeLogEntryEnum calls FindClose
  477. // automatically.
  478. CChangeLogEntryEnum cEnum( szDrv, 0, m_dwRPNum, FALSE );
  479. CChangeLogEntry cCLE;
  480. dwRet = cEnum.FindFirstChangeLogEntry( cCLE );
  481. if ( dwRet == ERROR_NO_MORE_ITEMS )
  482. continue;
  483. if ( dwRet != ERROR_SUCCESS )
  484. {
  485. cszErr = ::GetSysErrStr( dwRet );
  486. ErrorTrace(0, "FindFirstChangeLogEntry failed - %ls", cszErr);
  487. goto Exit;
  488. }
  489. while ( dwRet == ERROR_SUCCESS )
  490. {
  491. if ( !::CreateRestoreMapEntryFromChgLog( &cCLE, szDrv, szDSPath, m_paryEnt[i] ) )
  492. goto Exit;
  493. // Update progress bar.
  494. m_pProgress->Increment();
  495. dwRet = cEnum.FindNextChangeLogEntry( cCLE );
  496. }
  497. if ( dwRet != ERROR_NO_MORE_ITEMS )
  498. {
  499. cszErr = ::GetSysErrStr( dwRet );
  500. ErrorTrace(0, "FindNextChangeLogEntry failed - %ls", cszErr);
  501. goto Exit;
  502. }
  503. m_dwTotalEntry += m_paryEnt[i].GetSize();
  504. }
  505. dwRet = ERROR_SUCCESS;
  506. Exit:
  507. // clean up the list if necessary...
  508. TraceFunctLeave();
  509. return( dwRet );
  510. }
  511. /////////////////////////////////////////////////////////////////////////////
  512. DWORD
  513. CRestoreOperationManager::T2DoRestore( BOOL fUndo )
  514. {
  515. TraceFunctEnter("CRestoreOperationManager::T2DoRestore");
  516. DWORD dwRet = ERROR_SUCCESS;
  517. DWORD dwRes;
  518. DWORD dwErr;
  519. ULARGE_INTEGER ulTotalFreeBytes;
  520. for ( m_nDrv = 0; m_nDrv < m_aryDrv.GetSize(); m_nDrv++ )
  521. {
  522. for ( m_nEnt = 0; m_nEnt < m_paryEnt[m_nDrv].GetSize(); m_nEnt++ )
  523. {
  524. CRestoreMapEntry *pEnt = m_paryEnt[m_nDrv][m_nEnt];
  525. //
  526. // BUGBUG - this code is a workaround for filter logging
  527. // acl ops on FAT drives
  528. //
  529. // check if this volume supports acls
  530. // if not, no-op
  531. //
  532. if (pEnt->GetOpCode() == SrEventAclChange)
  533. {
  534. WCHAR szLabel[MAX_PATH];
  535. DWORD dwFlags = 0, dwRc;
  536. if (::GetVolumeInformation(m_aryDrv[m_nDrv]->GetID(),
  537. szLabel, MAX_PATH, NULL, NULL, &dwFlags, NULL, 0))
  538. {
  539. if (! (dwFlags & FS_PERSISTENT_ACLS))
  540. {
  541. DebugTrace(0, "Ignoring ACL change on non-NTFS drive");
  542. continue;
  543. }
  544. }
  545. else
  546. {
  547. dwRc = GetLastError();
  548. DebugTrace(0, "! GetVolumeInformation : %ld", dwRc);
  549. }
  550. }
  551. // Skip dependent entries of locked files
  552. if ( pEnt->GetResult() == RSTRRES_LOCKED )
  553. continue;
  554. // if any .CAT files are modified in the CATROOT directory,
  555. // we need to rebuild the catalog db later
  556. if (StrStrI(pEnt->GetPath1(), L"CatRoot") &&
  557. StrStrI(pEnt->GetPath1(), L".CAT"))
  558. {
  559. m_fRebuildCatalogDb = TRUE;
  560. }
  561. else if (pEnt->GetPath2() != NULL &&
  562. StrStrI(pEnt->GetPath2(), L"CatRoot") &&
  563. StrStrI(pEnt->GetPath2(), L".CAT"))
  564. {
  565. m_fRebuildCatalogDb = TRUE;
  566. }
  567. //
  568. // check if we have more than 60mb freespace
  569. // if we don't, pre-emptively undo the restore
  570. // 60mb was chosen so that there is a buffer between
  571. // the freeze threshold 50mb and the restore threshold -
  572. // this will avoid the case where we successfully restore
  573. // and freeze immediately after the reboot
  574. //
  575. if (FALSE == GetDiskFreeSpaceEx(m_aryDrv[m_nDrv]->GetID(),
  576. NULL,
  577. NULL,
  578. &ulTotalFreeBytes))
  579. {
  580. dwRet = GetLastError();
  581. ErrorTrace(0, "! GetDiskFreeSpaceEx : %ld - ignoring", dwRet);
  582. }
  583. else
  584. {
  585. if (ulTotalFreeBytes.QuadPart <= THRESHOLD_RESTORE_DISKSPACE * MEGABYTE)
  586. {
  587. DebugTrace(0, "***Less than 60MB free - initiating fifo***");
  588. dwRet = T2Fifo( m_nDrv, m_dwRPNum );
  589. if ( dwRet != ERROR_SUCCESS )
  590. {
  591. ErrorTrace(0, "! T2Fifo : %ld - ignoring", dwRet);
  592. }
  593. //
  594. // get free space again - if still below 60mb, bail
  595. //
  596. if (FALSE == GetDiskFreeSpaceEx(m_aryDrv[m_nDrv]->GetID(),
  597. NULL,
  598. NULL,
  599. &ulTotalFreeBytes))
  600. {
  601. dwRet = GetLastError();
  602. ErrorTrace(0, "! GetDiskFreeSpaceEx : %ld - ignoring", dwRet);
  603. }
  604. else
  605. {
  606. if (ulTotalFreeBytes.QuadPart <= THRESHOLD_RESTORE_DISKSPACE * MEGABYTE)
  607. {
  608. DebugTrace(0, "***Still less than 60MB free***");
  609. // if disk is indeed full, set the registry flag to indicate this
  610. // error
  611. _VERIFY(TRUE==SetRestoreError(ERROR_DISK_FULL)); // set this error
  612. if ( !fUndo )
  613. {
  614. ErrorTrace(0, "***Initiating Undo***");
  615. T2UndoForFail();
  616. dwRet = ERROR_INTERNAL_ERROR;
  617. goto Exit;
  618. }
  619. }
  620. }
  621. }
  622. }
  623. // RESTORE RESTORE RESTORE!!!
  624. pEnt->Restore( this );
  625. dwRes = pEnt->GetResult();
  626. dwErr = pEnt->GetError();
  627. DebugTrace(0, "Res=%d, Err=%d", dwRes, dwErr);
  628. if ( ( dwRes == RSTRRES_FAIL ) && ( dwErr == ERROR_DISK_FULL ) )
  629. {
  630. DebugTrace(0, "Disk full, initiating fifo to clean up memory...");
  631. dwRet = T2Fifo( m_nDrv, m_dwRPNum );
  632. if ( dwRet != ERROR_SUCCESS )
  633. goto Exit;
  634. // Try again...
  635. pEnt->Restore( this );
  636. dwRes = pEnt->GetResult();
  637. dwErr = pEnt->GetError();
  638. DebugTrace(0, "Res=%d, Err=%d", dwRes, dwErr);
  639. }
  640. // if disk is indeed full, set the registry flag to indicate this
  641. // error
  642. if ( ( dwRes == RSTRRES_FAIL ) && ( dwErr == ERROR_DISK_FULL ) )
  643. {
  644. DebugTrace(0, "Restore failed agin because of Disk full. Setting Error");
  645. _VERIFY(TRUE==SetRestoreError(ERROR_DISK_FULL)); // set this error
  646. }
  647. // Locked or Locked_Alt should be handled after finishing normal entries...
  648. if ( ( dwRes == RSTRRES_LOCKED ) || ( dwRes == RSTRRES_LOCKED_ALT ) )
  649. continue;
  650. // if there was a file-directory collision, record the file rename entry first
  651. // so that it will displayed on the results screen
  652. if ( ( pEnt->GetOpCode() == OPR_DIR_CREATE ||
  653. pEnt->GetOpCode() == OPR_DIR_RENAME ||
  654. pEnt->GetOpCode() == OPR_FILE_ADD ||
  655. pEnt->GetOpCode() == OPR_FILE_RENAME ) &&
  656. ( pEnt->GetResult() == RSTRRES_COLLISION ) )
  657. {
  658. // add collision log entry
  659. m_pLogFile->WriteCollisionEntry( pEnt->GetPath1(), pEnt->GetAltPath(), m_aryDrv[m_nDrv]->GetMount() );
  660. pEnt->SetResults(RSTRRES_OK, ERROR_SUCCESS);
  661. }
  662. // Write log entry
  663. if ( !m_pLogFile->WriteEntry( m_nEnt, pEnt, m_aryDrv[m_nDrv]->GetMount() ) )
  664. goto Exit;
  665. if ( !fUndo && ( pEnt->GetResult() == RSTRRES_FAIL ) )
  666. {
  667. ErrorTrace(0, "Failure detected, initiating Undo...");
  668. T2UndoForFail();
  669. dwRet = ERROR_INTERNAL_ERROR;
  670. goto Exit;
  671. }
  672. // Temporary Hack for directory collision, scan forward.
  673. if ( ( pEnt->GetOpCode() == OPR_DIR_DELETE ) &&
  674. ( pEnt->GetResult() == RSTRRES_IGNORE ) )
  675. {
  676. LPCWSTR cszSrc = pEnt->GetPath1();
  677. for ( int j = m_nEnt+1; j < m_paryEnt[m_nDrv].GetSize(); j++ )
  678. {
  679. CRestoreMapEntry *pEnt2 = m_paryEnt[m_nDrv][j];
  680. DWORD dwOpr = pEnt2->GetOpCode();
  681. if ( ( dwOpr == OPR_DIR_CREATE ) ||
  682. ( dwOpr == OPR_DIR_RENAME ) ||
  683. ( dwOpr == OPR_FILE_RENAME ) ||
  684. ( dwOpr == OPR_FILE_ADD ) )
  685. if ( ::StrCmpIW( cszSrc, pEnt2->GetPath1() ) == 0 )
  686. break;
  687. }
  688. if ( j < m_paryEnt[m_nDrv].GetSize() )
  689. {
  690. // found dependent node, current node should be renamed
  691. WCHAR szAlt[SR_MAX_FILENAME_LENGTH];
  692. if ( !::SRGetAltFileName( cszSrc, szAlt ) )
  693. {
  694. // Fatal, possible only when total disk failure.
  695. ErrorTrace(0, "Fatal failure, initiating Undo...");
  696. T2UndoForFail();
  697. dwRet = ERROR_INTERNAL_ERROR;
  698. goto Exit;
  699. }
  700. if ( !::MoveFile( cszSrc, szAlt ) )
  701. {
  702. // Failed to rename the directory, so the dependent opr will fail.
  703. // Abort the restore.
  704. LPCWSTR cszErr;
  705. pEnt->SetResults( RSTRRES_FAIL, ::GetLastError() );
  706. cszErr = ::GetSysErrStr( pEnt->GetError() );
  707. ErrorTrace(0, "::MoveFile failed - %s", cszErr);
  708. ErrorTrace(0, " Src=%ls", cszSrc);
  709. ErrorTrace(0, " New=%ls", szAlt);
  710. goto Exit;
  711. }
  712. // add collision log entry
  713. m_pLogFile->WriteCollisionEntry( cszSrc, szAlt, m_aryDrv[m_nDrv]->GetMount() );
  714. }
  715. }
  716. // Update progress bar.
  717. m_pProgress->Increment();
  718. }
  719. }
  720. //
  721. // get the size of the existing movefileex entries
  722. // so that we can skip these when we transfer restore's movefileex entries
  723. // to the old registry
  724. //
  725. DWORD dwType;
  726. g_dwExistingMFEXMarker = 0;
  727. if (ERROR_SUCCESS != SHGetValue( HKEY_LOCAL_MACHINE,
  728. STR_REGPATH_SESSIONMANAGER,
  729. STR_REGVAL_MOVEFILEEX,
  730. &dwType,
  731. NULL,
  732. &g_dwExistingMFEXMarker ))
  733. {
  734. g_dwExistingMFEXMarker = 0;
  735. }
  736. trace(0, "g_dwExistingMFEXMarker = %ld", g_dwExistingMFEXMarker);
  737. // Handles locked cases...
  738. for ( m_nDrv = 0; m_nDrv < m_aryDrv.GetSize(); m_nDrv++ )
  739. {
  740. for ( m_nEnt = 0; m_nEnt < m_paryEnt[m_nDrv].GetSize(); m_nEnt++ )
  741. {
  742. CRestoreMapEntry *pEnt = m_paryEnt[m_nDrv][m_nEnt];
  743. dwRes = pEnt->GetResult();
  744. if ( dwRes == RSTRRES_LOCKED_ALT )
  745. {
  746. // Add MoveFileEx entry to delete alt object.
  747. pEnt->ProcessLockedAlt();
  748. }
  749. else if ( dwRes == RSTRRES_LOCKED )
  750. {
  751. // Add MoveFileEx entry.
  752. pEnt->ProcessLocked();
  753. }
  754. else
  755. continue;
  756. // Write log entry
  757. if ( !m_pLogFile->WriteEntry( m_nEnt, pEnt, m_aryDrv[m_nDrv]->GetMount() ) )
  758. goto Exit;
  759. // Update progress bar.
  760. m_pProgress->Increment();
  761. }
  762. }
  763. Exit:
  764. TraceFunctLeave();
  765. return( dwRet );
  766. }
  767. /////////////////////////////////////////////////////////////////////////////
  768. static LPCWSTR s_cszRunOnceValueName = L"*Restore";
  769. static LPCWSTR s_cszRestoreUIPath = L"%SystemRoot%\\system32\\restore\\rstrui.exe";
  770. static LPCWSTR s_cszRunOnceOptNormal = L" -c";
  771. static LPCWSTR s_cszRunOnceOptSilent = L" -b";
  772. static LPCWSTR s_cszCatTimeStamp = L"%SystemRoot%\\system32\\catroot\\{F750E6C3-38EE-11D1-85E5-00C04FC295EE}\\timestamp";
  773. static LPCWSTR s_cszRegLMSWRunOnce = L"Microsoft\\Windows\\CurrentVersion\\RunOnce";
  774. static LPCWSTR s_cszRegLMSWWinLogon = L"Microsoft\\Windows NT\\CurrentVersion\\Winlogon";
  775. static LPCWSTR s_cszRegSystemRestore = L"Microsoft\\Windows NT\\CurrentVersion\\SystemRestore";
  776. static LPCWSTR s_cszRegValSfcScan = L"SfcScan";
  777. static LPCWSTR s_cszRegValAllowProtectedRenames = L"AllowProtectedRenames";
  778. static LPCWSTR s_cszTZKeyInHive = L"CurrentControlSet\\Control\\TimeZoneInformation";
  779. static LPCWSTR s_cszTZKeyInRegistry = L"System\\CurrentControlSet\\Control\\TimeZoneInformation";
  780. #define VALIDATE_DWRET(str) \
  781. if ( dwRet != ERROR_SUCCESS ) \
  782. { \
  783. cszErr = ::GetSysErrStr( dwRet ); \
  784. ErrorTrace(0, str " failed - %ls", cszErr); \
  785. goto Exit; \
  786. } \
  787. DWORD
  788. FindDriveMapping(HKEY hk, LPBYTE pSig, DWORD dwSig, LPWSTR pszDrive)
  789. {
  790. DWORD dwIndex = 0;
  791. DWORD dwRet = ERROR_SUCCESS;
  792. DWORD dwType, dwSize = MAX_PATH;
  793. BYTE rgbSig[1024];
  794. DWORD cbSig = sizeof(rgbSig);
  795. LPCWSTR cszErr;
  796. TENTER("FindDriveMapping");
  797. while (ERROR_SUCCESS ==
  798. (dwRet = RegEnumValue( hk,
  799. dwIndex++,
  800. pszDrive,
  801. &dwSize,
  802. NULL,
  803. &dwType,
  804. rgbSig,
  805. &cbSig )))
  806. {
  807. if (0 == wcsncmp(pszDrive, L"\\DosDevice", 10))
  808. {
  809. if (cbSig == dwSig &&
  810. (0 == memcmp(rgbSig, pSig, cbSig)))
  811. break;
  812. }
  813. dwSize = MAX_PATH;
  814. cbSig = sizeof(rgbSig);
  815. }
  816. TLEAVE();
  817. return dwRet;
  818. }
  819. DWORD
  820. KeepMountedDevices(HKEY hkMount)
  821. {
  822. HKEY hkNew = NULL, hkOld = NULL;
  823. DWORD dwIndex = 0;
  824. WCHAR szValue[MAX_PATH], szDrive[MAX_PATH];
  825. BYTE rgbSig[1024];
  826. DWORD cbSig;
  827. DWORD dwSize, dwType;
  828. DWORD dwRet = ERROR_SUCCESS;
  829. LPCWSTR cszErr;
  830. TENTER("KeepMountedDevices");
  831. //
  832. // open the old and new MountedDevices
  833. //
  834. dwRet = ::RegOpenKey( hkMount, L"MountedDevices", &hkOld );
  835. VALIDATE_DWRET("::RegOpenKey");
  836. dwRet = ::RegOpenKey( HKEY_LOCAL_MACHINE, L"System\\MountedDevices", &hkNew );
  837. VALIDATE_DWRET("::RegOpenKey");
  838. //
  839. // enumerate the old devices
  840. // delete volumes that don't exist in the new (i.e. current)
  841. //
  842. dwSize = MAX_PATH;
  843. cbSig = sizeof(rgbSig);
  844. while (ERROR_SUCCESS ==
  845. (dwRet = RegEnumValue( hkOld,
  846. dwIndex++,
  847. szValue,
  848. &dwSize,
  849. NULL,
  850. &dwType,
  851. rgbSig,
  852. &cbSig )))
  853. {
  854. if (0 == wcsncmp(szValue, L"\\??\\Volume", 10))
  855. {
  856. //
  857. // this is a Volume -> Signature mapping
  858. // check if the volume exists in the new
  859. //
  860. trace(0, "Old Volume = %S", szValue);
  861. dwSize = sizeof(rgbSig);
  862. dwRet = RegQueryValueEx(hkNew,
  863. szValue,
  864. NULL,
  865. &dwType,
  866. rgbSig,
  867. &dwSize);
  868. if (ERROR_SUCCESS != dwRet)
  869. {
  870. //
  871. // nope
  872. // so delete the volume and driveletter mapping from old
  873. //
  874. DWORD dwSave = FindDriveMapping(hkOld, rgbSig, cbSig, szDrive);
  875. dwRet = RegDeleteValue(hkOld, szValue);
  876. VALIDATE_DWRET("RegDeleteValue");
  877. if (dwSave == ERROR_SUCCESS)
  878. {
  879. dwIndex--; // hack to make RegEnumValueEx work
  880. dwRet = RegDeleteValue(hkOld, szDrive);
  881. VALIDATE_DWRET("RegDeleteValue");
  882. }
  883. trace(0, "Deleted old volume");
  884. }
  885. }
  886. else if (szValue[0] == L'#')
  887. {
  888. trace(0, "Old Mountpoint = %S", szValue);
  889. }
  890. else if (0 == wcsncmp(szValue, L"\\DosDevice", 10))
  891. {
  892. trace(0, "Old Drive = %S", szValue);
  893. }
  894. else
  895. {
  896. trace(0, "Old Unknown = %S", szValue);
  897. }
  898. dwSize = MAX_PATH;
  899. cbSig = sizeof(rgbSig);
  900. }
  901. if (dwRet != ERROR_NO_MORE_ITEMS)
  902. VALIDATE_DWRET("::RegEnumValue");
  903. //
  904. // now enumerate the current (new) devices
  905. //
  906. dwIndex = 0;
  907. dwSize = MAX_PATH;
  908. cbSig = sizeof(rgbSig);
  909. while (ERROR_SUCCESS ==
  910. (dwRet = RegEnumValue( hkNew,
  911. dwIndex++,
  912. szValue,
  913. &dwSize,
  914. NULL,
  915. &dwType,
  916. rgbSig,
  917. &cbSig )))
  918. {
  919. if (0 == wcsncmp(szValue, L"\\??\\Volume", 10))
  920. {
  921. //
  922. // this is a Volume -> Signature mapping
  923. // copy the new volume to the old
  924. //
  925. trace(0, "New Volume = %S", szValue);
  926. DWORD dwSave = FindDriveMapping(hkOld, rgbSig, cbSig, szDrive);
  927. dwRet = RegSetValueEx(hkOld,
  928. szValue,
  929. NULL,
  930. REG_BINARY,
  931. rgbSig,
  932. cbSig);
  933. VALIDATE_DWRET("::RegSetValueEx");
  934. if (dwSave == ERROR_NO_MORE_ITEMS)
  935. {
  936. //
  937. // there is no driveletter for this volume in the old registry
  938. // so copy the new one to the old if it exists
  939. //
  940. if (ERROR_SUCCESS ==
  941. FindDriveMapping(hkNew, rgbSig, cbSig, szDrive))
  942. {
  943. dwRet = RegSetValueEx(hkOld,
  944. szDrive,
  945. NULL,
  946. REG_BINARY,
  947. rgbSig,
  948. cbSig);
  949. VALIDATE_DWRET("::RegSetValueEx");
  950. trace(0, "Copied new driveletter %S to old", szDrive);
  951. }
  952. }
  953. else
  954. {
  955. //
  956. // preserve the old driveletter
  957. //
  958. trace(0, "Preserving old driveletter %S", szDrive);
  959. }
  960. }
  961. else if (szValue[0] == L'#')
  962. {
  963. //
  964. // this is a mountpoint specification
  965. // don't touch these
  966. //
  967. trace(0, "New Mountpoint = %S", szValue);
  968. }
  969. else if (0 == wcsncmp(szValue, L"\\DosDevice", 10))
  970. {
  971. //
  972. // this is a Driveletter -> Signature mapping
  973. // don't touch these
  974. //
  975. trace(0, "New Drive = %S", szValue);
  976. }
  977. else
  978. {
  979. trace(0, "New Unknown = %S", szValue);
  980. }
  981. dwSize = MAX_PATH;
  982. cbSig = sizeof(rgbSig);
  983. }
  984. if (dwRet == ERROR_NO_MORE_ITEMS)
  985. dwRet = ERROR_SUCCESS;
  986. VALIDATE_DWRET("::RegEnumValue");
  987. Exit:
  988. if (hkOld)
  989. RegCloseKey(hkOld);
  990. if (hkNew)
  991. RegCloseKey(hkNew);
  992. TLEAVE();
  993. return dwRet;
  994. }
  995. BOOL DeleteRegKey(HKEY hkOpenKey,
  996. const WCHAR * pszKeyNameToDelete)
  997. {
  998. TraceFunctEnter("DeleteRegKey");
  999. BOOL fRet=FALSE;
  1000. DWORD dwRet;
  1001. // this recursively deletes the key and all its subkeys
  1002. dwRet = SHDeleteKey( hkOpenKey, // handle to open key
  1003. pszKeyNameToDelete); // subkey name
  1004. if (dwRet != ERROR_SUCCESS)
  1005. {
  1006. // key does not exist - this is not an error case.
  1007. DebugTrace(0, "RegDeleteKey of %S failed ec=%d. Not an error.",
  1008. pszKeyNameToDelete, dwRet);
  1009. goto cleanup;
  1010. }
  1011. DebugTrace(0, "RegDeleteKey of %S succeeded", pszKeyNameToDelete);
  1012. fRet = TRUE;
  1013. cleanup:
  1014. TraceFunctLeave();
  1015. return fRet;
  1016. }
  1017. DWORD PersistRegKeys( HKEY hkMountedHive,
  1018. const WCHAR * pszKeyNameInHive,
  1019. HKEY hkOpenKeyInRegistry,
  1020. const WCHAR * pszKeyNameInRegistry,
  1021. const WCHAR * pszKeyBackupFile,
  1022. WCHAR * pszSnapshotPath)
  1023. {
  1024. TraceFunctEnter("PersistRegKeys");
  1025. HKEY hKey=NULL;
  1026. WCHAR szDataFile[MAX_PATH];
  1027. LPCWSTR cszErr;
  1028. DWORD dwRet=ERROR_INTERNAL_ERROR;
  1029. BOOL fKeySaved;
  1030. DWORD dwDisposition;
  1031. // construct the name of the file that stores the backup we will
  1032. // construct the name such that the file will get deleted after
  1033. // the restore.
  1034. wsprintf(szDataFile, L"%s%s\\%s.%s",pszSnapshotPath,SNAPSHOT_DIR_NAME,
  1035. pszKeyBackupFile, s_cszRegHiveCopySuffix);
  1036. DeleteFile(szDataFile); // delete the file if it exists
  1037. // first load the DRM key to a file
  1038. // open the DRM key
  1039. dwRet= RegOpenKeyEx(hkOpenKeyInRegistry, // handle to open key
  1040. pszKeyNameInRegistry, // name of subkey to open
  1041. 0, // reserved
  1042. KEY_READ, // security access mask
  1043. &hKey); // handle to open key
  1044. if (dwRet != ERROR_SUCCESS)
  1045. {
  1046. // key does not exist - this is not an error case.
  1047. DebugTrace(0, "RegOpenKey of %S failed ec=%d", pszKeyNameInRegistry,
  1048. dwRet);
  1049. fKeySaved = FALSE;
  1050. }
  1051. else
  1052. {
  1053. // key exist
  1054. dwRet = RegSaveKey( hKey, // handle to key
  1055. szDataFile, // data file
  1056. NULL); // SD
  1057. if (dwRet != ERROR_SUCCESS)
  1058. {
  1059. // key does not exist - this is not an error case.
  1060. DebugTrace(0, "RegSaveKey of %S failed ec=%d",
  1061. pszKeyNameInRegistry, dwRet);
  1062. fKeySaved = FALSE;
  1063. }
  1064. else
  1065. {
  1066. DebugTrace(0, "Current DRM Key %S saved successfully",
  1067. pszKeyNameInRegistry);
  1068. fKeySaved = TRUE;
  1069. }
  1070. }
  1071. // close the key
  1072. if (hKey)
  1073. {
  1074. RegCloseKey(hKey);
  1075. hKey = NULL;
  1076. }
  1077. // now replace the snapshotted DRM key with the new key
  1078. // first delete the existing key
  1079. DeleteRegKey(hkMountedHive, pszKeyNameInHive);
  1080. // now check to see if the key existing in the old registry in
  1081. // the first place
  1082. if (fKeySaved == FALSE)
  1083. {
  1084. DebugTrace(0, "Current key %S did not exist. Leaving",
  1085. pszKeyNameInRegistry);
  1086. goto Exit;
  1087. }
  1088. // Create the new DRM key
  1089. dwRet = RegCreateKeyEx( hkMountedHive, // handle to open key
  1090. pszKeyNameInHive, // subkey name
  1091. 0, // reserved
  1092. NULL, // class string
  1093. REG_OPTION_NON_VOLATILE, // special options
  1094. KEY_ALL_ACCESS, // desired security access
  1095. NULL, // inheritance
  1096. &hKey, // key handle
  1097. &dwDisposition); // disposition value buffer
  1098. VALIDATE_DWRET("::RegCreateKeyEx");
  1099. _VERIFY(dwDisposition == REG_CREATED_NEW_KEY);
  1100. dwRet= RegRestoreKey( hKey, // handle to key where restore begins
  1101. szDataFile, // registry file
  1102. REG_FORCE_RESTORE|REG_NO_LAZY_FLUSH); // options
  1103. VALIDATE_DWRET("::RegRestoreKey");
  1104. DebugTrace(0, "Successfully kept key %S", pszKeyNameInRegistry);
  1105. dwRet = ERROR_SUCCESS;
  1106. Exit:
  1107. if (hKey)
  1108. RegCloseKey(hKey);
  1109. DeleteFile(szDataFile); // delete the file if it exists
  1110. TraceFunctLeave();
  1111. return dwRet;
  1112. }
  1113. //
  1114. // return the next string in multisz pszBuffer
  1115. // if no string, will return empty
  1116. //
  1117. LPWSTR
  1118. GetNextMszString(LPWSTR pszBuffer)
  1119. {
  1120. return pszBuffer + lstrlen(pszBuffer) + 1;
  1121. }
  1122. //
  1123. // read regvalue pszString in current registry,
  1124. // and replace it in the old registry
  1125. //
  1126. DWORD
  1127. ValueReplace(HKEY hkOldSystem, LPWSTR pszOldString, HKEY hkNewSystem, LPWSTR pszNewString)
  1128. {
  1129. tenter("ValueReplace");
  1130. WCHAR szBuffer[MAX_PATH];
  1131. BYTE *pData = NULL;
  1132. DWORD dwType, dwSize, dwRet = ERROR_SUCCESS;
  1133. LPWSTR pszValue = NULL;
  1134. LPCWSTR cszErr;
  1135. // split up the key and value in pszNewString
  1136. lstrcpy(szBuffer, pszNewString);
  1137. pszValue = wcsrchr(szBuffer, L'\\');
  1138. if (! pszValue)
  1139. {
  1140. trace(0, "No value in %S", pszNewString);
  1141. goto Exit;
  1142. }
  1143. *pszValue=L'\0';
  1144. pszValue++;
  1145. trace(0, "New Key=%S, Value=%S", szBuffer, pszValue);
  1146. // get the value size
  1147. dwRet = SHGetValue(hkNewSystem, szBuffer, pszValue, &dwType, NULL, &dwSize);
  1148. VALIDATE_DWRET("SHGetValue");
  1149. pData = (BYTE *) SRMemAlloc(dwSize);
  1150. if (! pData)
  1151. {
  1152. trace(0, "! SRMemAlloc");
  1153. dwRet = ERROR_OUTOFMEMORY;
  1154. goto Exit;
  1155. }
  1156. // get the value
  1157. dwRet = SHGetValue(hkNewSystem, szBuffer, pszValue, &dwType, pData, &dwSize);
  1158. VALIDATE_DWRET("SHGetValue");
  1159. // split up the key and value in pszOldString
  1160. lstrcpy(szBuffer, pszOldString);
  1161. pszValue = wcsrchr(szBuffer, L'\\');
  1162. if (! pszValue)
  1163. {
  1164. trace(0, "No value in %S", pszOldString);
  1165. goto Exit;
  1166. }
  1167. *pszValue=L'\0';
  1168. pszValue++;
  1169. trace(0, "Old Key=%S, Value=%S", szBuffer, pszValue);
  1170. // set the value in the old registry
  1171. SHSetValue(hkOldSystem, szBuffer, pszValue, dwType, pData, dwSize);
  1172. VALIDATE_DWRET("SHGetValue");
  1173. Exit:
  1174. if (pData)
  1175. {
  1176. SRMemFree(pData);
  1177. }
  1178. tleave();
  1179. return dwRet;
  1180. }
  1181. //
  1182. // list of keys in KeysNotToRestore that we should ignore
  1183. //
  1184. LPWSTR g_rgKeysToRestore[] = {
  1185. L"Installed Services",
  1186. L"Mount Manager",
  1187. L"Pending Rename Operations",
  1188. L"Session Manager",
  1189. L"Plug & Play"
  1190. };
  1191. int g_nKeysToRestore = 5;
  1192. //
  1193. // check if pszKey is to be preserved or restored
  1194. //
  1195. BOOL
  1196. IsKeyToBeRestored(LPWSTR pszKey)
  1197. {
  1198. for (int i=0; i < g_nKeysToRestore; i++)
  1199. {
  1200. if (lstrcmpi(g_rgKeysToRestore[i], pszKey) == 0)
  1201. return TRUE;
  1202. }
  1203. return FALSE;
  1204. }
  1205. //
  1206. // copy the keys listed in System\CurrentControlSet\Control\BackupRestore\KeysNotToRestore
  1207. // from the current registry to the old registry
  1208. // -- with some exceptions
  1209. //
  1210. DWORD
  1211. PreserveKeysNotToRestore(HKEY hkOldSystem, LPWSTR pszSnapshotPath)
  1212. {
  1213. HKEY hkNewSystem = NULL;
  1214. DWORD dwIndex = 0;
  1215. WCHAR szName[MAX_PATH], szKey[MAX_PATH];
  1216. BYTE *pMszString = NULL;
  1217. DWORD dwSize, dwType, cbValue;
  1218. DWORD dwRet = ERROR_SUCCESS;
  1219. LPCWSTR cszErr;
  1220. HKEY hkKNTR = NULL;
  1221. TENTER("PreserveKeysNotToRestore");
  1222. //
  1223. // open the new system hive
  1224. //
  1225. dwRet = ::RegOpenKeyEx( HKEY_LOCAL_MACHINE, L"System", 0, KEY_ALL_ACCESS, &hkNewSystem );
  1226. VALIDATE_DWRET("::RegOpenKey");
  1227. //
  1228. // enumerate KeysNotToRestore
  1229. //
  1230. dwRet = ::RegOpenKeyEx( hkNewSystem,
  1231. L"CurrentControlSet\\Control\\BackupRestore\\KeysNotToRestore",
  1232. 0, KEY_READ,
  1233. &hkKNTR );
  1234. VALIDATE_DWRET("::RegOpenKey");
  1235. dwSize = MAX_PATH;
  1236. cbValue = 0;
  1237. while (ERROR_SUCCESS ==
  1238. (dwRet = RegEnumValue(hkKNTR,
  1239. dwIndex++,
  1240. szName,
  1241. &dwSize,
  1242. NULL,
  1243. &dwType,
  1244. NULL,
  1245. &cbValue )))
  1246. {
  1247. trace(0, "Name=%S", szName);
  1248. if (FALSE == IsKeyToBeRestored(szName))
  1249. {
  1250. //
  1251. // should preserve all the keys specified in this multisz value
  1252. //
  1253. LPWSTR pszString = NULL;
  1254. pMszString = (BYTE *) SRMemAlloc(cbValue);
  1255. if (NULL == pMszString)
  1256. {
  1257. trace(0, "! SRMemAlloc");
  1258. dwRet = ERROR_OUTOFMEMORY;
  1259. goto Exit;
  1260. }
  1261. // read the multisz string
  1262. dwRet = RegQueryValueEx(hkKNTR,
  1263. szName,
  1264. NULL,
  1265. &dwType,
  1266. pMszString,
  1267. &cbValue);
  1268. VALIDATE_DWRET("RegQueryValueEx");
  1269. // process each element in the multisz string
  1270. pszString = (LPWSTR) pMszString;
  1271. do
  1272. {
  1273. // stop on null or empty string
  1274. if (! pszString || ! *pszString)
  1275. break;
  1276. trace(0, "Key = %S", pszString);
  1277. // replace based on the last character of each key
  1278. // if '\', then the whole key and subkeys are to be replaced in the old registry
  1279. // if '*', it should be merged with the old -- we don't support this and will ignore
  1280. // otherwise, it is a value to be replaced
  1281. switch (pszString[lstrlen(pszString)-1])
  1282. {
  1283. case L'*' :
  1284. trace(0, "Merge key - ignoring");
  1285. break;
  1286. case L'\\':
  1287. trace(0, "Replacing key");
  1288. lstrcpy(szKey, pszString);
  1289. szKey[lstrlen(szKey)-1]=L'\0';
  1290. ChangeCCS(hkOldSystem, szKey);
  1291. PersistRegKeys(hkOldSystem, // mounted hive
  1292. szKey, // key name in hive
  1293. hkNewSystem, // open key in registry
  1294. pszString, // key name in registry
  1295. s_cszDRMKeyBackupFile, // name of backup file
  1296. pszSnapshotPath); // snapshot path
  1297. break;
  1298. default:
  1299. trace(0, "Replacing value");
  1300. lstrcpy(szKey, pszString);
  1301. ChangeCCS(hkOldSystem, szKey);
  1302. ValueReplace(hkOldSystem, szKey, hkNewSystem, pszString);
  1303. break;
  1304. }
  1305. } while (pszString = GetNextMszString(pszString));
  1306. SRMemFree(pMszString);
  1307. pMszString = NULL;
  1308. }
  1309. dwSize = MAX_PATH;
  1310. cbValue = 0;
  1311. }
  1312. Exit:
  1313. if (hkNewSystem)
  1314. RegCloseKey(hkNewSystem);
  1315. if (pMszString)
  1316. {
  1317. SRMemFree(pMszString);
  1318. }
  1319. if (hkKNTR)
  1320. {
  1321. RegCloseKey(hkKNTR);
  1322. }
  1323. TLEAVE();
  1324. return dwRet;
  1325. }
  1326. DWORD
  1327. RestorePendingRenames(LPWSTR pwcBuffer, LPWSTR pszSSPath)
  1328. {
  1329. TraceFunctEnter("RestorePendingRenames");
  1330. WCHAR szSrc[MAX_PATH];
  1331. DWORD dwRc = ERROR_SUCCESS;
  1332. int iFirst = 0;
  1333. int iSecond = 0;
  1334. int iFile = 1;
  1335. while (pwcBuffer[iFirst] != L'\0')
  1336. {
  1337. iSecond = iFirst + lstrlenW(&pwcBuffer[iFirst]) + 1;
  1338. DebugTrace(0, "Src : %S, Dest : %S", &pwcBuffer[iFirst], &pwcBuffer[iSecond]);
  1339. if (pwcBuffer[iSecond] != L'\0')
  1340. {
  1341. // restore the snapshot file MFEX-i.DAT in the snapshot dir
  1342. // to the source file
  1343. wsprintf(szSrc, L"%s%s\\MFEX-%d.DAT", pszSSPath, SNAPSHOT_DIR_NAME, iFile++);
  1344. DebugTrace(0, "%S -> %S", szSrc, &pwcBuffer[iFirst+4]);
  1345. SRCopyFile(szSrc, &pwcBuffer[iFirst+4]);
  1346. }
  1347. iFirst = iSecond + lstrlenW(&pwcBuffer[iSecond]) + 1;
  1348. }
  1349. TraceFunctLeave();
  1350. return dwRc;
  1351. }
  1352. static DWORD
  1353. HandleSoftwareHive( LPCWSTR cszDat, WCHAR * pszSnapshotPath )
  1354. {
  1355. TraceFunctEnter("HandleSoftwareHive");
  1356. DWORD dwRet,dwSafeMode;
  1357. LPCWSTR cszErr;
  1358. BOOL fRegLoaded = FALSE;
  1359. HKEY hkMount = NULL; // HKEY of temporary mount point of registry file
  1360. WCHAR szUIPath[MAX_PATH]=L"";
  1361. // 1. Load registry-to-be-restored temporarily.
  1362. dwRet = ::RegLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, cszDat );
  1363. VALIDATE_DWRET("::RegLoadKey");
  1364. fRegLoaded = TRUE;
  1365. dwRet = ::RegOpenKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, &hkMount );
  1366. VALIDATE_DWRET("::RegOpenKey");
  1367. // 2.1 Set RunOnce key for result page.
  1368. ::ExpandEnvironmentStrings( s_cszRestoreUIPath, szUIPath, MAX_PATH );
  1369. ::lstrcat( szUIPath, s_cszRunOnceOptNormal );
  1370. if ( !::SRSetRegStr( hkMount, s_cszRegLMSWRunOnce, s_cszRunOnceValueName, szUIPath ) )
  1371. goto Exit;
  1372. #if 0
  1373. // 2.2 Set SfcScan key to initiate WFP scanning after the restore.
  1374. if ( !::SRSetRegDword( hkMount, s_cszRegLMSWWinLogon, s_cszRegValSfcScan, 2 ) )
  1375. goto Exit;
  1376. #endif
  1377. // 2.3 Set RestoreStatus value to 1 to denote restore success
  1378. // test tools can use this when invoking silent restores to check success
  1379. if ( !::SRSetRegDword( hkMount, s_cszRegSystemRestore, s_cszRestoreStatus, 1 ) )
  1380. {
  1381. // ignore the error since this is not a fatal error
  1382. ErrorTrace(0,"SRSetRegDword failed.ec=%d", GetLastError());
  1383. }
  1384. // Write in the registry whether we are doing a restore from safe mode.
  1385. if (0 != GetSystemMetrics(SM_CLEANBOOT))
  1386. {
  1387. TRACE(0, "Restore from safemode");
  1388. dwSafeMode=1;
  1389. }
  1390. else
  1391. {
  1392. dwSafeMode=0;
  1393. }
  1394. // now write in the new registry about the status
  1395. if ( !::SRSetRegDword( hkMount, s_cszRegSystemRestore, s_cszRestoreSafeModeStatus, dwSafeMode ) )
  1396. {
  1397. // ignore the error since this is not a fatal error
  1398. ErrorTrace(0,"SRSetRegDword of safe mode status failed.ec=%d",
  1399. GetLastError());
  1400. }
  1401. // 3. also set the new DRM keys
  1402. {
  1403. WCHAR szDRMKeyNameInHive[MAX_PATH];
  1404. // ignore the error code since this is not a fatal error
  1405. wsprintf(szDRMKeyNameInHive, L"Classes\\%s",s_cszDRMKey1);
  1406. PersistRegKeys(hkMount, // mounted hive
  1407. szDRMKeyNameInHive, // key name in hive
  1408. HKEY_CLASSES_ROOT, // open key in registry
  1409. s_cszDRMKey1, // key name in registry
  1410. s_cszDRMKeyBackupFile, // name of backup file
  1411. pszSnapshotPath); // snapshot path
  1412. wsprintf(szDRMKeyNameInHive, L"Classes\\%s",s_cszDRMKey2);
  1413. PersistRegKeys(hkMount, // mounted hive
  1414. szDRMKeyNameInHive, // key name in hive
  1415. HKEY_CLASSES_ROOT, // open key in registry
  1416. s_cszDRMKey2, // key name in registry
  1417. s_cszDRMKeyBackupFile, // name of backup file
  1418. pszSnapshotPath); // snapshot path
  1419. }
  1420. // also ignore the Remote assistance reg key
  1421. {
  1422. WCHAR szRAKeyInRegistry[MAX_PATH];
  1423. wsprintf(szRAKeyInRegistry, L"%s\\%s",s_cszSoftwareHiveName,
  1424. s_cszRemoteAssistanceKey);
  1425. PersistRegKeys(hkMount, // mounted hive
  1426. s_cszRemoteAssistanceKey, // key name in hive
  1427. HKEY_LOCAL_MACHINE, // open key in registry
  1428. szRAKeyInRegistry, // key name in registry
  1429. s_cszDRMKeyBackupFile, // name of backup file
  1430. pszSnapshotPath); // snapshot path
  1431. }
  1432. // also ignore the Password Hints key
  1433. {
  1434. WCHAR szHintKeyInRegistry[MAX_PATH];
  1435. wsprintf(szHintKeyInRegistry, L"%s\\%s",s_cszSoftwareHiveName,
  1436. s_cszPasswordHints);
  1437. PersistRegKeys(hkMount, // mounted hive
  1438. s_cszPasswordHints, // key name in hive
  1439. HKEY_LOCAL_MACHINE, // open key in registry
  1440. szHintKeyInRegistry, // key name in registry
  1441. s_cszDRMKeyBackupFile, // name of backup file
  1442. pszSnapshotPath); // snapshot path
  1443. }
  1444. // also ignore the IE Content Advisor key
  1445. {
  1446. WCHAR szContentAdvisorKeyInRegistry[MAX_PATH];
  1447. wsprintf(szContentAdvisorKeyInRegistry, L"%s\\%s",
  1448. s_cszSoftwareHiveName,
  1449. s_cszContentAdvisor);
  1450. PersistRegKeys(hkMount, // mounted hive
  1451. s_cszContentAdvisor, // key name in hive
  1452. HKEY_LOCAL_MACHINE, // open key in registry
  1453. szContentAdvisorKeyInRegistry,// key name in registry
  1454. s_cszDRMKeyBackupFile, // name of backup file
  1455. pszSnapshotPath); // snapshot path
  1456. }
  1457. // 4. Save the LSA secrets
  1458. GetLsaRestoreState (hkMount);
  1459. Exit:
  1460. if ( hkMount != NULL )
  1461. (void)::RegCloseKey( hkMount );
  1462. if ( fRegLoaded )
  1463. (void)::RegUnLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp );
  1464. TraceFunctLeave();
  1465. return( dwRet );
  1466. }
  1467. static DWORD
  1468. HandleSystemHive( LPCWSTR cszDat, LPWSTR pszSSPath )
  1469. {
  1470. TraceFunctEnter("HandleSystemHive");
  1471. DWORD dwRet;
  1472. LPCWSTR cszErr;
  1473. WCHAR szWPAKeyNameInHive[MAX_PATH];
  1474. BOOL fRegLoaded = FALSE;
  1475. HKEY hkMount = NULL; // HKEY of temporary mount point of registry file
  1476. LPWSTR szRestoreMFE = NULL, szOldMFE = NULL;
  1477. BYTE * pszData = NULL, *pNewPos = NULL;
  1478. DWORD cbData1=0, cbData2=0, cbData=0;
  1479. DWORD dwCurrent = 1;
  1480. WCHAR szSessionManager[MAX_PATH];
  1481. // 1. Load registry-to-be-restored temporarily.
  1482. dwRet = ::RegLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, cszDat );
  1483. VALIDATE_DWRET("::RegLoadKey");
  1484. fRegLoaded = TRUE;
  1485. dwRet = ::RegOpenKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp, &hkMount );
  1486. VALIDATE_DWRET("::RegOpenKey");
  1487. // get the session manager regkey
  1488. lstrcpy(szSessionManager, s_cszRegLMSYSSessionMan);
  1489. ChangeCCS(hkMount, szSessionManager);
  1490. //persist WPA registry keys
  1491. wsprintf(szWPAKeyNameInHive, L"%s", s_cszWPAKeyRelative);
  1492. PersistRegKeys( hkMount,// mounted hive
  1493. szWPAKeyNameInHive,// key name in hive
  1494. HKEY_LOCAL_MACHINE,// open key in registry
  1495. s_cszWPAKey,// key name in registry
  1496. s_cszDRMKeyBackupFile,// name of backup file
  1497. pszSSPath); // snapshot path
  1498. //
  1499. // process KeysNotToRestore key
  1500. // and transfer listed keys to old system hive
  1501. //
  1502. PreserveKeysNotToRestore(hkMount, pszSSPath);
  1503. // process movefileex entries from old registry
  1504. szOldMFE = ::SRGetRegMultiSz( hkMount, szSessionManager, SRREG_VAL_MOVEFILEEX, &cbData1 );
  1505. if (szOldMFE != NULL)
  1506. {
  1507. dwRet = RestorePendingRenames(szOldMFE, pszSSPath);
  1508. VALIDATE_DWRET("RestorePendingRenames");
  1509. }
  1510. // copy restore's movefileex entries
  1511. //
  1512. // skip entries that were already there before restore began
  1513. //
  1514. szRestoreMFE = ::SRGetRegMultiSz( HKEY_LOCAL_MACHINE, SRREG_PATH_SESSIONMGR, SRREG_VAL_MOVEFILEEX, &cbData2 );
  1515. if ( cbData2 > g_dwExistingMFEXMarker && szRestoreMFE != NULL )
  1516. {
  1517. trace(0, "Restore MFE entries exist");
  1518. if (g_dwExistingMFEXMarker > 0)
  1519. {
  1520. szRestoreMFE = (LPWSTR) ((BYTE *) szRestoreMFE + g_dwExistingMFEXMarker - sizeof(WCHAR));
  1521. cbData2 -= g_dwExistingMFEXMarker - sizeof(WCHAR);
  1522. }
  1523. DebugTrace(0, "RestoreMFE:%S, cbData2:%ld", szRestoreMFE, cbData2);
  1524. // allocate memory for old and new entries
  1525. pszData = (BYTE *) malloc(cbData1 + cbData2);
  1526. if (! pszData)
  1527. {
  1528. ErrorTrace(0, "! malloc");
  1529. dwRet = ERROR_OUTOFMEMORY;
  1530. goto Exit;
  1531. }
  1532. // append old entries AFTER restore's entries
  1533. cbData = 0;
  1534. if (szRestoreMFE != NULL)
  1535. {
  1536. memcpy(pszData, szRestoreMFE, cbData2);
  1537. // truncate last '\0' if more to append
  1538. if (szOldMFE != NULL)
  1539. {
  1540. cbData = cbData2 - sizeof(WCHAR);
  1541. pNewPos = pszData + cbData;
  1542. }
  1543. else
  1544. {
  1545. cbData = cbData2;
  1546. pNewPos = pszData;
  1547. }
  1548. }
  1549. if (szOldMFE != NULL)
  1550. {
  1551. memcpy(pNewPos, szOldMFE, cbData1);
  1552. cbData += cbData1;
  1553. }
  1554. if ( !::SRSetRegMultiSz( hkMount, szSessionManager, SRREG_VAL_MOVEFILEEX, (LPWSTR) pszData, cbData ) )
  1555. {
  1556. ErrorTrace(0, "! SRSetRegMultiSz");
  1557. goto Exit;
  1558. }
  1559. free(pszData);
  1560. // Set AllowProtectedRenames key for MoveFileEx.
  1561. if ( !::SRSetRegDword( hkMount, szSessionManager, s_cszRegValAllowProtectedRenames, 1 ) )
  1562. goto Exit;
  1563. }
  1564. // get the timezone regkey
  1565. lstrcpy(szSessionManager, s_cszTZKeyInHive);
  1566. ChangeCCS(hkMount, szSessionManager);
  1567. //
  1568. // transfer timezone information from new registry to old registry
  1569. // ie. don't restore timezone, since we can't restore time
  1570. //
  1571. PersistRegKeys( hkMount,
  1572. szSessionManager,
  1573. HKEY_LOCAL_MACHINE,
  1574. s_cszTZKeyInRegistry,
  1575. s_cszDRMKeyBackupFile,
  1576. pszSSPath);
  1577. //
  1578. // use the currently existing mounted devices info
  1579. // i.e. all current volumes will be put back into the old registry
  1580. // however for volumes that existed in the old registry,
  1581. // the driveletter mapping from the old registry will be used
  1582. //
  1583. // dwRet = KeepMountedDevices(hkMount);
  1584. // VALIDATE_DWRET("KeepMountedDevices");
  1585. // Register password filter DLL to set old->new passwords
  1586. dwRet = RegisterNotificationDLL (hkMount, TRUE);
  1587. VALIDATE_DWRET("RegisterNotificationDLL");
  1588. Exit:
  1589. if ( szRestoreMFE != NULL )
  1590. delete [] szRestoreMFE;
  1591. if ( szOldMFE != NULL )
  1592. delete [] szOldMFE;
  1593. if ( hkMount != NULL )
  1594. (void)::RegCloseKey( hkMount );
  1595. if ( fRegLoaded )
  1596. (void)::RegUnLoadKey( HKEY_LOCAL_MACHINE, s_cszRegHiveTmp );
  1597. TraceFunctLeave();
  1598. return( dwRet );
  1599. }
  1600. DWORD
  1601. CRestoreOperationManager::T2HandleSnapshot( CSnapshot & cSS, WCHAR * szSSPath )
  1602. {
  1603. TraceFunctEnter("CRestoreOperationManager::T2HandleSnapshot");
  1604. DWORD dwRet;
  1605. LPCWSTR cszErr;
  1606. WCHAR szRegHive[MAX_PATH];
  1607. WCHAR szCatTSPath[MAX_PATH]; // Full path of CatRoot\TimeStamp
  1608. // 1. Initialize Snapshot Handling Module. ( already done by caller )
  1609. // 2. Manipulate HKLM\SOFTWARE Hive.
  1610. dwRet = cSS.GetSoftwareHivePath( szSSPath, szRegHive, MAX_PATH );
  1611. VALIDATE_DWRET("CSnapshot::GetSoftwareHivePath");
  1612. LogDSFileTrace(0,L"SWHive: ", szRegHive);
  1613. dwRet = ::HandleSoftwareHive( szRegHive, szSSPath);
  1614. if ( dwRet != ERROR_SUCCESS )
  1615. goto Exit;
  1616. // 3. Manipulate HKLM\SYSTEM Hive.
  1617. dwRet = cSS.GetSystemHivePath( szSSPath, szRegHive, MAX_PATH );
  1618. VALIDATE_DWRET("CSnapshot::GetSystemHivePath");
  1619. LogDSFileTrace(0,L"SysHive: ", szRegHive);
  1620. dwRet = ::HandleSystemHive( szRegHive, szSSPath );
  1621. if ( dwRet != ERROR_SUCCESS )
  1622. goto Exit;
  1623. // 3.5 Manipulate the HKLM\SAM Hive.
  1624. dwRet = cSS.GetSamHivePath ( szSSPath, szRegHive, MAX_PATH );
  1625. VALIDATE_DWRET("CSnapshot::GetSamHivePath");
  1626. LogDSFileTrace(0,L"SamHive: ", szRegHive);
  1627. dwRet = RestoreRIDs ( szRegHive );
  1628. if (dwRet != ERROR_SUCCESS)
  1629. goto Exit;
  1630. // 4. Restore the Snapshot.
  1631. dwRet = cSS.RestoreSnapshot( szSSPath );
  1632. //VALIDATE_DWRET("CSnapshot::RestoreSnapshot");
  1633. // 5. Cleanup Snapshot Handling Module.
  1634. //dwRet = ::CleanupAfterRestore( szSSPath );
  1635. //VALIDATE_DWRET("CSnapshot::CleanupAfterRestore");
  1636. // 6. Delete timestamp file for WFP
  1637. if (m_fRebuildCatalogDb == TRUE)
  1638. {
  1639. (void)::ExpandEnvironmentStrings( s_cszCatTimeStamp, szCatTSPath, MAX_PATH );
  1640. if ( !::DeleteFile( szCatTSPath ) )
  1641. {
  1642. cszErr = ::GetSysErrStr();
  1643. DebugTrace(0, "::DeleteFile(timestamp) failed - %ls", cszErr);
  1644. // ignore error...
  1645. }
  1646. }
  1647. Exit:
  1648. TraceFunctLeave();
  1649. return( dwRet );
  1650. }
  1651. /////////////////////////////////////////////////////////////////////////////
  1652. DWORD
  1653. CRestoreOperationManager::T2CleanUp()
  1654. {
  1655. TraceFunctEnter("CRestoreOperationManager::T2CleanUp");
  1656. int i;
  1657. for ( i = m_aryDrv.GetUpperBound(); i >= 0; i-- )
  1658. m_paryEnt[i].ReleaseAll();
  1659. delete [] m_paryEnt;
  1660. m_aryDrv.DeleteAll();
  1661. TraceFunctLeave();
  1662. return( ERROR_SUCCESS );
  1663. }
  1664. DWORD
  1665. WriteFifoLog(LPWSTR pszLog, LPWSTR pwszDir, LPWSTR pwszDrive)
  1666. {
  1667. FILE *f = NULL;
  1668. WCHAR szLog[MAX_PATH];
  1669. DWORD dwRc = ERROR_INTERNAL_ERROR;
  1670. WCHAR wszTime[MAX_PATH] = L"";
  1671. WCHAR wszDate[MAX_PATH] = L"";
  1672. CDataStore *pds = NULL;
  1673. TENTER("WriteFifoLog");
  1674. TRACE(0, "Fifoed %S on drive %S", pwszDir, pwszDrive);
  1675. f = (FILE *) _wfopen(szLog, L"a");
  1676. if (f)
  1677. {
  1678. _wstrdate(wszDate);
  1679. _wstrtime(wszTime);
  1680. fwprintf(f, L"%s-%s : Fifoed %s on drive %s\n", wszDate, wszTime, pwszDir, pwszDrive);
  1681. fclose(f);
  1682. dwRc = ERROR_SUCCESS;
  1683. }
  1684. else
  1685. {
  1686. TRACE(0, "_wfopen failed on %s", szLog);
  1687. }
  1688. TLEAVE();
  1689. return dwRc;
  1690. }
  1691. /////////////////////////////////////////////////////////////////////////////
  1692. DWORD
  1693. CRestoreOperationManager::T2Fifo( int nDrv, DWORD dwRpNum )
  1694. {
  1695. TraceFunctEnter("CRestoreOperationManager::T2Fifo");
  1696. DWORD dwErr = ERROR_SUCCESS;
  1697. CDriveTable dt;
  1698. CDataStore *pds = NULL;
  1699. BOOL fFifoed = FALSE;
  1700. DWORD dwLastFifoedRp;
  1701. WCHAR szFifoedRpPath[MAX_PATH];
  1702. CDataStore *pdsLead = NULL, *pdsSys = NULL;
  1703. BOOL fFirstIteration;
  1704. SDriveTableEnumContext dtec = {NULL, 0};
  1705. WCHAR szPath[MAX_PATH], szSys[MAX_PATH];
  1706. WCHAR szFifoedPath[MAX_PATH], szRpPath[MAX_PATH];
  1707. DWORD dwTargetRPNum = 0;
  1708. WCHAR szLog[MAX_PATH];
  1709. ::GetSystemDrive(szSys);
  1710. MakeRestorePath(szPath, szSys, s_cszDriveTable);
  1711. CHECKERR(dt.LoadDriveTable(szPath), L"LoadDriveTable");
  1712. pdsSys = dt.FindSystemDrive();
  1713. if (pdsSys == NULL)
  1714. {
  1715. TRACE(0, "! FindSystemDrive");
  1716. goto Err;
  1717. }
  1718. MakeRestorePath(szLog, pdsSys->GetDrive(), s_cszFifoLog);
  1719. pdsLead = NULL;
  1720. fFirstIteration = TRUE;
  1721. pds = dt.FindDriveInTable((LPWSTR) m_aryDrv[nDrv]->GetID());
  1722. while (pds)
  1723. {
  1724. fFifoed = FALSE;
  1725. //
  1726. // skip the drive we fifoed first
  1727. //
  1728. if (pds != pdsLead)
  1729. {
  1730. //
  1731. // enum forward, don't skip last
  1732. //
  1733. CRestorePointEnum rpe( pds->GetDrive(), TRUE, FALSE );
  1734. CRestorePoint rp;
  1735. //
  1736. // blow away any obsolete "Fifoed" directories
  1737. //
  1738. MakeRestorePath(szFifoedRpPath, pds->GetDrive(), s_cszFifoedRpDir);
  1739. CHECKERR( Delnode_Recurse(szFifoedRpPath, TRUE, NULL),
  1740. "Delnode_Recurse");
  1741. //
  1742. // blow away any obsolete "RP0" directories
  1743. //
  1744. MakeRestorePath(szFifoedRpPath, pds->GetDrive(), L"RP0");
  1745. CHECKERR( Delnode_Recurse(szFifoedRpPath, TRUE, NULL),
  1746. "Delnode_Recurse");
  1747. //
  1748. // loop through restore points on this drive
  1749. //
  1750. dwErr = rpe.FindFirstRestorePoint (rp);
  1751. //
  1752. // enumeration can return ERROR_FILE_NOT_FOUND for restorepoints
  1753. // that are missing rp.log
  1754. // we will just continue in this case
  1755. //
  1756. while (dwErr == ERROR_SUCCESS || dwErr == ERROR_FILE_NOT_FOUND)
  1757. {
  1758. //
  1759. // check if we've reached the target RP num
  1760. //
  1761. if (dwTargetRPNum)
  1762. {
  1763. if (rp.GetNum() > dwTargetRPNum)
  1764. {
  1765. TRACE(0, "Target restore point reached");
  1766. break;
  1767. }
  1768. }
  1769. //
  1770. // check if we've reached the selected rp
  1771. //
  1772. if (rp.GetNum() >= dwRpNum)
  1773. {
  1774. //
  1775. // don't fifo current rp
  1776. //
  1777. trace(0, "No more rps to fifo");
  1778. break;
  1779. }
  1780. //
  1781. // throw away this restore point on this drive
  1782. //
  1783. // move the rp dir to a temp dir "Fifoed"
  1784. // this is to make the fifo of a single rp atomic
  1785. // to take care of unclean shutdowns
  1786. MakeRestorePath(szRpPath, pds->GetDrive(), rp.GetDir());
  1787. MakeRestorePath(szFifoedPath, pds->GetDrive(), s_cszFifoedRpDir);
  1788. if (! MoveFile(szRpPath, szFifoedPath))
  1789. {
  1790. dwErr = GetLastError();
  1791. TRACE(0, "! MoveFile from %S to %S : %ld", szRpPath, szFifoedPath, dwErr);
  1792. goto Err;
  1793. }
  1794. // blow away the temp fifoed directory
  1795. CHECKERR(Delnode_Recurse(szFifoedPath, TRUE, NULL),
  1796. L"Delnode_Recurse");
  1797. dwLastFifoedRp = rp.GetNum();
  1798. fFifoed = TRUE;
  1799. //
  1800. // write to the fifo log
  1801. //
  1802. WriteFifoLog(szLog, rp.GetDir(), pds->GetDrive());
  1803. dwErr = rpe.FindNextRestorePoint(rp);
  1804. }
  1805. }
  1806. //
  1807. // go to next drive
  1808. //
  1809. if (fFirstIteration)
  1810. {
  1811. if (! fFifoed) // we did not fifo anything
  1812. {
  1813. break;
  1814. }
  1815. pdsLead = pds;
  1816. pds = dt.FindFirstDrive(dtec);
  1817. fFirstIteration = FALSE;
  1818. dwTargetRPNum = dwLastFifoedRp; // fifo till what we fifoed just now
  1819. }
  1820. else
  1821. {
  1822. pds = dt.FindNextDrive(dtec);
  1823. }
  1824. }
  1825. dwErr = ERROR_SUCCESS;
  1826. Err:
  1827. TraceFunctLeave();
  1828. return( dwErr );
  1829. }
  1830. DWORD DeleteAllChangeLogs(WCHAR * pszRestorePointPath)
  1831. {
  1832. TraceFunctEnter("DeleteAllFilesBySuffix");
  1833. DWORD dwErr, dwReturn=ERROR_INTERNAL_ERROR;
  1834. WCHAR szFindFileData[MAX_PATH];
  1835. // first construct the prefix of the file that stores the HKLM registry
  1836. // snapshot.
  1837. wsprintf(szFindFileData, L"%s\\%s*", pszRestorePointPath,
  1838. s_cszCurrentChangeLog);
  1839. dwErr = ProcessGivenFiles(pszRestorePointPath, DeleteGivenFile,
  1840. szFindFileData);
  1841. if (ERROR_SUCCESS != dwErr)
  1842. {
  1843. ErrorTrace(0, "Deleting files failed error %ld", dwErr);
  1844. dwReturn = dwErr;
  1845. goto cleanup;
  1846. }
  1847. dwReturn = ERROR_SUCCESS;
  1848. cleanup:
  1849. TraceFunctLeave();
  1850. return dwReturn;
  1851. }
  1852. /////////////////////////////////////////////////////////////////////////////
  1853. // Starting from the new "Restore" type restore point, enumerate
  1854. // change log entries and undo them. The order should be reverse (from
  1855. // the latest operation to the earliest operation.)
  1856. DWORD
  1857. CRestoreOperationManager::T2UndoForFail()
  1858. {
  1859. TraceFunctEnter("CRestoreOperationManager::T2UndoForFail");
  1860. DWORD dwRet = ERROR_INTERNAL_ERROR;
  1861. LPCWSTR cszErr;
  1862. HANDLE hFilter = NULL;
  1863. WCHAR szDrv[MAX_PATH];
  1864. WCHAR szRestorePointPath[MAX_PATH];
  1865. WCHAR szDSPath[MAX_PATH];
  1866. int i;
  1867. // Cleanup m_aryEnt to free up as much memory as possible and prepare
  1868. // to get the list of operations to be undone.
  1869. for ( i = m_aryDrv.GetUpperBound(); i >= 0; i-- )
  1870. m_paryEnt[i].ReleaseAll();
  1871. m_pLogFile->WriteMarker( RSTRLOGID_STARTUNDO, 0 );
  1872. // Stop filter from monitoring
  1873. dwRet = ::SrCreateControlHandle( SR_OPTION_OVERLAPPED, &hFilter );
  1874. if ( dwRet != ERROR_SUCCESS )
  1875. {
  1876. ErrorTrace(0, "::SrCreateControlHandle failed - %d", dwRet);
  1877. //One reason this can happen is if the SR service is still running.
  1878. // Stop the service and try again
  1879. if (IsSRServiceRunning() )
  1880. {
  1881. StopSRService(TRUE); // wait until service is stopped
  1882. dwRet = ::SrCreateControlHandle( SR_OPTION_OVERLAPPED, &hFilter );
  1883. if ( dwRet != ERROR_SUCCESS )
  1884. {
  1885. ErrorTrace(0, "::SrCreateControlHandle failed again - %d",
  1886. dwRet);
  1887. }
  1888. }
  1889. if ( dwRet != ERROR_SUCCESS )
  1890. {
  1891. //ISSUE - should I abort or continue???
  1892. goto Exit;
  1893. }
  1894. }
  1895. dwRet = ::SrStopMonitoring( hFilter );
  1896. if ( dwRet != ERROR_SUCCESS )
  1897. {
  1898. ErrorTrace(0, "::SrStopMonitoring failed - %ls", ::GetSysErrStr(dwRet));
  1899. //ISSUE - should I abort or continue???
  1900. goto Exit;
  1901. }
  1902. // Get change log entries to be undone
  1903. for ( i = 0; i < m_aryDrv.GetSize(); i++ )
  1904. {
  1905. if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsFrozen() || m_aryDrv[i]->IsExcluded() )
  1906. continue;
  1907. // use the volume guid for each volume
  1908. // we cannot use mountpoint paths because
  1909. // restore might delete mount points before
  1910. // the operations on that volume are restored
  1911. ::lstrcpy( szDrv, m_aryDrv[i]->GetID() );
  1912. //cszDrv = m_aryDrv[i]->GetMount();
  1913. ::MakeRestorePath( szDSPath, szDrv, NULL );
  1914. DebugTrace(0, "Drive #%d: Drv='%ls', DS='%ls'", i, szDrv, szDSPath);
  1915. CChangeLogEntryEnum cEnum( szDrv, 0, m_dwRPNew, TRUE );
  1916. CChangeLogEntry cCLE;
  1917. dwRet = cEnum.FindFirstChangeLogEntry( cCLE );
  1918. if ( dwRet == ERROR_NO_MORE_ITEMS )
  1919. goto EndOfChgLog;
  1920. if ( dwRet != ERROR_SUCCESS )
  1921. {
  1922. cszErr = ::GetSysErrStr( dwRet );
  1923. ErrorTrace(0, "FindFirstChangeLogEntry failed - %ls", cszErr);
  1924. // even in case of error, try to revert as many operations as possible...
  1925. goto EndOfChgLog;
  1926. }
  1927. while ( dwRet == ERROR_SUCCESS )
  1928. {
  1929. if ( !::CreateRestoreMapEntryFromChgLog( &cCLE, szDrv, szDSPath, m_paryEnt[i] ) )
  1930. {
  1931. // even in case of error, try to revert as many operations as possible...
  1932. goto EndOfChgLog;
  1933. }
  1934. dwRet = cEnum.FindNextChangeLogEntry( cCLE );
  1935. }
  1936. if ( dwRet != ERROR_NO_MORE_ITEMS )
  1937. {
  1938. cszErr = ::GetSysErrStr( dwRet );
  1939. ErrorTrace(0, "FindNextChangeLogEntry failed - %ls", cszErr);
  1940. // even in case of error, try to revert as many operations as possible...
  1941. goto EndOfChgLog;
  1942. }
  1943. EndOfChgLog:
  1944. cEnum.FindClose();
  1945. }
  1946. // UNDO!!!
  1947. dwRet = T2DoRestore( TRUE );
  1948. if ( dwRet != ERROR_SUCCESS )
  1949. goto Exit;
  1950. // Nuke everything in the RP directory
  1951. // Get change logs to be deleted
  1952. for ( i = 0; i < m_aryDrv.GetSize(); i++ )
  1953. {
  1954. if ( m_aryDrv[i]->IsOffline() || m_aryDrv[i]->IsFrozen() || m_aryDrv[i]->IsExcluded() )
  1955. continue;
  1956. // set cszDrv to proper drive letters...
  1957. ::lstrcpy( szDrv, m_aryDrv[i]->GetMount() );
  1958. if ( szDrv[2] == L'\0' )
  1959. {
  1960. szDrv[2] = L'\\';
  1961. szDrv[3] = L'\0';
  1962. }
  1963. ::MakeRestorePath( szDSPath, szDrv, NULL );
  1964. wsprintf(szRestorePointPath, L"%s\\%s%d",szDSPath, s_cszRPDir,
  1965. m_dwRPNew);
  1966. LogDSFileTrace(0, L"Deleting changelogs from ", szRestorePointPath);
  1967. DeleteAllChangeLogs(szRestorePointPath);
  1968. }
  1969. //
  1970. // change restorestatus in the registry to indicate that revert happened
  1971. // successfully
  1972. //
  1973. SetRestoreStatusFailed();
  1974. dwRet = ERROR_SUCCESS;
  1975. Exit:
  1976. m_pLogFile->WriteMarker( RSTRLOGID_ENDOFUNDO, 0 );
  1977. TraceFunctLeave();
  1978. return( dwRet );
  1979. }
  1980. /////////////////////////////////////////////////////////////////////////////
  1981. //
  1982. // CreateRestoreOperationManager function
  1983. //
  1984. /////////////////////////////////////////////////////////////////////////////
  1985. BOOL
  1986. CreateRestoreOperationManager( CRestoreOperationManager **ppROMgr )
  1987. {
  1988. TraceFunctEnter("CreateRestoreOperationManager");
  1989. BOOL fRet = FALSE;
  1990. CRestoreOperationManager *pROMgr=NULL;
  1991. if ( ppROMgr == NULL )
  1992. {
  1993. FatalTrace(0, "Invalid parameter, ppROMgr is NULL.");
  1994. goto Exit;
  1995. }
  1996. *ppROMgr = NULL;
  1997. pROMgr = new CRestoreOperationManager;
  1998. if ( pROMgr == NULL )
  1999. {
  2000. FatalTrace(0, "Insufficient memory...");
  2001. goto Exit;
  2002. }
  2003. if ( !pROMgr->Init() )
  2004. goto Exit;
  2005. *ppROMgr = pROMgr;
  2006. fRet = TRUE;
  2007. Exit:
  2008. if ( !fRet )
  2009. SAFE_RELEASE(pROMgr);
  2010. TraceFunctLeave();
  2011. return( fRet );
  2012. }
  2013. // end of file