diff --git a/INSTALL/Ventoy2Disk.exe b/INSTALL/Ventoy2Disk.exe index d207ffdb..90b024fa 100644 Binary files a/INSTALL/Ventoy2Disk.exe and b/INSTALL/Ventoy2Disk.exe differ diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg index f180475e..5c6797a9 100644 --- a/INSTALL/grub/grub.cfg +++ b/INSTALL/grub/grub.cfg @@ -133,6 +133,8 @@ function vt_check_compatible_pe { #set compatible if ISO file is less than 80MB if [ $vt_chosen_size -gt 33554432 -a $vt_chosen_size -le 83886080 ]; then set ventoy_compatible=YES + elif [ -e $1/WEPE/WEPE.INI ]; then + set ventoy_compatible=YES fi return @@ -328,6 +330,8 @@ function distro_specify_initrd_file_phase2 { vt_linux_specify_initrd_file /360Disk/initrd.gz elif [ -f (loop)/porteus/initrd.xz ]; then vt_linux_specify_initrd_file /porteus/initrd.xz + elif [ -f (loop)/pyabr/boot/initrfs.img ]; then + vt_linux_specify_initrd_file /pyabr/boot/initrfs.img fi } diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService.h b/Ventoy2Disk/Ventoy2Disk/DiskService.h new file mode 100644 index 00000000..a8b68af7 --- /dev/null +++ b/Ventoy2Disk/Ventoy2Disk/DiskService.h @@ -0,0 +1,57 @@ +/****************************************************************************** + * DiskService.h + * + * Copyright (c) 2021, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#ifndef __DISKSERVICE_H__ +#define __DISKSERVICE_H__ + +typedef struct VDS_PARA +{ + UINT64 Attr; + GUID Type; + GUID Id; + WCHAR Name[36]; + ULONG NameLen; + ULONGLONG Offset; +}VDS_PARA; + + +//VDS com +int VDS_Init(void); +BOOL VDS_CleanDisk(int DriveIndex); +BOOL VDS_DeleteAllPartitions(int DriveIndex); +BOOL VDS_DeleteVtoyEFIPartition(int DriveIndex); +BOOL VDS_ChangeVtoyEFIAttr(int DriveIndex, UINT64 Attr); +BOOL VDS_CreateVtoyEFIPart(int DriveIndex, UINT64 Offset); +BOOL VDS_ChangeVtoyEFI2ESP(int DriveIndex, UINT64 Offset); +BOOL VDS_ChangeVtoyEFI2Basic(int DriveIndex, UINT64 Offset); + + +//diskpart.exe +BOOL DSPT_CleanDisk(int DriveIndex); + + +// +// Internel define +// + + + + +#endif diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService_diskpart.c b/Ventoy2Disk/Ventoy2Disk/DiskService_diskpart.c new file mode 100644 index 00000000..7a55395e --- /dev/null +++ b/Ventoy2Disk/Ventoy2Disk/DiskService_diskpart.c @@ -0,0 +1,84 @@ +/****************************************************************************** + * DiskService_diskpart.c + * + * Copyright (c) 2021, longpanda + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include "Ventoy2Disk.h" +#include "DiskService.h" + +STATIC BOOL IsDiskpartExist(void) +{ + BOOL ret; + + ret = IsFileExist("C:\\Windows\\system32\\diskpart.exe"); + if (!ret) + { + Log("diskpart.exe not exist"); + } + + return ret; +} + +STATIC BOOL DSPT_CommProc(const char *Cmd) +{ + CHAR CmdBuf[MAX_PATH]; + CHAR CmdFile[MAX_PATH]; + STARTUPINFOA Si; + PROCESS_INFORMATION Pi; + + GetCurrentDirectoryA(sizeof(CmdBuf), CmdBuf); + sprintf_s(CmdFile, sizeof(CmdFile), "%s\\ventoy\\diskpart_%u.txt", CmdBuf, GetCurrentProcessId()); + + SaveBufToFile(CmdFile, Cmd, strlen(Cmd)); + + GetStartupInfoA(&Si); + Si.dwFlags |= STARTF_USESHOWWINDOW; + Si.wShowWindow = SW_HIDE; + + sprintf_s(CmdBuf, sizeof(CmdBuf), "C:\\Windows\\system32\\diskpart.exe /s \"%s\"", CmdFile); + + Log("CreateProcess <%s>", CmdBuf); + CreateProcessA(NULL, CmdBuf, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi); + + Log("Wair process ..."); + WaitForSingleObject(Pi.hProcess, INFINITE); + Log("Process finished..."); + + DeleteFileA(CmdFile); + return TRUE; +} + +BOOL DSPT_CleanDisk(int DriveIndex) +{ + CHAR CmdBuf[128]; + + Log("CleanDiskByDiskpart <%d>", DriveIndex); + + if (!IsDiskpartExist()) + { + return FALSE; + } + + sprintf_s(CmdBuf, sizeof(CmdBuf), "select disk %d\r\nclean\r\n", DriveIndex); + return DSPT_CommProc(CmdBuf); +} diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c b/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c new file mode 100644 index 00000000..38800c69 --- /dev/null +++ b/Ventoy2Disk/Ventoy2Disk/DiskService_vds.c @@ -0,0 +1,629 @@ +/****************************************************************************** + * DiskService_vds.c + * + * Copyright (c) 2021, longpanda + * Copyright (c) 2011-2020, Pete Batard + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include +#include +#include +#include +#include +#include "Ventoy2Disk.h" +#include "DiskService.h" + + +#define INTF_ADVANCEDDISK 1 +#define INTF_ADVANCEDDISK2 2 +#define INTF_CREATEPARTITIONEX 3 + +/* + * Some code and functions in the file are copied from rufus. + * https://github.com/pbatard/rufus + */ +#define VDS_SET_ERROR SetLastError +#define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService) +#define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This) +#define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum) +#define IVdsService_WaitForServiceReady(This) ((This)->lpVtbl->WaitForServiceReady(This)) +#define IVdsService_CleanupObsoleteMountPoints(This) ((This)->lpVtbl->CleanupObsoleteMountPoints(This)) +#define IVdsService_Refresh(This) ((This)->lpVtbl->Refresh(This)) +#define IVdsService_Reenumerate(This) ((This)->lpVtbl->Reenumerate(This)) +#define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) +#define IVdsProvider_Release(This) (This)->lpVtbl->Release(This) +#define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum) +#define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This) +#define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum) +#define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties) +#define IVdsDisk_Release(This) (This)->lpVtbl->Release(This) +#define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) +#define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) +#define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected) +#define IVdsAdvancedDisk_ChangeAttributes(This, ullOffset, para) (This)->lpVtbl->ChangeAttributes(This, ullOffset, para) +#define IVdsAdvancedDisk_CreatePartition(This, ullOffset, ullSize, para, ppAsync) (This)->lpVtbl->CreatePartition(This, ullOffset, ullSize, para, ppAsync) +#define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync) +#define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This) + +#define IVdsAdvancedDisk2_ChangePartitionType(This, ullOffset, bForce, para) (This)->lpVtbl->ChangePartitionType(This, ullOffset, bForce, para) +#define IVdsAdvancedDisk2_Release(This) (This)->lpVtbl->Release(This) + +#define IVdsCreatePartitionEx_CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync) (This)->lpVtbl->CreatePartitionEx(This, ullOffset, ullSize, ulAlign, para, ppAsync) +#define IVdsCreatePartitionEx_Release(This) (This)->lpVtbl->Release(This) +#define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched) +#define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum) +#define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) +#define IVdsVolume_Release(This) (This)->lpVtbl->Release(This) +#define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths) +#define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) +#define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This) +#define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties) +#define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This) +#define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted) +#define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut) +#define IVdsAsync_Release(This) (This)->lpVtbl->Release(This) + +#define IUnknown_QueryInterface(This, a, b) (This)->lpVtbl->QueryInterface(This,a,b) +#define IUnknown_Release(This) (This)->lpVtbl->Release(This) + +typedef BOOL(*VDS_Callback_PF)(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data); + +STATIC IVdsService * VDS_InitService(void) +{ + HRESULT hr; + IVdsServiceLoader *pLoader; + IVdsService *pService; + + // Initialize COM + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); + + // Create a VDS Loader Instance + hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, &IID_IVdsServiceLoader, (void **)&pLoader); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not create VDS Loader Instance: %u", LASTERR); + return NULL; + } + + // Load the VDS Service + hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService); + IVdsServiceLoader_Release(pLoader); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not load VDS Service: %u", LASTERR); + return NULL; + } + + // Wait for the Service to become ready if needed + hr = IVdsService_WaitForServiceReady(pService); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("VDS Service is not ready: %u", LASTERR); + return NULL; + } + + Log("VDS init OK, service %p", pService); + return pService; +} + + +STATIC BOOL VDS_DiskCommProc(int intf, int DriveIndex, VDS_Callback_PF callback, UINT64 data) +{ + BOOL r = FALSE; + HRESULT hr; + ULONG ulFetched; + IUnknown *pUnk = NULL; + IEnumVdsObject *pEnum = NULL; + IVdsService *pService = NULL; + wchar_t wPhysicalName[48]; + + swprintf_s(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive%d", DriveIndex); + + pService = VDS_InitService(); + if (!pService) + { + Log("Could not query VDS Service"); + goto out; + } + + // Query the VDS Service Providers + hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not query VDS Service Providers: 0x%lx %u", hr, LASTERR); + goto out; + } + + while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) + { + IVdsProvider *pProvider; + IVdsSwProvider *pSwProvider; + IEnumVdsObject *pEnumPack; + IUnknown *pPackUnk; + + // Get VDS Provider + hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider); + IUnknown_Release(pUnk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not get VDS Provider: %u", LASTERR); + goto out; + } + + // Get VDS Software Provider + hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider); + IVdsProvider_Release(pProvider); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not get VDS Software Provider: %u", LASTERR); + goto out; + } + + // Get VDS Software Provider Packs + hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack); + IVdsSwProvider_Release(pSwProvider); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not get VDS Software Provider Packs: %u", LASTERR); + goto out; + } + + // Enumerate Provider Packs + while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) == S_OK) + { + IVdsPack *pPack; + IEnumVdsObject *pEnumDisk; + IUnknown *pDiskUnk; + + hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack); + IUnknown_Release(pPackUnk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not query VDS Software Provider Pack: %u", LASTERR); + goto out; + } + + // Use the pack interface to access the disks + hr = IVdsPack_QueryDisks(pPack, &pEnumDisk); + if (hr != S_OK) { + VDS_SET_ERROR(hr); + Log("Could not query VDS disks: %u", LASTERR); + goto out; + } + + // List disks + while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFetched) == S_OK) + { + VDS_DISK_PROP diskprop; + IVdsDisk *pDisk; + IVdsAdvancedDisk *pAdvancedDisk; + IVdsAdvancedDisk2 *pAdvancedDisk2; + IVdsCreatePartitionEx *pCreatePartitionEx; + + // Get the disk interface. + hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk); + if (hr != S_OK) { + VDS_SET_ERROR(hr); + Log("Could not query VDS Disk Interface: %u", LASTERR); + goto out; + } + + // Get the disk properties + hr = IVdsDisk_GetProperties(pDisk, &diskprop); + if (hr != S_OK) { + VDS_SET_ERROR(hr); + Log("Could not query VDS Disk Properties: %u", LASTERR); + goto out; + } + + // Isolate the disk we want + if (_wcsicmp(wPhysicalName, diskprop.pwszName) != 0) + { + IVdsDisk_Release(pDisk); + continue; + } + + if (intf == INTF_ADVANCEDDISK) + { + // Instantiate the AdvanceDisk interface for our disk. + hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk); + IVdsDisk_Release(pDisk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not access VDS Advanced Disk interface: %u", LASTERR); + goto out; + } + else + { + Log("Callback %d process for disk <%S>", intf, diskprop.pwszName); + r = callback(pAdvancedDisk, &diskprop, data); + } + IVdsAdvancedDisk_Release(pAdvancedDisk); + } + else if (intf == INTF_ADVANCEDDISK2) + { + // Instantiate the AdvanceDisk interface for our disk. + hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk2, (void **)&pAdvancedDisk2); + IVdsDisk_Release(pDisk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not access VDS Advanced Disk2 interface: %u", LASTERR); + goto out; + } + else + { + Log("Callback %d process for disk2 <%S>", intf, diskprop.pwszName); + r = callback(pAdvancedDisk2, &diskprop, data); + } + IVdsAdvancedDisk2_Release(pAdvancedDisk2); + } + else if (intf == INTF_CREATEPARTITIONEX) + { + // Instantiate the CreatePartitionEx interface for our disk. + hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsCreatePartitionEx, (void **)&pCreatePartitionEx); + IVdsDisk_Release(pDisk); + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not access VDS CreatePartitionEx interface: %u", LASTERR); + goto out; + } + else + { + Log("Callback %d process for disk <%S>", intf, diskprop.pwszName); + r = callback(pCreatePartitionEx, &diskprop, data); + } + IVdsCreatePartitionEx_Release(pCreatePartitionEx); + } + + goto out; + } + } + } + +out: + return r; +} + +STATIC BOOL VDS_CallBack_CleanDisk(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + HRESULT hr, hr2; + ULONG completed; + IVdsAsync* pAsync; + IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface; + + (void)pDiskProp; + (void)data; + + hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, TRUE, FALSE, &pAsync); + while (SUCCEEDED(hr)) + { + hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed); + if (SUCCEEDED(hr)) + { + hr = hr2; + if (hr == S_OK) + { + Log("Disk clean QueryStatus OK"); + break; + } + else if (hr == VDS_E_OPERATION_PENDING) + { + hr = S_OK; + } + else + { + Log("QueryStatus invalid status:%u", hr); + } + } + Sleep(500); + } + + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not clean disk 0x%lx err:%u", hr, LASTERR); + return FALSE; + } + + return TRUE; +} + +BOOL VDS_CleanDisk(int DriveIndex) +{ + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_CleanDisk, 0); + Log("VDS_CleanDisk %d ret:%d", DriveIndex, ret); + return ret; +} + +STATIC BOOL VDS_CallBack_DeletePartition(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + BOOL r = FALSE; + HRESULT hr; + VDS_PARTITION_PROP* prop_array = NULL; + LONG i, prop_array_size; + ULONG PartNumber = (ULONG)data; + IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface; + + if (PartNumber == 0) + { + Log("Deleting ALL partitions from disk '%S':", pDiskProp->pwszName); + } + else + { + Log("Deleting partition(%ld) from disk '%S':", PartNumber, pDiskProp->pwszName); + } + + // Query the partition data, so we can get the start offset, which we need for deletion + hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size); + if (hr == S_OK) + { + for (i = 0; i < prop_array_size; i++) + { + if (PartNumber == 0 || PartNumber == prop_array[i].ulPartitionNumber) + { + Log("* Partition %d (offset: %lld, size: %llu) delete it.", + prop_array[i].ulPartitionNumber, prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize); + } + else + { + Log(" Partition %d (offset: %lld, size: %llu) skip it.", + prop_array[i].ulPartitionNumber, prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize); + continue; + } + + hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE); + if (hr != S_OK) + { + r = FALSE; + VDS_SET_ERROR(hr); + Log("Could not delete partitions: %u", LASTERR); + } + else + { + Log("Delete this partitions success"); + } + } + r = TRUE; + } + else + { + Log("No partition to delete on disk '%S'", pDiskProp->pwszName); + r = TRUE; + } + CoTaskMemFree(prop_array); + + return r; +} + +BOOL VDS_DeleteAllPartitions(int DriveIndex) +{ + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_DeletePartition, 0); + Log("VDS_DeleteAllPartitions %d ret:%d", DriveIndex, ret); + return ret; +} + +BOOL VDS_DeleteVtoyEFIPartition(int DriveIndex) +{ + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_DeletePartition, 2); + Log("VDS_DeleteVtoyEFIPartition %d ret:%d", DriveIndex, ret); + return ret; +} + +STATIC BOOL VDS_CallBack_ChangeEFIAttr(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + BOOL r = FALSE; + HRESULT hr; + VDS_PARTITION_PROP* prop_array = NULL; + LONG i, prop_array_size; + CHANGE_ATTRIBUTES_PARAMETERS AttrPara; + IVdsAdvancedDisk *pAdvancedDisk = (IVdsAdvancedDisk *)pInterface; + + // Query the partition data, so we can get the start offset, which we need for deletion + hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size); + if (hr == S_OK) + { + for (i = 0; i < prop_array_size; i++) + { + if (prop_array[i].ullSize == VENTOY_EFI_PART_SIZE && + prop_array[i].PartitionStyle == VDS_PST_GPT && + memcmp(prop_array[i].Gpt.name, L"VTOYEFI", 7 * 2) == 0) + { + Log("* Partition %d (offset: %lld, size: %llu, Attr:0x%llx)", prop_array[i].ulPartitionNumber, + prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize, prop_array[i].Gpt.attributes); + + if (prop_array[i].Gpt.attributes == data) + { + Log("Attribute match, No need to change."); + r = TRUE; + } + else + { + AttrPara.style = VDS_PST_GPT; + AttrPara.GptPartInfo.attributes = data; + hr = IVdsAdvancedDisk_ChangeAttributes(pAdvancedDisk, prop_array[i].ullOffset, &AttrPara); + if (hr == S_OK) + { + r = TRUE; + Log("Change this partitions attribute success"); + } + else + { + r = FALSE; + VDS_SET_ERROR(hr); + Log("Could not change partitions attr: %u", LASTERR); + } + } + break; + } + } + } + else + { + Log("No partition found on disk '%S'", pDiskProp->pwszName); + } + CoTaskMemFree(prop_array); + + return r; +} + +BOOL VDS_ChangeVtoyEFIAttr(int DriveIndex, UINT64 Attr) +{ + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK, DriveIndex, VDS_CallBack_ChangeEFIAttr, Attr); + Log("VDS_ChangeVtoyEFIAttr %d ret:%d", DriveIndex, ret); + return ret; +} + + + +STATIC BOOL VDS_CallBack_ChangeEFIType(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + BOOL r = FALSE; + HRESULT hr; + IVdsAdvancedDisk2 *pAdvancedDisk2 = (IVdsAdvancedDisk2 *)pInterface; + VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data; + CHANGE_PARTITION_TYPE_PARAMETERS para; + + para.style = VDS_PST_GPT; + memcpy(&(para.GptPartInfo.partitionType), &VdsPara->Type, sizeof(GUID)); + + hr = IVdsAdvancedDisk2_ChangePartitionType(pAdvancedDisk2, VdsPara->Offset, TRUE, ¶); + if (hr == S_OK) + { + r = TRUE; + } + else + { + Log("Failed to change partition type 0x%lx", hr); + } + + return r; +} + + +BOOL VDS_ChangeVtoyEFI2ESP(int DriveIndex, UINT64 Offset) +{ + VDS_PARA Para; + GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }; + + memcpy(&(Para.Type), &EspPartType, sizeof(GUID)); + Para.Offset = Offset; + + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK2, DriveIndex, VDS_CallBack_ChangeEFIType, (ULONG)&Para); + Log("VDS_ChangeVtoyEFI2ESP %d ret:%d", DriveIndex, ret); + return ret; +} + +BOOL VDS_ChangeVtoyEFI2Basic(int DriveIndex, UINT64 Offset) +{ + VDS_PARA Para; + GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } }; + + memcpy(&(Para.Type), &WindowsDataPartType, sizeof(GUID)); + Para.Offset = Offset; + + BOOL ret = VDS_DiskCommProc(INTF_ADVANCEDDISK2, DriveIndex, VDS_CallBack_ChangeEFIType, (ULONG)&Para); + Log("VDS_ChangeVtoyEFI2ESP %d ret:%d", DriveIndex, ret); + return ret; +} + + +STATIC BOOL VDS_CallBack_CreateVtoyEFI(void *pInterface, VDS_DISK_PROP *pDiskProp, UINT64 data) +{ + HRESULT hr, hr2; + ULONG completed; + IVdsAsync* pAsync; + CREATE_PARTITION_PARAMETERS para; + IVdsCreatePartitionEx *pCreatePartitionEx = (IVdsCreatePartitionEx *)pInterface; + VDS_PARA *VdsPara = (VDS_PARA *)(ULONG)data; + + (void)pDiskProp; + + memset(¶, 0, sizeof(para)); + para.style = VDS_PST_GPT; + memcpy(&(para.GptPartInfo.partitionType), &VdsPara->Type, sizeof(GUID)); + memcpy(&(para.GptPartInfo.partitionId), &VdsPara->Id, sizeof(GUID)); + para.GptPartInfo.attributes = VdsPara->Attr; + memcpy(para.GptPartInfo.name, VdsPara->Name, sizeof(WCHAR)* VdsPara->NameLen); + + hr = IVdsCreatePartitionEx_CreatePartitionEx(pCreatePartitionEx, VdsPara->Offset, VENTOY_EFI_PART_SIZE, 512, ¶, &pAsync); + while (SUCCEEDED(hr)) + { + hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed); + if (SUCCEEDED(hr)) + { + hr = hr2; + if (hr == S_OK) + { + Log("Disk create partition QueryStatus OK, %lu%%", completed); + break; + } + else if (hr == VDS_E_OPERATION_PENDING) + { + Log("Disk partition finish: %lu%%", completed); + hr = S_OK; + } + else + { + Log("QueryStatus invalid status:0x%lx", hr); + } + } + Sleep(1000); + } + + if (hr != S_OK) + { + VDS_SET_ERROR(hr); + Log("Could not create partition, err:0x%lx", LASTERR); + return FALSE; + } + + return TRUE; +} + +BOOL VDS_CreateVtoyEFIPart(int DriveIndex, UINT64 Offset) +{ + VDS_PARA Para; + GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } }; + GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } }; + + Log("VDS_CreateVtoyEFIPart %u Offset:%llu Sector:%llu", DriveIndex, Offset, Offset / 512); + + memset(&Para, 0, sizeof(Para)); + Para.Attr = 0x8000000000000000ULL; + Para.Offset = Offset; + memcpy(Para.Name, L"VTOYEFI", 7 * 2); + Para.NameLen = 7; + memcpy(&(Para.Type), &EspPartType, sizeof(GUID)); + CoCreateGuid(&(Para.Id)); + + BOOL ret = VDS_DiskCommProc(INTF_CREATEPARTITIONEX, DriveIndex, VDS_CallBack_CreateVtoyEFI, (ULONG)&Para); + Log("VDS_CreateVtoyEFIPart %d ret:%d", DriveIndex, ret); + return ret; +} + diff --git a/Ventoy2Disk/Ventoy2Disk/DiskService_wmsa.c b/Ventoy2Disk/Ventoy2Disk/DiskService_wmsa.c new file mode 100644 index 00000000..c5af4ccc --- /dev/null +++ b/Ventoy2Disk/Ventoy2Disk/DiskService_wmsa.c @@ -0,0 +1,27 @@ +/****************************************************************************** +* DiskService_wsma.c +* +* Copyright (c) 2021, longpanda +* +* This program is free software; you can redistribute it and/or +* modify it under the terms of the GNU General Public License as +* published by the Free Software Foundation; either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, but +* WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, see . +* +*/ + +#include +#include +#include +#include +#include +#include "Ventoy2Disk.h" +#include "DiskService.h" diff --git a/Ventoy2Disk/Ventoy2Disk/PhyDrive.c b/Ventoy2Disk/Ventoy2Disk/PhyDrive.c index 8d4e9bb4..a916d155 100644 --- a/Ventoy2Disk/Ventoy2Disk/PhyDrive.c +++ b/Ventoy2Disk/Ventoy2Disk/PhyDrive.c @@ -23,276 +23,12 @@ #include #include #include -#include #include "resource.h" #include "Language.h" #include "Ventoy2Disk.h" #include "fat_filelib.h" #include "ff.h" - -/* - * Some code and functions in the file are copied from rufus. - * https://github.com/pbatard/rufus - */ -#define VDS_SET_ERROR SetLastError -#define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService) -#define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This) -#define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum) -#define IVdsService_WaitForServiceReady(This) ((This)->lpVtbl->WaitForServiceReady(This)) -#define IVdsService_CleanupObsoleteMountPoints(This) ((This)->lpVtbl->CleanupObsoleteMountPoints(This)) -#define IVdsService_Refresh(This) ((This)->lpVtbl->Refresh(This)) -#define IVdsService_Reenumerate(This) ((This)->lpVtbl->Reenumerate(This)) -#define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) -#define IVdsProvider_Release(This) (This)->lpVtbl->Release(This) -#define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum) -#define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This) -#define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum) -#define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties) -#define IVdsDisk_Release(This) (This)->lpVtbl->Release(This) -#define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) -#define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) -#define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected) -#define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync) -#define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This) -#define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched) -#define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum) -#define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject) -#define IVdsVolume_Release(This) (This)->lpVtbl->Release(This) -#define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths) -#define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) -#define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This) -#define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties) -#define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This) -#define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted) -#define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut) -#define IVdsAsync_Release(This) (This)->lpVtbl->Release(This) - -#define IUnknown_QueryInterface(This, a, b) (This)->lpVtbl->QueryInterface(This,a,b) -#define IUnknown_Release(This) (This)->lpVtbl->Release(This) - -/* -* Delete all the partitions from a disk, using VDS -* Mostly copied from https://social.msdn.microsoft.com/Forums/vstudio/en-US/b90482ae-4e44-4b08-8731-81915030b32a/createpartition-using-vds-interface-throw-error-enointerface-dcom?forum=vcgeneral -*/ -BOOL DeletePartitions(DWORD DriveIndex, BOOL OnlyPart2) -{ - BOOL r = FALSE; - HRESULT hr; - ULONG ulFetched; - wchar_t wPhysicalName[48]; - IVdsServiceLoader *pLoader; - IVdsService *pService; - IEnumVdsObject *pEnum; - IUnknown *pUnk; - - swprintf_s(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive%lu", DriveIndex); - - // Initialize COM - CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); - CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT, - RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL); - - // Create a VDS Loader Instance - hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER, - &IID_IVdsServiceLoader, (void **)&pLoader); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not create VDS Loader Instance: %u", LASTERR); - goto out; - } - - // Load the VDS Service - hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService); - IVdsServiceLoader_Release(pLoader); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not load VDS Service: %u", LASTERR); - goto out; - } - - // Wait for the Service to become ready if needed - hr = IVdsService_WaitForServiceReady(pService); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("VDS Service is not ready: %u", LASTERR); - goto out; - } - - // Query the VDS Service Providers - hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not query VDS Service Providers: %u", LASTERR); - goto out; - } - - while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) { - IVdsProvider *pProvider; - IVdsSwProvider *pSwProvider; - IEnumVdsObject *pEnumPack; - IUnknown *pPackUnk; - - // Get VDS Provider - hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider); - IUnknown_Release(pUnk); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not get VDS Provider: %u", LASTERR); - goto out; - } - - // Get VDS Software Provider - hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider); - IVdsProvider_Release(pProvider); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not get VDS Software Provider: %u", LASTERR); - goto out; - } - - // Get VDS Software Provider Packs - hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack); - IVdsSwProvider_Release(pSwProvider); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not get VDS Software Provider Packs: %u", LASTERR); - goto out; - } - - // Enumerate Provider Packs - while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) == S_OK) { - IVdsPack *pPack; - IEnumVdsObject *pEnumDisk; - IUnknown *pDiskUnk; - - hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack); - IUnknown_Release(pPackUnk); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not query VDS Software Provider Pack: %u", LASTERR); - goto out; - } - - // Use the pack interface to access the disks - hr = IVdsPack_QueryDisks(pPack, &pEnumDisk); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not query VDS disks: %u", LASTERR); - goto out; - } - - // List disks - while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFetched) == S_OK) { - VDS_DISK_PROP diskprop; - VDS_PARTITION_PROP* prop_array; - LONG i, prop_array_size; - IVdsDisk *pDisk; - IVdsAdvancedDisk *pAdvancedDisk; - - // Get the disk interface. - hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not query VDS Disk Interface: %u", LASTERR); - goto out; - } - - // Get the disk properties - hr = IVdsDisk_GetProperties(pDisk, &diskprop); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not query VDS Disk Properties: %u", LASTERR); - goto out; - } - - // Isolate the disk we want - if (_wcsicmp(wPhysicalName, diskprop.pwszName) != 0) { - IVdsDisk_Release(pDisk); - continue; - } - - // Instantiate the AdvanceDisk interface for our disk. - hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk); - IVdsDisk_Release(pDisk); - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not access VDS Advanced Disk interface: %u", LASTERR); - goto out; - } - - // Query the partition data, so we can get the start offset, which we need for deletion - hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size); - if (hr == S_OK) { - Log("Deleting ALL partition(s) from disk '%S':", diskprop.pwszName); - // Now go through each partition - for (i = 0; i < prop_array_size; i++) { - - Log("* Partition %d (offset: %lld, size: %llu)", prop_array[i].ulPartitionNumber, - prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize); - - if (OnlyPart2) - { - if (prop_array[i].ullOffset == 2048 * 512 || prop_array[i].ullSize != 32 * 1024 * 1024) - { - Log("Skip this partition..."); - continue; - } - } - - hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE); - if (hr != S_OK) { - r = FALSE; - VDS_SET_ERROR(hr); - Log("Could not delete partitions: %u", LASTERR); - } - else { - Log("Delete this partitions success"); - } - } - r = TRUE; - } - else { - Log("No partition to delete on disk '%S'", diskprop.pwszName); - r = TRUE; - } - CoTaskMemFree(prop_array); - -#if 0 - // Issue a Clean while we're at it - HRESULT hr2 = E_FAIL; - ULONG completed; - IVdsAsync* pAsync; - hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, FALSE, FALSE, &pAsync); - while (SUCCEEDED(hr)) { - if (IS_ERROR(FormatStatus)) { - IVdsAsync_Cancel(pAsync); - break; - } - hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed); - if (SUCCEEDED(hr)) { - hr = hr2; - if (hr == S_OK) - break; - if (hr == VDS_E_OPERATION_PENDING) - hr = S_OK; - } - Sleep(500); - } - if (hr != S_OK) { - VDS_SET_ERROR(hr); - Log("Could not clean disk: %s", LASTERR); - } -#endif - IVdsAdvancedDisk_Release(pAdvancedDisk); - goto out; - } - } - } - -out: - return r; -} - +#include "DiskService.h" static DWORD GetVentoyVolumeName(int PhyDrive, UINT64 StartSectorId, CHAR *NameBuf, UINT32 BufLen, BOOL DelSlash) { @@ -1095,25 +831,33 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId) int len = 0; int writelen = 0; int partwrite = 0; + int Pos = PT_WRITE_VENTOY_START; DWORD dwSize = 0; BOOL bRet; unsigned char *data = NULL; LARGE_INTEGER liCurrentPosition; LARGE_INTEGER liNewPosition; + BYTE *CheckBuf = NULL; Log("FormatPart2Fat %llu...", StartSectorId); + CheckBuf = malloc(SIZE_1MB); + if (!CheckBuf) + { + Log("Failed to malloc check buf"); + return 1; + } + rc = ReadWholeFileToBuf(VENTOY_FILE_DISK_IMG, 0, (void **)&data, &len); if (rc) { Log("Failed to read img file %p %u", data, len); + free(CheckBuf); return 1; } liCurrentPosition.QuadPart = StartSectorId * 512; - SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN); - - Log("Set file pointer: %llu New pointer:%llu", liCurrentPosition.QuadPart, liNewPosition.QuadPart); + SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN); memset(g_part_img_buf, 0, sizeof(g_part_img_buf)); @@ -1141,7 +885,34 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId) goto End; } - PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i); + PROGRESS_BAR_SET_POS(Pos); + if (i % 2 == 0) + { + Pos++; + } + } + + //Read and check the data + liCurrentPosition.QuadPart = StartSectorId * 512; + SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN); + + for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++) + { + bRet = ReadFile(hDrive, CheckBuf, SIZE_1MB, &dwSize, NULL); + Log("Read part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR); + + if (!bRet || memcmp(CheckBuf, g_part_img_buf[0] + i * SIZE_1MB, SIZE_1MB)) + { + Log("### [Check Fail] The data write and read does not match"); + rc = 1; + goto End; + } + + PROGRESS_BAR_SET_POS(Pos); + if (i % 2 == 0) + { + Pos++; + } } } else @@ -1178,7 +949,7 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId) VentoyProcSecureBoot(g_SecureBoot); - for (int i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++) + for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++) { dwSize = 0; bRet = WriteFile(hDrive, g_part_img_buf[i], SIZE_1MB, &dwSize, NULL); @@ -1189,8 +960,35 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId) rc = 1; goto End; } + + PROGRESS_BAR_SET_POS(Pos); + if (i % 2 == 0) + { + Pos++; + } + } - PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i); + //Read and check the data + liCurrentPosition.QuadPart = StartSectorId * 512; + SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN); + + for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++) + { + bRet = ReadFile(hDrive, CheckBuf, SIZE_1MB, &dwSize, NULL); + Log("Read part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR); + + if (!bRet || memcmp(CheckBuf, g_part_img_buf[i], SIZE_1MB)) + { + Log("### [Check Fail] The data write and read does not match"); + rc = 1; + goto End; + } + + PROGRESS_BAR_SET_POS(Pos); + if (i % 2 == 0) + { + Pos++; + } } } else @@ -1204,6 +1002,7 @@ static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId) End: if (data) free(data); + if (CheckBuf)free(CheckBuf); if (partwrite) { @@ -1369,7 +1168,7 @@ int ClearVentoyFromPhyDrive(HWND hWnd, PHY_DRIVE_INFO *pPhyDrive, char *pDrvLett PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART); - if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE)) + if (!VDS_DeleteAllPartitions(pPhyDrive->PhyDrive)) { Log("Notice: Could not delete partitions: %u", GetLastError()); } @@ -1772,7 +1571,7 @@ End: } -int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle) +int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle, int TryId) { int i; int rc = 0; @@ -1789,7 +1588,7 @@ int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle) UINT64 Part1SectorCount = 0; UINT64 Part2StartSector = 0; - Log("InstallVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>", + Log("InstallVentoy2PhyDrive try%d %s PhyDrive%d <<%s %s %dGB>>", TryId, PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId, GetHumanReadableGBSize(pPhyDrive->SizeInBytes)); @@ -1856,7 +1655,7 @@ int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle) PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART); - if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE)) + if (!VDS_DeleteAllPartitions(pPhyDrive->PhyDrive)) { Log("Notice: Could not delete partitions: %u", GetLastError()); } @@ -2026,107 +1825,127 @@ End: return rc; } -int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive) + +int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId) { - int i; - int rc = 0; - BOOL ForceMBR = FALSE; - HANDLE hVolume; - HANDLE hDrive; - DWORD Status; - DWORD dwSize; - BOOL bRet; - CHAR DriveName[] = "?:\\"; - CHAR DriveLetters[MAX_PATH] = { 0 }; - UINT64 StartSector; + int i; + int rc = 0; + int MaxRetry = 3; + BOOL ForceMBR = FALSE; + BOOL Esp2Basic = FALSE; + HANDLE hVolume; + HANDLE hDrive; + DWORD Status; + DWORD dwSize; + BOOL bRet; + CHAR DriveName[] = "?:\\"; + CHAR DriveLetters[MAX_PATH] = { 0 }; + UINT64 StartSector; UINT64 ReservedMB = 0; - MBR_HEAD BootImg; - MBR_HEAD MBR; - VTOY_GPT_INFO *pGptInfo = NULL; - UINT8 ReservedData[4096]; + MBR_HEAD BootImg; + MBR_HEAD MBR; + VTOY_GPT_INFO *pGptInfo = NULL; + UINT8 ReservedData[4096]; - Log("UpdateVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>", - pPhyDrive->PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId, - GetHumanReadableGBSize(pPhyDrive->SizeInBytes)); + Log("UpdateVentoy2PhyDrive try%d %s PhyDrive%d <<%s %s %dGB>>", TryId, + pPhyDrive->PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId, + GetHumanReadableGBSize(pPhyDrive->SizeInBytes)); - PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN); + PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN); - Log("Lock disk for umount ............................ "); + Log("Lock disk for umount ............................ "); - hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE); - if (hDrive == INVALID_HANDLE_VALUE) - { - Log("Failed to open physical disk"); - return 1; - } + hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE); + if (hDrive == INVALID_HANDLE_VALUE) + { + Log("Failed to open physical disk"); + return 1; + } - if (pPhyDrive->PartStyle) - { - pGptInfo = malloc(sizeof(VTOY_GPT_INFO)); - if (!pGptInfo) - { - return 1; - } + if (pPhyDrive->PartStyle) + { + pGptInfo = malloc(sizeof(VTOY_GPT_INFO)); + if (!pGptInfo) + { + return 1; + } - memset(pGptInfo, 0, sizeof(VTOY_GPT_INFO)); + memset(pGptInfo, 0, sizeof(VTOY_GPT_INFO)); - // Read GPT Info - SetFilePointer(hDrive, 0, NULL, FILE_BEGIN); - ReadFile(hDrive, pGptInfo, sizeof(VTOY_GPT_INFO), &dwSize, NULL); + // Read GPT Info + SetFilePointer(hDrive, 0, NULL, FILE_BEGIN); + ReadFile(hDrive, pGptInfo, sizeof(VTOY_GPT_INFO), &dwSize, NULL); - //MBR will be used to compare with local boot image - memcpy(&MBR, &pGptInfo->MBR, sizeof(MBR_HEAD)); + //MBR will be used to compare with local boot image + memcpy(&MBR, &pGptInfo->MBR, sizeof(MBR_HEAD)); - StartSector = pGptInfo->PartTbl[1].StartLBA; - Log("GPT StartSector in PartTbl:%llu", (ULONGLONG)StartSector); + StartSector = pGptInfo->PartTbl[1].StartLBA; + Log("GPT StartSector in PartTbl:%llu", (ULONGLONG)StartSector); - ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512) - 33) / 2048; - Log("GPT Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB); - } - else - { - // Read MBR - SetFilePointer(hDrive, 0, NULL, FILE_BEGIN); - ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL); + ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512) - 33) / 2048; + Log("GPT Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB); + } + else + { + // Read MBR + SetFilePointer(hDrive, 0, NULL, FILE_BEGIN); + ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL); - StartSector = MBR.PartTbl[1].StartSectorId; - Log("MBR StartSector in PartTbl:%llu", (ULONGLONG)StartSector); + StartSector = MBR.PartTbl[1].StartSectorId; + Log("MBR StartSector in PartTbl:%llu", (ULONGLONG)StartSector); - ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512)) / 2048; - Log("MBR Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB); - } + ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512)) / 2048; + Log("MBR Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB); + } - //Read Reserved Data - SetFilePointer(hDrive, 512 * 2040, NULL, FILE_BEGIN); - ReadFile(hDrive, ReservedData, sizeof(ReservedData), &dwSize, NULL); + //Read Reserved Data + SetFilePointer(hDrive, 512 * 2040, NULL, FILE_BEGIN); + ReadFile(hDrive, ReservedData, sizeof(ReservedData), &dwSize, NULL); - GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters)); + GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters)); - if (DriveLetters[0] == 0) - { - Log("No drive letter was assigned..."); - } - else - { - // Unmount all mounted volumes that belong to this drive - // Do it in reverse so that we always end on the first volume letter - for (i = (int)strlen(DriveLetters); i > 0; i--) - { - DriveName[0] = DriveLetters[i - 1]; - if (IsVentoyLogicalDrive(DriveName[0])) - { - Log("%s is ventoy logical drive", DriveName); - bRet = DeleteVolumeMountPointA(DriveName); - Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, LASTERR); - break; - } - } - } + if (DriveLetters[0] == 0) + { + Log("No drive letter was assigned..."); + } + else + { + // Unmount all mounted volumes that belong to this drive + // Do it in reverse so that we always end on the first volume letter + for (i = (int)strlen(DriveLetters); i > 0; i--) + { + DriveName[0] = DriveLetters[i - 1]; + if (IsVentoyLogicalDrive(DriveName[0])) + { + Log("%s is ventoy logical drive", DriveName); + bRet = DeleteVolumeMountPointA(DriveName); + Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, LASTERR); + break; + } + } + } - // It kind of blows, but we have to relinquish access to the physical drive - // for VDS to be able to delete the partitions that reside on it... - DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); - CHECK_CLOSE_HANDLE(hDrive); + // It kind of blows, but we have to relinquish access to the physical drive + // for VDS to be able to delete the partitions that reside on it... + DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); + CHECK_CLOSE_HANDLE(hDrive); + + if (pPhyDrive->PartStyle == 1) + { + Log("TryId=%d EFI GPT partition type is 0x%llx", TryId, pPhyDrive->Part2GPTAttr); + + if ((TryId == 1 && (pPhyDrive->Part2GPTAttr >> 56) == 0xC0) || TryId == 2) + { + PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART); + Log("Change GPT partition type to ESP"); + + if (VDS_ChangeVtoyEFI2ESP(pPhyDrive->PhyDrive, StartSector * 512)) + { + Esp2Basic = TRUE; + Sleep(1000); + } + } + } PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE); @@ -2143,30 +1962,66 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive) Log("Lock volume for update .......................... "); hVolume = INVALID_HANDLE_VALUE; - Status = GetVentoyVolumeName(pPhyDrive->PhyDrive, StartSector, DriveLetters, sizeof(DriveLetters), TRUE); + + //If we change VTOYEFI to ESP, it can not have s volume name, so don't try to get it. + if (Esp2Basic) + { + Status = ERROR_NOT_FOUND; + } + else + { + for (i = 0; i < MaxRetry; i++) + { + Status = GetVentoyVolumeName(pPhyDrive->PhyDrive, StartSector, DriveLetters, sizeof(DriveLetters), TRUE); + if (ERROR_SUCCESS == Status) + { + break; + } + else + { + Log("==== Volume not found, wait and retry %d... ====", i); + Sleep(2); + } + } + } + if (ERROR_SUCCESS == Status) { Log("Now lock and dismount volume <%s>", DriveLetters); - hVolume = CreateFileA(DriveLetters, - GENERIC_READ | GENERIC_WRITE, - FILE_SHARE_READ, - NULL, - OPEN_EXISTING, - FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, - NULL); + + for (i = 0; i < MaxRetry; i++) + { + hVolume = CreateFileA(DriveLetters, + GENERIC_READ | GENERIC_WRITE, + FILE_SHARE_READ, + NULL, + OPEN_EXISTING, + FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH, + NULL); + + if (hVolume == INVALID_HANDLE_VALUE) + { + Log("Failed to create file volume, errcode:%u, wait and retry ...", LASTERR); + Sleep(2000); + } + else + { + break; + } + } if (hVolume == INVALID_HANDLE_VALUE) { Log("Failed to create file volume, errcode:%u", LASTERR); - rc = 1; - goto End; } + else + { + bRet = DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); + Log("FSCTL_LOCK_VOLUME bRet:%u code:%u", bRet, LASTERR); - bRet = DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); - Log("FSCTL_LOCK_VOLUME bRet:%u code:%u", bRet, LASTERR); - - bRet = DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); - Log("FSCTL_DISMOUNT_VOLUME bRet:%u code:%u", bRet, LASTERR); + bRet = DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL); + Log("FSCTL_DISMOUNT_VOLUME bRet:%u code:%u", bRet, LASTERR); + } } else if (ERROR_NOT_FOUND == Status) { @@ -2178,18 +2033,17 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive) goto End; } - if (!TryWritePart2(hDrive, StartSector)) { if (pPhyDrive->PartStyle == 0) { ForceMBR = TRUE; - Log("Try write failed, now delete partition 2..."); + Log("Try write failed, now delete partition 2 for MBR..."); CHECK_CLOSE_HANDLE(hDrive); Log("Now delete partition 2..."); - DeletePartitions(pPhyDrive->PhyDrive, TRUE); + VDS_DeleteVtoyEFIPartition(pPhyDrive->PhyDrive); hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE); if (hDrive == INVALID_HANDLE_VALUE) @@ -2199,6 +2053,12 @@ int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive) goto End; } } + else + { + Log("TryWritePart2 failed ...."); + rc = 1; + goto End; + } } PROGRESS_BAR_SET_POS(PT_FORMAT_PART2); @@ -2285,6 +2145,12 @@ End: CHECK_CLOSE_HANDLE(hDrive); + if (Esp2Basic) + { + Log("Recover GPT partition type to basic"); + VDS_ChangeVtoyEFI2Basic(pPhyDrive->PhyDrive, StartSector * 512); + } + if (pGptInfo) { free(pGptInfo); diff --git a/Ventoy2Disk/Ventoy2Disk/Utility.c b/Ventoy2Disk/Ventoy2Disk/Utility.c index 6b441607..c9c32bd1 100644 --- a/Ventoy2Disk/Ventoy2Disk/Utility.c +++ b/Ventoy2Disk/Ventoy2Disk/Utility.c @@ -1,7 +1,8 @@ /****************************************************************************** * Utility.c * - * Copyright (c) 2020, longpanda + * Copyright (c) 2021, longpanda + * Copyright (c) 2011-2020, Pete Batard * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -20,6 +21,25 @@ #include #include "Ventoy2Disk.h" +void TraceOut(const char *Fmt, ...) +{ + va_list Arg; + int Len = 0; + FILE *File = NULL; + char szBuf[1024]; + + va_start(Arg, Fmt); + Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg); + va_end(Arg); + + fopen_s(&File, VENTOY_FILE_LOG, "a+"); + if (File) + { + fwrite(szBuf, 1, Len, File); + fclose(File); + } +} + void Log(const char *Fmt, ...) { va_list Arg; @@ -92,6 +112,22 @@ BOOL IsPathExist(BOOL Dir, const char *Fmt, ...) return TRUE; } +int SaveBufToFile(const CHAR *FileName, const void *Buffer, int BufLen) +{ + FILE *File = NULL; + void *Data = NULL; + + fopen_s(&File, FileName, "wb"); + if (File == NULL) + { + Log("Failed to open file %s", FileName); + return 1; + } + + fwrite(Buffer, 1, BufLen, File); + fclose(File); + return 0; +} int ReadWholeFileToBuf(const CHAR *FileName, int ExtLen, void **Bufer, int *BufLen) { @@ -205,73 +241,239 @@ BOOL IsWow64(void) return bIsWow64; } -void DumpWindowsVersion(void) +/* +* Some code and functions in the file are copied from rufus. +* https://github.com/pbatard/rufus +*/ + +/* Windows versions */ +enum WindowsVersion { + WINDOWS_UNDEFINED = -1, + WINDOWS_UNSUPPORTED = 0, + WINDOWS_XP = 0x51, + WINDOWS_2003 = 0x52, // Also XP_64 + WINDOWS_VISTA = 0x60, // Also Server 2008 + WINDOWS_7 = 0x61, // Also Server 2008_R2 + WINDOWS_8 = 0x62, // Also Server 2012 + WINDOWS_8_1 = 0x63, // Also Server 2012_R2 + WINDOWS_10_PREVIEW1 = 0x64, + WINDOWS_10 = 0xA0, // Also Server 2016, also Server 2019 + WINDOWS_11 = 0xB0, // Also Server 2022 + WINDOWS_MAX +}; + +static const char* GetEdition(DWORD ProductType) { - int Bit; - BOOL WsVer; - DWORD Major, Minor; - ULONGLONG MajorEqual, MinorEqual; - OSVERSIONINFOEXA Ver1, Ver2; - const CHAR *Ver = NULL; - CHAR WinVer[256] = { 0 }; + // From: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getproductinfo + // These values can be found in the winnt.h header. + switch (ProductType) { + case 0x00000000: return ""; // Undefined + case 0x00000001: return "Ultimate"; + case 0x00000002: return "Home Basic"; + case 0x00000003: return "Home Premium"; + case 0x00000004: return "Enterprise"; + case 0x00000005: return "Home Basic N"; + case 0x00000006: return "Business"; + case 0x00000007: return "Standard Server"; + case 0x00000008: return "Datacenter Server"; + case 0x00000009: return "Smallbusiness Server"; + case 0x0000000A: return "Enterprise Server"; + case 0x0000000B: return "Starter"; + case 0x00000010: return "Business N"; + case 0x00000011: return "Web Server"; + case 0x00000012: return "Cluster Server"; + case 0x00000013: return "Home Server"; + case 0x0000001A: return "Home Premium N"; + case 0x0000001B: return "Enterprise N"; + case 0x0000001C: return "Ultimate N"; + case 0x00000022: return "Home Premium Server"; + case 0x0000002F: return "Starter N"; + case 0x00000030: return "Pro"; + case 0x00000031: return "Pro N"; + case 0x00000042: return "Starter E"; + case 0x00000043: return "Home Basic E"; + case 0x00000044: return "Premium E"; + case 0x00000045: return "Pro E"; + case 0x00000046: return "Enterprise E"; + case 0x00000047: return "Ultimate E"; + case 0x00000048: return "Enterprise Eval"; + case 0x00000054: return "Enterprise N Eval"; + case 0x00000057: return "Thin PC"; + case 0x0000006F: return "Core Connected"; + case 0x00000070: return "Pro Student"; + case 0x00000071: return "Core Connected N"; + case 0x00000072: return "Pro Student N"; + case 0x00000073: return "Core Connected Single Language"; + case 0x00000074: return "Core Connected China"; + case 0x00000079: return "Edu"; + case 0x0000007A: return "Edu N"; + case 0x0000007D: return "Enterprise S"; + case 0x0000007E: return "Enterprise S N"; + case 0x0000007F: return "Pro S"; + case 0x00000080: return "Pro S N"; + case 0x00000081: return "Enterprise S Eval"; + case 0x00000082: return "Enterprise S N Eval"; + case 0x0000008A: return "Pro Single Language"; + case 0x0000008B: return "Pro China"; + case 0x0000008C: return "Enterprise Subscription"; + case 0x0000008D: return "Enterprise Subscription N"; + case 0x00000095: return "Utility VM"; + case 0x000000A1: return "Pro Workstation"; + case 0x000000A2: return "Pro Workstation N"; + case 0x000000A4: return "Pro for Education"; + case 0x000000A5: return "Pro for Education N"; + case 0x000000AB: return "Enterprise G"; // I swear Microsoft are just making up editions... + case 0x000000AC: return "Enterprise G N"; + case 0x000000B6: return "Core OS"; + case 0x000000B7: return "Cloud E"; + case 0x000000B8: return "Cloud E N"; + case 0x000000BD: return "Lite"; + case 0xABCDABCD: return "(Unlicensed)"; + default: return "(Unknown Edition)"; + } +} - memset(&Ver1, 0, sizeof(Ver1)); - memset(&Ver2, 0, sizeof(Ver2)); +#define is_x64 IsWow64 +#define static_strcpy safe_strcpy +#define REGKEY_HKCU HKEY_CURRENT_USER +#define REGKEY_HKLM HKEY_LOCAL_MACHINE +static int nWindowsVersion = WINDOWS_UNDEFINED; +static int nWindowsBuildNumber = -1; +static char WindowsVersionStr[128] = ""; + +/* Helpers for 32 bit registry operations */ + +/* +* Read a generic registry key value. If a short key_name is used, assume that +* it belongs to the application and create the app subkey if required +*/ +static __inline BOOL _GetRegistryKey(HKEY key_root, const char* key_name, DWORD reg_type, + LPBYTE dest, DWORD dest_size) +{ + const char software_prefix[] = "SOFTWARE\\"; + char long_key_name[MAX_PATH] = { 0 }; + BOOL r = FALSE; + size_t i; + LONG s; + HKEY hSoftware = NULL, hApp = NULL; + DWORD dwType = -1, dwSize = dest_size; + + memset(dest, 0, dest_size); + + if (key_name == NULL) + return FALSE; + + for (i = strlen(key_name); i>0; i--) { + if (key_name[i] == '\\') + break; + } + + if (i > 0) { + // Prefix with "SOFTWARE" if needed + if (_strnicmp(key_name, software_prefix, sizeof(software_prefix)-1) != 0) { + if (i + sizeof(software_prefix) >= sizeof(long_key_name)) + return FALSE; + strcpy_s(long_key_name, sizeof(long_key_name), software_prefix); + strcat_s(long_key_name, sizeof(long_key_name), key_name); + long_key_name[sizeof(software_prefix)+i - 1] = 0; + } + else { + if (i >= sizeof(long_key_name)) + return FALSE; + static_strcpy(long_key_name, key_name); + long_key_name[i] = 0; + } + i++; + if (RegOpenKeyExA(key_root, long_key_name, 0, KEY_READ, &hApp) != ERROR_SUCCESS) { + hApp = NULL; + goto out; + } + } + else { + if (RegOpenKeyExA(key_root, "SOFTWARE", 0, KEY_READ | KEY_CREATE_SUB_KEY, &hSoftware) != ERROR_SUCCESS) { + hSoftware = NULL; + goto out; + } + } + + s = RegQueryValueExA(hApp, &key_name[i], NULL, &dwType, (LPBYTE)dest, &dwSize); + // No key means default value of 0 or empty string + if ((s == ERROR_FILE_NOT_FOUND) || ((s == ERROR_SUCCESS) && (dwType == reg_type) && (dwSize > 0))) { + r = TRUE; + } +out: + if (hSoftware != NULL) + RegCloseKey(hSoftware); + if (hApp != NULL) + RegCloseKey(hApp); + return r; +} + +#define GetRegistryKey32(root, key, pval) _GetRegistryKey(root, key, REG_DWORD, (LPBYTE)pval, sizeof(DWORD)) +static __inline INT32 ReadRegistryKey32(HKEY root, const char* key) { + DWORD val; + GetRegistryKey32(root, key, &val); + return (INT32)val; +} + +/* +* Modified from smartmontools' os_win32.cpp +*/ +void GetWindowsVersion(void) +{ + OSVERSIONINFOEXA vi, vi2; + DWORD dwProductType; + const char* w = 0; + const char* w64 = "32 bit"; + char *vptr; + size_t vlen; + unsigned major, minor; + ULONGLONG major_equal, minor_equal; + BOOL ws; + + nWindowsVersion = WINDOWS_UNDEFINED; + static_strcpy(WindowsVersionStr, "Windows Undefined"); - Ver1.dwOSVersionInfoSize = sizeof(Ver1); - // suppress the C4996 warning for GetVersionExA #pragma warning(push) #pragma warning(disable:4996) - if (!GetVersionExA((OSVERSIONINFOA *)&Ver1)) - { - memset(&Ver1, 0, sizeof(Ver1)); - Ver1.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); - if (!GetVersionExA((OSVERSIONINFOA *)&Ver1)) - { + + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(vi); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) { + memset(&vi, 0, sizeof(vi)); + vi.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA); + if (!GetVersionExA((OSVERSIONINFOA *)&vi)) return; - } } + #pragma warning(pop) - if (Ver1.dwPlatformId == VER_PLATFORM_WIN32_NT) - { - if (Ver1.dwMajorVersion > 6 || (Ver1.dwMajorVersion == 6 && Ver1.dwMinorVersion >= 2)) - { - // GetVersionEx() has problem on some Windows version + if (vi.dwPlatformId == VER_PLATFORM_WIN32_NT) { - MajorEqual = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); - for (Major = Ver1.dwMajorVersion; Major <= 9; Major++) - { - memset(&Ver2, 0, sizeof(Ver2)); - Ver2.dwOSVersionInfoSize = sizeof(Ver2); - Ver2.dwMajorVersion = Major; + if (vi.dwMajorVersion > 6 || (vi.dwMajorVersion == 6 && vi.dwMinorVersion >= 2)) { + // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version + // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx + // And starting with Windows 10 Preview 2, Windows enforces the use of the application/supportedOS + // manifest in order for VerSetConditionMask() to report the ACTUAL OS major and minor... - if (!VerifyVersionInfoA(&Ver2, VER_MAJORVERSION, MajorEqual)) - { + major_equal = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL); + for (major = vi.dwMajorVersion; major <= 9; major++) { + memset(&vi2, 0, sizeof(vi2)); + vi2.dwOSVersionInfoSize = sizeof(vi2); vi2.dwMajorVersion = major; + if (!VerifyVersionInfoA(&vi2, VER_MAJORVERSION, major_equal)) continue; - } - - if (Ver1.dwMajorVersion < Major) - { - Ver1.dwMajorVersion = Major; - Ver1.dwMinorVersion = 0; + if (vi.dwMajorVersion < major) { + vi.dwMajorVersion = major; vi.dwMinorVersion = 0; } - MinorEqual = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); - for (Minor = Ver1.dwMinorVersion; Minor <= 9; Minor++) - { - memset(&Ver2, 0, sizeof(Ver2)); - - Ver2.dwOSVersionInfoSize = sizeof(Ver2); - Ver2.dwMinorVersion = Minor; - - if (!VerifyVersionInfoA(&Ver2, VER_MINORVERSION, MinorEqual)) - { + minor_equal = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL); + for (minor = vi.dwMinorVersion; minor <= 9; minor++) { + memset(&vi2, 0, sizeof(vi2)); vi2.dwOSVersionInfoSize = sizeof(vi2); + vi2.dwMinorVersion = minor; + if (!VerifyVersionInfoA(&vi2, VER_MINORVERSION, minor_equal)) continue; - } - - Ver1.dwMinorVersion = Minor; + vi.dwMinorVersion = minor; break; } @@ -279,84 +481,81 @@ void DumpWindowsVersion(void) } } - if (Ver1.dwMajorVersion <= 0xF && Ver1.dwMinorVersion <= 0xF) - { - WsVer = (Ver1.wProductType <= VER_NT_WORKSTATION); - switch ((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion) - { - case 0x51: - { - Ver = "XP"; - break; - } - case 0x52: - { - Ver = GetSystemMetrics(89) ? "Server 2003 R2" : "Server 2003"; - break; - } - case 0x60: - { - Ver = WsVer ? "Vista" : "Server 2008"; - break; - } - case 0x61: - { - Ver = WsVer ? "7" : "Server 2008 R2"; - break; - } - case 0x62: - { - Ver = WsVer ? "8" : "Server 2012"; - break; - } - case 0x63: - { - Ver = WsVer ? "8.1" : "Server 2012 R2"; - break; - } - case 0x64: - { - Ver = WsVer ? "10 (Preview 1)" : "Server 10 (Preview 1)"; - break; - } - case 0xA0: - { - Ver = WsVer ? "10" : ((Ver1.dwBuildNumber > 15000) ? "Server 2019" : "Server 2016"); - break; - } - default: - { - Ver = "10 or later"; + if (vi.dwMajorVersion <= 0xf && vi.dwMinorVersion <= 0xf) { + ws = (vi.wProductType <= VER_NT_WORKSTATION); + nWindowsVersion = vi.dwMajorVersion << 4 | vi.dwMinorVersion; + switch (nWindowsVersion) { + case WINDOWS_XP: w = "XP"; + break; + case WINDOWS_2003: w = (ws ? "XP_64" : (!GetSystemMetrics(89) ? "Server 2003" : "Server 2003_R2")); + break; + case WINDOWS_VISTA: w = (ws ? "Vista" : "Server 2008"); + break; + case WINDOWS_7: w = (ws ? "7" : "Server 2008_R2"); + break; + case WINDOWS_8: w = (ws ? "8" : "Server 2012"); + break; + case WINDOWS_8_1: w = (ws ? "8.1" : "Server 2012_R2"); + break; + case WINDOWS_10_PREVIEW1: w = (ws ? "10 (Preview 1)" : "Server 10 (Preview 1)"); + break; + // Starting with Windows 10 Preview 2, the major is the same as the public-facing version + case WINDOWS_10: + if (vi.dwBuildNumber < 20000) { + w = (ws ? "10" : ((vi.dwBuildNumber < 17763) ? "Server 2016" : "Server 2019")); break; } + nWindowsVersion = WINDOWS_11; + // Fall through + case WINDOWS_11: w = (ws ? "11" : "Server 2022"); + break; + default: + if (nWindowsVersion < WINDOWS_XP) + nWindowsVersion = WINDOWS_UNSUPPORTED; + else + w = "12 or later"; + break; } } } - Bit = IsWow64() ? 64 : 32; + if (is_x64()) + w64 = "64-bit"; - if (Ver1.wServicePackMinor) - { - safe_sprintf(WinVer, "Windows %s SP%u.%u %d-bit", Ver, Ver1.wServicePackMajor, Ver1.wServicePackMinor, Bit); - } - else if (Ver1.wServicePackMajor) - { - safe_sprintf(WinVer, "Windows %s SP%u %d-bit", Ver, Ver1.wServicePackMajor, Bit); - } + GetProductInfo(vi.dwMajorVersion, vi.dwMinorVersion, vi.wServicePackMajor, vi.wServicePackMinor, &dwProductType); + vptr = WindowsVersionStr; + vlen = sizeof(WindowsVersionStr) - 1; + + if (!w) + sprintf_s(vptr, vlen, "%s %u.%u %s", (vi.dwPlatformId == VER_PLATFORM_WIN32_NT ? "NT" : "??"), + (unsigned)vi.dwMajorVersion, (unsigned)vi.dwMinorVersion, w64); + else if (vi.wServicePackMinor) + sprintf_s(vptr, vlen, "%s SP%u.%u %s", w, vi.wServicePackMajor, vi.wServicePackMinor, w64); + else if (vi.wServicePackMajor) + sprintf_s(vptr, vlen, "%s SP%u %s", w, vi.wServicePackMajor, w64); else - { - safe_sprintf(WinVer, "Windows %s %d-bit", Ver, Bit); - } + sprintf_s(vptr, vlen, "%s%s%s, %s", + w, (dwProductType != PRODUCT_UNDEFINED) ? " " : "", GetEdition(dwProductType), w64); - if (((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion) >= 0x62) - { - Log("Windows Version : %s (Build %u)", WinVer, Ver1.dwBuildNumber); - } - else - { - Log("Windows Version : %s", WinVer); + // Add the build number (including UBR if available) for Windows 8.0 and later + nWindowsBuildNumber = vi.dwBuildNumber; + if (nWindowsVersion >= 0x62) { + int nUbr = ReadRegistryKey32(REGKEY_HKLM, "Software\\Microsoft\\Windows NT\\CurrentVersion\\UBR"); + vptr = WindowsVersionStr + strlen(WindowsVersionStr); + vlen = sizeof(WindowsVersionStr) - strlen(WindowsVersionStr) - 1; + if (nUbr > 0) + sprintf_s(vptr, vlen, " (Build %d.%d)", nWindowsBuildNumber, nUbr); + else + sprintf_s(vptr, vlen, " (Build %d)", nWindowsBuildNumber); } +} + + +void DumpWindowsVersion(void) +{ + GetWindowsVersion(); + Log("Windows Version: <>", WindowsVersionStr); return; } diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c index 9eb25701..5ba9e71a 100644 --- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c +++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c @@ -71,7 +71,7 @@ int ParseCmdLineOption(LPSTR lpCmdLine) return 0; } -static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UINT64 *Part2StartSector) +static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UINT64 *Part2StartSector, UINT64 *GptPart2Attr) { int i; BOOL bRet; @@ -149,7 +149,15 @@ static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UIN if (memcmp(pGpt->PartTbl[1].Name, L"VTOYEFI", 7 * 2)) { - Log("Invalid ventoy efi part name"); + if (pGpt->PartTbl[1].Name[0]) + { + Log("Invalid ventoy efi part name <%S>", pGpt->PartTbl[1].Name); + } + else + { + Log("Invalid ventoy efi part name "); + } + return FALSE; } @@ -170,6 +178,7 @@ static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UIN return FALSE; } + *GptPart2Attr = pGpt->PartTbl[1].Attr; *Part2StartSector = pGpt->PartTbl[1].StartLBA; memcpy(pMBR, &(pGpt->MBR), sizeof(MBR_HEAD)); @@ -225,6 +234,7 @@ static int FilterPhysicalDrive(PHY_DRIVE_INFO *pDriveList, DWORD DriveCount) int Letter = 'A'; int Id = 0; int LetterCount = 0; + UINT64 Part2GPTAttr = 0; UINT64 Part2StartSector = 0; PHY_DRIVE_INFO *CurDrive; MBR_HEAD MBR; @@ -247,6 +257,7 @@ static int FilterPhysicalDrive(PHY_DRIVE_INFO *pDriveList, DWORD DriveCount) for (i = 0; i < DriveCount; i++) { + Part2GPTAttr = 0; CurDrive = pDriveList + i; CurDrive->Id = -1; @@ -278,10 +289,11 @@ static int FilterPhysicalDrive(PHY_DRIVE_INFO *pDriveList, DWORD DriveCount) } } - if (IsVentoyPhyDrive(CurDrive->PhyDrive, CurDrive->SizeInBytes, &MBR, &Part2StartSector)) + if (IsVentoyPhyDrive(CurDrive->PhyDrive, CurDrive->SizeInBytes, &MBR, &Part2StartSector, &Part2GPTAttr)) { memcpy(&(CurDrive->MBR), &MBR, sizeof(MBR)); CurDrive->PartStyle = (MBR.PartTbl[0].FsFlag == 0xEE) ? 1 : 0; + CurDrive->Part2GPTAttr = Part2GPTAttr; GetVentoyVerInPhyDrive(CurDrive, Part2StartSector, CurDrive->VentoyVersion, sizeof(CurDrive->VentoyVersion), &(CurDrive->SecureBootSupport)); Log("PhyDrive %d is Ventoy Disk ver:%s SecureBoot:%u", CurDrive->PhyDrive, CurDrive->VentoyVersion, CurDrive->SecureBootSupport); diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h index 72c9a363..dca9eb9f 100644 --- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h +++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h @@ -53,6 +53,7 @@ } #define LASTERR GetLastError() +#define RET_LASTERR (ret ? 0 : LASTERR) #pragma pack(1) typedef struct PART_TABLE @@ -153,12 +154,13 @@ typedef struct PHY_DRIVE_INFO BOOL SecureBootSupport; MBR_HEAD MBR; + UINT64 Part2GPTAttr; }PHY_DRIVE_INFO; typedef enum PROGRESS_POINT { PT_START = 0, - PT_LOCK_FOR_CLEAN, + PT_LOCK_FOR_CLEAN = 8, PT_DEL_ALL_PART, PT_LOCK_FOR_WRITE, PT_FORMAT_PART1, @@ -185,6 +187,7 @@ extern HFONT g_language_normal_font; extern HFONT g_language_bold_font; extern int g_FilterUSB; +void TraceOut(const char *Fmt, ...); void Log(const char *Fmt, ...); BOOL IsPathExist(BOOL Dir, const char *Fmt, ...); void DumpWindowsVersion(void); @@ -207,11 +210,12 @@ int Ventoy2DiskInit(void); int Ventoy2DiskDestroy(void); PHY_DRIVE_INFO * GetPhyDriveInfoById(int Id); int ParseCmdLineOption(LPSTR lpCmdLine); -int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle); -int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive); +int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle, int TryId); +int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int TryId); int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead); int VentoyFillWholeGpt(UINT64 DiskSizeBytes, VTOY_GPT_INFO *pInfo); void SetProgressBarPos(int Pos); +int SaveBufToFile(const CHAR *FileName, const void *Buffer, int BufLen); int ReadWholeFileToBuf(const CHAR *FileName, int ExtLen, void **Bufer, int *BufLen); int INIT unxz(unsigned char *in, int in_size, int(*fill)(void *dest, unsigned int size), diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc index 4cbe6228..18c7d06b 100644 Binary files a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc and b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc differ diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj index e1276f2a..8778b0f2 100644 --- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj +++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj @@ -92,6 +92,9 @@ + + + @@ -115,6 +118,7 @@ + diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj.filters b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj.filters index 45f86ffe..2be3bb28 100644 --- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj.filters +++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj.filters @@ -81,6 +81,15 @@ 源文件 + + 源文件 + + + 源文件 + + + 源文件 + @@ -143,6 +152,9 @@ 头文件 + + 头文件 + diff --git a/Ventoy2Disk/Ventoy2Disk/WinDialog.c b/Ventoy2Disk/Ventoy2Disk/WinDialog.c index a5402338..a2c41acd 100644 Binary files a/Ventoy2Disk/Ventoy2Disk/WinDialog.c and b/Ventoy2Disk/Ventoy2Disk/WinDialog.c differ diff --git a/Ventoy2Disk/Ventoy2Disk/resource.h b/Ventoy2Disk/Ventoy2Disk/resource.h index 7f164998..5ca99e24 100644 Binary files a/Ventoy2Disk/Ventoy2Disk/resource.h and b/Ventoy2Disk/Ventoy2Disk/resource.h differ