/*++ Copyright (c) 2000 Microsoft Corporation Module Name: asrrest.c Abstract: This module contains the following ASR routine: AsrRestoreNonCriticalDisks{A|W} This routine is called in GUI mode ASR, to reconfigure the non-critical storage devices on the target machine. Notes: Naming conventions: _AsrpXXX private ASR Macros AsrpXXX private ASR routines AsrXXX Publically defined and documented routines Author: Guhan Suriyanarayanan (guhans) 27-May-2000 Environment: User-mode only. Revision History: 27-May-2000 guhans Moved AsrRestoreNonCriticalDisks and other restore-time routines from asr.c to asrrest.c 01-Jan-2000 guhans Initial implementation for AsrRestoreNonCriticalDisks in asr.c --*/ #include "setupp.h" #pragma hdrstop #include // GPT partition type guids #include // mountmgr ioctls #include // ASR public routines #define THIS_MODULE 'R' #include "asrpriv.h" // Private ASR definitions and routines // // -------- // typedefs and constants used within this module // -------- // typedef enum _ASR_SORT_ORDER { SortByLength, SortByStartingOffset } ASR_SORT_ORDER; typedef struct _ASR_REGION_INFO { struct _ASR_REGION_INFO *pNext; LONGLONG StartingOffset; LONGLONG RegionLength; DWORD Index; } ASR_REGION_INFO, *PASR_REGION_INFO; #define ASR_AUTO_EXTEND_MAX_FREE_SPACE_IGNORED (1024 * 1024 * 16) // // -------- // function implementations // -------- // LONGLONG AsrpRoundUp( IN CONST LONGLONG Number, IN CONST LONGLONG Base ) /*++ Routine Description: Helper function to round-up a number to a multiple of a given base. Arguments: Number - The number to be rounded up. Base - The base using which Number is to be rounded-up. Return Value: The first multiple of Base that is greater than or equal to Number. --*/ { if (Number % Base) { return (Number + Base - (Number % Base)); } else { return Number; // already a multiple of Base. } } VOID AsrpCreatePartitionTable( IN OUT PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx, IN PASR_PTN_INFO_LIST pPtnInfoList, IN DWORD BytesPerSector ) /*++ Routine Description: This creates a partition table based on the partition information (pPtnInfoList) passed in Arguments: // needed to convert between sector count and byte offset Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { DWORD index = 0, NumEntries = 0; PPARTITION_INFORMATION_EX currentPtn = NULL; PASR_PTN_INFO pPtnInfo = NULL; MYASSERT(pDriveLayoutEx); if (!pDriveLayoutEx || !pPtnInfoList || !(pPtnInfoList->pOffsetHead)) { return; } if (PARTITION_STYLE_GPT == pDriveLayoutEx->PartitionStyle) { NumEntries = pDriveLayoutEx->Gpt.MaxPartitionCount; } else if (PARTITION_STYLE_MBR == pDriveLayoutEx->PartitionStyle) { NumEntries = pDriveLayoutEx->PartitionCount; } else { MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)"); return; } // // Zero out the entire partition table first // for (index = 0; index < NumEntries; index++) { currentPtn = &(pDriveLayoutEx->PartitionEntry[index]); currentPtn->StartingOffset.QuadPart = 0; currentPtn->PartitionLength.QuadPart = 0; } // // Now go through each of the partitions in the list, and add their entry // to the partition table (at index = SlotIndex) // pPtnInfo = pPtnInfoList->pOffsetHead; while (pPtnInfo) { // // For GPT partitions, SlotIndex is 0-based without holes // currentPtn = &(pDriveLayoutEx->PartitionEntry[pPtnInfo->SlotIndex]); MYASSERT(0 == currentPtn->StartingOffset.QuadPart); // this entry better be empty // // Convert the StartSector and SectorCount to BYTE-Offset and BYTE-Count ... // pPtnInfo->PartitionInfo.StartingOffset.QuadPart *= BytesPerSector; pPtnInfo->PartitionInfo.PartitionLength.QuadPart *= BytesPerSector; // // Copy the partition-information struct over // memcpy(currentPtn, &(pPtnInfo->PartitionInfo), sizeof(PARTITION_INFORMATION_EX)); currentPtn->RewritePartition = TRUE; currentPtn->PartitionStyle = pDriveLayoutEx->PartitionStyle; pPtnInfo = pPtnInfo->pOffsetNext; } } // // // ULONG64 AsrpStringToULong64( IN PWSTR String ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { ULONG64 result = 0, base = 10; BOOL negative = FALSE, done = FALSE; if (!String) { return 0; } if (L'-' == *String) { // But this is ULONG! negative = TRUE; String++; } if (L'0' == *String && (L'x' == *(String + 1) || L'X' == *(String + 1)) ) { // Hex base = 16; String += 2; } while (!done) { done = TRUE; if (L'0' <= *String && L'9' >= *String) { result = result*base + (*String - L'0'); String++; done = FALSE; } else if (16==base) { if (L'a' <= *String && L'f' >= *String) { result = result*base + (*String - L'a') + 10; String++; done = FALSE; } else if (L'A' <= *String && L'F' >= *String) { result = result*base + (*String - L'A') + 10; String++; done = FALSE; } } } if (negative) { result = 0 - result; } return result; } LONGLONG AsrpStringToLongLong( IN PWSTR String ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { LONGLONG result = 0, base = 10; BOOL negative = FALSE, done = FALSE; if (!String) { return 0; } if (L'-' == *String) { negative = TRUE; String++; } if (L'0' == *String && (L'x' == *(String + 1) || L'X' == *(String + 1)) ) { // Hex base = 16; String += 2; } while (!done) { done = TRUE; if (L'0' <= *String && L'9' >= *String) { result = result*base + (*String - L'0'); String++; done = FALSE; } else if (16==base) { if (L'a' <= *String && L'f' >= *String) { result = result*base + (*String - L'a') + 10; String++; done = FALSE; } else if (L'A' <= *String && L'F' >= *String) { result = result*base + (*String - L'A') + 10; String++; done = FALSE; } } } if (negative) { result = 0 - result; } return result; } DWORD AsrpStringToDword( IN PWSTR String ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { DWORD result = 0, base = 10; BOOL negative = FALSE, done = FALSE; if (!String) { return 0; } if (L'-' == *String) { // but this is unsigned! negative = TRUE; String++; } if (L'0' == *String && (L'x' == *(String + 1) || L'X' == *(String + 1)) ) { // Hex base = 16; String += 2; } while (!done) { done = TRUE; if (L'0' <= *String && L'9' >= *String) { result = result*base + (*String - L'0'); String++; done = FALSE; } else if (16==base) { if (L'a' <= *String && L'f' >= *String) { result = result*base + (*String - L'a') + 10; String++; done = FALSE; } else if (L'A' <= *String && L'F' >= *String) { result = result*base + (*String - L'A') + 10; String++; done = FALSE; } } } if (negative) { result = 0 - result; } return result; } ULONG AsrpStringToULong( IN PWSTR String ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { ULONG result = 0, base = 10; BOOL negative = FALSE, done = FALSE; if (!String) { return 0; } if (L'-' == *String) { // but this is unsigned! negative = TRUE; String++; } if (L'0' == *String && (L'x' == *(String + 1) || L'X' == *(String + 1)) ) { // Hex base = 16; String += 2; } while (!done) { done = TRUE; if (L'0' <= *String && L'9' >= *String) { result = result*base + (*String - L'0'); String++; done = FALSE; } else if (16==base) { if (L'a' <= *String && L'f' >= *String) { result = result*base + (*String - L'a') + 10; String++; done = FALSE; } else if (L'A' <= *String && L'F' >= *String) { result = result*base + (*String - L'A') + 10; String++; done = FALSE; } } } if (negative) { result = 0 - result; } return result; } VOID AsrpInsertSortedPartitionLengthOrder( IN PASR_PTN_INFO_LIST pPtnInfoList, IN PASR_PTN_INFO pPtnInfo ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_PTN_INFO pPreviousPtn = NULL, pCurrentPtn = NULL; // // Insert this in the sorted PartitionLength order ... // pCurrentPtn = pPtnInfoList->pLengthHead; if (!pCurrentPtn) { // // First item in the list // pPtnInfoList->pLengthHead = pPtnInfo; pPtnInfoList->pLengthTail = pPtnInfo; } else { while (pCurrentPtn) { if (pCurrentPtn->PartitionInfo.PartitionLength.QuadPart <= pPtnInfo->PartitionInfo.PartitionLength.QuadPart) { pPreviousPtn = pCurrentPtn; pCurrentPtn = pCurrentPtn->pLengthNext; } else { // // We found the spot, let's add it in. // if (!pPreviousPtn) { // // This is the first node // pPtnInfoList->pLengthHead = pPtnInfo; } else { pPreviousPtn->pLengthNext = pPtnInfo; } pPtnInfo->pLengthNext = pCurrentPtn; break; } } if (!pCurrentPtn) { // // We reached the end and didn't add this node in. // MYASSERT(pPtnInfoList->pLengthTail == pPreviousPtn); pPtnInfoList->pLengthTail = pPtnInfo; pPreviousPtn->pLengthNext = pPtnInfo; } } } VOID AsrpInsertSortedPartitionStartOrder( IN PASR_PTN_INFO_LIST pPtnInfoList, IN PASR_PTN_INFO pPtnInfo ) /*++ Routine Description: Arguments: Return Value: None --*/ { PASR_PTN_INFO pPreviousPtn = NULL, pCurrentPtn = NULL; // // Insert this in the sorted Start-Sector order ... // pCurrentPtn = pPtnInfoList->pOffsetHead; if (!pCurrentPtn) { // // First item in the list // pPtnInfoList->pOffsetHead = pPtnInfo; pPtnInfoList->pOffsetTail = pPtnInfo; } else { while (pCurrentPtn) { if (pCurrentPtn->PartitionInfo.StartingOffset.QuadPart <= pPtnInfo->PartitionInfo.StartingOffset.QuadPart) { pPreviousPtn = pCurrentPtn; pCurrentPtn = pCurrentPtn->pOffsetNext; } else { // // We found the spot, let's add it in. // if (!pPreviousPtn) { // // This is the first node // pPtnInfoList->pOffsetHead = pPtnInfo; } else { pPreviousPtn->pOffsetNext = pPtnInfo; } pPtnInfo->pOffsetNext = pCurrentPtn; break; } } if (!pCurrentPtn) { // // We reached the end and didn't add this node in. // MYASSERT(pPtnInfoList->pOffsetTail == pPreviousPtn); pPtnInfoList->pOffsetTail = pPtnInfo; pPreviousPtn->pOffsetNext = pPtnInfo; } } } // // Build the original MBR disk info from the sif file // BOOL AsrpBuildMbrSifDiskList( IN PCWSTR sifPath, OUT PASR_DISK_INFO *ppSifDiskList, OUT PASR_PTN_INFO_LIST *ppSifMbrPtnList, OUT BOOL *lpAutoExtend ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { HINF hSif = NULL; INFCONTEXT infSystemContext, infDiskContext, infBusContext, infPtnContext; BOOL result = FALSE; DWORD reqdSize = 0, diskCount = 0, status = ERROR_SUCCESS; INT tempInt = 0; UINT errorLine = 0; PASR_DISK_INFO pNewSifDisk = NULL, currentDisk = NULL; PASR_PTN_INFO_LIST pMbrPtnList = NULL; PASR_PTN_INFO pPtnInfo = NULL; HANDLE heapHandle = GetProcessHeap(); WCHAR tempBuffer[ASR_SIF_ENTRY_MAX_CHARS + 1]; ZeroMemory(&infSystemContext, sizeof(INFCONTEXT)); ZeroMemory(&infDiskContext, sizeof(INFCONTEXT)); ZeroMemory(&infBusContext, sizeof(INFCONTEXT)); ZeroMemory(&infPtnContext, sizeof(INFCONTEXT)); ZeroMemory(tempBuffer, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1)); // *ppSifDiskList = NULL; // // Open the sif // hSif = SetupOpenInfFileW(sifPath, NULL, INF_STYLE_WIN4, &errorLine); if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) { AsrpPrintDbgMsg(_asrerror, "The ASR state file \"%ws\" could not be opened. Error:%lu. Line: %lu.\r\n", sifPath, GetLastError(), errorLine ); return FALSE; // sif file couldn't be opened } *lpAutoExtend = TRUE; // enable by default // // Get the AutoExtend value // result = SetupFindFirstLineW(hSif, ASR_SIF_SYSTEM_SECTION, NULL, &infSystemContext); if (!result) { AsrpPrintDbgMsg(_asrerror, "The ASR state file \"%ws\" is corrupt (section %ws not be found).\r\n", sifPath, ASR_SIF_SYSTEM_SECTION ); return FALSE; // no system section } result = SetupGetIntField(&infSystemContext, 5, (PINT) (lpAutoExtend)); if (!result) { *lpAutoExtend = TRUE; // TRUE by default } result = SetupFindFirstLineW(hSif, ASR_SIF_MBR_DISKS_SECTION, NULL, &infDiskContext); if (!result) { AsrpPrintDbgMsg(_asrinfo, "Section [%ws] is empty. Assuming no MBR disks.\r\n", ASR_SIF_MBR_DISKS_SECTION ); return TRUE; // no mbr disks section } // // First, we go through the [DISKS.MBR] section. At the end of this loop, // we'll have a list of all MBR sif-disks. (*ppSifDiskList will point to // a linked list of ASR_DISK_INFO's, one for each disk). // do { ++diskCount; // // Create a new sif disk for this entry // pNewSifDisk = (PASR_DISK_INFO) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_DISK_INFO) ); _AsrpErrExitCode(!pNewSifDisk, status, ERROR_NOT_ENOUGH_MEMORY); pNewSifDisk->pNext = *ppSifDiskList; *ppSifDiskList = pNewSifDisk; // // Now fill in the fields in the struct. Since we zeroed the struct while // allocating mem, all pointers in the struct are NULL by default, and // all flags in the struct are FALSE. // pNewSifDisk->pDiskGeometry = (PDISK_GEOMETRY) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DISK_GEOMETRY) ); _AsrpErrExitCode(!pNewSifDisk->pDiskGeometry, status, ERROR_NOT_ENOUGH_MEMORY); pNewSifDisk->pPartition0Ex = (PPARTITION_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(PARTITION_INFORMATION_EX) ); _AsrpErrExitCode(!pNewSifDisk->pPartition0Ex, status, ERROR_NOT_ENOUGH_MEMORY); // This is an MBR disk pNewSifDisk->Style = PARTITION_STYLE_MBR; // // Index 0 is the key to the left of the = sign // result = SetupGetIntField(&infDiskContext, 0, (PINT) &(pNewSifDisk->SifDiskKey)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? // // Index 1 is the system key, it must be 1. We ignore it. // Index 2 - 6 are the bus key, critical flag, signature, // bytes-per-sector, sector-count // result = SetupGetIntField(&infDiskContext, 2, (PINT) &(pNewSifDisk->SifBusKey)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infDiskContext, 3, (PINT) &(tempInt)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->IsCritical = (tempInt ? TRUE: FALSE); result = SetupGetStringFieldW(&infDiskContext, 4, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->TempSignature = AsrpStringToDword(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 5, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->BytesPerSector = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->SectorsPerTrack = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->TracksPerCylinder = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer); // convert from sector count to byte count pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart *= pNewSifDisk->pDiskGeometry->BytesPerSector; // // Get the bus-type related to this disk. LineByIndex is 0 based, our bus key is 1-based. // result = SetupGetLineByIndexW(hSif, ASR_SIF_BUSES_SECTION, pNewSifDisk->SifBusKey - 1, &infBusContext); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infBusContext, 2, (PINT) &(pNewSifDisk->BusType)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupFindNextLine(&infDiskContext, &infDiskContext); } while (result); AsrpPrintDbgMsg(_asrinfo, "Found %lu records in section [%ws].\r\n", diskCount, ASR_SIF_MBR_DISKS_SECTION ); // // Now, enumerate all the [PARTITIONS.MBR] section. This will give us a list // of all the partitions (all) the MBR disks contained. // result = SetupFindFirstLineW(hSif, ASR_SIF_MBR_PARTITIONS_SECTION, NULL, &infPtnContext); if (result) { DWORD diskKey = 0; // // Init the table of partion lists. // pMbrPtnList = (PASR_PTN_INFO_LIST) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_PTN_INFO_LIST) * (diskCount + 1) ); _AsrpErrExitCode(!pMbrPtnList, status, ERROR_NOT_ENOUGH_MEMORY); // hack. // The 0'th entry of our table is not used, since the disk indices // begin with 1. Since we have no other way of keeping track of // how big this table is (so that we can free it properly), we can // use the 0th entry to store this. // pMbrPtnList[0].numTotalPtns = diskCount + 1; // size of table do { pPtnInfo = (PASR_PTN_INFO) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_PTN_INFO) ); _AsrpErrExitCode(!pPtnInfo, status, ERROR_NOT_ENOUGH_MEMORY); // // Read in the information. The format of this section is: // // [PARTITIONS.MBR] // 0.partition-key = 1.disk-key, 2.slot-index, 3.boot-sys-flag, // 4."volume-guid", 5.active-flag, 6.partition-type, // 7.file-system-type, 8.start-sector, 9.sector-count // result = SetupGetIntField(&infPtnContext, 1, &diskKey); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 2, (PINT) &(pPtnInfo->SlotIndex)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 3, (PINT) &(pPtnInfo->PartitionFlags)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetStringFieldW(&infPtnContext, 4, pPtnInfo->szVolumeGuid, ASR_CCH_MAX_VOLUME_GUID, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 5, (PINT) &tempInt); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.Mbr.BootIndicator = (tempInt ? TRUE: FALSE); // converting from int to uchar result = SetupGetIntField(&infPtnContext, 6, (PINT) &(pPtnInfo->PartitionInfo.Mbr.PartitionType)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 7, (PINT) &(pPtnInfo->FileSystemType)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? // // Note, we read in the start SECTOR and SECTOR count. We'll convert these to // their byte values later (in AsrpCreatePartitionTable) // result = SetupGetStringFieldW(&infPtnContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.StartingOffset.QuadPart = AsrpStringToLongLong(tempBuffer); result = SetupGetStringFieldW(&infPtnContext, 9, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer); // // Add this in the sorted starting-offset order. // AsrpInsertSortedPartitionStartOrder(&(pMbrPtnList[diskKey]), pPtnInfo); // // Add this in the sorted partition length order as well. This isn't really used for // MBR disks at present, only for GPT disks. // AsrpInsertSortedPartitionLengthOrder(&(pMbrPtnList[diskKey]), pPtnInfo); (pMbrPtnList[diskKey].numTotalPtns)++; if (IsContainerPartition(pPtnInfo->PartitionInfo.Mbr.PartitionType)) { (pMbrPtnList[diskKey].numExtendedPtns)++; } result = SetupFindNextLine(&infPtnContext, &infPtnContext); } while (result); // // Now, we have the table of all the MBR partition lists, and a list of // all MBR disks. The next step is to "assign" the partitions to their respective // disks--and update the DriveLayoutEx struct for the disks. // currentDisk = *(ppSifDiskList); while (currentDisk) { DWORD PartitionCount = 0, count = 0; if (PARTITION_STYLE_MBR != currentDisk->Style) { currentDisk = currentDisk->pNext; continue; } PartitionCount = ((pMbrPtnList[currentDisk->SifDiskKey].numExtendedPtns) * 4) + 4; currentDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX)*(PartitionCount-1)); currentDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, currentDisk->sizeDriveLayoutEx ); _AsrpErrExitCode(!currentDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY); // // Initialise the DriveLayout struct. // currentDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR; currentDisk->pDriveLayoutEx->PartitionCount = PartitionCount; currentDisk->pDriveLayoutEx->Mbr.Signature = currentDisk->TempSignature; AsrpCreatePartitionTable(currentDisk->pDriveLayoutEx, &(pMbrPtnList[currentDisk->SifDiskKey]), currentDisk->pDiskGeometry->BytesPerSector ); currentDisk = currentDisk->pNext; } } else { DWORD count = 0; AsrpPrintDbgMsg(_asrinfo, "Section [%ws] is empty. Assuming MBR disks have no partitions.\r\n", ASR_SIF_MBR_PARTITIONS_SECTION ); // // The partitions section is empty. Initialise each disk's drive layout // accordingly // currentDisk = *ppSifDiskList; while (currentDisk) { if (PARTITION_STYLE_MBR != currentDisk->Style) { currentDisk = currentDisk->pNext; continue; } currentDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * 3); currentDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, currentDisk->sizeDriveLayoutEx ); _AsrpErrExitCode(!currentDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY); currentDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR; currentDisk->pDriveLayoutEx->PartitionCount = 4; currentDisk->pDriveLayoutEx->Mbr.Signature = currentDisk->TempSignature; for (count = 0; count < currentDisk->pDriveLayoutEx->PartitionCount ; count++) { currentDisk->pDriveLayoutEx->PartitionEntry[count].PartitionStyle = PARTITION_STYLE_MBR; currentDisk->pDriveLayoutEx->PartitionEntry[count].RewritePartition = TRUE; } currentDisk = currentDisk->pNext; } } EXIT: *ppSifMbrPtnList = pMbrPtnList; if ((hSif) && (INVALID_HANDLE_VALUE != hSif)) { SetupCloseInfFile(hSif); hSif = NULL; } return (BOOL) (ERROR_SUCCESS == status); } // // Build the original disk info for GPT disks from the sif file // BOOL AsrpBuildGptSifDiskList( IN PCWSTR sifPath, OUT PASR_DISK_INFO *ppSifDiskList, OUT PASR_PTN_INFO_LIST *ppSifGptPtnList ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { HINF hSif = NULL; BOOL result = FALSE; DWORD reqdSize = 0, diskCount = 0, status = ERROR_SUCCESS; INFCONTEXT infDiskContext, infBusContext, infPtnContext; INT tempInt = 0; UINT errorLine = 0; PASR_DISK_INFO pNewSifDisk = NULL, currentDisk = NULL; HANDLE heapHandle = NULL; PASR_PTN_INFO pPtnInfo = NULL; RPC_STATUS rpcStatus = RPC_S_OK; PASR_PTN_INFO_LIST pGptPtnList = NULL; WCHAR tempBuffer[ASR_SIF_ENTRY_MAX_CHARS+1]; heapHandle = GetProcessHeap(); ZeroMemory(&infDiskContext, sizeof(INFCONTEXT)); ZeroMemory(&infBusContext, sizeof(INFCONTEXT)); ZeroMemory(&infPtnContext, sizeof(INFCONTEXT)); ZeroMemory(tempBuffer, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1)); // // Open the sif // hSif = SetupOpenInfFileW(sifPath, NULL, INF_STYLE_WIN4, &errorLine); if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) { AsrpPrintDbgMsg(_asrerror, "The ASR state file \"%ws\" could not be opened. Error:%lu. Line: %lu.\r\n", sifPath, GetLastError(), errorLine ); return FALSE; // sif file couldn't be opened } result = SetupFindFirstLineW(hSif, ASR_SIF_GPT_DISKS_SECTION, NULL, &infDiskContext); if (!result) { AsrpPrintDbgMsg(_asrinfo, "Section [%ws] is empty. Assuming no GPT disks.\r\n", ASR_SIF_GPT_DISKS_SECTION ); return TRUE; // no disks section } // // First, we go through the [DISKS.GPT] section. At the end of this loop, // we'll have a list of all GPT sif-disks. (*ppSifDiskList will point to // a linked list of ASR_DISK_INFO's, one for each disk). // do { ++diskCount; // // Create a new sif disk for this entry // pNewSifDisk = (PASR_DISK_INFO) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_DISK_INFO) ); _AsrpErrExitCode(!pNewSifDisk, status, ERROR_NOT_ENOUGH_MEMORY); pNewSifDisk->pNext = *ppSifDiskList; *ppSifDiskList = pNewSifDisk; // // Now fill in the fields in the struct. Since we zeroed the struct while // allocating mem, all pointers in the struct are NULL by default, and // all flags in the struct are FALSE. // pNewSifDisk->pDiskGeometry = (PDISK_GEOMETRY) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DISK_GEOMETRY) ); _AsrpErrExitCode(!pNewSifDisk->pDiskGeometry, status, ERROR_NOT_ENOUGH_MEMORY); pNewSifDisk->pPartition0Ex = (PPARTITION_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(PARTITION_INFORMATION_EX) ); _AsrpErrExitCode(!pNewSifDisk->pPartition0Ex, status, ERROR_NOT_ENOUGH_MEMORY); // This is a GPT disk pNewSifDisk->Style = PARTITION_STYLE_GPT; // // Index 0 is the key to the left of the = sign // result = SetupGetIntField(&infDiskContext, 0, (PINT) &(pNewSifDisk->SifDiskKey)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? // // Index 1 is the system key, it must be 1. We ignore it. // Index 2 - 7 are: // 2: bus key // 3: critical flag // 4: disk-guid // 5: max-partition-count // 6: bytes-per-sector // 7: sector-count // result = SetupGetIntField(&infDiskContext, 2, (PINT) &(pNewSifDisk->SifBusKey)); // BusKey _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infDiskContext, 3, (PINT) &(tempInt)); // IsCritical _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->IsCritical = (tempInt ? TRUE: FALSE); result = SetupGetStringFieldW(&infDiskContext, 4, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); // DiskGuid _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infDiskContext, 5, (PINT) &(tempInt)); // MaxPartitionCount _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? // // Allocate a drive layout struct, now that we know the max partition count // pNewSifDisk->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX)*(tempInt-1)); pNewSifDisk->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, pNewSifDisk->sizeDriveLayoutEx ); _AsrpErrExitCode(!pNewSifDisk->pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY); // This is a GPT disk pNewSifDisk->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT; // // Set the MaxPartitionCount and DiskGuid fields // pNewSifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount = tempInt; rpcStatus = UuidFromStringW(tempBuffer, &(pNewSifDisk->pDriveLayoutEx->Gpt.DiskId)); _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus); result = SetupGetStringFieldW(&infDiskContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->BytesPerSector = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->SectorsPerTrack = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 8, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pDiskGeometry->TracksPerCylinder = AsrpStringToULong(tempBuffer); result = SetupGetStringFieldW(&infDiskContext, 9, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer); // convert from sector count to byte count pNewSifDisk->pPartition0Ex->PartitionLength.QuadPart *= pNewSifDisk->pDiskGeometry->BytesPerSector; // TotalBytes // // Get the bus-type related to this disk. LineByIndex is 0 based, our bus key is 1-based. // result = SetupGetLineByIndexW(hSif, ASR_SIF_BUSES_SECTION, pNewSifDisk->SifBusKey - 1, &infBusContext); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infBusContext, 2, (PINT) &(pNewSifDisk->BusType)); // bus type _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupFindNextLine(&infDiskContext, &infDiskContext); } while(result); AsrpPrintDbgMsg(_asrinfo, "Found %lu records in section [%ws].\r\n", diskCount, ASR_SIF_MBR_DISKS_SECTION ); // // Now, enumerate all the [PARTITIONS.GPT] section. This will give us a list // of all the partitions (all) the GPT disks contained. // result = SetupFindFirstLineW(hSif, ASR_SIF_GPT_PARTITIONS_SECTION, NULL, &infPtnContext); if (result) { DWORD diskKey = 0; // // Init the table of partion lists. // pGptPtnList = (PASR_PTN_INFO_LIST) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_PTN_INFO_LIST) * (diskCount + 1) ); _AsrpErrExitCode(!pGptPtnList, status, ERROR_NOT_ENOUGH_MEMORY); // hack. // The 0'th entry of our table is not used, since the disk indices // begin with 1. Since we have no other way of keeping track of // how big this table is (so that we can free it properly), we can // use the 0th entry to store this. // pGptPtnList[0].numTotalPtns = diskCount + 1; // size of table do { pPtnInfo = (PASR_PTN_INFO) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(ASR_PTN_INFO) ); _AsrpErrExitCode(!pPtnInfo, status, ERROR_NOT_ENOUGH_MEMORY); // // This is a GPT partition // pPtnInfo->PartitionInfo.PartitionStyle = PARTITION_STYLE_GPT; // // Read in the values. The format of this section is: // // [PARTITIONS.GPT] // 0.partition-key = 1.disk-key, 2.slot-index, 3.boot-sys-flag, // 4."volume-guid", 5."partition-type-guid", 6."partition-id-guid" // 7.gpt-attributes, 8."partition-name", 9.file-system-type, // 10.start-sector, 11.sector-count // result = SetupGetIntField(&infPtnContext, 1, &diskKey); // 1. disk-key _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 2, (PINT) &(pPtnInfo->SlotIndex)); // 2. slot-index _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 3, (PINT) &(pPtnInfo->PartitionFlags)); // 3. boot-sys-flag _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetStringFieldW(&infPtnContext, 4, pPtnInfo->szVolumeGuid, ASR_CCH_MAX_VOLUME_GUID, &reqdSize); // volume-guid _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetStringFieldW(&infPtnContext, 5, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS + 1, &reqdSize); // partition-type-guid _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? rpcStatus = UuidFromStringW(tempBuffer, &(pPtnInfo->PartitionInfo.Gpt.PartitionType)); _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus); result = SetupGetStringFieldW(&infPtnContext, 6, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS + 1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? rpcStatus = UuidFromStringW(tempBuffer, &(pPtnInfo->PartitionInfo.Gpt.PartitionId)); _AsrpErrExitCode((RPC_S_OK != rpcStatus), status, rpcStatus); // // Note, we read in the start SECTOR and SECTOR count. We'll convert these to // their byte values later (in AsrpCreatePartitionTable) // result = SetupGetStringFieldW(&infPtnContext, 7, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.Gpt.Attributes = AsrpStringToULong64(tempBuffer); result = SetupGetStringFieldW(&infPtnContext, 8, pPtnInfo->PartitionInfo.Gpt.Name, 36, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetIntField(&infPtnContext, 9, (PINT) &(pPtnInfo->FileSystemType)); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? // // Note, we read in the start SECTOR and SECTOR count. We'll convert it to the // BYTE offset and BYTE length later (in AsrpCreatePartitionTable) // result = SetupGetStringFieldW(&infPtnContext, 10, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.StartingOffset.QuadPart = AsrpStringToLongLong(tempBuffer); result = SetupGetStringFieldW(&infPtnContext, 11, tempBuffer, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? pPtnInfo->PartitionInfo.PartitionLength.QuadPart = AsrpStringToLongLong(tempBuffer); // // Add this in the sorted partition starting-offset order. // AsrpInsertSortedPartitionStartOrder(&(pGptPtnList[diskKey]), pPtnInfo); // // Add this in the sorted partition length order as well. This is useful // later when we try to fit in the partitions on the disk. // AsrpInsertSortedPartitionLengthOrder(&(pGptPtnList[diskKey]), pPtnInfo); (pGptPtnList[diskKey].numTotalPtns)++; result = SetupFindNextLine(&infPtnContext, &infPtnContext); } while (result); // // Now, we have the table of all the partition lists, and a list of // all disks. The next task is to update the DriveLayoutEx struct for // the disks. // currentDisk = *(ppSifDiskList); while (currentDisk) { if (PARTITION_STYLE_GPT != currentDisk->Style) { currentDisk = currentDisk->pNext; continue; } // // Initialise the DriveLayoutEx struct. // currentDisk->pDriveLayoutEx->PartitionCount = pGptPtnList[currentDisk->SifDiskKey].numTotalPtns; AsrpCreatePartitionTable(currentDisk->pDriveLayoutEx, &(pGptPtnList[currentDisk->SifDiskKey]), currentDisk->pDiskGeometry->BytesPerSector ); currentDisk = currentDisk->pNext; } } else { DWORD count = 0; AsrpPrintDbgMsg(_asrinfo, "Section [%ws] is empty. Assuming GPT disks have no partitions.\r\n", ASR_SIF_GPT_PARTITIONS_SECTION ); // // The partitions section is empty. Initialise each disk's drive layout // accordingly // currentDisk = *ppSifDiskList; while (currentDisk) { if (PARTITION_STYLE_GPT != currentDisk->Style) { currentDisk = currentDisk->pNext; continue; } currentDisk->pDriveLayoutEx->PartitionCount = 0; for (count = 0; count < currentDisk->pDriveLayoutEx->Gpt.MaxPartitionCount ; count++) { currentDisk->pDriveLayoutEx->PartitionEntry[count].PartitionStyle = PARTITION_STYLE_GPT; currentDisk->pDriveLayoutEx->PartitionEntry[count].RewritePartition = TRUE; } currentDisk = currentDisk->pNext; } } EXIT: *ppSifGptPtnList = pGptPtnList; if ((hSif) && (INVALID_HANDLE_VALUE != hSif)) { SetupCloseInfFile(hSif); hSif = NULL; } return (BOOL) (ERROR_SUCCESS == status); } // // Returns // TRUE if pSifDisk and pPhysicalDisk have the exact same partition layout, // FALSE otherwise // BOOL AsrpIsDiskIntact( IN PASR_DISK_INFO pSifDisk, IN PASR_DISK_INFO pPhysicalDisk ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { ULONG index = 0, physicalIndex = 0; PPARTITION_INFORMATION_EX pSifPtnEx = NULL, pPhysicalPtnEx = NULL; if (pSifDisk->Style != pPhysicalDisk->Style) { return FALSE; // different partitioning styles } if (PARTITION_STYLE_MBR == pSifDisk->Style) { // // For MBR disks, we expect to find the same number of partitions, // and the starting-offset and partition-length for each of those // partitions must be the same as they were in the sif // if (pSifDisk->pDriveLayoutEx->Mbr.Signature != pPhysicalDisk->pDriveLayoutEx->Mbr.Signature) { return FALSE; // different signatures } if (pSifDisk->pDriveLayoutEx->PartitionCount != pPhysicalDisk->pDriveLayoutEx->PartitionCount) { return FALSE; // different partition counts } for (index =0; index < pSifDisk->pDriveLayoutEx->PartitionCount; index++) { pSifPtnEx = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index]); pPhysicalPtnEx = &(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[index]); if ((pSifPtnEx->StartingOffset.QuadPart != pPhysicalPtnEx->StartingOffset.QuadPart) || (pSifPtnEx->PartitionLength.QuadPart != pPhysicalPtnEx->PartitionLength.QuadPart) ) { // // The partition offset or length didn't match, ie the disk // isn't intact // return FALSE; } } // for } else if (PARTITION_STYLE_GPT == pSifDisk->Style) { BOOL found = FALSE; // // For GPT disks, the partitions must have the same partition-Id's, in // addition to the start sector and sector count. We can't rely on their // partition table entry order being the same, though--so we have to go // through all the partition entries from the beginning ... // for (index = 0; index < pSifDisk->pDriveLayoutEx->PartitionCount; index++) { pSifPtnEx = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index]); found = FALSE; for (physicalIndex = 0; (physicalIndex < pPhysicalDisk->pDriveLayoutEx->PartitionCount) // && (pSifPtnEx->StartingOffset.QuadPart >= pPhysicalDisk->pDriveLayoutEx->PartitionEntry[physicalIndex].StartingOffset.QuadPart) // entries are in ascending order && (!found); physicalIndex++) { pPhysicalPtnEx = &(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[physicalIndex]); if (IsEqualGUID(&(pSifPtnEx->Gpt.PartitionId), &(pPhysicalPtnEx->Gpt.PartitionId)) && (pSifPtnEx->StartingOffset.QuadPart == pPhysicalPtnEx->StartingOffset.QuadPart) && (pSifPtnEx->PartitionLength.QuadPart == pPhysicalPtnEx->PartitionLength.QuadPart) ) { // // The partition GUID, offset and length matched, this partition exists // found = TRUE; } } // for if (!found) { // // At least one partition wasn't found // return FALSE; } } } return TRUE; } LONGLONG AsrpCylinderAlignMbrPartitions( IN PASR_DISK_INFO pSifDisk, IN PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutEx, IN DWORD StartIndex, // index in the partitionEntry table to start at IN LONGLONG StartingOffset, IN PDISK_GEOMETRY pPhysicalDiskGeometry ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { LONGLONG nextEnd = 0, endingOffset = 0, bytesPerTrack = 0, bytesPerCylinder = 0, currentMax = 0, maxEndingOffset = 0; DWORD index = 0, tempIndex = 0, tempIndex2 = 0; PPARTITION_INFORMATION_EX alignedPtn = NULL, sifPtn = NULL, tempPtn = NULL; if (PARTITION_STYLE_MBR != pSifDisk->Style) { // // This routine only supports MBR disks. For GPT disks, we don't need to // cylinder-align partitions, so this routine shouldn't be called. // return -1; } if (0 == pSifDisk->pDriveLayoutEx->PartitionCount) { // // (boundary case) No partitions on disk to align // return 0; } MYASSERT(AsrpRoundUp(StartIndex,4) == StartIndex); MYASSERT(pSifDisk && pAlignedLayoutEx); if (!pSifDisk || !pAlignedLayoutEx) { return -1; } bytesPerTrack = pPhysicalDiskGeometry->BytesPerSector * pPhysicalDiskGeometry->SectorsPerTrack; bytesPerCylinder = bytesPerTrack * (pPhysicalDiskGeometry->TracksPerCylinder); // // The first partition entry in each MBR/EBR always starts at the // cylinder-boundary plus one track. So, add one track to the starting // offset. // // The exception (there had to be one, of course) is if the first // partition entry in the MBR/EBR itself is a container partition (0x05 or // 0x0f), then it starts on the next cylinder. // if (IsContainerPartition(pSifDisk->pDriveLayoutEx->PartitionEntry[StartIndex].Mbr.PartitionType)) { StartingOffset += (bytesPerCylinder); } else { StartingOffset += (bytesPerTrack); } for (index = 0; index < 4; index++) { alignedPtn = &(pAlignedLayoutEx->PartitionEntry[index + StartIndex]); sifPtn = &(pSifDisk->pDriveLayoutEx->PartitionEntry[index + StartIndex]); MYASSERT(PARTITION_STYLE_MBR == sifPtn->PartitionStyle); // // Set the fields of interest // alignedPtn->PartitionStyle = PARTITION_STYLE_MBR; alignedPtn->RewritePartition = TRUE; alignedPtn->Mbr.PartitionType = sifPtn->Mbr.PartitionType; alignedPtn->Mbr.BootIndicator = sifPtn->Mbr.BootIndicator; alignedPtn->Mbr.RecognizedPartition = sifPtn->Mbr.RecognizedPartition; if (PARTITION_ENTRY_UNUSED != sifPtn->Mbr.PartitionType) { alignedPtn->StartingOffset.QuadPart = StartingOffset; endingOffset = AsrpRoundUp(sifPtn->PartitionLength.QuadPart + StartingOffset, bytesPerCylinder); alignedPtn->PartitionLength.QuadPart = endingOffset - StartingOffset; if (IsContainerPartition(alignedPtn->Mbr.PartitionType)) { // // This is a container partition (0x5 or 0xf), so we have to try and // fit the logical drives inside this partition to get the // required size of this partition. // nextEnd = AsrpCylinderAlignMbrPartitions(pSifDisk, pAlignedLayoutEx, StartIndex + 4, StartingOffset, pPhysicalDiskGeometry ); if (-1 == nextEnd) { // // Propogate error upwards // return nextEnd; } if (StartIndex < 4) { // // We're dealing with the primary container partition // if (nextEnd > endingOffset) { MYASSERT(AsrpRoundUp(nextEnd, bytesPerCylinder) == nextEnd); alignedPtn->PartitionLength.QuadPart = nextEnd - StartingOffset; endingOffset = nextEnd; } // // If the primary container partition ends beyond cylinder // 1024, it should be of type 0xf, else it should be of // type 0x5. // if (endingOffset > (1024 * bytesPerCylinder)) { alignedPtn->Mbr.PartitionType = PARTITION_XINT13_EXTENDED; } else { alignedPtn->Mbr.PartitionType = PARTITION_EXTENDED; } } else { // // We're dealing with a secondary container. This // container should only be big enough to hold the // next logical drive. // alignedPtn->Mbr.PartitionType = PARTITION_EXTENDED; tempIndex = (DWORD) AsrpRoundUp((StartIndex + index), 4); currentMax = 0; for (tempIndex2 = 0; tempIndex2 < 4; tempIndex2++) { tempPtn = &(pSifDisk->pDriveLayoutEx->PartitionEntry[tempIndex + tempIndex2]); if ((PARTITION_ENTRY_UNUSED != tempPtn->Mbr.PartitionType) && !IsContainerPartition(tempPtn->Mbr.PartitionType) ) { if (tempPtn->StartingOffset.QuadPart + tempPtn->PartitionLength.QuadPart > currentMax ) { currentMax = tempPtn->StartingOffset.QuadPart + tempPtn->PartitionLength.QuadPart; } } } if (currentMax > endingOffset) { MYASSERT(AsrpRoundUp(currentMax, bytesPerCylinder) == currentMax); alignedPtn->PartitionLength.QuadPart = currentMax - StartingOffset; endingOffset = currentMax; } } if (nextEnd > maxEndingOffset) { maxEndingOffset = nextEnd; } } if (endingOffset > maxEndingOffset) { maxEndingOffset = endingOffset; } StartingOffset += (alignedPtn->PartitionLength.QuadPart); } else { alignedPtn->StartingOffset.QuadPart = 0; alignedPtn->PartitionLength.QuadPart = 0; } } return maxEndingOffset; } VOID AsrpFreeRegionInfo( IN PASR_REGION_INFO RegionInfo ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_REGION_INFO temp = RegionInfo; HANDLE heapHandle = GetProcessHeap(); while (temp) { RegionInfo = temp->pNext; _AsrpHeapFree(temp); temp = RegionInfo; } } BOOL AsrpIsOkayToErasePartition( IN PPARTITION_INFORMATION_EX pPartitionInfoEx ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { GUID typeGuid = pPartitionInfoEx->Gpt.PartitionType; // // For now, this checks the partition type against all the known ("recognised") // partition types. If the partition type is recognised (except the system partition), // it's okay to erase it. // if (IsEqualGUID(&(typeGuid), &(PARTITION_ENTRY_UNUSED_GUID))) { return TRUE; } if (IsEqualGUID(&(typeGuid), &(PARTITION_SYSTEM_GUID))) { return FALSE; // Cannot erase EFI system partition. } if (IsEqualGUID(&(typeGuid), &(PARTITION_MSFT_RESERVED_GUID))) { return TRUE; } if (IsEqualGUID(&(typeGuid), &(PARTITION_BASIC_DATA_GUID))) { return TRUE; } if (IsEqualGUID(&(typeGuid), &(PARTITION_LDM_METADATA_GUID))) { return TRUE; } if (IsEqualGUID(&(typeGuid), &(PARTITION_LDM_DATA_GUID))) { return TRUE; } // // It is okay to erase other, unrecognised partitions. // return TRUE; } // // Checks if it's okay to erase all the partitions on a disk. Returns TRUE for MBR disks. // Returns TRUE for GPT disks if all the partitions on it are erasable. A partition that // we don't recognise (including OEM partitions, ESP, etc) is considered non-erasable. // BOOL AsrpIsOkayToEraseDisk( IN PASR_DISK_INFO pPhysicalDisk ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { DWORD index; if (PARTITION_STYLE_GPT != pPhysicalDisk->pDriveLayoutEx->PartitionStyle) { return TRUE; } for (index = 0; index < pPhysicalDisk->pDriveLayoutEx->PartitionCount; index++) { if (!AsrpIsOkayToErasePartition(&(pPhysicalDisk->pDriveLayoutEx->PartitionEntry[index]))) { return FALSE; } } return TRUE; } BOOL AsrpInsertSortedRegion( IN OUT PASR_REGION_INFO *Head, IN LONGLONG StartingOffset, IN LONGLONG RegionLength, IN DWORD Index, IN LONGLONG MaxLength, // 0 == don't care IN ASR_SORT_ORDER SortBy ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_REGION_INFO previousRegion = NULL, newRegion = NULL, currentRegion = *Head; if (RegionLength < (1024*1024)) { return TRUE; } // // Alloc mem for the new region and set the fields of interest // newRegion = (PASR_REGION_INFO) HeapAlloc( GetProcessHeap(), HEAP_ZERO_MEMORY, sizeof(ASR_REGION_INFO) ); if (!newRegion) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } newRegion->StartingOffset = StartingOffset; newRegion->RegionLength = RegionLength; newRegion->Index = Index; newRegion->pNext = NULL; if (!currentRegion) { // // First item in the list // *Head = newRegion; } else { while (currentRegion) { if (((SortByLength == SortBy) && (currentRegion->RegionLength <= RegionLength)) || ((SortByStartingOffset == SortBy) && (currentRegion->StartingOffset <= StartingOffset)) ) { previousRegion = currentRegion; currentRegion = currentRegion->pNext; } else { // // We found the spot, let's add it in. // // // If this is sorted based on start sectors, make sure there's // enough space to add this region in, ie that the regions don't overlap. // if (SortByStartingOffset == SortBy) { // // Make sure this is after the end of the previous sector // if (previousRegion) { if ((previousRegion->StartingOffset + previousRegion->RegionLength) > StartingOffset) { return FALSE; } } // // And that this ends before the next sector starts // if ((StartingOffset + RegionLength) > (currentRegion->StartingOffset)) { return FALSE; } } if (!previousRegion) { // // This is the first node // *Head = newRegion; } else { previousRegion->pNext = newRegion; } newRegion->pNext = currentRegion; break; } } if (!currentRegion) { // // We reached the end and didn't add this node in. // MYASSERT(NULL == previousRegion->pNext); // // Make sure this is after the end of the previous sector // if (previousRegion && (MaxLength > 0)) { if ((previousRegion->StartingOffset + previousRegion->RegionLength) > MaxLength) { return FALSE; } } previousRegion->pNext = newRegion; } } return TRUE; } BOOL AsrpBuildFreeRegionList( IN PASR_REGION_INFO PartitionList, OUT PASR_REGION_INFO *FreeList, IN LONGLONG UsableStartingOffset, IN LONGLONG UsableLength ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_REGION_INFO currentRegion = PartitionList, previousRegion = NULL; LONGLONG previousEnd = UsableStartingOffset; while (currentRegion) { if (!AsrpInsertSortedRegion(FreeList, previousEnd, // free region start offset currentRegion->StartingOffset - previousEnd, // free region length, 0, // index--not meaningful for this list 0, SortByLength ) ) { return FALSE; } previousEnd = currentRegion->StartingOffset + currentRegion->RegionLength; currentRegion = currentRegion->pNext; } // // Add space after the last partition till the end of the disk to // our free regions list // return AsrpInsertSortedRegion(FreeList, // list head previousEnd, // free region start offset UsableStartingOffset + UsableLength - previousEnd, // free region length 0, // slot index in the partition entry table--not meaningful for this list 0, SortByLength ); } // // Both partitions and regions are sorted by sizes // BOOL AsrpFitPartitionToFreeRegion( IN PASR_REGION_INFO PartitionList, IN PASR_REGION_INFO FreeRegionList ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_REGION_INFO partition = PartitionList, hole = FreeRegionList; while (partition) { while (hole && (partition->RegionLength > hole->RegionLength)) { hole = hole->pNext; } if (!hole) { // // We ran out of holes and have unassigned partitions // return FALSE; } partition->StartingOffset = hole->StartingOffset; hole->RegionLength -= partition->RegionLength; hole->StartingOffset += partition->RegionLength; partition = partition->pNext; } return TRUE; } // // For optimisation purposes, this routine should only be called if: // PhysicalDisk and SifDisk are both GPT // PhysicalDisk is bigger than SifDisk // PhysicalDisk has non-erasable partitions // BOOL AsrpFitGptPartitionsToRegions( IN PASR_DISK_INFO SifDisk, IN PASR_DISK_INFO PhysicalDisk, IN BOOL Commit ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_REGION_INFO partitionList = NULL, collisionList = NULL, freeRegionList = NULL; LONGLONG StartingUsableOffset = 0, UsableLength = 0; DWORD index = 0; BOOL result = TRUE; if ((PARTITION_STYLE_GPT != SifDisk->Style) || (PARTITION_STYLE_GPT != PhysicalDisk->Style)) { return TRUE; } StartingUsableOffset = PhysicalDisk->pDriveLayoutEx->Gpt.StartingUsableOffset.QuadPart; UsableLength = PhysicalDisk->pDriveLayoutEx->Gpt.UsableLength.QuadPart; // // First, go through the existing non-erasable partitions, and add them to our list // sorted by start sectors. // for (index = 0; index < PhysicalDisk->pDriveLayoutEx->PartitionCount; index++) { if (!AsrpIsOkayToErasePartition(&(PhysicalDisk->pDriveLayoutEx->PartitionEntry[index]))) { PPARTITION_INFORMATION_EX currentPtn = &(PhysicalDisk->pDriveLayoutEx->PartitionEntry[index]); if (!AsrpInsertSortedRegion(&partitionList, currentPtn->StartingOffset.QuadPart, currentPtn->PartitionLength.QuadPart, index, (StartingUsableOffset + UsableLength), SortByStartingOffset )) { result = FALSE; break; } } } if (partitionList && result) { // // Then, go through the sif partitions, and add them to a list, sorted by start sectors. // For partitions that cannot be added, add them to another list sorted by sizes // for (index = 0; index < SifDisk->pDriveLayoutEx->PartitionCount; index++) { PPARTITION_INFORMATION_EX currentPtn = &(SifDisk->pDriveLayoutEx->PartitionEntry[index]); if (!AsrpInsertSortedRegion(&partitionList, currentPtn->StartingOffset.QuadPart, currentPtn->PartitionLength.QuadPart, index, (StartingUsableOffset + UsableLength), SortByStartingOffset )) { if (!AsrpInsertSortedRegion(&collisionList, currentPtn->StartingOffset.QuadPart, currentPtn->PartitionLength.QuadPart, index, 0, SortByLength )) { result = FALSE; break; } } } } if (collisionList && result) { // // Go through first list and come up with a list of free regions, sorted by sizes // result = AsrpBuildFreeRegionList(partitionList, &freeRegionList, StartingUsableOffset, UsableLength); } if (collisionList && result) { // // Try adding partitions from list 2 to regions from list 3. If any // are left over, return FALSE. // result = AsrpFitPartitionToFreeRegion(collisionList, freeRegionList); if (Commit && result) { PASR_REGION_INFO pCurrentRegion = collisionList; // // Go through the collision list, and update the start sectors of the // PartitionEntries in DriveLayoutEx's table. // while (pCurrentRegion) { MYASSERT(SifDisk->pDriveLayoutEx->PartitionEntry[pCurrentRegion->Index].PartitionLength.QuadPart == pCurrentRegion->RegionLength); SifDisk->pDriveLayoutEx->PartitionEntry[pCurrentRegion->Index].StartingOffset.QuadPart = pCurrentRegion->StartingOffset; pCurrentRegion = pCurrentRegion->pNext; } } } AsrpFreeRegionInfo(partitionList); AsrpFreeRegionInfo(collisionList); AsrpFreeRegionInfo(freeRegionList); return result; } BOOL AsrpIsThisDiskABetterFit( IN PASR_DISK_INFO CurrentBest, IN PASR_DISK_INFO PhysicalDisk, IN PASR_DISK_INFO SifDisk, IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx, OUT BOOL *IsAligned ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { LONGLONG endingOffset; if (ARGUMENT_PRESENT(IsAligned)) { *IsAligned = FALSE; } // // Make sure the bytes-per-sector values match // if (PhysicalDisk->pDiskGeometry->BytesPerSector != SifDisk->pDiskGeometry->BytesPerSector) { return FALSE; } if (PhysicalDisk->pPartition0Ex->PartitionLength.QuadPart >= SifDisk->pPartition0Ex->PartitionLength.QuadPart) { if ((!CurrentBest) || (PhysicalDisk->pPartition0Ex->PartitionLength.QuadPart < CurrentBest->pPartition0Ex->PartitionLength.QuadPart)) { // // This disk is smaller than our current best (or we don't have a // current best). Now try laying out the partitions to see if // they fit. // if (PARTITION_STYLE_GPT == SifDisk->Style) { // // If the disk has no partitions that need to be preserved, // we can use all of it. if (AsrpIsOkayToEraseDisk(PhysicalDisk)) { return TRUE; } else { // // This disk has some regions that need to be preserved. So // we try to fit our partitions in the holes // return AsrpFitGptPartitionsToRegions(SifDisk, PhysicalDisk, FALSE); // No commmit } } else if (PARTITION_STYLE_MBR == SifDisk->Style) { if (!pTempDriveLayoutEx) { // // Caller doesn't want to try cylinder-aligning partitions // return TRUE; } // // For MBR disks, the partitions have to be cylinder aligned // // AsrpCylinderAlignMbrPartitions(,,0,,) returns the ending offset (bytes) // of the entries in the MBR. // endingOffset = AsrpCylinderAlignMbrPartitions(SifDisk, pTempDriveLayoutEx, 0, // starting index--0 for the MBR 0, // starting offset, assume the partitions begin at the start of the disk PhysicalDisk->pDiskGeometry ); if ((endingOffset != -1) && (endingOffset <= SifDisk->pPartition0Ex->PartitionLength.QuadPart) ) { if (ARGUMENT_PRESENT(IsAligned)) { *IsAligned = TRUE; } return TRUE; } else { // // We couldn't fit the partitions on to the disk when we // tried to cylinder align them. If the disk geometries // are the same, this may still be okay. // if ((SifDisk->pDiskGeometry->BytesPerSector == PhysicalDisk->pDiskGeometry->BytesPerSector) && (SifDisk->pDiskGeometry->SectorsPerTrack == PhysicalDisk->pDiskGeometry->SectorsPerTrack) && (SifDisk->pDiskGeometry->TracksPerCylinder == PhysicalDisk->pDiskGeometry->TracksPerCylinder) ) { return TRUE; } else { return FALSE; } } } else { MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)"); } } } return FALSE; } // // Assigns sif-disks to physical disks with matching signatures, if // any exist. If the disk is critical, or the partition-layout matches, // the disk is marked as intact. // // Returns // FALSE if a critical disk is absent // TRUE if all critical disks are present // BOOL AsrpAssignBySignature( IN OUT PASR_DISK_INFO pSifDiskList, IN OUT PASR_DISK_INFO pPhysicalDiskList, OUT PULONG pMaxPartitionCount ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { BOOL result = TRUE, done = FALSE, found = FALSE, isAligned = FALSE; PASR_DISK_INFO sifDisk = pSifDiskList, physicalDisk = pPhysicalDiskList; PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutTemp = NULL; ULONG tableSize = 128; // start off at a reasonably high size HANDLE heapHandle = GetProcessHeap(); pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DRIVE_LAYOUT_INFORMATION) + (tableSize * sizeof(PARTITION_INFORMATION_EX)) ); if (!pAlignedLayoutTemp) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); result = FALSE; goto EXIT; } *pMaxPartitionCount = 0; // // For now, this is O(n-squared), since both lists are unsorted. // while (sifDisk && !done) { if (!(sifDisk->pDriveLayoutEx) || !(sifDisk->pDriveLayoutEx->Mbr.Signature)) { // // we won't assign disks with no signature here // sifDisk = sifDisk->pNext; continue; } if (sifDisk->pDriveLayoutEx->PartitionCount > *pMaxPartitionCount) { *pMaxPartitionCount = sifDisk->pDriveLayoutEx->PartitionCount; } if (sifDisk->pDriveLayoutEx->PartitionCount > tableSize) { tableSize = sifDisk->pDriveLayoutEx->PartitionCount + 128; _AsrpHeapFree(pAlignedLayoutTemp); pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DRIVE_LAYOUT_INFORMATION) + (tableSize * sizeof(PARTITION_INFORMATION_EX)) ); if (!pAlignedLayoutTemp) { SetLastError(ERROR_NOT_ENOUGH_MEMORY); result = FALSE; goto EXIT; } } found = FALSE; physicalDisk = pPhysicalDiskList; while (physicalDisk && !found) { // // For MBR disks, we use the signature // For GPT disks, we use the disk ID // if (sifDisk->Style == physicalDisk->Style) { if ((PARTITION_STYLE_MBR == sifDisk->Style) && (physicalDisk->pDriveLayoutEx->Mbr.Signature == sifDisk->pDriveLayoutEx->Mbr.Signature) ) { // // MBR disks, signatures match // found = TRUE; AsrpPrintDbgMsg(_asrlog, "Harddisk %lu matched disk %lu in section [%ws] of the ASR state file. (MBR signatures 0x%x match).\r\n", physicalDisk->DeviceNumber, sifDisk->SifDiskKey, ASR_SIF_MBR_DISKS_SECTION, sifDisk->pDriveLayoutEx->Mbr.Signature ); } else if ( (PARTITION_STYLE_GPT == sifDisk->Style) && IsEqualGUID(&(sifDisk->pDriveLayoutEx->Gpt.DiskId), &(physicalDisk->pDriveLayoutEx->Gpt.DiskId)) ) { found = TRUE; AsrpPrintDbgMsg(_asrlog, "Harddisk %lu matched disk %lu in section [%ws] of the ASR state file. (GPT Disk-ID's match).\r\n", physicalDisk->DeviceNumber, sifDisk->SifDiskKey, ASR_SIF_GPT_DISKS_SECTION ); } else { physicalDisk = physicalDisk->pNext; } } else { physicalDisk = physicalDisk->pNext; } } if (sifDisk->IsCritical) { if (found) { sifDisk->AssignedTo = physicalDisk; physicalDisk->AssignedTo = sifDisk; // // We don't check the partition layout on critical disks since they // may have been repartitioned in text-mode Setup. // sifDisk->IsIntact = TRUE; sifDisk->AssignedTo->IsIntact = TRUE; } else { // // Critical disk was not found. Fatal error. // SetLastError(ERROR_DEVICE_NOT_CONNECTED); result = FALSE; done = TRUE; AsrpPrintDbgMsg(_asrerror, "Critical disk not found (Entry %lu in section [%ws]).\r\n", sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); } } else { if (found) { // // We found a disk with matching signature. Now let's just // make sure that the partitions actually fit on the disk // before assigning it // isAligned = FALSE; if ((sifDisk->pDriveLayoutEx->PartitionCount == 0) || // disk has no partitions AsrpIsThisDiskABetterFit(NULL, physicalDisk, sifDisk, pAlignedLayoutTemp, &isAligned) // partitions fit on disk ) { sifDisk->AssignedTo = physicalDisk; physicalDisk->AssignedTo = sifDisk; sifDisk->IsAligned = isAligned; physicalDisk->IsAligned = isAligned; if (AsrpIsDiskIntact(sifDisk, physicalDisk)) { sifDisk->IsIntact = TRUE; sifDisk->AssignedTo->IsIntact = TRUE; } } else { AsrpPrintDbgMsg(_asrlog, "Harddisk %lu is not big enough to contain the partitions on disk %lu in section [%ws] of the ASR state file.\r\n", physicalDisk->DeviceNumber, sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); } } } sifDisk = sifDisk->pNext; } // while EXIT: _AsrpHeapFree(pAlignedLayoutTemp); return result; } // // Attempts to assign remaining sif disks to physical disks that // are on the same bus as the sif disk originally was (ie if // any other disk on that bus has been assigned, this tries to assign // this disk to the same bus) // BOOL AsrpAssignByBus( IN OUT PASR_DISK_INFO pSifDiskList, IN OUT PASR_DISK_INFO pPhysicalDiskList, IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_DISK_INFO sifDisk = pSifDiskList, physicalDisk = NULL, currentBest = NULL, tempSifDisk = NULL; BOOL done = FALSE, isAligned = FALSE, isAlignedTemp = FALSE; ULONG targetBusId = 0; while (sifDisk) { // // Skip disks that have already found a home, and disks for which // we didn't have any bus/group info even on the original system // if ((NULL != sifDisk->AssignedTo) || // already assigned (0 == sifDisk->SifBusKey) // this disk couldn't be grouped ) { sifDisk = sifDisk->pNext; continue; } // // Find another (sif) disk that used to be on the same (sif) bus, // and has already been assigned to a physical disk. // targetBusId = 0; tempSifDisk = pSifDiskList; done = FALSE; while (tempSifDisk && !done) { if ((tempSifDisk->SifBusKey == sifDisk->SifBusKey) && // same bus (tempSifDisk->AssignedTo != NULL) // assigned ) { targetBusId = tempSifDisk->AssignedTo->SifBusKey; // the physical bus // // If this physical disk is on an unknown bus, // (target id = sifbuskey = 0) then we want to try and look // for another disk on the same (sif) bus. Hence done is // TRUE only if targetId != 0 // if (targetBusId) { done = TRUE; } } tempSifDisk = tempSifDisk->pNext; } // while if (targetBusId) { // we found another disk on the same bus // // Go through the physical disks on the same bus, and try to // find the best fit for this disk. Best fit is the smallest // disk on the bus that's big enough for us. // physicalDisk = pPhysicalDiskList; currentBest = NULL; while (physicalDisk) { if ((NULL == physicalDisk->AssignedTo) && // not assigned (physicalDisk->SifBusKey == targetBusId) && // same bus (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp)) ) { isAligned = isAlignedTemp; currentBest = physicalDisk; } physicalDisk = physicalDisk->pNext; } // while sifDisk->AssignedTo = currentBest; // may be null if no match was found sifDisk->IsAligned = isAligned; if (currentBest) { currentBest->AssignedTo = sifDisk; currentBest->IsAligned = isAligned; AsrpPrintDbgMsg(_asrlog, "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on storage bus).\r\n", currentBest->DeviceNumber, sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); } } sifDisk = sifDisk->pNext; } // while sifdisk return TRUE; } // // Attempts to assign remaining sif disks to physical disks that // are on any bus of the same type (SCSI, IDE, etc) as the sif disk // originally was // BOOL AsrpAssignByBusType( IN OUT PASR_DISK_INFO pSifDiskList, IN OUT PASR_DISK_INFO pPhysicalDiskList, IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_DISK_INFO sifDisk = pSifDiskList, physicalDisk = NULL, currentBest = NULL; STORAGE_BUS_TYPE targetBusType; BOOL isAligned = FALSE, isAlignedTemp = FALSE; while (sifDisk) { // // Skip disks that have already found a home, and disks for which // we didn't have any bus/group info even on the original system // if ((NULL != sifDisk->AssignedTo) || // already assigned (BusTypeUnknown == sifDisk->BusType) // this disk couldn't be grouped ) { sifDisk = sifDisk->pNext; continue; } // // Go through the physical disks, and try to // find the best fit for this disk. Best fit is the smallest // disk on any bus of the same bus type that's big enough for us. // physicalDisk = pPhysicalDiskList; currentBest = NULL; while (physicalDisk) { if ((NULL == physicalDisk->AssignedTo) && // not assigned (physicalDisk->BusType == sifDisk->BusType) && // same bus type (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp)) ) { isAligned = isAlignedTemp; currentBest = physicalDisk; } physicalDisk = physicalDisk->pNext; } // while sifDisk->AssignedTo = currentBest; // may be null if no match was found sifDisk->IsAligned = isAligned; if (currentBest) { currentBest->AssignedTo = sifDisk; currentBest->IsAligned = isAligned; AsrpPrintDbgMsg(_asrlog, "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on storage bus type).\r\n", currentBest->DeviceNumber, sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx); } sifDisk = sifDisk->pNext; } // while sifdisk return TRUE; } // // Okay, so by now we've tried putting disks on the same bus, and // the same bus type. For disks that didn't fit using either of those // rules (or for which we didn't have any bus info at all), let's just // try to fit them where ever possible on the system. // BOOL AsrpAssignRemaining( IN OUT PASR_DISK_INFO pSifDiskList, IN OUT PASR_DISK_INFO pPhysicalDiskList, IN PDRIVE_LAYOUT_INFORMATION_EX pTempDriveLayoutEx ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_DISK_INFO sifDisk = pSifDiskList, physicalDisk = NULL, currentBest = NULL; BOOL isAligned = FALSE, isAlignedTemp = FALSE; while (sifDisk) { // // Skip disks that have already found a home // if (NULL != sifDisk->AssignedTo) { sifDisk = sifDisk->pNext; continue; } // // Go through the physical disks, and try to find the best // fit for this disk. Best fit is the smallest disk anywhere // on the system that's big enough for us. // physicalDisk = pPhysicalDiskList; currentBest = NULL; while (physicalDisk) { if ((NULL == physicalDisk->AssignedTo) && // not assigned (AsrpIsThisDiskABetterFit(currentBest, physicalDisk, sifDisk, pTempDriveLayoutEx, &isAlignedTemp)) ) { isAligned = isAlignedTemp; currentBest = physicalDisk; } physicalDisk = physicalDisk->pNext; } // while sifDisk->AssignedTo = currentBest; // may be null if no match was found sifDisk->IsAligned = isAligned; if (currentBest) { currentBest->AssignedTo = sifDisk; currentBest->IsAligned = isAligned; AsrpPrintDbgMsg(_asrlog, "Harddisk %lu assigned to disk %lu in section [%ws] of the ASR state file. (Based on size).\r\n", currentBest->DeviceNumber, sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx); AsrpAssignByBusType(pSifDiskList, pPhysicalDiskList, pTempDriveLayoutEx); } sifDisk = sifDisk->pNext; } // while sifdisk return TRUE; } BOOL AsrpIsPartitionExtendible( IN CONST UCHAR PartitionType ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { switch (PartitionType) { case PARTITION_EXTENDED: case PARTITION_IFS: case PARTITION_XINT13: case PARTITION_XINT13_EXTENDED: return TRUE; default: return FALSE; } return FALSE; } BOOL AsrpAutoExtendMbrPartitions( IN PASR_DISK_INFO pSifDisk, IN PASR_DISK_INFO pPhysicalDisk, IN LONGLONG LastUsedPhysicalDiskOffset ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PDISK_GEOMETRY physicalGeometry = NULL; IN PDRIVE_LAYOUT_INFORMATION_EX sifLayout = NULL, physicalLayout = NULL; LONGLONG MaxSifDiskOffset = 0, MaxPhysicalDiskOffset = 0, LastUsedSifDiskOffset = 0; DWORD count = 0; BOOL madeAChange = FALSE; // // Find the last sector of the disk // MaxSifDiskOffset = pSifDisk->pPartition0Ex->PartitionLength.QuadPart; physicalGeometry = pPhysicalDisk->pDiskGeometry; MaxPhysicalDiskOffset = (physicalGeometry->BytesPerSector) * (physicalGeometry->SectorsPerTrack) * (physicalGeometry->TracksPerCylinder) * (physicalGeometry->Cylinders.QuadPart); // // Did the old disk have empty space at the end? // sifLayout = pSifDisk->pDriveLayoutEx; for (count = 0; count < sifLayout->PartitionCount; count++) { if (((sifLayout->PartitionEntry[count].StartingOffset.QuadPart) + (sifLayout->PartitionEntry[count].PartitionLength.QuadPart)) > LastUsedSifDiskOffset) { LastUsedSifDiskOffset = (sifLayout->PartitionEntry[count].StartingOffset.QuadPart + sifLayout->PartitionEntry[count].PartitionLength.QuadPart); } } if ((LastUsedSifDiskOffset + ASR_AUTO_EXTEND_MAX_FREE_SPACE_IGNORED) >= MaxSifDiskOffset) { // // No, it didn't. Extend the last partition. // physicalLayout = pPhysicalDisk->pDriveLayoutEx; for (count = 0; count < physicalLayout->PartitionCount; count++) { if (((physicalLayout->PartitionEntry[count].StartingOffset.QuadPart) + (physicalLayout->PartitionEntry[count].PartitionLength.QuadPart)) == LastUsedPhysicalDiskOffset ) { if (AsrpIsPartitionExtendible(physicalLayout->PartitionEntry[count].Mbr.PartitionType)) { physicalLayout->PartitionEntry[count].PartitionLength.QuadPart += (MaxPhysicalDiskOffset - LastUsedPhysicalDiskOffset); madeAChange = TRUE; } } } } if (madeAChange) { AsrpPrintDbgMsg(_asrlog, "Extended partitions on Harddisk %lu (assigned to disk %lu in section [%ws]).\r\n", pPhysicalDisk->DeviceNumber, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); } else { AsrpPrintDbgMsg(_asrinfo, "Did not extend partitions on Harddisk %lu (assigned to disk %lu in section [%ws]).\r\n", pPhysicalDisk->DeviceNumber, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); } return madeAChange; } // // Try to determine which sif disks end up on which physical disk. // BOOL AsrpAssignDisks( IN OUT PASR_DISK_INFO pSifDiskList, IN OUT PASR_DISK_INFO pPhysicalDiskList, IN PASR_PTN_INFO_LIST pSifMbrPtnList, IN PASR_PTN_INFO_LIST pSifGptPtnList, IN BOOL AllOrNothing, IN BOOL AllowAutoExtend ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { ULONG maxSifPartitionCount = 0; PDRIVE_LAYOUT_INFORMATION_EX pAlignedLayoutTemp = NULL; LONGLONG endingOffset = 0; BOOL reAlloc = TRUE; HANDLE heapHandle = GetProcessHeap(); PASR_DISK_INFO sifDisk = NULL; PASR_PTN_INFO pCurrentPtn = NULL; PPARTITION_INFORMATION_EX pCurrentEntry = NULL; DWORD index = 0, preserveIndex = 0; if (!AsrpAssignBySignature(pSifDiskList, pPhysicalDiskList, &maxSifPartitionCount)) { // // Critical disks were not found // return FALSE; } pAlignedLayoutTemp = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DRIVE_LAYOUT_INFORMATION) + (maxSifPartitionCount * sizeof(PARTITION_INFORMATION_EX)) ); if (!pAlignedLayoutTemp) { return FALSE; } AsrpAssignByBus(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp); AsrpAssignByBusType(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp); AsrpAssignRemaining(pSifDiskList, pPhysicalDiskList, pAlignedLayoutTemp); _AsrpHeapFree(pAlignedLayoutTemp); // // All disks should be assigned by now, we now cylinder-snap // the partition boundaries. If AllOrNothing is TRUE, // we return false if any sif-disk couldn't be assigned. // sifDisk = pSifDiskList; while (sifDisk) { if (sifDisk->IsIntact || sifDisk->IsCritical) { // // We won't be re-partitioning critical disks or disks that are // intact, so it's no point trying to cylinder-align them. // sifDisk = sifDisk->pNext; continue; } if (NULL == sifDisk->AssignedTo) { AsrpPrintDbgMsg(_asrlog, "Disk %lu in section [%ws] could not be restored (no matching disks found).\r\n", sifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == sifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); // // This disk couldn't be assigned. If AllOrNothing is set, we return // FALSE, since we couldn't assign All. // if (AllOrNothing) { SetLastError(ERROR_NOT_FOUND); return FALSE; } else { sifDisk = sifDisk->pNext; continue; } } if (PARTITION_STYLE_MBR == sifDisk->Style) { // // Assume that we need to re-allocate mem for the physical disk's // partition table. // reAlloc = TRUE; if (sifDisk->AssignedTo->pDriveLayoutEx) { if (sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount == sifDisk->pDriveLayoutEx->PartitionCount) { // // If the physical drive happened to have the same number of // partitions, the drive layout struct is exactly the right // size, so we don't have to re-allocate it. // reAlloc = FALSE; // // consistency check. If the partition counts are // the same, the size of the drive layout stucts must be the same, too. // MYASSERT(sifDisk->AssignedTo->sizeDriveLayoutEx == sifDisk->sizeDriveLayoutEx); } } if (reAlloc) { // // The partition tables are of different sizes // _AsrpHeapFree(sifDisk->AssignedTo->pDriveLayoutEx); sifDisk->AssignedTo->pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(DRIVE_LAYOUT_INFORMATION_EX) + ((sifDisk->pDriveLayoutEx->PartitionCount - 1) * sizeof(PARTITION_INFORMATION_EX)) ); if (!sifDisk->AssignedTo->pDriveLayoutEx) { AsrpPrintDbgMsg(_asrerror, "Out of memory.\r\n"); SetLastError(ERROR_NOT_ENOUGH_MEMORY); return FALSE; } } // // Set the fields of interest // sifDisk->AssignedTo->sizeDriveLayoutEx = sifDisk->sizeDriveLayoutEx; sifDisk->AssignedTo->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_MBR; if (sifDisk->IsAligned) { sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount = sifDisk->pDriveLayoutEx->PartitionCount; sifDisk->AssignedTo->pDriveLayoutEx->Mbr.Signature = sifDisk->pDriveLayoutEx->Mbr.Signature; // // Cylinder-snap the partition boundaries // endingOffset = AsrpCylinderAlignMbrPartitions( sifDisk, sifDisk->AssignedTo->pDriveLayoutEx, 0, // starting index--0 for the MBR 0, // starting offset, assume the partitions begin at the start of the disk sifDisk->AssignedTo->pDiskGeometry ); MYASSERT(endingOffset != -1); if (-1 == endingOffset) { AsrpPrintDbgMsg(_asrlog, "Partitions on disk %lu in section [%ws] could not be restored.\r\n", sifDisk->SifDiskKey, ASR_SIF_MBR_DISKS_SECTION ); if (AllOrNothing) { SetLastError(ERROR_HANDLE_DISK_FULL); return FALSE; } else { sifDisk = sifDisk->pNext; continue; } } MYASSERT(endingOffset <= sifDisk->AssignedTo->pPartition0Ex->PartitionLength.QuadPart); if ((endingOffset) > (sifDisk->AssignedTo->pPartition0Ex->PartitionLength.QuadPart)) { AsrpPrintDbgMsg(_asrlog, "Partitions on disk %lu in section [%ws] could not be restored.\r\n", sifDisk->SifDiskKey, ASR_SIF_MBR_DISKS_SECTION ); if (AllOrNothing) { SetLastError(ERROR_HANDLE_DISK_FULL); return FALSE; } else { sifDisk = sifDisk->pNext; continue; } } if (AllowAutoExtend) { AsrpAutoExtendMbrPartitions(sifDisk, sifDisk->AssignedTo, endingOffset); } // // Now, we need to go through our partition list, and update the start sector // for the partitions in that list. This is needed since we use the start // sector later to assign the volume guids to the partitions. // pCurrentPtn = pSifMbrPtnList[sifDisk->SifDiskKey].pOffsetHead; while (pCurrentPtn) { pCurrentPtn->PartitionInfo.StartingOffset.QuadPart = sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].StartingOffset.QuadPart; pCurrentPtn->PartitionInfo.PartitionLength.QuadPart = sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].PartitionLength.QuadPart; pCurrentPtn = pCurrentPtn->pOffsetNext; } } else { // // The partitions didn't fit when we cylinder-aligned them. // However, the current disk geometry is identical to the // original disk geometry, so we can recreate the partitions // exactly the way they were before. Let's just copy over // the partition layout. // CopyMemory(sifDisk->AssignedTo->pDriveLayoutEx, sifDisk->pDriveLayoutEx, sifDisk->sizeDriveLayoutEx ); for (index = 0; index < sifDisk->pDriveLayoutEx->PartitionCount; index++) { sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index].RewritePartition = TRUE; } } } else if (PARTITION_STYLE_GPT == sifDisk->Style) { DWORD sizeNewDriveLayoutEx = 0; PDRIVE_LAYOUT_INFORMATION_EX pNewDriveLayoutEx = NULL; /* The MaxPartitionCount values are different for the two disks. We can't do much here, so we'll just ignore it. if ((PARTITION_STYLE_GPT == sifDisk->AssignedTo->Style) && (sifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount > sifDisk->AssignedTo->pDriveLayoutEx->Gpt.MaxPartitionCount)) { MYASSERT(0 && L"Not yet implemented: sifdisk MaxPartitionCount > physicalDisk->MaxPartitionCount"); sifDisk = sifDisk->pNext; continue; } */ // // Allocate a pDriveLayoutEx struct large enough to hold all the partitions on both // the sif disk and the physical disk. // sizeNewDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * (sifDisk->pDriveLayoutEx->PartitionCount + sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount - 1 ) ); pNewDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeNewDriveLayoutEx ); if (!pNewDriveLayoutEx) { return FALSE; } preserveIndex = 0; if (!sifDisk->IsIntact && !AsrpIsOkayToEraseDisk(sifDisk->AssignedTo)) { // // This disk is not intact, but it has partitions that must be preserved. // if (!AsrpFitGptPartitionsToRegions(sifDisk, sifDisk->AssignedTo, TRUE)) { AsrpPrintDbgMsg(_asrlog, "Partitions on disk %lu in section [%ws] could not be restored.\r\n", sifDisk->SifDiskKey, ASR_SIF_GPT_DISKS_SECTION ); MYASSERT(0 && L"AsrpFitGptPartitionsToRegions failed for assigned disk"); if (AllOrNothing) { SetLastError(ERROR_HANDLE_DISK_FULL); return FALSE; } else { sifDisk = sifDisk->pNext; continue; } } // // Now, we need to go through our partition list, and update the start sector // for the partitions in that list. This is needed since we use the start // sector later to assign the volume guids to the partitions. // // The start sectors could've changed because the physical disk may have had // un-erasable partitions. // pCurrentPtn = pSifGptPtnList[sifDisk->SifDiskKey].pOffsetHead; while (pCurrentPtn) { pCurrentPtn->PartitionInfo.StartingOffset.QuadPart = sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].StartingOffset.QuadPart; pCurrentPtn->PartitionInfo.PartitionLength.QuadPart = sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[pCurrentPtn->SlotIndex].PartitionLength.QuadPart; pCurrentPtn = pCurrentPtn->pOffsetNext; } // // Move the non-erasable partitions on the physical disks up to the beginning. // for (index = 0; index < sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount; index++) { pCurrentEntry = &(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index]); if (!AsrpIsOkayToErasePartition(pCurrentEntry)) { if (preserveIndex == index) { preserveIndex++; continue; } memmove(&(pNewDriveLayoutEx->PartitionEntry[preserveIndex]), &(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[index]), sizeof(PARTITION_INFORMATION_EX) ); preserveIndex++; } else { // // This partition can be erased. // pCurrentEntry->StartingOffset.QuadPart = 0; pCurrentEntry->PartitionLength.QuadPart = 0; } } // for } // if !IsIntact // // Now that we've copied over entries of interest to the new // drivelayoutex struct, we can get rid of the old one. // _AsrpHeapFree(sifDisk->AssignedTo->pDriveLayoutEx); sifDisk->AssignedTo->sizeDriveLayoutEx = sizeNewDriveLayoutEx; sifDisk->AssignedTo->pDriveLayoutEx = pNewDriveLayoutEx; // // Copy over the sif partition table to the physicalDisk // memcpy(&(sifDisk->AssignedTo->pDriveLayoutEx->PartitionEntry[preserveIndex]), &(sifDisk->pDriveLayoutEx->PartitionEntry[0]), sizeof(PARTITION_INFORMATION_EX) * (sifDisk->pDriveLayoutEx->PartitionCount) ); sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount = sifDisk->pDriveLayoutEx->PartitionCount + preserveIndex; sifDisk->AssignedTo->sizeDriveLayoutEx = sizeof(DRIVE_LAYOUT_INFORMATION_EX) + (sizeof(PARTITION_INFORMATION_EX) * (sifDisk->AssignedTo->pDriveLayoutEx->PartitionCount - 1)); sifDisk->AssignedTo->pDriveLayoutEx->PartitionStyle = PARTITION_STYLE_GPT; memcpy(&(sifDisk->AssignedTo->pDriveLayoutEx->Gpt.DiskId), &(sifDisk->pDriveLayoutEx->Gpt.DiskId), sizeof(GUID) ); } else { MYASSERT(0 && L"Unrecognised partitioning style (neither MBR nor GPT)"); } sifDisk = sifDisk->pNext; } return TRUE; } BOOL AsrpCreateMountPoint( IN DWORD DiskNumber, IN DWORD PartitionNumber, IN PCWSTR szVolumeGuid ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PMOUNTMGR_CREATE_POINT_INPUT inputCreatePoint = NULL; PMOUNTMGR_MOUNT_POINT inputDeletePoint = NULL; PMOUNTMGR_MOUNT_POINTS outputDeletePoint = NULL; WCHAR deviceName[ASR_CCH_DEVICE_PATH_FORMAT]; PMOUNTMGR_MOUNT_POINTS mountPointsOut = NULL; INT attempt = 0; DWORD cbName = 0; PWSTR lpName = NULL; DWORD cbDeletePoint = 0; USHORT sizeGuid = 0, sizeDeviceName = 0; DWORD bytes = 0, index = 0, status = ERROR_SUCCESS; HANDLE mpHandle = NULL, heapHandle = GetProcessHeap(); BOOL result = TRUE; if (!szVolumeGuid || !wcslen(szVolumeGuid)) { return TRUE; } // // Open the mount manager // mpHandle = CreateFileW( (PCWSTR) MOUNTMGR_DOS_DEVICE_NAME, // lpFileName GENERIC_READ | GENERIC_WRITE, // dwDesiredAccess FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode NULL, // lpSecurityAttributes OPEN_EXISTING, // dwCreationFlags FILE_ATTRIBUTE_NORMAL, // dwFlagsAndAttributes INVALID_HANDLE_VALUE // hTemplateFile ); _AsrpErrExitCode((!mpHandle || INVALID_HANDLE_VALUE == mpHandle), status, GetLastError()); swprintf(deviceName, ASR_WSZ_DEVICE_PATH_FORMAT, DiskNumber, PartitionNumber); sizeDeviceName = wcslen(deviceName) * sizeof(WCHAR); sizeGuid = wcslen(szVolumeGuid) * sizeof(WCHAR); // // There is a small window after a partition is created in which the // device-path to it (\Device\HarddiskX\PartitionY) doesn't exist, and // a small window in which the device-path is actually pointing to // the wrong object. (Partmgr first creates the path, , // assigns it to the correct object) // // Since this will cause CREATE_POINT to fail later with FILE_NOT_FOUND, // lets wait till mountmgr sees the device object. // result = FALSE; while ((!result) && (++attempt < 120)) { result = AsrpGetMountPoints(deviceName, sizeDeviceName + sizeof(WCHAR), &mountPointsOut); if (!result) { Sleep(500); } } outputDeletePoint = (PMOUNTMGR_MOUNT_POINTS) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, ASR_BUFFER_SIZE ); _AsrpErrExitCode(!outputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY); // // The mountmgr assigns a volume-GUID symbolic link (\??\Volume{Guid}) to // a basic partition as soon as it's created. In addition, we will re- // create the symbolic link that the partition originally used to have // (as stored in asr.sif). // // This will lead to the partition having two volume-GUID's at the end. // This is wasteful, but generally harmless to the system--however, the // ASR test verification scripts get numerous false hits because of the // additional GUID. // // To fix this, we delete the new mountmgr assigned-GUID before restoring // the original GUID for the partition from asr.sif. // if ((result) && (mountPointsOut)) { for (index = 0; index < mountPointsOut->NumberOfMountPoints; index++) { lpName = (PWSTR) (((LPBYTE)mountPointsOut) + mountPointsOut->MountPoints[index].SymbolicLinkNameOffset); cbName = (DWORD) mountPointsOut->MountPoints[index].SymbolicLinkNameLength; if (!_AsrpIsVolumeGuid(lpName, cbName)) { continue; } // // We found a link that looks like a volume GUID // cbDeletePoint = sizeof(MOUNTMGR_MOUNT_POINT) + mountPointsOut->MountPoints[index].SymbolicLinkNameLength + mountPointsOut->MountPoints[index].UniqueIdLength + mountPointsOut->MountPoints[index].DeviceNameLength; inputDeletePoint = (PMOUNTMGR_MOUNT_POINT) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, cbDeletePoint ); _AsrpErrExitCode(!inputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY); // // Set the fields to match the current link // inputDeletePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); inputDeletePoint->SymbolicLinkNameLength = mountPointsOut->MountPoints[index].SymbolicLinkNameLength; CopyMemory( ((LPBYTE)inputDeletePoint) + inputDeletePoint->SymbolicLinkNameOffset, ((LPBYTE)mountPointsOut) + mountPointsOut->MountPoints[index].SymbolicLinkNameOffset, inputDeletePoint->SymbolicLinkNameLength); inputDeletePoint->UniqueIdOffset = inputDeletePoint->SymbolicLinkNameOffset + inputDeletePoint->SymbolicLinkNameLength; inputDeletePoint->UniqueIdLength = mountPointsOut->MountPoints[index].UniqueIdLength; CopyMemory( ((LPBYTE)inputDeletePoint) + inputDeletePoint->UniqueIdOffset, ((LPBYTE)mountPointsOut) + mountPointsOut->MountPoints[index].UniqueIdOffset, inputDeletePoint->UniqueIdLength); inputDeletePoint->DeviceNameOffset = inputDeletePoint->UniqueIdOffset + inputDeletePoint->UniqueIdLength; inputDeletePoint->DeviceNameLength = mountPointsOut->MountPoints[index].DeviceNameLength; CopyMemory(( (LPBYTE)inputDeletePoint) + inputDeletePoint->DeviceNameOffset, ((LPBYTE)mountPointsOut) + mountPointsOut->MountPoints[index].DeviceNameOffset, inputDeletePoint->DeviceNameLength); // // And delete this link ... // result = DeviceIoControl( mpHandle, IOCTL_MOUNTMGR_DELETE_POINTS, inputDeletePoint, cbDeletePoint, outputDeletePoint, ASR_BUFFER_SIZE, &bytes, NULL ); // // It's okay if the delete fails. // GetLastError(); // for debug _AsrpHeapFree(inputDeletePoint); } } // // Alloc the MountMgr points we need // inputCreatePoint = (PMOUNTMGR_CREATE_POINT_INPUT) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof (MOUNTMGR_CREATE_POINT_INPUT) + sizeDeviceName + sizeGuid ); _AsrpErrExitCode(!inputCreatePoint, status, ERROR_NOT_ENOUGH_MEMORY); inputDeletePoint = (PMOUNTMGR_MOUNT_POINT) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeof(MOUNTMGR_MOUNT_POINT) + sizeGuid ); _AsrpErrExitCode(!inputDeletePoint, status, ERROR_NOT_ENOUGH_MEMORY); // // We should delete this volume guid if some other partition // already has it, else we'll get an ALREADY_EXISTS error // when we try to create it. // inputDeletePoint->DeviceNameOffset = 0; inputDeletePoint->DeviceNameLength = 0; inputDeletePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_MOUNT_POINT); inputDeletePoint->SymbolicLinkNameLength = sizeGuid; CopyMemory((((LPBYTE)inputDeletePoint) + inputDeletePoint->SymbolicLinkNameOffset), ((LPBYTE)szVolumeGuid), inputDeletePoint->SymbolicLinkNameLength ); result = DeviceIoControl( mpHandle, IOCTL_MOUNTMGR_DELETE_POINTS, inputDeletePoint, sizeof (MOUNTMGR_MOUNT_POINT) + sizeGuid, outputDeletePoint, ASR_BUFFER_SIZE, &bytes, NULL ); // // It's okay if this fails. // // _AsrpErrExitCode(!result, status, GetLastError()); GetLastError(); // for Debug // // Call IOCTL_MOUNTMGR_CREATE_POINT // inputCreatePoint->SymbolicLinkNameOffset = sizeof(MOUNTMGR_CREATE_POINT_INPUT); inputCreatePoint->SymbolicLinkNameLength = sizeGuid; inputCreatePoint->DeviceNameOffset = inputCreatePoint->SymbolicLinkNameOffset + inputCreatePoint->SymbolicLinkNameLength; inputCreatePoint->DeviceNameLength = sizeDeviceName; CopyMemory(((LPBYTE)inputCreatePoint) + inputCreatePoint->SymbolicLinkNameOffset, szVolumeGuid, inputCreatePoint->SymbolicLinkNameLength); CopyMemory(((LPBYTE)inputCreatePoint) + inputCreatePoint->DeviceNameOffset, deviceName, inputCreatePoint->DeviceNameLength); result = DeviceIoControl( mpHandle, IOCTL_MOUNTMGR_CREATE_POINT, inputCreatePoint, sizeof (MOUNTMGR_CREATE_POINT_INPUT) + sizeDeviceName + sizeGuid, NULL, 0, &bytes, NULL ); _AsrpErrExitCode(!result, status, GetLastError()); // // We're done. // EXIT: _AsrpCloseHandle(mpHandle); _AsrpHeapFree(mountPointsOut); _AsrpHeapFree(inputCreatePoint); _AsrpHeapFree(inputDeletePoint); _AsrpHeapFree(outputDeletePoint); return (BOOL) (ERROR_SUCCESS == status); } // // Assigns the volume guid's stored in the partition-list to partitions // on the physical disk, based on the start sectors // BOOL AsrpAssignVolumeGuids( IN PASR_DISK_INFO pPhysicalDisk, IN HANDLE hDisk, // open handle to the physical disk IN PASR_PTN_INFO pPtnInfo // list of partitions--with vol guids ... ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PDRIVE_LAYOUT_INFORMATION_EX pDriveLayoutEx = NULL; DWORD sizeDriveLayoutEx = pPhysicalDisk->sizeDriveLayoutEx; DWORD index = 0, status = ERROR_SUCCESS, bytes = 0; BOOL result = FALSE, found = FALSE; PASR_PTN_INFO currentPtn = NULL; HANDLE heapHandle = GetProcessHeap(); // // Get the new layout for the physical disk. // pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeDriveLayoutEx ); _AsrpErrExitCode(!pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY); while (!result) { result = DeviceIoControl( hDisk, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0L, pDriveLayoutEx, sizeDriveLayoutEx, &bytes, NULL ); if (!result) { status = GetLastError(); _AsrpHeapFree(pDriveLayoutEx); // // If the buffer is of insufficient size, resize the buffer. // if ((ERROR_MORE_DATA == status) || (ERROR_INSUFFICIENT_BUFFER == status)) { status = ERROR_SUCCESS; sizeDriveLayoutEx += sizeof(PARTITION_INFORMATION_EX) * 4; pDriveLayoutEx = (PDRIVE_LAYOUT_INFORMATION_EX) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, sizeDriveLayoutEx ); _AsrpErrExitCode(!pDriveLayoutEx, status, ERROR_NOT_ENOUGH_MEMORY); } else { AsrpPrintDbgMsg(_asrlog, "The drive layout on Harddisk %lu (%ws) could not be determined (%lu). The volumes on this disk may not be restored completely.\r\n", pPhysicalDisk->DeviceNumber, pPhysicalDisk->DevicePath, GetLastError() ); _AsrpErrExitCode(status, status, GetLastError()); } } } // // We have the drive layout. Now each partition in our list should have // an entry in the partition table. We use the mount manager to set it's // volume guid. // currentPtn = pPtnInfo; result = TRUE; while (currentPtn) { // // We only care about partitions that have a volume-guid // if ((currentPtn->szVolumeGuid) && (wcslen(currentPtn->szVolumeGuid) > 0) ) { // // Go through all the partitions on the disk, and find one that // starts at the offset we expect it to. // found = FALSE; index = 0; while (!found && (index < pDriveLayoutEx->PartitionCount)) { if (pDriveLayoutEx->PartitionEntry[index].StartingOffset.QuadPart == currentPtn->PartitionInfo.StartingOffset.QuadPart) { // // We found the partition, let's set its GUID now // AsrpCreateMountPoint( pPhysicalDisk->DeviceNumber, // disk number pDriveLayoutEx->PartitionEntry[index].PartitionNumber, // partition number currentPtn->szVolumeGuid // volumeGuid ); found = TRUE; } else { index++; } } if (!found) { result = FALSE; } } currentPtn = currentPtn->pOffsetNext; } if (!result) { // // We didn't find a partition // AsrpPrintDbgMsg(_asrlog, "One or more partitions on Harddisk %lu (%ws) could not be recreated. The volumes on this disk may not be restored completely.\r\n", pPhysicalDisk->DeviceNumber, pPhysicalDisk->DevicePath ); _AsrpErrExitCode(status, status, ERROR_BAD_DEVICE); } EXIT: _AsrpHeapFree(pDriveLayoutEx); return (BOOL) (ERROR_SUCCESS == status); } // // Re-partitions the disks // BOOL AsrpRecreateDisks( IN PASR_DISK_INFO pSifDiskList, IN PASR_PTN_INFO_LIST pSifMbrPtnList, IN PASR_PTN_INFO_LIST pSifGptPtnList, IN BOOL AllOrNothing ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { PASR_DISK_INFO pSifDisk = pSifDiskList; DWORD bytesReturned = 0, status = ERROR_SUCCESS; HANDLE hDisk = NULL; BOOL result = TRUE; // // For each sif disk that isn't intact, go to the physical // disk it's assigned to, and recreate that disk // while (pSifDisk) { if (!(pSifDisk->AssignedTo)) { AsrpPrintDbgMsg(_asrinfo, "Not recreating disk %lu in section [%ws] (no matching disk found).\r\n", pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); if (AllOrNothing) { return FALSE; } else { pSifDisk = pSifDisk->pNext; continue; } } if ((pSifDisk->IsCritical) || (pSifDisk->AssignedTo->IsCritical)) { AsrpPrintDbgMsg(_asrinfo, "Not recreating Harddisk %lu (disk %lu in section [%ws]) (critical disk).\r\n", pSifDisk->AssignedTo->DeviceNumber, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION) ); pSifDisk = pSifDisk->pNext; continue; } // // Open physical disk // hDisk = CreateFileW( pSifDisk->AssignedTo->DevicePath, // lpFileName GENERIC_WRITE | GENERIC_READ, // dwDesiredAccess FILE_SHARE_READ | FILE_SHARE_WRITE, // dwShareMode NULL, // lpSecurityAttributes OPEN_EXISTING, // dwCreationFlags 0, // dwFlagsAndAttributes NULL // hTemplateFile ); if ((!hDisk) || (INVALID_HANDLE_VALUE == hDisk)) { // // We couldn't open the disk. // AsrpPrintDbgMsg(_asrlog, "Unable to open Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n", pSifDisk->AssignedTo->DeviceNumber, pSifDisk->AssignedTo->DevicePath, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION), GetLastError() ); if (AllOrNothing) { return FALSE; } else { pSifDisk = pSifDisk->pNext; continue; } } if (!(pSifDisk->IsIntact) && // disk is not intact (pSifDisk->AssignedTo) && // matching physical disk was found ((PARTITION_STYLE_MBR == pSifDisk->Style) || (PARTITION_STYLE_GPT == pSifDisk->Style)) // not recognised partitioning style ) { // // Delete the old drive layout // result = DeviceIoControl( hDisk, IOCTL_DISK_DELETE_DRIVE_LAYOUT, NULL, 0L, NULL, 0L, &bytesReturned, NULL ); if (!result) { AsrpPrintDbgMsg(_asrlog, "Unable to delete layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (%lu).\r\n", pSifDisk->AssignedTo->DeviceNumber, pSifDisk->AssignedTo->DevicePath, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION), GetLastError() ); GetLastError(); } // // If we're converting an MBR to a GPT, then we need to call // IOCTL_DISK_CREATE_DISK first // if ((PARTITION_STYLE_GPT == pSifDisk->Style) && (PARTITION_STYLE_MBR == pSifDisk->AssignedTo->Style)) { CREATE_DISK CreateDisk; CreateDisk.PartitionStyle = PARTITION_STYLE_GPT; memcpy(&(CreateDisk.Gpt.DiskId), &(pSifDisk->pDriveLayoutEx->Gpt.DiskId), sizeof(GUID)); CreateDisk.Gpt.MaxPartitionCount = pSifDisk->pDriveLayoutEx->Gpt.MaxPartitionCount; result = DeviceIoControl( hDisk, IOCTL_DISK_CREATE_DISK, &(CreateDisk), sizeof(CREATE_DISK), NULL, 0L, &bytesReturned, NULL ); if (!result) { // // CREATE_DISK failed // status = GetLastError(); AsrpPrintDbgMsg(_asrlog, "Unable to initialize disk layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n", pSifDisk->AssignedTo->DeviceNumber, pSifDisk->AssignedTo->DevicePath, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION), GetLastError() ); _AsrpCloseHandle(hDisk); SetLastError(status); if (AllOrNothing) { return FALSE; } else { pSifDisk = pSifDisk->pNext; continue; } } } // // Set the new drive layout // result = DeviceIoControl( hDisk, IOCTL_DISK_SET_DRIVE_LAYOUT_EX, pSifDisk->AssignedTo->pDriveLayoutEx, pSifDisk->AssignedTo->sizeDriveLayoutEx, NULL, 0L, &bytesReturned, NULL ); if (!result) { // // SET_DRIVE_LAYOUT failed // status = GetLastError(); AsrpPrintDbgMsg(_asrlog, "Unable to set drive layout on Harddisk %lu (%ws) (disk %lu in section [%ws]) (0%lu).\r\n", pSifDisk->AssignedTo->DeviceNumber, pSifDisk->AssignedTo->DevicePath, pSifDisk->SifDiskKey, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? ASR_SIF_MBR_DISKS_SECTION : ASR_SIF_GPT_DISKS_SECTION), GetLastError() ); _AsrpCloseHandle(hDisk); SetLastError(status); if (AllOrNothing) { return FALSE; } else { pSifDisk = pSifDisk->pNext; continue; } } } // // Now we need to recreate the volumeGuids for each partition // result = AsrpAssignVolumeGuids( pSifDisk->AssignedTo, hDisk, ((PARTITION_STYLE_MBR == pSifDisk->Style) ? (pSifMbrPtnList[pSifDisk->SifDiskKey].pOffsetHead) : (pSifGptPtnList[pSifDisk->SifDiskKey].pOffsetHead)) ); // // We don't care about the result ... // MYASSERT(result && L"AsrpAssignVolumeGuids failed"); _AsrpCloseHandle(hDisk); // // Get the next drive from the drive list. // pSifDisk = pSifDisk->pNext; } return TRUE; } // // Restore Non Critical Disks // // BOOL AsrpRestoreNonCriticalDisksW( IN PCWSTR lpSifPath, IN BOOL bAllOrNothing ) /*++ Routine Description: Arguments: Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { BOOL result = FALSE; PWSTR asrSifPath = NULL; // // We have two lists of disks--one of all the physical disks // currently on the system, and the other constructed from the // sif file. The goal is to reconfigure non-critical disks in // the pPhysicalDiskList to match the pSifDiskList // PASR_DISK_INFO pSifDiskList = NULL, pPhysicalDiskList = NULL; PASR_PTN_INFO_LIST pSifMbrPtnList = NULL, pSifGptPtnList = NULL; DWORD cchAsrSifPath = 0, MaxDeviceNumber = 0, // not used status = ERROR_SUCCESS; BOOL bAutoExtend = FALSE, allOrNothing = FALSE; HANDLE heapHandle = GetProcessHeap(); SetLastError(ERROR_CAN_NOT_COMPLETE); if (!AsrIsEnabled()) { // // If we're not in GUI-mode ASR, we need to open the log files first // AsrpInitialiseErrorFile(); AsrpInitialiseLogFile(); } AsrpPrintDbgMsg(_asrlog, "Attempting to restore non-critical disks.\r\n"); if (!lpSifPath) { SetLastError(ERROR_INVALID_PARAMETER); goto EXIT; } cchAsrSifPath = wcslen(lpSifPath); // // Do a sanity check: we don't want to allow a file path // more than 4096 characters long. // if (cchAsrSifPath > ASR_SIF_ENTRY_MAX_CHARS) { SetLastError(ERROR_INVALID_PARAMETER); goto EXIT; } asrSifPath = (PWSTR) HeapAlloc( heapHandle, HEAP_ZERO_MEMORY, ((cchAsrSifPath + 1) * sizeof(WCHAR)) ); _AsrpErrExitCode(!asrSifPath, status, ERROR_NOT_ENOUGH_MEMORY); wcsncpy(asrSifPath, lpSifPath, cchAsrSifPath); allOrNothing = bAllOrNothing; AsrpPrintDbgMsg(_asrlog, "ASR state file: \"%ws\". AllOrNothing: %lu\r\n", asrSifPath, allOrNothing); // // The function calls are AND'ed below, hence if one fails, the // calls after it will not be executed (exactly the behaviour we // want). // result = ( // // Build the original disk info from the sif file // AsrpBuildMbrSifDiskList(asrSifPath, &pSifDiskList, &pSifMbrPtnList, &bAutoExtend) && AsrpBuildGptSifDiskList(asrSifPath, &pSifDiskList, &pSifGptPtnList) // // Build the list of current disks present on the target machine // && AsrpInitDiskInformation(&pPhysicalDiskList) // // Fill in the partition info for the fixed disks on the target machine // and remove non-fixed devices // && AsrpInitLayoutInformation(NULL, pPhysicalDiskList, &MaxDeviceNumber, TRUE, FALSE) && AsrpFreeNonFixedMedia(&pPhysicalDiskList) // // Try to determine which sif disk should end up on which physical disk. // && AsrpAssignDisks(pSifDiskList, pPhysicalDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing, bAutoExtend) // // Finally, repartition the disks and assign the volume guids // && AsrpRecreateDisks(pSifDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing) ); status = GetLastError(); AsrpFreeStateInformation(&pSifDiskList, NULL); AsrpFreeStateInformation(&pPhysicalDiskList, NULL); AsrpFreePartitionList(&pSifMbrPtnList); AsrpFreePartitionList(&pSifGptPtnList); SetLastError(status); EXIT: status = GetLastError(); if (result) { AsrpPrintDbgMsg(_asrinfo, "Done restoring non-critical disks.\r\n"); } else { AsrpPrintDbgMsg(_asrerror, "Error restoring non-critical disks. (0x%x)\r\n", status); if (ERROR_SUCCESS == status) { // // We're going to return failure, but we haven't set the LastError to // a failure code. This is bad, since we have no clue what went wrong. // // We shouldn't ever get here, because the function returning FALSE above // should set the LastError as it sees fit. // // But I've added this in just to be safe. Let's set it to a generic // error. // MYASSERT(0 && L"Returning failure, but LastError is not set"); status = ERROR_CAN_NOT_COMPLETE; } } if (!AsrIsEnabled()) { AsrpCloseLogFiles(); } _AsrpHeapFree(asrSifPath); SetLastError(status); return result; } BOOL AsrpRestoreTimeZoneInformation( IN PCWSTR lpSifPath ) /*++ Routine Description: Sets the current time-zone, based on the information stored in the SYSTEMS section of the ASR state file. Arguments: lpSifPath - Null-terminated string containing the full path to the ASR state file (including file name). Return Value: If the function succeeds, the return value is a nonzero value. If the function fails, the return value is zero. To get extended error information, call GetLastError(). --*/ { HINF hSif = NULL; BOOL result = FALSE; DWORD reqdSize = 0, status = ERROR_SUCCESS; INFCONTEXT infSystemContext; TIME_ZONE_INFORMATION TimeZoneInformation; WCHAR szTimeZoneInfo[ASR_SIF_ENTRY_MAX_CHARS+1]; ZeroMemory(&infSystemContext, sizeof(INFCONTEXT)); ZeroMemory(&TimeZoneInformation, sizeof(TIME_ZONE_INFORMATION)); ZeroMemory(&szTimeZoneInfo, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1)); // // Open the sif // hSif = SetupOpenInfFileW(lpSifPath, NULL, INF_STYLE_WIN4, NULL); if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) { return FALSE; // sif file couldn't be opened } // // Get the TimeZone strings value // result = SetupFindFirstLineW(hSif, ASR_SIF_SYSTEM_SECTION, NULL, &infSystemContext); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // no system section: corrupt asr.sif? result = SetupGetStringFieldW(&infSystemContext, 7, szTimeZoneInfo, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? swscanf(szTimeZoneInfo, L"%ld %ld %ld %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd", &(TimeZoneInformation.Bias), &(TimeZoneInformation.StandardBias), &(TimeZoneInformation.DaylightBias), &(TimeZoneInformation.StandardDate.wYear), &(TimeZoneInformation.StandardDate.wMonth), &(TimeZoneInformation.StandardDate.wDayOfWeek), &(TimeZoneInformation.StandardDate.wDay), &(TimeZoneInformation.StandardDate.wHour), &(TimeZoneInformation.StandardDate.wMinute), &(TimeZoneInformation.StandardDate.wSecond), &(TimeZoneInformation.StandardDate.wMilliseconds), &(TimeZoneInformation.DaylightDate.wYear), &(TimeZoneInformation.DaylightDate.wMonth), &(TimeZoneInformation.DaylightDate.wDayOfWeek), &(TimeZoneInformation.DaylightDate.wDay), &(TimeZoneInformation.DaylightDate.wHour), &(TimeZoneInformation.DaylightDate.wMinute), &(TimeZoneInformation.DaylightDate.wSecond), &(TimeZoneInformation.DaylightDate.wMilliseconds) ); result = SetupGetStringFieldW(&infSystemContext, 8, TimeZoneInformation.StandardName, 32, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetupGetStringFieldW(&infSystemContext, 9, TimeZoneInformation.DaylightName, 32, &reqdSize); _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? result = SetTimeZoneInformation(&TimeZoneInformation); if (!result) { GetLastError(); } _AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif? EXIT: if (ERROR_SUCCESS != status) { SetLastError(status); } return result; }