-/******************************************************************************
- * PhyDrive.c
- *
- * Copyright (c) 2020, longpanda <admin@ventoy.net>
- * Copyright (c) 2011-2020, Pete Batard <pete@akeo.ie>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-
-#include <Windows.h>
-#include <winternl.h>
-#include <commctrl.h>
-#include <initguid.h>
-#include <vds.h>
-#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 && prop_array[i].ullOffset == 2048*512)
- {
- 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);
- }
- }
- 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;
-}
-
-
-static DWORD GetVentoyVolumeName(int PhyDrive, UINT32 StartSectorId, CHAR *NameBuf, UINT32 BufLen, BOOL DelSlash)
-{
- size_t len;
- BOOL bRet;
- DWORD dwSize;
- HANDLE hDrive;
- HANDLE hVolume;
- UINT64 PartOffset;
- DWORD Status = ERROR_NOT_FOUND;
- DISK_EXTENT *pExtents = NULL;
- CHAR VolumeName[MAX_PATH] = { 0 };
- VOLUME_DISK_EXTENTS DiskExtents;
-
- PartOffset = 512ULL * StartSectorId;
-
- Log("GetVentoyVolumeName PhyDrive %d SectorStart:%u PartOffset:%llu", PhyDrive, StartSectorId, (ULONGLONG)PartOffset);
-
- hVolume = FindFirstVolumeA(VolumeName, sizeof(VolumeName));
- if (hVolume == INVALID_HANDLE_VALUE)
- {
- return 1;
- }
-
- do {
-
- len = strlen(VolumeName);
- Log("Find volume:%s", VolumeName);
-
- VolumeName[len - 1] = 0;
-
- hDrive = CreateFileA(VolumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- continue;
- }
-
- bRet = DeviceIoControl(hDrive,
- IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
- NULL,
- 0,
- &DiskExtents,
- (DWORD)(sizeof(DiskExtents)),
- (LPDWORD)&dwSize,
- NULL);
-
- Log("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS bRet:%u code:%u", bRet, LASTERR);
- Log("NumberOfDiskExtents:%u DiskNumber:%u", DiskExtents.NumberOfDiskExtents, DiskExtents.Extents[0].DiskNumber);
-
- if (bRet && DiskExtents.NumberOfDiskExtents == 1)
- {
- pExtents = DiskExtents.Extents;
-
- Log("This volume DiskNumber:%u offset:%llu", pExtents->DiskNumber, (ULONGLONG)pExtents->StartingOffset.QuadPart);
- if ((int)pExtents->DiskNumber == PhyDrive && pExtents->StartingOffset.QuadPart == PartOffset)
- {
- Log("This volume match");
-
- if (!DelSlash)
- {
- VolumeName[len - 1] = '\\';
- }
-
- sprintf_s(NameBuf, BufLen, "%s", VolumeName);
- Status = ERROR_SUCCESS;
- CloseHandle(hDrive);
- break;
- }
- }
-
- CloseHandle(hDrive);
- } while (FindNextVolumeA(hVolume, VolumeName, sizeof(VolumeName)));
-
- FindVolumeClose(hVolume);
-
- Log("GetVentoyVolumeName return %u", Status);
- return Status;
-}
-
-static int GetLettersBelongPhyDrive(int PhyDrive, char *DriveLetters, size_t Length)
-{
- int n = 0;
- DWORD DataSize = 0;
- CHAR *Pos = NULL;
- CHAR *StringBuf = NULL;
-
- DataSize = GetLogicalDriveStringsA(0, NULL);
- StringBuf = (CHAR *)malloc(DataSize + 1);
- if (StringBuf == NULL)
- {
- return 1;
- }
-
- GetLogicalDriveStringsA(DataSize, StringBuf);
-
- for (Pos = StringBuf; *Pos; Pos += strlen(Pos) + 1)
- {
- if (n < (int)Length && PhyDrive == GetPhyDriveByLogicalDrive(Pos[0]))
- {
- Log("%C: is belong to phydrive%d", Pos[0], PhyDrive);
- DriveLetters[n++] = Pos[0];
- }
- }
-
- free(StringBuf);
- return 0;
-}
-
-static HANDLE GetPhysicalHandle(int Drive, BOOLEAN bLockDrive, BOOLEAN bWriteAccess, BOOLEAN bWriteShare)
-{
- int i;
- DWORD dwSize;
- DWORD LastError;
- UINT64 EndTime;
- HANDLE hDrive = INVALID_HANDLE_VALUE;
- CHAR PhyDrive[128];
- CHAR DevPath[MAX_PATH] = { 0 };
-
- safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", Drive);
-
- if (0 == QueryDosDeviceA(PhyDrive + 4, DevPath, sizeof(DevPath)))
- {
- Log("QueryDosDeviceA failed error:%u", GetLastError());
- strcpy_s(DevPath, sizeof(DevPath), "???");
- }
- else
- {
- Log("QueryDosDeviceA success %s", DevPath);
- }
-
- for (i = 0; i < DRIVE_ACCESS_RETRIES; i++)
- {
- // Try without FILE_SHARE_WRITE (unless specifically requested) so that
- // we won't be bothered by the OS or other apps when we set up our data.
- // However this means we might have to wait for an access gap...
- // We keep FILE_SHARE_READ though, as this shouldn't hurt us any, and is
- // required for enumeration.
- hDrive = CreateFileA(PhyDrive,
- GENERIC_READ | (bWriteAccess ? GENERIC_WRITE : 0),
- FILE_SHARE_READ | (bWriteShare ? FILE_SHARE_WRITE : 0),
- NULL,
- OPEN_EXISTING,
- FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
- NULL);
-
- LastError = GetLastError();
- Log("[%d] CreateFileA %s code:%u %p", i, PhyDrive, LastError, hDrive);
-
- if (hDrive != INVALID_HANDLE_VALUE)
- {
- break;
- }
-
- if ((LastError != ERROR_SHARING_VIOLATION) && (LastError != ERROR_ACCESS_DENIED))
- {
- break;
- }
-
- if (i == 0)
- {
- Log("Waiting for access on %s [%s]...", PhyDrive, DevPath);
- }
- else if (!bWriteShare && (i > DRIVE_ACCESS_RETRIES / 3))
- {
- // If we can't seem to get a hold of the drive for some time, try to enable FILE_SHARE_WRITE...
- Log("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");
- bWriteShare = TRUE;
-
- // Try to report the process that is locking the drive
- // We also use bit 6 as a flag to indicate that SearchProcess was called.
- //access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE) | 0x40;
-
- }
- Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
- }
-
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Could not open %s %u", PhyDrive, LASTERR);
- goto End;
- }
-
- if (bWriteAccess)
- {
- Log("Opened %s for %s write access", PhyDrive, bWriteShare ? "shared" : "exclusive");
- }
-
- if (bLockDrive)
- {
- if (DeviceIoControl(hDrive, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwSize, NULL))
- {
- Log("I/O boundary checks disabled");
- }
-
- EndTime = GetTickCount64() + DRIVE_ACCESS_TIMEOUT;
-
- do {
- if (DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL))
- {
- Log("FSCTL_LOCK_VOLUME success");
- goto End;
- }
- Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
- } while (GetTickCount64() < EndTime);
-
- // If we reached this section, either we didn't manage to get a lock or the user cancelled
- Log("Could not lock access to %s %u", PhyDrive, LASTERR);
-
- // See if we can report the processes are accessing the drive
- //if (!IS_ERROR(FormatStatus) && (access_mask == 0))
- // access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE);
- // Try to continue if the only access rights we saw were for read-only
- //if ((access_mask & 0x07) != 0x01)
- // safe_closehandle(hDrive);
-
- CHECK_CLOSE_HANDLE(hDrive);
- }
-
-End:
-
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Can get handle of %s, maybe some process control it.", DevPath);
- }
-
- return hDrive;
-}
-
-int GetPhyDriveByLogicalDrive(int DriveLetter)
-{
- BOOL Ret;
- DWORD dwSize;
- HANDLE Handle;
- VOLUME_DISK_EXTENTS DiskExtents;
- CHAR PhyPath[128];
-
- safe_sprintf(PhyPath, "\\\\.\\%C:", (CHAR)DriveLetter);
-
- Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
- if (Handle == INVALID_HANDLE_VALUE)
- {
- Log("Could not open the disk<%s>, error:%u", PhyPath, LASTERR);
- return -1;
- }
-
- Ret = DeviceIoControl(Handle,
- IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
- NULL,
- 0,
- &DiskExtents,
- (DWORD)(sizeof(DiskExtents)),
- (LPDWORD)&dwSize,
- NULL);
-
- if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
- {
- Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, LASTERR);
- CHECK_CLOSE_HANDLE(Handle);
- return -1;
- }
- CHECK_CLOSE_HANDLE(Handle);
-
- Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",
- PhyPath,
- DiskExtents.Extents[0].DiskNumber,
- DiskExtents.Extents[0].StartingOffset.QuadPart,
- DiskExtents.Extents[0].ExtentLength.QuadPart
- );
-
- return (int)DiskExtents.Extents[0].DiskNumber;
-}
-
-int GetAllPhysicalDriveInfo(PHY_DRIVE_INFO *pDriveList, DWORD *pDriveCount)
-{
- int i;
- int Count;
- int id;
- int Letter = 'A';
- BOOL bRet;
- DWORD dwBytes;
- DWORD DriveCount = 0;
- HANDLE Handle = INVALID_HANDLE_VALUE;
- CHAR PhyDrive[128];
- PHY_DRIVE_INFO *CurDrive = pDriveList;
- GET_LENGTH_INFORMATION LengthInfo;
- STORAGE_PROPERTY_QUERY Query;
- STORAGE_DESCRIPTOR_HEADER DevDescHeader;
- STORAGE_DEVICE_DESCRIPTOR *pDevDesc;
- int PhyDriveId[VENTOY_MAX_PHY_DRIVE];
-
- Count = GetPhysicalDriveCount();
-
- for (i = 0; i < Count && i < VENTOY_MAX_PHY_DRIVE; i++)
- {
- PhyDriveId[i] = i;
- }
-
- dwBytes = GetLogicalDrives();
- Log("Logical Drives: 0x%x", dwBytes);
- while (dwBytes)
- {
- if (dwBytes & 0x01)
- {
- id = GetPhyDriveByLogicalDrive(Letter);
- Log("%C --> %d", Letter, id);
- if (id >= 0)
- {
- for (i = 0; i < Count; i++)
- {
- if (PhyDriveId[i] == id)
- {
- break;
- }
- }
-
- if (i >= Count)
- {
- Log("Add phy%d to list", i);
- PhyDriveId[Count] = id;
- Count++;
- }
- }
- }
-
- Letter++;
- dwBytes >>= 1;
- }
-
- for (i = 0; i < Count && DriveCount < VENTOY_MAX_PHY_DRIVE; i++)
- {
- CHECK_CLOSE_HANDLE(Handle);
-
- safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", PhyDriveId[i]);
- Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
- Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);
-
- if (Handle == INVALID_HANDLE_VALUE)
- {
- continue;
- }
-
- bRet = DeviceIoControl(Handle,
- IOCTL_DISK_GET_LENGTH_INFO, NULL,
- 0,
- &LengthInfo,
- sizeof(LengthInfo),
- &dwBytes,
- NULL);
- if (!bRet)
- {
- Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);
- continue;
- }
-
- Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);
-
- Query.PropertyId = StorageDeviceProperty;
- Query.QueryType = PropertyStandardQuery;
-
- bRet = DeviceIoControl(Handle,
- IOCTL_STORAGE_QUERY_PROPERTY,
- &Query,
- sizeof(Query),
- &DevDescHeader,
- sizeof(STORAGE_DESCRIPTOR_HEADER),
- &dwBytes,
- NULL);
- if (!bRet)
- {
- Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);
- continue;
- }
-
- if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))
- {
- Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);
- continue;
- }
-
- pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);
- if (!pDevDesc)
- {
- Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);
- continue;
- }
-
- bRet = DeviceIoControl(Handle,
- IOCTL_STORAGE_QUERY_PROPERTY,
- &Query,
- sizeof(Query),
- pDevDesc,
- DevDescHeader.Size,
- &dwBytes,
- NULL);
- if (!bRet)
- {
- Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);
- free(pDevDesc);
- continue;
- }
-
- CurDrive->PhyDrive = i;
- CurDrive->SizeInBytes = LengthInfo.Length.QuadPart;
- CurDrive->DeviceType = pDevDesc->DeviceType;
- CurDrive->RemovableMedia = pDevDesc->RemovableMedia;
- CurDrive->BusType = pDevDesc->BusType;
-
- if (pDevDesc->VendorIdOffset)
- {
- safe_strcpy(CurDrive->VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);
- TrimString(CurDrive->VendorId);
- }
-
- if (pDevDesc->ProductIdOffset)
- {
- safe_strcpy(CurDrive->ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);
- TrimString(CurDrive->ProductId);
- }
-
- if (pDevDesc->ProductRevisionOffset)
- {
- safe_strcpy(CurDrive->ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);
- TrimString(CurDrive->ProductRev);
- }
-
- if (pDevDesc->SerialNumberOffset)
- {
- safe_strcpy(CurDrive->SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);
- TrimString(CurDrive->SerialNumber);
- }
-
- CurDrive++;
- DriveCount++;
-
- free(pDevDesc);
-
- CHECK_CLOSE_HANDLE(Handle);
- }
-
- for (i = 0, CurDrive = pDriveList; i < (int)DriveCount; i++, CurDrive++)
- {
- Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",
- CurDrive->PhyDrive, GetBusTypeString(CurDrive->BusType), CurDrive->RemovableMedia,
- GetHumanReadableGBSize(CurDrive->SizeInBytes), CurDrive->SizeInBytes,
- CurDrive->VendorId, CurDrive->ProductId);
- }
-
- *pDriveCount = DriveCount;
-
- return 0;
-}
-
-
-static HANDLE g_FatPhyDrive;
-static UINT64 g_Part2StartSec;
-static int GetVentoyVersionFromFatFile(CHAR *VerBuf, size_t BufLen)
-{
- int rc = 1;
- int size = 0;
- char *buf = NULL;
- void *flfile = NULL;
-
- flfile = fl_fopen("/grub/grub.cfg", "rb");
- if (flfile)
- {
- fl_fseek(flfile, 0, SEEK_END);
- size = (int)fl_ftell(flfile);
-
- fl_fseek(flfile, 0, SEEK_SET);
-
- buf = (char *)malloc(size + 1);
- if (buf)
- {
- fl_fread(buf, 1, size, flfile);
- buf[size] = 0;
-
- rc = 0;
- sprintf_s(VerBuf, BufLen, "%s", ParseVentoyVersionFromString(buf));
- free(buf);
- }
-
- fl_fclose(flfile);
- }
-
- return rc;
-}
-
-static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
-{
- DWORD dwSize;
- BOOL bRet;
- DWORD ReadSize;
- LARGE_INTEGER liCurrentPosition;
-
- liCurrentPosition.QuadPart = Sector + g_Part2StartSec;
- liCurrentPosition.QuadPart *= 512;
- SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
-
- ReadSize = (DWORD)(SectorCount * 512);
-
- bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);
- if (bRet == FALSE || dwSize != ReadSize)
- {
- Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u\n", bRet, ReadSize, dwSize, LASTERR);
- }
-
- return 1;
-}
-
-
-int GetVentoyVerInPhyDrive(const PHY_DRIVE_INFO *pDriveInfo, UINT64 Part2StartSector, CHAR *VerBuf, size_t BufLen)
-{
- int rc = 0;
- HANDLE hDrive;
-
- hDrive = GetPhysicalHandle(pDriveInfo->PhyDrive, FALSE, FALSE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- return 1;
- }
-
- g_FatPhyDrive = hDrive;
- g_Part2StartSec = Part2StartSector;
-
- Log("Parse FAT fs...");
-
- fl_init();
-
- if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
- {
- rc = GetVentoyVersionFromFatFile(VerBuf, BufLen);
- }
- else
- {
- rc = 1;
- }
-
- fl_shutdown();
-
- CHECK_CLOSE_HANDLE(hDrive);
-
- return rc;
-}
-
-
-
-
-
-static unsigned int g_disk_unxz_len = 0;
-static BYTE *g_part_img_pos = NULL;
-static BYTE *g_part_img_buf[VENTOY_EFI_PART_SIZE / SIZE_1MB];
-
-
-static int VentoyFatMemRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
-{
- uint32 i;
- uint32 offset;
- BYTE *MbBuf = NULL;
-
- for (i = 0; i < SectorCount; i++)
- {
- offset = (Sector + i) * 512;
-
- if (g_part_img_buf[1] == NULL)
- {
- MbBuf = g_part_img_buf[0] + offset;
- memcpy(Buffer + i * 512, MbBuf, 512);
- }
- else
- {
- MbBuf = g_part_img_buf[offset / SIZE_1MB];
- memcpy(Buffer + i * 512, MbBuf + (offset % SIZE_1MB), 512);
- }
- }
-
- return 1;
-}
-
-
-static int VentoyFatMemWrite(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
-{
- uint32 i;
- uint32 offset;
- BYTE *MbBuf = NULL;
-
- for (i = 0; i < SectorCount; i++)
- {
- offset = (Sector + i) * 512;
-
- if (g_part_img_buf[1] == NULL)
- {
- MbBuf = g_part_img_buf[0] + offset;
- memcpy(MbBuf, Buffer + i * 512, 512);
- }
- else
- {
- MbBuf = g_part_img_buf[offset / SIZE_1MB];
- memcpy(MbBuf + (offset % SIZE_1MB), Buffer + i * 512, 512);
- }
- }
-
- return 1;
-}
-
-int VentoyProcSecureBoot(BOOL SecureBoot)
-{
- int rc = 0;
- int size;
- char *filebuf = NULL;
- void *file = NULL;
-
- Log("VentoyProcSecureBoot %d ...", SecureBoot);
-
- if (SecureBoot)
- {
- Log("Secure boot is enabled ...");
- return 0;
- }
-
- fl_init();
-
- if (0 == fl_attach_media(VentoyFatMemRead, VentoyFatMemWrite))
- {
- file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
- Log("Open ventoy efi file %p ", file);
- if (file)
- {
- fl_fseek(file, 0, SEEK_END);
- size = (int)fl_ftell(file);
- fl_fseek(file, 0, SEEK_SET);
-
- Log("ventoy efi file size %d ...", size);
-
- filebuf = (char *)malloc(size);
- if (filebuf)
- {
- fl_fread(filebuf, 1, size, file);
- }
-
- fl_fclose(file);
-
- Log("Now delete all efi files ...");
- fl_remove("/EFI/BOOT/BOOTX64.EFI");
- fl_remove("/EFI/BOOT/grubx64.efi");
- fl_remove("/EFI/BOOT/grubx64_real.efi");
- fl_remove("/EFI/BOOT/MokManager.efi");
-
- file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
- Log("Open bootx64 efi file %p ", file);
- if (file)
- {
- if (filebuf)
- {
- fl_fwrite(filebuf, 1, size, file);
- }
-
- fl_fflush(file);
- fl_fclose(file);
- }
-
- if (filebuf)
- {
- free(filebuf);
- }
- }
- }
- else
- {
- rc = 1;
- }
-
- fl_shutdown();
-
- return rc;
-}
-
-
-
-static int disk_xz_flush(void *src, unsigned int size)
-{
- unsigned int i;
- BYTE *buf = (BYTE *)src;
-
- for (i = 0; i < size; i++)
- {
- *g_part_img_pos = *buf++;
-
- g_disk_unxz_len++;
- if ((g_disk_unxz_len % SIZE_1MB) == 0)
- {
- g_part_img_pos = g_part_img_buf[g_disk_unxz_len / SIZE_1MB];
- }
- else
- {
- g_part_img_pos++;
- }
- }
-
- return (int)size;
-}
-
-static void unxz_error(char *x)
-{
- Log("%s", x);
-}
-
-static BOOL TryWritePart2(HANDLE hDrive, UINT64 StartSectorId)
-{
- BOOL bRet;
- DWORD TrySize = 16 * 1024;
- DWORD dwSize;
- BYTE *Buffer = NULL;
- unsigned char *data = NULL;
- LARGE_INTEGER liCurrentPosition;
-
- liCurrentPosition.QuadPart = StartSectorId * 512;
- SetFilePointerEx(hDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
-
- Buffer = malloc(TrySize);
-
- bRet = WriteFile(hDrive, Buffer, TrySize, &dwSize, NULL);
-
- free(Buffer);
-
- Log("Try write part2 bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
-
- if (bRet && dwSize == TrySize)
- {
- return TRUE;
- }
-
- return FALSE;
-}
-
-static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId)
-{
- int i;
- int rc = 0;
- int len = 0;
- int writelen = 0;
- int partwrite = 0;
- DWORD dwSize = 0;
- BOOL bRet;
- unsigned char *data = NULL;
- LARGE_INTEGER liCurrentPosition;
- LARGE_INTEGER liNewPosition;
-
- Log("FormatPart2Fat %llu...", StartSectorId);
-
- rc = ReadWholeFileToBuf(VENTOY_FILE_DISK_IMG, 0, (void **)&data, &len);
- if (rc)
- {
- Log("Failed to read img file %p %u", data, len);
- return 1;
- }
-
- liCurrentPosition.QuadPart = StartSectorId * 512;
- SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN);
-
- Log("Set file pointer: %llu New pointer:%llu", liCurrentPosition.QuadPart, liNewPosition.QuadPart);
-
- memset(g_part_img_buf, 0, sizeof(g_part_img_buf));
-
- g_part_img_buf[0] = (BYTE *)malloc(VENTOY_EFI_PART_SIZE);
- if (g_part_img_buf[0])
- {
- Log("Malloc whole img buffer success, now decompress ...");
- unxz(data, len, NULL, NULL, g_part_img_buf[0], &writelen, unxz_error);
-
- if (len == writelen)
- {
- Log("decompress finished success");
-
- VentoyProcSecureBoot(g_SecureBoot);
-
- for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
- {
- dwSize = 0;
- bRet = WriteFile(hDrive, g_part_img_buf[0] + i * SIZE_1MB, SIZE_1MB, &dwSize, NULL);
- Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
-
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i);
- }
- }
- else
- {
- rc = 1;
- Log("decompress finished failed");
- goto End;
- }
- }
- else
- {
- Log("Failed to malloc whole img size %u, now split it", VENTOY_EFI_PART_SIZE);
-
- partwrite = 1;
- for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
- {
- g_part_img_buf[i] = (BYTE *)malloc(SIZE_1MB);
- if (g_part_img_buf[i] == NULL)
- {
- rc = 1;
- goto End;
- }
- }
-
- Log("Malloc part img buffer success, now decompress ...");
-
- g_part_img_pos = g_part_img_buf[0];
-
- unxz(data, len, NULL, disk_xz_flush, NULL, NULL, unxz_error);
-
- if (g_disk_unxz_len == VENTOY_EFI_PART_SIZE)
- {
- Log("decompress finished success");
-
- VentoyProcSecureBoot(g_SecureBoot);
-
- for (int i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
- {
- dwSize = 0;
- bRet = WriteFile(hDrive, g_part_img_buf[i], SIZE_1MB, &dwSize, NULL);
- Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
-
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i);
- }
- }
- else
- {
- rc = 1;
- Log("decompress finished failed");
- goto End;
- }
- }
-
-End:
-
- if (data) free(data);
-
- if (partwrite)
- {
- for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
- {
- if (g_part_img_buf[i]) free(g_part_img_buf[i]);
- }
- }
- else
- {
- if (g_part_img_buf[0]) free(g_part_img_buf[0]);
- }
-
- return rc;
-}
-
-static int WriteGrubStage1ToPhyDrive(HANDLE hDrive, int PartStyle)
-{
- int Len = 0;
- int readLen = 0;
- BOOL bRet;
- DWORD dwSize;
- BYTE *ImgBuf = NULL;
- BYTE *RawBuf = NULL;
-
- Log("WriteGrubStage1ToPhyDrive ...");
-
- RawBuf = (BYTE *)malloc(SIZE_1MB);
- if (!RawBuf)
- {
- return 1;
- }
-
- if (ReadWholeFileToBuf(VENTOY_FILE_STG1_IMG, 0, (void **)&ImgBuf, &Len))
- {
- Log("Failed to read stage1 img");
- free(RawBuf);
- return 1;
- }
-
- unxz(ImgBuf, Len, NULL, NULL, RawBuf, &readLen, unxz_error);
-
- if (PartStyle)
- {
- Log("Write GPT stage1 ...");
- RawBuf[500] = 35;//update blocklist
- SetFilePointer(hDrive, 512 * 34, NULL, FILE_BEGIN);
- bRet = WriteFile(hDrive, RawBuf, SIZE_1MB - 512 * 34, &dwSize, NULL);
- }
- else
- {
- Log("Write MBR stage1 ...");
- SetFilePointer(hDrive, 512, NULL, FILE_BEGIN);
- bRet = WriteFile(hDrive, RawBuf, SIZE_1MB - 512, &dwSize, NULL);
- }
-
- Log("WriteFile Ret:%u dwSize:%u ErrCode:%u", bRet, dwSize, GetLastError());
-
- free(RawBuf);
- free(ImgBuf);
- return 0;
-}
-
-
-
-static int FormatPart1exFAT(UINT64 DiskSizeBytes)
-{
- MKFS_PARM Option;
- FRESULT Ret;
- FATFS fs;
-
- Option.fmt = FM_EXFAT;
- Option.n_fat = 1;
- Option.align = 8;
- Option.n_root = 1;
-
- // < 32GB select 32KB as cluster size
- // > 32GB select 128KB as cluster size
- if (DiskSizeBytes / 1024 / 1024 / 1024 <= 32)
- {
- Option.au_size = 32768;
- }
- else
- {
- Option.au_size = 131072;
- }
-
- Log("Formatting Part1 exFAT ...");
-
- Ret = f_mkfs(TEXT("0:"), &Option, 0, 8 * 1024 * 1024);
-
- if (FR_OK == Ret)
- {
- Log("Formatting Part1 exFAT success");
-
- Ret = f_mount(&fs, TEXT("0:"), 1);
- Log("mount part %d", Ret);
-
- if (FR_OK == Ret)
- {
- Ret = f_setlabel(TEXT("Ventoy"));
- Log("f_setlabel %d", Ret);
-
- Ret = f_mount(0, TEXT("0:"), 1);
- Log("umount part %d", Ret);
- return 0;
- }
- else
- {
- Log("mount exfat failed %d", Ret);
- return 1;
- }
- }
- else
- {
- Log("Formatting Part1 exFAT failed");
- return 1;
- }
-}
-
-
-
-int ClearVentoyFromPhyDrive(HWND hWnd, PHY_DRIVE_INFO *pPhyDrive, char *pDrvLetter)
-{
- int i;
- int rc = 0;
- int state = 0;
- HANDLE hDrive;
- DWORD dwSize;
- BOOL bRet;
- CHAR MountDrive;
- CHAR DriveName[] = "?:\\";
- CHAR DriveLetters[MAX_PATH] = { 0 };
- LARGE_INTEGER liCurrentPosition;
- char *pTmpBuf = NULL;
- MBR_HEAD MBR;
-
- *pDrvLetter = 0;
-
- Log("ClearVentoyFromPhyDrive PhyDrive%d <<%s %s %dGB>>",
- pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
- GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
-
- Log("Lock disk for clean ............................. ");
-
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to open physical disk");
- return 1;
- }
-
- GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
-
- if (DriveLetters[0] == 0)
- {
- Log("No drive letter was assigned...");
- DriveName[0] = GetFirstUnusedDriveLetter();
- Log("GetFirstUnusedDriveLetter %C: ...", DriveName[0]);
- }
- 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];
- bRet = DeleteVolumeMountPointA(DriveName);
- Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, GetLastError());
- }
- }
-
- MountDrive = DriveName[0];
- Log("Will use '%C:' as volume mountpoint", DriveName[0]);
-
- // 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);
-
- PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART);
-
- if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE))
- {
- Log("Notice: Could not delete partitions: %u", GetLastError());
- }
-
- Log("Deleting all partitions ......................... OK");
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);
-
- Log("Lock disk for write ............................. ");
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to GetPhysicalHandle for write.");
- rc = 1;
- goto End;
- }
-
- // clear first and last 1MB space
- pTmpBuf = malloc(SIZE_1MB);
- if (!pTmpBuf)
- {
- Log("Failed to alloc memory.");
- rc = 1;
- goto End;
- }
- memset(pTmpBuf, 0, SIZE_1MB);
-
- SET_FILE_POS(512);
- bRet = WriteFile(hDrive, pTmpBuf, SIZE_1MB - 512, &dwSize, NULL);
- Log("Write fisrt 1MB ret:%d size:%u err:%d", bRet, dwSize, LASTERR);
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- SET_FILE_POS(SIZE_1MB);
- bRet = WriteFile(hDrive, pTmpBuf, SIZE_1MB, &dwSize, NULL);
- Log("Write 2nd 1MB ret:%d size:%u err:%d", bRet, dwSize, LASTERR);
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- SET_FILE_POS(0);
- bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
- Log("Read MBR ret:%d size:%u err:%d", bRet, dwSize, LASTERR);
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- //clear boot code and partition table (reserved disk signature)
- memset(MBR.BootCode, 0, 440);
- memset(MBR.PartTbl, 0, sizeof(MBR.PartTbl));
-
- VentoyFillLocation(pPhyDrive->SizeInBytes, 2048, (UINT32)(pPhyDrive->SizeInBytes / 512 - 2048), MBR.PartTbl);
-
- MBR.PartTbl[0].Active = 0x00; // bootable
- MBR.PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS
-
- SET_FILE_POS(0);
- bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);
- Log("Write MBR ret:%d size:%u err:%d", bRet, dwSize, LASTERR);
- if (!bRet)
- {
- rc = 1;
- goto End;
- }
-
- Log("Clear Ventoy successfully finished");
-
- //Refresh Drive Layout
- DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
-
-End:
-
- PROGRESS_BAR_SET_POS(PT_MOUNT_VOLUME);
-
- if (pTmpBuf)
- {
- free(pTmpBuf);
- }
-
- if (rc == 0)
- {
- Log("Mounting Ventoy Partition ....................... ");
- Sleep(1000);
-
- state = 0;
- memset(DriveLetters, 0, sizeof(DriveLetters));
- GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
- Log("Logical drive letter after write ventoy: <%s>", DriveLetters);
-
- for (i = 0; i < sizeof(DriveLetters) && DriveLetters[i]; i++)
- {
- DriveName[0] = DriveLetters[i];
- Log("%s is ventoy part1, already mounted", DriveName);
- state = 1;
- }
-
- if (state != 1)
- {
- Log("need to mount ventoy part1...");
- if (0 == GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[0].StartSectorId, DriveLetters, sizeof(DriveLetters), FALSE))
- {
- DriveName[0] = MountDrive;
- bRet = SetVolumeMountPointA(DriveName, DriveLetters);
- Log("SetVolumeMountPoint <%s> <%s> bRet:%u code:%u", DriveName, DriveLetters, bRet, GetLastError());
-
- *pDrvLetter = MountDrive;
- }
- else
- {
- Log("Failed to find ventoy volume");
- }
- }
-
- Log("OK\n");
- }
- else
- {
- FindProcessOccupyDisk(hDrive, pPhyDrive);
- }
-
- CHECK_CLOSE_HANDLE(hDrive);
- return rc;
-}
-
-int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle)
-{
- int i;
- int rc = 0;
- int state = 0;
- HANDLE hDrive;
- DWORD dwSize;
- BOOL bRet;
- CHAR MountDrive;
- CHAR DriveName[] = "?:\\";
- CHAR DriveLetters[MAX_PATH] = { 0 };
- MBR_HEAD MBR;
- VTOY_GPT_INFO *pGptInfo = NULL;
-
- Log("InstallVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>",
- PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
- GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
-
- if (PartStyle)
- {
- pGptInfo = malloc(sizeof(VTOY_GPT_INFO));
- memset(pGptInfo, 0, sizeof(VTOY_GPT_INFO));
- }
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
-
- VentoyFillMBR(pPhyDrive->SizeInBytes, &MBR, PartStyle);//also used to format 1st partition in GPT mode
- if (PartStyle)
- {
- VentoyFillGpt(pPhyDrive->SizeInBytes, pGptInfo);
- }
-
- Log("Lock disk for clean ............................. ");
-
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to open physical disk");
- free(pGptInfo);
- return 1;
- }
-
- GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
-
- if (DriveLetters[0] == 0)
- {
- Log("No drive letter was assigned...");
- DriveName[0] = GetFirstUnusedDriveLetter();
- Log("GetFirstUnusedDriveLetter %C: ...", DriveName[0]);
- }
- 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];
- bRet = DeleteVolumeMountPointA(DriveName);
- Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, GetLastError());
- }
- }
-
- MountDrive = DriveName[0];
- Log("Will use '%C:' as volume mountpoint", DriveName[0]);
-
- // 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);
-
- PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART);
-
- if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE))
- {
- Log("Notice: Could not delete partitions: %u", GetLastError());
- }
-
- Log("Deleting all partitions ......................... OK");
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);
-
- Log("Lock disk for write ............................. ");
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to GetPhysicalHandle for write.");
- rc = 1;
- goto End;
- }
-
- //Refresh Drive Layout
- DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
-
- disk_io_set_param(hDrive, MBR.PartTbl[0].StartSectorId + MBR.PartTbl[0].SectorCount);
-
- PROGRESS_BAR_SET_POS(PT_FORMAT_PART1);
-
- Log("Formatting part1 exFAT ...");
- if (0 != FormatPart1exFAT(pPhyDrive->SizeInBytes))
- {
- Log("FormatPart1exFAT failed.");
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);
- Log("Writing part2 FAT img ...");
- if (0 != FormatPart2Fat(hDrive, MBR.PartTbl[1].StartSectorId))
- {
- Log("FormatPart2Fat failed.");
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_WRITE_STG1_IMG);
- Log("Writting Boot Image ............................. ");
- if (WriteGrubStage1ToPhyDrive(hDrive, PartStyle) != 0)
- {
- Log("WriteGrubStage1ToPhyDrive failed.");
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_WRITE_PART_TABLE);
- Log("Writting Partition Table ........................ ");
- SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
-
- if (PartStyle)
- {
- VTOY_GPT_HDR BackupHead;
- LARGE_INTEGER liCurrentPosition;
-
- SET_FILE_POS(pPhyDrive->SizeInBytes - 512);
- VentoyFillBackupGptHead(pGptInfo, &BackupHead);
- if (!WriteFile(hDrive, &BackupHead, sizeof(VTOY_GPT_HDR), &dwSize, NULL))
- {
- rc = 1;
- Log("Write GPT Backup Head Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());
- goto End;
- }
-
- SET_FILE_POS(pPhyDrive->SizeInBytes - 512 * 33);
- if (!WriteFile(hDrive, pGptInfo->PartTbl, sizeof(pGptInfo->PartTbl), &dwSize, NULL))
- {
- rc = 1;
- Log("Write GPT Backup Part Table Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());
- goto End;
- }
-
- SET_FILE_POS(0);
- if (!WriteFile(hDrive, pGptInfo, sizeof(VTOY_GPT_INFO), &dwSize, NULL))
- {
- rc = 1;
- Log("Write GPT Info Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());
- goto End;
- }
-
- Log("Write GPT Info OK ...");
- }
- else
- {
- if (!WriteFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL))
- {
- rc = 1;
- Log("Write MBR Failed, dwSize:%u ErrCode:%u", dwSize, GetLastError());
- goto End;
- }
- Log("Write MBR OK ...");
- }
-
-
- //Refresh Drive Layout
- DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
-
-End:
-
- PROGRESS_BAR_SET_POS(PT_MOUNT_VOLUME);
-
- if (rc == 0)
- {
- Log("Mounting Ventoy Partition ....................... ");
- Sleep(1000);
-
- state = 0;
- memset(DriveLetters, 0, sizeof(DriveLetters));
- GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
- Log("Logical drive letter after write ventoy: <%s>", DriveLetters);
-
- for (i = 0; i < sizeof(DriveLetters) && DriveLetters[i]; i++)
- {
- DriveName[0] = DriveLetters[i];
- if (IsVentoyLogicalDrive(DriveName[0]))
- {
- Log("%s is ventoy part2, delete mountpoint", DriveName);
- DeleteVolumeMountPointA(DriveName);
- }
- else
- {
- Log("%s is ventoy part1, already mounted", DriveName);
- state = 1;
- }
- }
-
- if (state != 1)
- {
- Log("need to mount ventoy part1...");
- if (0 == GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[0].StartSectorId, DriveLetters, sizeof(DriveLetters), FALSE))
- {
- DriveName[0] = MountDrive;
- bRet = SetVolumeMountPointA(DriveName, DriveLetters);
- Log("SetVolumeMountPoint <%s> <%s> bRet:%u code:%u", DriveName, DriveLetters, bRet, GetLastError());
- }
- else
- {
- Log("Failed to find ventoy volume");
- }
- }
- Log("OK\n");
- }
- else
- {
- FindProcessOccupyDisk(hDrive, pPhyDrive);
- }
-
- if (pGptInfo)
- {
- free(pGptInfo);
- }
-
- CHECK_CLOSE_HANDLE(hDrive);
- return rc;
-}
-
-int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive)
-{
- 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;
- UINT64 ReservedMB = 0;
- MBR_HEAD BootImg;
- MBR_HEAD MBR;
- VTOY_GPT_INFO *pGptInfo = NULL;
-
- Log("UpdateVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>",
- pPhyDrive->PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
- GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
-
- 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;
- }
-
- if (pPhyDrive->PartStyle)
- {
- pGptInfo = malloc(sizeof(VTOY_GPT_INFO));
- if (!pGptInfo)
- {
- return 1;
- }
-
- 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);
-
- 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);
-
- 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);
- }
-
- 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;
- }
- }
- }
-
- // 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);
-
- PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);
-
- Log("Lock disk for update ............................ ");
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to GetPhysicalHandle for write.");
- rc = 1;
- goto End;
- }
-
- PROGRESS_BAR_SET_POS(PT_LOCK_VOLUME);
-
- Log("Lock volume for update .......................... ");
- hVolume = INVALID_HANDLE_VALUE;
- Status = GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[1].StartSectorId, DriveLetters, sizeof(DriveLetters), TRUE);
- 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);
-
- if (hVolume == INVALID_HANDLE_VALUE)
- {
- Log("Failed to create file volume, errcode:%u", LASTERR);
- rc = 1;
- goto End;
- }
-
- 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);
- }
- else if (ERROR_NOT_FOUND == Status)
- {
- Log("Volume not found, maybe not supported");
- }
- else
- {
- rc = 1;
- goto End;
- }
-
-
- if (!TryWritePart2(hDrive, StartSector))
- {
- ForceMBR = TRUE;
- Log("Try write failed, now delete partition 2...");
-
- CHECK_CLOSE_HANDLE(hDrive);
-
- Log("Now delete partition 2...");
- DeletePartitions(pPhyDrive->PhyDrive, TRUE);
-
- hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
- if (hDrive == INVALID_HANDLE_VALUE)
- {
- Log("Failed to GetPhysicalHandle for write.");
- rc = 1;
- goto End;
- }
- }
-
-
- PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);
-
- Log("Write Ventoy to disk ............................ ");
- if (0 != FormatPart2Fat(hDrive, StartSector))
- {
- rc = 1;
- goto End;
- }
-
- if (hVolume != INVALID_HANDLE_VALUE)
- {
- bRet = DeviceIoControl(hVolume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
- Log("FSCTL_UNLOCK_VOLUME bRet:%u code:%u", bRet, LASTERR);
- CHECK_CLOSE_HANDLE(hVolume);
- }
-
- Log("Updating Boot Image ............................. ");
- if (WriteGrubStage1ToPhyDrive(hDrive, pPhyDrive->PartStyle) != 0)
- {
- rc = 1;
- goto End;
- }
-
- // Boot Image
- VentoyGetLocalBootImg(&BootImg);
-
- // Use Old UUID
- memcpy(BootImg.BootCode + 0x180, MBR.BootCode + 0x180, 16);
- if (pPhyDrive->PartStyle)
- {
- BootImg.BootCode[92] = 0x22;
- }
-
- if (ForceMBR == FALSE && memcmp(BootImg.BootCode, MBR.BootCode, 440) == 0)
- {
- Log("Boot image has no difference, no need to write.");
- }
- else
- {
- Log("Boot image need to write %u.", ForceMBR);
-
- SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
-
- memcpy(MBR.BootCode, BootImg.BootCode, 440);
- bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);
- Log("Write Boot Image ret:%u dwSize:%u Error:%u", bRet, dwSize, LASTERR);
- }
-
- if (pPhyDrive->PartStyle == 0)
- {
- if (0x00 == MBR.PartTbl[0].Active && 0x80 == MBR.PartTbl[1].Active)
- {
- Log("Need to chage 1st partition active and 2nd partition inactive.");
-
- MBR.PartTbl[0].Active = 0x80;
- MBR.PartTbl[1].Active = 0x00;
-
- SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
- bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);
- Log("Write NEW MBR ret:%u dwSize:%u Error:%u", bRet, dwSize, LASTERR);
- }
- }
-
- //Refresh Drive Layout
- DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
-
-End:
-
- if (rc == 0)
- {
- Log("OK");
- }
- else
- {
- FindProcessOccupyDisk(hDrive, pPhyDrive);
- }
-
- CHECK_CLOSE_HANDLE(hDrive);
-
- if (pGptInfo)
- {
- free(pGptInfo);
- }
-
- return rc;
-}
-
-
+/******************************************************************************\r
+ * PhyDrive.c\r
+ *\r
+ * Copyright (c) 2020, longpanda <admin@ventoy.net>\r
+ * Copyright (c) 2011-2020, Pete Batard <pete@akeo.ie>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License as\r
+ * published by the Free Software Foundation; either version 3 of the\r
+ * License, or (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+ \r
+#include <Windows.h>\r
+#include <winternl.h>\r
+#include <commctrl.h>\r
+#include <initguid.h>\r
+#include <vds.h>\r
+#include "resource.h"\r
+#include "Language.h"\r
+#include "Ventoy2Disk.h"\r
+#include "fat_filelib.h"\r
+#include "ff.h"\r
+\r
+/* \r
+ * Some code and functions in the file are copied from rufus.\r
+ * https://github.com/pbatard/rufus\r
+ */\r
+#define VDS_SET_ERROR SetLastError\r
+#define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService)\r
+#define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum)\r
+#define IVdsService_WaitForServiceReady(This) ((This)->lpVtbl->WaitForServiceReady(This))\r
+#define IVdsService_CleanupObsoleteMountPoints(This) ((This)->lpVtbl->CleanupObsoleteMountPoints(This))\r
+#define IVdsService_Refresh(This) ((This)->lpVtbl->Refresh(This))\r
+#define IVdsService_Reenumerate(This) ((This)->lpVtbl->Reenumerate(This)) \r
+#define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)\r
+#define IVdsProvider_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum)\r
+#define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum)\r
+#define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties)\r
+#define IVdsDisk_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)\r
+#define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions)\r
+#define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected)\r
+#define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync)\r
+#define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This)\r
+#define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched)\r
+#define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum)\r
+#define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)\r
+#define IVdsVolume_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths)\r
+#define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync)\r
+#define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This)\r
+#define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties)\r
+#define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This)\r
+#define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted)\r
+#define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut)\r
+#define IVdsAsync_Release(This) (This)->lpVtbl->Release(This)\r
+\r
+#define IUnknown_QueryInterface(This, a, b) (This)->lpVtbl->QueryInterface(This,a,b)\r
+#define IUnknown_Release(This) (This)->lpVtbl->Release(This)\r
+\r
+/*\r
+* Delete all the partitions from a disk, using VDS\r
+* 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\r
+*/\r
+BOOL DeletePartitions(DWORD DriveIndex, BOOL OnlyPart2)\r
+{\r
+ BOOL r = FALSE;\r
+ HRESULT hr;\r
+ ULONG ulFetched;\r
+ wchar_t wPhysicalName[48];\r
+ IVdsServiceLoader *pLoader;\r
+ IVdsService *pService;\r
+ IEnumVdsObject *pEnum;\r
+ IUnknown *pUnk;\r
+\r
+ swprintf_s(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive%lu", DriveIndex);\r
+\r
+ // Initialize COM\r
+ CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);\r
+ CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,\r
+ RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);\r
+\r
+ // Create a VDS Loader Instance\r
+ hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,\r
+ &IID_IVdsServiceLoader, (void **)&pLoader);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not create VDS Loader Instance: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Load the VDS Service\r
+ hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);\r
+ IVdsServiceLoader_Release(pLoader);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not load VDS Service: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Wait for the Service to become ready if needed\r
+ hr = IVdsService_WaitForServiceReady(pService);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("VDS Service is not ready: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Query the VDS Service Providers\r
+ hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not query VDS Service Providers: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) {\r
+ IVdsProvider *pProvider;\r
+ IVdsSwProvider *pSwProvider;\r
+ IEnumVdsObject *pEnumPack;\r
+ IUnknown *pPackUnk;\r
+\r
+ // Get VDS Provider\r
+ hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider);\r
+ IUnknown_Release(pUnk);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not get VDS Provider: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Get VDS Software Provider\r
+ hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider);\r
+ IVdsProvider_Release(pProvider);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not get VDS Software Provider: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Get VDS Software Provider Packs\r
+ hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);\r
+ IVdsSwProvider_Release(pSwProvider);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not get VDS Software Provider Packs: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Enumerate Provider Packs\r
+ while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) == S_OK) {\r
+ IVdsPack *pPack;\r
+ IEnumVdsObject *pEnumDisk;\r
+ IUnknown *pDiskUnk;\r
+\r
+ hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack);\r
+ IUnknown_Release(pPackUnk);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not query VDS Software Provider Pack: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Use the pack interface to access the disks\r
+ hr = IVdsPack_QueryDisks(pPack, &pEnumDisk);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not query VDS disks: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // List disks\r
+ while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFetched) == S_OK) {\r
+ VDS_DISK_PROP diskprop;\r
+ VDS_PARTITION_PROP* prop_array;\r
+ LONG i, prop_array_size;\r
+ IVdsDisk *pDisk;\r
+ IVdsAdvancedDisk *pAdvancedDisk;\r
+\r
+ // Get the disk interface.\r
+ hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not query VDS Disk Interface: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Get the disk properties\r
+ hr = IVdsDisk_GetProperties(pDisk, &diskprop);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not query VDS Disk Properties: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Isolate the disk we want\r
+ if (_wcsicmp(wPhysicalName, diskprop.pwszName) != 0) {\r
+ IVdsDisk_Release(pDisk);\r
+ continue;\r
+ }\r
+\r
+ // Instantiate the AdvanceDisk interface for our disk.\r
+ hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk);\r
+ IVdsDisk_Release(pDisk);\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not access VDS Advanced Disk interface: %u", LASTERR);\r
+ goto out;\r
+ }\r
+\r
+ // Query the partition data, so we can get the start offset, which we need for deletion\r
+ hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size);\r
+ if (hr == S_OK) {\r
+ Log("Deleting ALL partition(s) from disk '%S':", diskprop.pwszName);\r
+ // Now go through each partition\r
+ for (i = 0; i < prop_array_size; i++) {\r
+ \r
+ Log("* Partition %d (offset: %lld, size: %llu)", prop_array[i].ulPartitionNumber,\r
+ prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize);\r
+\r
+ if (OnlyPart2 && prop_array[i].ullOffset == 2048*512)\r
+ {\r
+ Log("Skip this partition...");\r
+ continue;\r
+ }\r
+\r
+\r
+ hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE);\r
+ if (hr != S_OK) {\r
+ r = FALSE;\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not delete partitions: %u", LASTERR);\r
+ }\r
+ }\r
+ r = TRUE;\r
+ }\r
+ else {\r
+ Log("No partition to delete on disk '%S'", diskprop.pwszName);\r
+ r = TRUE;\r
+ }\r
+ CoTaskMemFree(prop_array);\r
+\r
+#if 0\r
+ // Issue a Clean while we're at it\r
+ HRESULT hr2 = E_FAIL;\r
+ ULONG completed;\r
+ IVdsAsync* pAsync;\r
+ hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, FALSE, FALSE, &pAsync);\r
+ while (SUCCEEDED(hr)) {\r
+ if (IS_ERROR(FormatStatus)) {\r
+ IVdsAsync_Cancel(pAsync);\r
+ break;\r
+ }\r
+ hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);\r
+ if (SUCCEEDED(hr)) {\r
+ hr = hr2;\r
+ if (hr == S_OK)\r
+ break;\r
+ if (hr == VDS_E_OPERATION_PENDING)\r
+ hr = S_OK;\r
+ }\r
+ Sleep(500);\r
+ }\r
+ if (hr != S_OK) {\r
+ VDS_SET_ERROR(hr);\r
+ Log("Could not clean disk: %s", LASTERR);\r
+ }\r
+#endif\r
+ IVdsAdvancedDisk_Release(pAdvancedDisk);\r
+ goto out;\r
+ }\r
+ }\r
+ }\r
+\r
+out:\r
+ return r;\r
+}\r
+\r
+\r
+static DWORD GetVentoyVolumeName(int PhyDrive, UINT32 StartSectorId, CHAR *NameBuf, UINT32 BufLen, BOOL DelSlash)\r
+{\r
+ size_t len;\r
+ BOOL bRet;\r
+ DWORD dwSize;\r
+ HANDLE hDrive;\r
+ HANDLE hVolume;\r
+ UINT64 PartOffset;\r
+ DWORD Status = ERROR_NOT_FOUND;\r
+ DISK_EXTENT *pExtents = NULL;\r
+ CHAR VolumeName[MAX_PATH] = { 0 };\r
+ VOLUME_DISK_EXTENTS DiskExtents;\r
+\r
+ PartOffset = 512ULL * StartSectorId;\r
+\r
+ Log("GetVentoyVolumeName PhyDrive %d SectorStart:%u PartOffset:%llu", PhyDrive, StartSectorId, (ULONGLONG)PartOffset);\r
+\r
+ hVolume = FindFirstVolumeA(VolumeName, sizeof(VolumeName));\r
+ if (hVolume == INVALID_HANDLE_VALUE)\r
+ {\r
+ return 1;\r
+ }\r
+\r
+ do {\r
+\r
+ len = strlen(VolumeName);\r
+ Log("Find volume:%s", VolumeName);\r
+\r
+ VolumeName[len - 1] = 0;\r
+\r
+ hDrive = CreateFileA(VolumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ bRet = DeviceIoControl(hDrive,\r
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,\r
+ NULL,\r
+ 0,\r
+ &DiskExtents,\r
+ (DWORD)(sizeof(DiskExtents)),\r
+ (LPDWORD)&dwSize,\r
+ NULL);\r
+\r
+ Log("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS bRet:%u code:%u", bRet, LASTERR);\r
+ Log("NumberOfDiskExtents:%u DiskNumber:%u", DiskExtents.NumberOfDiskExtents, DiskExtents.Extents[0].DiskNumber);\r
+\r
+ if (bRet && DiskExtents.NumberOfDiskExtents == 1)\r
+ {\r
+ pExtents = DiskExtents.Extents;\r
+\r
+ Log("This volume DiskNumber:%u offset:%llu", pExtents->DiskNumber, (ULONGLONG)pExtents->StartingOffset.QuadPart);\r
+ if ((int)pExtents->DiskNumber == PhyDrive && pExtents->StartingOffset.QuadPart == PartOffset)\r
+ {\r
+ Log("This volume match");\r
+\r
+ if (!DelSlash)\r
+ {\r
+ VolumeName[len - 1] = '\\';\r
+ }\r
+\r
+ sprintf_s(NameBuf, BufLen, "%s", VolumeName);\r
+ Status = ERROR_SUCCESS;\r
+ CloseHandle(hDrive);\r
+ break;\r
+ }\r
+ }\r
+\r
+ CloseHandle(hDrive);\r
+ } while (FindNextVolumeA(hVolume, VolumeName, sizeof(VolumeName)));\r
+\r
+ FindVolumeClose(hVolume);\r
+\r
+ Log("GetVentoyVolumeName return %u", Status);\r
+ return Status;\r
+}\r
+\r
+static int GetLettersBelongPhyDrive(int PhyDrive, char *DriveLetters, size_t Length)\r
+{\r
+ int n = 0;\r
+ DWORD DataSize = 0;\r
+ CHAR *Pos = NULL;\r
+ CHAR *StringBuf = NULL;\r
+\r
+ DataSize = GetLogicalDriveStringsA(0, NULL);\r
+ StringBuf = (CHAR *)malloc(DataSize + 1);\r
+ if (StringBuf == NULL)\r
+ {\r
+ return 1;\r
+ }\r
+\r
+ GetLogicalDriveStringsA(DataSize, StringBuf);\r
+\r
+ for (Pos = StringBuf; *Pos; Pos += strlen(Pos) + 1)\r
+ {\r
+ if (n < (int)Length && PhyDrive == GetPhyDriveByLogicalDrive(Pos[0]))\r
+ {\r
+ Log("%C: is belong to phydrive%d", Pos[0], PhyDrive);\r
+ DriveLetters[n++] = Pos[0];\r
+ }\r
+ }\r
+\r
+ free(StringBuf);\r
+ return 0;\r
+}\r
+\r
+static HANDLE GetPhysicalHandle(int Drive, BOOLEAN bLockDrive, BOOLEAN bWriteAccess, BOOLEAN bWriteShare)\r
+{\r
+ int i;\r
+ DWORD dwSize;\r
+ DWORD LastError;\r
+ UINT64 EndTime;\r
+ HANDLE hDrive = INVALID_HANDLE_VALUE;\r
+ CHAR PhyDrive[128];\r
+ CHAR DevPath[MAX_PATH] = { 0 };\r
+\r
+ safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", Drive);\r
+\r
+ if (0 == QueryDosDeviceA(PhyDrive + 4, DevPath, sizeof(DevPath)))\r
+ {\r
+ Log("QueryDosDeviceA failed error:%u", GetLastError());\r
+ strcpy_s(DevPath, sizeof(DevPath), "???");\r
+ }\r
+ else\r
+ {\r
+ Log("QueryDosDeviceA success %s", DevPath);\r
+ }\r
+\r
+ for (i = 0; i < DRIVE_ACCESS_RETRIES; i++)\r
+ {\r
+ // Try without FILE_SHARE_WRITE (unless specifically requested) so that\r
+ // we won't be bothered by the OS or other apps when we set up our data.\r
+ // However this means we might have to wait for an access gap...\r
+ // We keep FILE_SHARE_READ though, as this shouldn't hurt us any, and is\r
+ // required for enumeration.\r
+ hDrive = CreateFileA(PhyDrive,\r
+ GENERIC_READ | (bWriteAccess ? GENERIC_WRITE : 0),\r
+ FILE_SHARE_READ | (bWriteShare ? FILE_SHARE_WRITE : 0),\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,\r
+ NULL);\r
+\r
+ LastError = GetLastError();\r
+ Log("[%d] CreateFileA %s code:%u %p", i, PhyDrive, LastError, hDrive);\r
+\r
+ if (hDrive != INVALID_HANDLE_VALUE)\r
+ {\r
+ break;\r
+ }\r
+\r
+ if ((LastError != ERROR_SHARING_VIOLATION) && (LastError != ERROR_ACCESS_DENIED))\r
+ {\r
+ break;\r
+ }\r
+\r
+ if (i == 0)\r
+ {\r
+ Log("Waiting for access on %s [%s]...", PhyDrive, DevPath);\r
+ }\r
+ else if (!bWriteShare && (i > DRIVE_ACCESS_RETRIES / 3))\r
+ {\r
+ // If we can't seem to get a hold of the drive for some time, try to enable FILE_SHARE_WRITE...\r
+ Log("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");\r
+ bWriteShare = TRUE;\r
+\r
+ // Try to report the process that is locking the drive\r
+ // We also use bit 6 as a flag to indicate that SearchProcess was called.\r
+ //access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE) | 0x40;\r
+\r
+ }\r
+ Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);\r
+ }\r
+\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Could not open %s %u", PhyDrive, LASTERR);\r
+ goto End;\r
+ }\r
+\r
+ if (bWriteAccess)\r
+ {\r
+ Log("Opened %s for %s write access", PhyDrive, bWriteShare ? "shared" : "exclusive");\r
+ }\r
+\r
+ if (bLockDrive)\r
+ {\r
+ if (DeviceIoControl(hDrive, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwSize, NULL))\r
+ {\r
+ Log("I/O boundary checks disabled");\r
+ }\r
+\r
+ EndTime = GetTickCount64() + DRIVE_ACCESS_TIMEOUT;\r
+\r
+ do {\r
+ if (DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL))\r
+ {\r
+ Log("FSCTL_LOCK_VOLUME success");\r
+ goto End;\r
+ }\r
+ Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);\r
+ } while (GetTickCount64() < EndTime);\r
+\r
+ // If we reached this section, either we didn't manage to get a lock or the user cancelled\r
+ Log("Could not lock access to %s %u", PhyDrive, LASTERR);\r
+\r
+ // See if we can report the processes are accessing the drive\r
+ //if (!IS_ERROR(FormatStatus) && (access_mask == 0))\r
+ // access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE);\r
+ // Try to continue if the only access rights we saw were for read-only\r
+ //if ((access_mask & 0x07) != 0x01)\r
+ // safe_closehandle(hDrive);\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+ }\r
+\r
+End:\r
+\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Can get handle of %s, maybe some process control it.", DevPath);\r
+ }\r
+\r
+ return hDrive;\r
+}\r
+\r
+int GetPhyDriveByLogicalDrive(int DriveLetter)\r
+{\r
+ BOOL Ret;\r
+ DWORD dwSize;\r
+ HANDLE Handle;\r
+ VOLUME_DISK_EXTENTS DiskExtents;\r
+ CHAR PhyPath[128];\r
+\r
+ safe_sprintf(PhyPath, "\\\\.\\%C:", (CHAR)DriveLetter);\r
+\r
+ Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);\r
+ if (Handle == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Could not open the disk<%s>, error:%u", PhyPath, LASTERR);\r
+ return -1;\r
+ }\r
+\r
+ Ret = DeviceIoControl(Handle,\r
+ IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,\r
+ NULL,\r
+ 0,\r
+ &DiskExtents,\r
+ (DWORD)(sizeof(DiskExtents)),\r
+ (LPDWORD)&dwSize,\r
+ NULL);\r
+\r
+ if (!Ret || DiskExtents.NumberOfDiskExtents == 0)\r
+ {\r
+ Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, LASTERR);\r
+ CHECK_CLOSE_HANDLE(Handle);\r
+ return -1;\r
+ }\r
+ CHECK_CLOSE_HANDLE(Handle);\r
+\r
+ Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",\r
+ PhyPath,\r
+ DiskExtents.Extents[0].DiskNumber,\r
+ DiskExtents.Extents[0].StartingOffset.QuadPart,\r
+ DiskExtents.Extents[0].ExtentLength.QuadPart\r
+ );\r
+\r
+ return (int)DiskExtents.Extents[0].DiskNumber;\r
+}\r
+\r
+int GetAllPhysicalDriveInfo(PHY_DRIVE_INFO *pDriveList, DWORD *pDriveCount)\r
+{\r
+ int i;\r
+ int Count;\r
+ int id;\r
+ int Letter = 'A';\r
+ BOOL bRet;\r
+ DWORD dwBytes;\r
+ DWORD DriveCount = 0;\r
+ HANDLE Handle = INVALID_HANDLE_VALUE;\r
+ CHAR PhyDrive[128];\r
+ PHY_DRIVE_INFO *CurDrive = pDriveList;\r
+ GET_LENGTH_INFORMATION LengthInfo;\r
+ STORAGE_PROPERTY_QUERY Query;\r
+ STORAGE_DESCRIPTOR_HEADER DevDescHeader;\r
+ STORAGE_DEVICE_DESCRIPTOR *pDevDesc;\r
+ int PhyDriveId[VENTOY_MAX_PHY_DRIVE];\r
+\r
+ Count = GetPhysicalDriveCount();\r
+\r
+ for (i = 0; i < Count && i < VENTOY_MAX_PHY_DRIVE; i++)\r
+ {\r
+ PhyDriveId[i] = i;\r
+ }\r
+\r
+ dwBytes = GetLogicalDrives();\r
+ Log("Logical Drives: 0x%x", dwBytes);\r
+ while (dwBytes)\r
+ {\r
+ if (dwBytes & 0x01)\r
+ {\r
+ id = GetPhyDriveByLogicalDrive(Letter);\r
+ Log("%C --> %d", Letter, id);\r
+ if (id >= 0)\r
+ {\r
+ for (i = 0; i < Count; i++)\r
+ {\r
+ if (PhyDriveId[i] == id)\r
+ {\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (i >= Count)\r
+ {\r
+ Log("Add phy%d to list", i);\r
+ PhyDriveId[Count] = id;\r
+ Count++;\r
+ }\r
+ }\r
+ }\r
+\r
+ Letter++;\r
+ dwBytes >>= 1;\r
+ }\r
+\r
+ for (i = 0; i < Count && DriveCount < VENTOY_MAX_PHY_DRIVE; i++)\r
+ {\r
+ CHECK_CLOSE_HANDLE(Handle);\r
+\r
+ safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", PhyDriveId[i]);\r
+ Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); \r
+ Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);\r
+\r
+ if (Handle == INVALID_HANDLE_VALUE)\r
+ {\r
+ continue;\r
+ }\r
+\r
+ bRet = DeviceIoControl(Handle,\r
+ IOCTL_DISK_GET_LENGTH_INFO, NULL,\r
+ 0,\r
+ &LengthInfo,\r
+ sizeof(LengthInfo),\r
+ &dwBytes,\r
+ NULL);\r
+ if (!bRet)\r
+ {\r
+ Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);\r
+ continue;\r
+ }\r
+\r
+ Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);\r
+\r
+ Query.PropertyId = StorageDeviceProperty;\r
+ Query.QueryType = PropertyStandardQuery;\r
+\r
+ bRet = DeviceIoControl(Handle,\r
+ IOCTL_STORAGE_QUERY_PROPERTY,\r
+ &Query,\r
+ sizeof(Query),\r
+ &DevDescHeader,\r
+ sizeof(STORAGE_DESCRIPTOR_HEADER),\r
+ &dwBytes,\r
+ NULL);\r
+ if (!bRet)\r
+ {\r
+ Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);\r
+ continue;\r
+ }\r
+\r
+ if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))\r
+ {\r
+ Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);\r
+ continue;\r
+ }\r
+\r
+ pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);\r
+ if (!pDevDesc)\r
+ {\r
+ Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);\r
+ continue;\r
+ }\r
+\r
+ bRet = DeviceIoControl(Handle,\r
+ IOCTL_STORAGE_QUERY_PROPERTY,\r
+ &Query,\r
+ sizeof(Query),\r
+ pDevDesc,\r
+ DevDescHeader.Size,\r
+ &dwBytes,\r
+ NULL);\r
+ if (!bRet)\r
+ {\r
+ Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);\r
+ free(pDevDesc);\r
+ continue;\r
+ }\r
+\r
+ CurDrive->PhyDrive = i;\r
+ CurDrive->SizeInBytes = LengthInfo.Length.QuadPart;\r
+ CurDrive->DeviceType = pDevDesc->DeviceType;\r
+ CurDrive->RemovableMedia = pDevDesc->RemovableMedia;\r
+ CurDrive->BusType = pDevDesc->BusType;\r
+\r
+ if (pDevDesc->VendorIdOffset)\r
+ {\r
+ safe_strcpy(CurDrive->VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);\r
+ TrimString(CurDrive->VendorId);\r
+ }\r
+\r
+ if (pDevDesc->ProductIdOffset)\r
+ {\r
+ safe_strcpy(CurDrive->ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);\r
+ TrimString(CurDrive->ProductId);\r
+ }\r
+\r
+ if (pDevDesc->ProductRevisionOffset)\r
+ {\r
+ safe_strcpy(CurDrive->ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);\r
+ TrimString(CurDrive->ProductRev);\r
+ }\r
+\r
+ if (pDevDesc->SerialNumberOffset)\r
+ {\r
+ safe_strcpy(CurDrive->SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);\r
+ TrimString(CurDrive->SerialNumber);\r
+ }\r
+\r
+ CurDrive++;\r
+ DriveCount++;\r
+\r
+ free(pDevDesc);\r
+\r
+ CHECK_CLOSE_HANDLE(Handle);\r
+ }\r
+\r
+ for (i = 0, CurDrive = pDriveList; i < (int)DriveCount; i++, CurDrive++)\r
+ {\r
+ Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",\r
+ CurDrive->PhyDrive, GetBusTypeString(CurDrive->BusType), CurDrive->RemovableMedia,\r
+ GetHumanReadableGBSize(CurDrive->SizeInBytes), CurDrive->SizeInBytes,\r
+ CurDrive->VendorId, CurDrive->ProductId);\r
+ }\r
+\r
+ *pDriveCount = DriveCount;\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static HANDLE g_FatPhyDrive;\r
+static UINT64 g_Part2StartSec;\r
+static int GetVentoyVersionFromFatFile(CHAR *VerBuf, size_t BufLen)\r
+{\r
+ int rc = 1;\r
+ int size = 0;\r
+ char *buf = NULL;\r
+ void *flfile = NULL;\r
+\r
+ flfile = fl_fopen("/grub/grub.cfg", "rb");\r
+ if (flfile)\r
+ {\r
+ fl_fseek(flfile, 0, SEEK_END);\r
+ size = (int)fl_ftell(flfile);\r
+\r
+ fl_fseek(flfile, 0, SEEK_SET);\r
+\r
+ buf = (char *)malloc(size + 1);\r
+ if (buf)\r
+ {\r
+ fl_fread(buf, 1, size, flfile);\r
+ buf[size] = 0;\r
+\r
+ rc = 0;\r
+ sprintf_s(VerBuf, BufLen, "%s", ParseVentoyVersionFromString(buf));\r
+ free(buf);\r
+ }\r
+\r
+ fl_fclose(flfile);\r
+ }\r
+\r
+ return rc;\r
+}\r
+\r
+static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)\r
+{\r
+ DWORD dwSize;\r
+ BOOL bRet;\r
+ DWORD ReadSize;\r
+ LARGE_INTEGER liCurrentPosition;\r
+\r
+ liCurrentPosition.QuadPart = Sector + g_Part2StartSec;\r
+ liCurrentPosition.QuadPart *= 512;\r
+ SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);\r
+\r
+ ReadSize = (DWORD)(SectorCount * 512);\r
+\r
+ bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);\r
+ if (bRet == FALSE || dwSize != ReadSize)\r
+ {\r
+ Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u\n", bRet, ReadSize, dwSize, LASTERR);\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+int GetVentoyVerInPhyDrive(const PHY_DRIVE_INFO *pDriveInfo, UINT64 Part2StartSector, CHAR *VerBuf, size_t BufLen)\r
+{\r
+ int rc = 0;\r
+ HANDLE hDrive;\r
+\r
+ hDrive = GetPhysicalHandle(pDriveInfo->PhyDrive, FALSE, FALSE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ return 1;\r
+ }\r
+ \r
+ g_FatPhyDrive = hDrive;\r
+ g_Part2StartSec = Part2StartSector;\r
+\r
+ Log("Parse FAT fs...");\r
+\r
+ fl_init();\r
+\r
+ if (0 == fl_attach_media(VentoyFatDiskRead, NULL))\r
+ {\r
+ rc = GetVentoyVersionFromFatFile(VerBuf, BufLen);\r
+ }\r
+ else\r
+ {\r
+ rc = 1;\r
+ }\r
+\r
+ fl_shutdown();\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ return rc;\r
+}\r
+\r
+\r
+\r
+\r
+\r
+static unsigned int g_disk_unxz_len = 0;\r
+static BYTE *g_part_img_pos = NULL;\r
+static BYTE *g_part_img_buf[VENTOY_EFI_PART_SIZE / SIZE_1MB];\r
+\r
+\r
+static int VentoyFatMemRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)\r
+{\r
+ uint32 i;\r
+ uint32 offset;\r
+ BYTE *MbBuf = NULL;\r
+\r
+ for (i = 0; i < SectorCount; i++)\r
+ {\r
+ offset = (Sector + i) * 512;\r
+\r
+ if (g_part_img_buf[1] == NULL)\r
+ {\r
+ MbBuf = g_part_img_buf[0] + offset;\r
+ memcpy(Buffer + i * 512, MbBuf, 512);\r
+ }\r
+ else\r
+ {\r
+ MbBuf = g_part_img_buf[offset / SIZE_1MB];\r
+ memcpy(Buffer + i * 512, MbBuf + (offset % SIZE_1MB), 512);\r
+ }\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+\r
+static int VentoyFatMemWrite(uint32 Sector, uint8 *Buffer, uint32 SectorCount)\r
+{\r
+ uint32 i;\r
+ uint32 offset;\r
+ BYTE *MbBuf = NULL;\r
+\r
+ for (i = 0; i < SectorCount; i++)\r
+ {\r
+ offset = (Sector + i) * 512;\r
+\r
+ if (g_part_img_buf[1] == NULL)\r
+ {\r
+ MbBuf = g_part_img_buf[0] + offset;\r
+ memcpy(MbBuf, Buffer + i * 512, 512);\r
+ }\r
+ else\r
+ {\r
+ MbBuf = g_part_img_buf[offset / SIZE_1MB];\r
+ memcpy(MbBuf + (offset % SIZE_1MB), Buffer + i * 512, 512);\r
+ }\r
+ }\r
+\r
+ return 1;\r
+}\r
+\r
+int VentoyProcSecureBoot(BOOL SecureBoot)\r
+{\r
+ int rc = 0;\r
+ int size;\r
+ char *filebuf = NULL;\r
+ void *file = NULL;\r
+\r
+ Log("VentoyProcSecureBoot %d ...", SecureBoot);\r
+ \r
+ if (SecureBoot)\r
+ {\r
+ Log("Secure boot is enabled ...");\r
+ return 0;\r
+ }\r
+\r
+ fl_init();\r
+\r
+ if (0 == fl_attach_media(VentoyFatMemRead, VentoyFatMemWrite))\r
+ {\r
+ file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");\r
+ Log("Open ventoy efi file %p ", file);\r
+ if (file)\r
+ {\r
+ fl_fseek(file, 0, SEEK_END);\r
+ size = (int)fl_ftell(file);\r
+ fl_fseek(file, 0, SEEK_SET);\r
+\r
+ Log("ventoy efi file size %d ...", size);\r
+\r
+ filebuf = (char *)malloc(size);\r
+ if (filebuf)\r
+ {\r
+ fl_fread(filebuf, 1, size, file);\r
+ }\r
+\r
+ fl_fclose(file);\r
+\r
+ Log("Now delete all efi files ...");\r
+ fl_remove("/EFI/BOOT/BOOTX64.EFI");\r
+ fl_remove("/EFI/BOOT/grubx64.efi");\r
+ fl_remove("/EFI/BOOT/grubx64_real.efi");\r
+ fl_remove("/EFI/BOOT/MokManager.efi");\r
+ fl_remove("/ENROLL_THIS_KEY_IN_MOKMANAGER.cer");\r
+\r
+ file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");\r
+ Log("Open bootx64 efi file %p ", file);\r
+ if (file)\r
+ {\r
+ if (filebuf)\r
+ {\r
+ fl_fwrite(filebuf, 1, size, file);\r
+ }\r
+ \r
+ fl_fflush(file);\r
+ fl_fclose(file);\r
+ }\r
+\r
+ if (filebuf)\r
+ {\r
+ free(filebuf);\r
+ }\r
+ }\r
+ }\r
+ else\r
+ {\r
+ rc = 1;\r
+ }\r
+\r
+ fl_shutdown();\r
+\r
+ return rc;\r
+}\r
+\r
+\r
+\r
+static int disk_xz_flush(void *src, unsigned int size)\r
+{\r
+ unsigned int i;\r
+ BYTE *buf = (BYTE *)src;\r
+\r
+ for (i = 0; i < size; i++)\r
+ {\r
+ *g_part_img_pos = *buf++;\r
+\r
+ g_disk_unxz_len++;\r
+ if ((g_disk_unxz_len % SIZE_1MB) == 0)\r
+ {\r
+ g_part_img_pos = g_part_img_buf[g_disk_unxz_len / SIZE_1MB];\r
+ }\r
+ else\r
+ {\r
+ g_part_img_pos++;\r
+ }\r
+ }\r
+\r
+ return (int)size;\r
+}\r
+\r
+static void unxz_error(char *x)\r
+{\r
+ Log("%s", x);\r
+}\r
+\r
+static BOOL TryWritePart2(HANDLE hDrive, UINT64 StartSectorId)\r
+{\r
+ BOOL bRet;\r
+ DWORD TrySize = 16 * 1024;\r
+ DWORD dwSize;\r
+ BYTE *Buffer = NULL;\r
+ unsigned char *data = NULL;\r
+ LARGE_INTEGER liCurrentPosition;\r
+\r
+ liCurrentPosition.QuadPart = StartSectorId * 512;\r
+ SetFilePointerEx(hDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);\r
+ \r
+ Buffer = malloc(TrySize);\r
+\r
+ bRet = WriteFile(hDrive, Buffer, TrySize, &dwSize, NULL);\r
+\r
+ free(Buffer);\r
+\r
+ Log("Try write part2 bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);\r
+\r
+ if (bRet && dwSize == TrySize)\r
+ {\r
+ return TRUE;\r
+ }\r
+\r
+ return FALSE;\r
+}\r
+\r
+static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId)\r
+{\r
+ int i;\r
+ int rc = 0;\r
+ int len = 0;\r
+ int writelen = 0;\r
+ int partwrite = 0;\r
+ DWORD dwSize = 0;\r
+ BOOL bRet;\r
+ unsigned char *data = NULL;\r
+ LARGE_INTEGER liCurrentPosition;\r
+ LARGE_INTEGER liNewPosition;\r
+\r
+ Log("FormatPart2Fat %llu...", StartSectorId);\r
+\r
+ rc = ReadWholeFileToBuf(VENTOY_FILE_DISK_IMG, 0, (void **)&data, &len);\r
+ if (rc)\r
+ {\r
+ Log("Failed to read img file %p %u", data, len);\r
+ return 1;\r
+ }\r
+\r
+ liCurrentPosition.QuadPart = StartSectorId * 512;\r
+ SetFilePointerEx(hDrive, liCurrentPosition, &liNewPosition, FILE_BEGIN);\r
+\r
+ Log("Set file pointer: %llu New pointer:%llu", liCurrentPosition.QuadPart, liNewPosition.QuadPart);\r
+\r
+ memset(g_part_img_buf, 0, sizeof(g_part_img_buf));\r
+\r
+ g_part_img_buf[0] = (BYTE *)malloc(VENTOY_EFI_PART_SIZE);\r
+ if (g_part_img_buf[0])\r
+ {\r
+ Log("Malloc whole img buffer success, now decompress ...");\r
+ unxz(data, len, NULL, NULL, g_part_img_buf[0], &writelen, unxz_error);\r
+\r
+ if (len == writelen)\r
+ {\r
+ Log("decompress finished success");\r
+\r
+ VentoyProcSecureBoot(g_SecureBoot);\r
+\r
+ for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)\r
+ {\r
+ dwSize = 0;\r
+ bRet = WriteFile(hDrive, g_part_img_buf[0] + i * SIZE_1MB, SIZE_1MB, &dwSize, NULL);\r
+ Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);\r
+\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i); \r
+ }\r
+ }\r
+ else\r
+ {\r
+ rc = 1;\r
+ Log("decompress finished failed");\r
+ goto End;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Log("Failed to malloc whole img size %u, now split it", VENTOY_EFI_PART_SIZE);\r
+\r
+ partwrite = 1;\r
+ for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)\r
+ {\r
+ g_part_img_buf[i] = (BYTE *)malloc(SIZE_1MB);\r
+ if (g_part_img_buf[i] == NULL)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+ }\r
+\r
+ Log("Malloc part img buffer success, now decompress ...");\r
+\r
+ g_part_img_pos = g_part_img_buf[0];\r
+\r
+ unxz(data, len, NULL, disk_xz_flush, NULL, NULL, unxz_error);\r
+\r
+ if (g_disk_unxz_len == VENTOY_EFI_PART_SIZE)\r
+ {\r
+ Log("decompress finished success");\r
+ \r
+ VentoyProcSecureBoot(g_SecureBoot);\r
+\r
+ for (int i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)\r
+ {\r
+ dwSize = 0;\r
+ bRet = WriteFile(hDrive, g_part_img_buf[i], SIZE_1MB, &dwSize, NULL);\r
+ Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);\r
+\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ rc = 1;\r
+ Log("decompress finished failed");\r
+ goto End;\r
+ }\r
+ }\r
+\r
+End:\r
+\r
+ if (data) free(data);\r
+\r
+ if (partwrite)\r
+ {\r
+ for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)\r
+ {\r
+ if (g_part_img_buf[i]) free(g_part_img_buf[i]);\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (g_part_img_buf[0]) free(g_part_img_buf[0]);\r
+ }\r
+\r
+ return rc;\r
+}\r
+\r
+static int WriteGrubStage1ToPhyDrive(HANDLE hDrive, int PartStyle)\r
+{\r
+ int Len = 0;\r
+ int readLen = 0;\r
+ BOOL bRet;\r
+ DWORD dwSize;\r
+ BYTE *ImgBuf = NULL;\r
+ BYTE *RawBuf = NULL;\r
+\r
+ Log("WriteGrubStage1ToPhyDrive ...");\r
+\r
+ RawBuf = (BYTE *)malloc(SIZE_1MB);\r
+ if (!RawBuf)\r
+ {\r
+ return 1;\r
+ }\r
+\r
+ if (ReadWholeFileToBuf(VENTOY_FILE_STG1_IMG, 0, (void **)&ImgBuf, &Len))\r
+ {\r
+ Log("Failed to read stage1 img");\r
+ free(RawBuf);\r
+ return 1;\r
+ }\r
+\r
+ unxz(ImgBuf, Len, NULL, NULL, RawBuf, &readLen, unxz_error);\r
+\r
+ if (PartStyle)\r
+ {\r
+ Log("Write GPT stage1 ...");\r
+ RawBuf[500] = 35;//update blocklist\r
+ SetFilePointer(hDrive, 512 * 34, NULL, FILE_BEGIN); \r
+ bRet = WriteFile(hDrive, RawBuf, SIZE_1MB - 512 * 34, &dwSize, NULL);\r
+ }\r
+ else\r
+ {\r
+ Log("Write MBR stage1 ...");\r
+ SetFilePointer(hDrive, 512, NULL, FILE_BEGIN);\r
+ bRet = WriteFile(hDrive, RawBuf, SIZE_1MB - 512, &dwSize, NULL);\r
+ }\r
+\r
+ Log("WriteFile Ret:%u dwSize:%u ErrCode:%u", bRet, dwSize, GetLastError());\r
+\r
+ free(RawBuf);\r
+ free(ImgBuf);\r
+ return 0;\r
+}\r
+\r
+\r
+\r
+static int FormatPart1exFAT(UINT64 DiskSizeBytes)\r
+{\r
+ MKFS_PARM Option;\r
+ FRESULT Ret;\r
+ FATFS fs;\r
+\r
+ Option.fmt = FM_EXFAT;\r
+ Option.n_fat = 1;\r
+ Option.align = 8;\r
+ Option.n_root = 1;\r
+\r
+ // < 32GB select 32KB as cluster size\r
+ // > 32GB select 128KB as cluster size\r
+ if (DiskSizeBytes / 1024 / 1024 / 1024 <= 32)\r
+ {\r
+ Option.au_size = 32768;\r
+ }\r
+ else\r
+ {\r
+ Option.au_size = 131072;\r
+ }\r
+\r
+ Log("Formatting Part1 exFAT ...");\r
+\r
+ Ret = f_mkfs(TEXT("0:"), &Option, 0, 8 * 1024 * 1024);\r
+\r
+ if (FR_OK == Ret)\r
+ {\r
+ Log("Formatting Part1 exFAT success");\r
+\r
+ Ret = f_mount(&fs, TEXT("0:"), 1);\r
+ Log("mount part %d", Ret);\r
+\r
+ if (FR_OK == Ret)\r
+ {\r
+ Ret = f_setlabel(TEXT("Ventoy"));\r
+ Log("f_setlabel %d", Ret);\r
+\r
+ Ret = f_mount(0, TEXT("0:"), 1);\r
+ Log("umount part %d", Ret);\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ Log("mount exfat failed %d", Ret);\r
+ return 1;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ Log("Formatting Part1 exFAT failed");\r
+ return 1;\r
+ }\r
+}\r
+\r
+\r
+\r
+int ClearVentoyFromPhyDrive(HWND hWnd, PHY_DRIVE_INFO *pPhyDrive, char *pDrvLetter)\r
+{\r
+ int i;\r
+ int rc = 0;\r
+ int state = 0;\r
+ HANDLE hDrive;\r
+ DWORD dwSize;\r
+ BOOL bRet;\r
+ CHAR MountDrive;\r
+ CHAR DriveName[] = "?:\\";\r
+ CHAR DriveLetters[MAX_PATH] = { 0 };\r
+ LARGE_INTEGER liCurrentPosition;\r
+ char *pTmpBuf = NULL;\r
+ MBR_HEAD MBR;\r
+\r
+ *pDrvLetter = 0;\r
+\r
+ Log("ClearVentoyFromPhyDrive PhyDrive%d <<%s %s %dGB>>",\r
+ pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,\r
+ GetHumanReadableGBSize(pPhyDrive->SizeInBytes));\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);\r
+\r
+ Log("Lock disk for clean ............................. ");\r
+\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to open physical disk");\r
+ return 1;\r
+ }\r
+\r
+ GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));\r
+\r
+ if (DriveLetters[0] == 0)\r
+ {\r
+ Log("No drive letter was assigned...");\r
+ DriveName[0] = GetFirstUnusedDriveLetter();\r
+ Log("GetFirstUnusedDriveLetter %C: ...", DriveName[0]);\r
+ }\r
+ else\r
+ {\r
+ // Unmount all mounted volumes that belong to this drive\r
+ // Do it in reverse so that we always end on the first volume letter\r
+ for (i = (int)strlen(DriveLetters); i > 0; i--)\r
+ {\r
+ DriveName[0] = DriveLetters[i - 1];\r
+ bRet = DeleteVolumeMountPointA(DriveName);\r
+ Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, GetLastError());\r
+ }\r
+ }\r
+\r
+ MountDrive = DriveName[0];\r
+ Log("Will use '%C:' as volume mountpoint", DriveName[0]);\r
+\r
+ // It kind of blows, but we have to relinquish access to the physical drive\r
+ // for VDS to be able to delete the partitions that reside on it...\r
+ DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART);\r
+\r
+ if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE))\r
+ {\r
+ Log("Notice: Could not delete partitions: %u", GetLastError());\r
+ }\r
+\r
+ Log("Deleting all partitions ......................... OK");\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);\r
+\r
+ Log("Lock disk for write ............................. ");\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to GetPhysicalHandle for write.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ // clear first and last 1MB space\r
+ pTmpBuf = malloc(SIZE_1MB);\r
+ if (!pTmpBuf)\r
+ {\r
+ Log("Failed to alloc memory.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+ memset(pTmpBuf, 0, SIZE_1MB); \r
+\r
+ SET_FILE_POS(512);\r
+ bRet = WriteFile(hDrive, pTmpBuf, SIZE_1MB - 512, &dwSize, NULL);\r
+ Log("Write fisrt 1MB ret:%d size:%u err:%d", bRet, dwSize, LASTERR);\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ SET_FILE_POS(SIZE_1MB);\r
+ bRet = WriteFile(hDrive, pTmpBuf, SIZE_1MB, &dwSize, NULL);\r
+ Log("Write 2nd 1MB ret:%d size:%u err:%d", bRet, dwSize, LASTERR);\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ SET_FILE_POS(0);\r
+ bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);\r
+ Log("Read MBR ret:%d size:%u err:%d", bRet, dwSize, LASTERR);\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ //clear boot code and partition table (reserved disk signature)\r
+ memset(MBR.BootCode, 0, 440);\r
+ memset(MBR.PartTbl, 0, sizeof(MBR.PartTbl));\r
+\r
+ VentoyFillLocation(pPhyDrive->SizeInBytes, 2048, (UINT32)(pPhyDrive->SizeInBytes / 512 - 2048), MBR.PartTbl);\r
+\r
+ MBR.PartTbl[0].Active = 0x00; // bootable\r
+ MBR.PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS\r
+\r
+ SET_FILE_POS(0);\r
+ bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);\r
+ Log("Write MBR ret:%d size:%u err:%d", bRet, dwSize, LASTERR);\r
+ if (!bRet)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ Log("Clear Ventoy successfully finished");\r
+\r
+ //Refresh Drive Layout\r
+ DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);\r
+\r
+End:\r
+ \r
+ PROGRESS_BAR_SET_POS(PT_MOUNT_VOLUME);\r
+ \r
+ if (pTmpBuf)\r
+ {\r
+ free(pTmpBuf);\r
+ }\r
+\r
+ if (rc == 0)\r
+ {\r
+ Log("Mounting Ventoy Partition ....................... ");\r
+ Sleep(1000);\r
+\r
+ state = 0;\r
+ memset(DriveLetters, 0, sizeof(DriveLetters));\r
+ GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));\r
+ Log("Logical drive letter after write ventoy: <%s>", DriveLetters);\r
+\r
+ for (i = 0; i < sizeof(DriveLetters) && DriveLetters[i]; i++)\r
+ {\r
+ DriveName[0] = DriveLetters[i];\r
+ Log("%s is ventoy part1, already mounted", DriveName);\r
+ state = 1;\r
+ }\r
+\r
+ if (state != 1)\r
+ {\r
+ Log("need to mount ventoy part1...");\r
+ if (0 == GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[0].StartSectorId, DriveLetters, sizeof(DriveLetters), FALSE))\r
+ {\r
+ DriveName[0] = MountDrive;\r
+ bRet = SetVolumeMountPointA(DriveName, DriveLetters);\r
+ Log("SetVolumeMountPoint <%s> <%s> bRet:%u code:%u", DriveName, DriveLetters, bRet, GetLastError());\r
+\r
+ *pDrvLetter = MountDrive;\r
+ }\r
+ else\r
+ {\r
+ Log("Failed to find ventoy volume");\r
+ }\r
+ }\r
+\r
+ Log("OK\n");\r
+ }\r
+ else\r
+ {\r
+ FindProcessOccupyDisk(hDrive, pPhyDrive);\r
+ }\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+ return rc;\r
+}\r
+\r
+int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive, int PartStyle)\r
+{\r
+ int i;\r
+ int rc = 0;\r
+ int state = 0;\r
+ HANDLE hDrive;\r
+ DWORD dwSize;\r
+ BOOL bRet;\r
+ CHAR MountDrive;\r
+ CHAR DriveName[] = "?:\\";\r
+ CHAR DriveLetters[MAX_PATH] = { 0 };\r
+ MBR_HEAD MBR;\r
+ VTOY_GPT_INFO *pGptInfo = NULL;\r
+\r
+ Log("InstallVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>",\r
+ PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,\r
+ GetHumanReadableGBSize(pPhyDrive->SizeInBytes));\r
+\r
+ if (PartStyle)\r
+ {\r
+ pGptInfo = malloc(sizeof(VTOY_GPT_INFO));\r
+ memset(pGptInfo, 0, sizeof(VTOY_GPT_INFO));\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);\r
+\r
+ VentoyFillMBR(pPhyDrive->SizeInBytes, &MBR, PartStyle);//also used to format 1st partition in GPT mode\r
+ if (PartStyle)\r
+ {\r
+ VentoyFillGpt(pPhyDrive->SizeInBytes, pGptInfo);\r
+ }\r
+\r
+ Log("Lock disk for clean ............................. ");\r
+\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to open physical disk");\r
+ free(pGptInfo);\r
+ return 1;\r
+ }\r
+\r
+ GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));\r
+\r
+ if (DriveLetters[0] == 0)\r
+ {\r
+ Log("No drive letter was assigned...");\r
+ DriveName[0] = GetFirstUnusedDriveLetter();\r
+ Log("GetFirstUnusedDriveLetter %C: ...", DriveName[0]);\r
+ }\r
+ else\r
+ {\r
+ // Unmount all mounted volumes that belong to this drive\r
+ // Do it in reverse so that we always end on the first volume letter\r
+ for (i = (int)strlen(DriveLetters); i > 0; i--)\r
+ {\r
+ DriveName[0] = DriveLetters[i - 1];\r
+ bRet = DeleteVolumeMountPointA(DriveName);\r
+ Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, GetLastError());\r
+ }\r
+ }\r
+\r
+ MountDrive = DriveName[0];\r
+ Log("Will use '%C:' as volume mountpoint", DriveName[0]);\r
+\r
+ // It kind of blows, but we have to relinquish access to the physical drive\r
+ // for VDS to be able to delete the partitions that reside on it...\r
+ DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART);\r
+\r
+ if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE))\r
+ {\r
+ Log("Notice: Could not delete partitions: %u", GetLastError());\r
+ }\r
+\r
+ Log("Deleting all partitions ......................... OK");\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);\r
+\r
+ Log("Lock disk for write ............................. ");\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to GetPhysicalHandle for write.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ //Refresh Drive Layout\r
+ DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);\r
+\r
+ disk_io_set_param(hDrive, MBR.PartTbl[0].StartSectorId + MBR.PartTbl[0].SectorCount);\r
+\r
+ PROGRESS_BAR_SET_POS(PT_FORMAT_PART1);\r
+\r
+ if (PartStyle == 1 && pPhyDrive->PartStyle == 0)\r
+ {\r
+ Log("Wait for format part1 ...");\r
+ Sleep(1000 * 5);\r
+ }\r
+\r
+ Log("Formatting part1 exFAT ...");\r
+ if (0 != FormatPart1exFAT(pPhyDrive->SizeInBytes))\r
+ {\r
+ Log("FormatPart1exFAT failed.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);\r
+ Log("Writing part2 FAT img ...");\r
+ if (0 != FormatPart2Fat(hDrive, MBR.PartTbl[1].StartSectorId))\r
+ {\r
+ Log("FormatPart2Fat failed.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_WRITE_STG1_IMG);\r
+ Log("Writting Boot Image ............................. ");\r
+ if (WriteGrubStage1ToPhyDrive(hDrive, PartStyle) != 0)\r
+ {\r
+ Log("WriteGrubStage1ToPhyDrive failed.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_WRITE_PART_TABLE);\r
+ Log("Writting Partition Table ........................ ");\r
+ SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+\r
+ if (PartStyle)\r
+ {\r
+ VTOY_GPT_HDR BackupHead;\r
+ LARGE_INTEGER liCurrentPosition;\r
+\r
+ SET_FILE_POS(pPhyDrive->SizeInBytes - 512);\r
+ VentoyFillBackupGptHead(pGptInfo, &BackupHead);\r
+ if (!WriteFile(hDrive, &BackupHead, sizeof(VTOY_GPT_HDR), &dwSize, NULL))\r
+ {\r
+ rc = 1;\r
+ Log("Write GPT Backup Head Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());\r
+ goto End;\r
+ }\r
+\r
+ SET_FILE_POS(pPhyDrive->SizeInBytes - 512 * 33);\r
+ if (!WriteFile(hDrive, pGptInfo->PartTbl, sizeof(pGptInfo->PartTbl), &dwSize, NULL))\r
+ {\r
+ rc = 1;\r
+ Log("Write GPT Backup Part Table Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());\r
+ goto End;\r
+ }\r
+\r
+ SET_FILE_POS(0);\r
+ if (!WriteFile(hDrive, pGptInfo, sizeof(VTOY_GPT_INFO), &dwSize, NULL))\r
+ {\r
+ rc = 1;\r
+ Log("Write GPT Info Failed, dwSize:%u (%u) ErrCode:%u", dwSize, sizeof(VTOY_GPT_INFO), GetLastError());\r
+ goto End;\r
+ }\r
+\r
+ Log("Write GPT Info OK ...");\r
+ }\r
+ else\r
+ {\r
+ if (!WriteFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL))\r
+ {\r
+ rc = 1;\r
+ Log("Write MBR Failed, dwSize:%u ErrCode:%u", dwSize, GetLastError());\r
+ goto End;\r
+ }\r
+ Log("Write MBR OK ...");\r
+ }\r
+ \r
+\r
+ //Refresh Drive Layout\r
+ DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);\r
+\r
+End:\r
+\r
+ PROGRESS_BAR_SET_POS(PT_MOUNT_VOLUME);\r
+\r
+ if (rc == 0)\r
+ {\r
+ Log("Mounting Ventoy Partition ....................... ");\r
+ Sleep(1000);\r
+\r
+ state = 0;\r
+ memset(DriveLetters, 0, sizeof(DriveLetters));\r
+ GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));\r
+ Log("Logical drive letter after write ventoy: <%s>", DriveLetters);\r
+\r
+ for (i = 0; i < sizeof(DriveLetters) && DriveLetters[i]; i++)\r
+ {\r
+ DriveName[0] = DriveLetters[i];\r
+ if (IsVentoyLogicalDrive(DriveName[0]))\r
+ {\r
+ Log("%s is ventoy part2, delete mountpoint", DriveName);\r
+ DeleteVolumeMountPointA(DriveName);\r
+ }\r
+ else\r
+ {\r
+ Log("%s is ventoy part1, already mounted", DriveName);\r
+ state = 1;\r
+ }\r
+ }\r
+\r
+ if (state != 1)\r
+ {\r
+ Log("need to mount ventoy part1...");\r
+ if (0 == GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[0].StartSectorId, DriveLetters, sizeof(DriveLetters), FALSE))\r
+ {\r
+ DriveName[0] = MountDrive;\r
+ bRet = SetVolumeMountPointA(DriveName, DriveLetters);\r
+ Log("SetVolumeMountPoint <%s> <%s> bRet:%u code:%u", DriveName, DriveLetters, bRet, GetLastError());\r
+ }\r
+ else\r
+ {\r
+ Log("Failed to find ventoy volume");\r
+ }\r
+ }\r
+ Log("OK\n");\r
+ }\r
+ else\r
+ {\r
+ FindProcessOccupyDisk(hDrive, pPhyDrive);\r
+ }\r
+\r
+ if (pGptInfo)\r
+ {\r
+ free(pGptInfo);\r
+ }\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+ return rc;\r
+}\r
+\r
+int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive)\r
+{\r
+ int i;\r
+ int rc = 0;\r
+ BOOL ForceMBR = FALSE;\r
+ HANDLE hVolume;\r
+ HANDLE hDrive;\r
+ DWORD Status;\r
+ DWORD dwSize;\r
+ BOOL bRet;\r
+ CHAR DriveName[] = "?:\\";\r
+ CHAR DriveLetters[MAX_PATH] = { 0 };\r
+ UINT64 StartSector;\r
+ UINT64 ReservedMB = 0;\r
+ MBR_HEAD BootImg;\r
+ MBR_HEAD MBR;\r
+ VTOY_GPT_INFO *pGptInfo = NULL;\r
+\r
+ Log("UpdateVentoy2PhyDrive %s PhyDrive%d <<%s %s %dGB>>",\r
+ pPhyDrive->PartStyle ? "GPT" : "MBR", pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,\r
+ GetHumanReadableGBSize(pPhyDrive->SizeInBytes));\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);\r
+\r
+ Log("Lock disk for umount ............................ ");\r
+\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to open physical disk");\r
+ return 1;\r
+ }\r
+\r
+ if (pPhyDrive->PartStyle)\r
+ {\r
+ pGptInfo = malloc(sizeof(VTOY_GPT_INFO));\r
+ if (!pGptInfo)\r
+ {\r
+ return 1;\r
+ }\r
+\r
+ memset(pGptInfo, 0, sizeof(VTOY_GPT_INFO));\r
+\r
+ // Read GPT Info\r
+ SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+ ReadFile(hDrive, pGptInfo, sizeof(VTOY_GPT_INFO), &dwSize, NULL);\r
+\r
+ //MBR will be used to compare with local boot image\r
+ memcpy(&MBR, &pGptInfo->MBR, sizeof(MBR_HEAD));\r
+\r
+ StartSector = pGptInfo->PartTbl[1].StartLBA;\r
+ Log("GPT StartSector in PartTbl:%llu", (ULONGLONG)StartSector);\r
+\r
+ ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512) - 33) / 2048;\r
+ Log("GPT Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB);\r
+ }\r
+ else\r
+ {\r
+ // Read MBR\r
+ SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+ ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);\r
+\r
+ StartSector = MBR.PartTbl[1].StartSectorId;\r
+ Log("MBR StartSector in PartTbl:%llu", (ULONGLONG)StartSector);\r
+\r
+ ReservedMB = (pPhyDrive->SizeInBytes / 512 - (StartSector + VENTOY_EFI_PART_SIZE / 512)) / 2048;\r
+ Log("MBR Reserved Disk Space:%llu MB", (ULONGLONG)ReservedMB);\r
+ }\r
+\r
+ GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));\r
+\r
+ if (DriveLetters[0] == 0)\r
+ {\r
+ Log("No drive letter was assigned...");\r
+ }\r
+ else\r
+ {\r
+ // Unmount all mounted volumes that belong to this drive\r
+ // Do it in reverse so that we always end on the first volume letter\r
+ for (i = (int)strlen(DriveLetters); i > 0; i--)\r
+ {\r
+ DriveName[0] = DriveLetters[i - 1];\r
+ if (IsVentoyLogicalDrive(DriveName[0]))\r
+ {\r
+ Log("%s is ventoy logical drive", DriveName);\r
+ bRet = DeleteVolumeMountPointA(DriveName);\r
+ Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, LASTERR);\r
+ break;\r
+ }\r
+ }\r
+ }\r
+\r
+ // It kind of blows, but we have to relinquish access to the physical drive\r
+ // for VDS to be able to delete the partitions that reside on it...\r
+ DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);\r
+\r
+ Log("Lock disk for update ............................ ");\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to GetPhysicalHandle for write.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ PROGRESS_BAR_SET_POS(PT_LOCK_VOLUME);\r
+\r
+ Log("Lock volume for update .......................... ");\r
+ hVolume = INVALID_HANDLE_VALUE;\r
+ Status = GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[1].StartSectorId, DriveLetters, sizeof(DriveLetters), TRUE);\r
+ if (ERROR_SUCCESS == Status)\r
+ {\r
+ Log("Now lock and dismount volume <%s>", DriveLetters);\r
+ hVolume = CreateFileA(DriveLetters,\r
+ GENERIC_READ | GENERIC_WRITE,\r
+ FILE_SHARE_READ,\r
+ NULL,\r
+ OPEN_EXISTING,\r
+ FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,\r
+ NULL);\r
+\r
+ if (hVolume == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to create file volume, errcode:%u", LASTERR);\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ bRet = DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ Log("FSCTL_LOCK_VOLUME bRet:%u code:%u", bRet, LASTERR);\r
+\r
+ bRet = DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ Log("FSCTL_DISMOUNT_VOLUME bRet:%u code:%u", bRet, LASTERR);\r
+ }\r
+ else if (ERROR_NOT_FOUND == Status)\r
+ {\r
+ Log("Volume not found, maybe not supported");\r
+ }\r
+ else\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+\r
+ if (!TryWritePart2(hDrive, StartSector))\r
+ {\r
+ ForceMBR = TRUE;\r
+ Log("Try write failed, now delete partition 2...");\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ Log("Now delete partition 2...");\r
+ DeletePartitions(pPhyDrive->PhyDrive, TRUE);\r
+\r
+ hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);\r
+ if (hDrive == INVALID_HANDLE_VALUE)\r
+ {\r
+ Log("Failed to GetPhysicalHandle for write.");\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+ }\r
+\r
+\r
+ PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);\r
+\r
+ Log("Write Ventoy to disk ............................ ");\r
+ if (0 != FormatPart2Fat(hDrive, StartSector))\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ if (hVolume != INVALID_HANDLE_VALUE)\r
+ {\r
+ bRet = DeviceIoControl(hVolume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);\r
+ Log("FSCTL_UNLOCK_VOLUME bRet:%u code:%u", bRet, LASTERR);\r
+ CHECK_CLOSE_HANDLE(hVolume);\r
+ }\r
+\r
+ Log("Updating Boot Image ............................. ");\r
+ if (WriteGrubStage1ToPhyDrive(hDrive, pPhyDrive->PartStyle) != 0)\r
+ {\r
+ rc = 1;\r
+ goto End;\r
+ }\r
+\r
+ // Boot Image\r
+ VentoyGetLocalBootImg(&BootImg);\r
+\r
+ // Use Old UUID\r
+ memcpy(BootImg.BootCode + 0x180, MBR.BootCode + 0x180, 16);\r
+ if (pPhyDrive->PartStyle)\r
+ {\r
+ BootImg.BootCode[92] = 0x22;\r
+ }\r
+\r
+ if (ForceMBR == FALSE && memcmp(BootImg.BootCode, MBR.BootCode, 440) == 0)\r
+ {\r
+ Log("Boot image has no difference, no need to write.");\r
+ }\r
+ else\r
+ {\r
+ Log("Boot image need to write %u.", ForceMBR);\r
+\r
+ SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+\r
+ memcpy(MBR.BootCode, BootImg.BootCode, 440);\r
+ bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);\r
+ Log("Write Boot Image ret:%u dwSize:%u Error:%u", bRet, dwSize, LASTERR);\r
+ }\r
+\r
+ if (pPhyDrive->PartStyle == 0)\r
+ {\r
+ if (0x00 == MBR.PartTbl[0].Active && 0x80 == MBR.PartTbl[1].Active)\r
+ {\r
+ Log("Need to chage 1st partition active and 2nd partition inactive.");\r
+\r
+ MBR.PartTbl[0].Active = 0x80;\r
+ MBR.PartTbl[1].Active = 0x00;\r
+\r
+ SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);\r
+ bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);\r
+ Log("Write NEW MBR ret:%u dwSize:%u Error:%u", bRet, dwSize, LASTERR);\r
+ }\r
+ }\r
+\r
+ //Refresh Drive Layout\r
+ DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);\r
+\r
+End:\r
+\r
+ if (rc == 0)\r
+ {\r
+ Log("OK");\r
+ }\r
+ else\r
+ {\r
+ FindProcessOccupyDisk(hDrive, pPhyDrive);\r
+ }\r
+\r
+ CHECK_CLOSE_HANDLE(hDrive);\r
+\r
+ if (pGptInfo)\r
+ {\r
+ free(pGptInfo);\r
+ }\r
+ \r
+ return rc;\r
+}\r
+\r
+\r
-/******************************************************************************
- * Utility.c
- *
- * Copyright (c) 2020, longpanda <admin@ventoy.net>
- *
- * 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 <http://www.gnu.org/licenses/>.
- *
- */
-#include <Windows.h>
-#include "Ventoy2Disk.h"
-
-void Log(const char *Fmt, ...)
-{
- va_list Arg;
- int Len = 0;
- FILE *File = NULL;
- SYSTEMTIME Sys;
- char szBuf[1024];
-
- GetLocalTime(&Sys);
- Len += safe_sprintf(szBuf,
- "[%4d/%02d/%02d %02d:%02d:%02d.%03d] ",
- Sys.wYear, Sys.wMonth, Sys.wDay,
- Sys.wHour, Sys.wMinute, Sys.wSecond,
- Sys.wMilliseconds);
-
- va_start(Arg, Fmt);
- Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);
- va_end(Arg);
-
- //printf("%s\n", szBuf);
-
-#if 1
- fopen_s(&File, VENTOY_FILE_LOG, "a+");
- if (File)
- {
- fwrite(szBuf, 1, Len, File);
- fwrite("\n", 1, 1, File);
- fclose(File);
- }
-#endif
-
-}
-
-BOOL IsPathExist(BOOL Dir, const char *Fmt, ...)
-{
- va_list Arg;
- HANDLE hFile;
- DWORD Attr;
- CHAR FilePath[MAX_PATH];
-
- va_start(Arg, Fmt);
- vsnprintf_s(FilePath, sizeof(FilePath), sizeof(FilePath), Fmt, Arg);
- va_end(Arg);
-
- hFile = CreateFileA(FilePath, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
- if (INVALID_HANDLE_VALUE == hFile)
- {
- return FALSE;
- }
-
- CloseHandle(hFile);
-
- Attr = GetFileAttributesA(FilePath);
-
- if (Dir)
- {
- if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
- {
- return FALSE;
- }
- }
- else
- {
- if (Attr & FILE_ATTRIBUTE_DIRECTORY)
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-
-int ReadWholeFileToBuf(const CHAR *FileName, int ExtLen, void **Bufer, int *BufLen)
-{
- int FileSize;
- FILE *File = NULL;
- void *Data = NULL;
-
- fopen_s(&File, FileName, "rb");
- if (File == NULL)
- {
- Log("Failed to open file %s", FileName);
- return 1;
- }
-
- fseek(File, 0, SEEK_END);
- FileSize = (int)ftell(File);
-
- Data = malloc(FileSize + ExtLen);
- if (!Data)
- {
- fclose(File);
- return 1;
- }
-
- fseek(File, 0, SEEK_SET);
- fread(Data, 1, FileSize, File);
-
- fclose(File);
-
- *Bufer = Data;
- *BufLen = FileSize;
-
- return 0;
-}
-
-const CHAR* GetLocalVentoyVersion(void)
-{
- int rc;
- int FileSize;
- CHAR *Pos = NULL;
- CHAR *Buf = NULL;
- static CHAR LocalVersion[64] = { 0 };
-
- if (LocalVersion[0] == 0)
- {
- rc = ReadWholeFileToBuf(VENTOY_FILE_VERSION, 1, (void **)&Buf, &FileSize);
- if (rc)
- {
- return "";
- }
- Buf[FileSize] = 0;
-
- for (Pos = Buf; *Pos; Pos++)
- {
- if (*Pos == '\r' || *Pos == '\n')
- {
- *Pos = 0;
- break;
- }
- }
-
- safe_sprintf(LocalVersion, "%s", Buf);
- free(Buf);
- }
-
- return LocalVersion;
-}
-
-const CHAR* ParseVentoyVersionFromString(CHAR *Buf)
-{
- CHAR *Pos = NULL;
- CHAR *End = NULL;
- static CHAR LocalVersion[64] = { 0 };
-
- Pos = strstr(Buf, "VENTOY_VERSION=");
- if (Pos)
- {
- Pos += strlen("VENTOY_VERSION=");
- if (*Pos == '"')
- {
- Pos++;
- }
-
- End = Pos;
- while (*End != 0 && *End != '"' && *End != '\r' && *End != '\n')
- {
- End++;
- }
-
- *End = 0;
-
- safe_sprintf(LocalVersion, "%s", Pos);
- return LocalVersion;
- }
-
- return "";
-}
-
-BOOL IsWow64(void)
-{
- typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
- LPFN_ISWOW64PROCESS fnIsWow64Process;
- BOOL bIsWow64 = FALSE;
-
- fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
- if (NULL != fnIsWow64Process)
- {
- fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
- }
-
- return bIsWow64;
-}
-
-void DumpWindowsVersion(void)
-{
- int Bit;
- BOOL WsVer;
- DWORD Major, Minor;
- ULONGLONG MajorEqual, MinorEqual;
- OSVERSIONINFOEXA Ver1, Ver2;
- const CHAR *Ver = NULL;
- CHAR WinVer[256] = { 0 };
-
- memset(&Ver1, 0, sizeof(Ver1));
- memset(&Ver2, 0, sizeof(Ver2));
-
- 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))
- {
- 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
-
- 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 (!VerifyVersionInfoA(&Ver2, VER_MAJORVERSION, MajorEqual))
- {
- continue;
- }
-
- if (Ver1.dwMajorVersion < Major)
- {
- Ver1.dwMajorVersion = Major;
- Ver1.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))
- {
- continue;
- }
-
- Ver1.dwMinorVersion = Minor;
- break;
- }
-
- break;
- }
- }
-
- 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";
- break;
- }
- }
- }
- }
-
- Bit = IsWow64() ? 64 : 32;
-
- 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);
- }
- else
- {
- safe_sprintf(WinVer, "Windows %s %d-bit", Ver, Bit);
- }
-
- if (((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion) >= 0x62)
- {
- Log("Windows Version : %s (Build %u)", WinVer, Ver1.dwBuildNumber);
- }
- else
- {
- Log("Windows Version : %s", WinVer);
- }
-
- return;
-}
-
-BOOL IsVentoyLogicalDrive(CHAR DriveLetter)
-{
- int i;
- CONST CHAR *Files[] =
- {
- "EFI\\BOOT\\BOOTX64.EFI",
- "grub\\themes\\ventoy\\theme.txt",
- "ventoy\\ventoy.cpio",
- };
-
- for (i = 0; i < sizeof(Files) / sizeof(Files[0]); i++)
- {
- if (!IsFileExist("%C:\\%s", DriveLetter, Files[i]))
- {
- return FALSE;
- }
- }
-
- return TRUE;
-}
-
-
-int VentoyFillLocation(UINT64 DiskSizeInBytes, UINT32 StartSectorId, UINT32 SectorCount, PART_TABLE *Table)
-{
- BYTE Head;
- BYTE Sector;
- BYTE nSector = 63;
- BYTE nHead = 8;
- UINT32 Cylinder;
- UINT32 EndSectorId;
-
- while (nHead != 0 && (DiskSizeInBytes / 512 / nSector / nHead) > 1024)
- {
- nHead = (BYTE)nHead * 2;
- }
-
- if (nHead == 0)
- {
- nHead = 255;
- }
-
- Cylinder = StartSectorId / nSector / nHead;
- Head = StartSectorId / nSector % nHead;
- Sector = StartSectorId % nSector + 1;
-
- Table->StartHead = Head;
- Table->StartSector = Sector;
- Table->StartCylinder = Cylinder;
-
- EndSectorId = StartSectorId + SectorCount - 1;
- Cylinder = EndSectorId / nSector / nHead;
- Head = EndSectorId / nSector % nHead;
- Sector = EndSectorId % nSector + 1;
-
- Table->EndHead = Head;
- Table->EndSector = Sector;
- Table->EndCylinder = Cylinder;
-
- Table->StartSectorId = StartSectorId;
- Table->SectorCount = SectorCount;
-
- return 0;
-}
-
-int VentoyFillMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR, int PartStyle)
-{
- GUID Guid;
- int ReservedValue;
- UINT32 DiskSignature;
- UINT32 DiskSectorCount;
- UINT32 PartSectorCount;
- UINT32 PartStartSector;
- UINT32 ReservedSector;
-
- VentoyGetLocalBootImg(pMBR);
-
- CoCreateGuid(&Guid);
-
- memcpy(&DiskSignature, &Guid, sizeof(UINT32));
-
- Log("Disk signature: 0x%08x", DiskSignature);
-
- *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;
-
- if (DiskSizeBytes / 512 > 0xFFFFFFFF)
- {
- DiskSectorCount = 0xFFFFFFFF;
- }
- else
- {
- DiskSectorCount = (UINT32)(DiskSizeBytes / 512);
- }
-
- ReservedValue = GetReservedSpaceInMB();
- if (ReservedValue <= 0)
- {
- ReservedSector = 0;
- }
- else
- {
- ReservedSector = (UINT32)(ReservedValue * 2048);
- }
-
- if (PartStyle)
- {
- ReservedSector += 33; // backup GPT part table
- }
-
- Log("ReservedSector: %u", ReservedSector);
-
- //Part1
- PartStartSector = VENTOY_PART1_START_SECTOR;
- PartSectorCount = DiskSectorCount - ReservedSector - VENTOY_EFI_PART_SIZE / 512 - PartStartSector;
- VentoyFillLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl);
-
- pMBR->PartTbl[0].Active = 0x80; // bootable
- pMBR->PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS
-
- //Part2
- PartStartSector += PartSectorCount;
- PartSectorCount = VENTOY_EFI_PART_SIZE / 512;
- VentoyFillLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl + 1);
-
- pMBR->PartTbl[1].Active = 0x00;
- pMBR->PartTbl[1].FsFlag = 0xEF; // EFI System Partition
-
- pMBR->Byte55 = 0x55;
- pMBR->ByteAA = 0xAA;
-
- return 0;
-}
-
-
-static int VentoyFillProtectMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR)
-{
- GUID Guid;
- UINT32 DiskSignature;
- UINT64 DiskSectorCount;
-
- VentoyGetLocalBootImg(pMBR);
-
- CoCreateGuid(&Guid);
-
- memcpy(&DiskSignature, &Guid, sizeof(UINT32));
-
- Log("Disk signature: 0x%08x", DiskSignature);
-
- *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;
-
- DiskSectorCount = DiskSizeBytes / 512 - 1;
- if (DiskSectorCount > 0xFFFFFFFF)
- {
- DiskSectorCount = 0xFFFFFFFF;
- }
-
- memset(pMBR->PartTbl, 0, sizeof(pMBR->PartTbl));
-
- pMBR->PartTbl[0].Active = 0x00;
- pMBR->PartTbl[0].FsFlag = 0xee; // EE
-
- pMBR->PartTbl[0].StartHead = 0;
- pMBR->PartTbl[0].StartSector = 1;
- pMBR->PartTbl[0].StartCylinder = 0;
- pMBR->PartTbl[0].EndHead = 254;
- pMBR->PartTbl[0].EndSector = 63;
- pMBR->PartTbl[0].EndCylinder = 1023;
-
- pMBR->PartTbl[0].StartSectorId = 1;
- pMBR->PartTbl[0].SectorCount = (UINT32)DiskSectorCount;
-
- pMBR->Byte55 = 0x55;
- pMBR->ByteAA = 0xAA;
-
- pMBR->BootCode[92] = 0x22;
-
- return 0;
-}
-
-
-int VentoyFillGpt(UINT64 DiskSizeBytes, VTOY_GPT_INFO *pInfo)
-{
- INT64 ReservedValue = 0;
- UINT64 ReservedSector = 33;
- UINT64 Part1SectorCount = 0;
- UINT64 DiskSectorCount = DiskSizeBytes / 512;
- VTOY_GPT_HDR *Head = &pInfo->Head;
- VTOY_GPT_PART_TBL *Table = pInfo->PartTbl;
- 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 } };
-
- VentoyFillProtectMBR(DiskSizeBytes, &pInfo->MBR);
-
- ReservedValue = GetReservedSpaceInMB();
- if (ReservedValue > 0)
- {
- ReservedSector += ReservedValue * 2048;
- }
-
- Part1SectorCount = DiskSectorCount - ReservedSector - (VENTOY_EFI_PART_SIZE / 512) - 2048;
-
- memcpy(Head->Signature, "EFI PART", 8);
- Head->Version[2] = 0x01;
- Head->Length = 92;
- Head->Crc = 0;
- Head->EfiStartLBA = 1;
- Head->EfiBackupLBA = DiskSectorCount - 1;
- Head->PartAreaStartLBA = 34;
- Head->PartAreaEndLBA = DiskSectorCount - 34;
- CoCreateGuid(&Head->DiskGuid);
- Head->PartTblStartLBA = 2;
- Head->PartTblTotNum = 128;
- Head->PartTblEntryLen = 128;
-
-
- memcpy(&(Table[0].PartType), &WindowsDataPartType, sizeof(GUID));
- CoCreateGuid(&(Table[0].PartGuid));
- Table[0].StartLBA = 2048;
- Table[0].LastLBA = 2048 + Part1SectorCount - 1;
- Table[0].Attr = 0;
- memcpy(Table[0].Name, L"Ventoy", 6 * 2);
-
- memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));
- CoCreateGuid(&(Table[1].PartGuid));
- Table[1].StartLBA = Table[0].LastLBA + 1;
- Table[1].LastLBA = Table[1].StartLBA + VENTOY_EFI_PART_SIZE / 512 - 1;
- Table[1].Attr = 1;
- memcpy(Table[1].Name, L"VTOYEFI", 7 * 2);
-
-#if 0
- memcpy(&(Table[2].PartType), &BiosGrubPartType, sizeof(GUID));
- CoCreateGuid(&(Table[2].PartGuid));
- Table[2].StartLBA = 34;
- Table[2].LastLBA = 2047;
- Table[2].Attr = 0;
-#endif
-
- //Update CRC
- Head->PartTblCrc = VentoyCrc32(Table, sizeof(pInfo->PartTbl));
- Head->Crc = VentoyCrc32(Head, Head->Length);
-
- return 0;
-}
-
-int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)
-{
- UINT64 LBA;
- UINT64 BackupLBA;
-
- memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));
-
- LBA = pHead->EfiStartLBA;
- BackupLBA = pHead->EfiBackupLBA;
-
- pHead->EfiStartLBA = BackupLBA;
- pHead->EfiBackupLBA = LBA;
- pHead->PartTblStartLBA = BackupLBA + 1 - 33;
-
- pHead->Crc = 0;
- pHead->Crc = VentoyCrc32(pHead, pHead->Length);
-
- return 0;
-}
-
-CHAR GetFirstUnusedDriveLetter(void)
-{
- CHAR Letter = 'D';
- DWORD Drives = GetLogicalDrives();
-
- Drives >>= 3;
- while (Drives & 0x1)
- {
- Letter++;
- Drives >>= 1;
- }
-
- return Letter;
-}
-
-const CHAR * GetBusTypeString(STORAGE_BUS_TYPE Type)
-{
- switch (Type)
- {
- case BusTypeUnknown: return "unknown";
- case BusTypeScsi: return "SCSI";
- case BusTypeAtapi: return "Atapi";
- case BusTypeAta: return "ATA";
- case BusType1394: return "1394";
- case BusTypeSsa: return "SSA";
- case BusTypeFibre: return "Fibre";
- case BusTypeUsb: return "USB";
- case BusTypeRAID: return "RAID";
- case BusTypeiScsi: return "iSCSI";
- case BusTypeSas: return "SAS";
- case BusTypeSata: return "SATA";
- case BusTypeSd: return "SD";
- case BusTypeMmc: return "MMC";
- case BusTypeVirtual: return "Virtual";
- case BusTypeFileBackedVirtual: return "FileBackedVirtual";
- case BusTypeSpaces: return "Spaces";
- case BusTypeNvme: return "Nvme";
- }
- return "unknown";
-}
-
-int VentoyGetLocalBootImg(MBR_HEAD *pMBR)
-{
- int Len = 0;
- BYTE *ImgBuf = NULL;
- static int Loaded = 0;
- static MBR_HEAD MBR;
-
- if (Loaded)
- {
- memcpy(pMBR, &MBR, 512);
- return 0;
- }
-
- if (0 == ReadWholeFileToBuf(VENTOY_FILE_BOOT_IMG, 0, (void **)&ImgBuf, &Len))
- {
- Log("Copy boot img success");
- memcpy(pMBR, ImgBuf, 512);
- free(ImgBuf);
-
- CoCreateGuid((GUID *)(pMBR->BootCode + 0x180));
-
- memcpy(&MBR, pMBR, 512);
- Loaded = 1;
-
- return 0;
- }
- else
- {
- Log("Copy boot img failed");
- return 1;
- }
-}
-
-int GetHumanReadableGBSize(UINT64 SizeBytes)
-{
- int i;
- int Pow2 = 1;
- double Delta;
- double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
-
- for (i = 0; i < 12; i++)
- {
- if (Pow2 > GB)
- {
- Delta = (Pow2 - GB) / Pow2;
- }
- else
- {
- Delta = (GB - Pow2) / Pow2;
- }
-
- if (Delta < 0.05)
- {
- return Pow2;
- }
-
- Pow2 <<= 1;
- }
-
- return (int)GB;
-}
-
-void TrimString(CHAR *String)
-{
- CHAR *Pos1 = String;
- CHAR *Pos2 = String;
- size_t Len = strlen(String);
-
- while (Len > 0)
- {
- if (String[Len - 1] != ' ' && String[Len - 1] != '\t')
- {
- break;
- }
- String[Len - 1] = 0;
- Len--;
- }
-
- while (*Pos1 == ' ' || *Pos1 == '\t')
- {
- Pos1++;
- }
-
- while (*Pos1)
- {
- *Pos2++ = *Pos1++;
- }
- *Pos2++ = 0;
-
- return;
-}
-
-int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)
-{
- HKEY hKey;
- DWORD Type;
- DWORD Size;
- LSTATUS lRet;
- DWORD Value;
-
- lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);
- Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);
-
- if (ERROR_SUCCESS == lRet)
- {
- Size = sizeof(Value);
- lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);
- Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName, lRet, Size, Value);
-
- *pValue = Value;
- RegCloseKey(hKey);
-
- return 0;
- }
- else
- {
- return 1;
- }
-}
-
-int GetPhysicalDriveCount(void)
-{
- DWORD Value;
- int Count = 0;
-
- if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)
- {
- Count = (int)Value;
- }
-
- Log("GetPhysicalDriveCount: %d", Count);
- return Count;
-}
-
-
-
+/******************************************************************************\r
+ * Utility.c\r
+ *\r
+ * Copyright (c) 2020, longpanda <admin@ventoy.net>\r
+ *\r
+ * This program is free software; you can redistribute it and/or\r
+ * modify it under the terms of the GNU General Public License as\r
+ * published by the Free Software Foundation; either version 3 of the\r
+ * License, or (at your option) any later version.\r
+ * \r
+ * This program is distributed in the hope that it will be useful, but\r
+ * WITHOUT ANY WARRANTY; without even the implied warranty of\r
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU\r
+ * General Public License for more details.\r
+ * \r
+ * You should have received a copy of the GNU General Public License\r
+ * along with this program; if not, see <http://www.gnu.org/licenses/>.\r
+ *\r
+ */\r
+#include <Windows.h>\r
+#include "Ventoy2Disk.h"\r
+\r
+void Log(const char *Fmt, ...)\r
+{\r
+ va_list Arg;\r
+ int Len = 0;\r
+ FILE *File = NULL;\r
+ SYSTEMTIME Sys;\r
+ char szBuf[1024];\r
+\r
+ GetLocalTime(&Sys);\r
+ Len += safe_sprintf(szBuf,\r
+ "[%4d/%02d/%02d %02d:%02d:%02d.%03d] ",\r
+ Sys.wYear, Sys.wMonth, Sys.wDay,\r
+ Sys.wHour, Sys.wMinute, Sys.wSecond,\r
+ Sys.wMilliseconds);\r
+\r
+ va_start(Arg, Fmt);\r
+ Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);\r
+ va_end(Arg);\r
+\r
+ //printf("%s\n", szBuf);\r
+\r
+#if 1\r
+ fopen_s(&File, VENTOY_FILE_LOG, "a+");\r
+ if (File)\r
+ {\r
+ fwrite(szBuf, 1, Len, File);\r
+ fwrite("\n", 1, 1, File);\r
+ fclose(File);\r
+ }\r
+#endif\r
+\r
+}\r
+\r
+BOOL IsPathExist(BOOL Dir, const char *Fmt, ...)\r
+{\r
+ va_list Arg;\r
+ HANDLE hFile;\r
+ DWORD Attr;\r
+ CHAR FilePath[MAX_PATH];\r
+\r
+ va_start(Arg, Fmt);\r
+ vsnprintf_s(FilePath, sizeof(FilePath), sizeof(FilePath), Fmt, Arg);\r
+ va_end(Arg);\r
+\r
+ hFile = CreateFileA(FilePath, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);\r
+ if (INVALID_HANDLE_VALUE == hFile)\r
+ {\r
+ return FALSE;\r
+ }\r
+\r
+ CloseHandle(hFile);\r
+\r
+ Attr = GetFileAttributesA(FilePath);\r
+\r
+ if (Dir)\r
+ {\r
+ if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0)\r
+ {\r
+ return FALSE;\r
+ }\r
+ }\r
+ else\r
+ {\r
+ if (Attr & FILE_ATTRIBUTE_DIRECTORY)\r
+ {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+int ReadWholeFileToBuf(const CHAR *FileName, int ExtLen, void **Bufer, int *BufLen)\r
+{\r
+ int FileSize;\r
+ FILE *File = NULL;\r
+ void *Data = NULL;\r
+\r
+ fopen_s(&File, FileName, "rb");\r
+ if (File == NULL)\r
+ {\r
+ Log("Failed to open file %s", FileName);\r
+ return 1;\r
+ }\r
+\r
+ fseek(File, 0, SEEK_END);\r
+ FileSize = (int)ftell(File);\r
+\r
+ Data = malloc(FileSize + ExtLen);\r
+ if (!Data)\r
+ {\r
+ fclose(File);\r
+ return 1;\r
+ }\r
+\r
+ fseek(File, 0, SEEK_SET);\r
+ fread(Data, 1, FileSize, File);\r
+\r
+ fclose(File);\r
+\r
+ *Bufer = Data;\r
+ *BufLen = FileSize;\r
+\r
+ return 0;\r
+}\r
+\r
+const CHAR* GetLocalVentoyVersion(void)\r
+{\r
+ int rc;\r
+ int FileSize;\r
+ CHAR *Pos = NULL;\r
+ CHAR *Buf = NULL;\r
+ static CHAR LocalVersion[64] = { 0 };\r
+\r
+ if (LocalVersion[0] == 0)\r
+ {\r
+ rc = ReadWholeFileToBuf(VENTOY_FILE_VERSION, 1, (void **)&Buf, &FileSize);\r
+ if (rc)\r
+ {\r
+ return "";\r
+ }\r
+ Buf[FileSize] = 0;\r
+\r
+ for (Pos = Buf; *Pos; Pos++)\r
+ {\r
+ if (*Pos == '\r' || *Pos == '\n')\r
+ {\r
+ *Pos = 0;\r
+ break;\r
+ }\r
+ }\r
+\r
+ safe_sprintf(LocalVersion, "%s", Buf);\r
+ free(Buf);\r
+ }\r
+ \r
+ return LocalVersion;\r
+}\r
+\r
+const CHAR* ParseVentoyVersionFromString(CHAR *Buf)\r
+{\r
+ CHAR *Pos = NULL;\r
+ CHAR *End = NULL;\r
+ static CHAR LocalVersion[64] = { 0 };\r
+\r
+ Pos = strstr(Buf, "VENTOY_VERSION=");\r
+ if (Pos)\r
+ {\r
+ Pos += strlen("VENTOY_VERSION=");\r
+ if (*Pos == '"')\r
+ {\r
+ Pos++;\r
+ }\r
+\r
+ End = Pos;\r
+ while (*End != 0 && *End != '"' && *End != '\r' && *End != '\n')\r
+ {\r
+ End++;\r
+ }\r
+\r
+ *End = 0;\r
+\r
+ safe_sprintf(LocalVersion, "%s", Pos);\r
+ return LocalVersion;\r
+ }\r
+\r
+ return "";\r
+}\r
+\r
+BOOL IsWow64(void)\r
+{\r
+ typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);\r
+ LPFN_ISWOW64PROCESS fnIsWow64Process;\r
+ BOOL bIsWow64 = FALSE;\r
+\r
+ fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");\r
+ if (NULL != fnIsWow64Process)\r
+ {\r
+ fnIsWow64Process(GetCurrentProcess(), &bIsWow64);\r
+ }\r
+\r
+ return bIsWow64;\r
+}\r
+\r
+void DumpWindowsVersion(void)\r
+{\r
+ int Bit; \r
+ BOOL WsVer; \r
+ DWORD Major, Minor;\r
+ ULONGLONG MajorEqual, MinorEqual;\r
+ OSVERSIONINFOEXA Ver1, Ver2;\r
+ const CHAR *Ver = NULL; \r
+ CHAR WinVer[256] = { 0 };\r
+\r
+ memset(&Ver1, 0, sizeof(Ver1));\r
+ memset(&Ver2, 0, sizeof(Ver2));\r
+\r
+ Ver1.dwOSVersionInfoSize = sizeof(Ver1);\r
+ \r
+ // suppress the C4996 warning for GetVersionExA\r
+ #pragma warning(push)\r
+ #pragma warning(disable:4996)\r
+ if (!GetVersionExA((OSVERSIONINFOA *)&Ver1))\r
+ {\r
+ memset(&Ver1, 0, sizeof(Ver1));\r
+ Ver1.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);\r
+ if (!GetVersionExA((OSVERSIONINFOA *)&Ver1))\r
+ {\r
+ return;\r
+ }\r
+ }\r
+ #pragma warning(pop)\r
+\r
+ if (Ver1.dwPlatformId == VER_PLATFORM_WIN32_NT)\r
+ {\r
+ if (Ver1.dwMajorVersion > 6 || (Ver1.dwMajorVersion == 6 && Ver1.dwMinorVersion >= 2))\r
+ {\r
+ // GetVersionEx() has problem on some Windows version \r
+\r
+ MajorEqual = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);\r
+ for (Major = Ver1.dwMajorVersion; Major <= 9; Major++) \r
+ {\r
+ memset(&Ver2, 0, sizeof(Ver2));\r
+ Ver2.dwOSVersionInfoSize = sizeof(Ver2);\r
+ Ver2.dwMajorVersion = Major;\r
+\r
+ if (!VerifyVersionInfoA(&Ver2, VER_MAJORVERSION, MajorEqual))\r
+ {\r
+ continue;\r
+ }\r
+ \r
+ if (Ver1.dwMajorVersion < Major) \r
+ {\r
+ Ver1.dwMajorVersion = Major;\r
+ Ver1.dwMinorVersion = 0;\r
+ }\r
+\r
+ MinorEqual = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);\r
+ for (Minor = Ver1.dwMinorVersion; Minor <= 9; Minor++) \r
+ {\r
+ memset(&Ver2, 0, sizeof(Ver2)); \r
+ \r
+ Ver2.dwOSVersionInfoSize = sizeof(Ver2);\r
+ Ver2.dwMinorVersion = Minor;\r
+\r
+ if (!VerifyVersionInfoA(&Ver2, VER_MINORVERSION, MinorEqual))\r
+ {\r
+ continue;\r
+ }\r
+ \r
+ Ver1.dwMinorVersion = Minor;\r
+ break;\r
+ }\r
+\r
+ break;\r
+ }\r
+ }\r
+\r
+ if (Ver1.dwMajorVersion <= 0xF && Ver1.dwMinorVersion <= 0xF)\r
+ {\r
+ WsVer = (Ver1.wProductType <= VER_NT_WORKSTATION);\r
+ switch ((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion)\r
+ {\r
+ case 0x51:\r
+ {\r
+ Ver = "XP";\r
+ break;\r
+ }\r
+ case 0x52:\r
+ {\r
+ Ver = GetSystemMetrics(89) ? "Server 2003 R2" : "Server 2003";\r
+ break;\r
+ }\r
+ case 0x60:\r
+ {\r
+ Ver = WsVer ? "Vista" : "Server 2008";\r
+ break;\r
+ }\r
+ case 0x61:\r
+ {\r
+ Ver = WsVer ? "7" : "Server 2008 R2";\r
+ break;\r
+ }\r
+ case 0x62:\r
+ {\r
+ Ver = WsVer ? "8" : "Server 2012";\r
+ break;\r
+ }\r
+ case 0x63:\r
+ {\r
+ Ver = WsVer ? "8.1" : "Server 2012 R2";\r
+ break;\r
+ }\r
+ case 0x64:\r
+ {\r
+ Ver = WsVer ? "10 (Preview 1)" : "Server 10 (Preview 1)";\r
+ break;\r
+ }\r
+ case 0xA0:\r
+ {\r
+ Ver = WsVer ? "10" : ((Ver1.dwBuildNumber > 15000) ? "Server 2019" : "Server 2016");\r
+ break;\r
+ }\r
+ default:\r
+ {\r
+ Ver = "10 or later";\r
+ break;\r
+ }\r
+ }\r
+ }\r
+ }\r
+\r
+ Bit = IsWow64() ? 64 : 32;\r
+\r
+ if (Ver1.wServicePackMinor)\r
+ {\r
+ safe_sprintf(WinVer, "Windows %s SP%u.%u %d-bit", Ver, Ver1.wServicePackMajor, Ver1.wServicePackMinor, Bit);\r
+ }\r
+ else if (Ver1.wServicePackMajor)\r
+ {\r
+ safe_sprintf(WinVer, "Windows %s SP%u %d-bit", Ver, Ver1.wServicePackMajor, Bit);\r
+ }\r
+ else\r
+ {\r
+ safe_sprintf(WinVer, "Windows %s %d-bit", Ver, Bit);\r
+ }\r
+\r
+ if (((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion) >= 0x62)\r
+ {\r
+ Log("Windows Version : %s (Build %u)", WinVer, Ver1.dwBuildNumber);\r
+ }\r
+ else\r
+ {\r
+ Log("Windows Version : %s", WinVer);\r
+ }\r
+\r
+ return;\r
+}\r
+\r
+BOOL IsVentoyLogicalDrive(CHAR DriveLetter)\r
+{\r
+ int i;\r
+ CONST CHAR *Files[] =\r
+ {\r
+ "EFI\\BOOT\\BOOTX64.EFI",\r
+ "grub\\themes\\ventoy\\theme.txt",\r
+ "ventoy\\ventoy.cpio",\r
+ };\r
+\r
+ for (i = 0; i < sizeof(Files) / sizeof(Files[0]); i++)\r
+ {\r
+ if (!IsFileExist("%C:\\%s", DriveLetter, Files[i]))\r
+ {\r
+ return FALSE;\r
+ }\r
+ }\r
+\r
+ return TRUE;\r
+}\r
+\r
+\r
+int VentoyFillLocation(UINT64 DiskSizeInBytes, UINT32 StartSectorId, UINT32 SectorCount, PART_TABLE *Table)\r
+{\r
+ BYTE Head;\r
+ BYTE Sector;\r
+ BYTE nSector = 63;\r
+ BYTE nHead = 8; \r
+ UINT32 Cylinder;\r
+ UINT32 EndSectorId;\r
+\r
+ while (nHead != 0 && (DiskSizeInBytes / 512 / nSector / nHead) > 1024)\r
+ {\r
+ nHead = (BYTE)nHead * 2;\r
+ }\r
+\r
+ if (nHead == 0)\r
+ {\r
+ nHead = 255;\r
+ }\r
+\r
+ Cylinder = StartSectorId / nSector / nHead;\r
+ Head = StartSectorId / nSector % nHead;\r
+ Sector = StartSectorId % nSector + 1;\r
+\r
+ Table->StartHead = Head;\r
+ Table->StartSector = Sector;\r
+ Table->StartCylinder = Cylinder;\r
+\r
+ EndSectorId = StartSectorId + SectorCount - 1;\r
+ Cylinder = EndSectorId / nSector / nHead;\r
+ Head = EndSectorId / nSector % nHead;\r
+ Sector = EndSectorId % nSector + 1;\r
+\r
+ Table->EndHead = Head;\r
+ Table->EndSector = Sector;\r
+ Table->EndCylinder = Cylinder;\r
+\r
+ Table->StartSectorId = StartSectorId;\r
+ Table->SectorCount = SectorCount;\r
+\r
+ return 0;\r
+}\r
+\r
+int VentoyFillMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR, int PartStyle)\r
+{\r
+ GUID Guid;\r
+ int ReservedValue;\r
+ UINT32 DiskSignature;\r
+ UINT32 DiskSectorCount;\r
+ UINT32 PartSectorCount;\r
+ UINT32 PartStartSector;\r
+ UINT32 ReservedSector;\r
+\r
+ VentoyGetLocalBootImg(pMBR);\r
+\r
+ CoCreateGuid(&Guid);\r
+\r
+ memcpy(&DiskSignature, &Guid, sizeof(UINT32));\r
+\r
+ Log("Disk signature: 0x%08x", DiskSignature);\r
+\r
+ *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;\r
+\r
+ if (DiskSizeBytes / 512 > 0xFFFFFFFF)\r
+ {\r
+ DiskSectorCount = 0xFFFFFFFF;\r
+ }\r
+ else\r
+ {\r
+ DiskSectorCount = (UINT32)(DiskSizeBytes / 512);\r
+ }\r
+\r
+ ReservedValue = GetReservedSpaceInMB();\r
+ if (ReservedValue <= 0)\r
+ {\r
+ ReservedSector = 0;\r
+ }\r
+ else\r
+ {\r
+ ReservedSector = (UINT32)(ReservedValue * 2048);\r
+ }\r
+\r
+ if (PartStyle)\r
+ {\r
+ ReservedSector += 33; // backup GPT part table\r
+ }\r
+\r
+ Log("ReservedSector: %u", ReservedSector);\r
+\r
+ //Part1\r
+ PartStartSector = VENTOY_PART1_START_SECTOR;\r
+ PartSectorCount = DiskSectorCount - ReservedSector - VENTOY_EFI_PART_SIZE / 512 - PartStartSector;\r
+ VentoyFillLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl);\r
+\r
+ pMBR->PartTbl[0].Active = 0x80; // bootable\r
+ pMBR->PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS\r
+\r
+ //Part2\r
+ PartStartSector += PartSectorCount;\r
+ PartSectorCount = VENTOY_EFI_PART_SIZE / 512;\r
+ VentoyFillLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl + 1);\r
+\r
+ pMBR->PartTbl[1].Active = 0x00; \r
+ pMBR->PartTbl[1].FsFlag = 0xEF; // EFI System Partition\r
+\r
+ pMBR->Byte55 = 0x55;\r
+ pMBR->ByteAA = 0xAA;\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+static int VentoyFillProtectMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR)\r
+{\r
+ GUID Guid;\r
+ UINT32 DiskSignature;\r
+ UINT64 DiskSectorCount;\r
+\r
+ VentoyGetLocalBootImg(pMBR);\r
+\r
+ CoCreateGuid(&Guid);\r
+\r
+ memcpy(&DiskSignature, &Guid, sizeof(UINT32));\r
+\r
+ Log("Disk signature: 0x%08x", DiskSignature);\r
+\r
+ *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;\r
+\r
+ DiskSectorCount = DiskSizeBytes / 512 - 1;\r
+ if (DiskSectorCount > 0xFFFFFFFF)\r
+ {\r
+ DiskSectorCount = 0xFFFFFFFF;\r
+ }\r
+\r
+ memset(pMBR->PartTbl, 0, sizeof(pMBR->PartTbl));\r
+\r
+ pMBR->PartTbl[0].Active = 0x00;\r
+ pMBR->PartTbl[0].FsFlag = 0xee; // EE\r
+\r
+ pMBR->PartTbl[0].StartHead = 0;\r
+ pMBR->PartTbl[0].StartSector = 1;\r
+ pMBR->PartTbl[0].StartCylinder = 0;\r
+ pMBR->PartTbl[0].EndHead = 254;\r
+ pMBR->PartTbl[0].EndSector = 63;\r
+ pMBR->PartTbl[0].EndCylinder = 1023;\r
+\r
+ pMBR->PartTbl[0].StartSectorId = 1;\r
+ pMBR->PartTbl[0].SectorCount = (UINT32)DiskSectorCount;\r
+\r
+ pMBR->Byte55 = 0x55;\r
+ pMBR->ByteAA = 0xAA;\r
+\r
+ pMBR->BootCode[92] = 0x22;\r
+\r
+ return 0;\r
+}\r
+\r
+\r
+int VentoyFillGpt(UINT64 DiskSizeBytes, VTOY_GPT_INFO *pInfo)\r
+{\r
+ INT64 ReservedValue = 0;\r
+ UINT64 ReservedSector = 33;\r
+ UINT64 Part1SectorCount = 0;\r
+ UINT64 DiskSectorCount = DiskSizeBytes / 512;\r
+ VTOY_GPT_HDR *Head = &pInfo->Head;\r
+ VTOY_GPT_PART_TBL *Table = pInfo->PartTbl;\r
+ static GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };\r
+ static GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };\r
+ static GUID BiosGrubPartType = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };\r
+\r
+ VentoyFillProtectMBR(DiskSizeBytes, &pInfo->MBR);\r
+\r
+ ReservedValue = GetReservedSpaceInMB();\r
+ if (ReservedValue > 0)\r
+ {\r
+ ReservedSector += ReservedValue * 2048;\r
+ }\r
+\r
+ Part1SectorCount = DiskSectorCount - ReservedSector - (VENTOY_EFI_PART_SIZE / 512) - 2048;\r
+\r
+ memcpy(Head->Signature, "EFI PART", 8);\r
+ Head->Version[2] = 0x01;\r
+ Head->Length = 92;\r
+ Head->Crc = 0;\r
+ Head->EfiStartLBA = 1;\r
+ Head->EfiBackupLBA = DiskSectorCount - 1;\r
+ Head->PartAreaStartLBA = 34;\r
+ Head->PartAreaEndLBA = DiskSectorCount - 34;\r
+ CoCreateGuid(&Head->DiskGuid);\r
+ Head->PartTblStartLBA = 2;\r
+ Head->PartTblTotNum = 128;\r
+ Head->PartTblEntryLen = 128;\r
+\r
+\r
+ memcpy(&(Table[0].PartType), &WindowsDataPartType, sizeof(GUID));\r
+ CoCreateGuid(&(Table[0].PartGuid));\r
+ Table[0].StartLBA = 2048;\r
+ Table[0].LastLBA = 2048 + Part1SectorCount - 1;\r
+ Table[0].Attr = 0;\r
+ memcpy(Table[0].Name, L"Ventoy", 6 * 2);\r
+\r
+ // to fix windows issue\r
+ //memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));\r
+ memcpy(&(Table[1].PartType), &WindowsDataPartType, sizeof(GUID));\r
+ CoCreateGuid(&(Table[1].PartGuid));\r
+ Table[1].StartLBA = Table[0].LastLBA + 1;\r
+ Table[1].LastLBA = Table[1].StartLBA + VENTOY_EFI_PART_SIZE / 512 - 1;\r
+ Table[1].Attr = 0xC000000000000001ULL;\r
+ memcpy(Table[1].Name, L"VTOYEFI", 7 * 2);\r
+\r
+#if 0\r
+ memcpy(&(Table[2].PartType), &BiosGrubPartType, sizeof(GUID));\r
+ CoCreateGuid(&(Table[2].PartGuid));\r
+ Table[2].StartLBA = 34;\r
+ Table[2].LastLBA = 2047;\r
+ Table[2].Attr = 0;\r
+#endif\r
+\r
+ //Update CRC\r
+ Head->PartTblCrc = VentoyCrc32(Table, sizeof(pInfo->PartTbl));\r
+ Head->Crc = VentoyCrc32(Head, Head->Length);\r
+\r
+ return 0;\r
+}\r
+\r
+int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)\r
+{\r
+ UINT64 LBA;\r
+ UINT64 BackupLBA;\r
+\r
+ memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));\r
+\r
+ LBA = pHead->EfiStartLBA;\r
+ BackupLBA = pHead->EfiBackupLBA;\r
+ \r
+ pHead->EfiStartLBA = BackupLBA;\r
+ pHead->EfiBackupLBA = LBA;\r
+ pHead->PartTblStartLBA = BackupLBA + 1 - 33;\r
+\r
+ pHead->Crc = 0;\r
+ pHead->Crc = VentoyCrc32(pHead, pHead->Length);\r
+\r
+ return 0;\r
+}\r
+\r
+CHAR GetFirstUnusedDriveLetter(void)\r
+{\r
+ CHAR Letter = 'D';\r
+ DWORD Drives = GetLogicalDrives();\r
+\r
+ Drives >>= 3;\r
+ while (Drives & 0x1)\r
+ {\r
+ Letter++;\r
+ Drives >>= 1;\r
+ }\r
+\r
+ return Letter;\r
+}\r
+\r
+const CHAR * GetBusTypeString(STORAGE_BUS_TYPE Type)\r
+{\r
+ switch (Type)\r
+ {\r
+ case BusTypeUnknown: return "unknown";\r
+ case BusTypeScsi: return "SCSI";\r
+ case BusTypeAtapi: return "Atapi";\r
+ case BusTypeAta: return "ATA";\r
+ case BusType1394: return "1394";\r
+ case BusTypeSsa: return "SSA";\r
+ case BusTypeFibre: return "Fibre";\r
+ case BusTypeUsb: return "USB";\r
+ case BusTypeRAID: return "RAID";\r
+ case BusTypeiScsi: return "iSCSI";\r
+ case BusTypeSas: return "SAS";\r
+ case BusTypeSata: return "SATA";\r
+ case BusTypeSd: return "SD";\r
+ case BusTypeMmc: return "MMC";\r
+ case BusTypeVirtual: return "Virtual";\r
+ case BusTypeFileBackedVirtual: return "FileBackedVirtual";\r
+ case BusTypeSpaces: return "Spaces";\r
+ case BusTypeNvme: return "Nvme";\r
+ }\r
+ return "unknown";\r
+}\r
+\r
+int VentoyGetLocalBootImg(MBR_HEAD *pMBR)\r
+{\r
+ int Len = 0;\r
+ BYTE *ImgBuf = NULL;\r
+ static int Loaded = 0;\r
+ static MBR_HEAD MBR;\r
+\r
+ if (Loaded)\r
+ {\r
+ memcpy(pMBR, &MBR, 512);\r
+ return 0;\r
+ }\r
+\r
+ if (0 == ReadWholeFileToBuf(VENTOY_FILE_BOOT_IMG, 0, (void **)&ImgBuf, &Len))\r
+ {\r
+ Log("Copy boot img success");\r
+ memcpy(pMBR, ImgBuf, 512);\r
+ free(ImgBuf);\r
+ \r
+ CoCreateGuid((GUID *)(pMBR->BootCode + 0x180));\r
+\r
+ memcpy(&MBR, pMBR, 512);\r
+ Loaded = 1;\r
+\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ Log("Copy boot img failed");\r
+ return 1;\r
+ }\r
+}\r
+\r
+int GetHumanReadableGBSize(UINT64 SizeBytes)\r
+{\r
+ int i;\r
+ int Pow2 = 1;\r
+ double Delta;\r
+ double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;\r
+\r
+ for (i = 0; i < 12; i++)\r
+ {\r
+ if (Pow2 > GB)\r
+ {\r
+ Delta = (Pow2 - GB) / Pow2;\r
+ }\r
+ else\r
+ {\r
+ Delta = (GB - Pow2) / Pow2;\r
+ }\r
+\r
+ if (Delta < 0.05)\r
+ {\r
+ return Pow2;\r
+ }\r
+\r
+ Pow2 <<= 1;\r
+ }\r
+\r
+ return (int)GB;\r
+}\r
+\r
+void TrimString(CHAR *String)\r
+{\r
+ CHAR *Pos1 = String;\r
+ CHAR *Pos2 = String;\r
+ size_t Len = strlen(String);\r
+\r
+ while (Len > 0)\r
+ {\r
+ if (String[Len - 1] != ' ' && String[Len - 1] != '\t')\r
+ {\r
+ break;\r
+ }\r
+ String[Len - 1] = 0;\r
+ Len--;\r
+ }\r
+\r
+ while (*Pos1 == ' ' || *Pos1 == '\t')\r
+ {\r
+ Pos1++;\r
+ }\r
+\r
+ while (*Pos1)\r
+ {\r
+ *Pos2++ = *Pos1++;\r
+ }\r
+ *Pos2++ = 0;\r
+\r
+ return;\r
+}\r
+\r
+int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)\r
+{\r
+ HKEY hKey;\r
+ DWORD Type;\r
+ DWORD Size;\r
+ LSTATUS lRet;\r
+ DWORD Value;\r
+\r
+ lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);\r
+ Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);\r
+\r
+ if (ERROR_SUCCESS == lRet)\r
+ {\r
+ Size = sizeof(Value);\r
+ lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);\r
+ Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName, lRet, Size, Value);\r
+\r
+ *pValue = Value;\r
+ RegCloseKey(hKey);\r
+\r
+ return 0;\r
+ }\r
+ else\r
+ {\r
+ return 1;\r
+ }\r
+}\r
+\r
+int GetPhysicalDriveCount(void)\r
+{\r
+ DWORD Value;\r
+ int Count = 0;\r
+\r
+ if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)\r
+ {\r
+ Count = (int)Value;\r
+ }\r
+\r
+ Log("GetPhysicalDriveCount: %d", Count);\r
+ return Count;\r
+}\r
+\r
+\r
+\r