windows-nt/Source/XPSP1/NT/base/ntsetup/syssetup/asrrest.c
2020-09-26 16:20:57 +08:00

4681 lines
138 KiB
C

/*++
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 <diskguid.h> // GPT partition type guids
#include <mountmgr.h> // mountmgr ioctls
#include <winasr.h> // 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, <small window>,
// 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)
&& 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;
}