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.

2621 lines
81 KiB

  1. /*++
  2. Copyright (c) 1999 Microsoft Corporation
  3. Module Name:
  4. ftasr.cpp
  5. Abstract:
  6. Implementation of class CFtasrDlg
  7. This class provides a GUI interface for the FTASR process.
  8. It also implements the 3 main FTASR operations:
  9. "register" - register FTASR as a BackupRestore command
  10. "backup" - save the current FT hierarchy state in dr_state.sif file
  11. "restore" - restore the FT hierarchy as it is in dr_state.sif file
  12. Author:
  13. Norbert Kusters
  14. Cristian Teodorescu 3-March-1999
  15. Notes:
  16. Revision History:
  17. --*/
  18. #include "stdafx.h"
  19. #include "ftasr.h"
  20. #include "ftasrdlg.h"
  21. #include <mountmgr.h>
  22. #include <ntddft2.h>
  23. #include <winbase.h>
  24. #include <winioctl.h>
  25. #ifdef _DEBUG
  26. #define new DEBUG_NEW
  27. #undef THIS_FILE
  28. static char THIS_FILE[] = __FILE__;
  29. #endif
  30. ULONG DbgPrint(PWSTR Format, ...)
  31. {
  32. WCHAR achMsg[256];
  33. va_list vlArgs;
  34. va_start(vlArgs, Format);
  35. _vsnwprintf(achMsg, sizeof(achMsg), Format, vlArgs);
  36. va_end(vlArgs);
  37. OutputDebugString(achMsg);
  38. return TRUE;
  39. }
  40. /////////////////////////////////////////////////////////////////////////////
  41. // CFtasrDlg dialog
  42. CFtasrDlg::CFtasrDlg(
  43. CWnd* pParent /*=NULL*/
  44. )
  45. : CDialog(CFtasrDlg::IDD, pParent)
  46. {
  47. //{{AFX_DATA_INIT(CFtasrDlg)
  48. //}}AFX_DATA_INIT
  49. m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
  50. }
  51. void
  52. CFtasrDlg::DoDataExchange(
  53. CDataExchange* pDX
  54. )
  55. {
  56. CDialog::DoDataExchange(pDX);
  57. //{{AFX_DATA_MAP(CFtasrDlg)
  58. DDX_Control(pDX, IDC_PROGRESS, m_Progress);
  59. //}}AFX_DATA_MAP
  60. }
  61. BEGIN_MESSAGE_MAP(CFtasrDlg, CDialog)
  62. //{{AFX_MSG_MAP(CFtasrDlg)
  63. ON_WM_PAINT()
  64. ON_WM_QUERYDRAGICON()
  65. //}}AFX_MSG_MAP
  66. // manually added message handlers (for user-defined messages) should be added OUTSIDE
  67. // the AFX_MSG_MAP part above
  68. ON_MESSAGE( WM_WORKER_THREAD_DONE, OnWorkerThreadDone )
  69. ON_MESSAGE( WM_UPDATE_STATUS_TEXT, OnUpdateStatusText )
  70. END_MESSAGE_MAP()
  71. /////////////////////////////////////////////////////////////////////////////
  72. // CFtasrDlg message handlers
  73. BOOL
  74. CFtasrDlg::OnInitDialog()
  75. {
  76. CDialog::OnInitDialog();
  77. SetIcon(m_hIcon, TRUE); // Set big icon
  78. SetIcon(m_hIcon, FALSE); // Set small icon
  79. // initialize the progress range and start posiiton
  80. m_Progress.SetRange(0, 100 );
  81. m_Progress.SetPos( 0 ) ;
  82. DWORD dummy ;
  83. // Launch the worker thread.
  84. CreateThread(NULL,0, (LPTHREAD_START_ROUTINE) CFtasrDlg::DoWork,this,0,&dummy ) ;
  85. return TRUE; // return TRUE unless you set the focus to a control
  86. }
  87. LRESULT
  88. CFtasrDlg::OnWorkerThreadDone(
  89. WPARAM wparam,
  90. LPARAM lparam
  91. )
  92. {
  93. EndDialog( m_EndStatusCode ) ;
  94. return 0 ;
  95. }
  96. LRESULT
  97. CFtasrDlg::OnUpdateStatusText(
  98. WPARAM wparam,
  99. LPARAM lparam
  100. )
  101. {
  102. SetDlgItemText( IDC_PROGRESS_TEXT, m_StatusText ) ;
  103. return 0 ;
  104. }
  105. long
  106. CFtasrDlg::DoWork(
  107. CFtasrDlg *_this
  108. )
  109. {
  110. UINT operation ;
  111. operation = _this->ParseCommandLine();
  112. //((CFtasrDlg *)_this)->m_drState = NULL ;
  113. _this->m_EndStatusCode = 0 ;
  114. switch( operation ) {
  115. case DISPLAY_HELP :
  116. _this->m_EndStatusCode = 2;
  117. break;
  118. case BACKUP_STATE:
  119. _this->m_EndStatusCode = _this->DoBackup();
  120. break ;
  121. case RESTORE_STATE :
  122. _this->m_EndStatusCode = _this->DoRestore();
  123. break ;
  124. case REGISTER_STATE :
  125. _this->m_EndStatusCode = _this->DoRegister();
  126. break ;
  127. }
  128. _this->PostMessage( WM_WORKER_THREAD_DONE, 0, 0 ) ;
  129. return 0 ;
  130. }
  131. long
  132. CFtasrDlg::DoBackup()
  133. {
  134. BOOL b;
  135. DWORD numDisks, i;
  136. PFT_LOGICAL_DISK_ID diskId;
  137. FILE* output;
  138. long r;
  139. CHAR* windir;
  140. CHAR fileName[MAX_PATH];
  141. m_StatusText.LoadString( IDS_BACKUP_STATE );
  142. PostMessage( WM_UPDATE_STATUS_TEXT );
  143. b = FtEnumerateLogicalDisks(0, NULL, &numDisks);
  144. if (!b) {
  145. r = GetLastError();
  146. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  147. return r;
  148. }
  149. m_Progress.SetStep(100/(numDisks+3));
  150. diskId = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numDisks*sizeof(FT_LOGICAL_DISK_ID));
  151. if (!diskId) {
  152. r = GetLastError();
  153. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  154. return r;
  155. }
  156. b = FtEnumerateLogicalDisks(numDisks, diskId, &numDisks);
  157. if (!b) {
  158. r = GetLastError();
  159. LocalFree(diskId);
  160. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  161. return r;
  162. }
  163. #ifdef CHECK_UNSUPPORTED_CONFIG
  164. r = CheckForUnsupportedConfig(numDisks, diskId);
  165. if (r != ERROR_SUCCESS) {
  166. LocalFree(diskId);
  167. // The error message was already displayed in CheckForUnsupportedConfig
  168. return r;
  169. }
  170. #endif
  171. m_Progress.StepIt();
  172. Sleep(300);
  173. windir = getenv("windir");
  174. strcpy(fileName, windir);
  175. strcat(fileName, "\\repair\\dr_state.sif");
  176. output = fopen(fileName, "r+");
  177. if (!output) {
  178. LocalFree(diskId);
  179. DisplaySystemError(ERROR_FILE_NOT_FOUND);
  180. return ERROR_FILE_NOT_FOUND;
  181. }
  182. m_Progress.StepIt();
  183. Sleep(300);
  184. r = AddToCommands(output);
  185. if (r != ERROR_SUCCESS) {
  186. fclose(output);
  187. LocalFree(diskId);
  188. DisplayResourceError(IDS_ERROR_ADD_TO_COMMANDS);
  189. return r;
  190. }
  191. if (fseek(output, 0, SEEK_END)) {
  192. fclose(output);
  193. LocalFree(diskId);
  194. DisplaySystemError(ERROR_INVALID_FUNCTION);
  195. return ERROR_INVALID_FUNCTION;
  196. }
  197. fprintf(output, "\n[FT.VolumeState]\n");
  198. fprintf(output, "%lu\n", numDisks);
  199. m_Progress.StepIt();
  200. Sleep(300);
  201. for (i = 0; i < numDisks; i++) {
  202. r = PrintOutVolumeNames(output, diskId[i]);
  203. if (r != ERROR_SUCCESS) {
  204. fclose(output);
  205. LocalFree(diskId);
  206. // The error message was already displayed in PrintOutVolumeNames
  207. return r;
  208. }
  209. r = PrintOutDiskInfo(output, diskId[i]);
  210. if (r != ERROR_SUCCESS) {
  211. fclose(output);
  212. LocalFree(diskId);
  213. // The error message was already displayed in PrintOutDiskInfo
  214. return r;
  215. }
  216. m_Progress.StepIt();
  217. Sleep(300);
  218. }
  219. fclose(output);
  220. LocalFree(diskId);
  221. m_Progress.SetPos(101);
  222. return ERROR_SUCCESS;
  223. }
  224. long
  225. CFtasrDlg::DoRestore()
  226. {
  227. FILE* input;
  228. CHAR* windir;
  229. CHAR fileName[MAX_PATH];
  230. CHAR string[MAX_PATH];
  231. int result;
  232. m_StatusText.LoadString( IDS_RESTORE_STATE );
  233. PostMessage( WM_UPDATE_STATUS_TEXT );
  234. windir = getenv("windir");
  235. strcpy(fileName, windir);
  236. strcat(fileName, "\\repair\\dr_state.sif");
  237. input = fopen(fileName, "r");
  238. if (!input) {
  239. DisplaySystemError(ERROR_FILE_NOT_FOUND);
  240. return ERROR_FILE_NOT_FOUND;
  241. }
  242. for (;;) {
  243. if (!fgets(string, MAX_PATH, input)) {
  244. fclose(input);
  245. DbgPrint(L"ftasr: Section [FT.VolumeState] not found\n");
  246. m_Progress.SetPos(101);
  247. Sleep(300);
  248. return ERROR_SUCCESS;
  249. }
  250. if (!strncmp(string, "[FT.VolumeState]", 16)) {
  251. break;
  252. }
  253. }
  254. result = Restore(input);
  255. fclose(input);
  256. return result;
  257. }
  258. long
  259. CFtasrDlg::DoRegister()
  260. {
  261. int r;
  262. HKEY key;
  263. m_StatusText.LoadString( IDS_REGISTER_STATE ) ;
  264. PostMessage( WM_UPDATE_STATUS_TEXT ) ;
  265. r = RegCreateKeyEx(HKEY_LOCAL_MACHINE,
  266. L"SYSTEM\\CurrentControlSet\\Control\\BackupRestore\\AsrCommands",
  267. 0, NULL, 0, KEY_SET_VALUE, NULL, &key, NULL);
  268. if (r != ERROR_SUCCESS) {
  269. DisplaySystemError(r);
  270. return r;
  271. }
  272. m_Progress.SetPos(50);
  273. Sleep(300) ;
  274. r = RegSetValueEx(key, L"FT Volumes Recovery", 0, REG_SZ, (CONST BYTE*) L"ftasr backup",
  275. 26);
  276. if (r != ERROR_SUCCESS) {
  277. DisplaySystemError(r);
  278. return r;
  279. }
  280. m_Progress.SetPos(101);
  281. Sleep(300) ;
  282. return r;
  283. }
  284. UINT
  285. CFtasrDlg::ParseCommandLine()
  286. {
  287. CString cmd;
  288. cmd = GetCommandLine() ;
  289. cmd.MakeLower( ) ;
  290. if (cmd.Find(TEXT("backup") ) != -1) {
  291. return BACKUP_STATE ;
  292. } else if (cmd.Find(TEXT("restore")) != -1) {
  293. return RESTORE_STATE ;
  294. } else if (cmd.Find(TEXT("register")) != -1) {
  295. return REGISTER_STATE;
  296. }
  297. CString error_msg ;
  298. error_msg.LoadString(IDS_ERROR_USAGE);
  299. DisplayError(error_msg);
  300. return DISPLAY_HELP;
  301. }
  302. void
  303. CFtasrDlg::DisplayError(
  304. const CString& ErrorMsg
  305. )
  306. {
  307. CString title;
  308. title.LoadString(IDS_ERROR_TITLE);
  309. ::MessageBox(m_hWnd, ErrorMsg, title, MB_OK);
  310. }
  311. void
  312. CFtasrDlg::DisplaySystemError(
  313. DWORD ErrorCode
  314. )
  315. {
  316. CString title;
  317. WCHAR messageBuffer[MAX_PATH];
  318. title.LoadString(IDS_ERROR_TITLE);
  319. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode,
  320. 0, messageBuffer, MAX_PATH, NULL);
  321. ::MessageBox(m_hWnd, messageBuffer, title, MB_OK);
  322. }
  323. void
  324. CFtasrDlg::DisplayResourceError(
  325. DWORD ErrorId
  326. )
  327. {
  328. CString title, errorMsg;
  329. title.LoadString(IDS_ERROR_TITLE);
  330. errorMsg.LoadString(ErrorId);
  331. ::MessageBox(m_hWnd, errorMsg, title, MB_OK);
  332. }
  333. void
  334. CFtasrDlg::DisplayResourceSystemError(
  335. DWORD ErrorId,
  336. DWORD ErrorCode
  337. )
  338. {
  339. CString title, errorMsg;
  340. WCHAR messageBuffer[MAX_PATH];
  341. title.LoadString(IDS_ERROR_TITLE);
  342. errorMsg.LoadString(ErrorId);
  343. FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, ErrorCode,
  344. 0, messageBuffer, MAX_PATH, NULL);
  345. errorMsg += messageBuffer;
  346. ::MessageBox(m_hWnd, errorMsg, title, MB_OK);
  347. }
  348. void
  349. CFtasrDlg::DisplayResourceResourceError(
  350. DWORD ErrorId1,
  351. DWORD ErrorId2
  352. )
  353. {
  354. CString title, errorMsg1, errorMsg2;
  355. title.LoadString(IDS_ERROR_TITLE);
  356. errorMsg1.LoadString(ErrorId1);
  357. errorMsg2.LoadString(ErrorId2);
  358. errorMsg1 += errorMsg2;
  359. ::MessageBox(m_hWnd, errorMsg1, title, MB_OK);
  360. }
  361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. long
  363. CFtasrDlg::AddToCommands(
  364. FILE* Output
  365. )
  366. /*++
  367. Routine Description:
  368. This routine registers ftasr in the "Commands" section of
  369. the ASR backup file
  370. Arguments:
  371. Output - Supplies the backup file open in write mode
  372. Return Value:
  373. ERROR_SUCCESS if the function succeeded. Other error codes for failure
  374. --*/
  375. {
  376. CHAR string[MAX_PATH];
  377. CHAR lastString[MAX_PATH];
  378. int c, nextNumber;
  379. long position, endPosition;
  380. PCHAR buffer;
  381. size_t amountRead;
  382. long r;
  383. for (;;) {
  384. if (!fgets(string, MAX_PATH, Output)) {
  385. return ERROR_INVALID_DATA;
  386. }
  387. if (!strncmp(string, "[COMMANDS]", 10)) {
  388. break;
  389. }
  390. }
  391. strcpy(lastString, "");
  392. nextNumber = 1;
  393. for (;;) {
  394. c = getc(Output);
  395. ungetc(c, Output);
  396. if (c == '[') {
  397. break;
  398. }
  399. if (!fgets(string, MAX_PATH, Output)) {
  400. return ERROR_INVALID_DATA;
  401. }
  402. if (string[0] >= '0' && string[0] <= '9') {
  403. nextNumber = string[0] - '0' + 1;
  404. }
  405. }
  406. position = ftell(Output);
  407. r = fseek(Output, 0, SEEK_END);
  408. if (r) {
  409. return r;
  410. }
  411. endPosition = ftell(Output);
  412. r = fseek(Output, position, SEEK_SET);
  413. if (r) {
  414. return r;
  415. }
  416. buffer = (PCHAR)LocalAlloc(0, endPosition - position + 1);
  417. if (!buffer) {
  418. return ERROR_NOT_ENOUGH_MEMORY;
  419. }
  420. amountRead = fread(buffer, 1, endPosition - position + 1, Output);
  421. if (!amountRead) {
  422. return ERROR_INVALID_DATA;
  423. }
  424. r = fseek(Output, position + 28, SEEK_SET);
  425. if (r) {
  426. return r;
  427. }
  428. if (fwrite(buffer, 1, amountRead, Output) != amountRead) {
  429. return ERROR_INVALID_DATA;
  430. }
  431. r = fseek(Output, position, SEEK_SET);
  432. if (r) {
  433. return r;
  434. }
  435. fprintf(Output, "%d=1,2000,1,ftasr,\"restore\"\n", nextNumber);
  436. return ERROR_SUCCESS;
  437. }
  438. long
  439. CFtasrDlg::PrintOutVolumeNames(
  440. IN FILE* Output,
  441. IN FT_LOGICAL_DISK_ID RootLogicalDiskId
  442. )
  443. /*++
  444. Routine Description:
  445. This routine saves all volume names of a root logical disk in a
  446. backup file
  447. Arguments:
  448. Output - Supplies the backup file open in write mode
  449. RootLogicalDiskId - Supplies the id of the root logical disk.
  450. Return Value:
  451. ERROR_SUCCESS if the function succeeded. Other error codes for failure
  452. --*/
  453. {
  454. HANDLE h;
  455. PMOUNTMGR_MOUNT_POINT point;
  456. PMOUNTMGR_MOUNT_POINTS points;
  457. BOOL b;
  458. DWORD bytes;
  459. ULONG i;
  460. PWSTR name;
  461. WCHAR s;
  462. DWORD numNames;
  463. long r;
  464. h = CreateFileW(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  465. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  466. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  467. if (h == INVALID_HANDLE_VALUE) {
  468. r = GetLastError();
  469. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_NAMES, r);
  470. return r;
  471. }
  472. point = (PMOUNTMGR_MOUNT_POINT)LocalAlloc(0, sizeof(MOUNTMGR_MOUNT_POINT) +
  473. sizeof(FT_LOGICAL_DISK_ID));
  474. if (!point) {
  475. r = GetLastError();
  476. CloseHandle(h);
  477. DisplaySystemError(r);
  478. return r;
  479. }
  480. ZeroMemory(point, sizeof(MOUNTMGR_MOUNT_POINT));
  481. point->UniqueIdOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  482. point->UniqueIdLength = sizeof(FT_LOGICAL_DISK_ID);
  483. CopyMemory((PCHAR) point + point->UniqueIdOffset, &RootLogicalDiskId,
  484. point->UniqueIdLength);
  485. points = (PMOUNTMGR_MOUNT_POINTS)LocalAlloc(0, sizeof(MOUNTMGR_MOUNT_POINTS) + sizeof(WCHAR));
  486. if (!points) {
  487. r = GetLastError();
  488. LocalFree(point);
  489. CloseHandle(h);
  490. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_NAMES, r);
  491. return r;
  492. }
  493. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
  494. sizeof(MOUNTMGR_MOUNT_POINT) +
  495. sizeof(FT_LOGICAL_DISK_ID), points,
  496. sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
  497. while (!b && GetLastError() == ERROR_MORE_DATA) {
  498. bytes = points->Size + sizeof(WCHAR);
  499. LocalFree(points);
  500. points = (PMOUNTMGR_MOUNT_POINTS)LocalAlloc(0, bytes);
  501. if (!points) {
  502. r = GetLastError();
  503. LocalFree(point);
  504. CloseHandle(h);
  505. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_NAMES, r);
  506. return r;
  507. }
  508. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, point,
  509. sizeof(MOUNTMGR_MOUNT_POINT) +
  510. sizeof(FT_LOGICAL_DISK_ID), points, bytes, &bytes,
  511. NULL);
  512. }
  513. r = GetLastError();
  514. LocalFree(point);
  515. CloseHandle(h);
  516. if (!b) {
  517. LocalFree(points);
  518. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_NAMES, r);
  519. return r;
  520. }
  521. numNames = 0;
  522. for (i = 0; i < points->NumberOfMountPoints; i++) {
  523. point = &points->MountPoints[i];
  524. if (point->SymbolicLinkNameLength != 96) {
  525. continue;
  526. }
  527. name = (PWCHAR) ((PCHAR) points + point->SymbolicLinkNameOffset);
  528. if (name[0] == '\\' &&
  529. name[1] == '?' &&
  530. name[2] == '?' &&
  531. name[3] == '\\' &&
  532. name[4] == 'V' &&
  533. name[5] == 'o' &&
  534. name[6] == 'l' &&
  535. name[7] == 'u' &&
  536. name[8] == 'm' &&
  537. name[9] == 'e' &&
  538. name[10] == '{' &&
  539. name[19] == '-' &&
  540. name[24] == '-' &&
  541. name[29] == '-' &&
  542. name[34] == '-' &&
  543. name[47] == '}') {
  544. numNames++;
  545. }
  546. }
  547. fprintf(Output, "%d\n", numNames);
  548. for (i = 0; i < points->NumberOfMountPoints; i++) {
  549. point = &points->MountPoints[i];
  550. if (point->SymbolicLinkNameLength != 96) {
  551. continue;
  552. }
  553. name = (PWCHAR) ((PCHAR) points + point->SymbolicLinkNameOffset);
  554. if (name[0] == '\\' &&
  555. name[1] == '?' &&
  556. name[2] == '?' &&
  557. name[3] == '\\' &&
  558. name[4] == 'V' &&
  559. name[5] == 'o' &&
  560. name[6] == 'l' &&
  561. name[7] == 'u' &&
  562. name[8] == 'm' &&
  563. name[9] == 'e' &&
  564. name[10] == '{' &&
  565. name[19] == '-' &&
  566. name[24] == '-' &&
  567. name[29] == '-' &&
  568. name[34] == '-' &&
  569. name[47] == '}') {
  570. s = name[48];
  571. name[48] = 0;
  572. fprintf(Output,"\"");
  573. fwprintf(Output, name);
  574. fprintf(Output, "\"\n");
  575. name[48] = s;
  576. }
  577. }
  578. LocalFree(points);
  579. return ERROR_SUCCESS;
  580. }
  581. long
  582. CFtasrDlg::PrintOutDiskInfo(
  583. IN FILE* Output,
  584. IN FT_LOGICAL_DISK_ID LogicalDiskId
  585. )
  586. /*++
  587. Routine Description:
  588. This routine saves all information needed to restore a
  589. logical disk in a backup file
  590. Arguments:
  591. Output - Supplies the backup file open in write mode
  592. LogicalDiskId - Supplies the id of the logical disk.
  593. Return Value:
  594. ERROR_SUCCESS if the function succeeded. Other error codes for failure
  595. --*/
  596. {
  597. BOOL b;
  598. WORD numMembers;
  599. PFT_LOGICAL_DISK_ID members;
  600. FT_LOGICAL_DISK_TYPE diskType;
  601. LONGLONG volumeSize;
  602. WORD i;
  603. CHAR configInfo[100];
  604. CHAR stateInfo[100];
  605. PFT_PARTITION_CONFIGURATION_INFORMATION partConfig;
  606. PFT_STRIPE_SET_CONFIGURATION_INFORMATION stripeConfig;
  607. PFT_MIRROR_SET_CONFIGURATION_INFORMATION mirrorConfig;
  608. PFT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION swpConfig;
  609. PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION redistConfig;
  610. long r;
  611. fprintf(Output, "%I64X", LogicalDiskId);
  612. if (!LogicalDiskId) {
  613. fprintf(Output, "\n");
  614. return ERROR_SUCCESS;
  615. }
  616. b = FtQueryLogicalDiskInformation(LogicalDiskId, NULL, NULL,
  617. 0, NULL, &numMembers, 0, NULL, 0, NULL);
  618. if (!b) {
  619. r = GetLastError();
  620. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  621. return r;
  622. }
  623. if (numMembers) {
  624. members = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numMembers*sizeof(FT_LOGICAL_DISK_ID));
  625. if (!members) {
  626. r = GetLastError();
  627. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  628. return r;
  629. }
  630. } else {
  631. members = NULL;
  632. }
  633. b = FtQueryLogicalDiskInformation(LogicalDiskId, &diskType, &volumeSize,
  634. numMembers, members, &numMembers,
  635. 100, configInfo, 100, stateInfo);
  636. if (!b) {
  637. r = GetLastError();
  638. LocalFree(members);
  639. DisplayResourceSystemError(IDS_ERROR_PRINT_VOLUME_INFO, r);
  640. return r;
  641. }
  642. fprintf(Output, ",%d,%d", diskType, numMembers);
  643. switch (diskType) {
  644. case FtPartition:
  645. partConfig = (PFT_PARTITION_CONFIGURATION_INFORMATION) configInfo;
  646. fprintf(Output, ",%X,%I64X,%I64X", partConfig->Signature,
  647. partConfig->ByteOffset, volumeSize);
  648. break;
  649. case FtStripeSet:
  650. stripeConfig = (PFT_STRIPE_SET_CONFIGURATION_INFORMATION) configInfo;
  651. fprintf(Output, ",%X", stripeConfig->StripeSize);
  652. break;
  653. case FtMirrorSet:
  654. mirrorConfig = (PFT_MIRROR_SET_CONFIGURATION_INFORMATION) configInfo;
  655. fprintf(Output, ",%I64X", mirrorConfig->MemberSize);
  656. break;
  657. case FtStripeSetWithParity:
  658. swpConfig = (PFT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION) configInfo;
  659. fprintf(Output, ",%I64X,%X", swpConfig->MemberSize, swpConfig->StripeSize);
  660. break;
  661. case FtRedistribution:
  662. redistConfig = (PFT_REDISTRIBUTION_CONFIGURATION_INFORMATION) configInfo;
  663. fprintf(Output, ",%X,%d,%d", redistConfig->StripeSize,
  664. redistConfig->FirstMemberWidth,
  665. redistConfig->SecondMemberWidth);
  666. break;
  667. }
  668. fprintf(Output, "\n");
  669. for (i = 0; i < numMembers; i++) {
  670. r = PrintOutDiskInfo(Output, members[i]);
  671. if (r != ERROR_SUCCESS) {
  672. LocalFree(members);
  673. return r;
  674. }
  675. }
  676. LocalFree(members);
  677. return ERROR_SUCCESS;
  678. }
  679. long
  680. CFtasrDlg::Restore(
  681. IN FILE* Input
  682. )
  683. /*++
  684. Routine Description:
  685. This routine restores the logical disks hierarchy using information
  686. saved in a backup file
  687. Arguments:
  688. Input - Supplies the backup file open in read mode
  689. Return Value:
  690. ERROR_SUCCESS if the restore succeeded. Other error codes for failure
  691. --*/
  692. {
  693. DWORD numDisks, numNames, i, j, k;
  694. PWCHAR* volumeNames;
  695. PWCHAR volumeName;
  696. int nameLength;
  697. FT_LOGICAL_DISK_ID diskId;
  698. FT_LOGICAL_DISK_ID expectedPath[MAX_STACK_DEPTH];
  699. long r;
  700. m_Progress.SetPos(20);
  701. Sleep(300);
  702. fwscanf(Input, L"%lu", &numDisks);
  703. if (feof(Input)) {
  704. numDisks = 0;
  705. }
  706. if (numDisks > 0) {
  707. m_Progress.SetStep(80/numDisks);
  708. }
  709. for (k = 0; k < numDisks; k++) {
  710. DbgPrint(L"ftasr: Start processing disk\n");
  711. fwscanf(Input, L"%d", &numNames);
  712. if (feof(Input)) {
  713. break;
  714. }
  715. if (numNames) {
  716. volumeNames = (PWCHAR*)LocalAlloc(0, numNames*sizeof(PWCHAR));
  717. if (!volumeNames) {
  718. r = GetLastError();
  719. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  720. return r;
  721. }
  722. for (i = 0; i < numNames; i++) {
  723. volumeName = (PWCHAR)LocalAlloc(0, MAX_PATH*sizeof(WCHAR));
  724. if (!volumeName) {
  725. r = GetLastError();
  726. for (j = 0; j < i; j++) {
  727. LocalFree(volumeNames[j]);
  728. }
  729. LocalFree(volumeNames);
  730. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  731. return r;
  732. }
  733. fwscanf(Input, L"%s", volumeName);
  734. nameLength = wcslen(volumeName);
  735. if (nameLength < 2 ||
  736. volumeName[0] != L'\"' || volumeName[nameLength-1] != L'\"') {
  737. for (j = 0; j < i; j++) {
  738. LocalFree(volumeNames[j]);
  739. }
  740. LocalFree(volumeNames);
  741. LocalFree(volumeName);
  742. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME_NAMES, IDS_ERROR_INVALID_BACKUP);
  743. return ERROR_INVALID_DATA;
  744. }
  745. for (j = 0; (long)j < nameLength - 2; j++) {
  746. volumeName[j] = volumeName[j+1];
  747. }
  748. volumeName[j] = L'\0';
  749. volumeNames[i] = volumeName;
  750. }
  751. }
  752. if (feof(Input)) {
  753. break;
  754. }
  755. diskId = BuildFtDisk(Input, expectedPath, 0, TRUE, NULL, NULL);
  756. if (diskId && numNames) {
  757. LinkVolumeNamesToLogicalDisk(volumeNames, numNames, diskId);
  758. for (i = 0; i < numNames; i++) {
  759. LocalFree(volumeNames[i]);
  760. }
  761. LocalFree(volumeNames);
  762. }
  763. m_Progress.StepIt();
  764. Sleep(300);
  765. }
  766. m_Progress.SetPos(101);
  767. Sleep(300);
  768. return ERROR_SUCCESS;
  769. }
  770. VOID
  771. CFtasrDlg::LinkVolumeNamesToLogicalDisk(
  772. IN PWCHAR* VolumeNames,
  773. IN DWORD NumNames,
  774. IN FT_LOGICAL_DISK_ID LogicalDiskId
  775. )
  776. /*++
  777. Routine Description:
  778. This links volumes names to a root logical disk
  779. Arguments:
  780. VolumeNames - Supplies the volume names
  781. NumNames - Supplies the number of volume names
  782. LogicalDiskId - Supplies the id of the logical disk
  783. Return Value:
  784. -
  785. --*/
  786. {
  787. HANDLE h;
  788. FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_INPUT inputNtDevice;
  789. PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT outputNtDevice;
  790. WCHAR bufferNtDevice[MAX_PATH];
  791. ULONG inputQueryPointsSize;
  792. PMOUNTMGR_MOUNT_POINT inputQueryPoints;
  793. MOUNTMGR_MOUNT_POINTS outputQueryPoints;
  794. PMOUNTMGR_TARGET_NAME inputArrival;
  795. WCHAR buffer[MAX_PATH];
  796. PMOUNTMGR_CREATE_POINT_INPUT inputCreatePoint;
  797. BOOL b;
  798. long r;
  799. DWORD i;
  800. DWORD bytes;
  801. // 1. Get the NT device name of the volume
  802. inputNtDevice.RootLogicalDiskId = LogicalDiskId;
  803. outputNtDevice = (PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT)bufferNtDevice;
  804. h = CreateFile(DD_DOS_FT_CONTROL_NAME, GENERIC_READ, FILE_SHARE_READ |
  805. FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  806. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  807. if (h == INVALID_HANDLE_VALUE) {
  808. r = GetLastError();
  809. DbgPrint(L"ftasr: Link volume names failed: Open DD_DOS_FT_CONTROL_NAME failed with %lu\n", r);
  810. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  811. return;
  812. }
  813. b = DeviceIoControl(h, FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK, &inputNtDevice, sizeof(inputNtDevice),
  814. outputNtDevice, MAX_PATH * sizeof(WCHAR), &bytes, NULL);
  815. r = GetLastError();
  816. CloseHandle(h);
  817. if (!b) {
  818. DbgPrint(L"ftasr: Link volume names failed: FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK failed with %lu\n", r);
  819. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  820. return;
  821. }
  822. outputNtDevice->NtDeviceName[outputNtDevice->NumberOfCharactersInNtDeviceName] = 0;
  823. // 2. Open the mount manager
  824. h = CreateFile(MOUNTMGR_DOS_DEVICE_NAME, GENERIC_READ | GENERIC_WRITE,
  825. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING,
  826. FILE_ATTRIBUTE_NORMAL, INVALID_HANDLE_VALUE);
  827. if (h == INVALID_HANDLE_VALUE) {
  828. r = GetLastError();
  829. DbgPrint(L"ftasr: Link volume names failed: Open MOUNTMGR_DOS_DEVICE_NAME failed with %lu\n", r);
  830. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  831. return;
  832. }
  833. // 3. Call IOCTL_MOUNTMGR_QUERY_POINTS to check whether the volume is installed or not
  834. inputQueryPointsSize = sizeof(MOUNTMGR_MOUNT_POINT) + outputNtDevice->NumberOfCharactersInNtDeviceName * sizeof(WCHAR);
  835. inputQueryPoints = (PMOUNTMGR_MOUNT_POINT)LocalAlloc(0, inputQueryPointsSize);
  836. if (!inputQueryPoints)
  837. {
  838. r = GetLastError();
  839. CloseHandle(h);
  840. DbgPrint(L"ftasr: Link volume names failed: Cannot allocate memory for IOCTL_MOUNTMGR_QUERY_POINTS input\n");
  841. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  842. return;
  843. }
  844. inputQueryPoints->SymbolicLinkNameLength = 0;
  845. inputQueryPoints->SymbolicLinkNameOffset = 0;
  846. inputQueryPoints->UniqueIdOffset = 0;
  847. inputQueryPoints->UniqueIdLength = 0;
  848. inputQueryPoints->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  849. inputQueryPoints->DeviceNameLength = outputNtDevice->NumberOfCharactersInNtDeviceName * sizeof(WCHAR);
  850. CopyMemory((PCHAR)inputQueryPoints + inputQueryPoints->DeviceNameOffset, outputNtDevice->NtDeviceName,
  851. inputQueryPoints->DeviceNameLength);
  852. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, inputQueryPoints, inputQueryPointsSize,
  853. &outputQueryPoints, sizeof(MOUNTMGR_MOUNT_POINTS), &bytes, NULL);
  854. r = GetLastError();
  855. LocalFree(inputQueryPoints);
  856. // 4. If the volume is not installed then force the installation
  857. if (!b && r != ERROR_MORE_DATA) {
  858. DbgPrint(L"ftasr: Link volume names: IOCTL_MOUNTMGR_QUERY_POINTS failed with %lu\n", r);
  859. inputArrival = (PMOUNTMGR_TARGET_NAME)buffer;
  860. inputArrival->DeviceNameLength = outputNtDevice->NumberOfCharactersInNtDeviceName * sizeof(WCHAR);
  861. CopyMemory((PCHAR)inputArrival->DeviceName, outputNtDevice->NtDeviceName,
  862. inputArrival->DeviceNameLength);
  863. // Send volume arrival notifications until one of them succeedes. Timeout 2 minutes
  864. for (i = 0; i < 1200; i++) {
  865. b = DeviceIoControl(h, IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION, inputArrival,
  866. MAX_PATH * sizeof(WCHAR), NULL, 0, &bytes, NULL);
  867. if (b) {
  868. DbgPrint(L"ftasr: Link volume names: IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for %s succeeded\n",
  869. outputNtDevice->NtDeviceName);
  870. break;
  871. }
  872. r = GetLastError();
  873. DbgPrint(L"ftasr: Link volume names: %lu. IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for %s failed with %lu\n",
  874. i, outputNtDevice->NtDeviceName, r);
  875. Sleep(100);
  876. }
  877. if (!b) {
  878. CloseHandle(h);
  879. DbgPrint(L"ftasr: Link volume names failed: IOCTL_MOUNTMGR_VOLUME_ARRIVAL_NOTIFICATION for %s timed out\n",
  880. outputNtDevice->NtDeviceName);
  881. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME_NAMES, r);
  882. return;
  883. }
  884. }
  885. // 5. Call IOCTL_MOUNTMGR_CREATE_POINT
  886. inputCreatePoint = (PMOUNTMGR_CREATE_POINT_INPUT)buffer;
  887. for (i = 0; i < NumNames; i++) {
  888. inputCreatePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  889. inputCreatePoint->SymbolicLinkNameLength = wcslen(VolumeNames[i]) * sizeof(WCHAR);
  890. inputCreatePoint->DeviceNameOffset = inputCreatePoint->SymbolicLinkNameOffset +
  891. inputCreatePoint->SymbolicLinkNameLength;
  892. inputCreatePoint->DeviceNameLength = outputNtDevice->NumberOfCharactersInNtDeviceName * sizeof(WCHAR);
  893. CopyMemory((PCHAR)inputCreatePoint + inputCreatePoint->SymbolicLinkNameOffset,
  894. VolumeNames[i], inputCreatePoint->SymbolicLinkNameLength);
  895. CopyMemory((PCHAR)inputCreatePoint + inputCreatePoint->DeviceNameOffset,
  896. outputNtDevice->NtDeviceName, inputCreatePoint->DeviceNameLength);
  897. b = DeviceIoControl(h, IOCTL_MOUNTMGR_CREATE_POINT, inputCreatePoint,
  898. MAX_PATH * sizeof(WCHAR), NULL, 0, &bytes, NULL);
  899. if (b) {
  900. DbgPrint(L"ftasr: Link volume names: IOCTL_MOUNTMGR_CREATE_POINT succeeded\n");
  901. } else {
  902. DbgPrint(L"ftasr: Link volume names: IOCTL_MOUNTMGR_CREATE_POINT failed with %lu\n",
  903. GetLastError());
  904. }
  905. }
  906. // 6. Close the mount manager
  907. CloseHandle(h);
  908. }
  909. FT_LOGICAL_DISK_ID
  910. CFtasrDlg::BuildFtDisk(
  911. IN FILE* Input,
  912. IN OUT PFT_LOGICAL_DISK_ID ExpectedPath,
  913. IN WORD ExpectedPathSize,
  914. IN BOOL AllowBreak,
  915. OUT PBOOL Existing, /* OPTIONAL */
  916. OUT PBOOL Overwriteable /* OPTIONAL */
  917. )
  918. /*++
  919. Routine Description:
  920. This routine restores a logical disk based on the information saved
  921. in the backup file
  922. Arguments:
  923. Input - Supplies the backup file open in read mode
  924. ExpectedPath - Supplies the expected forefathers of the logical disk
  925. as they appear in the backup file, starting with a root
  926. logical volume and ending with the expected parent.
  927. The size of this array is maximum MAX_STACK_DEPTH.
  928. The array content may change inside this function due
  929. to logical disk breakings or replacements
  930. ExpectedPathSize - Supplies the number of expected forefathers
  931. AllowBreak - Specifies whether the expected forefathers can be broken
  932. inside this function
  933. Existing - Returns TRUE if the logical disk was already alive and valid
  934. at the moment of the execution of this function
  935. Overwriteable - Returns TRUE if the FT volume can be overwritten later in the FT ASR process
  936. If FALSE we should avoid building an FT set on top of it that may destroy the content of the FT volume
  937. Return Value:
  938. The id of the logical disk. 0 if the function failed
  939. --*/
  940. {
  941. FT_LOGICAL_DISK_ID diskId, candidate;
  942. FT_LOGICAL_DISK_TYPE diskType, candidateType;
  943. DWORD numMembers;
  944. WORD candidateNumMembers;
  945. DWORD numNewMembers, numInvalidNewMembers;
  946. DWORD numNotOverwriteableMembers, notOverwriteableMember;
  947. DWORD numReplacedMembers, i, j;
  948. PFT_LOGICAL_DISK_ID members;
  949. PBOOL existingMembers;
  950. ULONG signature;
  951. LONGLONG offset, length;
  952. DWORD configSize;
  953. PVOID config;
  954. DWORD stripeSize, firstWidth, secondWidth;
  955. DWORDLONG memberSize;
  956. FT_STRIPE_SET_CONFIGURATION_INFORMATION stripeConfig;
  957. FT_MIRROR_SET_CONFIGURATION_INFORMATION mirrorConfig;
  958. FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION swpConfig;
  959. FT_REDISTRIBUTION_CONFIGURATION_INFORMATION redistConfig;
  960. WCHAR messageBuffer[MAX_PATH];
  961. BOOL ioCapable, b;
  962. FT_LOGICAL_DISK_ID realPath[MAX_STACK_DEPTH];
  963. FT_LOGICAL_DISK_ID newRealPath[MAX_STACK_DEPTH];
  964. WORD realPathSize, newRealPathSize;
  965. SHORT k;
  966. LONGLONG size0, size1;
  967. long r;
  968. BOOL isSystem, isBoot;
  969. DbgPrint(L"ftasr: Build FT disk: ");
  970. // Initialization
  971. if (Existing) {
  972. *Existing = FALSE;
  973. }
  974. if (Overwriteable) {
  975. *Overwriteable = TRUE;
  976. }
  977. ioCapable = FALSE;
  978. candidate = 0;
  979. // 1. Read the disk id, type and number of members from the file
  980. diskId = 0;
  981. fwscanf(Input, L"%I64X", &diskId);
  982. if (!diskId) {
  983. DbgPrint(L"Error - cannot read DiskId\n");
  984. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_INVALID_BACKUP);
  985. return candidate;
  986. }
  987. DbgPrint(L"DiskId = %I64X\n", diskId);
  988. fwscanf(Input, L",%d,%d", &diskType, &numMembers);
  989. // 2. Check whether the disk is alive, has the same main parameters and is IO capable
  990. b = FtQueryLogicalDiskInformation(
  991. diskId, &candidateType, NULL, 0, NULL,
  992. &candidateNumMembers, 0, NULL, 0, NULL );
  993. if (b && diskType == candidateType &&
  994. numMembers == candidateNumMembers) {
  995. if (Existing) {
  996. *Existing = TRUE;
  997. }
  998. candidate = diskId;
  999. b = FtCheckIo(candidate, &ioCapable);
  1000. if (!b) {
  1001. ioCapable = FALSE;
  1002. }
  1003. }
  1004. // 3. Read the configuration information from file. Dismiss the FtPartition case
  1005. switch (diskType) {
  1006. case FtPartition:
  1007. fwscanf(Input, L",%X,%I64X,%I64X", &signature, &offset, &length);
  1008. if (candidate) {
  1009. ASSERT(candidate == diskId);
  1010. DbgPrint(L"ftasr: Build FT disk succeeded - FT partition already exists\n");
  1011. return candidate;
  1012. }
  1013. candidate = CreateFtPartition(signature, offset, length, &b);
  1014. // If the new FT partition is not overwritable break the expected path
  1015. // We try to avoid regenerations that may overwrite the content of the boot/system partition
  1016. if (!b) {
  1017. for (i = 0; i < ExpectedPathSize; i++) {
  1018. if (ExpectedPath[i]) {
  1019. b = FtBreakLogicalDisk(ExpectedPath[i]);
  1020. if (b) {
  1021. DbgPrint(L"ftasr: Expected parent %I64X broken\n", ExpectedPath[i]);
  1022. ExpectedPath[i] = 0;
  1023. } else {
  1024. DbgPrint(L"ftasr: Expected parent %I64X break failed with %ld\n", ExpectedPath[i], GetLastError());
  1025. }
  1026. }
  1027. }
  1028. }
  1029. if (Overwriteable) {
  1030. *Overwriteable = b;
  1031. }
  1032. DbgPrint(L"ftasr: Build FT disk succeeded - new FT partition %I64X\n", candidate);
  1033. return candidate;
  1034. break;
  1035. case FtVolumeSet:
  1036. configSize = 0;
  1037. config = NULL;
  1038. break;
  1039. case FtStripeSet:
  1040. fwscanf(Input, L",%X", &stripeSize);
  1041. stripeConfig.StripeSize = stripeSize;
  1042. configSize = sizeof(FT_STRIPE_SET_CONFIGURATION_INFORMATION);
  1043. config = &stripeConfig;
  1044. break;
  1045. case FtMirrorSet:
  1046. fwscanf(Input, L",%I64X", &memberSize);
  1047. mirrorConfig.MemberSize = memberSize;
  1048. configSize = sizeof(FT_MIRROR_SET_CONFIGURATION_INFORMATION);
  1049. config = &mirrorConfig;
  1050. break;
  1051. case FtStripeSetWithParity:
  1052. fwscanf(Input, L",%I64X,%X", &memberSize, &stripeSize);
  1053. ZeroMemory(&swpConfig, sizeof(swpConfig));
  1054. swpConfig.MemberSize = memberSize;
  1055. swpConfig.StripeSize = stripeSize;
  1056. configSize = sizeof(FT_STRIPE_SET_WITH_PARITY_CONFIGURATION_INFORMATION);
  1057. config = &swpConfig;
  1058. break;
  1059. case FtRedistribution:
  1060. fwscanf(Input, L",%X,%d,%d", &stripeSize, &firstWidth, &secondWidth);
  1061. redistConfig.StripeSize = stripeSize | 0x80000000;
  1062. redistConfig.FirstMemberWidth = (USHORT) firstWidth;
  1063. redistConfig.SecondMemberWidth = (USHORT) secondWidth;
  1064. configSize = sizeof(FT_REDISTRIBUTION_CONFIGURATION_INFORMATION);
  1065. config = &redistConfig;
  1066. break;
  1067. default:
  1068. ASSERT(!candidate);
  1069. DbgPrint(L"ftasr: Build FT disk failed - unrecognized logical disk type\n");
  1070. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_INVALID_BACKUP);
  1071. return 0;
  1072. }
  1073. // 4. Build the members
  1074. members = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numMembers*sizeof(FT_LOGICAL_DISK_ID));
  1075. if (!members) {
  1076. DbgPrint(L"ftasr: Build FT disk failed - allocation failed for members array\n");
  1077. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME, GetLastError());
  1078. return candidate;
  1079. }
  1080. existingMembers = (PBOOL)LocalAlloc(0, numMembers*sizeof(BOOL));
  1081. if (!existingMembers) {
  1082. DbgPrint(L"ftasr: Build FT disk failed - allocation failed for existing members array\n");
  1083. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME, GetLastError());
  1084. LocalFree(members);
  1085. return candidate;
  1086. }
  1087. if (ExpectedPathSize >= MAX_STACK_DEPTH) {
  1088. // that's really a huge, huge stack!
  1089. DbgPrint(L"ftasr: Build FT disk failed - expected path size overpassed\n");
  1090. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_UNEXPECTED);
  1091. goto _cleanup;
  1092. }
  1093. ExpectedPath[ExpectedPathSize] = candidate; // kind of push in a stack
  1094. numNewMembers = 0;
  1095. numInvalidNewMembers = 0;
  1096. numNotOverwriteableMembers = 0;
  1097. for (i = 0; i < numMembers; i++) {
  1098. members[i] = BuildFtDisk(Input, ExpectedPath, (WORD)(ExpectedPathSize + 1),
  1099. AllowBreak && !ioCapable, &(existingMembers[i]), &b);
  1100. if (!existingMembers[i]) {
  1101. DbgPrint(L"ftasr: New member %I64X\n", members[i]);
  1102. numNewMembers++;
  1103. }
  1104. if (!members[i]) {
  1105. numInvalidNewMembers++;
  1106. }
  1107. if (!b && members[i] && !existingMembers[i]) {
  1108. numNotOverwriteableMembers++;
  1109. notOverwriteableMember = i;
  1110. }
  1111. }
  1112. ASSERT(numInvalidNewMembers <= numNewMembers);
  1113. // 5. See what happened with the candidate during step 4
  1114. // It might have been broken or replaced, so we must update the candidate
  1115. candidate = ExpectedPath[ExpectedPathSize]; // kind of pop from a stack
  1116. if (Existing) {
  1117. *Existing = (candidate != 0);
  1118. }
  1119. // 6. "Use Candidate" - check whether the candidate is intact, can be repaired or should be broken
  1120. if (candidate) {
  1121. ASSERT(!Existing || *Existing);
  1122. // 6.1. All members are intact -> return candidate
  1123. if (!numNewMembers) {
  1124. DbgPrint(L"ftasr: Build FT disk succeeded - all members are intact\n");
  1125. goto _cleanup;
  1126. }
  1127. // 6.2. "Replace members" - We have new valid members waiting to replace old invalid members
  1128. if (numNewMembers > numInvalidNewMembers) {
  1129. // 6.2.1. Get the path from the candidate to its root volume
  1130. b = GetPathFromLogicalDiskToRoot(candidate, realPath, &realPathSize);
  1131. if (!b) {
  1132. // Unexpected error. Cannot take the risk to replace members or break the disk
  1133. DbgPrint(L"ftasr: Build FT disk failed - GetPathFromLogicalDiskToRoot failed\n");
  1134. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_UNEXPECTED);
  1135. goto _cleanup;
  1136. }
  1137. // 6.2.2. Call replace for every new valid member
  1138. numReplacedMembers = 0;
  1139. for (i = 0; i < numMembers; i++) {
  1140. if (!existingMembers[i] && members[i] != 0) {
  1141. DbgPrint(L"ftasr: Replace member %d with logical disk %I64X\n", i, members[i]);
  1142. b = FtReplaceLogicalDiskMember(candidate, (WORD)i, members[i], &diskId);
  1143. if (b) {
  1144. candidate = diskId;
  1145. numReplacedMembers++;
  1146. DbgPrint(L"ftasr: Replacement succeeded. Id = %I64X\n", candidate);
  1147. } else {
  1148. DbgPrint(L"ftasr: Replacement failed with %ld\n", GetLastError());
  1149. }
  1150. }
  1151. }
  1152. // 6.2.3. If at least one replacement succeeded update the expected path
  1153. if (numReplacedMembers > 0) {
  1154. b = GetPathFromLogicalDiskToRoot(candidate, newRealPath, &newRealPathSize);
  1155. ASSERT(!b || realPathSize == newRealPathSize);
  1156. // Stop synchronization at this moment
  1157. if (b) {
  1158. if (newRealPathSize > 0 ) {
  1159. FtStopSyncOperations(newRealPath[newRealPathSize - 1]);
  1160. } else {
  1161. FtStopSyncOperations(candidate);
  1162. }
  1163. }
  1164. // Update the expected path. Some of the expected parents may have been changed
  1165. // due to replacements performed
  1166. for(i = 0; i < ExpectedPathSize; i++) {
  1167. if (ExpectedPath[i]) {
  1168. for(j = 0; j < realPathSize; j++) {
  1169. if (ExpectedPath[i] == realPath[j]) {
  1170. ExpectedPath[i] = b ? newRealPath[j] : 0;
  1171. break;
  1172. }
  1173. }
  1174. }
  1175. }
  1176. }
  1177. // 6.2.4. If all replacements succeeded return the candidate
  1178. if (numReplacedMembers == numNewMembers - numInvalidNewMembers) {
  1179. DbgPrint(L"ftasr: Build FT disk succeeded - all replacements succeeded\n");
  1180. goto _cleanup;
  1181. }
  1182. }
  1183. // End "Replace members"
  1184. // 6.3. "Break" - Check whether we are allowed to break the candidate. If we aren't, return it.
  1185. b = FtCheckIo(candidate, &ioCapable);
  1186. if (!b) {
  1187. ioCapable = FALSE;
  1188. }
  1189. if (!AllowBreak || ioCapable || numInvalidNewMembers > 0 ||
  1190. !GetPathFromLogicalDiskToRoot(candidate, realPath, &realPathSize) ) {
  1191. // Cannot break or doesn't make sense to break
  1192. DbgPrint(L"ftasr: Build FT disk failed - cannot break or doesn't make sense to break\n");
  1193. goto _cleanup;
  1194. }
  1195. // Check whether the real path matches with the expected path
  1196. // Note: real path is a reversed path
  1197. for (i = 0; i < realPathSize; i++) {
  1198. if (i >= ExpectedPathSize || realPath[i] != ExpectedPath[ExpectedPathSize - i - 1]) {
  1199. DbgPrint(L"ftasr: Build FT disk failed - real path doesn't match with the expected path\n");
  1200. goto _cleanup;
  1201. }
  1202. }
  1203. for (k = (SHORT)realPathSize - 1; k >= 0; k--){
  1204. DbgPrint(L"ftasr: Break parent %I64X\n", realPath[k]);
  1205. b = FtBreakLogicalDisk(realPath[k]);
  1206. if (!b) {
  1207. DbgPrint(L"ftasr: Build FT disk failed - parent break failed with %ld\n", GetLastError());
  1208. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_UNEXPECTED);
  1209. goto _cleanup;
  1210. }
  1211. for (i = 0; i < ExpectedPathSize; i++) {
  1212. if (ExpectedPath[i] == realPath[k]) {
  1213. ExpectedPath[i] = 0;
  1214. break;
  1215. }
  1216. }
  1217. }
  1218. DbgPrint(L"ftasr: Break candidate %I64X\n", candidate);
  1219. b = FtBreakLogicalDisk(candidate);
  1220. if (!b) {
  1221. DbgPrint(L"ftasr: Build FT disk - candidate break failed with %ld\n", GetLastError());
  1222. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_UNEXPECTED);
  1223. goto _cleanup;
  1224. }
  1225. candidate = 0;
  1226. if (Existing) {
  1227. *Existing = FALSE;
  1228. }
  1229. // End "Break"
  1230. }
  1231. // End "Use candidate"
  1232. // 7. Take care of not overwriteable members
  1233. if (numNotOverwriteableMembers > 0) {
  1234. ASSERT(candidate == 0);
  1235. if (diskType != FtMirrorSet ||
  1236. numNotOverwriteableMembers > 1) {
  1237. DbgPrint(L"ftasr: Build FT disk failed - too many not overwriteable members\n");
  1238. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_MORE_FORMATTED);
  1239. goto _cleanup;
  1240. }
  1241. // Make sure the not overwriteable member is the winner of the mirror set
  1242. if (notOverwriteableMember > 0) {
  1243. ASSERT(notOverwriteableMember == 1);
  1244. diskId = members[0];
  1245. members[0] = members[notOverwriteableMember];
  1246. members[notOverwriteableMember] = diskId;
  1247. }
  1248. }
  1249. // At this moment we have to create a brand new logical disk
  1250. ASSERT(candidate == 0);
  1251. ASSERT(!Existing || !(*Existing));
  1252. // 8. Check whether all members are valid
  1253. if (numInvalidNewMembers > 0) {
  1254. DbgPrint(L"ftasr: Build FT disk failed - invalid members\n");
  1255. candidate = 0;
  1256. goto _cleanup;
  1257. }
  1258. // 9. If we create a stripe or a swp take every old member and
  1259. // delete its file system info
  1260. /*
  1261. //If we create a stripe or a swp take every old member and call
  1262. //DeleteFileSystemInfo().
  1263. //This is to prevent those annoying popups "The file or directory ... is
  1264. //corrupt and unreadable."
  1265. if (diskType == FtStripeSet || diskType == FtStripeSetWithParity) {
  1266. for (i = 0; i < numMembers; i++) {
  1267. if (existingMembers[i]) {
  1268. ASSERT(members[i]);
  1269. if (DeleteFileSystemInfo(members[i])) {
  1270. DbgPrint(L"ftasr: Build FT disk - file system info deleted successfully for %I64X\n", members[i]);
  1271. } else {
  1272. DbgPrint(L"ftasr: Build FT disk - delete file system info failed for %I64X\n", members[i]);
  1273. }
  1274. }
  1275. }
  1276. }
  1277. */
  1278. // 10. If we try to mirror the boot volume make sure the second member is
  1279. // at least as large as the boot volume (which should be the first member
  1280. // because of step 7)
  1281. if (diskType == FtMirrorSet) {
  1282. ASSERT(members[0]);
  1283. ASSERT(members[1]);
  1284. r = IsSystemOrBootVolume(members[0], &isSystem, &isBoot);
  1285. if( r != ERROR_SUCCESS) {
  1286. DbgPrint(L"ftasr: Build FT disk failed - IsSystemOrBootVolume failed with %lu", r);
  1287. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME, r);
  1288. goto _cleanup;
  1289. }
  1290. if (isBoot) {
  1291. if (!FtQueryLogicalDiskInformation(members[0], NULL, &size0, 0,
  1292. NULL, NULL, 0, NULL, 0, NULL) ||
  1293. !FtQueryLogicalDiskInformation(members[1], NULL, &size1, 0,
  1294. NULL, NULL, 0, NULL, 0, NULL) ||
  1295. (size0 > size1) ) {
  1296. DbgPrint(L"ftasr: Build FT disk - cannot mirror the boot volume\n");
  1297. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_MIRROR_BOOT_VOLUME);
  1298. goto _cleanup;
  1299. }
  1300. }
  1301. }
  1302. // 11. "Create" - No candidate.Create a brand new logical disk
  1303. if (!FtCreateLogicalDisk(diskType, (USHORT) numMembers, members,
  1304. (USHORT) configSize, config, &candidate)) {
  1305. DbgPrint(L"ftasr: Build FT disk failed - logical disk creation failed\n");
  1306. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME, GetLastError());
  1307. candidate = 0;
  1308. goto _cleanup;
  1309. }
  1310. DbgPrint(L"ftasr: Build FT disk succeeded - logical disk created successfully. DiskId = %I64X\n", candidate);
  1311. // Stop synchronization at this moment
  1312. FtStopSyncOperations(candidate);
  1313. if (Overwriteable) {
  1314. *Overwriteable = (numNotOverwriteableMembers == 0);
  1315. }
  1316. _cleanup:
  1317. LocalFree(members);
  1318. LocalFree(existingMembers);
  1319. return candidate;
  1320. }
  1321. FT_LOGICAL_DISK_ID
  1322. CFtasrDlg::CreateFtPartition(
  1323. IN ULONG Signature,
  1324. IN LONGLONG Offset,
  1325. IN LONGLONG Length,
  1326. OUT PBOOL Overwriteable
  1327. )
  1328. /*++
  1329. Routine Description:
  1330. This routine creates an FT partition based on a disk partition
  1331. Arguments:
  1332. Signature - Supplies the signature of the disk partition
  1333. Offset - Supplies the offset of the disk partition
  1334. Length - Supplies the length of the disk partition
  1335. Overwriteable - Returns TRUE if the partition can be overwritten later in the FT ASR process
  1336. If FALSE we should avoid building an FT set on top of it that may destroy the content of the partition
  1337. FALSE if the partition is already formatted and contains data.
  1338. Return Value:
  1339. The id of the FT partition. 0 if the creation failed
  1340. --*/
  1341. {
  1342. ULONG s;
  1343. LONGLONG o, l, bestDelta, newDelta;
  1344. HANDLE h, hh, best;
  1345. WCHAR volumeName[MAX_PATH], bestVolName[MAX_PATH];
  1346. FT_LOGICAL_DISK_ID diskId;
  1347. long r;
  1348. BOOL b;
  1349. WCHAR fileSystem[100];
  1350. DbgPrint(L"ftasr: Create FT partition: Signature = %lX, Offset = %I64X, Length = %I64X\n",
  1351. Signature, Offset, Length);
  1352. *Overwriteable = TRUE;
  1353. h = FindFirstVolume(volumeName, MAX_PATH);
  1354. if (h == INVALID_HANDLE_VALUE) {
  1355. DbgPrint(L"ftasr: Create FT partition failed - FindFirstVolume failed\n");
  1356. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_PARTITION_NOT_FOUND);
  1357. return 0;
  1358. }
  1359. bestDelta = -1;
  1360. for (;;) {
  1361. volumeName[lstrlen(volumeName) - 1] = 0;
  1362. hh = CreateFile(volumeName, GENERIC_READ | GENERIC_WRITE,
  1363. FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,
  1364. OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  1365. INVALID_HANDLE_VALUE);
  1366. if (hh == INVALID_HANDLE_VALUE) {
  1367. DbgPrint(L"ftasr: Create FT partition failed - Volume opening failed\n");
  1368. continue;
  1369. }
  1370. if (QueryPartitionInformation(hh, &s, &o, &l) && s == Signature &&
  1371. l >= Length) {
  1372. if (o > Offset) {
  1373. newDelta = o - Offset;
  1374. } else {
  1375. newDelta = Offset - o;
  1376. }
  1377. if (bestDelta == -1 ||
  1378. newDelta < bestDelta) {
  1379. if (bestDelta >= 0 ) {
  1380. CloseHandle(best);
  1381. }
  1382. bestDelta = newDelta;
  1383. best = hh;
  1384. wcscpy(bestVolName, volumeName);
  1385. } else {
  1386. CloseHandle(hh);
  1387. }
  1388. } else {
  1389. CloseHandle(hh);
  1390. }
  1391. if (!FindNextVolume(h, volumeName, MAX_PATH)) {
  1392. break;
  1393. }
  1394. }
  1395. FindVolumeClose(h);
  1396. if (bestDelta < 0) {
  1397. DisplayResourceResourceError(IDS_ERROR_RESTORE_VOLUME, IDS_ERROR_PARTITION_NOT_FOUND);
  1398. return 0;
  1399. }
  1400. b = FtCreatePartitionLogicalDisk(best, &diskId);
  1401. r = GetLastError();
  1402. CloseHandle(best);
  1403. if (!b) {
  1404. DbgPrint(L"ftasr: Create FT partition failed - FtCreatePartitionLogicalDisk failed\n");
  1405. DisplayResourceSystemError(IDS_ERROR_RESTORE_VOLUME, r);
  1406. return 0;
  1407. }
  1408. // Check whether the partition is formatted
  1409. wcscat(bestVolName, L"\\");
  1410. b = GetVolumeInformation(bestVolName, NULL, 0, NULL, NULL, NULL, fileSystem, 100);
  1411. if (b) {
  1412. DbgPrint(L"ftasr: Create FT partition - GetVolumeInformation returned %s\n", fileSystem);
  1413. if (wcscmp(fileSystem, L"RAW")) {
  1414. *Overwriteable = FALSE;
  1415. }
  1416. } else {
  1417. r = GetLastError();
  1418. DbgPrint(L"ftasr: Create FT partition - GetVolumeInformation failed with %lu\n", r);
  1419. }
  1420. DbgPrint(L"ftasr: Create FT partition succeeded: DiskId = %I64X %s\n", diskId, *Overwriteable ? L"" : L"Formatted");
  1421. return diskId;
  1422. }
  1423. BOOL
  1424. CFtasrDlg::QueryPartitionInformation(
  1425. IN HANDLE Handle,
  1426. OUT PDWORD Signature,
  1427. OUT PLONGLONG Offset,
  1428. OUT PLONGLONG Length
  1429. )
  1430. /*++
  1431. Routine Description:
  1432. This routine returns the signature, offset and length of a partition
  1433. Arguments:
  1434. Handle - Supplies a handle to an open partition
  1435. Signature - Returns the signature of the partition
  1436. Offset - Returns the offset of the partition
  1437. Length - Returns the length of the partition
  1438. Return Value:
  1439. TRUE if the query succeeded
  1440. --*/
  1441. {
  1442. BOOL b;
  1443. STORAGE_DEVICE_NUMBER number;
  1444. DWORD bytes;
  1445. WCHAR diskName[MAX_PATH];
  1446. HANDLE h;
  1447. PDRIVE_LAYOUT_INFORMATION layout;
  1448. PARTITION_INFORMATION partInfo;
  1449. b = DeviceIoControl(Handle, IOCTL_STORAGE_GET_DEVICE_NUMBER, NULL, 0,
  1450. &number, sizeof(number), &bytes, NULL);
  1451. if (!b || number.PartitionNumber == -1 || number.PartitionNumber == 0) {
  1452. return FALSE;
  1453. }
  1454. swprintf(diskName, L"\\\\.\\PhysicalDrive%d", number.DeviceNumber);
  1455. h = CreateFile(diskName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE,
  1456. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  1457. INVALID_HANDLE_VALUE);
  1458. if (h == INVALID_HANDLE_VALUE) {
  1459. return FALSE;
  1460. }
  1461. layout = (PDRIVE_LAYOUT_INFORMATION)LocalAlloc(0, 4096);
  1462. if (!layout) {
  1463. CloseHandle(h);
  1464. return FALSE;
  1465. }
  1466. b = DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL, 0,
  1467. layout, 4096, &bytes, NULL);
  1468. if (!b) {
  1469. LocalFree(layout);
  1470. CloseHandle(h);
  1471. return FALSE;
  1472. }
  1473. *Signature = layout->Signature;
  1474. LocalFree(layout);
  1475. CloseHandle(h);
  1476. b = DeviceIoControl(Handle, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0,
  1477. &partInfo, sizeof(partInfo), &bytes, NULL);
  1478. if (!b) {
  1479. return b;
  1480. }
  1481. *Offset = partInfo.StartingOffset.QuadPart;
  1482. *Length = partInfo.PartitionLength.QuadPart;
  1483. return b;
  1484. }
  1485. /****************************************************************************************************/
  1486. /* */
  1487. /* Method FtGetParentLogicalDisk should be a ftapi call based on a ftdisk IOCTL. When this will */
  1488. /* happen the next two methods will disappear from this code. */
  1489. /* */
  1490. /****************************************************************************************************/
  1491. BOOL
  1492. CFtasrDlg::GetParentLogicalDiskInVolume(
  1493. IN FT_LOGICAL_DISK_ID VolumeId,
  1494. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1495. OUT PFT_LOGICAL_DISK_ID ParentId
  1496. )
  1497. /*++
  1498. Routine Description:
  1499. This routine search for a logical disk inside a (sub)volume and
  1500. returns the logical disk id of its parent.
  1501. Arguments:
  1502. VolumeId - Supplies the id of the (sub)volume.
  1503. LogicalDiskId - Supplies the id of the logical disk.
  1504. ParentId - Returns the id of the parent.
  1505. 0 if the disk is not found inside the volume.
  1506. Return Value:
  1507. FALSE - Failure to search for the given disk.
  1508. TRUE - The search succeeded. The value returned in ParentId is valid
  1509. --*/
  1510. {
  1511. WORD numberOfMembers, i;
  1512. PFT_LOGICAL_DISK_ID members;
  1513. FT_LOGICAL_DISK_ID parentId;
  1514. BOOL b, result;
  1515. *ParentId = 0;
  1516. b = FtQueryLogicalDiskInformation(
  1517. VolumeId, NULL, NULL, 0, NULL, &numberOfMembers,
  1518. 0, NULL, 0, NULL);
  1519. if (!b) {
  1520. return FALSE;
  1521. }
  1522. if (numberOfMembers > 0 ) {
  1523. members = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numberOfMembers * sizeof(FT_LOGICAL_DISK_ID));
  1524. if (!members) {
  1525. return FALSE;
  1526. }
  1527. b = FtQueryLogicalDiskInformation(
  1528. VolumeId, NULL, NULL, numberOfMembers, members, &numberOfMembers,
  1529. 0, NULL, 0, NULL);
  1530. if (!b) {
  1531. LocalFree(members);
  1532. return FALSE;
  1533. }
  1534. } else {
  1535. members = NULL;
  1536. }
  1537. result = TRUE;
  1538. for (i = 0; i < numberOfMembers; i++) {
  1539. if (members[i] == LogicalDiskId) {
  1540. *ParentId = VolumeId;
  1541. result = TRUE;
  1542. break;
  1543. }
  1544. b = GetParentLogicalDiskInVolume(members[i], LogicalDiskId, &parentId);
  1545. if (!b) {
  1546. result = FALSE;
  1547. continue;
  1548. }
  1549. if (parentId) {
  1550. *ParentId = parentId;
  1551. result = TRUE;
  1552. break;
  1553. }
  1554. }
  1555. if (members) {
  1556. LocalFree(members);
  1557. }
  1558. return result;
  1559. }
  1560. BOOL
  1561. CFtasrDlg::FtGetParentLogicalDisk(
  1562. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1563. OUT PFT_LOGICAL_DISK_ID ParentId
  1564. )
  1565. /*++
  1566. Routine Description:
  1567. This routine returns the parent of a logical disk
  1568. Arguments:
  1569. LogicalDiskId - Supplies the id of the logical disk.
  1570. ParentId - Returns the id of the parent.
  1571. 0 if the disk doesn't exist or has no parent
  1572. Return Value:
  1573. FALSE - Failure to search for the given disk.
  1574. TRUE - The search succeeded. The value returned in ParentId is valid
  1575. --*/
  1576. {
  1577. BOOL b, result;
  1578. PFT_LOGICAL_DISK_ID diskId;
  1579. FT_LOGICAL_DISK_ID parentId;
  1580. DWORD numDisks, i;
  1581. *ParentId = 0;
  1582. b = FtEnumerateLogicalDisks(0, NULL, &numDisks);
  1583. if (!b) {
  1584. return FALSE;
  1585. }
  1586. if (numDisks > 0) {
  1587. diskId = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numDisks*sizeof(FT_LOGICAL_DISK_ID));
  1588. if (!diskId) {
  1589. return FALSE;
  1590. }
  1591. b = FtEnumerateLogicalDisks(numDisks, diskId, &numDisks);
  1592. if (!b) {
  1593. LocalFree(diskId);
  1594. return FALSE;
  1595. }
  1596. } else {
  1597. diskId = NULL;
  1598. }
  1599. result = TRUE;
  1600. for (i = 0; i < numDisks; i++) {
  1601. if (diskId[i] == LogicalDiskId) {
  1602. result = TRUE;
  1603. break;
  1604. }
  1605. b = GetParentLogicalDiskInVolume(diskId[i], LogicalDiskId, &parentId);
  1606. if (!b) {
  1607. result = FALSE;
  1608. continue;
  1609. }
  1610. if (parentId) {
  1611. *ParentId = parentId;
  1612. result = TRUE;
  1613. break;
  1614. }
  1615. }
  1616. if (diskId) {
  1617. LocalFree(diskId);
  1618. }
  1619. return result;
  1620. }
  1621. BOOL
  1622. CFtasrDlg::GetPathFromLogicalDiskToRoot(
  1623. IN FT_LOGICAL_DISK_ID LogicalDiskId,
  1624. OUT PFT_LOGICAL_DISK_ID Path,
  1625. OUT PWORD PathSize
  1626. )
  1627. /*++
  1628. Routine Description:
  1629. This routine returns all forefathers of a logical disk starting with its
  1630. parent and ending with a root logical disk
  1631. Arguments:
  1632. LogicalDiskId - Supplies the id of the logical disk
  1633. Path - Returns the forefathers of the logical disk.
  1634. The size of the array is maximum MAX_STACK_DEPTH
  1635. PathSize - Returns the number of forefathers
  1636. Return Value:
  1637. TRUE if all forefathers were found and added to Path
  1638. --*/
  1639. {
  1640. FT_LOGICAL_DISK_ID diskId;
  1641. WORD i;
  1642. BOOL b;
  1643. diskId = LogicalDiskId;
  1644. for (i = 0; i < MAX_STACK_DEPTH; i++) {
  1645. b = FtGetParentLogicalDisk(diskId, &(Path[i]));
  1646. if (!b) {
  1647. return FALSE;
  1648. }
  1649. diskId = Path[i];
  1650. if (!diskId) {
  1651. break;
  1652. }
  1653. }
  1654. if (i >= MAX_STACK_DEPTH) {
  1655. return FALSE;
  1656. }
  1657. *PathSize = i;
  1658. return TRUE;
  1659. }
  1660. /*********************************************************************************************/
  1661. /* Some methods used to check for FT configurations not supported by ftasr at this moment */
  1662. /*********************************************************************************************/
  1663. #ifdef CHECK_UNSUPPORTED_CONFIG
  1664. long
  1665. CFtasrDlg::CheckForUnsupportedConfig(
  1666. IN DWORD NumDisks,
  1667. IN PFT_LOGICAL_DISK_ID ArrayOfDiskId
  1668. )
  1669. /*++
  1670. Routine Description:
  1671. This routine check if the current FT configuration is supported by ASR.
  1672. Supported configurations are:
  1673. - Mirrored boot and system partition filling the entire disk
  1674. - Mirrored boot partition and mirrored system partition, saharing the same disk and filling it completely
  1675. - Data volume sets whose members fill their disks completely
  1676. - Data stripe sets whose members fill their disks completely
  1677. Arguments:
  1678. NumDisks - Supplies the number of root FT volumes
  1679. ArrayOfDiskId - Supplies the Id's of the root FT volumes
  1680. Return Value:
  1681. ERROR_SUCCESS if the restore succeeded. Other error codes for failure
  1682. --*/
  1683. {
  1684. DWORD i, j;
  1685. FT_LOGICAL_DISK_ID diskId;
  1686. WORD numMembers;
  1687. PFT_LOGICAL_DISK_ID members;
  1688. FT_LOGICAL_DISK_TYPE diskType;
  1689. BOOL b;
  1690. BOOL isSystem;
  1691. BOOL isBoot;
  1692. long r;
  1693. FT_LOGICAL_DISK_TYPE memberType;
  1694. LONGLONG memberSize;
  1695. CHAR configInfo[100];
  1696. PFT_PARTITION_CONFIGURATION_INFORMATION partConfig;
  1697. DISK_GEOMETRY geometry;
  1698. LONGLONG cylinderSize;
  1699. WORD numMirrors = 0;
  1700. DWORD lastMirrorFirstMemberDiskNumber;
  1701. LONGLONG lastMirrorFirstMemberByteOffset;
  1702. LONGLONG lastMirrorFirstMemberSize;
  1703. for (i = 0; i < NumDisks; i++) {
  1704. diskId = ArrayOfDiskId[i];
  1705. b = FtQueryLogicalDiskInformation(diskId, &diskType, NULL,
  1706. 0, NULL, &numMembers, 0, NULL, 0, NULL);
  1707. if (!b) {
  1708. r = GetLastError();
  1709. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1710. return r;
  1711. }
  1712. switch(diskType) {
  1713. case FtMirrorSet:
  1714. case FtVolumeSet:
  1715. case FtStripeSet:
  1716. break;
  1717. case FtPartition:
  1718. DisplayResourceResourceError(IDS_ERROR_FTPARTITION_DETECTED, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1719. return ERROR_NOT_SUPPORTED;
  1720. case FtStripeSetWithParity:
  1721. DisplayResourceResourceError(IDS_ERROR_SWP_DETECTED, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1722. return ERROR_NOT_SUPPORTED;
  1723. case FtRedistribution:
  1724. DisplayResourceResourceError(IDS_ERROR_REDISTRIBUTION_DETECTED, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1725. return ERROR_NOT_SUPPORTED;
  1726. default:
  1727. DisplayResourceError(IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1728. return ERROR_NOT_SUPPORTED;
  1729. }
  1730. r = IsSystemOrBootVolume(diskId, &isSystem, &isBoot);
  1731. if (r != ERROR_SUCCESS) {
  1732. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1733. return r;
  1734. }
  1735. if(diskType == FtMirrorSet) {
  1736. if (!isSystem && !isBoot) {
  1737. DisplayResourceResourceError(IDS_ERROR_NOT_BOOT_SYSTEM_MIRROR, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1738. return ERROR_NOT_SUPPORTED;
  1739. }
  1740. } else { // Volume set or stripe set
  1741. if (isSystem || isBoot) {
  1742. DisplayResourceResourceError(IDS_ERROR_BOOT_SYSTEM_NOT_MIRROR, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1743. return ERROR_NOT_SUPPORTED;
  1744. }
  1745. }
  1746. members = (PFT_LOGICAL_DISK_ID)LocalAlloc(0, numMembers*sizeof(FT_LOGICAL_DISK_ID));
  1747. if (!members) {
  1748. r = GetLastError();
  1749. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1750. return r;
  1751. }
  1752. b = FtQueryLogicalDiskInformation(diskId, &diskType, NULL,
  1753. numMembers, members, &numMembers,
  1754. 0, NULL, 0, NULL);
  1755. if (!b) {
  1756. r = GetLastError();
  1757. LocalFree(members);
  1758. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1759. return r;
  1760. }
  1761. for (j = 0; j < numMembers; j++) {
  1762. b = FtQueryLogicalDiskInformation(members[j], &memberType, &memberSize,
  1763. 0, NULL, NULL, 100, configInfo, 0, NULL);
  1764. if (!b) {
  1765. r = GetLastError();
  1766. LocalFree(members);
  1767. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1768. return r;
  1769. }
  1770. if (memberType != FtPartition) {
  1771. LocalFree(members);
  1772. DisplayResourceResourceError(IDS_ERROR_STACK, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1773. return ERROR_NOT_SUPPORTED;
  1774. }
  1775. partConfig = (PFT_PARTITION_CONFIGURATION_INFORMATION)configInfo;
  1776. if ((diskType != FtMirrorSet) || (j == 0)) {
  1777. r = GetDiskGeometry(partConfig->DiskNumber, &geometry);
  1778. if (r != ERROR_SUCCESS) {
  1779. LocalFree(members);
  1780. DisplayResourceSystemError(IDS_ERROR_CHECK_FAILURE, r);
  1781. return r;
  1782. }
  1783. cylinderSize = geometry.TracksPerCylinder *
  1784. geometry.SectorsPerTrack *
  1785. geometry.BytesPerSector;
  1786. if((diskType != FtMirrorSet) || (isSystem && isBoot)) {
  1787. if (partConfig->ByteOffset < cylinderSize &&
  1788. partConfig->ByteOffset + memberSize >= (geometry.Cylinders.QuadPart - 1) * cylinderSize) {
  1789. // It's OK. The first member of the boot/system mirror fills the entire disk
  1790. } else {
  1791. LocalFree(members);
  1792. switch(diskType) {
  1793. case FtVolumeSet:
  1794. DisplayResourceResourceError(IDS_ERROR_VOLUME_SET_SIZE, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1795. break;
  1796. case FtStripeSet:
  1797. DisplayResourceResourceError(IDS_ERROR_STRIPE_SET_SIZE, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1798. break;
  1799. case FtMirrorSet:
  1800. DisplayResourceResourceError(IDS_ERROR_MIRROR_SET_SIZE, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1801. break;
  1802. }
  1803. return ERROR_NOT_SUPPORTED;
  1804. }
  1805. } else { // Mirror set boot OR system first member
  1806. if (numMirrors == 0) {
  1807. numMirrors++;
  1808. lastMirrorFirstMemberDiskNumber = partConfig->DiskNumber;
  1809. lastMirrorFirstMemberByteOffset = partConfig->ByteOffset;
  1810. lastMirrorFirstMemberSize = memberSize;
  1811. } else { // numMirrors == 1 We cannot find more than one boot and one system mirror
  1812. numMirrors++;
  1813. if (lastMirrorFirstMemberDiskNumber != partConfig->DiskNumber) {
  1814. LocalFree(members);
  1815. DisplayResourceResourceError(IDS_ERROR_MIRRORS_ON_DIFFERENT_DISKS, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1816. return ERROR_NOT_SUPPORTED;
  1817. }
  1818. if ( ( partConfig->ByteOffset < cylinderSize &&
  1819. partConfig->ByteOffset + memberSize + cylinderSize > lastMirrorFirstMemberByteOffset &&
  1820. lastMirrorFirstMemberByteOffset + lastMirrorFirstMemberSize >= (geometry.Cylinders.QuadPart - 1) * cylinderSize
  1821. ) ||
  1822. ( lastMirrorFirstMemberByteOffset < cylinderSize &&
  1823. lastMirrorFirstMemberByteOffset + lastMirrorFirstMemberSize + cylinderSize > partConfig->ByteOffset &&
  1824. partConfig->ByteOffset + memberSize >= (geometry.Cylinders.QuadPart - 1) * cylinderSize
  1825. )
  1826. ) {
  1827. // It's OK. The first members of the two mirrors fill the entire disk
  1828. } else {
  1829. LocalFree(members);
  1830. DisplayResourceResourceError(IDS_ERROR_MIRRORS_SIZES, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1831. return ERROR_NOT_SUPPORTED;
  1832. }
  1833. }
  1834. }
  1835. }
  1836. } // members loop
  1837. LocalFree(members);
  1838. } // disks loop
  1839. if (numMirrors == 1) {
  1840. DisplayResourceResourceError(IDS_ERROR_ONE_MIRROR, IDS_ERROR_UNSUPPORTED_CONFIGURATION);
  1841. return ERROR_NOT_SUPPORTED;
  1842. }
  1843. return ERROR_SUCCESS;
  1844. }
  1845. #define DOSDEV_PREFIX L"\\DosDevices\\"
  1846. long
  1847. CFtasrDlg::IsSystemOrBootVolume(
  1848. IN FT_LOGICAL_DISK_ID DiskId,
  1849. OUT PBOOL IsSystem,
  1850. OUT PBOOL IsBoot
  1851. )
  1852. /*++
  1853. Routine Description:
  1854. This routine check if a FT root volume is the boot and/or system volume
  1855. Arguments:
  1856. DiskId - Supplies the Id of the root FT volume
  1857. IsSystem - Returns TRUE if the volume contains the NT loader files
  1858. IsBoot - Returns TRUE if the volume contains the NT root
  1859. Return Value:
  1860. ERROR_SUCCESS if the restore succeeded. Other error codes for failure
  1861. --*/
  1862. {
  1863. HANDLE h;
  1864. FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_INPUT input1;
  1865. ULONG output1Size;
  1866. PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT output1;
  1867. BOOL b;
  1868. ULONG bytes;
  1869. long r;
  1870. HKEY key = NULL ;
  1871. DWORD disposition;
  1872. WCHAR system[MAX_PATH];
  1873. DWORD valueSize ;
  1874. DWORD type ;
  1875. WCHAR ntPath[MAX_PATH] ;
  1876. ULONG input2Size;
  1877. PMOUNTMGR_MOUNT_POINT input2;
  1878. ULONG output2Size;
  1879. PMOUNTMGR_MOUNT_POINTS output2;
  1880. ULONG i;
  1881. PWSTR symName;
  1882. *IsSystem = FALSE;
  1883. *IsBoot = FALSE;
  1884. // First get the NT volume name of the logical disk
  1885. h = CreateFile(L"\\\\.\\FtControl", GENERIC_READ,
  1886. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  1887. NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL,
  1888. INVALID_HANDLE_VALUE);
  1889. if (h == INVALID_HANDLE_VALUE){
  1890. return GetLastError();
  1891. }
  1892. input1.RootLogicalDiskId = DiskId;
  1893. output1Size = MAX_PATH;
  1894. output1 = (PFT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK_OUTPUT)LocalAlloc(0, output1Size);
  1895. if (!output1)
  1896. {
  1897. r = GetLastError();
  1898. CloseHandle(h);
  1899. return r;
  1900. }
  1901. b = DeviceIoControl(h, FT_QUERY_NT_DEVICE_NAME_FOR_LOGICAL_DISK, &input1,
  1902. sizeof(input1), output1, output1Size, &bytes, NULL);
  1903. r = GetLastError();
  1904. CloseHandle(h);
  1905. if (!b) {
  1906. LocalFree(output1);
  1907. return r;
  1908. }
  1909. //output1->NtDeviceName,
  1910. //output1->NumberOfCharactersInNtDeviceName
  1911. output1->NtDeviceName[output1->NumberOfCharactersInNtDeviceName] = L'\0';
  1912. // Second get the NT volume name of the system partition from HKLM:\SYSTEM\Setup
  1913. r = RegCreateKeyEx( HKEY_LOCAL_MACHINE,
  1914. L"SYSTEM\\SETUP",
  1915. 0,
  1916. NULL,
  1917. 0,
  1918. KEY_READ,
  1919. NULL,
  1920. &key,
  1921. &disposition);
  1922. if (r != ERROR_SUCCESS) {
  1923. LocalFree(output1);
  1924. return r;
  1925. }
  1926. valueSize = sizeof(system) ;
  1927. r = RegQueryValueEx(key,
  1928. L"SystemPartition",
  1929. NULL,
  1930. &type,
  1931. (PBYTE)system,
  1932. &valueSize);
  1933. if (r != ERROR_SUCCESS) {
  1934. LocalFree(output1);
  1935. return r;
  1936. }
  1937. // Compare the logical disk NT volume name with the system volume name
  1938. if (!wcscmp(output1->NtDeviceName, system)) {
  1939. *IsSystem = TRUE;
  1940. }
  1941. // Third get the boot volume path
  1942. b = GetEnvironmentVariable(L"SystemRoot", ntPath, MAX_PATH);
  1943. if (!b) {
  1944. LocalFree(output1);
  1945. return ERROR_SUCCESS;
  1946. }
  1947. // Then compare its drive letter with our logical disk drive letter
  1948. h = CreateFile( MOUNTMGR_DOS_DEVICE_NAME,
  1949. GENERIC_READ | GENERIC_WRITE,
  1950. FILE_SHARE_READ | FILE_SHARE_WRITE,
  1951. NULL,
  1952. OPEN_EXISTING,
  1953. FILE_ATTRIBUTE_NORMAL,
  1954. INVALID_HANDLE_VALUE );
  1955. if (h == INVALID_HANDLE_VALUE) {
  1956. r = GetLastError();
  1957. LocalFree(output1);
  1958. return r;
  1959. }
  1960. input2Size = sizeof(MOUNTMGR_MOUNT_POINT) + ((output1->NumberOfCharactersInNtDeviceName + 1)*sizeof(WCHAR));
  1961. input2 = (PMOUNTMGR_MOUNT_POINT)LocalAlloc(0, input2Size);
  1962. if (!input2)
  1963. {
  1964. r = GetLastError();
  1965. CloseHandle(h);
  1966. LocalFree(output1);
  1967. return r;
  1968. }
  1969. input2->SymbolicLinkNameLength = 0;
  1970. input2->SymbolicLinkNameOffset = 0;
  1971. input2->UniqueIdOffset = 0;
  1972. input2->UniqueIdLength = 0;
  1973. input2->DeviceNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  1974. input2->DeviceNameLength = output1->NumberOfCharactersInNtDeviceName * sizeof(WCHAR);
  1975. wcscpy((PWSTR)((PCHAR)input2 + input2->DeviceNameOffset), output1->NtDeviceName);
  1976. LocalFree(output1);
  1977. output2Size = sizeof(MOUNTMGR_MOUNT_POINTS) + 1024;
  1978. output2 = (PMOUNTMGR_MOUNT_POINTS)LocalAlloc(0, output2Size);
  1979. if (!output2) {
  1980. r = GetLastError();
  1981. CloseHandle(h);
  1982. LocalFree(input2);
  1983. return r;
  1984. }
  1985. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, input2, input2Size,
  1986. output2, output2Size, &bytes, NULL);
  1987. r = GetLastError();
  1988. while (!b && r == ERROR_MORE_DATA)
  1989. {
  1990. output2Size = output2->Size;
  1991. LocalFree(output2);
  1992. output2 = (PMOUNTMGR_MOUNT_POINTS)LocalAlloc(0, output2Size);
  1993. if (!output2)
  1994. {
  1995. r = GetLastError();
  1996. CloseHandle(h);
  1997. LocalFree(input2);
  1998. return r;
  1999. }
  2000. b = DeviceIoControl(h, IOCTL_MOUNTMGR_QUERY_POINTS, input2, input2Size,
  2001. output2, output2Size, &bytes, NULL);
  2002. r = GetLastError();
  2003. }
  2004. CloseHandle(h);
  2005. LocalFree(input2);
  2006. if (!b) {
  2007. LocalFree(output2);
  2008. return r;
  2009. }
  2010. for (i = 0; i < output2->NumberOfMountPoints; i++) {
  2011. symName = (PWSTR)( (PCHAR)output2 + output2->MountPoints[i].SymbolicLinkNameOffset) ;
  2012. if (!wcsncmp(DOSDEV_PREFIX, symName, wcslen(DOSDEV_PREFIX))) {
  2013. if (ntPath[0] == symName[wcslen(DOSDEV_PREFIX)]) {
  2014. *IsBoot = TRUE;
  2015. }
  2016. }
  2017. }
  2018. LocalFree(output2);
  2019. return ERROR_SUCCESS;
  2020. }
  2021. long
  2022. CFtasrDlg::GetDiskGeometry(
  2023. ULONG DiskNumber,
  2024. PDISK_GEOMETRY Geometry
  2025. )
  2026. /*++
  2027. Routine Description:
  2028. This routine retrieves the geometry of the given disk
  2029. Arguments:
  2030. DiskNumber - Supplies the disk number (0, 1, 2 ...)
  2031. Geometry - Returns the disk geometry
  2032. Return Value:
  2033. ERROR_SUCCESS if the restore succeeded. Other error codes for failure
  2034. --*/
  2035. {
  2036. WCHAR name[50];
  2037. ULONG bytes;
  2038. HANDLE h;
  2039. BOOL b;
  2040. long r;
  2041. wsprintf(name, L"\\\\.\\PHYSICALDRIVE%lu", DiskNumber);
  2042. h = CreateFile(name, GENERIC_READ,
  2043. FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
  2044. NULL, OPEN_EXISTING, 0 , INVALID_HANDLE_VALUE );
  2045. if (h == INVALID_HANDLE_VALUE) {
  2046. return GetLastError();
  2047. }
  2048. b = DeviceIoControl(h, IOCTL_DISK_GET_DRIVE_GEOMETRY, NULL, 0,
  2049. Geometry, sizeof(DISK_GEOMETRY), &bytes, NULL );
  2050. r = GetLastError();
  2051. CloseHandle(h);
  2052. if (!b) {
  2053. return r;
  2054. }
  2055. return ERROR_SUCCESS;
  2056. }
  2057. #endif // #ifdef CHECK_UNSUPPORTED_CONFIG
  2058. /*
  2059. BOOL
  2060. CFtasrDlg::DeleteFileSystemInfo(
  2061. IN FT_LOGICAL_DISK_ID LogicalDiskId )
  2062. {
  2063. // This should be done only for partitions.
  2064. // We have to fill the first sector of the partition with zeroes. There is
  2065. // the file system info stored.
  2066. //1. Open the volume READ & WRITE, FILE_SHARE_EVERYTHING ....
  2067. //2. GET_DISK_GEOMETRY ---> get SectorSize
  2068. //3. Allocate a buffer 2*SectorSize
  2069. //4. Choose the first address in the buffer which is multiple of sector size
  2070. //5. Fill the buffer with zeroes
  2071. //6. DeviceIoControl FSCTL_LOCK_VOLUME
  2072. //7. SetFilePointer to the beginning of the file
  2073. //8. WriteFile (address multiple of SectorSize in the buffer, SectorSize)
  2074. //9. CloseHandle
  2075. //If one of them doesn't work, don't worry! All that can happen is to keep
  2076. //getting those annoying popups
  2077. }
  2078. */