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.

4680 lines
142 KiB

  1. /*++
  2. Copyright (c) 2000 Microsoft Corporation
  3. Module Name:
  4. asrrest.c
  5. Abstract:
  6. This module contains the following ASR routine:
  7. AsrRestoreNonCriticalDisks{A|W}
  8. This routine is called in GUI mode ASR, to reconfigure
  9. the non-critical storage devices on the target machine.
  10. Notes:
  11. Naming conventions:
  12. _AsrpXXX private ASR Macros
  13. AsrpXXX private ASR routines
  14. AsrXXX Publically defined and documented routines
  15. Author:
  16. Guhan Suriyanarayanan (guhans) 27-May-2000
  17. Environment:
  18. User-mode only.
  19. Revision History:
  20. 27-May-2000 guhans
  21. Moved AsrRestoreNonCriticalDisks and other restore-time
  22. routines from asr.c to asrrest.c
  23. 01-Jan-2000 guhans
  24. Initial implementation for AsrRestoreNonCriticalDisks
  25. in asr.c
  26. --*/
  27. #include "setupp.h"
  28. #pragma hdrstop
  29. #include <diskguid.h> // GPT partition type guids
  30. #include <mountmgr.h> // mountmgr ioctls
  31. #include <winasr.h> // ASR public routines
  32. #define THIS_MODULE 'R'
  33. #include "asrpriv.h" // Private ASR definitions and routines
  34. //
  35. // --------
  36. // typedefs and constants used within this module
  37. // --------
  38. //
  39. typedef enum _ASR_SORT_ORDER {
  40. SortByLength,
  41. SortByStartingOffset
  42. } ASR_SORT_ORDER;
  43. typedef struct _ASR_REGION_INFO {
  44. struct _ASR_REGION_INFO *pNext;
  45. LONGLONG StartingOffset;
  46. LONGLONG RegionLength;
  47. DWORD Index;
  48. } ASR_REGION_INFO, *PASR_REGION_INFO;
  49. #define ASR_AUTO_EXTEND_MAX_FREE_SPACE_IGNORED (1024 * 1024 * 16)
  50. //
  51. // --------
  52. // function implementations
  53. // --------
  54. //
  55. LONGLONG
  56. AsrpRoundUp(
  57. IN CONST LONGLONG Number,
  58. IN CONST LONGLONG Base
  59. )
  60. /*++
  61. Routine Description:
  62. Helper function to round-up a number to a multiple of a given base.
  63. Arguments:
  64. Number - The number to be rounded up.
  65. Base - The base using which Number is to be rounded-up.
  66. Return Value:
  67. The first multiple of Base that is greater than or equal to Number.
  68. --*/
  69. {
  70. if (Number % Base) {
  71. return (Number + Base - (Number % Base));
  72. }
  73. else {
  74. return Number; // already a multiple of Base.
  75. }
  76. }
  77. VOID
  78. AsrpCreatePartitionTable(
  79. IN OUT PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx,
  80. IN PASR_PTN_INFO_LIST pPtnInfoList,
  81. IN DWORD BytesPerSector
  82. )
  83. /*++
  84. Routine Description:
  85. This creates a partition table based on the partition information
  86. (pPtnInfoList) passed in
  87. Arguments:
  88. // needed to convert between sector count and byte offset
  89. Return Value:
  90. If the function succeeds, the return value is a nonzero value.
  91. If the function fails, the return value is zero. To get extended error
  92. information, call GetLastError().
  93. --*/
  94. {
  95. DWORD index = 0,
  96. NumEntries = 0;
  97. PPARTITION_INFORMATION_EX currentPtn = NULL;
  98. PASR_PTN_INFO pPtnInfo = NULL;
  99. MYASSERT(pDriveLayoutEx);
  100. if (!pDriveLayoutEx || !pPtnInfoList || !(pPtnInfoList->pOffsetHead)) {
  101. return;
  102. }
  103. if (PARTITION_STYLE_GPT == pDriveLayoutEx->PartitionStyle) {
  104. NumEntries = pDriveLayoutEx->Gpt.MaxPartitionCount;
  105. }
  106. else if (PARTITION_STYLE_MBR == pDriveLayoutEx->PartitionStyle) {
  107. NumEntries = pDriveLayoutEx->PartitionCount;
  108. }
  109. else {
  110. MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)");
  111. return;
  112. }
  113. //
  114. // Zero out the entire partition table first
  115. //
  116. for (index = 0; index < NumEntries; index++) {
  117. currentPtn = &(pDriveLayoutEx->PartitionEntry[index]);
  118. currentPtn->StartingOffset.QuadPart = 0;
  119. currentPtn->PartitionLength.QuadPart = 0;
  120. }
  121. //
  122. // Now go through each of the partitions in the list, and add their entry
  123. // to the partition table (at index = SlotIndex)
  124. //
  125. pPtnInfo = pPtnInfoList->pOffsetHead;
  126. while (pPtnInfo) {
  127. //
  128. // For GPT partitions, SlotIndex is 0-based without holes
  129. //
  130. currentPtn = &(pDriveLayoutEx->PartitionEntry[pPtnInfo->SlotIndex]);
  131. MYASSERT(0 == currentPtn->StartingOffset.QuadPart); // this entry better be empty
  132. //
  133. // Convert the StartSector and SectorCount to BYTE-Offset and BYTE-Count ...
  134. //
  135. pPtnInfo->PartitionInfo.StartingOffset.QuadPart *= BytesPerSector;
  136. pPtnInfo->PartitionInfo.PartitionLength.QuadPart *= BytesPerSector;
  137. //
  138. // Copy the partition-information struct over
  139. //
  140. memcpy(currentPtn, &(pPtnInfo->PartitionInfo), sizeof(PARTITION_INFORMATION_EX));
  141. currentPtn->RewritePartition = TRUE;
  142. currentPtn->PartitionStyle = pDriveLayoutEx->PartitionStyle;
  143. pPtnInfo = pPtnInfo->pOffsetNext;
  144. }
  145. }
  146. //
  147. //
  148. //
  149. ULONG64
  150. AsrpStringToULong64(
  151. IN PWSTR String
  152. )
  153. /*++
  154. Routine Description:
  155. Arguments:
  156. Return Value:
  157. If the function succeeds, the return value is a nonzero value.
  158. If the function fails, the return value is zero. To get extended error
  159. information, call GetLastError().
  160. --*/
  161. {
  162. ULONG64 result = 0, base = 10;
  163. BOOL negative = FALSE, done = FALSE;
  164. if (!String) {
  165. return 0;
  166. }
  167. if (L'-' == *String) { // But this is ULONG!
  168. negative = TRUE;
  169. String++;
  170. }
  171. if (L'0' == *String &&
  172. (L'x' == *(String + 1) || L'X' == *(String + 1))
  173. ) {
  174. // Hex
  175. base = 16;
  176. String += 2;
  177. }
  178. while (!done) {
  179. done = TRUE;
  180. if (L'0' <= *String && L'9' >= *String) {
  181. result = result*base + (*String - L'0');
  182. String++;
  183. done = FALSE;
  184. }
  185. else if (16==base) {
  186. if (L'a' <= *String && L'f' >= *String) {
  187. result = result*base + (*String - L'a') + 10;
  188. String++;
  189. done = FALSE;
  190. }
  191. else if (L'A' <= *String && L'F' >= *String) {
  192. result = result*base + (*String - L'A') + 10;
  193. String++;
  194. done = FALSE;
  195. }
  196. }
  197. }
  198. if (negative) {
  199. result = 0 - result;
  200. }
  201. return result;
  202. }
  203. LONGLONG
  204. AsrpStringToLongLong(
  205. IN PWSTR String
  206. )
  207. /*++
  208. Routine Description:
  209. Arguments:
  210. Return Value:
  211. If the function succeeds, the return value is a nonzero value.
  212. If the function fails, the return value is zero. To get extended error
  213. information, call GetLastError().
  214. --*/
  215. {
  216. LONGLONG result = 0, base = 10;
  217. BOOL negative = FALSE, done = FALSE;
  218. if (!String) {
  219. return 0;
  220. }
  221. if (L'-' == *String) {
  222. negative = TRUE;
  223. String++;
  224. }
  225. if (L'0' == *String &&
  226. (L'x' == *(String + 1) || L'X' == *(String + 1))
  227. ) {
  228. // Hex
  229. base = 16;
  230. String += 2;
  231. }
  232. while (!done) {
  233. done = TRUE;
  234. if (L'0' <= *String && L'9' >= *String) {
  235. result = result*base + (*String - L'0');
  236. String++;
  237. done = FALSE;
  238. }
  239. else if (16==base) {
  240. if (L'a' <= *String && L'f' >= *String) {
  241. result = result*base + (*String - L'a') + 10;
  242. String++;
  243. done = FALSE;
  244. }
  245. else if (L'A' <= *String && L'F' >= *String) {
  246. result = result*base + (*String - L'A') + 10;
  247. String++;
  248. done = FALSE;
  249. }
  250. }
  251. }
  252. if (negative) {
  253. result = 0 - result;
  254. }
  255. return result;
  256. }
  257. DWORD
  258. AsrpStringToDword(
  259. IN PWSTR String
  260. )
  261. /*++
  262. Routine Description:
  263. Arguments:
  264. Return Value:
  265. If the function succeeds, the return value is a nonzero value.
  266. If the function fails, the return value is zero. To get extended error
  267. information, call GetLastError().
  268. --*/
  269. {
  270. DWORD result = 0, base = 10;
  271. BOOL negative = FALSE, done = FALSE;
  272. if (!String) {
  273. return 0;
  274. }
  275. if (L'-' == *String) { // but this is unsigned!
  276. negative = TRUE;
  277. String++;
  278. }
  279. if (L'0' == *String &&
  280. (L'x' == *(String + 1) || L'X' == *(String + 1))
  281. ) {
  282. // Hex
  283. base = 16;
  284. String += 2;
  285. }
  286. while (!done) {
  287. done = TRUE;
  288. if (L'0' <= *String && L'9' >= *String) {
  289. result = result*base + (*String - L'0');
  290. String++;
  291. done = FALSE;
  292. }
  293. else if (16==base) {
  294. if (L'a' <= *String && L'f' >= *String) {
  295. result = result*base + (*String - L'a') + 10;
  296. String++;
  297. done = FALSE;
  298. }
  299. else if (L'A' <= *String && L'F' >= *String) {
  300. result = result*base + (*String - L'A') + 10;
  301. String++;
  302. done = FALSE;
  303. }
  304. }
  305. }
  306. if (negative) {
  307. result = 0 - result;
  308. }
  309. return result;
  310. }
  311. ULONG
  312. AsrpStringToULong(
  313. IN PWSTR String
  314. )
  315. /*++
  316. Routine Description:
  317. Arguments:
  318. Return Value:
  319. If the function succeeds, the return value is a nonzero value.
  320. If the function fails, the return value is zero. To get extended error
  321. information, call GetLastError().
  322. --*/
  323. {
  324. ULONG result = 0, base = 10;
  325. BOOL negative = FALSE, done = FALSE;
  326. if (!String) {
  327. return 0;
  328. }
  329. if (L'-' == *String) { // but this is unsigned!
  330. negative = TRUE;
  331. String++;
  332. }
  333. if (L'0' == *String &&
  334. (L'x' == *(String + 1) || L'X' == *(String + 1))
  335. ) {
  336. // Hex
  337. base = 16;
  338. String += 2;
  339. }
  340. while (!done) {
  341. done = TRUE;
  342. if (L'0' <= *String && L'9' >= *String) {
  343. result = result*base + (*String - L'0');
  344. String++;
  345. done = FALSE;
  346. }
  347. else if (16==base) {
  348. if (L'a' <= *String && L'f' >= *String) {
  349. result = result*base + (*String - L'a') + 10;
  350. String++;
  351. done = FALSE;
  352. }
  353. else if (L'A' <= *String && L'F' >= *String) {
  354. result = result*base + (*String - L'A') + 10;
  355. String++;
  356. done = FALSE;
  357. }
  358. }
  359. }
  360. if (negative) {
  361. result = 0 - result;
  362. }
  363. return result;
  364. }
  365. VOID
  366. AsrpInsertSortedPartitionLengthOrder(
  367. IN PASR_PTN_INFO_LIST pPtnInfoList,
  368. IN PASR_PTN_INFO pPtnInfo
  369. )
  370. /*++
  371. Routine Description:
  372. Arguments:
  373. Return Value:
  374. If the function succeeds, the return value is a nonzero value.
  375. If the function fails, the return value is zero. To get extended error
  376. information, call GetLastError().
  377. --*/
  378. {
  379. PASR_PTN_INFO pPreviousPtn = NULL,
  380. pCurrentPtn = NULL;
  381. //
  382. // Insert this in the sorted PartitionLength order ...
  383. //
  384. pCurrentPtn = pPtnInfoList->pLengthHead;
  385. if (!pCurrentPtn) {
  386. //
  387. // First item in the list
  388. //
  389. pPtnInfoList->pLengthHead = pPtnInfo;
  390. pPtnInfoList->pLengthTail = pPtnInfo;
  391. }
  392. else {
  393. while (pCurrentPtn) {
  394. if (pCurrentPtn->PartitionInfo.PartitionLength.QuadPart
  395. <= pPtnInfo->PartitionInfo.PartitionLength.QuadPart) {
  396. pPreviousPtn = pCurrentPtn;
  397. pCurrentPtn = pCurrentPtn->pLengthNext;
  398. }
  399. else {
  400. //
  401. // We found the spot, let's add it in.
  402. //
  403. if (!pPreviousPtn) {
  404. //
  405. // This is the first node
  406. //
  407. pPtnInfoList->pLengthHead = pPtnInfo;
  408. }
  409. else {
  410. pPreviousPtn->pLengthNext = pPtnInfo;
  411. }
  412. pPtnInfo->pLengthNext = pCurrentPtn;
  413. break;
  414. }
  415. }
  416. if (!pCurrentPtn) {
  417. //
  418. // We reached the end and didn't add this node in.
  419. //
  420. MYASSERT(pPtnInfoList->pLengthTail == pPreviousPtn);
  421. pPtnInfoList->pLengthTail = pPtnInfo;
  422. pPreviousPtn->pLengthNext = pPtnInfo;
  423. }
  424. }
  425. }
  426. VOID
  427. AsrpInsertSortedPartitionStartOrder(
  428. IN PASR_PTN_INFO_LIST pPtnInfoList,
  429. IN PASR_PTN_INFO pPtnInfo
  430. )
  431. /*++
  432. Routine Description:
  433. Arguments:
  434. Return Value:
  435. None
  436. --*/
  437. {
  438. PASR_PTN_INFO pPreviousPtn = NULL,
  439. pCurrentPtn = NULL;
  440. //
  441. // Insert this in the sorted Start-Sector order ...
  442. //
  443. pCurrentPtn = pPtnInfoList->pOffsetHead;
  444. if (!pCurrentPtn) {
  445. //
  446. // First item in the list
  447. //
  448. pPtnInfoList->pOffsetHead = pPtnInfo;
  449. pPtnInfoList->pOffsetTail = pPtnInfo;
  450. }
  451. else {
  452. while (pCurrentPtn) {
  453. if (pCurrentPtn->PartitionInfo.StartingOffset.QuadPart
  454. <= pPtnInfo->PartitionInfo.StartingOffset.QuadPart) {
  455. pPreviousPtn = pCurrentPtn;
  456. pCurrentPtn = pCurrentPtn->pOffsetNext;
  457. }
  458. else {
  459. //
  460. // We found the spot, let's add it in.
  461. //
  462. if (!pPreviousPtn) {
  463. //
  464. // This is the first node
  465. //
  466. pPtnInfoList->pOffsetHead = pPtnInfo;
  467. }
  468. else {
  469. pPreviousPtn->pOffsetNext = pPtnInfo;
  470. }
  471. pPtnInfo->pOffsetNext = pCurrentPtn;
  472. break;
  473. }
  474. }
  475. if (!pCurrentPtn) {
  476. //
  477. // We reached the end and didn't add this node in.
  478. //
  479. MYASSERT(pPtnInfoList->pOffsetTail == pPreviousPtn);
  480. pPtnInfoList->pOffsetTail = pPtnInfo;
  481. pPreviousPtn->pOffsetNext = pPtnInfo;
  482. }
  483. }
  484. }
  485. //
  486. // Build the original MBR disk info from the sif file
  487. //
  488. BOOL
  489. AsrpBuildMbrSifDiskList(
  490. IN PCWSTR sifPath,
  491. OUT PASR_DISK_INFO *ppSifDiskList,
  492. OUT PASR_PTN_INFO_LIST *ppSifMbrPtnList,
  493. OUT BOOL *lpAutoExtend
  494. )
  495. /*++
  496. Routine Description:
  497. Arguments:
  498. Return Value:
  499. If the function succeeds, the return value is a nonzero value.
  500. If the function fails, the return value is zero. To get extended error
  501. information, call GetLastError().
  502. --*/
  503. {
  504. HINF hSif = NULL;
  505. INFCONTEXT infSystemContext,
  506. infDiskContext,
  507. infBusContext,
  508. infPtnContext;
  509. BOOL result = FALSE;
  510. DWORD reqdSize = 0,
  511. diskCount = 0,
  512. status = ERROR_SUCCESS;
  513. INT tempInt = 0;
  514. UINT errorLine = 0;
  515. PASR_DISK_INFO pNewSifDisk = NULL,
  516. currentDisk = NULL;
  517. PASR_PTN_INFO_LIST pMbrPtnList = NULL;
  518. PASR_PTN_INFO pPtnInfo = NULL;
  519. HANDLE heapHandle = GetProcessHeap();
  520. WCHAR tempBuffer[ASR_SIF_ENTRY_MAX_CHARS + 1];
  521. ZeroMemory(&infSystemContext, sizeof(INFCONTEXT));
  522. ZeroMemory(&infDiskContext, sizeof(INFCONTEXT));
  523. ZeroMemory(&infBusContext, sizeof(INFCONTEXT));
  524. ZeroMemory(&infPtnContext, sizeof(INFCONTEXT));
  525. ZeroMemory(tempBuffer, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1));
  526. // *ppSifDiskList = NULL;
  527. //
  528. // Open the sif
  529. //
  530. hSif = SetupOpenInfFileW(sifPath, NULL, INF_STYLE_WIN4, &errorLine);
  531. if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) {
  532. AsrpPrintDbgMsg(_asrerror,
  533. "The ASR state file \"%ws\" could not be opened. Error:%lu. Line: %lu.\r\n",
  534. sifPath,
  535. GetLastError(),
  536. errorLine
  537. );
  538. return FALSE; // sif file couldn't be opened
  539. }
  540. *lpAutoExtend = TRUE; // enable by default
  541. //
  542. // Get the AutoExtend value
  543. //
  544. result = SetupFindFirstLineW(hSif, ASR_SIF_SYSTEM_SECTION, NULL, &infSystemContext);
  545. if (!result) {
  546. AsrpPrintDbgMsg(_asrerror,
  547. "The ASR state file \"%ws\" is corrupt (section %ws not be found).\r\n",
  548. sifPath,
  549. ASR_SIF_SYSTEM_SECTION
  550. );
  551. return FALSE; // no system section
  552. }
  553. result = SetupGetIntField(&infSystemContext, 5, (PINT) (lpAutoExtend));
  554. if (!result) {
  555. *lpAutoExtend = TRUE; // TRUE by default
  556. }
  557. result = SetupFindFirstLineW(hSif, ASR_SIF_MBR_DISKS_SECTION, NULL, &infDiskContext);
  558. if (!result) {
  559. AsrpPrintDbgMsg(_asrinfo,
  560. "Section [%ws] is empty. Assuming no MBR disks.\r\n",
  561. ASR_SIF_MBR_DISKS_SECTION
  562. );
  563. return TRUE; // no mbr disks section
  564. }
  565. //
  566. // First, we go through the [DISKS.MBR] section. At the end of this loop,
  567. // we'll have a list of all MBR sif-disks. (*ppSifDiskList will point to
  568. // a linked list of ASR_DISK_INFO's, one for each disk).
  569. //
  570. do {
  571. ++diskCount;
  572. //
  573. // Create a new sif disk for this entry
  574. //
  575. pNewSifDisk = (PASR_DISK_INFO) HeapAlloc(
  576. heapHandle,
  577. HEAP_ZERO_MEMORY,
  578. sizeof(ASR_DISK_INFO)
  579. );
  580. _AsrpErrExitCode(!pNewSifDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  581. pNewSifDisk->pNext = *ppSifDiskList;
  582. *ppSifDiskList = pNewSifDisk;
  583. //
  584. // Now fill in the fields in the struct. Since we zeroed the struct while
  585. // allocating mem, all pointers in the struct are NULL by default, and
  586. // all flags in the struct are FALSE.
  587. //
  588. pNewSifDisk->pDiskGeometry = (PDISK_GEOMETRY) HeapAlloc(
  589. heapHandle,
  590. HEAP_ZERO_MEMORY,
  591. sizeof(DISK_GEOMETRY)
  592. );
  593. _AsrpErrExitCode(!pNewSifDisk->pDiskGeometry, status, ERROR_NOT_ENOUGH_MEMORY);
  594. pNewSifDisk->pPartition0Ex = (PPARTITION_INFORMATION_EX) HeapAlloc(
  595. heapHandle,
  596. HEAP_ZERO_MEMORY,
  597. sizeof(PARTITION_INFORMATION_EX)
  598. );
  599. _AsrpErrExitCode(!pNewSifDisk->pPartition0Ex, status, ERROR_NOT_ENOUGH_MEMORY);
  600. // This is an MBR disk
  601. pNewSifDisk->Style = PARTITION_STYLE_MBR;
  602. //
  603. // Index 0 is the key to the left of the = sign
  604. //
  605. result = SetupGetIntField(&infDiskContext, 0, (PINT) &(pNewSifDisk->SifDiskKey));
  606. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  607. //
  608. // Index 1 is the system key, it must be 1. We ignore it.
  609. // Index 2 - 6 are the bus key, critical flag, signature,
  610. // bytes-per-sector, sector-count
  611. //
  612. result = SetupGetIntField(&infDiskContext, 2, (PINT) &(pNewSifDisk->SifBusKey));
  613. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  614. result = SetupGetIntField(&infDiskContext, 3, (PINT) &(tempInt));
  615. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  616. pNewSifDisk->IsCritical = (tempInt ? TRUE: FALSE);
  617. result = SetupGetStringFieldW(&infDiskContext, 4, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  618. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  619. pNewSifDisk->TempSignature = AsrpStringToDword(tempBuffer);
  620. result = SetupGetStringFieldW(&infDiskContext, 5, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  621. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  622. pNewSifDisk->pDiskGeometry->BytesPerSector = AsrpStringToULong(tempBuffer);
  623. result = SetupGetStringFieldW(&infDiskContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  624. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  625. pNewSifDisk->pDiskGeometry->SectorsPerTrack = AsrpStringToULong(tempBuffer);
  626. result = SetupGetStringFieldW(&infDiskContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  627. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  628. pNewSifDisk->pDiskGeometry->TracksPerCylinder = AsrpStringToULong(tempBuffer);
  629. result = SetupGetStringFieldW(&infDiskContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  630. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  631. pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer);
  632. // convert from sector count to byte count
  633. pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart *= pNewSifDisk->pDiskGeometry->BytesPerSector;
  634. //
  635. // Get the bus-type related to this disk. LineByIndex is 0 based, our bus key is 1-based.
  636. //
  637. result = SetupGetLineByIndexW(hSif, ASR_SIF_BUSES_SECTION, pNewSifDisk->SifBusKey - 1, &infBusContext);
  638. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  639. result = SetupGetIntField(&infBusContext, 2, (PINT) &(pNewSifDisk->BusType));
  640. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  641. result = SetupFindNextLine(&infDiskContext, &infDiskContext);
  642. } while (result);
  643. AsrpPrintDbgMsg(_asrinfo,
  644. "Found %lu records in section [%ws].\r\n",
  645. diskCount,
  646. ASR_SIF_MBR_DISKS_SECTION
  647. );
  648. //
  649. // Now, enumerate all the [PARTITIONS.MBR] section. This will give us a list
  650. // of all the partitions (all) the MBR disks contained.
  651. //
  652. result = SetupFindFirstLineW(hSif, ASR_SIF_MBR_PARTITIONS_SECTION, NULL, &infPtnContext);
  653. if (result) {
  654. DWORD diskKey = 0;
  655. //
  656. // Init the table of partion lists.
  657. //
  658. pMbrPtnList = (PASR_PTN_INFO_LIST) HeapAlloc(
  659. heapHandle,
  660. HEAP_ZERO_MEMORY,
  661. sizeof(ASR_PTN_INFO_LIST) * (diskCount + 1)
  662. );
  663. _AsrpErrExitCode(!pMbrPtnList, status, ERROR_NOT_ENOUGH_MEMORY);
  664. // hack.
  665. // The 0'th entry of our table is not used, since the disk indices
  666. // begin with 1. Since we have no other way of keeping track of
  667. // how big this table is (so that we can free it properly), we can
  668. // use the 0th entry to store this.
  669. //
  670. pMbrPtnList[0].numTotalPtns = diskCount + 1; // size of table
  671. do {
  672. pPtnInfo = (PASR_PTN_INFO) HeapAlloc(
  673. heapHandle,
  674. HEAP_ZERO_MEMORY,
  675. sizeof(ASR_PTN_INFO)
  676. );
  677. _AsrpErrExitCode(!pPtnInfo, status, ERROR_NOT_ENOUGH_MEMORY);
  678. //
  679. // Read in the information. The format of this section is:
  680. //
  681. // [PARTITIONS.MBR]
  682. // 0.partition-key = 1.disk-key, 2.slot-index, 3.boot-sys-flag,
  683. // 4."volume-guid", 5.active-flag, 6.partition-type,
  684. // 7.file-system-type, 8.start-sector, 9.sector-count
  685. //
  686. result = SetupGetIntField(&infPtnContext, 1, &diskKey);
  687. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  688. result = SetupGetIntField(&infPtnContext, 2, (PINT) &(pPtnInfo->SlotIndex));
  689. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  690. result = SetupGetIntField(&infPtnContext, 3, (PINT) &(pPtnInfo->PartitionFlags));
  691. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  692. result = SetupGetStringFieldW(&infPtnContext, 4, pPtnInfo->szVolumeGuid, ASR_CCH_MAX_VOLUME_GUID, &reqdSize);
  693. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  694. result = SetupGetIntField(&infPtnContext, 5, (PINT) &tempInt);
  695. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  696. pPtnInfo->PartitionInfo.Mbr.BootIndicator = (tempInt ? TRUE: FALSE);
  697. // converting from int to uchar
  698. result = SetupGetIntField(&infPtnContext, 6, (PINT) &(pPtnInfo->PartitionInfo.Mbr.PartitionType));
  699. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  700. result = SetupGetIntField(&infPtnContext, 7, (PINT) &(pPtnInfo->FileSystemType));
  701. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  702. //
  703. // Note, we read in the start SECTOR and SECTOR count. We'll convert these to
  704. // their byte values later (in AsrpCreatePartitionTable)
  705. //
  706. result = SetupGetStringFieldW(&infPtnContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  707. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  708. pPtnInfo->PartitionInfo.StartingOffset.QuadPart = AsrpStringToLongLong(tempBuffer);
  709. result = SetupGetStringFieldW(&infPtnContext, 9, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  710. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  711. pPtnInfo->PartitionInfo.PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer);
  712. //
  713. // Add this in the sorted starting-offset order.
  714. //
  715. AsrpInsertSortedPartitionStartOrder(&(pMbrPtnList[diskKey]), pPtnInfo);
  716. //
  717. // Add this in the sorted partition length order as well. This isn't really used for
  718. // MBR disks at present, only for GPT disks.
  719. //
  720. AsrpInsertSortedPartitionLengthOrder(&(pMbrPtnList[diskKey]), pPtnInfo);
  721. (pMbrPtnList[diskKey].numTotalPtns)++;
  722. if (IsContainerPartition(pPtnInfo->PartitionInfo.Mbr.PartitionType)) {
  723. (pMbrPtnList[diskKey].numExtendedPtns)++;
  724. }
  725. result = SetupFindNextLine(&infPtnContext, &infPtnContext);
  726. } while (result);
  727. //
  728. // Now, we have the table of all the MBR partition lists, and a list of
  729. // all MBR disks. The next step is to "assign" the partitions to their respective
  730. // disks--and update the DriveLayoutEx struct for the disks.
  731. //
  732. currentDisk = *(ppSifDiskList);
  733. while (currentDisk) {
  734. DWORD PartitionCount = 0,
  735. count = 0;
  736. if (PARTITION_STYLE_MBR != currentDisk->Style) {
  737. currentDisk = currentDisk->pNext;
  738. continue;
  739. }
  740. PartitionCount = ((pMbrPtnList[currentDisk->SifDiskKey].numExtendedPtns) * 4) + 4;
  741. currentDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX)*(PartitionCount-1));
  742. currentDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  743. heapHandle,
  744. HEAP_ZERO_MEMORY,
  745. currentDisk->sizeDriveLayoutEx
  746. );
  747. _AsrpErrExitCode(!currentDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  748. //
  749. // Initialise the DriveLayout struct.
  750. //
  751. currentDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  752. currentDisk->pDriveLayoutEx->PartitionCount = PartitionCount;
  753. currentDisk->pDriveLayoutEx->Mbr.Signature = currentDisk->TempSignature;
  754. AsrpCreatePartitionTable(currentDisk->pDriveLayoutEx,
  755. &(pMbrPtnList[currentDisk->SifDiskKey]),
  756. currentDisk->pDiskGeometry->BytesPerSector
  757. );
  758. currentDisk = currentDisk->pNext;
  759. }
  760. }
  761. else {
  762. DWORD count = 0;
  763. AsrpPrintDbgMsg(_asrinfo,
  764. "Section [%ws] is empty. Assuming MBR disks have no partitions.\r\n",
  765. ASR_SIF_MBR_PARTITIONS_SECTION
  766. );
  767. //
  768. // The partitions section is empty. Initialise each disk's drive layout
  769. // accordingly
  770. //
  771. currentDisk = *ppSifDiskList;
  772. while (currentDisk) {
  773. if (PARTITION_STYLE_MBR != currentDisk->Style) {
  774. currentDisk = currentDisk->pNext;
  775. continue;
  776. }
  777. currentDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * 3);
  778. currentDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  779. heapHandle,
  780. HEAP_ZERO_MEMORY,
  781. currentDisk->sizeDriveLayoutEx
  782. );
  783. _AsrpErrExitCode(!currentDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  784. currentDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  785. currentDisk->pDriveLayoutEx->PartitionCount = 4;
  786. currentDisk->pDriveLayoutEx->Mbr.Signature = currentDisk->TempSignature;
  787. for (count = 0; count < currentDisk->pDriveLayoutEx->PartitionCount ; count++) {
  788. currentDisk->pDriveLayoutEx->PartitionEntry[count].PartitionStyle = PARTITION_STYLE_MBR;
  789. currentDisk->pDriveLayoutEx->PartitionEntry[count].RewritePartition = TRUE;
  790. }
  791. currentDisk = currentDisk->pNext;
  792. }
  793. }
  794. EXIT:
  795. *ppSifMbrPtnList = pMbrPtnList;
  796. if ((hSif) && (INVALID_HANDLE_VALUE != hSif)) {
  797. SetupCloseInfFile(hSif);
  798. hSif = NULL;
  799. }
  800. return (BOOL) (ERROR_SUCCESS == status);
  801. }
  802. //
  803. // Build the original disk info for GPT disks from the sif file
  804. //
  805. BOOL
  806. AsrpBuildGptSifDiskList(
  807. IN PCWSTR sifPath,
  808. OUT PASR_DISK_INFO *ppSifDiskList,
  809. OUT PASR_PTN_INFO_LIST *ppSifGptPtnList
  810. )
  811. /*++
  812. Routine Description:
  813. Arguments:
  814. Return Value:
  815. If the function succeeds, the return value is a nonzero value.
  816. If the function fails, the return value is zero. To get extended error
  817. information, call GetLastError().
  818. --*/
  819. {
  820. HINF hSif = NULL;
  821. BOOL result = FALSE;
  822. DWORD reqdSize = 0,
  823. diskCount = 0,
  824. status = ERROR_SUCCESS;
  825. INFCONTEXT infDiskContext,
  826. infBusContext,
  827. infPtnContext;
  828. INT tempInt = 0;
  829. UINT errorLine = 0;
  830. PASR_DISK_INFO pNewSifDisk = NULL,
  831. currentDisk = NULL;
  832. HANDLE heapHandle = NULL;
  833. PASR_PTN_INFO pPtnInfo = NULL;
  834. RPC_STATUS rpcStatus = RPC_S_OK;
  835. PASR_PTN_INFO_LIST pGptPtnList = NULL;
  836. WCHAR tempBuffer[ASR_SIF_ENTRY_MAX_CHARS+1];
  837. heapHandle = GetProcessHeap();
  838. ZeroMemory(&infDiskContext, sizeof(INFCONTEXT));
  839. ZeroMemory(&infBusContext, sizeof(INFCONTEXT));
  840. ZeroMemory(&infPtnContext, sizeof(INFCONTEXT));
  841. ZeroMemory(tempBuffer, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1));
  842. //
  843. // Open the sif
  844. //
  845. hSif = SetupOpenInfFileW(sifPath, NULL, INF_STYLE_WIN4, &errorLine);
  846. if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) {
  847. AsrpPrintDbgMsg(_asrerror,
  848. "The ASR state file \"%ws\" could not be opened. Error:%lu. Line: %lu.\r\n",
  849. sifPath,
  850. GetLastError(),
  851. errorLine
  852. );
  853. return FALSE; // sif file couldn't be opened
  854. }
  855. result = SetupFindFirstLineW(hSif, ASR_SIF_GPT_DISKS_SECTION, NULL, &infDiskContext);
  856. if (!result) {
  857. AsrpPrintDbgMsg(_asrinfo,
  858. "Section [%ws] is empty. Assuming no GPT disks.\r\n",
  859. ASR_SIF_GPT_DISKS_SECTION
  860. );
  861. return TRUE; // no disks section
  862. }
  863. //
  864. // First, we go through the [DISKS.GPT] section. At the end of this loop,
  865. // we'll have a list of all GPT sif-disks. (*ppSifDiskList will point to
  866. // a linked list of ASR_DISK_INFO's, one for each disk).
  867. //
  868. do {
  869. ++diskCount;
  870. //
  871. // Create a new sif disk for this entry
  872. //
  873. pNewSifDisk = (PASR_DISK_INFO) HeapAlloc(
  874. heapHandle,
  875. HEAP_ZERO_MEMORY,
  876. sizeof(ASR_DISK_INFO)
  877. );
  878. _AsrpErrExitCode(!pNewSifDisk, status, ERROR_NOT_ENOUGH_MEMORY);
  879. pNewSifDisk->pNext = *ppSifDiskList;
  880. *ppSifDiskList = pNewSifDisk;
  881. //
  882. // Now fill in the fields in the struct. Since we zeroed the struct while
  883. // allocating mem, all pointers in the struct are NULL by default, and
  884. // all flags in the struct are FALSE.
  885. //
  886. pNewSifDisk->pDiskGeometry = (PDISK_GEOMETRY) HeapAlloc(
  887. heapHandle,
  888. HEAP_ZERO_MEMORY,
  889. sizeof(DISK_GEOMETRY)
  890. );
  891. _AsrpErrExitCode(!pNewSifDisk->pDiskGeometry, status, ERROR_NOT_ENOUGH_MEMORY);
  892. pNewSifDisk->pPartition0Ex = (PPARTITION_INFORMATION_EX) HeapAlloc(
  893. heapHandle,
  894. HEAP_ZERO_MEMORY,
  895. sizeof(PARTITION_INFORMATION_EX)
  896. );
  897. _AsrpErrExitCode(!pNewSifDisk->pPartition0Ex, status, ERROR_NOT_ENOUGH_MEMORY);
  898. // This is a GPT disk
  899. pNewSifDisk->Style = PARTITION_STYLE_GPT;
  900. //
  901. // Index 0 is the key to the left of the = sign
  902. //
  903. result = SetupGetIntField(&infDiskContext, 0, (PINT) &(pNewSifDisk->SifDiskKey));
  904. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  905. //
  906. // Index 1 is the system key, it must be 1. We ignore it.
  907. // Index 2 - 7 are:
  908. // 2: bus key
  909. // 3: critical flag
  910. // 4: disk-guid
  911. // 5: max-partition-count
  912. // 6: bytes-per-sector
  913. // 7: sector-count
  914. //
  915. result = SetupGetIntField(&infDiskContext, 2, (PINT) &(pNewSifDisk->SifBusKey)); // BusKey
  916. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  917. result = SetupGetIntField(&infDiskContext, 3, (PINT) &(tempInt)); // IsCritical
  918. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  919. pNewSifDisk->IsCritical = (tempInt ? TRUE: FALSE);
  920. result = SetupGetStringFieldW(&infDiskContext, 4, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); // DiskGuid
  921. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  922. result = SetupGetIntField(&infDiskContext, 5, (PINT) &(tempInt)); // MaxPartitionCount
  923. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  924. //
  925. // Allocate a drive layout struct, now that we know the max partition count
  926. //
  927. pNewSifDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX)*(tempInt-1));
  928. pNewSifDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  929. heapHandle,
  930. HEAP_ZERO_MEMORY,
  931. pNewSifDisk->sizeDriveLayoutEx
  932. );
  933. _AsrpErrExitCode(!pNewSifDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  934. // This is a GPT disk
  935. pNewSifDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT;
  936. //
  937. // Set the MaxPartitionCount and DiskGuid fields
  938. //
  939. pNewSifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount = tempInt;
  940. rpcStatus = UuidFromStringW(tempBuffer, &(pNewSifDisk->pDriveLayoutEx->Gpt.DiskId));
  941. _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus);
  942. result = SetupGetStringFieldW(&infDiskContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  943. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  944. pNewSifDisk->pDiskGeometry->BytesPerSector = AsrpStringToULong(tempBuffer);
  945. result = SetupGetStringFieldW(&infDiskContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  946. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  947. pNewSifDisk->pDiskGeometry->SectorsPerTrack = AsrpStringToULong(tempBuffer);
  948. result = SetupGetStringFieldW(&infDiskContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  949. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  950. pNewSifDisk->pDiskGeometry->TracksPerCylinder = AsrpStringToULong(tempBuffer);
  951. result = SetupGetStringFieldW(&infDiskContext, 9, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  952. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  953. pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer);
  954. // convert from sector count to byte count
  955. pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart *= pNewSifDisk->pDiskGeometry->BytesPerSector; // TotalBytes
  956. //
  957. // Get the bus-type related to this disk. LineByIndex is 0 based, our bus key is 1-based.
  958. //
  959. result = SetupGetLineByIndexW(hSif, ASR_SIF_BUSES_SECTION, pNewSifDisk->SifBusKey - 1, &infBusContext);
  960. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  961. result = SetupGetIntField(&infBusContext, 2, (PINT) &(pNewSifDisk->BusType)); // bus type
  962. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  963. result = SetupFindNextLine(&infDiskContext, &infDiskContext);
  964. } while(result);
  965. AsrpPrintDbgMsg(_asrinfo,
  966. "Found %lu records in section [%ws].\r\n",
  967. diskCount,
  968. ASR_SIF_MBR_DISKS_SECTION
  969. );
  970. //
  971. // Now, enumerate all the [PARTITIONS.GPT] section. This will give us a list
  972. // of all the partitions (all) the GPT disks contained.
  973. //
  974. result = SetupFindFirstLineW(hSif, ASR_SIF_GPT_PARTITIONS_SECTION, NULL, &infPtnContext);
  975. if (result) {
  976. DWORD diskKey = 0;
  977. //
  978. // Init the table of partion lists.
  979. //
  980. pGptPtnList = (PASR_PTN_INFO_LIST) HeapAlloc(
  981. heapHandle,
  982. HEAP_ZERO_MEMORY,
  983. sizeof(ASR_PTN_INFO_LIST) * (diskCount + 1)
  984. );
  985. _AsrpErrExitCode(!pGptPtnList, status, ERROR_NOT_ENOUGH_MEMORY);
  986. // hack.
  987. // The 0'th entry of our table is not used, since the disk indices
  988. // begin with 1. Since we have no other way of keeping track of
  989. // how big this table is (so that we can free it properly), we can
  990. // use the 0th entry to store this.
  991. //
  992. pGptPtnList[0].numTotalPtns = diskCount + 1; // size of table
  993. do {
  994. pPtnInfo = (PASR_PTN_INFO) HeapAlloc(
  995. heapHandle,
  996. HEAP_ZERO_MEMORY,
  997. sizeof(ASR_PTN_INFO)
  998. );
  999. _AsrpErrExitCode(!pPtnInfo, status, ERROR_NOT_ENOUGH_MEMORY);
  1000. //
  1001. // This is a GPT partition
  1002. //
  1003. pPtnInfo->PartitionInfo.PartitionStyle = PARTITION_STYLE_GPT;
  1004. //
  1005. // Read in the values. The format of this section is:
  1006. //
  1007. // [PARTITIONS.GPT]
  1008. // 0.partition-key = 1.disk-key, 2.slot-index, 3.boot-sys-flag,
  1009. // 4."volume-guid", 5."partition-type-guid", 6."partition-id-guid"
  1010. // 7.gpt-attributes, 8."partition-name", 9.file-system-type,
  1011. // 10.start-sector, 11.sector-count
  1012. //
  1013. result = SetupGetIntField(&infPtnContext, 1, &diskKey); // 1. disk-key
  1014. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1015. result = SetupGetIntField(&infPtnContext, 2, (PINT) &(pPtnInfo->SlotIndex)); // 2. slot-index
  1016. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1017. result = SetupGetIntField(&infPtnContext, 3, (PINT) &(pPtnInfo->PartitionFlags)); // 3. boot-sys-flag
  1018. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1019. result = SetupGetStringFieldW(&infPtnContext, 4, pPtnInfo->szVolumeGuid, ASR_CCH_MAX_VOLUME_GUID, &reqdSize); // volume-guid
  1020. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1021. result = SetupGetStringFieldW(&infPtnContext, 5, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS + 1, &reqdSize); // partition-type-guid
  1022. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1023. rpcStatus = UuidFromStringW(tempBuffer, &(pPtnInfo->PartitionInfo.Gpt.PartitionType));
  1024. _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus);
  1025. result = SetupGetStringFieldW(&infPtnContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS + 1, &reqdSize);
  1026. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1027. rpcStatus = UuidFromStringW(tempBuffer, &(pPtnInfo->PartitionInfo.Gpt.PartitionId));
  1028. _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus);
  1029. //
  1030. // Note, we read in the start SECTOR and SECTOR count. We'll convert these to
  1031. // their byte values later (in AsrpCreatePartitionTable)
  1032. //
  1033. result = SetupGetStringFieldW(&infPtnContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  1034. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1035. pPtnInfo->PartitionInfo.Gpt.Attributes = AsrpStringToULong64(tempBuffer);
  1036. result = SetupGetStringFieldW(&infPtnContext, 8, pPtnInfo->PartitionInfo.Gpt.Name, 36, &reqdSize);
  1037. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1038. result = SetupGetIntField(&infPtnContext, 9, (PINT) &(pPtnInfo->FileSystemType));
  1039. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1040. //
  1041. // Note, we read in the start SECTOR and SECTOR count. We'll convert it to the
  1042. // BYTE offset and BYTE length later (in AsrpCreatePartitionTable)
  1043. //
  1044. result = SetupGetStringFieldW(&infPtnContext, 10, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  1045. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1046. pPtnInfo->PartitionInfo.StartingOffset.QuadPart = AsrpStringToLongLong(tempBuffer);
  1047. result = SetupGetStringFieldW(&infPtnContext, 11, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  1048. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  1049. pPtnInfo->PartitionInfo.PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer);
  1050. //
  1051. // Add this in the sorted partition starting-offset order.
  1052. //
  1053. AsrpInsertSortedPartitionStartOrder(&(pGptPtnList[diskKey]), pPtnInfo);
  1054. //
  1055. // Add this in the sorted partition length order as well. This is useful
  1056. // later when we try to fit in the partitions on the disk.
  1057. //
  1058. AsrpInsertSortedPartitionLengthOrder(&(pGptPtnList[diskKey]), pPtnInfo);
  1059. (pGptPtnList[diskKey].numTotalPtns)++;
  1060. result = SetupFindNextLine(&infPtnContext, &infPtnContext);
  1061. } while (result);
  1062. //
  1063. // Now, we have the table of all the partition lists, and a list of
  1064. // all disks. The next task is to update the DriveLayoutEx struct for
  1065. // the disks.
  1066. //
  1067. currentDisk = *(ppSifDiskList);
  1068. while (currentDisk) {
  1069. if (PARTITION_STYLE_GPT != currentDisk->Style) {
  1070. currentDisk = currentDisk->pNext;
  1071. continue;
  1072. }
  1073. //
  1074. // Initialise the DriveLayoutEx struct.
  1075. //
  1076. currentDisk->pDriveLayoutEx->PartitionCount = pGptPtnList[currentDisk->SifDiskKey].numTotalPtns;
  1077. AsrpCreatePartitionTable(currentDisk->pDriveLayoutEx,
  1078. &(pGptPtnList[currentDisk->SifDiskKey]),
  1079. currentDisk->pDiskGeometry->BytesPerSector
  1080. );
  1081. currentDisk = currentDisk->pNext;
  1082. }
  1083. }
  1084. else {
  1085. DWORD count = 0;
  1086. AsrpPrintDbgMsg(_asrinfo,
  1087. "Section [%ws] is empty. Assuming GPT disks have no partitions.\r\n",
  1088. ASR_SIF_GPT_PARTITIONS_SECTION
  1089. );
  1090. //
  1091. // The partitions section is empty. Initialise each disk's drive layout
  1092. // accordingly
  1093. //
  1094. currentDisk = *ppSifDiskList;
  1095. while (currentDisk) {
  1096. if (PARTITION_STYLE_GPT != currentDisk->Style) {
  1097. currentDisk = currentDisk->pNext;
  1098. continue;
  1099. }
  1100. currentDisk->pDriveLayoutEx->PartitionCount = 0;
  1101. for (count = 0; count < currentDisk->pDriveLayoutEx->Gpt.MaxPartitionCount ; count++) {
  1102. currentDisk->pDriveLayoutEx->PartitionEntry[count].PartitionStyle = PARTITION_STYLE_GPT;
  1103. currentDisk->pDriveLayoutEx->PartitionEntry[count].RewritePartition = TRUE;
  1104. }
  1105. currentDisk = currentDisk->pNext;
  1106. }
  1107. }
  1108. EXIT:
  1109. *ppSifGptPtnList = pGptPtnList;
  1110. if ((hSif) && (INVALID_HANDLE_VALUE != hSif)) {
  1111. SetupCloseInfFile(hSif);
  1112. hSif = NULL;
  1113. }
  1114. return (BOOL) (ERROR_SUCCESS == status);
  1115. }
  1116. //
  1117. // Returns
  1118. // TRUE if pSifDisk and pPhysicalDisk have the exact same partition layout,
  1119. // FALSE otherwise
  1120. //
  1121. BOOL
  1122. AsrpIsDiskIntact(
  1123. IN PASR_DISK_INFO pSifDisk,
  1124. IN PASR_DISK_INFO pPhysicalDisk
  1125. )
  1126. /*++
  1127. Routine Description:
  1128. Arguments:
  1129. Return Value:
  1130. If the function succeeds, the return value is a nonzero value.
  1131. If the function fails, the return value is zero. To get extended error
  1132. information, call GetLastError().
  1133. --*/
  1134. {
  1135. ULONG index = 0,
  1136. physicalIndex = 0;
  1137. PPARTITION_INFORMATION_EX pSifPtnEx = NULL,
  1138. pPhysicalPtnEx = NULL;
  1139. if (pSifDisk->Style != pPhysicalDisk->Style) {
  1140. return FALSE; // different partitioning styles
  1141. }
  1142. if (PARTITION_STYLE_MBR == pSifDisk->Style) {
  1143. //
  1144. // For MBR disks, we expect to find the same number of partitions,
  1145. // and the starting-offset and partition-length for each of those
  1146. // partitions must be the same as they were in the sif
  1147. //
  1148. if (pSifDisk->pDriveLayoutEx->Mbr.Signature
  1149. != pPhysicalDisk->pDriveLayoutEx->Mbr.Signature) {
  1150. return FALSE; // different signatures
  1151. }
  1152. if (pSifDisk->pDriveLayoutEx->PartitionCount
  1153. != pPhysicalDisk->pDriveLayoutEx->PartitionCount) {
  1154. return FALSE; // different partition counts
  1155. }
  1156. for (index =0; index < pSifDisk->pDriveLayoutEx->PartitionCount; index++) {
  1157. pSifPtnEx = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index]);
  1158. pPhysicalPtnEx = &(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[index]);
  1159. if ((pSifPtnEx->StartingOffset.QuadPart != pPhysicalPtnEx->StartingOffset.QuadPart) ||
  1160. (pSifPtnEx->PartitionLength.QuadPart != pPhysicalPtnEx->PartitionLength.QuadPart)
  1161. ) {
  1162. //
  1163. // The partition offset or length didn't match, ie the disk
  1164. // isn't intact
  1165. //
  1166. return FALSE;
  1167. }
  1168. } // for
  1169. }
  1170. else if (PARTITION_STYLE_GPT == pSifDisk->Style) {
  1171. BOOL found = FALSE;
  1172. //
  1173. // For GPT disks, the partitions must have the same partition-Id's, in
  1174. // addition to the start sector and sector count. We can't rely on their
  1175. // partition table entry order being the same, though--so we have to go
  1176. // through all the partition entries from the beginning ...
  1177. //
  1178. for (index = 0; index < pSifDisk->pDriveLayoutEx->PartitionCount; index++) {
  1179. pSifPtnEx = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index]);
  1180. found = FALSE;
  1181. for (physicalIndex = 0;
  1182. (physicalIndex < pPhysicalDisk->pDriveLayoutEx->PartitionCount)
  1183. // && (pSifPtnEx->StartingOffset.QuadPart >= pPhysicalDisk->pDriveLayoutEx->PartitionEntry[physicalIndex].StartingOffset.QuadPart) // entries are in ascending order
  1184. && (!found);
  1185. physicalIndex++) {
  1186. pPhysicalPtnEx = &(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[physicalIndex]);
  1187. if (IsEqualGUID(&(pSifPtnEx->Gpt.PartitionId), &(pPhysicalPtnEx->Gpt.PartitionId)) &&
  1188. (pSifPtnEx->StartingOffset.QuadPart == pPhysicalPtnEx->StartingOffset.QuadPart) &&
  1189. (pSifPtnEx->PartitionLength.QuadPart == pPhysicalPtnEx->PartitionLength.QuadPart)
  1190. ) {
  1191. //
  1192. // The partition GUID, offset and length matched, this partition exists
  1193. //
  1194. found = TRUE;
  1195. }
  1196. } // for
  1197. if (!found) {
  1198. //
  1199. // At least one partition wasn't found
  1200. //
  1201. return FALSE;
  1202. }
  1203. }
  1204. }
  1205. return TRUE;
  1206. }
  1207. LONGLONG
  1208. AsrpCylinderAlignMbrPartitions(
  1209. IN PASR_DISK_INFO pSifDisk,
  1210. IN PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutEx,
  1211. IN DWORD StartIndex, // index in the partitionEntry table to start at
  1212. IN LONGLONG StartingOffset,
  1213. IN PDISK_GEOMETRY pPhysicalDiskGeometry
  1214. )
  1215. /*++
  1216. Routine Description:
  1217. Arguments:
  1218. Return Value:
  1219. If the function succeeds, the return value is a nonzero value.
  1220. If the function fails, the return value is zero. To get extended error
  1221. information, call GetLastError().
  1222. --*/
  1223. {
  1224. LONGLONG nextEnd = 0,
  1225. endingOffset = 0,
  1226. bytesPerTrack = 0,
  1227. bytesPerCylinder = 0,
  1228. currentMax = 0,
  1229. maxEndingOffset = 0;
  1230. DWORD index = 0,
  1231. tempIndex = 0,
  1232. tempIndex2 = 0;
  1233. PPARTITION_INFORMATION_EX alignedPtn = NULL,
  1234. sifPtn = NULL,
  1235. tempPtn = NULL;
  1236. if (PARTITION_STYLE_MBR != pSifDisk->Style) {
  1237. //
  1238. // This routine only supports MBR disks. For GPT disks, we don't need to
  1239. // cylinder-align partitions, so this routine shouldn't be called.
  1240. //
  1241. return -1;
  1242. }
  1243. if (0 == pSifDisk->pDriveLayoutEx->PartitionCount) {
  1244. //
  1245. // (boundary case) No partitions on disk to align
  1246. //
  1247. return 0;
  1248. }
  1249. MYASSERT(AsrpRoundUp(StartIndex,4) == StartIndex);
  1250. MYASSERT(pSifDisk && pAlignedLayoutEx);
  1251. if (!pSifDisk || !pAlignedLayoutEx) {
  1252. return -1;
  1253. }
  1254. bytesPerTrack = pPhysicalDiskGeometry->BytesPerSector * pPhysicalDiskGeometry->SectorsPerTrack;
  1255. bytesPerCylinder = bytesPerTrack * (pPhysicalDiskGeometry->TracksPerCylinder);
  1256. //
  1257. // The first partition entry in each MBR/EBR always starts at the
  1258. // cylinder-boundary plus one track. So, add one track to the starting
  1259. // offset.
  1260. //
  1261. // The exception (there had to be one, of course) is if the first
  1262. // partition entry in the MBR/EBR itself is a container partition (0x05 or
  1263. // 0x0f), then it starts on the next cylinder.
  1264. //
  1265. if (IsContainerPartition(pSifDisk->pDriveLayoutEx->PartitionEntry[StartIndex].Mbr.PartitionType)) {
  1266. StartingOffset += (bytesPerCylinder);
  1267. }
  1268. else {
  1269. StartingOffset += (bytesPerTrack);
  1270. }
  1271. for (index = 0; index < 4; index++) {
  1272. alignedPtn = &(pAlignedLayoutEx->PartitionEntry[index + StartIndex]);
  1273. sifPtn = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index + StartIndex]);
  1274. MYASSERT(PARTITION_STYLE_MBR == sifPtn->PartitionStyle);
  1275. //
  1276. // Set the fields of interest
  1277. //
  1278. alignedPtn->PartitionStyle = PARTITION_STYLE_MBR;
  1279. alignedPtn->RewritePartition = TRUE;
  1280. alignedPtn->Mbr.PartitionType = sifPtn->Mbr.PartitionType;
  1281. alignedPtn->Mbr.BootIndicator = sifPtn->Mbr.BootIndicator;
  1282. alignedPtn->Mbr.RecognizedPartition = sifPtn->Mbr.RecognizedPartition;
  1283. if (PARTITION_ENTRY_UNUSED != sifPtn->Mbr.PartitionType) {
  1284. alignedPtn->StartingOffset.QuadPart = StartingOffset;
  1285. endingOffset = AsrpRoundUp(sifPtn->PartitionLength.QuadPart + StartingOffset, bytesPerCylinder);
  1286. alignedPtn->PartitionLength.QuadPart = endingOffset - StartingOffset;
  1287. if (IsContainerPartition(alignedPtn->Mbr.PartitionType)) {
  1288. //
  1289. // This is a container partition (0x5 or 0xf), so we have to try and
  1290. // fit the logical drives inside this partition to get the
  1291. // required size of this partition.
  1292. //
  1293. nextEnd = AsrpCylinderAlignMbrPartitions(pSifDisk,
  1294. pAlignedLayoutEx,
  1295. StartIndex + 4,
  1296. StartingOffset,
  1297. pPhysicalDiskGeometry
  1298. );
  1299. if (-1 == nextEnd) {
  1300. //
  1301. // Propogate error upwards
  1302. //
  1303. return nextEnd;
  1304. }
  1305. if (StartIndex < 4) {
  1306. //
  1307. // We're dealing with the primary container partition
  1308. //
  1309. if (nextEnd > endingOffset) {
  1310. MYASSERT(AsrpRoundUp(nextEnd, bytesPerCylinder) == nextEnd);
  1311. alignedPtn->PartitionLength.QuadPart = nextEnd - StartingOffset;
  1312. endingOffset = nextEnd;
  1313. }
  1314. //
  1315. // If the primary container partition ends beyond cylinder
  1316. // 1024, it should be of type 0xf, else it should be of
  1317. // type 0x5.
  1318. //
  1319. if (endingOffset > (1024 * bytesPerCylinder)) {
  1320. alignedPtn->Mbr.PartitionType = PARTITION_XINT13_EXTENDED;
  1321. }
  1322. else {
  1323. alignedPtn->Mbr.PartitionType = PARTITION_EXTENDED;
  1324. }
  1325. }
  1326. else {
  1327. //
  1328. // We're dealing with a secondary container. This
  1329. // container should only be big enough to hold the
  1330. // next logical drive.
  1331. //
  1332. alignedPtn->Mbr.PartitionType = PARTITION_EXTENDED;
  1333. tempIndex = (DWORD) AsrpRoundUp((StartIndex + index), 4);
  1334. currentMax = 0;
  1335. for (tempIndex2 = 0; tempIndex2 < 4; tempIndex2++) {
  1336. tempPtn = &(pSifDisk->pDriveLayoutEx->PartitionEntry[tempIndex + tempIndex2]);
  1337. if ((PARTITION_ENTRY_UNUSED != tempPtn->Mbr.PartitionType) &&
  1338. !IsContainerPartition(tempPtn->Mbr.PartitionType)
  1339. ) {
  1340. if (tempPtn->StartingOffset.QuadPart + tempPtn->PartitionLength.QuadPart
  1341. > currentMax
  1342. ) {
  1343. currentMax = tempPtn->StartingOffset.QuadPart + tempPtn->PartitionLength.QuadPart;
  1344. }
  1345. }
  1346. }
  1347. if (currentMax > endingOffset) {
  1348. MYASSERT(AsrpRoundUp(currentMax, bytesPerCylinder) == currentMax);
  1349. alignedPtn->PartitionLength.QuadPart = currentMax - StartingOffset;
  1350. endingOffset = currentMax;
  1351. }
  1352. }
  1353. if (nextEnd > maxEndingOffset) {
  1354. maxEndingOffset = nextEnd;
  1355. }
  1356. }
  1357. if (endingOffset > maxEndingOffset) {
  1358. maxEndingOffset = endingOffset;
  1359. }
  1360. StartingOffset += (alignedPtn->PartitionLength.QuadPart);
  1361. }
  1362. else {
  1363. alignedPtn->StartingOffset.QuadPart = 0;
  1364. alignedPtn->PartitionLength.QuadPart = 0;
  1365. }
  1366. }
  1367. return maxEndingOffset;
  1368. }
  1369. VOID
  1370. AsrpFreeRegionInfo(
  1371. IN PASR_REGION_INFO RegionInfo
  1372. )
  1373. /*++
  1374. Routine Description:
  1375. Arguments:
  1376. Return Value:
  1377. If the function succeeds, the return value is a nonzero value.
  1378. If the function fails, the return value is zero. To get extended error
  1379. information, call GetLastError().
  1380. --*/
  1381. {
  1382. PASR_REGION_INFO temp = RegionInfo;
  1383. HANDLE heapHandle = GetProcessHeap();
  1384. while (temp) {
  1385. RegionInfo = temp->pNext;
  1386. _AsrpHeapFree(temp);
  1387. temp = RegionInfo;
  1388. }
  1389. }
  1390. BOOL
  1391. AsrpIsOkayToErasePartition(
  1392. IN PPARTITION_INFORMATION_EX pPartitionInfoEx
  1393. )
  1394. /*++
  1395. Routine Description:
  1396. Arguments:
  1397. Return Value:
  1398. If the function succeeds, the return value is a nonzero value.
  1399. If the function fails, the return value is zero. To get extended error
  1400. information, call GetLastError().
  1401. --*/
  1402. {
  1403. GUID typeGuid = pPartitionInfoEx->Gpt.PartitionType;
  1404. //
  1405. // For now, this checks the partition type against all the known ("recognised")
  1406. // partition types. If the partition type is recognised (except the system partition),
  1407. // it's okay to erase it.
  1408. //
  1409. if (IsEqualGUID(&(typeGuid), &(PARTITION_ENTRY_UNUSED_GUID))) {
  1410. return TRUE;
  1411. }
  1412. if (IsEqualGUID(&(typeGuid), &(PARTITION_SYSTEM_GUID))) {
  1413. return FALSE; // Cannot erase EFI system partition.
  1414. }
  1415. if (IsEqualGUID(&(typeGuid), &(PARTITION_MSFT_RESERVED_GUID))) {
  1416. return TRUE;
  1417. }
  1418. if (IsEqualGUID(&(typeGuid), &(PARTITION_BASIC_DATA_GUID))) {
  1419. return TRUE;
  1420. }
  1421. if (IsEqualGUID(&(typeGuid), &(PARTITION_LDM_METADATA_GUID))) {
  1422. return TRUE;
  1423. }
  1424. if (IsEqualGUID(&(typeGuid), &(PARTITION_LDM_DATA_GUID))) {
  1425. return TRUE;
  1426. }
  1427. //
  1428. // It is okay to erase other, unrecognised partitions.
  1429. //
  1430. return TRUE;
  1431. }
  1432. //
  1433. // Checks if it's okay to erase all the partitions on a disk. Returns TRUE for MBR disks.
  1434. // Returns TRUE for GPT disks if all the partitions on it are erasable. A partition that
  1435. // we don't recognise (including OEM partitions, ESP, etc) is considered non-erasable.
  1436. //
  1437. BOOL
  1438. AsrpIsOkayToEraseDisk(
  1439. IN PASR_DISK_INFO pPhysicalDisk
  1440. )
  1441. /*++
  1442. Routine Description:
  1443. Arguments:
  1444. Return Value:
  1445. If the function succeeds, the return value is a nonzero value.
  1446. If the function fails, the return value is zero. To get extended error
  1447. information, call GetLastError().
  1448. --*/
  1449. {
  1450. DWORD index;
  1451. if (PARTITION_STYLE_GPT != pPhysicalDisk->pDriveLayoutEx->PartitionStyle) {
  1452. return TRUE;
  1453. }
  1454. for (index = 0; index < pPhysicalDisk->pDriveLayoutEx->PartitionCount; index++) {
  1455. if (!AsrpIsOkayToErasePartition(&(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[index]))) {
  1456. return FALSE;
  1457. }
  1458. }
  1459. return TRUE;
  1460. }
  1461. BOOL
  1462. AsrpInsertSortedRegion(
  1463. IN OUT PASR_REGION_INFO *Head,
  1464. IN LONGLONG StartingOffset,
  1465. IN LONGLONG RegionLength,
  1466. IN DWORD Index,
  1467. IN LONGLONG MaxLength, // 0 == don't care
  1468. IN ASR_SORT_ORDER SortBy
  1469. )
  1470. /*++
  1471. Routine Description:
  1472. Arguments:
  1473. Return Value:
  1474. If the function succeeds, the return value is a nonzero value.
  1475. If the function fails, the return value is zero. To get extended error
  1476. information, call GetLastError().
  1477. --*/
  1478. {
  1479. PASR_REGION_INFO previousRegion = NULL,
  1480. newRegion = NULL,
  1481. currentRegion = *Head;
  1482. if (RegionLength < (1024*1024)) {
  1483. return TRUE;
  1484. }
  1485. //
  1486. // Alloc mem for the new region and set the fields of interest
  1487. //
  1488. newRegion = (PASR_REGION_INFO) HeapAlloc(
  1489. GetProcessHeap(),
  1490. HEAP_ZERO_MEMORY,
  1491. sizeof(ASR_REGION_INFO)
  1492. );
  1493. if (!newRegion) {
  1494. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1495. return FALSE;
  1496. }
  1497. newRegion->StartingOffset = StartingOffset;
  1498. newRegion->RegionLength = RegionLength;
  1499. newRegion->Index = Index;
  1500. newRegion->pNext = NULL;
  1501. if (!currentRegion) {
  1502. //
  1503. // First item in the list
  1504. //
  1505. *Head = newRegion;
  1506. }
  1507. else {
  1508. while (currentRegion) {
  1509. if (((SortByLength == SortBy) && (currentRegion->RegionLength <= RegionLength))
  1510. || ((SortByStartingOffset == SortBy) && (currentRegion->StartingOffset <= StartingOffset))
  1511. ) {
  1512. previousRegion = currentRegion;
  1513. currentRegion = currentRegion->pNext;
  1514. }
  1515. else {
  1516. //
  1517. // We found the spot, let's add it in.
  1518. //
  1519. //
  1520. // If this is sorted based on start sectors, make sure there's
  1521. // enough space to add this region in, ie that the regions don't overlap.
  1522. //
  1523. if (SortByStartingOffset == SortBy) {
  1524. //
  1525. // Make sure this is after the end of the previous sector
  1526. //
  1527. if (previousRegion) {
  1528. if ((previousRegion->StartingOffset + previousRegion->RegionLength) > StartingOffset) {
  1529. return FALSE;
  1530. }
  1531. }
  1532. //
  1533. // And that this ends before the next sector starts
  1534. //
  1535. if ((StartingOffset + RegionLength) > (currentRegion->StartingOffset)) {
  1536. return FALSE;
  1537. }
  1538. }
  1539. if (!previousRegion) {
  1540. //
  1541. // This is the first node
  1542. //
  1543. *Head = newRegion;
  1544. }
  1545. else {
  1546. previousRegion->pNext = newRegion;
  1547. }
  1548. newRegion->pNext = currentRegion;
  1549. break;
  1550. }
  1551. }
  1552. if (!currentRegion) {
  1553. //
  1554. // We reached the end and didn't add this node in.
  1555. //
  1556. MYASSERT(NULL == previousRegion->pNext);
  1557. //
  1558. // Make sure this is after the end of the previous sector
  1559. //
  1560. if (previousRegion && (MaxLength > 0)) {
  1561. if ((previousRegion->StartingOffset + previousRegion->RegionLength) > MaxLength) {
  1562. return FALSE;
  1563. }
  1564. }
  1565. previousRegion->pNext = newRegion;
  1566. }
  1567. }
  1568. return TRUE;
  1569. }
  1570. BOOL
  1571. AsrpBuildFreeRegionList(
  1572. IN PASR_REGION_INFO PartitionList,
  1573. OUT PASR_REGION_INFO *FreeList,
  1574. IN LONGLONG UsableStartingOffset,
  1575. IN LONGLONG UsableLength
  1576. )
  1577. /*++
  1578. Routine Description:
  1579. Arguments:
  1580. Return Value:
  1581. If the function succeeds, the return value is a nonzero value.
  1582. If the function fails, the return value is zero. To get extended error
  1583. information, call GetLastError().
  1584. --*/
  1585. {
  1586. PASR_REGION_INFO currentRegion = PartitionList,
  1587. previousRegion = NULL;
  1588. LONGLONG previousEnd = UsableStartingOffset;
  1589. while (currentRegion) {
  1590. if (!AsrpInsertSortedRegion(FreeList,
  1591. previousEnd, // free region start offset
  1592. currentRegion->StartingOffset - previousEnd, // free region length,
  1593. 0, // index--not meaningful for this list
  1594. 0,
  1595. SortByLength
  1596. ) ) {
  1597. return FALSE;
  1598. }
  1599. previousEnd = currentRegion->StartingOffset + currentRegion->RegionLength;
  1600. currentRegion = currentRegion->pNext;
  1601. }
  1602. //
  1603. // Add space after the last partition till the end of the disk to
  1604. // our free regions list
  1605. //
  1606. return AsrpInsertSortedRegion(FreeList, // list head
  1607. previousEnd, // free region start offset
  1608. UsableStartingOffset + UsableLength - previousEnd, // free region length
  1609. 0, // slot index in the partition entry table--not meaningful for this list
  1610. 0,
  1611. SortByLength
  1612. );
  1613. }
  1614. //
  1615. // Both partitions and regions are sorted by sizes
  1616. //
  1617. BOOL
  1618. AsrpFitPartitionToFreeRegion(
  1619. IN PASR_REGION_INFO PartitionList,
  1620. IN PASR_REGION_INFO FreeRegionList
  1621. )
  1622. /*++
  1623. Routine Description:
  1624. Arguments:
  1625. Return Value:
  1626. If the function succeeds, the return value is a nonzero value.
  1627. If the function fails, the return value is zero. To get extended error
  1628. information, call GetLastError().
  1629. --*/
  1630. {
  1631. PASR_REGION_INFO partition = PartitionList,
  1632. hole = FreeRegionList;
  1633. while (partition) {
  1634. while (hole && (partition->RegionLength > hole->RegionLength)) {
  1635. hole = hole->pNext;
  1636. }
  1637. if (!hole) {
  1638. //
  1639. // We ran out of holes and have unassigned partitions
  1640. //
  1641. return FALSE;
  1642. }
  1643. partition->StartingOffset = hole->StartingOffset;
  1644. hole->RegionLength -= partition->RegionLength;
  1645. hole->StartingOffset += partition->RegionLength;
  1646. partition = partition->pNext;
  1647. }
  1648. return TRUE;
  1649. }
  1650. //
  1651. // For optimisation purposes, this routine should only be called if:
  1652. // PhysicalDisk and SifDisk are both GPT
  1653. // PhysicalDisk is bigger than SifDisk
  1654. // PhysicalDisk has non-erasable partitions
  1655. //
  1656. BOOL
  1657. AsrpFitGptPartitionsToRegions(
  1658. IN PASR_DISK_INFO SifDisk,
  1659. IN PASR_DISK_INFO PhysicalDisk,
  1660. IN BOOL Commit
  1661. )
  1662. /*++
  1663. Routine Description:
  1664. Arguments:
  1665. Return Value:
  1666. If the function succeeds, the return value is a nonzero value.
  1667. If the function fails, the return value is zero. To get extended error
  1668. information, call GetLastError().
  1669. --*/
  1670. {
  1671. PASR_REGION_INFO partitionList = NULL,
  1672. collisionList = NULL,
  1673. freeRegionList = NULL;
  1674. LONGLONG StartingUsableOffset = 0,
  1675. UsableLength = 0;
  1676. DWORD index = 0;
  1677. BOOL result = TRUE;
  1678. if ((PARTITION_STYLE_GPT != SifDisk->Style) || (PARTITION_STYLE_GPT != PhysicalDisk->Style)) {
  1679. return TRUE;
  1680. }
  1681. StartingUsableOffset = PhysicalDisk->pDriveLayoutEx->Gpt.StartingUsableOffset.QuadPart;
  1682. UsableLength = PhysicalDisk->pDriveLayoutEx->Gpt.UsableLength.QuadPart;
  1683. //
  1684. // First, go through the existing non-erasable partitions, and add them to our list
  1685. // sorted by start sectors.
  1686. //
  1687. for (index = 0; index < PhysicalDisk->pDriveLayoutEx->PartitionCount; index++) {
  1688. if (!AsrpIsOkayToErasePartition(&(PhysicalDisk->pDriveLayoutEx->PartitionEntry[index]))) {
  1689. PPARTITION_INFORMATION_EX currentPtn = &(PhysicalDisk->pDriveLayoutEx->PartitionEntry[index]);
  1690. if (!AsrpInsertSortedRegion(&partitionList,
  1691. currentPtn->StartingOffset.QuadPart,
  1692. currentPtn->PartitionLength.QuadPart,
  1693. index,
  1694. (StartingUsableOffset + UsableLength),
  1695. SortByStartingOffset
  1696. )) {
  1697. result = FALSE;
  1698. break;
  1699. }
  1700. }
  1701. }
  1702. if (partitionList && result) {
  1703. //
  1704. // Then, go through the sif partitions, and add them to a list, sorted by start sectors.
  1705. // For partitions that cannot be added, add them to another list sorted by sizes
  1706. //
  1707. for (index = 0; index < SifDisk->pDriveLayoutEx->PartitionCount; index++) {
  1708. PPARTITION_INFORMATION_EX currentPtn = &(SifDisk->pDriveLayoutEx->PartitionEntry[index]);
  1709. if (!AsrpInsertSortedRegion(&partitionList,
  1710. currentPtn->StartingOffset.QuadPart,
  1711. currentPtn->PartitionLength.QuadPart,
  1712. index,
  1713. (StartingUsableOffset + UsableLength),
  1714. SortByStartingOffset
  1715. )) {
  1716. if (!AsrpInsertSortedRegion(&collisionList,
  1717. currentPtn->StartingOffset.QuadPart,
  1718. currentPtn->PartitionLength.QuadPart,
  1719. index,
  1720. 0,
  1721. SortByLength
  1722. )) {
  1723. result = FALSE;
  1724. break;
  1725. }
  1726. }
  1727. }
  1728. }
  1729. if (collisionList && result) {
  1730. //
  1731. // Go through first list and come up with a list of free regions, sorted by sizes
  1732. //
  1733. result = AsrpBuildFreeRegionList(partitionList, &freeRegionList, StartingUsableOffset, UsableLength);
  1734. }
  1735. if (collisionList && result) {
  1736. //
  1737. // Try adding partitions from list 2 to regions from list 3. If any
  1738. // are left over, return FALSE.
  1739. //
  1740. result = AsrpFitPartitionToFreeRegion(collisionList, freeRegionList);
  1741. if (Commit && result) {
  1742. PASR_REGION_INFO pCurrentRegion = collisionList;
  1743. //
  1744. // Go through the collision list, and update the start sectors of the
  1745. // PartitionEntries in DriveLayoutEx's table.
  1746. //
  1747. while (pCurrentRegion) {
  1748. MYASSERT(SifDisk->pDriveLayoutEx->PartitionEntry[pCurrentRegion->Index].PartitionLength.QuadPart == pCurrentRegion->RegionLength);
  1749. SifDisk->pDriveLayoutEx->PartitionEntry[pCurrentRegion->Index].StartingOffset.QuadPart =
  1750. pCurrentRegion->StartingOffset;
  1751. pCurrentRegion = pCurrentRegion->pNext;
  1752. }
  1753. }
  1754. }
  1755. AsrpFreeRegionInfo(partitionList);
  1756. AsrpFreeRegionInfo(collisionList);
  1757. AsrpFreeRegionInfo(freeRegionList);
  1758. return result;
  1759. }
  1760. BOOL
  1761. AsrpIsThisDiskABetterFit(
  1762. IN PASR_DISK_INFO CurrentBest,
  1763. IN PASR_DISK_INFO PhysicalDisk,
  1764. IN PASR_DISK_INFO SifDisk,
  1765. IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx,
  1766. OUT BOOL *IsAligned
  1767. )
  1768. /*++
  1769. Routine Description:
  1770. Arguments:
  1771. Return Value:
  1772. If the function succeeds, the return value is a nonzero value.
  1773. If the function fails, the return value is zero. To get extended error
  1774. information, call GetLastError().
  1775. --*/
  1776. {
  1777. LONGLONG endingOffset;
  1778. if (ARGUMENT_PRESENT(IsAligned)) {
  1779. *IsAligned = FALSE;
  1780. }
  1781. //
  1782. // Make sure the bytes-per-sector values match
  1783. //
  1784. if (PhysicalDisk->pDiskGeometry->BytesPerSector != SifDisk->pDiskGeometry->BytesPerSector) {
  1785. return FALSE;
  1786. }
  1787. if (PhysicalDisk->pPartition0Ex->PartitionLength.QuadPart >=
  1788. SifDisk->pPartition0Ex->PartitionLength.QuadPart) {
  1789. if ((!CurrentBest) ||
  1790. (PhysicalDisk->pPartition0Ex->PartitionLength.QuadPart <
  1791. CurrentBest->pPartition0Ex->PartitionLength.QuadPart)) {
  1792. //
  1793. // This disk is smaller than our current best (or we don't have a
  1794. // current best). Now try laying out the partitions to see if
  1795. // they fit.
  1796. //
  1797. if (PARTITION_STYLE_GPT == SifDisk->Style) {
  1798. //
  1799. // If the disk has no partitions that need to be preserved,
  1800. // we can use all of it.
  1801. if (AsrpIsOkayToEraseDisk(PhysicalDisk)) {
  1802. return TRUE;
  1803. }
  1804. else {
  1805. //
  1806. // This disk has some regions that need to be preserved. So
  1807. // we try to fit our partitions in the holes
  1808. //
  1809. return AsrpFitGptPartitionsToRegions(SifDisk, PhysicalDisk, FALSE); // No commmit
  1810. }
  1811. }
  1812. else if (PARTITION_STYLE_MBR == SifDisk->Style) {
  1813. if (!pTempDriveLayoutEx) {
  1814. //
  1815. // Caller doesn't want to try cylinder-aligning partitions
  1816. //
  1817. return TRUE;
  1818. }
  1819. //
  1820. // For MBR disks, the partitions have to be cylinder aligned
  1821. //
  1822. // AsrpCylinderAlignMbrPartitions(,,0,,) returns the ending offset (bytes)
  1823. // of the entries in the MBR.
  1824. //
  1825. endingOffset = AsrpCylinderAlignMbrPartitions(SifDisk,
  1826. pTempDriveLayoutEx,
  1827. 0, // starting index--0 for the MBR
  1828. 0, // starting offset, assume the partitions begin at the start of the disk
  1829. PhysicalDisk->pDiskGeometry
  1830. );
  1831. if ((endingOffset != -1) &&
  1832. (endingOffset <= SifDisk->pPartition0Ex->PartitionLength.QuadPart)
  1833. ) {
  1834. if (ARGUMENT_PRESENT(IsAligned)) {
  1835. *IsAligned = TRUE;
  1836. }
  1837. return TRUE;
  1838. }
  1839. else {
  1840. //
  1841. // We couldn't fit the partitions on to the disk when we
  1842. // tried to cylinder align them. If the disk geometries
  1843. // are the same, this may still be okay.
  1844. //
  1845. if ((SifDisk->pDiskGeometry->BytesPerSector == PhysicalDisk->pDiskGeometry->BytesPerSector) &&
  1846. (SifDisk->pDiskGeometry->SectorsPerTrack == PhysicalDisk->pDiskGeometry->SectorsPerTrack) &&
  1847. (SifDisk->pDiskGeometry->TracksPerCylinder == PhysicalDisk->pDiskGeometry->TracksPerCylinder)
  1848. ) {
  1849. return TRUE;
  1850. }
  1851. else {
  1852. return FALSE;
  1853. }
  1854. }
  1855. }
  1856. else {
  1857. MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)");
  1858. }
  1859. }
  1860. }
  1861. return FALSE;
  1862. }
  1863. //
  1864. // Assigns sif-disks to physical disks with matching signatures, if
  1865. // any exist. If the disk is critical, or the partition-layout matches,
  1866. // the disk is marked as intact.
  1867. //
  1868. // Returns
  1869. // FALSE if a critical disk is absent
  1870. // TRUE if all critical disks are present
  1871. //
  1872. BOOL
  1873. AsrpAssignBySignature(
  1874. IN OUT PASR_DISK_INFO pSifDiskList,
  1875. IN OUT PASR_DISK_INFO pPhysicalDiskList,
  1876. OUT PULONG pMaxPartitionCount
  1877. )
  1878. /*++
  1879. Routine Description:
  1880. Arguments:
  1881. Return Value:
  1882. If the function succeeds, the return value is a nonzero value.
  1883. If the function fails, the return value is zero. To get extended error
  1884. information, call GetLastError().
  1885. --*/
  1886. {
  1887. BOOL result = TRUE,
  1888. done = FALSE,
  1889. found = FALSE,
  1890. isAligned = FALSE;
  1891. PASR_DISK_INFO sifDisk = pSifDiskList,
  1892. physicalDisk = pPhysicalDiskList;
  1893. PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutTemp = NULL;
  1894. ULONG tableSize = 128; // start off at a reasonably high size
  1895. HANDLE heapHandle = GetProcessHeap();
  1896. pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  1897. heapHandle,
  1898. HEAP_ZERO_MEMORY,
  1899. sizeof(DRIVE_LAYOUT_INFORMATION) + (tableSize * sizeof(PARTITION_INFORMATION_EX))
  1900. );
  1901. if (!pAlignedLayoutTemp) {
  1902. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1903. result = FALSE;
  1904. goto EXIT;
  1905. }
  1906. *pMaxPartitionCount = 0;
  1907. //
  1908. // For now, this is O(n-squared), since both lists are unsorted.
  1909. //
  1910. while (sifDisk && !done) {
  1911. if (!(sifDisk->pDriveLayoutEx) || !(sifDisk->pDriveLayoutEx->Mbr.Signature)) {
  1912. //
  1913. // we won't assign disks with no signature here
  1914. //
  1915. sifDisk = sifDisk->pNext;
  1916. continue;
  1917. }
  1918. if (sifDisk->pDriveLayoutEx->PartitionCount > *pMaxPartitionCount) {
  1919. *pMaxPartitionCount = sifDisk->pDriveLayoutEx->PartitionCount;
  1920. }
  1921. if (sifDisk->pDriveLayoutEx->PartitionCount > tableSize) {
  1922. tableSize = sifDisk->pDriveLayoutEx->PartitionCount + 128;
  1923. _AsrpHeapFree(pAlignedLayoutTemp);
  1924. pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  1925. heapHandle,
  1926. HEAP_ZERO_MEMORY,
  1927. sizeof(DRIVE_LAYOUT_INFORMATION) + (tableSize * sizeof(PARTITION_INFORMATION_EX))
  1928. );
  1929. if (!pAlignedLayoutTemp) {
  1930. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  1931. result = FALSE;
  1932. goto EXIT;
  1933. }
  1934. }
  1935. found = FALSE;
  1936. physicalDisk = pPhysicalDiskList;
  1937. while (physicalDisk && !found) {
  1938. //
  1939. // For MBR disks, we use the signature
  1940. // For GPT disks, we use the disk ID
  1941. //
  1942. if (sifDisk->Style == physicalDisk->Style) {
  1943. if ((PARTITION_STYLE_MBR == sifDisk->Style) &&
  1944. (physicalDisk->pDriveLayoutEx->Mbr.Signature == sifDisk->pDriveLayoutEx->Mbr.Signature)
  1945. ) {
  1946. //
  1947. // MBR disks, signatures match
  1948. //
  1949. found = TRUE;
  1950. AsrpPrintDbgMsg(_asrlog,
  1951. "Harddisk %lu matched disk %lu in section [%ws] of the ASR state file. (MBR signatures 0x%x match).\r\n",
  1952. physicalDisk->DeviceNumber,
  1953. sifDisk->SifDiskKey,
  1954. ASR_SIF_MBR_DISKS_SECTION,
  1955. sifDisk->pDriveLayoutEx->Mbr.Signature
  1956. );
  1957. }
  1958. else if (
  1959. (PARTITION_STYLE_GPT == sifDisk->Style) &&
  1960. IsEqualGUID(&(sifDisk->pDriveLayoutEx->Gpt.DiskId), &(physicalDisk->pDriveLayoutEx->Gpt.DiskId))
  1961. ) {
  1962. found = TRUE;
  1963. AsrpPrintDbgMsg(_asrlog,
  1964. "Harddisk %lu matched disk %lu in section [%ws] of the ASR state file. (GPT Disk-ID's match).\r\n",
  1965. physicalDisk->DeviceNumber,
  1966. sifDisk->SifDiskKey,
  1967. ASR_SIF_GPT_DISKS_SECTION
  1968. );
  1969. }
  1970. else {
  1971. physicalDisk = physicalDisk->pNext;
  1972. }
  1973. }
  1974. else {
  1975. physicalDisk = physicalDisk->pNext;
  1976. }
  1977. }
  1978. if (sifDisk->IsCritical) {
  1979. if (found) {
  1980. sifDisk->AssignedTo = physicalDisk;
  1981. physicalDisk->AssignedTo = sifDisk;
  1982. //
  1983. // We don't check the partition layout on critical disks since they
  1984. // may have been repartitioned in text-mode Setup.
  1985. //
  1986. sifDisk->IsIntact = TRUE;
  1987. sifDisk->AssignedTo->IsIntact = TRUE;
  1988. }
  1989. else {
  1990. //
  1991. // Critical disk was not found. Fatal error.
  1992. //
  1993. SetLastError(ERROR_DEVICE_NOT_CONNECTED);
  1994. result = FALSE;
  1995. done = TRUE;
  1996. AsrpPrintDbgMsg(_asrerror,
  1997. "Critical disk not found (Entry %lu in section [%ws]).\r\n",
  1998. sifDisk->SifDiskKey,
  1999. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2000. );
  2001. }
  2002. }
  2003. else {
  2004. if (found) {
  2005. //
  2006. // We found a disk with matching signature. Now let's just
  2007. // make sure that the partitions actually fit on the disk
  2008. // before assigning it
  2009. //
  2010. isAligned = FALSE;
  2011. if ((sifDisk->pDriveLayoutEx->PartitionCount == 0) || // disk has no partitions
  2012. AsrpIsThisDiskABetterFit(NULL, physicalDisk, sifDisk, pAlignedLayoutTemp, &isAligned) // partitions fit on disk
  2013. ) {
  2014. sifDisk->AssignedTo = physicalDisk;
  2015. physicalDisk->AssignedTo = sifDisk;
  2016. sifDisk->IsAligned = isAligned;
  2017. physicalDisk->IsAligned = isAligned;
  2018. if (AsrpIsDiskIntact(sifDisk, physicalDisk)) {
  2019. sifDisk->IsIntact = TRUE;
  2020. sifDisk->AssignedTo->IsIntact = TRUE;
  2021. }
  2022. }
  2023. else {
  2024. AsrpPrintDbgMsg(_asrlog,
  2025. "Harddisk %lu is not big enough to contain the partitions on disk %lu in section [%ws] of the ASR state file.\r\n",
  2026. physicalDisk->DeviceNumber,
  2027. sifDisk->SifDiskKey,
  2028. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2029. );
  2030. }
  2031. }
  2032. }
  2033. sifDisk = sifDisk->pNext;
  2034. } // while
  2035. EXIT:
  2036. _AsrpHeapFree(pAlignedLayoutTemp);
  2037. return result;
  2038. }
  2039. //
  2040. // Attempts to assign remaining sif disks to physical disks that
  2041. // are on the same bus as the sif disk originally was (ie if
  2042. // any other disk on that bus has been assigned, this tries to assign
  2043. // this disk to the same bus)
  2044. //
  2045. BOOL
  2046. AsrpAssignByBus(
  2047. IN OUT PASR_DISK_INFO pSifDiskList,
  2048. IN OUT PASR_DISK_INFO pPhysicalDiskList,
  2049. IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx
  2050. )
  2051. /*++
  2052. Routine Description:
  2053. Arguments:
  2054. Return Value:
  2055. If the function succeeds, the return value is a nonzero value.
  2056. If the function fails, the return value is zero. To get extended error
  2057. information, call GetLastError().
  2058. --*/
  2059. {
  2060. PASR_DISK_INFO sifDisk = pSifDiskList,
  2061. physicalDisk = NULL,
  2062. currentBest = NULL,
  2063. tempSifDisk = NULL;
  2064. BOOL done = FALSE,
  2065. isAligned = FALSE,
  2066. isAlignedTemp = FALSE;
  2067. ULONG targetBusId = 0;
  2068. while (sifDisk) {
  2069. //
  2070. // Skip disks that have already found a home, and disks for which
  2071. // we didn't have any bus/group info even on the original system
  2072. //
  2073. if ((NULL != sifDisk->AssignedTo) || // already assigned
  2074. (0 == sifDisk->SifBusKey) // this disk couldn't be grouped
  2075. ) {
  2076. sifDisk = sifDisk->pNext;
  2077. continue;
  2078. }
  2079. //
  2080. // Find another (sif) disk that used to be on the same (sif) bus,
  2081. // and has already been assigned to a physical disk.
  2082. //
  2083. targetBusId = 0;
  2084. tempSifDisk = pSifDiskList;
  2085. done = FALSE;
  2086. while (tempSifDisk && !done) {
  2087. if ((tempSifDisk->SifBusKey == sifDisk->SifBusKey) && // same bus
  2088. (tempSifDisk->AssignedTo != NULL) // assigned
  2089. ) {
  2090. targetBusId = tempSifDisk->AssignedTo->SifBusKey; // the physical bus
  2091. //
  2092. // If this physical disk is on an unknown bus,
  2093. // (target id = sifbuskey = 0) then we want to try and look
  2094. // for another disk on the same (sif) bus. Hence done is
  2095. // TRUE only if targetId != 0
  2096. //
  2097. if (targetBusId) {
  2098. done = TRUE;
  2099. }
  2100. }
  2101. tempSifDisk = tempSifDisk->pNext;
  2102. } // while
  2103. if (targetBusId) { // we found another disk on the same bus
  2104. //
  2105. // Go through the physical disks on the same bus, and try to
  2106. // find the best fit for this disk. Best fit is the smallest
  2107. // disk on the bus that's big enough for us.
  2108. //
  2109. physicalDisk = pPhysicalDiskList;
  2110. currentBest = NULL;
  2111. while (physicalDisk) {
  2112. if ((NULL == physicalDisk->AssignedTo) && // not assigned
  2113. (physicalDisk->SifBusKey == targetBusId) && // same bus
  2114. (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp))
  2115. ) {
  2116. isAligned = isAlignedTemp;
  2117. currentBest = physicalDisk;
  2118. }
  2119. physicalDisk = physicalDisk->pNext;
  2120. } // while
  2121. sifDisk->AssignedTo = currentBest; // may be null if no match was found
  2122. sifDisk->IsAligned = isAligned;
  2123. if (currentBest) {
  2124. currentBest->AssignedTo = sifDisk;
  2125. currentBest->IsAligned = isAligned;
  2126. AsrpPrintDbgMsg(_asrlog,
  2127. "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on storage bus).\r\n",
  2128. currentBest->DeviceNumber,
  2129. sifDisk->SifDiskKey,
  2130. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2131. );
  2132. }
  2133. }
  2134. sifDisk = sifDisk->pNext;
  2135. } // while sifdisk
  2136. return TRUE;
  2137. }
  2138. //
  2139. // Attempts to assign remaining sif disks to physical disks that
  2140. // are on any bus of the same type (SCSI, IDE, etc) as the sif disk
  2141. // originally was
  2142. //
  2143. BOOL
  2144. AsrpAssignByBusType(
  2145. IN OUT PASR_DISK_INFO pSifDiskList,
  2146. IN OUT PASR_DISK_INFO pPhysicalDiskList,
  2147. IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx
  2148. )
  2149. /*++
  2150. Routine Description:
  2151. Arguments:
  2152. Return Value:
  2153. If the function succeeds, the return value is a nonzero value.
  2154. If the function fails, the return value is zero. To get extended error
  2155. information, call GetLastError().
  2156. --*/
  2157. {
  2158. PASR_DISK_INFO sifDisk = pSifDiskList,
  2159. physicalDisk = NULL,
  2160. currentBest = NULL;
  2161. STORAGE_BUS_TYPE targetBusType;
  2162. BOOL isAligned = FALSE,
  2163. isAlignedTemp = FALSE;
  2164. while (sifDisk) {
  2165. //
  2166. // Skip disks that have already found a home, and disks for which
  2167. // we didn't have any bus/group info even on the original system
  2168. //
  2169. if ((NULL != sifDisk->AssignedTo) || // already assigned
  2170. (BusTypeUnknown == sifDisk->BusType) // this disk couldn't be grouped
  2171. ) {
  2172. sifDisk = sifDisk->pNext;
  2173. continue;
  2174. }
  2175. //
  2176. // Go through the physical disks, and try to
  2177. // find the best fit for this disk. Best fit is the smallest
  2178. // disk on any bus of the same bus type that's big enough for us.
  2179. //
  2180. physicalDisk = pPhysicalDiskList;
  2181. currentBest = NULL;
  2182. while (physicalDisk) {
  2183. if ((NULL == physicalDisk->AssignedTo) && // not assigned
  2184. (physicalDisk->BusType == sifDisk->BusType) && // same bus type
  2185. (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp))
  2186. ) {
  2187. isAligned = isAlignedTemp;
  2188. currentBest = physicalDisk;
  2189. }
  2190. physicalDisk = physicalDisk->pNext;
  2191. } // while
  2192. sifDisk->AssignedTo = currentBest; // may be null if no match was found
  2193. sifDisk->IsAligned = isAligned;
  2194. if (currentBest) {
  2195. currentBest->AssignedTo = sifDisk;
  2196. currentBest->IsAligned = isAligned;
  2197. AsrpPrintDbgMsg(_asrlog,
  2198. "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on storage bus type).\r\n",
  2199. currentBest->DeviceNumber,
  2200. sifDisk->SifDiskKey,
  2201. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2202. );
  2203. AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx);
  2204. }
  2205. sifDisk = sifDisk->pNext;
  2206. } // while sifdisk
  2207. return TRUE;
  2208. }
  2209. //
  2210. // Okay, so by now we've tried putting disks on the same bus, and
  2211. // the same bus type. For disks that didn't fit using either of those
  2212. // rules (or for which we didn't have any bus info at all), let's just
  2213. // try to fit them where ever possible on the system.
  2214. //
  2215. BOOL
  2216. AsrpAssignRemaining(
  2217. IN OUT PASR_DISK_INFO pSifDiskList,
  2218. IN OUT PASR_DISK_INFO pPhysicalDiskList,
  2219. IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx
  2220. )
  2221. /*++
  2222. Routine Description:
  2223. Arguments:
  2224. Return Value:
  2225. If the function succeeds, the return value is a nonzero value.
  2226. If the function fails, the return value is zero. To get extended error
  2227. information, call GetLastError().
  2228. --*/
  2229. {
  2230. PASR_DISK_INFO sifDisk = pSifDiskList,
  2231. physicalDisk = NULL,
  2232. currentBest = NULL;
  2233. BOOL isAligned = FALSE,
  2234. isAlignedTemp = FALSE;
  2235. while (sifDisk) {
  2236. //
  2237. // Skip disks that have already found a home
  2238. //
  2239. if (NULL != sifDisk->AssignedTo) {
  2240. sifDisk = sifDisk->pNext;
  2241. continue;
  2242. }
  2243. //
  2244. // Go through the physical disks, and try to find the best
  2245. // fit for this disk. Best fit is the smallest disk anywhere
  2246. // on the system that's big enough for us.
  2247. //
  2248. physicalDisk = pPhysicalDiskList;
  2249. currentBest = NULL;
  2250. while (physicalDisk) {
  2251. if ((NULL == physicalDisk->AssignedTo) && // not assigned
  2252. (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp))
  2253. ) {
  2254. isAligned = isAlignedTemp;
  2255. currentBest = physicalDisk;
  2256. }
  2257. physicalDisk = physicalDisk->pNext;
  2258. } // while
  2259. sifDisk->AssignedTo = currentBest; // may be null if no match was found
  2260. sifDisk->IsAligned = isAligned;
  2261. if (currentBest) {
  2262. currentBest->AssignedTo = sifDisk;
  2263. currentBest->IsAligned = isAligned;
  2264. AsrpPrintDbgMsg(_asrlog,
  2265. "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on size).\r\n",
  2266. currentBest->DeviceNumber,
  2267. sifDisk->SifDiskKey,
  2268. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2269. );
  2270. AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx);
  2271. AsrpAssignByBusType(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx);
  2272. }
  2273. sifDisk = sifDisk->pNext;
  2274. } // while sifdisk
  2275. return TRUE;
  2276. }
  2277. BOOL
  2278. AsrpIsPartitionExtendible(
  2279. IN CONST UCHAR PartitionType
  2280. )
  2281. /*++
  2282. Routine Description:
  2283. Arguments:
  2284. Return Value:
  2285. If the function succeeds, the return value is a nonzero value.
  2286. If the function fails, the return value is zero. To get extended error
  2287. information, call GetLastError().
  2288. --*/
  2289. {
  2290. switch (PartitionType) {
  2291. case PARTITION_EXTENDED:
  2292. case PARTITION_IFS:
  2293. case PARTITION_XINT13:
  2294. case PARTITION_XINT13_EXTENDED:
  2295. return TRUE;
  2296. default:
  2297. return FALSE;
  2298. }
  2299. return FALSE;
  2300. }
  2301. BOOL
  2302. AsrpAutoExtendMbrPartitions(
  2303. IN PASR_DISK_INFO pSifDisk,
  2304. IN PASR_DISK_INFO pPhysicalDisk,
  2305. IN LONGLONG LastUsedPhysicalDiskOffset
  2306. )
  2307. /*++
  2308. Routine Description:
  2309. Arguments:
  2310. Return Value:
  2311. If the function succeeds, the return value is a nonzero value.
  2312. If the function fails, the return value is zero. To get extended error
  2313. information, call GetLastError().
  2314. --*/
  2315. {
  2316. PDISK_GEOMETRY physicalGeometry = NULL;
  2317. IN PDRIVE_LAYOUT_INFORMATION_EX sifLayout = NULL,
  2318. physicalLayout = NULL;
  2319. LONGLONG MaxSifDiskOffset = 0,
  2320. MaxPhysicalDiskOffset = 0,
  2321. LastUsedSifDiskOffset = 0;
  2322. DWORD count = 0;
  2323. BOOL madeAChange = FALSE;
  2324. //
  2325. // Find the last sector of the disk
  2326. //
  2327. MaxSifDiskOffset = pSifDisk->pPartition0Ex->PartitionLength.QuadPart;
  2328. physicalGeometry = pPhysicalDisk->pDiskGeometry;
  2329. MaxPhysicalDiskOffset = (physicalGeometry->BytesPerSector) *
  2330. (physicalGeometry->SectorsPerTrack) *
  2331. (physicalGeometry->TracksPerCylinder) *
  2332. (physicalGeometry->Cylinders.QuadPart);
  2333. //
  2334. // Did the old disk have empty space at the end?
  2335. //
  2336. sifLayout = pSifDisk->pDriveLayoutEx;
  2337. for (count = 0; count < sifLayout->PartitionCount; count++) {
  2338. if (((sifLayout->PartitionEntry[count].StartingOffset.QuadPart) +
  2339. (sifLayout->PartitionEntry[count].PartitionLength.QuadPart))
  2340. > LastUsedSifDiskOffset) {
  2341. LastUsedSifDiskOffset = (sifLayout->PartitionEntry[count].StartingOffset.QuadPart +
  2342. sifLayout->PartitionEntry[count].PartitionLength.QuadPart);
  2343. }
  2344. }
  2345. if ((LastUsedSifDiskOffset + ASR_AUTO_EXTEND_MAX_FREE_SPACE_IGNORED) >= MaxSifDiskOffset) {
  2346. //
  2347. // No, it didn't. Extend the last partition.
  2348. //
  2349. physicalLayout = pPhysicalDisk->pDriveLayoutEx;
  2350. for (count = 0; count < physicalLayout->PartitionCount; count++) {
  2351. if (((physicalLayout->PartitionEntry[count].StartingOffset.QuadPart) +
  2352. (physicalLayout->PartitionEntry[count].PartitionLength.QuadPart))
  2353. == LastUsedPhysicalDiskOffset
  2354. ) {
  2355. if (AsrpIsPartitionExtendible(physicalLayout->PartitionEntry[count].Mbr.PartitionType)) {
  2356. physicalLayout->PartitionEntry[count].PartitionLength.QuadPart +=
  2357. (MaxPhysicalDiskOffset - LastUsedPhysicalDiskOffset);
  2358. madeAChange = TRUE;
  2359. }
  2360. }
  2361. }
  2362. }
  2363. if (madeAChange) {
  2364. AsrpPrintDbgMsg(_asrlog,
  2365. "Extended partitions on Harddisk %lu (assigned to disk %lu in section [%ws]).\r\n",
  2366. pPhysicalDisk->DeviceNumber,
  2367. pSifDisk->SifDiskKey,
  2368. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2369. );
  2370. }
  2371. else {
  2372. AsrpPrintDbgMsg(_asrinfo,
  2373. "Did not extend partitions on Harddisk %lu (assigned to disk %lu in section [%ws]).\r\n",
  2374. pPhysicalDisk->DeviceNumber,
  2375. pSifDisk->SifDiskKey,
  2376. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2377. );
  2378. }
  2379. return madeAChange;
  2380. }
  2381. //
  2382. // Try to determine which sif disks end up on which physical disk.
  2383. //
  2384. BOOL
  2385. AsrpAssignDisks(
  2386. IN OUT PASR_DISK_INFO pSifDiskList,
  2387. IN OUT PASR_DISK_INFO pPhysicalDiskList,
  2388. IN PASR_PTN_INFO_LIST pSifMbrPtnList,
  2389. IN PASR_PTN_INFO_LIST pSifGptPtnList,
  2390. IN BOOL AllOrNothing,
  2391. IN BOOL AllowAutoExtend
  2392. )
  2393. /*++
  2394. Routine Description:
  2395. Arguments:
  2396. Return Value:
  2397. If the function succeeds, the return value is a nonzero value.
  2398. If the function fails, the return value is zero. To get extended error
  2399. information, call GetLastError().
  2400. --*/
  2401. {
  2402. ULONG maxSifPartitionCount = 0;
  2403. PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutTemp = NULL;
  2404. LONGLONG endingOffset = 0;
  2405. BOOL reAlloc = TRUE;
  2406. HANDLE heapHandle = GetProcessHeap();
  2407. PASR_DISK_INFO sifDisk = NULL;
  2408. PASR_PTN_INFO pCurrentPtn = NULL;
  2409. PPARTITION_INFORMATION_EX pCurrentEntry = NULL;
  2410. DWORD index = 0, preserveIndex = 0;
  2411. if (!AsrpAssignBySignature(pSifDiskList, pPhysicalDiskList, &maxSifPartitionCount)) {
  2412. //
  2413. // Critical disks were not found
  2414. //
  2415. return FALSE;
  2416. }
  2417. pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  2418. heapHandle,
  2419. HEAP_ZERO_MEMORY,
  2420. sizeof(DRIVE_LAYOUT_INFORMATION) + (maxSifPartitionCount * sizeof(PARTITION_INFORMATION_EX))
  2421. );
  2422. if (!pAlignedLayoutTemp) {
  2423. return FALSE;
  2424. }
  2425. AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp);
  2426. AsrpAssignByBusType(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp);
  2427. AsrpAssignRemaining(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp);
  2428. _AsrpHeapFree(pAlignedLayoutTemp);
  2429. //
  2430. // All disks should be assigned by now, we now cylinder-snap
  2431. // the partition boundaries. If AllOrNothing is TRUE,
  2432. // we return false if any sif-disk couldn't be assigned.
  2433. //
  2434. sifDisk = pSifDiskList;
  2435. while (sifDisk) {
  2436. if (sifDisk->IsIntact || sifDisk->IsCritical) {
  2437. //
  2438. // We won't be re-partitioning critical disks or disks that are
  2439. // intact, so it's no point trying to cylinder-align them.
  2440. //
  2441. sifDisk = sifDisk->pNext;
  2442. continue;
  2443. }
  2444. if (NULL == sifDisk->AssignedTo) {
  2445. AsrpPrintDbgMsg(_asrlog,
  2446. "Disk %lu in section [%ws] could not be restored (no matching disks found).\r\n",
  2447. sifDisk->SifDiskKey,
  2448. ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  2449. );
  2450. //
  2451. // This disk couldn't be assigned. If AllOrNothing is set, we return
  2452. // FALSE, since we couldn't assign All.
  2453. //
  2454. if (AllOrNothing) {
  2455. SetLastError(ERROR_NOT_FOUND);
  2456. return FALSE;
  2457. }
  2458. else {
  2459. sifDisk = sifDisk->pNext;
  2460. continue;
  2461. }
  2462. }
  2463. if (PARTITION_STYLE_MBR == sifDisk->Style) {
  2464. //
  2465. // Assume that we need to re-allocate mem for the physical disk's
  2466. // partition table.
  2467. //
  2468. reAlloc = TRUE;
  2469. if (sifDisk->AssignedTo->pDriveLayoutEx) {
  2470. if (sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount ==
  2471. sifDisk->pDriveLayoutEx->PartitionCount) {
  2472. //
  2473. // If the physical drive happened to have the same number of
  2474. // partitions, the drive layout struct is exactly the right
  2475. // size, so we don't have to re-allocate it.
  2476. //
  2477. reAlloc = FALSE;
  2478. //
  2479. // consistency check. If the partition counts are
  2480. // the same, the size of the drive layout stucts must be the same, too.
  2481. //
  2482. MYASSERT(sifDisk->AssignedTo->sizeDriveLayoutEx == sifDisk->sizeDriveLayoutEx);
  2483. }
  2484. }
  2485. if (reAlloc) {
  2486. //
  2487. // The partition tables are of different sizes
  2488. //
  2489. _AsrpHeapFree(sifDisk->AssignedTo->pDriveLayoutEx);
  2490. sifDisk->AssignedTo->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  2491. heapHandle,
  2492. HEAP_ZERO_MEMORY,
  2493. sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  2494. ((sifDisk->pDriveLayoutEx->PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX))
  2495. );
  2496. if (!sifDisk->AssignedTo->pDriveLayoutEx) {
  2497. AsrpPrintDbgMsg(_asrerror, "Out of memory.\r\n");
  2498. SetLastError(ERROR_NOT_ENOUGH_MEMORY);
  2499. return FALSE;
  2500. }
  2501. }
  2502. //
  2503. // Set the fields of interest
  2504. //
  2505. sifDisk->AssignedTo->sizeDriveLayoutEx = sifDisk->sizeDriveLayoutEx;
  2506. sifDisk->AssignedTo->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR;
  2507. if (sifDisk->IsAligned) {
  2508. sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount = sifDisk->pDriveLayoutEx->PartitionCount;
  2509. sifDisk->AssignedTo->pDriveLayoutEx->Mbr.Signature = sifDisk->pDriveLayoutEx->Mbr.Signature;
  2510. //
  2511. // Cylinder-snap the partition boundaries
  2512. //
  2513. endingOffset = AsrpCylinderAlignMbrPartitions(
  2514. sifDisk,
  2515. sifDisk->AssignedTo->pDriveLayoutEx,
  2516. 0, // starting index--0 for the MBR
  2517. 0, // starting offset, assume the partitions begin at the start of the disk
  2518. sifDisk->AssignedTo->pDiskGeometry
  2519. );
  2520. MYASSERT(endingOffset != -1);
  2521. if (-1 == endingOffset) {
  2522. AsrpPrintDbgMsg(_asrlog,
  2523. "Partitions on disk %lu in section [%ws] could not be restored.\r\n",
  2524. sifDisk->SifDiskKey,
  2525. ASR_SIF_MBR_DISKS_SECTION
  2526. );
  2527. if (AllOrNothing) {
  2528. SetLastError(ERROR_HANDLE_DISK_FULL);
  2529. return FALSE;
  2530. }
  2531. else {
  2532. sifDisk = sifDisk->pNext;
  2533. continue;
  2534. }
  2535. }
  2536. MYASSERT(endingOffset <= sifDisk->AssignedTo->pPartition0Ex->PartitionLength.QuadPart);
  2537. if ((endingOffset) > (sifDisk->AssignedTo->pPartition0Ex->PartitionLength.QuadPart)) {
  2538. AsrpPrintDbgMsg(_asrlog,
  2539. "Partitions on disk %lu in section [%ws] could not be restored.\r\n",
  2540. sifDisk->SifDiskKey,
  2541. ASR_SIF_MBR_DISKS_SECTION
  2542. );
  2543. if (AllOrNothing) {
  2544. SetLastError(ERROR_HANDLE_DISK_FULL);
  2545. return FALSE;
  2546. }
  2547. else {
  2548. sifDisk = sifDisk->pNext;
  2549. continue;
  2550. }
  2551. }
  2552. if (AllowAutoExtend) {
  2553. AsrpAutoExtendMbrPartitions(sifDisk, sifDisk->AssignedTo, endingOffset);
  2554. }
  2555. //
  2556. // Now, we need to go through our partition list, and update the start sector
  2557. // for the partitions in that list. This is needed since we use the start
  2558. // sector later to assign the volume guids to the partitions.
  2559. //
  2560. pCurrentPtn = pSifMbrPtnList[sifDisk->SifDiskKey].pOffsetHead;
  2561. while (pCurrentPtn) {
  2562. pCurrentPtn->PartitionInfo.StartingOffset.QuadPart =
  2563. sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].StartingOffset.QuadPart;
  2564. pCurrentPtn->PartitionInfo.PartitionLength.QuadPart =
  2565. sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].PartitionLength.QuadPart;
  2566. pCurrentPtn = pCurrentPtn->pOffsetNext;
  2567. }
  2568. }
  2569. else {
  2570. //
  2571. // The partitions didn't fit when we cylinder-aligned them.
  2572. // However, the current disk geometry is identical to the
  2573. // original disk geometry, so we can recreate the partitions
  2574. // exactly the way they were before. Let's just copy over
  2575. // the partition layout.
  2576. //
  2577. CopyMemory(sifDisk->AssignedTo->pDriveLayoutEx,
  2578. sifDisk->pDriveLayoutEx,
  2579. sifDisk->sizeDriveLayoutEx
  2580. );
  2581. for (index = 0; index < sifDisk->pDriveLayoutEx->PartitionCount; index++) {
  2582. sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index].RewritePartition = TRUE;
  2583. }
  2584. }
  2585. }
  2586. else if (PARTITION_STYLE_GPT == sifDisk->Style) {
  2587. DWORD sizeNewDriveLayoutEx = 0;
  2588. PDRIVE_LAYOUT_INFORMATION_EX pNewDriveLayoutEx = NULL;
  2589. /*
  2590. The MaxPartitionCount values are different for the two disks. We can't do
  2591. much here, so we'll just ignore it.
  2592. if ((PARTITION_STYLE_GPT == sifDisk->AssignedTo->Style) &&
  2593. (sifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount
  2594. > sifDisk->AssignedTo->pDriveLayoutEx->Gpt.MaxPartitionCount)) {
  2595. MYASSERT(0 && L"Not yet implemented: sifdisk MaxPartitionCount > physicalDisk->MaxPartitionCount");
  2596. sifDisk = sifDisk->pNext;
  2597. continue;
  2598. }
  2599. */
  2600. //
  2601. // Allocate a pDriveLayoutEx struct large enough to hold all the partitions on both
  2602. // the sif disk and the physical disk.
  2603. //
  2604. sizeNewDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) +
  2605. (sizeof(PARTITION_INFORMATION_EX) *
  2606. (sifDisk->pDriveLayoutEx->PartitionCount +
  2607. sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount - 1 )
  2608. );
  2609. pNewDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  2610. heapHandle,
  2611. HEAP_ZERO_MEMORY,
  2612. sizeNewDriveLayoutEx
  2613. );
  2614. if (!pNewDriveLayoutEx) {
  2615. return FALSE;
  2616. }
  2617. preserveIndex = 0;
  2618. if (!sifDisk->IsIntact && !AsrpIsOkayToEraseDisk(sifDisk->AssignedTo)) {
  2619. //
  2620. // This disk is not intact, but it has partitions that must be preserved.
  2621. //
  2622. if (!AsrpFitGptPartitionsToRegions(sifDisk, sifDisk->AssignedTo, TRUE)) {
  2623. AsrpPrintDbgMsg(_asrlog,
  2624. "Partitions on disk %lu in section [%ws] could not be restored.\r\n",
  2625. sifDisk->SifDiskKey,
  2626. ASR_SIF_GPT_DISKS_SECTION
  2627. );
  2628. MYASSERT(0 && L"AsrpFitGptPartitionsToRegions failed for assigned disk");
  2629. if (AllOrNothing) {
  2630. SetLastError(ERROR_HANDLE_DISK_FULL);
  2631. return FALSE;
  2632. }
  2633. else {
  2634. sifDisk = sifDisk->pNext;
  2635. continue;
  2636. }
  2637. }
  2638. //
  2639. // Now, we need to go through our partition list, and update the start sector
  2640. // for the partitions in that list. This is needed since we use the start
  2641. // sector later to assign the volume guids to the partitions.
  2642. //
  2643. // The start sectors could've changed because the physical disk may have had
  2644. // un-erasable partitions.
  2645. //
  2646. pCurrentPtn = pSifGptPtnList[sifDisk->SifDiskKey].pOffsetHead;
  2647. while (pCurrentPtn) {
  2648. pCurrentPtn->PartitionInfo.StartingOffset.QuadPart =
  2649. sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].StartingOffset.QuadPart;
  2650. pCurrentPtn->PartitionInfo.PartitionLength.QuadPart =
  2651. sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].PartitionLength.QuadPart;
  2652. pCurrentPtn = pCurrentPtn->pOffsetNext;
  2653. }
  2654. //
  2655. // Move the non-erasable partitions on the physical disks up to the beginning.
  2656. //
  2657. for (index = 0; index < sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount; index++) {
  2658. pCurrentEntry = &(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index]);
  2659. if (!AsrpIsOkayToErasePartition(pCurrentEntry)) {
  2660. if (preserveIndex == index) {
  2661. preserveIndex++;
  2662. continue;
  2663. }
  2664. memmove(&(pNewDriveLayoutEx->PartitionEntry[preserveIndex]),
  2665. &(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index]),
  2666. sizeof(PARTITION_INFORMATION_EX)
  2667. );
  2668. preserveIndex++;
  2669. }
  2670. else {
  2671. //
  2672. // This partition can be erased.
  2673. //
  2674. pCurrentEntry->StartingOffset.QuadPart = 0;
  2675. pCurrentEntry->PartitionLength.QuadPart = 0;
  2676. }
  2677. } // for
  2678. } // if !IsIntact
  2679. //
  2680. // Now that we've copied over entries of interest to the new
  2681. // drivelayoutex struct, we can get rid of the old one.
  2682. //
  2683. _AsrpHeapFree(sifDisk->AssignedTo->pDriveLayoutEx);
  2684. sifDisk->AssignedTo->sizeDriveLayoutEx = sizeNewDriveLayoutEx;
  2685. sifDisk->AssignedTo->pDriveLayoutEx = pNewDriveLayoutEx;
  2686. //
  2687. // Copy over the sif partition table to the physicalDisk
  2688. //
  2689. memcpy(&(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[preserveIndex]),
  2690. &(sifDisk->pDriveLayoutEx->PartitionEntry[0]),
  2691. sizeof(PARTITION_INFORMATION_EX) * (sifDisk->pDriveLayoutEx->PartitionCount)
  2692. );
  2693. sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount = sifDisk->pDriveLayoutEx->PartitionCount + preserveIndex;
  2694. sifDisk->AssignedTo->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * (sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount - 1));
  2695. sifDisk->AssignedTo->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT;
  2696. memcpy(&(sifDisk->AssignedTo->pDriveLayoutEx->Gpt.DiskId),
  2697. &(sifDisk->pDriveLayoutEx->Gpt.DiskId),
  2698. sizeof(GUID)
  2699. );
  2700. }
  2701. else {
  2702. MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)");
  2703. }
  2704. sifDisk = sifDisk->pNext;
  2705. }
  2706. return TRUE;
  2707. }
  2708. BOOL
  2709. AsrpCreateMountPoint(
  2710. IN DWORD DiskNumber,
  2711. IN DWORD PartitionNumber,
  2712. IN PCWSTR szVolumeGuid
  2713. )
  2714. /*++
  2715. Routine Description:
  2716. Arguments:
  2717. Return Value:
  2718. If the function succeeds, the return value is a nonzero value.
  2719. If the function fails, the return value is zero. To get extended error
  2720. information, call GetLastError().
  2721. --*/
  2722. {
  2723. PMOUNTMGR_CREATE_POINT_INPUT inputCreatePoint = NULL;
  2724. PMOUNTMGR_MOUNT_POINT inputDeletePoint = NULL;
  2725. PMOUNTMGR_MOUNT_POINTS outputDeletePoint = NULL;
  2726. WCHAR deviceName[ASR_CCH_DEVICE_PATH_FORMAT];
  2727. PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL;
  2728. INT attempt = 0;
  2729. DWORD cbName = 0;
  2730. PWSTR lpName = NULL;
  2731. DWORD cbDeletePoint = 0;
  2732. USHORT sizeGuid = 0,
  2733. sizeDeviceName = 0;
  2734. DWORD bytes = 0, index = 0,
  2735. status = ERROR_SUCCESS;
  2736. HANDLE mpHandle = NULL,
  2737. heapHandle = GetProcessHeap();
  2738. BOOL result = TRUE;
  2739. if (!szVolumeGuid || !wcslen(szVolumeGuid)) {
  2740. return TRUE;
  2741. }
  2742. //
  2743. // Open the mount manager
  2744. //
  2745. mpHandle = CreateFileW(
  2746. (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME, // lpFileName
  2747. GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess
  2748. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  2749. NULL, // lpSecurityAttributes
  2750. OPEN_EXISTING, // dwCreationFlags
  2751. FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes
  2752. INVALID_HANDLE_VALUE // hTemplateFile
  2753. );
  2754. _AsrpErrExitCode((!mpHandle || INVALID_HANDLE_VALUE == mpHandle), status, GetLastError());
  2755. swprintf(deviceName, ASR_WSZ_DEVICE_PATH_FORMAT, DiskNumber, PartitionNumber);
  2756. sizeDeviceName = wcslen(deviceName) * sizeof(WCHAR);
  2757. sizeGuid = wcslen(szVolumeGuid) * sizeof(WCHAR);
  2758. //
  2759. // There is a small window after a partition is created in which the
  2760. // device-path to it (\Device\HarddiskX\PartitionY) doesn't exist, and
  2761. // a small window in which the device-path is actually pointing to
  2762. // the wrong object. (Partmgr first creates the path, <small window>,
  2763. // assigns it to the correct object)
  2764. //
  2765. // Since this will cause CREATE_POINT to fail later with FILE_NOT_FOUND,
  2766. // lets wait till mountmgr sees the device object.
  2767. //
  2768. result = FALSE;
  2769. while ((!result) && (++attempt < 120)) {
  2770. result = AsrpGetMountPoints(deviceName, sizeDeviceName + sizeof(WCHAR), &mountPointsOut);
  2771. if (!result) {
  2772. Sleep(500);
  2773. }
  2774. }
  2775. outputDeletePoint = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc(
  2776. heapHandle,
  2777. HEAP_ZERO_MEMORY,
  2778. ASR_BUFFER_SIZE
  2779. );
  2780. _AsrpErrExitCode(!outputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY);
  2781. //
  2782. // The mountmgr assigns a volume-GUID symbolic link (\??\Volume{Guid}) to
  2783. // a basic partition as soon as it's created. In addition, we will re-
  2784. // create the symbolic link that the partition originally used to have
  2785. // (as stored in asr.sif).
  2786. //
  2787. // This will lead to the partition having two volume-GUID's at the end.
  2788. // This is wasteful, but generally harmless to the system--however, the
  2789. // ASR test verification scripts get numerous false hits because of the
  2790. // additional GUID.
  2791. //
  2792. // To fix this, we delete the new mountmgr assigned-GUID before restoring
  2793. // the original GUID for the partition from asr.sif.
  2794. //
  2795. if ((result) && (mountPointsOut)) {
  2796. for (index = 0; index < mountPointsOut->NumberOfMountPoints; index++) {
  2797. lpName = (PWSTR) (((LPBYTE)mountPointsOut) + mountPointsOut->MountPoints[index].SymbolicLinkNameOffset);
  2798. cbName = (DWORD) mountPointsOut->MountPoints[index].SymbolicLinkNameLength;
  2799. if (!_AsrpIsVolumeGuid(lpName, cbName)) {
  2800. continue;
  2801. }
  2802. //
  2803. // We found a link that looks like a volume GUID
  2804. //
  2805. cbDeletePoint = sizeof(MOUNTMGR_MOUNT_POINT) +
  2806. mountPointsOut->MountPoints[index].SymbolicLinkNameLength +
  2807. mountPointsOut->MountPoints[index].UniqueIdLength +
  2808. mountPointsOut->MountPoints[index].DeviceNameLength;
  2809. inputDeletePoint = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  2810. heapHandle,
  2811. HEAP_ZERO_MEMORY,
  2812. cbDeletePoint
  2813. );
  2814. _AsrpErrExitCode(!inputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY);
  2815. //
  2816. // Set the fields to match the current link
  2817. //
  2818. inputDeletePoint->SymbolicLinkNameOffset =
  2819. sizeof(MOUNTMGR_MOUNT_POINT);
  2820. inputDeletePoint->SymbolicLinkNameLength =
  2821. mountPointsOut->MountPoints[index].SymbolicLinkNameLength;
  2822. CopyMemory(
  2823. ((LPBYTE)inputDeletePoint) +
  2824. inputDeletePoint->SymbolicLinkNameOffset,
  2825. ((LPBYTE)mountPointsOut) +
  2826. mountPointsOut->MountPoints[index].SymbolicLinkNameOffset,
  2827. inputDeletePoint->SymbolicLinkNameLength);
  2828. inputDeletePoint->UniqueIdOffset =
  2829. inputDeletePoint->SymbolicLinkNameOffset +
  2830. inputDeletePoint->SymbolicLinkNameLength;
  2831. inputDeletePoint->UniqueIdLength =
  2832. mountPointsOut->MountPoints[index].UniqueIdLength;
  2833. CopyMemory(
  2834. ((LPBYTE)inputDeletePoint) +
  2835. inputDeletePoint->UniqueIdOffset,
  2836. ((LPBYTE)mountPointsOut) +
  2837. mountPointsOut->MountPoints[index].UniqueIdOffset,
  2838. inputDeletePoint->UniqueIdLength);
  2839. inputDeletePoint->DeviceNameOffset =
  2840. inputDeletePoint->UniqueIdOffset +
  2841. inputDeletePoint->UniqueIdLength;
  2842. inputDeletePoint->DeviceNameLength =
  2843. mountPointsOut->MountPoints[index].DeviceNameLength;
  2844. CopyMemory((
  2845. (LPBYTE)inputDeletePoint) +
  2846. inputDeletePoint->DeviceNameOffset,
  2847. ((LPBYTE)mountPointsOut) +
  2848. mountPointsOut->MountPoints[index].DeviceNameOffset,
  2849. inputDeletePoint->DeviceNameLength);
  2850. //
  2851. // And delete this link ...
  2852. //
  2853. result = DeviceIoControl(
  2854. mpHandle,
  2855. IOCTL_MOUNTMGR_DELETE_POINTS,
  2856. inputDeletePoint,
  2857. cbDeletePoint,
  2858. outputDeletePoint,
  2859. ASR_BUFFER_SIZE,
  2860. &bytes,
  2861. NULL
  2862. );
  2863. //
  2864. // It's okay if the delete fails.
  2865. //
  2866. GetLastError(); // for debug
  2867. _AsrpHeapFree(inputDeletePoint);
  2868. }
  2869. }
  2870. //
  2871. // Alloc the MountMgr points we need
  2872. //
  2873. inputCreatePoint = (PMOUNTMGR_CREATE_POINT_INPUT) HeapAlloc(
  2874. heapHandle,
  2875. HEAP_ZERO_MEMORY,
  2876. sizeof (MOUNTMGR_CREATE_POINT_INPUT) + sizeDeviceName + sizeGuid
  2877. );
  2878. _AsrpErrExitCode(!inputCreatePoint, status, ERROR_NOT_ENOUGH_MEMORY);
  2879. inputDeletePoint = (PMOUNTMGR_MOUNT_POINT) HeapAlloc(
  2880. heapHandle,
  2881. HEAP_ZERO_MEMORY,
  2882. sizeof(MOUNTMGR_MOUNT_POINT) + sizeGuid
  2883. );
  2884. _AsrpErrExitCode(!inputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY);
  2885. //
  2886. // We should delete this volume guid if some other partition
  2887. // already has it, else we'll get an ALREADY_EXISTS error
  2888. // when we try to create it.
  2889. //
  2890. inputDeletePoint->DeviceNameOffset = 0;
  2891. inputDeletePoint->DeviceNameLength = 0;
  2892. inputDeletePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT);
  2893. inputDeletePoint->SymbolicLinkNameLength = sizeGuid;
  2894. CopyMemory((((LPBYTE)inputDeletePoint) + inputDeletePoint->SymbolicLinkNameOffset),
  2895. ((LPBYTE)szVolumeGuid),
  2896. inputDeletePoint->SymbolicLinkNameLength
  2897. );
  2898. result = DeviceIoControl(
  2899. mpHandle,
  2900. IOCTL_MOUNTMGR_DELETE_POINTS,
  2901. inputDeletePoint,
  2902. sizeof (MOUNTMGR_MOUNT_POINT) + sizeGuid,
  2903. outputDeletePoint,
  2904. ASR_BUFFER_SIZE,
  2905. &bytes,
  2906. NULL
  2907. );
  2908. //
  2909. // It's okay if this fails.
  2910. //
  2911. // _AsrpErrExitCode(!result, status, GetLastError());
  2912. GetLastError(); // for Debug
  2913. //
  2914. // Call IOCTL_MOUNTMGR_CREATE_POINT
  2915. //
  2916. inputCreatePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT);
  2917. inputCreatePoint->SymbolicLinkNameLength = sizeGuid;
  2918. inputCreatePoint->DeviceNameOffset = inputCreatePoint->SymbolicLinkNameOffset + inputCreatePoint->SymbolicLinkNameLength;
  2919. inputCreatePoint->DeviceNameLength = sizeDeviceName;
  2920. CopyMemory(((LPBYTE)inputCreatePoint) + inputCreatePoint->SymbolicLinkNameOffset,
  2921. szVolumeGuid, inputCreatePoint->SymbolicLinkNameLength);
  2922. CopyMemory(((LPBYTE)inputCreatePoint) + inputCreatePoint->DeviceNameOffset,
  2923. deviceName, inputCreatePoint->DeviceNameLength);
  2924. result = DeviceIoControl(
  2925. mpHandle,
  2926. IOCTL_MOUNTMGR_CREATE_POINT,
  2927. inputCreatePoint,
  2928. sizeof (MOUNTMGR_CREATE_POINT_INPUT) + sizeDeviceName + sizeGuid,
  2929. NULL,
  2930. 0,
  2931. &bytes,
  2932. NULL
  2933. );
  2934. _AsrpErrExitCode(!result, status, GetLastError());
  2935. //
  2936. // We're done.
  2937. //
  2938. EXIT:
  2939. _AsrpCloseHandle(mpHandle);
  2940. _AsrpHeapFree(mountPointsOut);
  2941. _AsrpHeapFree(inputCreatePoint);
  2942. _AsrpHeapFree(inputDeletePoint);
  2943. _AsrpHeapFree(outputDeletePoint);
  2944. return (BOOL) (ERROR_SUCCESS == status);
  2945. }
  2946. //
  2947. // Assigns the volume guid's stored in the partition-list to partitions
  2948. // on the physical disk, based on the start sectors
  2949. //
  2950. BOOL
  2951. AsrpAssignVolumeGuids(
  2952. IN PASR_DISK_INFO pPhysicalDisk,
  2953. IN HANDLE hDisk, // open handle to the physical disk
  2954. IN PASR_PTN_INFO pPtnInfo // list of partitions--with vol guids ...
  2955. )
  2956. /*++
  2957. Routine Description:
  2958. Arguments:
  2959. Return Value:
  2960. If the function succeeds, the return value is a nonzero value.
  2961. If the function fails, the return value is zero. To get extended error
  2962. information, call GetLastError().
  2963. --*/
  2964. {
  2965. PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx = NULL;
  2966. DWORD sizeDriveLayoutEx = pPhysicalDisk->sizeDriveLayoutEx;
  2967. DWORD index = 0,
  2968. status = ERROR_SUCCESS,
  2969. bytes = 0;
  2970. BOOL result = FALSE,
  2971. found = FALSE;
  2972. PASR_PTN_INFO currentPtn = NULL;
  2973. HANDLE heapHandle = GetProcessHeap();
  2974. //
  2975. // Get the new layout for the physical disk.
  2976. //
  2977. pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  2978. heapHandle,
  2979. HEAP_ZERO_MEMORY,
  2980. sizeDriveLayoutEx
  2981. );
  2982. _AsrpErrExitCode(!pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  2983. while (!result) {
  2984. result = DeviceIoControl(
  2985. hDisk,
  2986. IOCTL_DISK_GET_DRIVE_LAYOUT_EX,
  2987. NULL,
  2988. 0L,
  2989. pDriveLayoutEx,
  2990. sizeDriveLayoutEx,
  2991. &bytes,
  2992. NULL
  2993. );
  2994. if (!result) {
  2995. status = GetLastError();
  2996. _AsrpHeapFree(pDriveLayoutEx);
  2997. //
  2998. // If the buffer is of insufficient size, resize the buffer.
  2999. //
  3000. if ((ERROR_MORE_DATA == status) || (ERROR_INSUFFICIENT_BUFFER == status)) {
  3001. status = ERROR_SUCCESS;
  3002. sizeDriveLayoutEx += sizeof(PARTITION_INFORMATION_EX) * 4;
  3003. pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc(
  3004. heapHandle,
  3005. HEAP_ZERO_MEMORY,
  3006. sizeDriveLayoutEx
  3007. );
  3008. _AsrpErrExitCode(!pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY);
  3009. }
  3010. else {
  3011. AsrpPrintDbgMsg(_asrlog,
  3012. "The drive layout on Harddisk %lu (%ws) could not be determined (%lu). The volumes on this disk may not be restored completely.\r\n",
  3013. pPhysicalDisk->DeviceNumber,
  3014. pPhysicalDisk->DevicePath,
  3015. GetLastError()
  3016. );
  3017. _AsrpErrExitCode(status, status, GetLastError());
  3018. }
  3019. }
  3020. }
  3021. //
  3022. // We have the drive layout. Now each partition in our list should have
  3023. // an entry in the partition table. We use the mount manager to set it's
  3024. // volume guid.
  3025. //
  3026. currentPtn = pPtnInfo;
  3027. result = TRUE;
  3028. while (currentPtn) {
  3029. //
  3030. // We only care about partitions that have a volume-guid
  3031. //
  3032. if ((currentPtn->szVolumeGuid) &&
  3033. (wcslen(currentPtn->szVolumeGuid) > 0)
  3034. ) {
  3035. //
  3036. // Go through all the partitions on the disk, and find one that
  3037. // starts at the offset we expect it to.
  3038. //
  3039. found = FALSE;
  3040. index = 0;
  3041. while (!found && (index < pDriveLayoutEx->PartitionCount)) {
  3042. if (pDriveLayoutEx->PartitionEntry[index].StartingOffset.QuadPart
  3043. == currentPtn->PartitionInfo.StartingOffset.QuadPart) {
  3044. //
  3045. // We found the partition, let's set its GUID now
  3046. //
  3047. AsrpCreateMountPoint(
  3048. pPhysicalDisk->DeviceNumber, // disk number
  3049. pDriveLayoutEx->PartitionEntry[index].PartitionNumber, // partition number
  3050. currentPtn->szVolumeGuid // volumeGuid
  3051. );
  3052. found = TRUE;
  3053. }
  3054. else {
  3055. index++;
  3056. }
  3057. }
  3058. if (!found) {
  3059. result = FALSE;
  3060. }
  3061. }
  3062. currentPtn = currentPtn->pOffsetNext;
  3063. }
  3064. if (!result) {
  3065. //
  3066. // We didn't find a partition
  3067. //
  3068. AsrpPrintDbgMsg(_asrlog,
  3069. "One or more partitions on Harddisk %lu (%ws) could not be recreated. The volumes on this disk may not be restored completely.\r\n",
  3070. pPhysicalDisk->DeviceNumber,
  3071. pPhysicalDisk->DevicePath
  3072. );
  3073. _AsrpErrExitCode(status, status, ERROR_BAD_DEVICE);
  3074. }
  3075. EXIT:
  3076. _AsrpHeapFree(pDriveLayoutEx);
  3077. return (BOOL) (ERROR_SUCCESS == status);
  3078. }
  3079. //
  3080. // Re-partitions the disks
  3081. //
  3082. BOOL
  3083. AsrpRecreateDisks(
  3084. IN PASR_DISK_INFO pSifDiskList,
  3085. IN PASR_PTN_INFO_LIST pSifMbrPtnList,
  3086. IN PASR_PTN_INFO_LIST pSifGptPtnList,
  3087. IN BOOL AllOrNothing
  3088. )
  3089. /*++
  3090. Routine Description:
  3091. Arguments:
  3092. Return Value:
  3093. If the function succeeds, the return value is a nonzero value.
  3094. If the function fails, the return value is zero. To get extended error
  3095. information, call GetLastError().
  3096. --*/
  3097. {
  3098. PASR_DISK_INFO pSifDisk = pSifDiskList;
  3099. DWORD bytesReturned = 0,
  3100. status = ERROR_SUCCESS;
  3101. HANDLE hDisk = NULL;
  3102. BOOL result = TRUE;
  3103. //
  3104. // For each sif disk that isn't intact, go to the physical
  3105. // disk it's assigned to, and recreate that disk
  3106. //
  3107. while (pSifDisk) {
  3108. if (!(pSifDisk->AssignedTo)) {
  3109. AsrpPrintDbgMsg(_asrinfo,
  3110. "Not recreating disk %lu in section [%ws] (no matching disk found).\r\n",
  3111. pSifDisk->SifDiskKey,
  3112. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  3113. );
  3114. if (AllOrNothing) {
  3115. return FALSE;
  3116. }
  3117. else {
  3118. pSifDisk = pSifDisk->pNext;
  3119. continue;
  3120. }
  3121. }
  3122. if ((pSifDisk->IsCritical) ||
  3123. (pSifDisk->AssignedTo->IsCritical)) {
  3124. AsrpPrintDbgMsg(_asrinfo,
  3125. "Not recreating Harddisk %lu (disk %lu in section [%ws]) (critical disk).\r\n",
  3126. pSifDisk->AssignedTo->DeviceNumber,
  3127. pSifDisk->SifDiskKey,
  3128. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION)
  3129. );
  3130. pSifDisk = pSifDisk->pNext;
  3131. continue;
  3132. }
  3133. //
  3134. // Open physical disk
  3135. //
  3136. hDisk = CreateFileW(
  3137. pSifDisk->AssignedTo->DevicePath, // lpFileName
  3138. GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess
  3139. FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode
  3140. NULL, // lpSecurityAttributes
  3141. OPEN_EXISTING, // dwCreationFlags
  3142. 0, // dwFlagsAndAttributes
  3143. NULL // hTemplateFile
  3144. );
  3145. if ((!hDisk) || (INVALID_HANDLE_VALUE == hDisk)) {
  3146. //
  3147. // We couldn't open the disk.
  3148. //
  3149. AsrpPrintDbgMsg(_asrlog,
  3150. "Unable to open Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n",
  3151. pSifDisk->AssignedTo->DeviceNumber,
  3152. pSifDisk->AssignedTo->DevicePath,
  3153. pSifDisk->SifDiskKey,
  3154. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION),
  3155. GetLastError()
  3156. );
  3157. if (AllOrNothing) {
  3158. return FALSE;
  3159. }
  3160. else {
  3161. pSifDisk = pSifDisk->pNext;
  3162. continue;
  3163. }
  3164. }
  3165. if (!(pSifDisk->IsIntact) && // disk is not intact
  3166. (pSifDisk->AssignedTo) && // matching physical disk was found
  3167. ((PARTITION_STYLE_MBR == pSifDisk->Style) || (PARTITION_STYLE_GPT == pSifDisk->Style)) // not recognised partitioning style
  3168. ) {
  3169. //
  3170. // Delete the old drive layout
  3171. //
  3172. result = DeviceIoControl(
  3173. hDisk,
  3174. IOCTL_DISK_DELETE_DRIVE_LAYOUT,
  3175. NULL,
  3176. 0L,
  3177. NULL,
  3178. 0L,
  3179. &bytesReturned,
  3180. NULL
  3181. );
  3182. if (!result) {
  3183. AsrpPrintDbgMsg(_asrlog,
  3184. "Unable to delete layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (%lu).\r\n",
  3185. pSifDisk->AssignedTo->DeviceNumber,
  3186. pSifDisk->AssignedTo->DevicePath,
  3187. pSifDisk->SifDiskKey,
  3188. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION),
  3189. GetLastError()
  3190. );
  3191. GetLastError();
  3192. }
  3193. //
  3194. // If we're converting an MBR to a GPT, then we need to call
  3195. // IOCTL_DISK_CREATE_DISK first
  3196. //
  3197. if ((PARTITION_STYLE_GPT == pSifDisk->Style) &&
  3198. (PARTITION_STYLE_MBR == pSifDisk->AssignedTo->Style)) {
  3199. CREATE_DISK CreateDisk;
  3200. CreateDisk.PartitionStyle = PARTITION_STYLE_GPT;
  3201. memcpy(&(CreateDisk.Gpt.DiskId), &(pSifDisk->pDriveLayoutEx->Gpt.DiskId), sizeof(GUID));
  3202. CreateDisk.Gpt.MaxPartitionCount = pSifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount;
  3203. result = DeviceIoControl(
  3204. hDisk,
  3205. IOCTL_DISK_CREATE_DISK,
  3206. &(CreateDisk),
  3207. sizeof(CREATE_DISK),
  3208. NULL,
  3209. 0L,
  3210. &bytesReturned,
  3211. NULL
  3212. );
  3213. if (!result) {
  3214. //
  3215. // CREATE_DISK failed
  3216. //
  3217. status = GetLastError();
  3218. AsrpPrintDbgMsg(_asrlog,
  3219. "Unable to initialize disk layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n",
  3220. pSifDisk->AssignedTo->DeviceNumber,
  3221. pSifDisk->AssignedTo->DevicePath,
  3222. pSifDisk->SifDiskKey,
  3223. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION),
  3224. GetLastError()
  3225. );
  3226. _AsrpCloseHandle(hDisk);
  3227. SetLastError(status);
  3228. if (AllOrNothing) {
  3229. return FALSE;
  3230. }
  3231. else {
  3232. pSifDisk = pSifDisk->pNext;
  3233. continue;
  3234. }
  3235. }
  3236. }
  3237. //
  3238. // Set the new drive layout
  3239. //
  3240. result = DeviceIoControl(
  3241. hDisk,
  3242. IOCTL_DISK_SET_DRIVE_LAYOUT_EX,
  3243. pSifDisk->AssignedTo->pDriveLayoutEx,
  3244. pSifDisk->AssignedTo->sizeDriveLayoutEx,
  3245. NULL,
  3246. 0L,
  3247. &bytesReturned,
  3248. NULL
  3249. );
  3250. if (!result) {
  3251. //
  3252. // SET_DRIVE_LAYOUT failed
  3253. //
  3254. status = GetLastError();
  3255. AsrpPrintDbgMsg(_asrlog,
  3256. "Unable to set drive layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n",
  3257. pSifDisk->AssignedTo->DeviceNumber,
  3258. pSifDisk->AssignedTo->DevicePath,
  3259. pSifDisk->SifDiskKey,
  3260. ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION),
  3261. GetLastError()
  3262. );
  3263. _AsrpCloseHandle(hDisk);
  3264. SetLastError(status);
  3265. if (AllOrNothing) {
  3266. return FALSE;
  3267. }
  3268. else {
  3269. pSifDisk = pSifDisk->pNext;
  3270. continue;
  3271. }
  3272. }
  3273. }
  3274. //
  3275. // Now we need to recreate the volumeGuids for each partition
  3276. //
  3277. result = AsrpAssignVolumeGuids(
  3278. pSifDisk->AssignedTo,
  3279. hDisk,
  3280. ((PARTITION_STYLE_MBR == pSifDisk->Style) ?
  3281. (pSifMbrPtnList[pSifDisk->SifDiskKey].pOffsetHead) :
  3282. (pSifGptPtnList[pSifDisk->SifDiskKey].pOffsetHead))
  3283. );
  3284. //
  3285. // We don't care about the result ...
  3286. //
  3287. MYASSERT(result && L"AsrpAssignVolumeGuids failed");
  3288. _AsrpCloseHandle(hDisk);
  3289. //
  3290. // Get the next drive from the drive list.
  3291. //
  3292. pSifDisk = pSifDisk->pNext;
  3293. }
  3294. return TRUE;
  3295. }
  3296. //
  3297. // Restore Non Critical Disks
  3298. //
  3299. //
  3300. BOOL
  3301. AsrpRestoreNonCriticalDisksW(
  3302. IN PCWSTR lpSifPath,
  3303. IN BOOL bAllOrNothing
  3304. )
  3305. /*++
  3306. Routine Description:
  3307. Arguments:
  3308. Return Value:
  3309. If the function succeeds, the return value is a nonzero value.
  3310. If the function fails, the return value is zero. To get extended error
  3311. information, call GetLastError().
  3312. --*/
  3313. {
  3314. BOOL result = FALSE;
  3315. PWSTR asrSifPath = NULL;
  3316. //
  3317. // We have two lists of disks--one of all the physical disks
  3318. // currently on the system, and the other constructed from the
  3319. // sif file. The goal is to reconfigure non-critical disks in
  3320. // the pPhysicalDiskList to match the pSifDiskList
  3321. //
  3322. PASR_DISK_INFO pSifDiskList = NULL,
  3323. pPhysicalDiskList = NULL;
  3324. PASR_PTN_INFO_LIST pSifMbrPtnList = NULL,
  3325. pSifGptPtnList = NULL;
  3326. DWORD cchAsrSifPath = 0,
  3327. MaxDeviceNumber = 0, // not used
  3328. status = ERROR_SUCCESS;
  3329. BOOL bAutoExtend = FALSE,
  3330. allOrNothing = FALSE;
  3331. HANDLE heapHandle = GetProcessHeap();
  3332. SetLastError(ERROR_CAN_NOT_COMPLETE);
  3333. if (!AsrIsEnabled()) {
  3334. //
  3335. // If we're not in GUI-mode ASR, we need to open the log files first
  3336. //
  3337. AsrpInitialiseErrorFile();
  3338. AsrpInitialiseLogFile();
  3339. }
  3340. AsrpPrintDbgMsg(_asrlog, "Attempting to restore non-critical disks.\r\n");
  3341. if (!lpSifPath) {
  3342. SetLastError(ERROR_INVALID_PARAMETER);
  3343. goto EXIT;
  3344. }
  3345. cchAsrSifPath = wcslen(lpSifPath);
  3346. //
  3347. // Do a sanity check: we don't want to allow a file path
  3348. // more than 4096 characters long.
  3349. //
  3350. if (cchAsrSifPath > ASR_SIF_ENTRY_MAX_CHARS) {
  3351. SetLastError(ERROR_INVALID_PARAMETER);
  3352. goto EXIT;
  3353. }
  3354. asrSifPath = (PWSTR) HeapAlloc(
  3355. heapHandle,
  3356. HEAP_ZERO_MEMORY,
  3357. ((cchAsrSifPath + 1) * sizeof(WCHAR))
  3358. );
  3359. _AsrpErrExitCode(!asrSifPath, status, ERROR_NOT_ENOUGH_MEMORY);
  3360. wcsncpy(asrSifPath, lpSifPath, cchAsrSifPath);
  3361. allOrNothing = bAllOrNothing;
  3362. AsrpPrintDbgMsg(_asrlog, "ASR state file: \"%ws\". AllOrNothing: %lu\r\n",
  3363. asrSifPath, allOrNothing);
  3364. //
  3365. // The function calls are AND'ed below, hence if one fails, the
  3366. // calls after it will not be executed (exactly the behaviour we
  3367. // want).
  3368. //
  3369. result = (
  3370. //
  3371. // Build the original disk info from the sif file
  3372. //
  3373. AsrpBuildMbrSifDiskList(asrSifPath, &pSifDiskList, &pSifMbrPtnList, &bAutoExtend)
  3374. && AsrpBuildGptSifDiskList(asrSifPath, &pSifDiskList, &pSifGptPtnList)
  3375. //
  3376. // Build the list of current disks present on the target machine
  3377. //
  3378. && AsrpInitDiskInformation(&pPhysicalDiskList)
  3379. //
  3380. // Fill in the partition info for the fixed disks on the target machine
  3381. // and remove non-fixed devices
  3382. //
  3383. && AsrpInitLayoutInformation(NULL, pPhysicalDiskList, &MaxDeviceNumber, TRUE, FALSE)
  3384. && AsrpFreeNonFixedMedia(&pPhysicalDiskList)
  3385. //
  3386. // Try to determine which sif disk should end up on which physical disk.
  3387. //
  3388. && AsrpAssignDisks(pSifDiskList, pPhysicalDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing, bAutoExtend)
  3389. //
  3390. // Finally, repartition the disks and assign the volume guids
  3391. //
  3392. && AsrpRecreateDisks(pSifDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing)
  3393. );
  3394. status = GetLastError();
  3395. AsrpFreeStateInformation(&pSifDiskList, NULL);
  3396. AsrpFreeStateInformation(&pPhysicalDiskList, NULL);
  3397. AsrpFreePartitionList(&pSifMbrPtnList);
  3398. AsrpFreePartitionList(&pSifGptPtnList);
  3399. SetLastError(status);
  3400. EXIT:
  3401. status = GetLastError();
  3402. if (result) {
  3403. AsrpPrintDbgMsg(_asrinfo, "Done restoring non-critical disks.\r\n");
  3404. }
  3405. else {
  3406. AsrpPrintDbgMsg(_asrerror, "Error restoring non-critical disks. (0x%x)\r\n", status);
  3407. if (ERROR_SUCCESS == status) {
  3408. //
  3409. // We're going to return failure, but we haven't set the LastError to
  3410. // a failure code. This is bad, since we have no clue what went wrong.
  3411. //
  3412. // We shouldn't ever get here, because the function returning FALSE above
  3413. // should set the LastError as it sees fit.
  3414. //
  3415. // But I've added this in just to be safe. Let's set it to a generic
  3416. // error.
  3417. //
  3418. MYASSERT(0 && L"Returning failure, but LastError is not set");
  3419. status = ERROR_CAN_NOT_COMPLETE;
  3420. }
  3421. }
  3422. if (!AsrIsEnabled()) {
  3423. AsrpCloseLogFiles();
  3424. }
  3425. _AsrpHeapFree(asrSifPath);
  3426. SetLastError(status);
  3427. return result;
  3428. }
  3429. BOOL
  3430. AsrpRestoreTimeZoneInformation(
  3431. IN PCWSTR lpSifPath
  3432. )
  3433. /*++
  3434. Routine Description:
  3435. Sets the current time-zone, based on the information stored in the SYSTEMS
  3436. section of the ASR state file.
  3437. Arguments:
  3438. lpSifPath - Null-terminated string containing the full path to the ASR
  3439. state file (including file name).
  3440. Return Value:
  3441. If the function succeeds, the return value is a nonzero value.
  3442. If the function fails, the return value is zero. To get extended error
  3443. information, call GetLastError().
  3444. --*/
  3445. {
  3446. HINF hSif = NULL;
  3447. BOOL result = FALSE;
  3448. DWORD reqdSize = 0,
  3449. status = ERROR_SUCCESS;
  3450. INFCONTEXT infSystemContext;
  3451. TIME_ZONE_INFORMATION TimeZoneInformation;
  3452. WCHAR szTimeZoneInfo[ASR_SIF_ENTRY_MAX_CHARS+1];
  3453. ZeroMemory(&infSystemContext, sizeof(INFCONTEXT));
  3454. ZeroMemory(&TimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
  3455. ZeroMemory(&szTimeZoneInfo, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1));
  3456. //
  3457. // Open the sif
  3458. //
  3459. hSif = SetupOpenInfFileW(lpSifPath, NULL, INF_STYLE_WIN4, NULL);
  3460. if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) {
  3461. return FALSE; // sif file couldn't be opened
  3462. }
  3463. //
  3464. // Get the TimeZone strings value
  3465. //
  3466. result = SetupFindFirstLineW(hSif, ASR_SIF_SYSTEM_SECTION, NULL, &infSystemContext);
  3467. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // no system section: corrupt asr.sif?
  3468. result = SetupGetStringFieldW(&infSystemContext, 7, szTimeZoneInfo, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
  3469. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  3470. swscanf(szTimeZoneInfo,
  3471. L"%ld %ld %ld %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd",
  3472. &(TimeZoneInformation.Bias),
  3473. &(TimeZoneInformation.StandardBias),
  3474. &(TimeZoneInformation.DaylightBias),
  3475. &(TimeZoneInformation.StandardDate.wYear),
  3476. &(TimeZoneInformation.StandardDate.wMonth),
  3477. &(TimeZoneInformation.StandardDate.wDayOfWeek),
  3478. &(TimeZoneInformation.StandardDate.wDay),
  3479. &(TimeZoneInformation.StandardDate.wHour),
  3480. &(TimeZoneInformation.StandardDate.wMinute),
  3481. &(TimeZoneInformation.StandardDate.wSecond),
  3482. &(TimeZoneInformation.StandardDate.wMilliseconds),
  3483. &(TimeZoneInformation.DaylightDate.wYear),
  3484. &(TimeZoneInformation.DaylightDate.wMonth),
  3485. &(TimeZoneInformation.DaylightDate.wDayOfWeek),
  3486. &(TimeZoneInformation.DaylightDate.wDay),
  3487. &(TimeZoneInformation.DaylightDate.wHour),
  3488. &(TimeZoneInformation.DaylightDate.wMinute),
  3489. &(TimeZoneInformation.DaylightDate.wSecond),
  3490. &(TimeZoneInformation.DaylightDate.wMilliseconds)
  3491. );
  3492. result = SetupGetStringFieldW(&infSystemContext, 8, TimeZoneInformation.StandardName, 32, &reqdSize);
  3493. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  3494. result = SetupGetStringFieldW(&infSystemContext, 9, TimeZoneInformation.DaylightName, 32, &reqdSize);
  3495. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  3496. result = SetTimeZoneInformation(&TimeZoneInformation);
  3497. if (!result) {
  3498. GetLastError();
  3499. }
  3500. _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
  3501. EXIT:
  3502. if (ERROR_SUCCESS != status) {
  3503. SetLastError(status);
  3504. }
  3505. return result;
  3506. }