Add experimental support for Non-destructive Installation in Windows.

This commit is contained in:
longpanda
2021-11-10 17:53:21 +08:00
parent b67f738b00
commit 563214ed40
14 changed files with 844 additions and 12 deletions

View File

@@ -33,6 +33,34 @@
static int g_backup_bin_index = 0;
static BOOL WriteDataToPhyDisk(HANDLE hDrive, UINT64 Offset, VOID *buffer, DWORD len)
{
BOOL bRet;
DWORD dwSize = 0;
LARGE_INTEGER liCurPosition;
LARGE_INTEGER liNewPosition;
liCurPosition.QuadPart = (LONGLONG)Offset;
liNewPosition.QuadPart = 0;
if (0 == SetFilePointerEx(hDrive, liCurPosition, &liNewPosition, FILE_BEGIN) ||
liNewPosition.QuadPart != liCurPosition.QuadPart)
{
Log("SetFilePointerEx Failed %u", LASTERR);
return FALSE;
}
bRet = WriteFile(hDrive, buffer, len, &dwSize, NULL);
if (bRet == FALSE || dwSize != len)
{
Log("Write file error %u %u", dwSize, LASTERR);
return FALSE;
}
return TRUE;
}
static DWORD GetVentoyVolumeName(int PhyDrive, UINT64 StartSectorId, CHAR *NameBuf, UINT32 BufLen, BOOL DelSlash)
{
size_t len;
@@ -129,7 +157,7 @@ static int GetLettersBelongPhyDrive(int PhyDrive, char *DriveLetters, size_t Len
for (Pos = StringBuf; *Pos; Pos += strlen(Pos) + 1)
{
if (n < (int)Length && PhyDrive == GetPhyDriveByLogicalDrive(Pos[0]))
if (n < (int)Length && PhyDrive == GetPhyDriveByLogicalDrive(Pos[0], NULL))
{
Log("%C: is belong to phydrive%d", Pos[0], PhyDrive);
DriveLetters[n++] = Pos[0];
@@ -140,7 +168,7 @@ static int GetLettersBelongPhyDrive(int PhyDrive, char *DriveLetters, size_t Len
return 0;
}
static HANDLE GetPhysicalHandle(int Drive, BOOLEAN bLockDrive, BOOLEAN bWriteAccess, BOOLEAN bWriteShare)
HANDLE GetPhysicalHandle(int Drive, BOOLEAN bLockDrive, BOOLEAN bWriteAccess, BOOLEAN bWriteShare)
{
int i;
DWORD dwSize;
@@ -260,7 +288,7 @@ End:
return hDrive;
}
int GetPhyDriveByLogicalDrive(int DriveLetter)
int GetPhyDriveByLogicalDrive(int DriveLetter, UINT64 *Offset)
{
BOOL Ret;
DWORD dwSize;
@@ -301,6 +329,11 @@ int GetPhyDriveByLogicalDrive(int DriveLetter)
DiskExtents.Extents[0].ExtentLength.QuadPart
);
if (Offset)
{
*Offset = (UINT64)(DiskExtents.Extents[0].StartingOffset.QuadPart);
}
return (int)DiskExtents.Extents[0].DiskNumber;
}
@@ -335,7 +368,7 @@ int GetAllPhysicalDriveInfo(PHY_DRIVE_INFO *pDriveList, DWORD *pDriveCount)
{
if (dwBytes & 0x01)
{
id = GetPhyDriveByLogicalDrive(Letter);
id = GetPhyDriveByLogicalDrive(Letter, NULL);
Log("%C --> %d", Letter, id);
if (id >= 0)
{
@@ -842,7 +875,7 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId)
LARGE_INTEGER liNewPosition;
BYTE *CheckBuf = NULL;
Log("FormatPart2Fat %llu...", StartSectorId);
Log("FormatPart2Fat %llu...", (ULONGLONG)StartSectorId);
CheckBuf = malloc(SIZE_1MB);
if (!CheckBuf)
@@ -1830,6 +1863,269 @@ End:
return rc;
}
int PartitionResizeForVentoy(PHY_DRIVE_INFO *pPhyDrive)
{
int i, j;
int rc = 1;
int PhyDrive;
int PartStyle;
INT64 ReservedValue;
UINT64 RecudeBytes;
GUID Guid;
MBR_HEAD MBR;
VTOY_GPT_INFO *pGPT;
MBR_HEAD *pMBR;
DWORD dwSize = 0;
VTOY_GPT_HDR BackupHead;
HANDLE hDrive = INVALID_HANDLE_VALUE;
GUID ZeroGuid = { 0 };
static GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
static GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
static GUID BiosGrubPartType = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };
Log("#####################################################");
Log("PartitionResizeForVentoy PhyDrive%d <<%s %s %dGB>>",
pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
Log("#####################################################");
pGPT = &(pPhyDrive->Gpt);
pMBR = &(pPhyDrive->Gpt.MBR);
Log("Disksize:%llu Part2Start:%llu", pPhyDrive->SizeInBytes, pPhyDrive->ResizePart2StartSector * 512);
if (pMBR->PartTbl[0].FsFlag == 0xEE && memcmp(pGPT->Head.Signature, "EFI PART", 8) == 0)
{
PartStyle = 1;
}
else
{
PartStyle = 0;
}
PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
RecudeBytes = VENTOY_EFI_PART_SIZE;
ReservedValue = GetReservedSpaceInMB();
if (ReservedValue > 0)
{
Log("Reduce add reserved space %lldMB", (LONGLONG)ReservedValue);
RecudeBytes += (UINT64)(ReservedValue * SIZE_1MB);
}
if (pPhyDrive->ResizeNoShrink == FALSE)
{
Log("Need to shrink the volume");
if (VDS_ShrinkVolume(pPhyDrive->ResizeVolumeGuid, RecudeBytes))
{
Log("Shrink volume success, now check again");
hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
if (hDrive == INVALID_HANDLE_VALUE)
{
Log("Failed to GetPhysicalHandle for update.");
goto End;
}
//Refresh Drive Layout
DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
CHECK_CLOSE_HANDLE(hDrive);
if (PartResizePreCheck(NULL) && pPhyDrive->ResizeNoShrink)
{
Log("Recheck after Shrink volume success");
Log("After shrink Disksize:%llu Part2Start:%llu", pPhyDrive->SizeInBytes, pPhyDrive->ResizePart2StartSector * 512);
}
else
{
Log("Recheck after Shrink volume failed %u", pPhyDrive->ResizeNoShrink);
goto End;
}
}
else
{
Log("Shrink volume failed");
goto End;
}
}
//Now try write data
hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
if (hDrive == INVALID_HANDLE_VALUE)
{
Log("Failed to GetPhysicalHandle for update.");
goto End;
}
//Write partition 2 data
PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);
if (0 != FormatPart2Fat(hDrive, pPhyDrive->ResizePart2StartSector))
{
Log("FormatPart2Fat failed.");
goto End;
}
//Write grub stage2 gap
PROGRESS_BAR_SET_POS(PT_WRITE_STG1_IMG);
Log("Writing Boot Image ............................. ");
if (WriteGrubStage1ToPhyDrive(hDrive, PartStyle) != 0)
{
Log("WriteGrubStage1ToPhyDrive failed.");
goto End;
}
//Write partition table
PROGRESS_BAR_SET_POS(PT_WRITE_PART_TABLE);
Log("Writing partition table ............................. ");
VentoyGetLocalBootImg(&MBR);
CoCreateGuid(&Guid);
memcpy(MBR.BootCode + 0x180, &Guid, 16);
memcpy(pMBR->BootCode, MBR.BootCode, 440);
if (PartStyle == 0)
{
for (i = 1; i < 4; i++)
{
if (pMBR->PartTbl[i].SectorCount == 0)
{
break;
}
}
if (i >= 4)
{
Log("Can not find MBR free partition table");
goto End;
}
for (j = i - 1; j > 0; j--)
{
Log("Move MBR partition table %d --> %d", j + 1, j + 2);
memcpy(pMBR->PartTbl + (j + 1), pMBR->PartTbl + j, sizeof(PART_TABLE));
}
VentoyFillMBRLocation(pPhyDrive->SizeInBytes, (UINT32)pPhyDrive->ResizePart2StartSector, VENTOY_EFI_PART_SIZE / 512, pMBR->PartTbl + 1);
pMBR->PartTbl[0].Active = 0x80; // bootable
pMBR->PartTbl[1].Active = 0x00;
pMBR->PartTbl[1].FsFlag = 0xEF; // EFI System Partition
if (!WriteDataToPhyDisk(hDrive, 0, pMBR, 512))
{
Log("Legacy BIOS write MBR failed");
goto End;
}
}
else
{
for (i = 1; i < 128; i++)
{
if (memcmp(&(pGPT->PartTbl[i].PartGuid), &ZeroGuid, sizeof(GUID)) == 0)
{
break;
}
}
if (i >= 128)
{
Log("Can not find GPT free partition table");
goto End;
}
for (j = i - 1; j > 0; j--)
{
Log("Move GPT partition table %d --> %d", j + 1, j + 2);
memcpy(pGPT->PartTbl + (j + 1), pGPT->PartTbl + j, sizeof(VTOY_GPT_PART_TBL));
}
pMBR->BootCode[92] = 0x22;
// to fix windows issue
memcpy(&(pGPT->PartTbl[1].PartType), &WindowsDataPartType, sizeof(GUID));
CoCreateGuid(&(pGPT->PartTbl[1].PartGuid));
pGPT->PartTbl[1].StartLBA = pGPT->PartTbl[0].LastLBA + 1;
pGPT->PartTbl[1].LastLBA = pGPT->PartTbl[1].StartLBA + VENTOY_EFI_PART_SIZE / 512 - 1;
pGPT->PartTbl[1].Attr = 0xC000000000000001ULL;
memcpy(pGPT->PartTbl[1].Name, L"VTOYEFI", 7 * 2);
//Update CRC
pGPT->Head.PartTblCrc = VentoyCrc32(pGPT->PartTbl, sizeof(pGPT->PartTbl));
pGPT->Head.Crc = VentoyCrc32(&(pGPT->Head), pGPT->Head.Length);
Log("pGPT->Head.EfiStartLBA=%llu", (ULONGLONG)pGPT->Head.EfiStartLBA);
Log("pGPT->Head.EfiBackupLBA=%llu", (ULONGLONG)pGPT->Head.EfiBackupLBA);
VentoyFillBackupGptHead(pGPT, &BackupHead);
if (!WriteDataToPhyDisk(hDrive, pGPT->Head.EfiBackupLBA * 512, &BackupHead, 512))
{
Log("UEFI write backup head failed");
goto End;
}
if (!WriteDataToPhyDisk(hDrive, (pGPT->Head.EfiBackupLBA - 32) * 512, pGPT->PartTbl, 512 * 32))
{
Log("UEFI write backup partition table failed");
goto End;
}
if (!WriteDataToPhyDisk(hDrive, 0, pGPT, 512 * 34))
{
Log("UEFI write MBR & Main partition table failed");
goto End;
}
}
//Refresh Drive Layout
DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
//We must close handle here, because it will block the refresh bellow
CHECK_CLOSE_HANDLE(hDrive);
Sleep(2000);
//Refresh disk list
PhyDrive = pPhyDrive->PhyDrive;
Log("#### Now Refresh PhyDrive ####");
Ventoy2DiskDestroy();
Ventoy2DiskInit();
pPhyDrive = GetPhyDriveInfoByPhyDrive(PhyDrive);
if (pPhyDrive)
{
if (pPhyDrive->VentoyVersion[0] == 0)
{
Log("After process the Ventoy version is still invalid");
goto End;
}
Log("### Ventoy non-destructive installation successfully finished <%s>", pPhyDrive->VentoyVersion);
}
else
{
Log("### Ventoy non-destructive installation successfully finished <not found>");
}
InitComboxCtrl(g_DialogHwnd, PhyDrive);
rc = 0;
End:
CHECK_CLOSE_HANDLE(hDrive);
return rc;
}
static BOOL DiskCheckWriteAccess(HANDLE hDrive)
{
DWORD dwSize;