You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
4681 lines
142 KiB
4681 lines
142 KiB
/*++
|
|
|
|
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, FALSE)
|
|
|
|
&& AsrpFreeNonFixedMedia(&pPhysicalDiskList)
|
|
|
|
//
|
|
// Try to determine which sif disk should end up on which physical disk.
|
|
//
|
|
&& AsrpAssignDisks(pSifDiskList, pPhysicalDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing, bAutoExtend)
|
|
|
|
//
|
|
// Finally, repartition the disks and assign the volume guids
|
|
//
|
|
&& AsrpRecreateDisks(pSifDiskList, pSifMbrPtnList, pSifGptPtnList, allOrNothing)
|
|
);
|
|
|
|
status = GetLastError();
|
|
AsrpFreeStateInformation(&pSifDiskList, NULL);
|
|
AsrpFreeStateInformation(&pPhysicalDiskList, NULL);
|
|
AsrpFreePartitionList(&pSifMbrPtnList);
|
|
AsrpFreePartitionList(&pSifGptPtnList);
|
|
SetLastError(status);
|
|
|
|
EXIT:
|
|
|
|
status = GetLastError();
|
|
|
|
if (result) {
|
|
AsrpPrintDbgMsg(_asrinfo, "Done restoring non-critical disks.\r\n");
|
|
}
|
|
else {
|
|
|
|
AsrpPrintDbgMsg(_asrerror, "Error restoring non-critical disks. (0x%x)\r\n", status);
|
|
|
|
if (ERROR_SUCCESS == status) {
|
|
//
|
|
// We're going to return failure, but we haven't set the LastError to
|
|
// a failure code. This is bad, since we have no clue what went wrong.
|
|
//
|
|
// We shouldn't ever get here, because the function returning FALSE above
|
|
// should set the LastError as it sees fit.
|
|
//
|
|
// But I've added this in just to be safe. Let's set it to a generic
|
|
// error.
|
|
//
|
|
MYASSERT(0 && L"Returning failure, but LastError is not set");
|
|
status = ERROR_CAN_NOT_COMPLETE;
|
|
}
|
|
}
|
|
|
|
if (!AsrIsEnabled()) {
|
|
AsrpCloseLogFiles();
|
|
}
|
|
|
|
_AsrpHeapFree(asrSifPath);
|
|
|
|
SetLastError(status);
|
|
return result;
|
|
}
|
|
|
|
|
|
BOOL
|
|
AsrpRestoreTimeZoneInformation(
|
|
IN PCWSTR lpSifPath
|
|
)
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Sets the current time-zone, based on the information stored in the SYSTEMS
|
|
section of the ASR state file.
|
|
|
|
Arguments:
|
|
|
|
lpSifPath - Null-terminated string containing the full path to the ASR
|
|
state file (including file name).
|
|
|
|
Return Value:
|
|
|
|
If the function succeeds, the return value is a nonzero value.
|
|
|
|
If the function fails, the return value is zero. To get extended error
|
|
information, call GetLastError().
|
|
|
|
--*/
|
|
|
|
{
|
|
|
|
HINF hSif = NULL;
|
|
|
|
BOOL result = FALSE;
|
|
|
|
DWORD reqdSize = 0,
|
|
status = ERROR_SUCCESS;
|
|
|
|
INFCONTEXT infSystemContext;
|
|
|
|
TIME_ZONE_INFORMATION TimeZoneInformation;
|
|
|
|
WCHAR szTimeZoneInfo[ASR_SIF_ENTRY_MAX_CHARS+1];
|
|
|
|
ZeroMemory(&infSystemContext, sizeof(INFCONTEXT));
|
|
ZeroMemory(&TimeZoneInformation, sizeof(TIME_ZONE_INFORMATION));
|
|
ZeroMemory(&szTimeZoneInfo, sizeof(WCHAR)*(ASR_SIF_ENTRY_MAX_CHARS+1));
|
|
|
|
//
|
|
// Open the sif
|
|
//
|
|
hSif = SetupOpenInfFileW(lpSifPath, NULL, INF_STYLE_WIN4, NULL);
|
|
if (NULL == hSif || INVALID_HANDLE_VALUE == hSif) {
|
|
return FALSE; // sif file couldn't be opened
|
|
}
|
|
|
|
//
|
|
// Get the TimeZone strings value
|
|
//
|
|
result = SetupFindFirstLineW(hSif, ASR_SIF_SYSTEM_SECTION, NULL, &infSystemContext);
|
|
_AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // no system section: corrupt asr.sif?
|
|
|
|
result = SetupGetStringFieldW(&infSystemContext, 7, szTimeZoneInfo, ASR_SIF_ENTRY_MAX_CHARS+1, &reqdSize);
|
|
_AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
|
|
|
|
swscanf(szTimeZoneInfo,
|
|
L"%ld %ld %ld %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd %hd-%hd-%hd-%hd %hd:%hd:%hd.%hd",
|
|
&(TimeZoneInformation.Bias),
|
|
&(TimeZoneInformation.StandardBias),
|
|
&(TimeZoneInformation.DaylightBias),
|
|
|
|
&(TimeZoneInformation.StandardDate.wYear),
|
|
&(TimeZoneInformation.StandardDate.wMonth),
|
|
&(TimeZoneInformation.StandardDate.wDayOfWeek),
|
|
&(TimeZoneInformation.StandardDate.wDay),
|
|
|
|
&(TimeZoneInformation.StandardDate.wHour),
|
|
&(TimeZoneInformation.StandardDate.wMinute),
|
|
&(TimeZoneInformation.StandardDate.wSecond),
|
|
&(TimeZoneInformation.StandardDate.wMilliseconds),
|
|
|
|
&(TimeZoneInformation.DaylightDate.wYear),
|
|
&(TimeZoneInformation.DaylightDate.wMonth),
|
|
&(TimeZoneInformation.DaylightDate.wDayOfWeek),
|
|
&(TimeZoneInformation.DaylightDate.wDay),
|
|
|
|
&(TimeZoneInformation.DaylightDate.wHour),
|
|
&(TimeZoneInformation.DaylightDate.wMinute),
|
|
&(TimeZoneInformation.DaylightDate.wSecond),
|
|
&(TimeZoneInformation.DaylightDate.wMilliseconds)
|
|
);
|
|
|
|
result = SetupGetStringFieldW(&infSystemContext, 8, TimeZoneInformation.StandardName, 32, &reqdSize);
|
|
_AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
|
|
|
|
result = SetupGetStringFieldW(&infSystemContext, 9, TimeZoneInformation.DaylightName, 32, &reqdSize);
|
|
_AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
|
|
|
|
result = SetTimeZoneInformation(&TimeZoneInformation);
|
|
if (!result) {
|
|
GetLastError();
|
|
}
|
|
_AsrpErrExitCode(!result, status, ERROR_INVALID_DATA); // corrupt asr.sif?
|
|
|
|
EXIT:
|
|
|
|
if (ERROR_SUCCESS != status) {
|
|
SetLastError(status);
|
|
}
|
|
|
|
return result;
|
|
}
|