Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

3590 lines
107 KiB

  1. /*++
  2. Copyright (c) 1993 Microsoft Corporation
  3. Module Name:
  4. spdrpset.c
  5. Abstract:
  6. Contains all routines that create and initialize the partition sets.
  7. Terminology
  8. Restrictions:
  9. Revision History:
  10. Initial Code Michael Peterson (v-michpe) 21.Aug.1998
  11. Code cleanup and changes Guhan Suriyanarayanan (guhans) 21.Aug.1999
  12. --*/
  13. #include "spprecmp.h"
  14. #pragma hdrstop
  15. #include "spdrpriv.h"
  16. #include "ntddscsi.h"
  17. //
  18. // Module identification for debug traces
  19. //
  20. #define THIS_MODULE L"spdrpset.c"
  21. #define THIS_MODULE_CODE L"P"
  22. extern PVOID Gbl_SifHandle;
  23. extern const PWSTR SIF_ASR_MBR_DISKS_SECTION;
  24. extern const PWSTR SIF_ASR_GPT_DISKS_SECTION;
  25. extern const PWSTR SIF_ASR_DISKS_SECTION;
  26. extern const PWSTR SIF_ASR_PARTITIONS_SECTION;
  27. //
  28. // Useful macros
  29. //
  30. #define DISK_SIZE_MB(n) ((ULONGLONG) HardDisks[(n)].DiskSizeMB)
  31. //
  32. // constants
  33. //
  34. #define ASR_FREE_SPACE_FUDGE_FACTOR_BYTES (16*1024*1024)
  35. #define ASR_LDM_RESERVED_SPACE_BYTES (1024*1024)
  36. //
  37. // Variables global to this module.
  38. // These are not referenced outside of spdrpset.c.
  39. //
  40. ULONG Gbl_PartitionSetCount;
  41. PSIF_DISK_RECORD *Gbl_SifDiskTable;
  42. BOOLEAN Gbl_AutoExtend;
  43. // used to see if a disk can hold the private region at the end,
  44. // and for bus-groupings
  45. PASR_PHYSICAL_DISK_INFO Gbl_PhysicalDiskInfo;
  46. //
  47. // Forward declarations
  48. //
  49. VOID SpAsrDbgDumpPartitionLists(BYTE DataOption, PWSTR Msg);
  50. BOOLEAN
  51. SpAsrDoesListFitOnDisk(
  52. IN PSIF_DISK_RECORD pDisk,
  53. IN ULONG DiskIndex,
  54. OUT BOOLEAN *IsAligned
  55. );
  56. //
  57. // Function definitions
  58. //
  59. PSIF_PARTITION_RECORD_LIST
  60. SpAsrGetMbrPartitionListByDiskKey(
  61. IN PWSTR DiskKey
  62. )
  63. {
  64. ULONG numRecords = 0,
  65. index = 0;
  66. PWSTR diskKeyFromPartitionRec = NULL,
  67. partitionKey = NULL;
  68. PSIF_PARTITION_RECORD pRec = NULL;
  69. PSIF_PARTITION_RECORD_LIST pList = NULL;
  70. ASSERT(DiskKey);
  71. numRecords = SpAsrGetMbrPartitionRecordCount(); // won't return if count < 1
  72. ASSERT(numRecords);
  73. pList = SpAsrMemAlloc(sizeof(SIF_PARTITION_RECORD_LIST), TRUE);
  74. for (index = 0; index < numRecords; index++) {
  75. partitionKey = SpAsrGetMbrPartitionKey(index);
  76. if (!partitionKey) {
  77. ASSERT(0 && L"Partition key is NULL!");
  78. continue;
  79. }
  80. diskKeyFromPartitionRec = SpAsrGetDiskKeyByMbrPartitionKey(partitionKey);
  81. if (!diskKeyFromPartitionRec) {
  82. ASSERT(0 && L"Disk key is NULL!");
  83. partitionKey = NULL;
  84. continue;
  85. }
  86. if (COMPARE_KEYS(diskKeyFromPartitionRec, DiskKey)) {
  87. //
  88. // This partition is on this disk
  89. //
  90. pRec = SpAsrGetMbrPartitionRecord(partitionKey);
  91. if (!pRec) {
  92. ASSERT(0 && L"Partition record is NULL!");
  93. partitionKey = NULL;
  94. diskKeyFromPartitionRec = NULL;
  95. continue;
  96. }
  97. SpAsrInsertPartitionRecord(pList, pRec);
  98. if ((pRec->StartSector + pRec->SectorCount) > pList->LastUsedSector) {
  99. pList->LastUsedSector = pRec->StartSector + pRec->SectorCount;
  100. }
  101. }
  102. partitionKey = NULL;
  103. diskKeyFromPartitionRec = NULL;
  104. }
  105. if (pList->ElementCount == 0) {
  106. DbgStatusMesg((_asrinfo, "Disk [%ws] appears to have no partitions\n", DiskKey));
  107. SpMemFree(pList);
  108. pList = NULL;
  109. }
  110. else {
  111. //
  112. // Get the sector count of the disk that this list used to be on
  113. //
  114. pList->DiskSectorCount = SpAsrGetSectorCountByMbrDiskKey(DiskKey);
  115. }
  116. return pList;
  117. }
  118. PSIF_PARTITION_RECORD_LIST
  119. SpAsrGetGptPartitionListByDiskKey(
  120. IN PWSTR DiskKey
  121. )
  122. {
  123. ULONG numRecords = 0,
  124. index = 0;
  125. PWSTR diskKeyFromPartitionRec = NULL,
  126. partitionKey = NULL;
  127. PSIF_PARTITION_RECORD pRec = NULL;
  128. PSIF_PARTITION_RECORD_LIST pList = NULL;
  129. ASSERT(DiskKey);
  130. numRecords = SpAsrGetGptPartitionRecordCount(); // won't return if count < 1
  131. ASSERT(numRecords);
  132. pList = SpAsrMemAlloc(sizeof(SIF_PARTITION_RECORD_LIST), TRUE);
  133. for (index = 0; index < numRecords; index++) {
  134. partitionKey = SpAsrGetGptPartitionKey(index);
  135. if (!partitionKey) {
  136. ASSERT(0 && L"Partition key is NULL!");
  137. continue;
  138. }
  139. diskKeyFromPartitionRec = SpAsrGetDiskKeyByGptPartitionKey(partitionKey);
  140. if (!diskKeyFromPartitionRec) {
  141. ASSERT(0 && L"Disk key is NULL!");
  142. partitionKey = NULL;
  143. continue;
  144. }
  145. if (COMPARE_KEYS(diskKeyFromPartitionRec, DiskKey)) {
  146. //
  147. // This partition is on this disk
  148. //
  149. pRec = SpAsrGetGptPartitionRecord(partitionKey);
  150. if (!pRec) {
  151. ASSERT(0 && L"Partition record is NULL!");
  152. partitionKey = NULL;
  153. diskKeyFromPartitionRec = NULL;
  154. continue;
  155. }
  156. SpAsrInsertPartitionRecord(pList, pRec);
  157. if ((pRec->StartSector + pRec->SectorCount) > pList->LastUsedSector) {
  158. pList->LastUsedSector = pRec->StartSector + pRec->SectorCount;
  159. }
  160. }
  161. partitionKey = NULL;
  162. diskKeyFromPartitionRec = NULL;
  163. }
  164. if (pList->ElementCount == 0) {
  165. DbgStatusMesg((_asrinfo, "Disk [%ws] appears to have no partitions\n", DiskKey));
  166. SpMemFree(pList);
  167. pList = NULL;
  168. }
  169. else {
  170. //
  171. // Get the sector count of the disk that this list used to be on
  172. //
  173. pList->DiskSectorCount = SpAsrGetSectorCountByGptDiskKey(DiskKey);
  174. }
  175. return pList;
  176. }
  177. PSIF_PARTITION_RECORD_LIST
  178. SpAsrGetPartitionListByDiskKey(
  179. IN PARTITION_STYLE PartitionStyle,
  180. IN PWSTR DiskKey
  181. )
  182. {
  183. switch (PartitionStyle) {
  184. case PARTITION_STYLE_MBR:
  185. return SpAsrGetMbrPartitionListByDiskKey(DiskKey);
  186. break;
  187. case PARTITION_STYLE_GPT:
  188. return SpAsrGetGptPartitionListByDiskKey(DiskKey);
  189. break;
  190. }
  191. ASSERT(0 && L"Unrecognised partition style");
  192. return NULL;
  193. }
  194. //
  195. // Sets the extendedstartsector and extendedsectorcount values. Only
  196. // makes sense in the context of an MBR disk
  197. //
  198. VOID
  199. SpAsrSetContainerBoundaries(IN ULONG Index)
  200. {
  201. BOOLEAN hasExtendedPartition = FALSE;
  202. USHORT consistencyCheck = 0;
  203. PSIF_PARTITION_RECORD pRec = NULL;
  204. ULONGLONG extSectorCount = 0,
  205. extStartSector = -1,
  206. extEndSector = 0;
  207. if (!(Gbl_SifDiskTable[Index]) ||
  208. (PARTITION_STYLE_MBR != Gbl_SifDiskTable[Index]->PartitionStyle) ||
  209. !(Gbl_SifDiskTable[Index]->PartitionList)) {
  210. ASSERT(0 && L"SetContainerBoundaries called with invalid Index");
  211. return;
  212. }
  213. Gbl_SifDiskTable[Index]->LastUsedSector = 0;
  214. pRec = Gbl_SifDiskTable[Index]->PartitionList->First;
  215. while (pRec) {
  216. if ((pRec->StartSector + pRec->SectorCount) > Gbl_SifDiskTable[Index]->LastUsedSector) {
  217. Gbl_SifDiskTable[Index]->LastUsedSector = pRec->StartSector + pRec->SectorCount;
  218. }
  219. //
  220. // Find the lowest-valued start-sector and highest-valued
  221. // end-sector of all of the extended (0x05 or 0x0f) partitions.
  222. //
  223. if (IsContainerPartition(pRec->PartitionType)) {
  224. hasExtendedPartition = TRUE;
  225. if (pRec->StartSector < extStartSector) {
  226. extStartSector = pRec->StartSector;
  227. if ((pRec->StartSector + pRec->SectorCount) > extEndSector) {
  228. extEndSector = pRec->StartSector + pRec->SectorCount;
  229. }
  230. else {
  231. DbgErrorMesg((_asrwarn,
  232. "SpAsrSetContainerBoundaries. Extended partition with lowest SS (%ld) does not have highest EndSec (This EndSec: %ld, Max EndSec: %ld)\n",
  233. extStartSector,
  234. extStartSector+pRec->SectorCount,
  235. extEndSector
  236. ));
  237. ASSERT(0 && L"Extended partition with lowest SS does not have highest EndSec");
  238. }
  239. }
  240. if ((pRec->StartSector + pRec->SectorCount) > extEndSector) {
  241. DbgErrorMesg((_asrwarn,
  242. "SpAsrSetContainerBoundaries. Extended partition with highest EndSec (%ld) does not have lowest SS (this SS:%ld, MaxEndSec:%ld, LowestSS: %ld)\n",
  243. pRec->StartSector + pRec->SectorCount,
  244. pRec->StartSector,
  245. extEndSector,
  246. extStartSector
  247. ));
  248. ASSERT(0 && L"Extended partition with highest EndSec does not have lowest SS");
  249. }
  250. }
  251. pRec = pRec->Next;
  252. }
  253. extSectorCount = extEndSector - extStartSector;
  254. //
  255. // Update the table for the disk
  256. //
  257. if (!hasExtendedPartition) {
  258. Gbl_SifDiskTable[Index]->ExtendedPartitionStartSector = -1;
  259. Gbl_SifDiskTable[Index]->ExtendedPartitionSectorCount = 0;
  260. Gbl_SifDiskTable[Index]->ExtendedPartitionEndSector = -1;
  261. return;
  262. }
  263. Gbl_SifDiskTable[Index]->ExtendedPartitionStartSector = extStartSector;
  264. Gbl_SifDiskTable[Index]->ExtendedPartitionSectorCount = extSectorCount;
  265. Gbl_SifDiskTable[Index]->ExtendedPartitionEndSector = extEndSector;
  266. //
  267. // Mark the container partition
  268. //
  269. pRec = Gbl_SifDiskTable[Index]->PartitionList->First;
  270. while (pRec) {
  271. pRec->IsContainerRecord = FALSE;
  272. if (pRec->StartSector == extStartSector) {
  273. consistencyCheck++;
  274. ASSERT((consistencyCheck == 1) && L"Two partitions start at the same sector");
  275. pRec->IsContainerRecord = TRUE;
  276. pRec->IsDescriptorRecord = FALSE;
  277. pRec->IsLogicalDiskRecord = FALSE;
  278. pRec->IsPrimaryRecord = FALSE;
  279. }
  280. pRec = pRec->Next;
  281. }
  282. }
  283. VOID
  284. SpAsrDetermineMbrPartitionRecordTypes(IN ULONG Index)
  285. {
  286. PSIF_PARTITION_RECORD pRec = NULL,
  287. pLogical = NULL,
  288. pDescr = NULL;
  289. ULONGLONG extStartSector = 0,
  290. extEndSector = 0;
  291. if (!(Gbl_SifDiskTable[Index]) ||
  292. (PARTITION_STYLE_MBR != Gbl_SifDiskTable[Index]->PartitionStyle) ||
  293. !(Gbl_SifDiskTable[Index]->PartitionList)) {
  294. ASSERT(0 && L"DetermineMbrPartitionRecordTypes called with invalid Index");
  295. return;
  296. }
  297. extStartSector = Gbl_SifDiskTable[Index]->ExtendedPartitionStartSector;
  298. extEndSector = Gbl_SifDiskTable[Index]->ExtendedPartitionEndSector;
  299. //
  300. // Check for descriptor, logical or primary
  301. //
  302. pRec = Gbl_SifDiskTable[Index]->PartitionList->First;
  303. while (pRec) {
  304. //
  305. // To start off, assume it's none of the recognised types
  306. //
  307. pRec->IsDescriptorRecord = FALSE;
  308. pRec->IsLogicalDiskRecord = FALSE;
  309. pRec->IsPrimaryRecord = FALSE;
  310. if (IsContainerPartition(pRec->PartitionType)) {
  311. //
  312. // Extended partition: this is either the container
  313. // or a descriptor partition record.
  314. //
  315. if (pRec->StartSector != extStartSector) {
  316. ASSERT(pRec->StartSector > extStartSector);
  317. ASSERT(FALSE == pRec->IsContainerRecord); // should've been marked above
  318. pRec->IsContainerRecord = FALSE; // just in case
  319. //
  320. // Not the container, so it must be a descriptor partition record.
  321. //
  322. pRec->IsDescriptorRecord = TRUE;
  323. }
  324. }
  325. else {
  326. ASSERT(FALSE == pRec->IsContainerRecord); // should've been marked above
  327. pRec->IsContainerRecord = FALSE; // just in case
  328. //
  329. // Not an extended partition. It's a primary record if its
  330. // StartSector lies outside of the container partition's
  331. // boundaries. Otherwise, it's a logical disk partition record.
  332. //
  333. if (pRec->StartSector < extStartSector ||
  334. pRec->StartSector >= extEndSector) {
  335. pRec->IsPrimaryRecord = TRUE;
  336. }
  337. else {
  338. pRec->IsLogicalDiskRecord = TRUE;
  339. }
  340. }
  341. pRec = pRec->Next;
  342. }
  343. //
  344. // -guhans! this is O(n-squared)
  345. // Next, loop through the list once more and, for each logical disk
  346. // record, find its descriptor partition. For each descriptor partition
  347. // find its logical disk. NB: All logical disk records will have a
  348. // descriptor record. All descriptor records will have a logical disk
  349. // record.
  350. //
  351. // To determine this we make use of the observation that a logical disk
  352. // record's start sector and sector count have the following relationship
  353. // to its descriptor partition:
  354. //
  355. // Logical Disk Record Descriptor Record
  356. //
  357. // Start Sector >= Start Sector
  358. // Sector Count <= Sector Count
  359. //
  360. // NB: In most cases, the container partition record also acts as a
  361. // descriptor partition record for the first logical disk in the extended
  362. // partition.
  363. //
  364. pLogical = Gbl_SifDiskTable[Index]->PartitionList->First;
  365. while (pLogical) {
  366. //
  367. // we're only interested in logical disks.
  368. //
  369. if (pLogical->IsLogicalDiskRecord) {
  370. //
  371. // Determine the descriptor record describing pLogical and vice versa.
  372. //
  373. pDescr = Gbl_SifDiskTable[Index]->PartitionList->First;
  374. while (pDescr) {
  375. //
  376. // skip this record itself.
  377. //
  378. if (pLogical == pDescr) {
  379. pDescr = pDescr->Next;
  380. continue;
  381. }
  382. //
  383. // skip primary or logical disk records.
  384. //
  385. if (pDescr->IsPrimaryRecord || pDescr->IsLogicalDiskRecord) {
  386. pDescr = pDescr->Next;
  387. continue;
  388. }
  389. //
  390. // At this point, the record describes a container or a descriptor
  391. // partition. If the end sectors match, we this is the descriptor
  392. // record for our logical rec.
  393. //
  394. if ((pLogical->StartSector + pLogical->SectorCount) ==
  395. (pDescr->StartSector + pDescr->SectorCount)) {
  396. pLogical->DescriptorKey = pDescr->CurrPartKey;
  397. pDescr->LogicalDiskKey = pLogical->CurrPartKey;
  398. break;
  399. }
  400. pDescr = pDescr->Next;
  401. }
  402. }
  403. pLogical = pLogical->Next;
  404. }
  405. }
  406. VOID
  407. SpAsrDetermineGptPartitionRecordTypes(IN ULONG Index)
  408. {
  409. PSIF_PARTITION_RECORD pRec = NULL;
  410. if (!(Gbl_SifDiskTable[Index]) ||
  411. (PARTITION_STYLE_GPT != Gbl_SifDiskTable[Index]->PartitionStyle) ||
  412. !(Gbl_SifDiskTable[Index]->PartitionList)) {
  413. ASSERT(0 && L"DetermineGptPartitionRecordTypes called with invalid Index");
  414. return;
  415. }
  416. //
  417. // Check for descriptor, logical or primary
  418. //
  419. pRec = Gbl_SifDiskTable[Index]->PartitionList->First;
  420. while (pRec) {
  421. //
  422. // All GPT partitions are "primary"
  423. //
  424. pRec->IsContainerRecord = FALSE;
  425. pRec->IsDescriptorRecord = FALSE;
  426. pRec->IsLogicalDiskRecord = FALSE;
  427. pRec->IsPrimaryRecord = TRUE;
  428. pRec = pRec->Next;
  429. }
  430. }
  431. VOID
  432. SpAsrDeterminePartitionRecordTypes(IN ULONG Index)
  433. {
  434. switch (Gbl_SifDiskTable[Index]->PartitionStyle) {
  435. case PARTITION_STYLE_MBR:
  436. SpAsrDetermineMbrPartitionRecordTypes(Index);
  437. break;
  438. case PARTITION_STYLE_GPT:
  439. SpAsrDetermineGptPartitionRecordTypes(Index);
  440. break;
  441. default:
  442. ASSERT(0 && L"Unrecognised partition style");
  443. break;
  444. }
  445. }
  446. VOID
  447. SpAsrSetDiskSizeRequirement(IN ULONG Index)
  448. {
  449. PSIF_PARTITION_RECORD_LIST pList = NULL;
  450. PSIF_PARTITION_RECORD pRec = NULL;
  451. ASSERT(Gbl_SifDiskTable[Index]);
  452. pList = Gbl_SifDiskTable[Index]->PartitionList;
  453. if (!pList) {
  454. return;
  455. }
  456. pRec = pList->First;
  457. pList->TotalMbRequired = 0;
  458. while (pRec) {
  459. //
  460. // No need to sum the disk requirements of the descriptor and
  461. // logical disk partition records.
  462. //
  463. // In a GPT disk, all partitions are primary.
  464. //
  465. if (pRec->IsContainerRecord || pRec->IsPrimaryRecord) {
  466. pList->TotalMbRequired += pRec->SizeMB;
  467. }
  468. pRec = pRec->Next;
  469. }
  470. }
  471. VOID
  472. SpAsrInitSifDiskTable(VOID)
  473. {
  474. LONG count = 0,
  475. index = 0,
  476. mbrDiskRecordCount = 0,
  477. gptDiskRecordCount = 0;
  478. PWSTR diskKey = NULL,
  479. systemKey = ASR_SIF_SYSTEM_KEY;
  480. PSIF_DISK_RECORD pCurrent = NULL;
  481. BOOLEAN done = FALSE;
  482. Gbl_AutoExtend = SpAsrGetAutoExtend(systemKey);
  483. //
  484. // Allocate the array for the disk records.
  485. //
  486. mbrDiskRecordCount = (LONG) SpAsrGetMbrDiskRecordCount();
  487. gptDiskRecordCount = (LONG) SpAsrGetGptDiskRecordCount();
  488. if ((mbrDiskRecordCount + gptDiskRecordCount) <= 0) {
  489. //
  490. // We need at least one disk in asr.sif
  491. //
  492. SpAsrRaiseFatalErrorWs(
  493. SP_SCRN_DR_SIF_BAD_RECORD,
  494. L"No records in the disks sections",
  495. SIF_ASR_DISKS_SECTION
  496. );
  497. }
  498. Gbl_SifDiskTable = SpAsrMemAlloc(sizeof(PSIF_DISK_RECORD) * (mbrDiskRecordCount + gptDiskRecordCount), TRUE);
  499. //
  500. // Get each MBR disk's partition list from the sif.
  501. //
  502. for (count = 0; count < mbrDiskRecordCount; count++) {
  503. diskKey = SpAsrGetDiskKey(PARTITION_STYLE_MBR, count);
  504. if (!diskKey) {
  505. ASSERT(0 && L"Disk key is NULL!");
  506. continue;
  507. }
  508. pCurrent = SpAsrGetDiskRecord(PARTITION_STYLE_MBR, diskKey);
  509. if (!pCurrent) {
  510. ASSERT(0 && L"Disk Record is NULL!");
  511. continue;
  512. }
  513. //
  514. // Determine the index where this record is to be added.
  515. //
  516. index = count - 1; // last entry added so far
  517. done = FALSE;
  518. while ((index >= 0) && (!done)) {
  519. if (Gbl_SifDiskTable[index]->TotalSectors > pCurrent->TotalSectors) {
  520. Gbl_SifDiskTable[index+1] = Gbl_SifDiskTable[index];
  521. --index;
  522. }
  523. else {
  524. done = TRUE;
  525. }
  526. }
  527. ++index;
  528. Gbl_SifDiskTable[index] = pCurrent;
  529. Gbl_SifDiskTable[index]->Assigned = FALSE;
  530. Gbl_SifDiskTable[index]->ContainsNtPartition = FALSE;
  531. Gbl_SifDiskTable[index]->ContainsSystemPartition = FALSE;
  532. //
  533. // Get the partitions on this disk.
  534. //
  535. Gbl_SifDiskTable[index]->PartitionList = SpAsrGetPartitionListByDiskKey(PARTITION_STYLE_MBR, diskKey);
  536. if (Gbl_SifDiskTable[index]->PartitionList) {
  537. //
  538. // Set the extended partition record boundaries, if any.
  539. //
  540. SpAsrSetContainerBoundaries(index);
  541. //
  542. // Walk the partition list and determine the type of each
  543. // partition record (i.e., IsDescriptorRecord, IsPrimaryRecord,
  544. // IsLogicalDiskRecord).
  545. //
  546. SpAsrDeterminePartitionRecordTypes(index);
  547. //
  548. // Set the SizeMB member
  549. //
  550. SpAsrSetDiskSizeRequirement(index);
  551. }
  552. }
  553. //
  554. // Repeat for GPT disks.
  555. //
  556. for (count = 0; count < gptDiskRecordCount; count++) {
  557. diskKey = SpAsrGetDiskKey(PARTITION_STYLE_GPT, count);
  558. if (!diskKey) {
  559. ASSERT(0 && L"Disk key is NULL!");
  560. continue;
  561. }
  562. pCurrent = SpAsrGetDiskRecord(PARTITION_STYLE_GPT, diskKey);
  563. if (!pCurrent) {
  564. ASSERT(0 && L"Disk Record is NULL!");
  565. continue;
  566. }
  567. //
  568. // Determine the index where this record is to be added.
  569. //
  570. index = mbrDiskRecordCount + count - 1; // last entry added so far
  571. done = FALSE;
  572. while ((index >= 0) && (!done)) {
  573. if (Gbl_SifDiskTable[index]->TotalSectors > pCurrent->TotalSectors) {
  574. Gbl_SifDiskTable[index+1] = Gbl_SifDiskTable[index];
  575. --index;
  576. }
  577. else {
  578. done = TRUE;
  579. }
  580. }
  581. ++index;
  582. Gbl_SifDiskTable[index] = pCurrent;
  583. Gbl_SifDiskTable[index]->Assigned = FALSE;
  584. Gbl_SifDiskTable[index]->ContainsNtPartition = FALSE;
  585. Gbl_SifDiskTable[index]->ContainsSystemPartition = FALSE;
  586. //
  587. // Get the partitions on this disk.
  588. //
  589. Gbl_SifDiskTable[index]->PartitionList = SpAsrGetPartitionListByDiskKey(PARTITION_STYLE_GPT, diskKey);
  590. if (Gbl_SifDiskTable[index]->PartitionList) {
  591. //
  592. // Mark all partitions as primary
  593. //
  594. SpAsrDeterminePartitionRecordTypes(index);
  595. //
  596. // Set the SizeMB member
  597. //
  598. SpAsrSetDiskSizeRequirement(index);
  599. }
  600. }
  601. }
  602. NTSTATUS
  603. SpAsrGetPartitionInfo(
  604. IN PWSTR PartitionPath,
  605. OUT PARTITION_INFORMATION *PartitionInfo
  606. )
  607. {
  608. NTSTATUS status = STATUS_SUCCESS;
  609. HANDLE partitionHandle = NULL;
  610. IO_STATUS_BLOCK ioStatusBlock;
  611. //
  612. // Open partition0 of the disk. This should always succeed.
  613. // Partition 0 is an alias for the entire disk.
  614. //
  615. status = SpOpenPartition0(
  616. PartitionPath,
  617. &partitionHandle,
  618. FALSE
  619. );
  620. if (!NT_SUCCESS(status)) {
  621. DbgErrorMesg((_asrerr,
  622. "SpAsrGetPartitionInfo. SpOpenPartition0 failed for [%ws]. (0x%lx)\n" ,
  623. PartitionPath,
  624. status));
  625. ASSERT(0 && L"SpOpenPartition0 failed");
  626. return status;
  627. }
  628. //
  629. // Use the Partition0 handle to get a PARTITION_INFORMATION structure.
  630. //
  631. status = ZwDeviceIoControlFile(
  632. partitionHandle,
  633. NULL,
  634. NULL,
  635. NULL,
  636. &ioStatusBlock,
  637. IOCTL_DISK_GET_PARTITION_INFO,
  638. NULL,
  639. 0,
  640. PartitionInfo,
  641. sizeof(PARTITION_INFORMATION)
  642. );
  643. ZwClose(partitionHandle);
  644. if(!NT_SUCCESS(status)) {
  645. DbgErrorMesg((_asrerr,
  646. "IOCTL_DISK_GET_PARTITION_INFO failed for [%ws]. (0x%lx)\n",
  647. PartitionPath,
  648. status
  649. ));
  650. // ASSERT(0 && L"IOCTL_DISK_GET_PARTITION_INFO failed");
  651. }
  652. return status;
  653. }
  654. ULONGLONG
  655. SpAsrGetTrueDiskSectorCount(IN ULONG Disk)
  656. /*++
  657. Description:
  658. Gets the sector count of this disk by using the PARTITION_INFORMATION structure
  659. obtained by using the disk's device name in the IOCTL_GET_PARTITION_INFO ioct.
  660. Arguments:
  661. Disk The physical number of the disk whose sectors are to be obtained.
  662. Returns:
  663. The total number of sectors on this disk.
  664. --*/
  665. {
  666. NTSTATUS status = STATUS_SUCCESS;
  667. PWSTR devicePath = NULL;
  668. ULONGLONG sectorCount = 0;
  669. PARTITION_INFORMATION partitionInfo;
  670. swprintf(TemporaryBuffer, L"\\Device\\Harddisk%u", Disk);
  671. devicePath = SpDupStringW(TemporaryBuffer);
  672. status = SpAsrGetPartitionInfo(devicePath, &partitionInfo);
  673. if (!NT_SUCCESS(status)) {
  674. DbgFatalMesg((_asrerr,
  675. "Could not get true disk size (0x%x). devicePath [%ws], Disk %lu\n",
  676. status, devicePath, Disk));
  677. swprintf(TemporaryBuffer, L"Failed to get partition info for %ws", devicePath);
  678. sectorCount = 0;
  679. }
  680. else {
  681. sectorCount = (ULONGLONG) (partitionInfo.PartitionLength.QuadPart / BYTES_PER_SECTOR(Disk));
  682. }
  683. SpMemFree(devicePath);
  684. return sectorCount;
  685. }
  686. VOID
  687. DetermineBuses()
  688. {
  689. HANDLE handle = NULL;
  690. PWSTR devicePath = NULL;
  691. ULONG physicalIndex = 0;
  692. IO_STATUS_BLOCK ioStatusBlock;
  693. NTSTATUS status = STATUS_SUCCESS;
  694. STORAGE_PROPERTY_QUERY propertyQuery;
  695. STORAGE_DEVICE_DESCRIPTOR deviceDesc;
  696. DISK_CONTROLLER_NUMBER ControllerInfo;
  697. SCSI_ADDRESS scsiAddress;
  698. BOOLEAN newBus, done;
  699. DWORD targetController;
  700. ULONG targetBusKey;
  701. UCHAR targetPort;
  702. //
  703. //
  704. //
  705. for (physicalIndex = 0; physicalIndex < HardDiskCount; physicalIndex++) {
  706. Gbl_PhysicalDiskInfo[physicalIndex].ControllerNumber = (DWORD) (-1);
  707. Gbl_PhysicalDiskInfo[physicalIndex].PortNumber = (UCHAR) (-1);
  708. Gbl_PhysicalDiskInfo[physicalIndex].BusKey = 0;
  709. Gbl_PhysicalDiskInfo[physicalIndex].BusType = BusTypeUnknown;
  710. //
  711. // Get a handle to the disk by opening partition 0
  712. //
  713. swprintf(TemporaryBuffer, L"\\Device\\Harddisk%u", physicalIndex);
  714. devicePath = SpDupStringW(TemporaryBuffer);
  715. status = SpOpenPartition0(devicePath, &handle, FALSE);
  716. if (!NT_SUCCESS(status)) {
  717. DbgErrorMesg((_asrwarn,
  718. "DetermineBuses: SpOpenPartition0 failed for [%ws]. (0x%lx) Assumed to be unknown bus.\n" ,
  719. devicePath, status));
  720. ASSERT(0 && L"SpOpenPartition0 failed, assuming unknown bus");
  721. continue;
  722. }
  723. //
  724. // We have a handle to the disk now. Get the controller number.
  725. //
  726. status = ZwDeviceIoControlFile(
  727. handle,
  728. NULL,
  729. NULL,
  730. NULL,
  731. &ioStatusBlock,
  732. IOCTL_DISK_CONTROLLER_NUMBER,
  733. NULL,
  734. 0,
  735. &ControllerInfo,
  736. sizeof(DISK_CONTROLLER_NUMBER)
  737. );
  738. if (!NT_SUCCESS(status)) {
  739. DbgErrorMesg((_asrwarn,
  740. "DetermineBuses: Couldn't get controller number for [%ws]. (0x%lx)\n" ,
  741. devicePath,
  742. status
  743. ));
  744. }
  745. else {
  746. Gbl_PhysicalDiskInfo[physicalIndex].ControllerNumber = ControllerInfo.ControllerNumber;
  747. }
  748. //
  749. // Figure out the bus that this disk is on.
  750. //
  751. propertyQuery.QueryType = PropertyStandardQuery;
  752. propertyQuery.PropertyId = StorageDeviceProperty;
  753. status = ZwDeviceIoControlFile(
  754. handle,
  755. NULL,
  756. NULL,
  757. NULL,
  758. &ioStatusBlock,
  759. IOCTL_STORAGE_QUERY_PROPERTY,
  760. &propertyQuery,
  761. sizeof(STORAGE_PROPERTY_QUERY),
  762. &deviceDesc,
  763. sizeof(STORAGE_DEVICE_DESCRIPTOR)
  764. );
  765. if (NT_SUCCESS(status)) {
  766. Gbl_PhysicalDiskInfo[physicalIndex].BusType = deviceDesc.BusType;
  767. }
  768. else {
  769. DbgErrorMesg((_asrwarn,
  770. "DetermineBuses: Couldn't get bus type for [%ws]. (0x%lx)\n" ,
  771. devicePath,
  772. status
  773. ));
  774. }
  775. //
  776. // Try to get the scsi address. This will fail for non-SCSI/IDE disks.
  777. //
  778. status = ZwDeviceIoControlFile(
  779. handle,
  780. NULL,
  781. NULL,
  782. NULL,
  783. &ioStatusBlock,
  784. IOCTL_SCSI_GET_ADDRESS,
  785. NULL,
  786. 0,
  787. &scsiAddress,
  788. sizeof(SCSI_ADDRESS)
  789. );
  790. if (NT_SUCCESS(status)) {
  791. Gbl_PhysicalDiskInfo[physicalIndex].PortNumber = scsiAddress.PortNumber;
  792. }
  793. SpMemFree(devicePath);
  794. ZwClose(handle);
  795. }
  796. //
  797. // Now we have the controller number and scsi port info for each of the disks
  798. // Group the disks based on this.
  799. //
  800. targetBusKey = 0;
  801. newBus = TRUE; done = FALSE;
  802. while (!done) {
  803. newBus = TRUE;
  804. for (physicalIndex = 0; physicalIndex < HardDiskCount; physicalIndex++) {
  805. if (newBus) {
  806. if (!(Gbl_PhysicalDiskInfo[physicalIndex].BusKey)) {
  807. //
  808. // This disk doesn't have a bus key yet.
  809. //
  810. newBus = FALSE;
  811. ++targetBusKey; // we found a new bus
  812. targetController = Gbl_PhysicalDiskInfo[physicalIndex].ControllerNumber;
  813. targetPort = Gbl_PhysicalDiskInfo[physicalIndex].PortNumber;
  814. Gbl_PhysicalDiskInfo[physicalIndex].BusKey = targetBusKey;
  815. }
  816. }
  817. else {
  818. if ((Gbl_PhysicalDiskInfo[physicalIndex].ControllerNumber == targetController) &&
  819. (Gbl_PhysicalDiskInfo[physicalIndex].PortNumber == targetPort)) {
  820. Gbl_PhysicalDiskInfo[physicalIndex].BusKey = targetBusKey;
  821. }
  822. }
  823. }
  824. if (newBus) {
  825. //
  826. // We went through the entire table without finding even a single disk
  827. // with BusKey = 0, ie, we've assigned BusKeys to all of them.
  828. //
  829. done = TRUE;
  830. }
  831. }
  832. }
  833. //
  834. // Sets the disk sizes by getting info about partition 0
  835. //
  836. VOID
  837. SpAsrInitPhysicalDiskInfo()
  838. {
  839. ULONG index = 0;
  840. IO_STATUS_BLOCK IoStatusBlock;
  841. DISK_CONTROLLER_NUMBER ControllerInfo;
  842. ULONGLONG TrueSectorCount = 0;
  843. Gbl_PhysicalDiskInfo = SpAsrMemAlloc((sizeof(ASR_PHYSICAL_DISK_INFO) * HardDiskCount), TRUE);
  844. DbgStatusMesg((_asrinfo, "Setting true disk sizes:\n"));
  845. for (index = 0; index < HardDiskCount; index++) {
  846. TrueSectorCount = SpAsrGetTrueDiskSectorCount(index);
  847. if (0 == TrueSectorCount) {
  848. Gbl_PhysicalDiskInfo[index].TrueDiskSize = HardDisks[index].DiskSizeSectors;
  849. }
  850. else {
  851. Gbl_PhysicalDiskInfo[index].TrueDiskSize = TrueSectorCount;
  852. }
  853. DbgStatusMesg((_asrinfo,
  854. "Disk %lu: %I64u sectors\n",
  855. index,
  856. Gbl_PhysicalDiskInfo[index].TrueDiskSize
  857. ));
  858. }
  859. //
  860. // Now determine the bus-topology of the disks. This will be used later when
  861. // we're trying to find a match for the sif-disks.
  862. //
  863. DetermineBuses();
  864. } // SpAsrInitPhysicalDiskInfo
  865. VOID
  866. SpAsrAllocateGblPartitionSetTable(VOID)
  867. {
  868. ULONG size;
  869. //
  870. // Allocate memory for the partition set table. One entry
  871. // for each physical disk attached to the system, including
  872. // removable disks (e.g., Jaz). NB: HardDiskCount does not
  873. // include CDROMs.
  874. //
  875. size = sizeof(PDISK_PARTITION_SET) * HardDiskCount;
  876. Gbl_PartitionSetTable1 = SpAsrMemAlloc(size, TRUE);
  877. }
  878. VOID
  879. SpAsrFreePartitionRecord(IN PSIF_PARTITION_RECORD pRec)
  880. {
  881. if (pRec) {
  882. if (pRec->NtDirectoryName) {
  883. SpMemFree(pRec->NtDirectoryName);
  884. }
  885. SpMemFree(pRec);
  886. }
  887. }
  888. VOID
  889. SpAsrFreePartitionList(IN PSIF_PARTITION_RECORD_LIST pList)
  890. {
  891. PSIF_PARTITION_RECORD pRec;
  892. if (!pList) {
  893. return;
  894. }
  895. while (pRec = SpAsrPopNextPartitionRecord(pList)) {
  896. SpAsrFreePartitionRecord(pRec);
  897. }
  898. SpMemFree(pList);
  899. }
  900. VOID
  901. SpAsrFreePartitionDisk(IN PSIF_DISK_RECORD pDisk)
  902. {
  903. if (!pDisk) {
  904. return;
  905. }
  906. if (pDisk->PartitionList) {
  907. SpAsrFreePartitionList(pDisk->PartitionList);
  908. }
  909. SpMemFree(pDisk);
  910. }
  911. VOID
  912. SpAsrFreePartitionSet(IN PDISK_PARTITION_SET pSet)
  913. {
  914. if (!pSet) {
  915. return;
  916. }
  917. if (pSet->pDiskRecord) {
  918. if (pSet->pDiskRecord->PartitionList) {
  919. SpAsrFreePartitionList(pSet->pDiskRecord->PartitionList);
  920. }
  921. SpMemFree(pSet->pDiskRecord);
  922. pSet->pDiskRecord = NULL;
  923. }
  924. SpMemFree(pSet);
  925. pSet = NULL;
  926. }
  927. VOID
  928. SpAsrFreePartitionSetTable(IN DISK_PARTITION_SET_TABLE Table)
  929. {
  930. ULONG index;
  931. if (!Table) {
  932. return;
  933. }
  934. for (index = 0; index < HardDiskCount; index++) {
  935. if (Table[index]) {
  936. SpAsrFreePartitionSet(Table[index]);
  937. }
  938. }
  939. SpMemFree(Table);
  940. Table = NULL;
  941. }
  942. PDISK_PARTITION_SET
  943. SpAsrCopyPartitionSet(IN PDISK_PARTITION_SET pSetOriginal)
  944. {
  945. PDISK_PARTITION_SET pSetNew;
  946. if (!pSetOriginal) {
  947. return NULL;
  948. }
  949. pSetNew = SpAsrMemAlloc(sizeof(DISK_PARTITION_SET), TRUE);
  950. pSetNew->ActualDiskSignature = pSetOriginal->ActualDiskSignature;
  951. pSetNew->PartitionsIntact = pSetOriginal->PartitionsIntact;
  952. pSetNew->IsReplacementDisk = pSetOriginal->IsReplacementDisk;
  953. pSetNew->NtPartitionKey = pSetOriginal->NtPartitionKey;
  954. if (pSetOriginal->pDiskRecord == NULL) {
  955. pSetNew->pDiskRecord = NULL;
  956. }
  957. else {
  958. pSetNew->pDiskRecord = SpAsrCopyDiskRecord(pSetOriginal->pDiskRecord);
  959. pSetNew->pDiskRecord->pSetRecord = pSetNew;
  960. }
  961. return pSetNew;
  962. }
  963. DISK_PARTITION_SET_TABLE
  964. SpAsrCopyPartitionSetTable(IN DISK_PARTITION_SET_TABLE SrcTable)
  965. {
  966. ULONG index = 0;
  967. DISK_PARTITION_SET_TABLE destTable = NULL;
  968. PSIF_PARTITION_RECORD_LIST pList = NULL;
  969. if (!SrcTable) {
  970. ASSERT(0 && L"SpAsrCopyPartitionSetTable: Copy failed, source partition table is NULL.");
  971. return NULL;
  972. }
  973. destTable = SpAsrMemAlloc(sizeof(PDISK_PARTITION_SET) * HardDiskCount, TRUE);
  974. for (index = 0; index < HardDiskCount; index++) {
  975. if (SrcTable[index]) {
  976. destTable[index] = SpAsrCopyPartitionSet(SrcTable[index]);
  977. }
  978. else {
  979. destTable[index] = NULL;
  980. }
  981. }
  982. return destTable;
  983. } // SpAsrCopyPartitionSetTable
  984. BOOLEAN
  985. PickABootPartition(
  986. IN OUT PSIF_PARTITION_RECORD pCurrent,
  987. IN OUT PSIF_PARTITION_RECORD pNew
  988. )
  989. {
  990. ASSERT(pCurrent && pNew);
  991. //
  992. // They must both be marked boot or sys.
  993. //
  994. ASSERT(SpAsrIsBootPartitionRecord(pCurrent->PartitionFlag)
  995. && SpAsrIsBootPartitionRecord(pNew->PartitionFlag));
  996. //
  997. // If this is a mirrored partition, then the volume guids must
  998. // be the same. And they should be on different spindles. But
  999. // in the interests of being nice to the user, we don't enforce this
  1000. // here, we just ASSERT.
  1001. //
  1002. // We pick one of the two partitions marked as boot, based on:
  1003. // 1. If one of the partitions is marked active and the other isn't,
  1004. // we use the active partition.
  1005. // 2. If they are of different sizes, we pick the smaller partition
  1006. // since we don't want to mirror a partition to a smaller one.
  1007. // 3. Just pick the first one.
  1008. //
  1009. ASSERT(wcscmp(pCurrent->VolumeGuid, pNew->VolumeGuid) == 0);
  1010. ASSERT(wcscmp(pCurrent->DiskKey, pNew->DiskKey) != 0);
  1011. //
  1012. // 1. Check active flags
  1013. //
  1014. if ((pCurrent->ActiveFlag) && (!pNew->ActiveFlag)) {
  1015. //
  1016. // pCurrent is marked active and pNew isn't
  1017. //
  1018. pNew->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1019. return FALSE;
  1020. }
  1021. if ((!pCurrent->ActiveFlag) && (pNew->ActiveFlag)) {
  1022. //
  1023. // pNew is marked active and pCurrent isn't
  1024. //
  1025. pCurrent->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1026. return TRUE; // new boot ptn rec
  1027. }
  1028. //
  1029. // 2. Check sizes
  1030. //
  1031. if (pCurrent->SizeMB != pNew->SizeMB) {
  1032. if (pCurrent->SizeMB > pNew->SizeMB) {
  1033. //
  1034. // pNew is smaller, so that becomes the new boot ptn
  1035. //
  1036. pCurrent->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1037. return TRUE;
  1038. }
  1039. else {
  1040. //
  1041. // pCurrent is smaller, so that is the boot ptn
  1042. //
  1043. pNew->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1044. return FALSE;
  1045. }
  1046. }
  1047. //
  1048. // 3. Just pick the first (pCurrent)
  1049. //
  1050. pNew->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1051. return FALSE;
  1052. }
  1053. BOOLEAN
  1054. PickASystemPartition(
  1055. IN PSIF_PARTITION_RECORD FirstPartition,
  1056. IN PSIF_DISK_RECORD FirstDisk,
  1057. IN PSIF_PARTITION_RECORD SecondPartition,
  1058. IN PSIF_DISK_RECORD SecondDisk,
  1059. IN CONST DWORD CurrentSystemDiskNumber,
  1060. IN CONST BOOL BootSameAsSystem
  1061. )
  1062. {
  1063. PHARD_DISK CurrentSystemDisk = NULL;
  1064. BOOLEAN IsAligned = TRUE;
  1065. if (CurrentSystemDiskNumber != (DWORD)(-1)) {
  1066. CurrentSystemDisk = &HardDisks[CurrentSystemDiskNumber];
  1067. }
  1068. ASSERT(FirstPartition && SecondPartition);
  1069. ASSERT(FirstDisk && SecondDisk);
  1070. //
  1071. // They must both be marked system
  1072. //
  1073. ASSERT(SpAsrIsSystemPartitionRecord(FirstPartition->PartitionFlag)
  1074. && SpAsrIsSystemPartitionRecord(SecondPartition->PartitionFlag));
  1075. //
  1076. // If this is a mirrored partition, then the volume guids must
  1077. // be the same. And they should be on different spindles. But
  1078. // in the interests of being nice to the user, we don't enforce this
  1079. // here, we just ASSERT.
  1080. //
  1081. ASSERT(wcscmp(FirstPartition->VolumeGuid, SecondPartition->VolumeGuid) == 0);
  1082. ASSERT(wcscmp(FirstPartition->DiskKey, SecondPartition->DiskKey) != 0);
  1083. //
  1084. // If the partitioning style of either disk is different from the
  1085. // current system disk (very unlikely) then we should pick the other
  1086. //
  1087. if ((CurrentSystemDisk) &&
  1088. ((PARTITION_STYLE)CurrentSystemDisk->DriveLayout.PartitionStyle != SecondDisk->PartitionStyle)
  1089. ) {
  1090. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1091. if (BootSameAsSystem) {
  1092. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1093. }
  1094. return FALSE;
  1095. }
  1096. if ((CurrentSystemDisk) &&
  1097. (PARTITION_STYLE)CurrentSystemDisk->DriveLayout.PartitionStyle != FirstDisk->PartitionStyle) {
  1098. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1099. if (BootSameAsSystem) {
  1100. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1101. }
  1102. return TRUE;
  1103. }
  1104. //
  1105. // All three have the same partitioning style. Check signatures/GUID.
  1106. //
  1107. if (PARTITION_STYLE_MBR == FirstDisk->PartitionStyle) {
  1108. if ((CurrentSystemDisk) &&
  1109. (CurrentSystemDisk->DriveLayout.Mbr.Signature == FirstDisk->SifDiskMbrSignature)) {
  1110. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1111. if (BootSameAsSystem) {
  1112. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1113. }
  1114. return FALSE;
  1115. }
  1116. if ((CurrentSystemDisk) &&
  1117. (CurrentSystemDisk->DriveLayout.Mbr.Signature == SecondDisk->SifDiskMbrSignature)) {
  1118. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1119. if (BootSameAsSystem) {
  1120. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1121. }
  1122. return TRUE;
  1123. }
  1124. }
  1125. else if (PARTITION_STYLE_GPT == FirstDisk->PartitionStyle) {
  1126. if ((CurrentSystemDisk) &&
  1127. !RtlCompareMemory(
  1128. &(CurrentSystemDisk->DriveLayout.Gpt.DiskId),
  1129. &(FirstDisk->SifDiskGptId),
  1130. sizeof(GUID)
  1131. )) {
  1132. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1133. if (BootSameAsSystem) {
  1134. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1135. }
  1136. return FALSE;
  1137. }
  1138. if (!RtlCompareMemory(
  1139. &(CurrentSystemDisk->DriveLayout.Gpt.DiskId),
  1140. &(SecondDisk->SifDiskGptId),
  1141. sizeof(GUID)
  1142. )) {
  1143. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1144. if (BootSameAsSystem) {
  1145. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1146. }
  1147. return TRUE;
  1148. }
  1149. }
  1150. else {
  1151. ASSERT(0 && L"Unrecognised partition style found");
  1152. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1153. if (BootSameAsSystem) {
  1154. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1155. }
  1156. return FALSE;
  1157. }
  1158. //
  1159. // The signatures didn't match. Now try to see which might be a better fit
  1160. //
  1161. //
  1162. // Else, look for the better fit of the two disks.
  1163. //
  1164. if ((!SpAsrDoesListFitOnDisk(SecondDisk, CurrentSystemDiskNumber, &IsAligned)) ||
  1165. (!IsAligned)
  1166. ) {
  1167. //
  1168. // The current system disk isn't big enough to hold the partitions
  1169. // on the second disk, so return the first disk as our chosen one.
  1170. //
  1171. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1172. if (BootSameAsSystem) {
  1173. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1174. }
  1175. return FALSE;
  1176. }
  1177. if ((!SpAsrDoesListFitOnDisk(FirstDisk, CurrentSystemDiskNumber, &IsAligned)) ||
  1178. (!IsAligned)
  1179. ) {
  1180. //
  1181. // The current system disk isn't big enough to hold the partitions
  1182. // on the first disk, so return the second disk as our chosen one.
  1183. //
  1184. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1185. if (BootSameAsSystem) {
  1186. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1187. }
  1188. return TRUE;
  1189. }
  1190. //
  1191. // The current system disk is big enough to hold either of the two
  1192. // disks we're trying to decide between.
  1193. //
  1194. //
  1195. // Check active flags
  1196. //
  1197. if ((FirstPartition->ActiveFlag) && (!SecondPartition->ActiveFlag)) {
  1198. //
  1199. // FirstPartition is marked active and SecondPartition isn't
  1200. //
  1201. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1202. if (BootSameAsSystem) {
  1203. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1204. }
  1205. return FALSE;
  1206. }
  1207. if ((!FirstPartition->ActiveFlag) && (SecondPartition->ActiveFlag)) {
  1208. //
  1209. // SecondPartition is marked active and FirstPartition isn't
  1210. //
  1211. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1212. if (BootSameAsSystem) {
  1213. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1214. }
  1215. return TRUE; // new sys ptn rec
  1216. }
  1217. //
  1218. // Check sizes
  1219. //
  1220. if (FirstPartition->SizeMB != SecondPartition->SizeMB) {
  1221. if (FirstPartition->SizeMB > SecondPartition->SizeMB) {
  1222. //
  1223. // SecondPartition is smaller, so that becomes the new system ptn
  1224. //
  1225. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1226. if (BootSameAsSystem) {
  1227. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1228. }
  1229. return TRUE;
  1230. }
  1231. else {
  1232. //
  1233. // FirstPartition is smaller, so that is the system ptn
  1234. //
  1235. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1236. if (BootSameAsSystem) {
  1237. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1238. }
  1239. return FALSE;
  1240. }
  1241. }
  1242. //
  1243. // Check sizes of the original disks
  1244. //
  1245. if (FirstDisk->TotalSectors != SecondDisk->TotalSectors) {
  1246. if (FirstDisk->TotalSectors > SecondDisk->TotalSectors) {
  1247. //
  1248. // First disk used to be bigger than the second (and
  1249. // fits in our current system disk), so pick that
  1250. //
  1251. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1252. if (BootSameAsSystem) {
  1253. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1254. }
  1255. return FALSE;
  1256. }
  1257. else {
  1258. //
  1259. // Second disk used to be bigger than the first (and
  1260. // fits in our current system disk), so pick that
  1261. //
  1262. FirstPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1263. if (BootSameAsSystem) {
  1264. FirstPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1265. }
  1266. return TRUE; // new sys ptn rec
  1267. }
  1268. }
  1269. //
  1270. // Just pick the first (FirstPartition)
  1271. //
  1272. SecondPartition->PartitionFlag -= ASR_PTN_MASK_SYS;
  1273. if (BootSameAsSystem) {
  1274. SecondPartition->PartitionFlag -= ASR_PTN_MASK_BOOT;
  1275. }
  1276. return FALSE;
  1277. }
  1278. //
  1279. // This sets the "NeedsLdmRetype" flag to true for all the partitions on
  1280. // the system/boot disk, if the system/boot partition is of an
  1281. // unrecognised partition type. We need to do this because we can't install
  1282. // to unrecognised partition types.
  1283. //
  1284. VOID
  1285. MarkPartitionLdmRetypes(
  1286. PSIF_PARTITION_RECORD pPartition, // system/boot partition
  1287. PSIF_PARTITION_RECORD pFirst // first partition rec on the sys/boot disk
  1288. )
  1289. {
  1290. PSIF_PARTITION_RECORD pPtnRec = pFirst;
  1291. //
  1292. // Make sure it's an MBR or a GPT disk. Also, if the system partition
  1293. // is NOT a special partition--such as an 0x42 LDM partition or some other
  1294. // third party FS type that we can't install to--then we don't need to
  1295. // retype any of the partitions.
  1296. //
  1297. if (PARTITION_STYLE_MBR == pPartition->PartitionStyle) {
  1298. if (IsRecognizedPartition(pPartition->PartitionType)) {
  1299. //
  1300. // They system/boot partition has a recognised FS, such as FAT
  1301. // or NTFS. We don't need any special handling.
  1302. //
  1303. return;
  1304. }
  1305. }
  1306. else if (PARTITION_STYLE_GPT == pPartition->PartitionStyle) {
  1307. if (!memcmp(&(pPartition->PartitionTypeGuid), &PARTITION_BASIC_DATA_GUID, sizeof(GUID)) ||
  1308. !memcmp(&(pPartition->PartitionTypeGuid), &PARTITION_ENTRY_UNUSED_GUID, sizeof(GUID)) ||
  1309. !memcmp(&(pPartition->PartitionTypeGuid), &PARTITION_SYSTEM_GUID, sizeof(GUID)) ||
  1310. !memcmp(&(pPartition->PartitionTypeGuid), &PARTITION_MSFT_RESERVED_GUID, sizeof(GUID))
  1311. ) {
  1312. //
  1313. // They system/boot partition is a basic partition type
  1314. // We don't need any special handling.
  1315. //
  1316. return;
  1317. }
  1318. }
  1319. else {
  1320. ASSERT(0 && L"Unrecognised partition type");
  1321. return;
  1322. }
  1323. //
  1324. // The partition of interest is an LDM, or some other special third party
  1325. // partition. We need to mark all the partitions on that disk of the
  1326. // same type (ie all LDM partitions on the disk) to be retyped to a basic
  1327. // partition.
  1328. //
  1329. while (pPtnRec) {
  1330. //
  1331. // They both better be the same--either MBR or GPT.
  1332. //
  1333. ASSERT(pPtnRec->PartitionStyle == pPartition->PartitionStyle);
  1334. if (PARTITION_STYLE_MBR == pPtnRec->PartitionStyle) {
  1335. if (pPtnRec->PartitionType == pPartition->PartitionType) {
  1336. //
  1337. // This partition has the same partition-type as the
  1338. // partition of interest. We need to retype it.
  1339. //
  1340. pPtnRec->NeedsLdmRetype = TRUE;
  1341. DbgStatusMesg((_asrinfo,
  1342. "Marked disk [%ws] ptn [%ws] to change (Ptn:0x%x Fs:0x%x)\n",
  1343. pPtnRec->DiskKey,
  1344. pPtnRec->CurrPartKey,
  1345. pPtnRec->PartitionType,
  1346. pPtnRec->FileSystemType
  1347. ));
  1348. }
  1349. }
  1350. else if (PARTITION_STYLE_GPT == pPtnRec->PartitionStyle) {
  1351. if (!memcmp(&(pPtnRec->PartitionTypeGuid), &(pPartition->PartitionTypeGuid), sizeof(GUID))) {
  1352. //
  1353. // This partition has the same partition-type as the
  1354. // partition of interest. We need to retype it.
  1355. //
  1356. pPtnRec->NeedsLdmRetype = TRUE;
  1357. DbgStatusMesg((_asrinfo,
  1358. "Marked disk %d ptn [%ws] to change (%ws to basic)\n",
  1359. pPtnRec->DiskKey,
  1360. pPtnRec->CurrPartKey,
  1361. pPtnRec->PartitionTypeGuid
  1362. ));
  1363. }
  1364. }
  1365. pPtnRec = pPtnRec->Next;
  1366. }
  1367. }
  1368. //
  1369. // If more than one system/boot partitions exist (because of mirrors), this
  1370. // will mark one as the sys/boot ptns, and reset the others.
  1371. //
  1372. VOID
  1373. SpAsrCheckSifDiskTable(IN CONST DWORD CurrentSystemDiskNumber)
  1374. {
  1375. ULONG numDiskRecords = 0,
  1376. diskIndex = 0,
  1377. partitionIndex = 0;
  1378. USHORT numNtPartitionsFound = 0,
  1379. numSysPartitionsFound = 0;
  1380. PSIF_DISK_RECORD pDiskRec = NULL,
  1381. pBootDiskRec = NULL,
  1382. pSysDiskRec = NULL;
  1383. PSIF_PARTITION_RECORD pPtnRec = NULL,
  1384. pBootPtnRec = NULL,
  1385. pSysPtnRec = NULL;
  1386. DWORD dwConsistencyCheck = 0;
  1387. BOOLEAN needToRetypeBoot = TRUE;
  1388. //
  1389. // Go through the sif-disk list. We check each partition on each of
  1390. // these disks to see if it is marked as boot/sys. We need
  1391. // at least one boot/sys ptn.
  1392. //
  1393. numDiskRecords = SpAsrGetMbrDiskRecordCount() + SpAsrGetGptDiskRecordCount();
  1394. for (diskIndex = 0; diskIndex < numDiskRecords; diskIndex++) {
  1395. pDiskRec = Gbl_SifDiskTable[diskIndex];
  1396. if (!pDiskRec || !(pDiskRec->PartitionList)) {
  1397. continue;
  1398. }
  1399. pPtnRec = Gbl_SifDiskTable[diskIndex]->PartitionList->First;
  1400. while (pPtnRec) {
  1401. //
  1402. // A system could end up having multiple boot and/or system
  1403. // partitions. For instance, LDM-Pro supports 3-way mirrors,
  1404. // and we would hence have three partitions marked as boot/sys.
  1405. //
  1406. // We will reset this to have only one boot partition,
  1407. // and only one system partition.
  1408. //
  1409. if (SpAsrIsSystemPartitionRecord(pPtnRec->PartitionFlag) &&
  1410. SpAsrIsBootPartitionRecord(pPtnRec->PartitionFlag)) {
  1411. //
  1412. // The boot and system volumes are the same
  1413. //
  1414. ASSERT((0 == dwConsistencyCheck) || (1 == dwConsistencyCheck));
  1415. if (0 == dwConsistencyCheck) {
  1416. DbgStatusMesg((_asrinfo,
  1417. "Boot and system partitions are the same\n"
  1418. ));
  1419. }
  1420. dwConsistencyCheck = 1;
  1421. numSysPartitionsFound++;
  1422. numNtPartitionsFound++;
  1423. if (numSysPartitionsFound == 1) {
  1424. //
  1425. // This is the first system/boot partition we found. Save
  1426. // a pointer to it.
  1427. //
  1428. pDiskRec->ContainsSystemPartition = TRUE;
  1429. pSysPtnRec = pPtnRec;
  1430. pSysDiskRec = pDiskRec;
  1431. pDiskRec->ContainsNtPartition = TRUE;
  1432. pBootPtnRec = pPtnRec;
  1433. pBootDiskRec = pDiskRec;
  1434. }
  1435. else {
  1436. //
  1437. // We found more than one system/boot partition. Pick one
  1438. // of them as the system/boot partition and reset the
  1439. // other for now. (It will be recreated at the end of
  1440. // gui setup by the appropriate vol mgr utils).
  1441. //
  1442. BOOLEAN newSys = PickASystemPartition(pSysPtnRec,
  1443. pSysDiskRec,
  1444. pPtnRec,
  1445. pDiskRec,
  1446. CurrentSystemDiskNumber,
  1447. TRUE // Boot and system are the same
  1448. );
  1449. if (newSys) {
  1450. //
  1451. // pPtnRec is the new system partition
  1452. //
  1453. pSysDiskRec->ContainsSystemPartition = FALSE;
  1454. pDiskRec->ContainsSystemPartition = TRUE;
  1455. pSysDiskRec = pDiskRec;
  1456. pSysPtnRec = pPtnRec;
  1457. pBootDiskRec->ContainsNtPartition = FALSE;
  1458. pDiskRec->ContainsNtPartition = TRUE;
  1459. pBootDiskRec = pDiskRec;
  1460. pBootPtnRec = pPtnRec;
  1461. }
  1462. }
  1463. }
  1464. else {
  1465. //
  1466. // The boot and system volumes are distinct
  1467. //
  1468. if (SpAsrIsBootPartitionRecord(pPtnRec->PartitionFlag)) {
  1469. if (0 == dwConsistencyCheck) {
  1470. DbgStatusMesg((_asrinfo,
  1471. "Boot and system partitions different\n"
  1472. ));
  1473. }
  1474. ASSERT((0 == dwConsistencyCheck) || (2 == dwConsistencyCheck));
  1475. dwConsistencyCheck = 2;
  1476. numNtPartitionsFound++;
  1477. if (numNtPartitionsFound == 1) {
  1478. //
  1479. // This is the first boot partition we found, save
  1480. // a pointer to it.
  1481. //
  1482. pDiskRec->ContainsNtPartition = TRUE;
  1483. pBootPtnRec = pPtnRec;
  1484. pBootDiskRec = pDiskRec;
  1485. }
  1486. else {
  1487. //
  1488. // We found more than one boot partition. Pick
  1489. // one of them as the boot partition, reset the other
  1490. // for now. (It will be recreated at the end of
  1491. // gui setup by the appropriate vol mgr utils).
  1492. //
  1493. BOOLEAN newBoot = PickABootPartition(pBootPtnRec, pPtnRec);
  1494. if (newBoot) {
  1495. //
  1496. // pPtnRec is our new boot record
  1497. //
  1498. pBootDiskRec->ContainsNtPartition = FALSE;
  1499. pDiskRec->ContainsNtPartition = TRUE;
  1500. pBootDiskRec = pDiskRec;
  1501. pBootPtnRec = pPtnRec;
  1502. }
  1503. }
  1504. }
  1505. if (SpAsrIsSystemPartitionRecord(pPtnRec->PartitionFlag)) {
  1506. ASSERT((0 == dwConsistencyCheck) || (2 == dwConsistencyCheck));
  1507. dwConsistencyCheck = 2;
  1508. numSysPartitionsFound++;
  1509. if (numSysPartitionsFound == 1) {
  1510. //
  1511. // This is the first system partition we found. Save
  1512. // a pointer to it.
  1513. //
  1514. pDiskRec->ContainsSystemPartition = TRUE;
  1515. pSysPtnRec = pPtnRec;
  1516. pSysDiskRec = pDiskRec;
  1517. }
  1518. else {
  1519. //
  1520. // We found more than one system partition. Pick one of
  1521. // them as the system partition and reset the other
  1522. // for now. (It will be recreated at the end of
  1523. // gui setup by the appropriate vol mgr utils).
  1524. //
  1525. BOOLEAN newSys = PickASystemPartition(pSysPtnRec,
  1526. pSysDiskRec,
  1527. pPtnRec,
  1528. pDiskRec,
  1529. CurrentSystemDiskNumber,
  1530. FALSE // Boot and system are distinct
  1531. );
  1532. if (newSys) {
  1533. //
  1534. // pPtnRec is the new system partition
  1535. //
  1536. pSysDiskRec->ContainsSystemPartition = FALSE;
  1537. pDiskRec->ContainsSystemPartition = TRUE;
  1538. pSysDiskRec = pDiskRec;
  1539. pSysPtnRec = pPtnRec;
  1540. }
  1541. }
  1542. }
  1543. }
  1544. pPtnRec = pPtnRec->Next;
  1545. }
  1546. }
  1547. DbgStatusMesg((_asrinfo,
  1548. "Found %hu boot partition(s) and %hu system partition(s) in asr.sif\n",
  1549. numNtPartitionsFound,
  1550. numSysPartitionsFound
  1551. ));
  1552. //
  1553. // We should have at least one boot and one system volume
  1554. // We can't proceed without them, so this has to be a fatal error.
  1555. //
  1556. if (numNtPartitionsFound < 1) {
  1557. DbgFatalMesg((_asrerr, "Error in asr.sif: No boot partitions found.\n"));
  1558. SpAsrRaiseFatalErrorWs(
  1559. SP_SCRN_DR_SIF_BAD_RECORD,
  1560. L"No boot partition found in asr.sif",
  1561. SIF_ASR_PARTITIONS_SECTION
  1562. );
  1563. }
  1564. if (numSysPartitionsFound < 1) {
  1565. DbgFatalMesg((_asrerr, "Error in asr.sif: No system partitions found.\n"));
  1566. SpAsrRaiseFatalErrorWs(
  1567. SP_SCRN_DR_SIF_BAD_RECORD,
  1568. L"No system partition found in asr.sif",
  1569. SIF_ASR_PARTITIONS_SECTION
  1570. );
  1571. }
  1572. //
  1573. // Now, look for the disk(s) which contain the boot and system partitions.
  1574. // If any partitions on these disks are not recognised (recognised implies
  1575. // types 6, 7 and B--if they aren't recognised, they could be LDM (0x42),
  1576. // LDM-Pro, etc) then *all* the partitions on the disk that have the
  1577. // same type as the system or boot partition are changed to the basic type.
  1578. //
  1579. // For the boot and system partitions, since we actually format them in text-
  1580. // mode, we will change the type to the FS type. For everything else, we
  1581. // don't format them till the volumes are actually exposed by LDM/LDM-Pro.
  1582. // So we just use type 0x7 as a place-holder.
  1583. //
  1584. // LDM needs this to recover its state after textmode setup. Mark them.
  1585. //
  1586. needToRetypeBoot = TRUE;
  1587. if (PARTITION_STYLE_MBR == pSysDiskRec->PartitionStyle) {
  1588. MarkPartitionLdmRetypes(pSysPtnRec, pSysDiskRec->PartitionList->First);
  1589. if (pBootDiskRec == pSysDiskRec) {
  1590. needToRetypeBoot = FALSE;
  1591. }
  1592. }
  1593. if (needToRetypeBoot) {
  1594. MarkPartitionLdmRetypes(pBootPtnRec, pBootDiskRec->PartitionList->First);
  1595. }
  1596. } // SpAsrCheckSifDiskTable
  1597. PDISK_REGION
  1598. SpAsrDiskPartitionExists(
  1599. IN ULONG Disk,
  1600. IN PSIF_PARTITION_RECORD pRec
  1601. )
  1602. {
  1603. PPARTITIONED_DISK pDisk = NULL;
  1604. PDISK_REGION pRegion = NULL;
  1605. ULONGLONG startSector = 0;
  1606. BOOLEAN isLogical = FALSE;
  1607. pDisk = &PartitionedDisks[Disk];
  1608. isLogical = pRec->IsLogicalDiskRecord;
  1609. startSector = pRec->StartSector;// - (isLogical? SECTORS_PER_TRACK(Disk) : 0);
  1610. pRegion = SpPtLookupRegionByStart(
  1611. pDisk,
  1612. (BOOLEAN) (pRec->IsPrimaryRecord ? 0 : 1),
  1613. startSector
  1614. );
  1615. if (!pRegion && isLogical) {
  1616. //
  1617. // For logical drives, try finding their descriptor.
  1618. //
  1619. startSector = pRec->StartSector - SECTORS_PER_TRACK(Disk);
  1620. pRegion = SpPtLookupRegionByStart(
  1621. pDisk,
  1622. (BOOLEAN) (pRec->IsPrimaryRecord ? 0 : 1),
  1623. startSector
  1624. );
  1625. }
  1626. if (!pRegion) {
  1627. //
  1628. // No primary or extended partition could be found at the specified start sector.
  1629. //
  1630. DbgErrorMesg((_asrwarn, "partition for record [%ws] not found at start sector %I64u (disk %lu)\n",
  1631. pRec->CurrPartKey,
  1632. startSector,
  1633. Disk
  1634. ));
  1635. return NULL;
  1636. }
  1637. DbgStatusMesg((_asrinfo, "Partition for record [%ws] found at SS %I64u\n",
  1638. pRec->CurrPartKey,
  1639. startSector
  1640. ));
  1641. return pRegion;
  1642. }
  1643. //
  1644. // Goes through the list of sif-disks ("partition sets") and checks if
  1645. // they are intact. A disk is intact if its signature and the partition
  1646. // layout are intact.
  1647. //
  1648. VOID
  1649. MarkIntactSifDisk(IN ULONG Disk, IN PDISK_PARTITION_SET pSet)
  1650. {
  1651. PSIF_PARTITION_RECORD pRec = NULL;
  1652. ULONG diskSignature = 0;
  1653. PDISK_REGION pRegion = NULL;
  1654. if (!pSet || !pSet->pDiskRecord) {
  1655. DbgStatusMesg((_asrinfo, "Disk %lu contains no partition set\n", Disk));
  1656. return;
  1657. }
  1658. pSet->IsReplacementDisk = TRUE;
  1659. pSet->PartitionsIntact = FALSE;
  1660. //
  1661. // If one's an MBR and the other's a GPT, it's not the same disk
  1662. //
  1663. if (pSet->pDiskRecord->PartitionStyle != (PARTITION_STYLE) HardDisks[Disk].DriveLayout.PartitionStyle) {
  1664. return;
  1665. }
  1666. //
  1667. // If signatures (MBR) or disk ID's (GPT) are different, it
  1668. // is a replacement disk
  1669. //
  1670. if (PARTITION_STYLE_MBR == pSet->pDiskRecord->PartitionStyle) {
  1671. diskSignature = SpAsrGetActualDiskSignature(Disk);
  1672. if (pSet->pDiskRecord->SifDiskMbrSignature != diskSignature) {
  1673. return;
  1674. }
  1675. }
  1676. else if (PARTITION_STYLE_GPT == pSet->pDiskRecord->PartitionStyle) {
  1677. if (memcmp(&(HardDisks[Disk].DriveLayout.Gpt.DiskId),
  1678. &(pSet->pDiskRecord->SifDiskGptId),
  1679. sizeof(GUID)
  1680. )) {
  1681. return;
  1682. }
  1683. }
  1684. //
  1685. // This is the same disk as the original system. Now, determine whether
  1686. // the disk is intact.
  1687. //
  1688. pSet->IsReplacementDisk = FALSE;
  1689. pSet->PartitionsIntact = TRUE;
  1690. //
  1691. // The disk had no partitions to begin with, we'll assume it's intact
  1692. //
  1693. if (!(pSet->pDiskRecord->PartitionList)) {
  1694. DbgStatusMesg((_asrinfo,
  1695. "MarkIntactSifDisk. ptn-list for disk %lu NULL, assuming it is intact\n",
  1696. Disk));
  1697. return;
  1698. }
  1699. //
  1700. // check if each partition exists
  1701. //
  1702. pRec = pSet->pDiskRecord->PartitionList->First;
  1703. while (pRec) {
  1704. //
  1705. // we're interested only in primary partitions and logical disks
  1706. //
  1707. if ((pRec->IsPrimaryRecord) || (pRec->IsLogicalDiskRecord)) {
  1708. //
  1709. // Make sure the region exists
  1710. //
  1711. pRegion = SpAsrDiskPartitionExists(Disk, pRec);
  1712. if (!pRegion) {
  1713. DbgStatusMesg((_asrinfo, "Partition %p [%ws], SS "
  1714. "%I64u NOT intact: Region not found\n",
  1715. pRec, pRec->CurrPartKey, pRec->StartSector));
  1716. pSet->PartitionsIntact = FALSE;
  1717. break;
  1718. }
  1719. //
  1720. // And it's not free space
  1721. //
  1722. if (!(SPPT_IS_REGION_PARTITIONED(pRegion))) {
  1723. DbgStatusMesg((_asrinfo, "Partition %p [%ws], SS %I64u NOT "
  1724. "intact: Region %p not partitioned\n",
  1725. pRec, pRec->CurrPartKey, pRec->StartSector, pRegion));
  1726. pSet->PartitionsIntact = FALSE;
  1727. break;
  1728. }
  1729. //
  1730. // And that the partition lengths match
  1731. //
  1732. if (pRegion->SectorCount != pRec->SectorCount) {
  1733. DbgStatusMesg((_asrinfo, "Partition %p [%ws] Region %p, SS "
  1734. "%I64u NOT intact (Sector count orig-ptn: %I64u, Region: "
  1735. " %I64u)\n", pRec, pRec->CurrPartKey, pRegion,
  1736. pRec->StartSector, pRec->SectorCount, pRegion->SectorCount));
  1737. pSet->PartitionsIntact = FALSE;
  1738. break;
  1739. }
  1740. //
  1741. // And that the partition type is the same
  1742. //
  1743. if (PARTITION_STYLE_MBR == pSet->pDiskRecord->PartitionStyle) {
  1744. if (pRegion->PartInfo.Mbr.PartitionType != pRec->PartitionType) {
  1745. DbgStatusMesg((_asrinfo, "Partition %p [%ws] Region %p, SS "
  1746. "%I64u NOT intact (Ptn types orig-ptn: 0x%x, Region: "
  1747. "0x%x)\n", pRec, pRec->CurrPartKey, pRegion,
  1748. pRec->StartSector, pRec->PartitionType,
  1749. pRegion->PartInfo.Mbr.PartitionType));
  1750. pSet->PartitionsIntact = FALSE;
  1751. break;
  1752. }
  1753. }
  1754. else if (PARTITION_STYLE_GPT == pSet->pDiskRecord->PartitionStyle) {
  1755. if (memcmp(&(pRegion->PartInfo.Gpt.PartitionId),
  1756. &(pRec->PartitionIdGuid), sizeof(GUID))) {
  1757. DbgStatusMesg((_asrinfo, "Partition %p [%ws] Region %p, "
  1758. "SS %I64u NOT intact (GPT partition Id's don't match)\n",
  1759. pRec, pRec->CurrPartKey,pRegion, pRec->StartSector));
  1760. pSet->PartitionsIntact = FALSE;
  1761. break;
  1762. }
  1763. if (memcmp(&(pRegion->PartInfo.Gpt.PartitionType),
  1764. &(pRec->PartitionTypeGuid), sizeof(GUID))) {
  1765. DbgStatusMesg((_asrinfo, "Partition %p [%ws] Region %p, "
  1766. "SS %I64u NOT intact (GPT partition types don't match)\n",
  1767. pRec, pRec->CurrPartKey, pRegion, pRec->StartSector));
  1768. pSet->PartitionsIntact = FALSE;
  1769. break;
  1770. }
  1771. //
  1772. // Note that I'm not checking the GPT attributes here. If
  1773. // the attributes are not intact, but everything else above
  1774. // is, we'll assume that the partition is intact.
  1775. //
  1776. }
  1777. //
  1778. // And finally, if the boot/system region is dynamic, we
  1779. // repartition the disk.
  1780. //
  1781. if (SpAsrIsBootPartitionRecord(pRec->PartitionFlag) ||
  1782. SpAsrIsSystemPartitionRecord(pRec->PartitionFlag)) {
  1783. if (pRegion->DynamicVolume) {
  1784. DbgStatusMesg((_asrinfo, "Boot/system partition %p [%ws] "
  1785. "Region %p, SS %I64u NOT intact (Dynamic region)\n",
  1786. pRec, pRec->CurrPartKey, pRegion, pRec->StartSector));
  1787. pSet->PartitionsIntact = FALSE;
  1788. break;
  1789. }
  1790. }
  1791. }
  1792. pRec = pRec->Next;
  1793. }
  1794. DbgStatusMesg((_asrinfo, "Disk %lu is %wsintact\n",
  1795. Disk, (pSet->PartitionsIntact ? L"" : L"NOT ")));
  1796. }
  1797. VOID
  1798. MarkIntactSifDisks(VOID)
  1799. {
  1800. ULONG disk;
  1801. for (disk = 0; disk < HardDiskCount; disk++) {
  1802. if (Gbl_PartitionSetTable1[disk]) {
  1803. MarkIntactSifDisk(disk, Gbl_PartitionSetTable1[disk]);
  1804. }
  1805. }
  1806. }
  1807. //
  1808. // Snaps the partitions in the list pRecord to cylinder boundaries, using the
  1809. // disk geometry from HardDisks[PhysicalIndex].
  1810. //
  1811. // This should only be called for MBR partitions, though it should work for GPT
  1812. // partitions as well.
  1813. //
  1814. //
  1815. ULONGLONG
  1816. CylinderAlignPartitions(
  1817. IN ULONG PhysicalIndex,
  1818. IN PSIF_PARTITION_RECORD pFirst
  1819. )
  1820. {
  1821. ULONGLONG endSector = 0,
  1822. logicalDisksNeed = 0;
  1823. PSIF_PARTITION_RECORD pRecord = pFirst;
  1824. //
  1825. // First, figure out how much the logical disks need. The container
  1826. // partition must be big enough to hold these.
  1827. //
  1828. while (pRecord) {
  1829. if (pRecord->IsLogicalDiskRecord) {
  1830. logicalDisksNeed += SpPtAlignStart(
  1831. &HardDisks[PhysicalIndex],
  1832. pRecord->SectorCount,
  1833. TRUE
  1834. );
  1835. }
  1836. pRecord = pRecord->Next;
  1837. }
  1838. //
  1839. // Next, calculate how much the primary partitions and the container need.
  1840. //
  1841. pRecord = pFirst;
  1842. while (pRecord) {
  1843. if (pRecord->IsPrimaryRecord) {
  1844. endSector += SpPtAlignStart(&HardDisks[PhysicalIndex],
  1845. pRecord->SectorCount,
  1846. TRUE
  1847. );
  1848. }
  1849. else if (pRecord->IsContainerRecord) {
  1850. //
  1851. // The container partition must be at least as big as the logical
  1852. // drives inside it.
  1853. //
  1854. ULONGLONG ContainerNeeds = SpPtAlignStart(&HardDisks[PhysicalIndex],
  1855. pRecord->SectorCount,
  1856. TRUE
  1857. );
  1858. endSector += ((logicalDisksNeed > ContainerNeeds) ? logicalDisksNeed : ContainerNeeds);
  1859. }
  1860. pRecord = pRecord->Next;
  1861. }
  1862. return endSector;
  1863. }
  1864. VOID
  1865. SpAsrAssignPartitionSet(
  1866. IN ULONG PhysicalDisk,
  1867. IN ULONG SifDisk,
  1868. IN CONST BOOLEAN IsAligned
  1869. )
  1870. {
  1871. PDISK_PARTITION_SET pSet = NULL;
  1872. PSIF_PARTITION_RECORD pRec = NULL;
  1873. //
  1874. // Ensure that the partition set isn't already assigned. This is
  1875. // a serious enough problem to report a fatal internal error if
  1876. // it happens.
  1877. //
  1878. if (Gbl_PartitionSetTable1[PhysicalDisk]) {
  1879. DbgFatalMesg((_asrerr,
  1880. "SpAsrAssignPartitionSet. SifDisk Index %lu: Gbl_PartitionSetTable1[%lu] already assigned.\n",
  1881. SifDisk,
  1882. PhysicalDisk
  1883. ));
  1884. swprintf(
  1885. TemporaryBuffer,
  1886. L"SifDisk Index %lu - Gbl_PartitionSetTable1[%lu] already assigned.",
  1887. SifDisk, PhysicalDisk
  1888. );
  1889. INTERNAL_ERROR(TemporaryBuffer); // ok
  1890. // does not return
  1891. }
  1892. //
  1893. // Assign the partition set
  1894. //
  1895. pSet = SpAsrMemAlloc(sizeof(DISK_PARTITION_SET), TRUE);
  1896. pSet->pDiskRecord = Gbl_SifDiskTable[SifDisk];
  1897. pSet->pDiskRecord->Assigned = TRUE;
  1898. pSet->pDiskRecord->pSetRecord = pSet;
  1899. pSet->PartitionStyle = pSet->pDiskRecord->PartitionStyle;
  1900. if (PARTITION_STYLE_MBR == pSet->PartitionStyle) {
  1901. pSet->ActualDiskSignature = pSet->pDiskRecord->SifDiskMbrSignature;
  1902. }
  1903. pSet->ActualDiskSizeMB = DISK_SIZE_MB(PhysicalDisk);
  1904. pSet->PartitionsIntact = FALSE;
  1905. pSet->IsReplacementDisk = TRUE;
  1906. pSet->NtPartitionKey = NULL;
  1907. pSet->Index = PhysicalDisk;
  1908. pSet->IsAligned = IsAligned;
  1909. //
  1910. // Check for boot or system partitions
  1911. //
  1912. if (pSet->pDiskRecord->PartitionList) {
  1913. pRec = pSet->pDiskRecord->PartitionList->First;
  1914. while (pRec) {
  1915. if (SpAsrIsBootPartitionRecord(pRec->PartitionFlag)) {
  1916. pSet->NtPartitionKey = pRec->CurrPartKey;
  1917. ASSERT(pSet->pDiskRecord->ContainsNtPartition);
  1918. // pSet->pDiskRecord->ContainsNtPartition = TRUE; // should've already been set
  1919. }
  1920. if (SpAsrIsSystemPartitionRecord(pRec->PartitionFlag)) {
  1921. ASSERT(pSet->pDiskRecord->ContainsSystemPartition); // should've already been set
  1922. }
  1923. pRec = pRec->Next;
  1924. }
  1925. //
  1926. // Cylinder align the partitions.
  1927. //
  1928. Gbl_SifDiskTable[SifDisk]->LastUsedAlignedSector = CylinderAlignPartitions(
  1929. PhysicalDisk,
  1930. Gbl_SifDiskTable[SifDisk]->PartitionList->First
  1931. );
  1932. }
  1933. else {
  1934. Gbl_SifDiskTable[SifDisk]->LastUsedAlignedSector = 0;
  1935. }
  1936. Gbl_PartitionSetTable1[PhysicalDisk] = pSet;
  1937. Gbl_PartitionSetCount += 1;
  1938. }
  1939. //
  1940. // We only extend FAT32, NTFS and Container partitions. We don't extend
  1941. // FAT or unknown (including LDM) partitions
  1942. //
  1943. BOOLEAN
  1944. IsExtendable(UCHAR PartitionType)
  1945. {
  1946. switch (PartitionType) {
  1947. case PARTITION_EXTENDED:
  1948. case PARTITION_IFS:
  1949. case PARTITION_XINT13:
  1950. case PARTITION_XINT13_EXTENDED:
  1951. return TRUE;
  1952. }
  1953. if (IsContainerPartition(PartitionType)) {
  1954. return TRUE;
  1955. }
  1956. return FALSE;
  1957. }
  1958. //
  1959. // Will resize (extend) the last partition on the disk if there is free space
  1960. // at the end (and there was no free space at the end of the original disk).
  1961. // The last partition must be FAT32 or NTFS--we don't extend FAT or unknown
  1962. // partitions. This routine also extends any container partitions that
  1963. // contained the last partition.
  1964. //
  1965. BOOLEAN
  1966. SpAsrAutoExtendDiskPartition(
  1967. IN ULONG PhysicalIndex,
  1968. IN ULONG SifIndex
  1969. )
  1970. {
  1971. ULONGLONG oldFreeSpace = 0,
  1972. newEndSector = 0,
  1973. newEndOfDisk = 0,
  1974. extraSpace = 0;
  1975. BOOLEAN didAnExtend = FALSE;
  1976. DWORD bytesPerSector = Gbl_SifDiskTable[SifIndex]->BytesPerSector;
  1977. PSIF_PARTITION_RECORD pPtnRecord = NULL;
  1978. //
  1979. // We won't extend GPT partitions
  1980. //
  1981. if (PARTITION_STYLE_MBR != Gbl_SifDiskTable[SifIndex]->PartitionStyle) {
  1982. return FALSE;
  1983. }
  1984. //
  1985. // Check if there was free space at the end of the original disk
  1986. //
  1987. oldFreeSpace = (Gbl_SifDiskTable[SifIndex]->TotalSectors -
  1988. Gbl_SifDiskTable[SifIndex]->LastUsedSector) *
  1989. bytesPerSector;
  1990. if ((oldFreeSpace > ASR_FREE_SPACE_FUDGE_FACTOR_BYTES) || // free space at the end of old disk
  1991. (!Gbl_AutoExtend) || // auto-extend is disabled in the sif
  1992. (!Gbl_SifDiskTable[SifIndex]->PartitionList)) { // no partitions on disk
  1993. return FALSE;
  1994. }
  1995. //
  1996. // We can auto-extend. Check how many free sectors are available at the end of
  1997. // the new disk.
  1998. //
  1999. newEndSector = Gbl_SifDiskTable[SifIndex]->LastUsedAlignedSector;
  2000. //
  2001. // Find the last cylinder boundary that we can use. This is usually the last cylinder
  2002. // boundary on the disk. The only exception is when the "fall off sectors" after the
  2003. // end of the last cylinder boundary are less than the 1 MB needed for LDM private region.
  2004. //
  2005. newEndOfDisk = HardDisks[PhysicalIndex].SectorsPerCylinder *
  2006. HardDisks[PhysicalIndex].Geometry.Cylinders.QuadPart;
  2007. if (((newEndOfDisk - Gbl_PhysicalDiskInfo[PhysicalIndex].TrueDiskSize) * BYTES_PER_SECTOR(PhysicalIndex))
  2008. < ASR_LDM_RESERVED_SPACE_BYTES) {
  2009. newEndOfDisk -= HardDisks[PhysicalIndex].SectorsPerCylinder;
  2010. }
  2011. extraSpace = newEndOfDisk - newEndSector;
  2012. //
  2013. // Go through all the partitions, and for partitions that end on the newEndSector,
  2014. // add the extra space to their SectorCounts.
  2015. //
  2016. pPtnRecord = Gbl_SifDiskTable[SifIndex]->PartitionList->First;
  2017. while (pPtnRecord) {
  2018. if (((pPtnRecord->StartSector) + (pPtnRecord->SectorCount) == newEndSector)
  2019. && (IsExtendable(pPtnRecord->PartitionType))) {
  2020. didAnExtend = TRUE;
  2021. pPtnRecord->SectorCount += extraSpace;
  2022. pPtnRecord->SizeMB = SpAsrConvertSectorsToMB(pPtnRecord->SectorCount, bytesPerSector);
  2023. }
  2024. pPtnRecord = pPtnRecord->Next;
  2025. }
  2026. return didAnExtend;
  2027. }
  2028. VOID
  2029. SpAsrSystemWasDataWarning()
  2030. /*++
  2031. Routine Description:
  2032. Display a screen warning the user that his current system
  2033. disk used to be a data disk that we recognise and will
  2034. destroy, and allow him to abort
  2035. Arguments:
  2036. None.
  2037. Return Value:
  2038. None.
  2039. --*/
  2040. {
  2041. ULONG warningKeys[] = {KEY_F3, ASCI_CR, 0};
  2042. ULONG mnemonicKeys[] = {0};
  2043. BOOLEAN done = FALSE;
  2044. //
  2045. // We currently display a list of disks that will be repartitioned
  2046. // anyway.
  2047. //
  2048. return;
  2049. /*
  2050. // put this back in user\msg.mc if reactivating this bit of code.
  2051. MessageId=12429 SymbolicName=SP_SCRN_DR_SYSTEM_DISK_WAS_DATA_DISK
  2052. Language=English
  2053. The current system disk used to be a data disk.
  2054. To continue, press Enter
  2055. To quit Setup, press F3. No changes will be
  2056. made to any of the disks on the system.
  2057. .
  2058. do {
  2059. // display the warning message
  2060. SpDisplayScreen(SP_SCRN_DR_SYSTEM_DISK_WAS_DATA_DISK,3,4);
  2061. SpDisplayStatusOptions(DEFAULT_STATUS_ATTRIBUTE,
  2062. SP_STAT_ENTER_EQUALS_CONTINUE,
  2063. SP_STAT_F3_EQUALS_EXIT,
  2064. 0
  2065. );
  2066. // wait for keypress. Valid keys:
  2067. // ENTER = continue
  2068. // F3 = exit
  2069. SpInputDrain();
  2070. switch(SpWaitValidKey(warningKeys,NULL,mnemonicKeys)) {
  2071. case KEY_F3:
  2072. // User wants to exit.
  2073. SpConfirmExit();
  2074. break;
  2075. case ASCI_CR:
  2076. // User wants to continue.
  2077. done = TRUE;
  2078. break;
  2079. }
  2080. } while (!done);
  2081. */
  2082. }
  2083. //
  2084. // This assigns a disk based on signature (for MBR disks) or diskId (for GPT disks)
  2085. //
  2086. //
  2087. VOID
  2088. SpAsrAssignDisksBySignature(DWORD PhysicalSystemIndex)
  2089. {
  2090. ULONG index =0,
  2091. sifIndex = 0,
  2092. physicalIndex = 0,
  2093. numDiskRecords = 0,
  2094. diskSignature = 0;
  2095. BOOLEAN done = FALSE,
  2096. matchFound = FALSE,
  2097. IsAligned = TRUE;
  2098. WCHAR physicalDiskGuid[MAX_PATH + 1];
  2099. numDiskRecords = SpAsrGetDiskRecordCount();
  2100. //
  2101. // Loop through the list of sif disks, and attempt to find a
  2102. // physical disk with the same signature.
  2103. //
  2104. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2105. if (
  2106. ((PARTITION_STYLE_MBR == Gbl_SifDiskTable[sifIndex]->PartitionStyle) &&
  2107. !(Gbl_SifDiskTable[sifIndex]->SifDiskMbrSignature)) ||
  2108. ((PARTITION_STYLE_GPT == Gbl_SifDiskTable[sifIndex]->PartitionStyle) &&
  2109. SpAsrIsZeroGuid(&(Gbl_SifDiskTable[sifIndex]->SifDiskGptId)))
  2110. ) {
  2111. //
  2112. // Skip GPT disks that have no ID, and MBR disks that have no signature
  2113. //
  2114. continue;
  2115. }
  2116. if (Gbl_SifDiskTable[sifIndex]->ContainsSystemPartition) {
  2117. //
  2118. // The system disk would have already been assigned
  2119. //
  2120. ASSERT(Gbl_SifDiskTable[sifIndex]->Assigned && L"System disk should be assigned");
  2121. }
  2122. done = FALSE;
  2123. for (physicalIndex = 0; (physicalIndex < HardDiskCount) && (!done); physicalIndex++) {
  2124. matchFound = FALSE;
  2125. if (DISK_IS_REMOVABLE(physicalIndex)) {
  2126. continue;
  2127. }
  2128. if (Gbl_SifDiskTable[sifIndex]->PartitionStyle !=
  2129. (PARTITION_STYLE) HardDisks[physicalIndex].DriveLayout.PartitionStyle
  2130. ) {
  2131. //
  2132. // The sif disk's MBR, and the physical disk's GPT, or vice-versa.
  2133. //
  2134. continue;
  2135. }
  2136. if (PARTITION_STYLE_MBR == Gbl_SifDiskTable[sifIndex]->PartitionStyle) {
  2137. diskSignature = SpAsrGetActualDiskSignature(physicalIndex);
  2138. if (!diskSignature) {
  2139. //
  2140. // we won't assign disks with no signature here
  2141. //
  2142. continue;
  2143. }
  2144. if (diskSignature == Gbl_SifDiskTable[sifIndex]->SifDiskMbrSignature) {
  2145. if (Gbl_PartitionSetTable1[physicalIndex]) {
  2146. //
  2147. // The signatures match, but this physical-disk has already
  2148. // been assigned. This can be because this physical disk is
  2149. // the current system disk, or (!) there were duplicate
  2150. // signatures.
  2151. //
  2152. if (Gbl_PartitionSetTable1[physicalIndex]->pDiskRecord &&
  2153. Gbl_PartitionSetTable1[physicalIndex]->pDiskRecord->ContainsSystemPartition) {
  2154. if (PhysicalSystemIndex == physicalIndex) {
  2155. //
  2156. // This is the original system disk
  2157. //
  2158. Gbl_PartitionSetTable1[physicalIndex]->IsReplacementDisk = FALSE;
  2159. }
  2160. else {
  2161. //
  2162. // We recognise the physical disk to be some other data
  2163. // disk in the original system.
  2164. //
  2165. SpAsrSystemWasDataWarning();
  2166. }
  2167. }
  2168. else {
  2169. ASSERT(0 && L"Disk already assigned");
  2170. }
  2171. continue;
  2172. }
  2173. //
  2174. // We found a disk with matching signatures
  2175. //
  2176. matchFound = TRUE;
  2177. }
  2178. }
  2179. else if (PARTITION_STYLE_GPT == Gbl_SifDiskTable[sifIndex]->PartitionStyle) {
  2180. if (!memcmp(&(HardDisks[physicalIndex].DriveLayout.Gpt.DiskId),
  2181. &(Gbl_SifDiskTable[sifIndex]->SifDiskGptId),
  2182. sizeof(GUID)
  2183. )) {
  2184. if (Gbl_PartitionSetTable1[physicalIndex]) {
  2185. //
  2186. // The signatures match, but this physical-disk has already
  2187. // been assigned. This can be because this physical disk is
  2188. // the current system disk, or (!) there were duplicate
  2189. // signatures.
  2190. //
  2191. if (Gbl_PartitionSetTable1[physicalIndex]->pDiskRecord &&
  2192. Gbl_PartitionSetTable1[physicalIndex]->pDiskRecord->ContainsSystemPartition) {
  2193. if (PhysicalSystemIndex == physicalIndex) {
  2194. Gbl_PartitionSetTable1[physicalIndex]->IsReplacementDisk = FALSE;
  2195. }
  2196. else {
  2197. //
  2198. // We recognise the physical disk to be some other data
  2199. // disk in the original system.
  2200. //
  2201. SpAsrSystemWasDataWarning();
  2202. }
  2203. }
  2204. else {
  2205. ASSERT(0 && L"Disk already assigned");
  2206. }
  2207. continue;
  2208. }
  2209. //
  2210. // We found a disk with matching signatures
  2211. //
  2212. matchFound = TRUE;
  2213. }
  2214. }
  2215. if (matchFound) {
  2216. //
  2217. // Make sure it fits (!)
  2218. //
  2219. if (SpAsrDoesListFitOnDisk(Gbl_SifDiskTable[sifIndex], physicalIndex, &IsAligned)) {
  2220. SpAsrAssignPartitionSet(physicalIndex, sifIndex, IsAligned);
  2221. //
  2222. // Will not auto-extend disks that match by signature
  2223. //
  2224. //
  2225. // The signatures match, so we assume it's original (may not be
  2226. // intact, but it's the original)
  2227. //
  2228. Gbl_PartitionSetTable1[physicalIndex]->IsReplacementDisk = FALSE;
  2229. DbgStatusMesg((_asrinfo, "Partition list %lu assigned to disk %lu (assign by signature).\n",
  2230. sifIndex,
  2231. physicalIndex
  2232. ));
  2233. }
  2234. else {
  2235. DbgStatusMesg((_asrerr, "Disk signatures match, but partitions don't fit! Partition list %lu, disk %lu. Not assigned\n",
  2236. sifIndex,
  2237. physicalIndex
  2238. ));
  2239. }
  2240. done = TRUE;
  2241. }
  2242. }
  2243. }
  2244. } // SpAsrAssignDisksBySignature
  2245. //
  2246. // Checks if the partition list fits on the disk. In addition to checking
  2247. // the total sizeSectors of the disk and the SectorCount of the partition list,
  2248. // we also need to try and "lay out" the partitions on the disk to make sure
  2249. // that they fit--because of different disk geometries and the requirement that
  2250. // partitions must be cylinder-aligned, we may have a list that doesn't fit on
  2251. // a disk even if the total sectors it requires is less than the sectors on the
  2252. // disk
  2253. //
  2254. BOOLEAN
  2255. SpAsrDoesListFitOnDisk(
  2256. IN PSIF_DISK_RECORD pSifDisk,
  2257. IN ULONG DiskIndex,
  2258. OUT BOOLEAN *IsAligned
  2259. )
  2260. {
  2261. ULONGLONG endSector = 0;
  2262. PSIF_PARTITION_RECORD_LIST pList = NULL;
  2263. BOOLEAN tryNoAlign = FALSE;
  2264. if ((DWORD)(-1) == DiskIndex) {
  2265. return FALSE;
  2266. }
  2267. if (!(pSifDisk && pSifDisk->PartitionList)) {
  2268. return TRUE;
  2269. }
  2270. ASSERT(pSifDisk && pSifDisk->PartitionList);
  2271. pList = pSifDisk->PartitionList;
  2272. *IsAligned = FALSE;
  2273. //
  2274. // Requirement 1. The replacement disk must have at least as many
  2275. // "true" sectors as the original disk. This is a little more
  2276. // restrictive than is absolutely required, but it somewhat simplifies
  2277. // the LDM requirement of making sure we have enough cylinders to create
  2278. // the LDM private database at the end.
  2279. //
  2280. if (pList->DiskSectorCount > Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize) {
  2281. DbgStatusMesg((_asrinfo,
  2282. "Original Disk sector count %I64u, Current Disk %lu true sector count %I64u. Not big enough\n",
  2283. pList->DiskSectorCount, DiskIndex, Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize
  2284. ));
  2285. return FALSE;
  2286. }
  2287. //
  2288. // Requirement 2:
  2289. //
  2290. // "If the replacement disk has a different geometry, ASR will cylinder-
  2291. // align the partitions--this may result in some partitions being marginally
  2292. // bigger than they used to be. The requirement in this case is that the
  2293. // replacement disk must have at least as many true sectors as the original
  2294. // disk, plus the number of sectors required to cylinder-align all
  2295. // partitions."
  2296. //
  2297. //
  2298. //
  2299. // Cylinder-align the partitions
  2300. //
  2301. endSector = CylinderAlignPartitions(DiskIndex, pList->First);
  2302. *IsAligned = TRUE;
  2303. //
  2304. // And make sure that the space at the end is at least as much as it
  2305. // used to be
  2306. //
  2307. if ((pList->DiskSectorCount - pList->LastUsedSector)
  2308. > (Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize - endSector)) {
  2309. DbgStatusMesg((_asrinfo,
  2310. "List->DiskSectorCount: %I64u, LastUsedSector:%I64u, Disk->TrueDiskSize: %I64u, EndSector: %I64u. Not big enough\n",
  2311. pList->DiskSectorCount, pList->LastUsedSector, Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize, endSector
  2312. ));
  2313. tryNoAlign = TRUE;
  2314. }
  2315. if (endSector > Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize) {
  2316. DbgStatusMesg((_asrinfo,
  2317. "List->DiskSectorCount: %I64u, Disk->TrueDiskSize: %I64u < EndSector: %I64u. Not big enough\n",
  2318. pList->DiskSectorCount, Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize, endSector
  2319. ));
  2320. tryNoAlign = TRUE;
  2321. }
  2322. if (tryNoAlign) {
  2323. //
  2324. // We couldn't fit the partitions on the disk after cylinder-aligning
  2325. // them. If the disk has the exact same geometry as it used to, we
  2326. // can try to fit the partitions on it without cylinder aligning them.
  2327. //
  2328. if ((pSifDisk->BytesPerSector == HardDisks[DiskIndex].Geometry.BytesPerSector) &&
  2329. (pSifDisk->SectorsPerTrack == HardDisks[DiskIndex].Geometry.SectorsPerTrack) &&
  2330. (pSifDisk->TracksPerCylinder == HardDisks[DiskIndex].Geometry.TracksPerCylinder)
  2331. ) {
  2332. //
  2333. // The geometries are the same. We don't really need to *check*
  2334. // if the partitions will fit, since we already know that the disk
  2335. // is large enough to hold them (we checked the sector count above)
  2336. //
  2337. *IsAligned = FALSE;
  2338. return TRUE;
  2339. }
  2340. //
  2341. // The partitions didn't fit, and the disk has a different geometry.
  2342. // Oh well.
  2343. //
  2344. return FALSE;
  2345. }
  2346. //
  2347. // This disk is okay to hold this list
  2348. //
  2349. DbgStatusMesg((_asrinfo,
  2350. "List->DiskSectorCount: %I64u, LastUsedSector: %I64u, Disk->TrueDiskSize: %I64u, EndSector: %I64u. Disk okay.\n",
  2351. pList->DiskSectorCount, pList->LastUsedSector, Gbl_PhysicalDiskInfo[DiskIndex].TrueDiskSize, endSector
  2352. ));
  2353. return TRUE;
  2354. }
  2355. BOOLEAN
  2356. SpAsrIsThisDiskABetterFit(
  2357. IN DWORD CurrentBest,
  2358. IN DWORD PhysicalIndex,
  2359. IN DWORD SifIndex,
  2360. OUT BOOLEAN *IsAligned
  2361. )
  2362. {
  2363. if ((CurrentBest == HardDiskCount) ||
  2364. (DISK_SIZE_MB(PhysicalIndex) < DISK_SIZE_MB(CurrentBest))) {
  2365. if ((!DISK_IS_REMOVABLE(PhysicalIndex)) &&
  2366. (BYTES_PER_SECTOR(PhysicalIndex) == (Gbl_SifDiskTable[SifIndex]->BytesPerSector)) &&
  2367. SpAsrDoesListFitOnDisk(Gbl_SifDiskTable[SifIndex], PhysicalIndex, IsAligned)) {
  2368. return TRUE;
  2369. }
  2370. }
  2371. return FALSE;
  2372. }
  2373. //
  2374. // Attempts to assign remaining sif disks to physical disks that
  2375. // are on the same bus as the sif disk originally was (ie if
  2376. // any other disk on that bus has been assigned, this tries to assign
  2377. // this disk to the same bus)
  2378. //
  2379. VOID
  2380. SpAsrAssignCriticalDisksByBus()
  2381. {
  2382. DWORD sifIndex = 0,
  2383. sifIndex2 = 0,
  2384. physicalIndex = 0,
  2385. currentBest = 0,
  2386. targetBusId = 0,
  2387. numDiskRecords = 0;
  2388. BOOLEAN done = FALSE,
  2389. isAligned = FALSE,
  2390. isAlignedTemp = FALSE;
  2391. //
  2392. // Loop through the list of sif disks, and for each disk that
  2393. // hasn't been assigned yet, attempt to find a sif-disk "X" that used
  2394. // to be on the same bus, and has been assigned. Then, attempt
  2395. // to find other disks on the same physical bus that X is on.
  2396. //
  2397. numDiskRecords = SpAsrGetDiskRecordCount();
  2398. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2399. //
  2400. // Skip sif-disks that have already been assigned, and
  2401. // disks for which we don't have any bus info in the
  2402. // sif file
  2403. //
  2404. if ((!Gbl_SifDiskTable[sifIndex]->IsCritical) || // not critical
  2405. (!Gbl_SifDiskTable[sifIndex]->PartitionList) || // no partitions
  2406. (Gbl_SifDiskTable[sifIndex]->Assigned) || // assigned
  2407. !(Gbl_SifDiskTable[sifIndex]->BusKey)) { // no bus info
  2408. continue;
  2409. }
  2410. //
  2411. // Find another (sif) disk that used to be on the same (sif) bus,
  2412. // and has already been assigned to a physical disk.
  2413. //
  2414. targetBusId = 0;
  2415. done = FALSE;
  2416. for (sifIndex2 = 0; (sifIndex2 < numDiskRecords) && (!done); sifIndex2++) {
  2417. if ((Gbl_SifDiskTable[sifIndex2]->BusKey == Gbl_SifDiskTable[sifIndex]->BusKey) // same bus
  2418. && (Gbl_SifDiskTable[sifIndex2]->pSetRecord)) { // assigned
  2419. ULONG index = Gbl_SifDiskTable[sifIndex2]->pSetRecord->Index; // set when disk was assigned
  2420. targetBusId = Gbl_PhysicalDiskInfo[index].BusKey; // the physical bus
  2421. //
  2422. // If this physical disk is on an unknown bus,
  2423. // (target id = sifbuskey = 0) then we want to try and look
  2424. // for another disk on the same (sif) bus. Hence done is
  2425. // TRUE only if targetId != 0
  2426. //
  2427. if (targetBusId) {
  2428. done = TRUE;
  2429. }
  2430. }
  2431. } // for sifIndex2
  2432. if (targetBusId) { // we found another disk on the same sif bus
  2433. //
  2434. // Go through the physical disks on the same bus, and try to
  2435. // find the best fit for this disk. Best fit is the smallest
  2436. // disk on the bus that's big enough for us.
  2437. //
  2438. currentBest = HardDiskCount;
  2439. for (physicalIndex = 0; physicalIndex < HardDiskCount; physicalIndex++) {
  2440. if ((NULL == Gbl_PartitionSetTable1[physicalIndex]) && // not assigned
  2441. (Gbl_PhysicalDiskInfo[physicalIndex].BusKey == targetBusId) && // same bus
  2442. (SpAsrIsThisDiskABetterFit(currentBest, physicalIndex, sifIndex, &isAlignedTemp))) {
  2443. isAligned = isAlignedTemp;
  2444. currentBest = physicalIndex;
  2445. }
  2446. }
  2447. if (currentBest < HardDiskCount) { // we found a match
  2448. //
  2449. // Assign the disks, and extend the last partition if needed.
  2450. //
  2451. SpAsrAssignPartitionSet(currentBest, sifIndex, isAligned);
  2452. SpAsrAutoExtendDiskPartition(currentBest, sifIndex);
  2453. DbgStatusMesg((_asrinfo, "Partition list %lu assigned to disk %lu (assign by bus).\n",
  2454. sifIndex,
  2455. currentBest
  2456. ));
  2457. }
  2458. }
  2459. } // for sifIndex
  2460. }
  2461. //
  2462. // Attempts to assign remaining sif disks to physical disks that
  2463. // are on any bus of the same type (SCSI, IDE, etc) as the sif disk
  2464. // originally was
  2465. //
  2466. VOID
  2467. SpAsrAssignCriticalDisksByBusType()
  2468. {
  2469. DWORD sifIndex = 0,
  2470. physicalIndex = 0,
  2471. currentBest = 0,
  2472. numDiskRecords = 0;
  2473. BOOLEAN done = FALSE,
  2474. isAligned = FALSE,
  2475. isAlignedTemp = FALSE;
  2476. numDiskRecords = SpAsrGetDiskRecordCount();
  2477. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2478. //
  2479. // Skip sif-disks that have already been assigned, and
  2480. // disks for which we don't have any bus info in the
  2481. // sif file
  2482. //
  2483. if ((!Gbl_SifDiskTable[sifIndex]->IsCritical) || // not critical
  2484. (!Gbl_SifDiskTable[sifIndex]->PartitionList) || // no partitions
  2485. (Gbl_SifDiskTable[sifIndex]->Assigned) || // assigned
  2486. (BusTypeUnknown == Gbl_SifDiskTable[sifIndex]->BusType)) { // no bus info
  2487. continue;
  2488. }
  2489. //
  2490. // Go through the physical disks, and try to
  2491. // find the best fit for this disk. Best fit is the smallest
  2492. // disk on any bus of the same bus type that's big enough for us.
  2493. //
  2494. currentBest = HardDiskCount;
  2495. for (physicalIndex = 0; physicalIndex < HardDiskCount; physicalIndex++) {
  2496. if ((NULL == Gbl_PartitionSetTable1[physicalIndex]) && // not assigned
  2497. (Gbl_PhysicalDiskInfo[physicalIndex].BusType == Gbl_SifDiskTable[sifIndex]->BusType) && // same bus
  2498. (SpAsrIsThisDiskABetterFit(currentBest, physicalIndex, sifIndex, &isAlignedTemp))) {
  2499. isAligned = isAlignedTemp;
  2500. currentBest = physicalIndex;
  2501. }
  2502. }
  2503. if (currentBest < HardDiskCount) { // we found a match
  2504. //
  2505. // Assign the disks, and extend the last partition if needed.
  2506. //
  2507. SpAsrAssignPartitionSet(currentBest, sifIndex, isAligned);
  2508. SpAsrAutoExtendDiskPartition(currentBest, sifIndex);
  2509. DbgStatusMesg((_asrinfo, "Partition list %lu assigned to disk %lu (assign by bus type).\n",
  2510. sifIndex,
  2511. currentBest
  2512. ));
  2513. //
  2514. // Now call AssignByBus again
  2515. //
  2516. SpAsrAssignCriticalDisksByBus();
  2517. }
  2518. } // for sifIndex
  2519. }
  2520. //
  2521. // Okay, so by now we've tried putting disks on the same bus, and
  2522. // the same bus type. For disks that didn't fit using either of those
  2523. // rules (or for whom we didn't have any bus info at all), let's just
  2524. // try to fit them where ever possible on the system.
  2525. //
  2526. BOOL
  2527. SpAsrAssignRemainingCriticalDisks(VOID)
  2528. {
  2529. DWORD sifIndex = 0,
  2530. physicalIndex = 0,
  2531. currentBest = 0,
  2532. numDiskRecords = 0;
  2533. BOOLEAN done = FALSE,
  2534. isAligned = FALSE,
  2535. isAlignedTemp = FALSE;
  2536. numDiskRecords = SpAsrGetDiskRecordCount();
  2537. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2538. //
  2539. // Skip sif-disks that have already been assigned
  2540. //
  2541. if ((!Gbl_SifDiskTable[sifIndex]->IsCritical) || // not critical
  2542. (!Gbl_SifDiskTable[sifIndex]->PartitionList) || // no partitions
  2543. (Gbl_SifDiskTable[sifIndex]->Assigned)) { // already assigned
  2544. continue;
  2545. }
  2546. //
  2547. // Go through the physical disks, and try to find the best
  2548. // fit for this disk. Best fit is the smallest disk anywhere
  2549. // on the system that's big enough for us.
  2550. //
  2551. currentBest = HardDiskCount;
  2552. for (physicalIndex = 0; physicalIndex < HardDiskCount; physicalIndex++) {
  2553. if ((NULL == Gbl_PartitionSetTable1[physicalIndex]) && // not assigned
  2554. (SpAsrIsThisDiskABetterFit(currentBest, physicalIndex, sifIndex, &isAlignedTemp))) {
  2555. isAligned = isAlignedTemp;
  2556. currentBest = physicalIndex;
  2557. }
  2558. }
  2559. if (currentBest < HardDiskCount) { // we found a match
  2560. //
  2561. // Assign the disks, and extend the last partition if needed.
  2562. //
  2563. SpAsrAssignPartitionSet(currentBest, sifIndex, isAligned);
  2564. SpAsrAutoExtendDiskPartition(currentBest, sifIndex);
  2565. DbgStatusMesg((_asrinfo, "Partition list %lu assigned to disk %lu (assign by size).\n",
  2566. sifIndex,
  2567. currentBest
  2568. ));
  2569. SpAsrAssignCriticalDisksByBus();
  2570. SpAsrAssignCriticalDisksByBusType();
  2571. }
  2572. } // for sifIndex
  2573. //
  2574. // There should be no unassigned critical disks at this point
  2575. //
  2576. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2577. if ((Gbl_SifDiskTable[sifIndex]->IsCritical) &&
  2578. (Gbl_SifDiskTable[sifIndex]->PartitionList) &&
  2579. (!Gbl_SifDiskTable[sifIndex]->Assigned)) {
  2580. return FALSE;
  2581. }
  2582. }
  2583. return TRUE;
  2584. }
  2585. VOID
  2586. SpAsrInitInternalData(VOID)
  2587. {
  2588. SpAsrInitSifDiskTable();
  2589. SpAsrAllocateGblPartitionSetTable();
  2590. SpAsrInitPhysicalDiskInfo();
  2591. }
  2592. VOID
  2593. SpAsrFreeSifData(VOID)
  2594. {
  2595. ULONG numDiskRecords;
  2596. ULONG diskIndex;
  2597. // SpAsrUnassignPartitionSets(TRUE);
  2598. numDiskRecords = SpAsrGetDiskRecordCount();
  2599. for (diskIndex = 0; diskIndex < numDiskRecords; diskIndex++) {
  2600. SpAsrFreePartitionDisk(Gbl_SifDiskTable[diskIndex]);
  2601. }
  2602. }
  2603. DWORD
  2604. SpAsrGetCurrentSystemDiskNumber(
  2605. IN PWSTR SetupSourceDevicePath,
  2606. IN PWSTR DirectoryOnSetupSource
  2607. )
  2608. {
  2609. DWORD physicalIndex = (DWORD) (-1);
  2610. //
  2611. // Get the index of the current (physical) system disk
  2612. //
  2613. /* (guhans, 10.May.2001) Turns out that SpDetermineDisk0 should work on
  2614. IA-64 as well.
  2615. if (SpIsArc()) {
  2616. PDISK_REGION systemPartitionArea = NULL;
  2617. systemPartitionArea = SpPtnValidSystemPartitionArc(Gbl_SifHandle,
  2618. SetupSourceDevicePath,
  2619. DirectoryOnSetupSource,
  2620. FALSE
  2621. );
  2622. if (systemPartitionArea) {
  2623. physicalIndex = systemPartitionArea->DiskNumber;
  2624. }
  2625. }
  2626. else {
  2627. */
  2628. physicalIndex = SpDetermineDisk0();
  2629. // }
  2630. return physicalIndex;
  2631. }
  2632. //
  2633. // This goes through the list of physical disks, and checks which disk
  2634. // is marked as the system disk. It then assigns the system-disk in the
  2635. // sif file to the current disk.
  2636. //
  2637. // If the current system disk isn't "compatible" with the sif-system-disk
  2638. // (ie it isn't big enough, it doesn't have the same bytes-per-sector),
  2639. // it's a fatal error.
  2640. //
  2641. // If the current system disk is recognised as a data disk that used to
  2642. // exist in the sif-file, a warning is displayed to the user
  2643. //
  2644. VOID
  2645. SpAsrAssignSystemDisk(
  2646. IN DWORD CurrentPhysicalSystemDisk
  2647. )
  2648. {
  2649. DWORD sifIndex = 0,
  2650. numDiskRecords = 0;
  2651. BOOLEAN isAligned = FALSE;
  2652. numDiskRecords = SpAsrGetMbrDiskRecordCount() + SpAsrGetGptDiskRecordCount();
  2653. //
  2654. // Find the index of the system-disk in the sif
  2655. //
  2656. for (sifIndex = 0; sifIndex < numDiskRecords; sifIndex++) {
  2657. if (Gbl_SifDiskTable[sifIndex]->ContainsSystemPartition) {
  2658. break;
  2659. }
  2660. }
  2661. if (SpAsrIsThisDiskABetterFit(HardDiskCount, CurrentPhysicalSystemDisk, sifIndex, &isAligned)) {
  2662. SpAsrAssignPartitionSet(CurrentPhysicalSystemDisk, sifIndex, isAligned);
  2663. DbgStatusMesg((_asrinfo, "Partition list %lu assigned to disk %lu (system disk).\n",
  2664. sifIndex,
  2665. CurrentPhysicalSystemDisk
  2666. ));
  2667. }
  2668. else {
  2669. //
  2670. // Fatal Error
  2671. //
  2672. DbgErrorMesg((_asrerr,
  2673. "Current sytem disk smaller than original system disk. Curr:%lu sifIndex:%lu\n" ,
  2674. CurrentPhysicalSystemDisk,
  2675. sifIndex
  2676. ));
  2677. ASSERT(0 && L"Current sytem disk smaller than original system disk");
  2678. SpAsrRaiseFatalError(
  2679. SP_SCRN_DR_SYSTEM_DISK_TOO_SMALL,
  2680. L"The current system disk is too small to hold the partitions"
  2681. );
  2682. }
  2683. }
  2684. VOID
  2685. SpAsrCreatePartitionSets(
  2686. IN PWSTR SetupSourceDevicePath,
  2687. IN PWSTR DirectoryOnSetupSource
  2688. )
  2689. /*++
  2690. Description:
  2691. This is the top-level routine from which all of the partition set services
  2692. are called. When complete, all partitions in the asr.sif file will
  2693. have been assigned to a physical disks attached to the system.
  2694. The list of partitions associated with a physical disk is called a
  2695. partition set. Partition lists exist in one of two states: Unassigned and
  2696. Assigned. Physical disks exist in one of two states: Unassigned or
  2697. Assigned. A disk is assigned if it is a member of a partition set, that is
  2698. the disk is associated with a list of partitions. Like an assigned disk, a
  2699. partition list is assigned if it is a member of a partition set, i.e., it
  2700. is associated with a physical disk.
  2701. The rules by which partition sets are constructed are executed in the
  2702. following sequence:
  2703. 0. Assign-system-disk
  2704. 1. Assign-by-signature:
  2705. ASR attempts to assign each partition list found in the asr.sif
  2706. file to the physical disk on the system whose disk signature is
  2707. identical to the disk signature specified in the asr.sif file.
  2708. 2. Assign-by-bus
  2709. 3. Assign-by-bus-type
  2710. 4. Assign-by-size:
  2711. All remaining unassigned partition lists are assigned to disks on the
  2712. basis of their storage requirements. The partition list with the
  2713. smallest storage requirement is assigned to the disk with the smallest
  2714. storage capacity where partition list's storage capacity is less than
  2715. or equal to the disk's storage capacity.
  2716. Returns:
  2717. None
  2718. --*/
  2719. {
  2720. BOOL result = TRUE;
  2721. DWORD systemDiskNumber = (DWORD)(-1);
  2722. //
  2723. // Initialise our global structs. If there's a fatal error, these
  2724. // won't return
  2725. //
  2726. SpAsrInitInternalData();
  2727. systemDiskNumber = SpAsrGetCurrentSystemDiskNumber(SetupSourceDevicePath, DirectoryOnSetupSource);
  2728. SpAsrCheckSifDiskTable(systemDiskNumber);
  2729. if (systemDiskNumber != (DWORD) (-1)) {
  2730. SpAsrAssignSystemDisk(systemDiskNumber);
  2731. }
  2732. //
  2733. // If the signatures of the sif-disks match that of the physical-disks,
  2734. // assign them to each other.
  2735. //
  2736. SpAsrAssignDisksBySignature(systemDiskNumber);
  2737. //
  2738. // If this is a new system disk, we should extend the last partition if
  2739. // needed.
  2740. //
  2741. if (Gbl_PartitionSetTable1[systemDiskNumber] &&
  2742. Gbl_PartitionSetTable1[systemDiskNumber]->IsReplacementDisk &&
  2743. Gbl_PartitionSetTable1[systemDiskNumber]->pDiskRecord) {
  2744. SpAsrAutoExtendDiskPartition(systemDiskNumber,
  2745. Gbl_PartitionSetTable1[systemDiskNumber]->pDiskRecord->SifDiskNumber);
  2746. }
  2747. //
  2748. // Attempt to assign the remaining critical disks. We first attempt
  2749. // to assign disks to the buses they used to be on, then by bus-types,
  2750. // and finally just by smallest-fit.
  2751. //
  2752. SpAsrAssignCriticalDisksByBus();
  2753. SpAsrAssignCriticalDisksByBusType();
  2754. result = SpAsrAssignRemainingCriticalDisks();
  2755. if (!result) {
  2756. SpAsrRaiseFatalError(
  2757. SP_TEXT_DR_INSUFFICIENT_CAPACITY,
  2758. L"Some critical disks could not be assigned"
  2759. );
  2760. }
  2761. MarkIntactSifDisks();
  2762. SpAsrDbgDumpPartitionLists(1, L"After validate ...");
  2763. Gbl_PartitionSetTable2 = SpAsrCopyPartitionSetTable(Gbl_PartitionSetTable1);
  2764. }
  2765. // Debug routines
  2766. VOID
  2767. SpAsrDbgDumpPartitionSet(IN ULONG Disk, PDISK_PARTITION_SET pSet)
  2768. {
  2769. PSIF_PARTITION_RECORD pRec;
  2770. if (!pSet->pDiskRecord) {
  2771. DbgMesg((_asrinfo,
  2772. "No disk (or partition) records assigned to [%ws] (0x%lx)\n\n",
  2773. (PWSTR) HardDisks[Disk].DevicePath,
  2774. pSet->ActualDiskSignature
  2775. ));
  2776. return;
  2777. }
  2778. if (!pSet->pDiskRecord->PartitionList) {
  2779. DbgMesg((_asrinfo, "Disk record [%ws] ([%ws] (0x%lx)). Not referenced by any partition record.\n\n",
  2780. pSet->pDiskRecord->CurrDiskKey,
  2781. (PWSTR) HardDisks[Disk].DevicePath,
  2782. pSet->ActualDiskSignature));
  2783. return;
  2784. }
  2785. // dump the partition table.
  2786. DbgMesg((_asrinfo, "Disk record [%ws] assigned to [%ws] (0x%lx)\n",
  2787. pSet->pDiskRecord->CurrDiskKey,
  2788. (PWSTR) HardDisks[Disk].DevicePath,
  2789. pSet->ActualDiskSignature));
  2790. DbgMesg((_asrinfo, "[%ws] Capacity:%lu Mb. Partitions require:%I64u Mb\n",
  2791. (PWSTR) HardDisks[Disk].DevicePath,
  2792. HardDisks[Disk].DiskSizeMB,
  2793. pSet->pDiskRecord->PartitionList->TotalMbRequired));
  2794. if (pSet->pDiskRecord->ExtendedPartitionStartSector != -1) {
  2795. DbgMesg((_asrinfo, "Extended partition exists. SS:%I64u SC:%I64u\n",
  2796. pSet->pDiskRecord->ExtendedPartitionStartSector,
  2797. pSet->pDiskRecord->ExtendedPartitionSectorCount));
  2798. }
  2799. DbgMesg((_asrinfo, "Ptns-intact: %s Ptn-recs: ", pSet->PartitionsIntact? "Yes" : "No" ));
  2800. pRec = pSet->pDiskRecord->PartitionList->First;
  2801. while (pRec) {
  2802. KdPrintEx((_asrinfo, "[%ws] ", pRec->CurrPartKey));
  2803. pRec = pRec->Next;
  2804. }
  2805. KdPrintEx((_asrinfo, "\n\n"));
  2806. }
  2807. VOID
  2808. SpAsrDbgDumpPartitionSets(VOID)
  2809. {
  2810. ULONG i;
  2811. DbgMesg((_asrinfo, " ----- Partition Set Tables -----\n\n"));
  2812. for (i = 0; i < HardDiskCount; i++) {
  2813. if (!Gbl_PartitionSetTable1[i]) {
  2814. if (DISK_IS_REMOVABLE(i)) {
  2815. DbgMesg((_asrinfo, "- No disk records assigned to removable drive [%ws].\n",
  2816. (PWSTR) HardDisks[i].DevicePath));
  2817. }
  2818. else {
  2819. DbgMesg((_asrinfo, "- No disk records assigned to %ws (0x%lx).\n",
  2820. (PWSTR) HardDisks[i].DevicePath,
  2821. SpAsrGetActualDiskSignature(i)));
  2822. }
  2823. }
  2824. else {
  2825. SpAsrDbgDumpPartitionSet(i, Gbl_PartitionSetTable1[i]);
  2826. }
  2827. }
  2828. DbgMesg((_asrinfo, "----- End of Partition Set Tables -----\n\n"));
  2829. }
  2830. VOID
  2831. SpAsrDbgDumpADisk(PSIF_DISK_RECORD pDiskRec)
  2832. {
  2833. PSIF_PARTITION_RECORD pPtnRec;
  2834. PSIF_PARTITION_RECORD_LIST pList;
  2835. pList = pDiskRec->PartitionList;
  2836. DbgMesg((_asrinfo, "DiskRec %ws. sig:0x%x%s%s\n",
  2837. pDiskRec->CurrDiskKey,
  2838. pDiskRec->SifDiskMbrSignature,
  2839. pDiskRec->ContainsNtPartition ? " [Boot]" : "",
  2840. pDiskRec->ContainsSystemPartition ? " [Sys]" : ""));
  2841. if (pDiskRec->Assigned) {
  2842. DbgMesg((_asrinfo, "Assigned-to:0x%x [%sintact] [%s] size:%I64u MB\n",
  2843. pDiskRec->pSetRecord->ActualDiskSignature,
  2844. pDiskRec->pSetRecord->PartitionsIntact ? "" : "not ",
  2845. pDiskRec->pSetRecord->IsReplacementDisk ? "replacement" : "original",
  2846. pDiskRec->pSetRecord->ActualDiskSizeMB));
  2847. }
  2848. if (!pList) {
  2849. DbgMesg((_asrinfo, "No partition records.\n\n"));
  2850. return;
  2851. }
  2852. DbgMesg((_asrinfo, "Partition records. count:%lu, totalMbRequired:%I64u\n",
  2853. pList->ElementCount, pList->TotalMbRequired));
  2854. pPtnRec = pList->First;
  2855. while (pPtnRec) {
  2856. DbgMesg((_asrinfo, "Ptn %2ws. sz:%4I64u SS:%8I64u SC:%8I64u type:%s FS:0x%-2x %s %s\n",
  2857. pPtnRec->CurrPartKey,
  2858. pPtnRec->SizeMB,
  2859. pPtnRec->StartSector,
  2860. pPtnRec->SectorCount,
  2861. pPtnRec->IsPrimaryRecord ? "Pri" :
  2862. pPtnRec->IsContainerRecord ? "Con" :
  2863. pPtnRec->IsLogicalDiskRecord ? "Log" :
  2864. pPtnRec->IsDescriptorRecord ? "Des" :"ERR",
  2865. pPtnRec->PartitionType,
  2866. SpAsrIsBootPartitionRecord(pPtnRec->PartitionFlag) ? "boot" : "",
  2867. SpAsrIsSystemPartitionRecord(pPtnRec->PartitionFlag) ? "sys" : ""));
  2868. pPtnRec = pPtnRec->Next;
  2869. }
  2870. DbgMesg((_asrinfo, "\n"));
  2871. }
  2872. VOID
  2873. SpAsrDbgDumpPartitionLists(BYTE DataOption, PWSTR Msg)
  2874. {
  2875. ULONG DiskRecords;
  2876. ULONG DiskIndex;
  2877. ULONG SetIndex;
  2878. PSIF_DISK_RECORD pDiskRec;
  2879. PDISK_PARTITION_SET pSetRec;
  2880. DbgMesg((_asrinfo, " ----- Partition Lists: [%ws] -----\n\n", Msg));
  2881. if (DataOption == 1) {
  2882. DiskRecords = SpAsrGetDiskRecordCount();
  2883. for (DiskIndex = 0; DiskIndex < DiskRecords; DiskIndex++) {
  2884. pDiskRec = Gbl_SifDiskTable[DiskIndex];
  2885. if (pDiskRec != NULL) {
  2886. SpAsrDbgDumpADisk(pDiskRec);
  2887. }
  2888. }
  2889. }
  2890. else if (DataOption == 2) {
  2891. ULONG SetRecords = sizeof(Gbl_PartitionSetTable2) / sizeof(PDISK_PARTITION_SET);
  2892. for (SetIndex = 0; SetIndex < HardDiskCount; SetIndex++) {
  2893. pSetRec = Gbl_PartitionSetTable2[SetIndex];
  2894. if (pSetRec != NULL && pSetRec->pDiskRecord != NULL) {
  2895. SpAsrDbgDumpADisk(pSetRec->pDiskRecord);
  2896. }
  2897. }
  2898. }
  2899. DbgMesg((_asrinfo, "----- End of Partition Lists: [%ws] -----\n\n", Msg));
  2900. }