]> glassweightruler.freedombox.rocks Git - Ventoy.git/commitdiff
update
authorlongpanda <admin@ventoy.net>
Tue, 7 Jul 2020 15:37:00 +0000 (23:37 +0800)
committerlongpanda <admin@ventoy.net>
Tue, 7 Jul 2020 15:38:57 +0000 (23:38 +0800)
16 files changed:
GRUB2/MOD_SRC/grub-2.04/install.sh
INSTALL/Ventoy2Disk.exe
INSTALL/all_in_one.sh
INSTALL/grub/grub.cfg
INSTALL/tool/VentoyWorker.sh
INSTALL/tool/ventoy_lib.sh
INSTALL/tool/vtoygpt_32 [new file with mode: 0644]
INSTALL/tool/vtoygpt_64 [new file with mode: 0644]
Ventoy2Disk/Ventoy2Disk/PartDialog.c
Ventoy2Disk/Ventoy2Disk/PhyDrive.c
Ventoy2Disk/Ventoy2Disk/Utility.c
Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc
Ventoy2Disk/Ventoy2Disk/WinDialog.c
vtoygpt/build.sh [new file with mode: 0644]
vtoygpt/crc32.c [new file with mode: 0644]
vtoygpt/vtoygpt.c [new file with mode: 0644]

index 8d9ba4cb322a409aa6c654e67c803d4f91471a79..19cffe5624ad4a479565d88e77d646304bfbc6f2 100644 (file)
@@ -12,7 +12,7 @@ make install
 PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/
 
 net_modules_legacy="net tftp http"
 PATH=$PATH:$VT_DIR/GRUB2/INSTALL/bin/:$VT_DIR/GRUB2/INSTALL/sbin/
 
 net_modules_legacy="net tftp http"
-all_modules_legacy="date drivemap blocklist ntldr search at_keyboard usb_keyboard  gcry_md5 hashsum gzio xzio lzopio lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal  linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_gpt part_msdos fat exfat ntfs loopback gzio normal  udf gfxmenu gfxterm gfxterm_background gfxterm_menu"
+all_modules_legacy="date drivemap blocklist vga_text ntldr search at_keyboard usb_keyboard  gcry_md5 hashsum gzio xzio lzopio lspci pci ext2 xfs ventoy chain read halt iso9660 linux16 test true sleep reboot echo videotest videoinfo videotest_checksum video_colors video_cirrus video_bochs vga vbe video_fb font video gettext extcmd terminal  linux minicmd help configfile tr trig boot biosdisk disk ls tar squash4 password_pbkdf2 all_video png jpeg part_gpt part_msdos fat exfat ntfs loopback gzio normal  udf gfxmenu gfxterm gfxterm_background gfxterm_menu"
 
 net_modules_uefi="efinet net tftp http"
 all_modules_uefi="blocklist ventoy test search at_keyboard usb_keyboard  gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain  priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu"
 
 net_modules_uefi="efinet net tftp http"
 all_modules_uefi="blocklist ventoy test search at_keyboard usb_keyboard  gcry_md5 hashsum gzio xzio lzopio ext2 xfs read halt sleep serial terminfo png password_pbkdf2 gcry_sha512 pbkdf2 part_gpt part_msdos ls tar squash4 loopback part_apple minicmd diskfilter linux relocator jpeg iso9660 udf hfsplus halt acpi mmap gfxmenu video_colors trig bitmap_scale gfxterm bitmap font fat exfat ntfs fshelp efifwsetup reboot echo configfile normal terminal gettext chain  priority_queue bufio datetime cat extcmd crypto gzio boot all_video efi_gop efi_uga video_bochs video_cirrus video video_fb gfxterm_background gfxterm_menu"
index 0951124453c43783d1e6d9be93757728f160ebbb..5c4f5ae99e000d89d16655dacfdb0a4e6f9438e8 100644 (file)
Binary files a/INSTALL/Ventoy2Disk.exe and b/INSTALL/Ventoy2Disk.exe differ
index 89484e7c7b9b7d8ec916e6b7a516c8355d0e3c12..660b63bed3fa856c4a3fbf7f9bc518f7a4d9cd16 100644 (file)
@@ -23,6 +23,8 @@ sh buildlib.sh
 cd $VTOY_PATH/vtoyfat
 sh build.sh || exit 1
 
 cd $VTOY_PATH/vtoyfat
 sh build.sh || exit 1
 
+cd $VTOY_PATH/vtoygpt
+sh build.sh || exit 1
 
 cd $VTOY_PATH/ExFAT
 sh buidlibfuse.sh || exit 1
 
 cd $VTOY_PATH/ExFAT
 sh buidlibfuse.sh || exit 1
index 52e8a6b75d55af8918fd1743e849c97b79dea983..6b94d74a6104901ad09dba9382851549b92e33d9 100644 (file)
@@ -30,6 +30,29 @@ function ventoy_debug_pause {
     fi
 }
 
     fi
 }
 
+function ventoy_cli_console {      
+    if [ "$grub_platform" = "pc" ]; then
+        terminal_output  vga_text
+    else
+        if [ "$vtoy_display_mode" != "CLI" ]; then
+            terminal_output  console
+        fi
+    fi
+}
+
+function ventoy_gui_console {  
+    if [ "$grub_platform" = "pc" ]; then
+        if [ "$vtoy_display_mode" = "CLI" ]; then
+            terminal_output  console
+        else
+            terminal_output  gfxterm
+        fi
+    else
+        if [ "$vtoy_display_mode" != "CLI" ]; then
+            terminal_output  gfxterm
+        fi
+    fi
+}
 
 function ventoy_power {
     configfile $prefix/power.cfg
 
 function ventoy_power {
     configfile $prefix/power.cfg
@@ -186,7 +209,7 @@ function uefi_windows_menu_func {
     ventoy_debug_pause
     
     if [ -n "$vtoy_chain_mem_addr" ]; then
     ventoy_debug_pause
     
     if [ -n "$vtoy_chain_mem_addr" ]; then
-        terminal_output  console       
+        ventoy_cli_console
         chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         boot
     else
         chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         boot
     else
@@ -262,7 +285,7 @@ function uefi_linux_menu_func {
     vt_linux_chain_data ${1}${chosen_path}
 
     if [ -n "$vtoy_chain_mem_addr" ]; then
     vt_linux_chain_data ${1}${chosen_path}
 
     if [ -n "$vtoy_chain_mem_addr" ]; then
-        terminal_output  console       
+        ventoy_cli_console       
         chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} FirstTry=${FirstTryBootFile} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         boot
     else
         chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} FirstTry=${FirstTryBootFile} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         boot
     else
@@ -327,7 +350,7 @@ function uefi_iso_menu_func {
         uefi_linux_menu_func  $1 ${chosen_path}
     fi
 
         uefi_linux_menu_func  $1 ${chosen_path}
     fi
 
-    terminal_output  gfxterm    
+    ventoy_gui_console
 }
 
 function uefi_iso_memdisk {    
 }
 
 function uefi_iso_memdisk {    
@@ -336,11 +359,11 @@ function uefi_iso_memdisk {
     echo 'Loading ISO file to memory ...'
     vt_load_iso_to_mem ${1}${chosen_path} vtoy_iso_buf
     
     echo 'Loading ISO file to memory ...'
     vt_load_iso_to_mem ${1}${chosen_path} vtoy_iso_buf
     
-    terminal_output  console
+    ventoy_cli_console
     chainloader ${vtoy_path}/ventoy_x64.efi memdisk env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_iso_buf_addr}:size:${vtoy_iso_buf_size}
     boot
     
     chainloader ${vtoy_path}/ventoy_x64.efi memdisk env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_iso_buf_addr}:size:${vtoy_iso_buf_size}
     boot
     
-    terminal_output  gfxterm
+    ventoy_gui_console
 }
 
 
 }
 
 
@@ -527,9 +550,9 @@ function wim_common_menuentry {
         if [ "$grub_platform" = "pc" ]; then
             linux16   $vtoy_path/ipxe.krn ${vtdebug_flag}  mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         else
         if [ "$grub_platform" = "pc" ]; then
             linux16   $vtoy_path/ipxe.krn ${vtdebug_flag}  mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
         else
-            terminal_output  console       
+            ventoy_cli_console
             chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
             chainloader ${vtoy_path}/ventoy_x64.efi  env_param=${env_param} isoefi=${LoadIsoEfiDriver} ${vtdebug_flag} mem:${vtoy_chain_mem_addr}:size:${vtoy_chain_mem_size}
-            terminal_output  gfxterm
+            ventoy_gui_console
         fi
         boot
     else
         fi
         boot
     else
@@ -545,10 +568,10 @@ function wim_unsupport_menuentry {
 function efi_common_menuentry {
     vt_chosen_img_path chosen_path
     
 function efi_common_menuentry {
     vt_chosen_img_path chosen_path
     
-    terminal_output  console    
+    ventoy_cli_console    
     chainloader ${iso_path}${chosen_path}
     boot
     chainloader ${iso_path}${chosen_path}
     boot
-    terminal_output  gfxterm
+    ventoy_gui_console
 }
 
 function efi_unsupport_menuentry {
 }
 
 function efi_unsupport_menuentry {
index 099b2d553d8a61977aed45b97539b069abee97f6..2fe07e6af5bda721d3cec4284001ecffe28d3bc8 100644 (file)
@@ -327,22 +327,28 @@ else
     SHORT_PART2=${PART2#/dev/}
     part2_start=$(cat /sys/class/block/$SHORT_PART2/start)
     
     SHORT_PART2=${PART2#/dev/}
     part2_start=$(cat /sys/class/block/$SHORT_PART2/start)
     
-    dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=440
+    PART1_TYPE=$(dd if=$DISK bs=1 count=1 skip=450 status=none | ./tool/hexdump -n1 -e  '1/1 "%02X"')
     
     
-    PART1_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=446 status=none | ./tool/hexdump -n1 -e  '1/1 "%02X"')
-    PART2_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=462 status=none | ./tool/hexdump -n1 -e  '1/1 "%02X"')
+    if [ "$PART1_TYPE" = "EE" ]; then
+        vtdebug "This is GPT partition style ..."        
+        ./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2014 seek=34
+        echo -en '\x23' | dd of=$DISK conv=fsync bs=1 count=1 seek=17908 status=none
+    else
+        vtdebug "This is MBR partition style ..."
+        dd status=none conv=fsync if=./boot/boot.img of=$DISK bs=1 count=440
     
     
-    vtdebug "PART1_ACTIVE=$PART1_ACTIVE  PART2_ACTIVE=$PART2_ACTIVE"
-    if [ "$PART1_ACTIVE" = "00" ] && [ "$PART2_ACTIVE" = "80" ]; then
-        vtdebug "change 1st partition active, 2nd partition inactive ..."
-        echo -en '\x80' | dd of=$DISK conv=fsync bs=1 count=1 seek=446 status=none
-        echo -en '\x00' | dd of=$DISK conv=fsync bs=1 count=1 seek=462 status=none
+        PART1_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=446 status=none | ./tool/hexdump -n1 -e  '1/1 "%02X"')
+        PART2_ACTIVE=$(dd if=$DISK bs=1 count=1 skip=462 status=none | ./tool/hexdump -n1 -e  '1/1 "%02X"')
+        
+        vtdebug "PART1_ACTIVE=$PART1_ACTIVE  PART2_ACTIVE=$PART2_ACTIVE"
+        if [ "$PART1_ACTIVE" = "00" ] && [ "$PART2_ACTIVE" = "80" ]; then
+            vtdebug "change 1st partition active, 2nd partition inactive ..."
+            echo -en '\x80' | dd of=$DISK conv=fsync bs=1 count=1 seek=446 status=none
+            echo -en '\x00' | dd of=$DISK conv=fsync bs=1 count=1 seek=462 status=none
+        fi
+        ./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
     fi
 
     fi
 
-
-    ./tool/xzcat ./boot/core.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=2047 seek=1
-
-
     ./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start
 
     sync
     ./tool/xzcat ./ventoy/ventoy.disk.img.xz | dd status=none conv=fsync of=$DISK bs=512 count=$VENTOY_SECTOR_NUM seek=$part2_start
 
     sync
index 9e4d45d887f752ac79e0ac4f19a6c939a4647ae8..915deaa6969fae24b9cbac9000a2333fb4dabc5e 100644 (file)
@@ -345,11 +345,19 @@ format_ventoy_disk_gpt() {
         unit s \
         mkpart Ventoy ntfs $part1_start_sector $part1_end_sector \
         mkpart VTOYEFI fat16 $part2_start_sector $part2_end_sector \
         unit s \
         mkpart Ventoy ntfs $part1_start_sector $part1_end_sector \
         mkpart VTOYEFI fat16 $part2_start_sector $part2_end_sector \
-        set 2 boot on \
-        set 2 esp on \
+        set 2 msftdata on \
         set 2 hidden on \
         quit
         set 2 hidden on \
         quit
+        
+    sync
+    
+    if ventoy_is_linux64; then
+        vtoygpt=./tool/vtoygpt_64
+    else
+        vtoygpt=./tool/vtoygpt_32
+    fi
 
 
+    $vtoygpt -f $DISK
     sync
 
     udevadm trigger >/dev/null 2>&1
     sync
 
     udevadm trigger >/dev/null 2>&1
diff --git a/INSTALL/tool/vtoygpt_32 b/INSTALL/tool/vtoygpt_32
new file mode 100644 (file)
index 0000000..127f080
Binary files /dev/null and b/INSTALL/tool/vtoygpt_32 differ
diff --git a/INSTALL/tool/vtoygpt_64 b/INSTALL/tool/vtoygpt_64
new file mode 100644 (file)
index 0000000..068aaf6
Binary files /dev/null and b/INSTALL/tool/vtoygpt_64 differ
index b5f737c01a14ff94ed254a913faf8df2b372d21b..2b30c7464faa4ad9b1a16dd6575c4834559a98fe 100644 (file)
Binary files a/Ventoy2Disk/Ventoy2Disk/PartDialog.c and b/Ventoy2Disk/Ventoy2Disk/PartDialog.c differ
index 572aeb8719f6783fb11bc24acd4ffb50f56c9ac9..1cd0054485e26b38818c9a4411dc8669facfe934 100644 (file)
-/******************************************************************************
- * 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
index 586d2368d3491c3634f8bf38d8673f0f83dc1013..2b9327f1b5fad9ec62e4e95f617431c03d42a2c8 100644 (file)
-/******************************************************************************
- * 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
index 03a4a003ff6786f74be1fe58bfdbfdc5ff5ef70b..b8d9b67f83e7c8c1c07d7a331cf34cd117441804 100644 (file)
Binary files a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc and b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.rc differ
index 814ba2777615c631feaaf281d273399fbc8f896e..b72d22f4ef7396e6b7eb8699526d10e417cc8634 100644 (file)
Binary files a/Ventoy2Disk/Ventoy2Disk/WinDialog.c and b/Ventoy2Disk/Ventoy2Disk/WinDialog.c differ
diff --git a/vtoygpt/build.sh b/vtoygpt/build.sh
new file mode 100644 (file)
index 0000000..a8c3f7e
--- /dev/null
@@ -0,0 +1,19 @@
+#!/bin/bash
+
+rm -f vtoytool/00/*
+
+/opt/diet64/bin/diet -Os gcc -D_FILE_OFFSET_BITS=64  vtoygpt.c crc32.c -o  vtoygpt_64
+/opt/diet32/bin/diet -Os gcc -D_FILE_OFFSET_BITS=64 -m32 vtoygpt.c crc32.c -o  vtoygpt_32
+
+#gcc -D_FILE_OFFSET_BITS=64 -static -Wall vtoygpt.c  -o  vtoytool_64
+#gcc -D_FILE_OFFSET_BITS=64  -Wall  -m32  vtoygpt.c  -o  vtoytool_32
+
+if [ -e vtoygpt_64 ] && [ -e vtoygpt_32 ]; then
+    echo -e '\n############### SUCCESS ###############\n'
+    mv vtoygpt_64 ../INSTALL/tool/
+    mv vtoygpt_32 ../INSTALL/tool/
+else
+    echo -e '\n############### FAILED ################\n'
+    exit 1
+fi
+
diff --git a/vtoygpt/crc32.c b/vtoygpt/crc32.c
new file mode 100644 (file)
index 0000000..354372b
--- /dev/null
@@ -0,0 +1,315 @@
+/******************************************************************************
+ * vtoygpt.c  ---- ventoy gpt util
+ *
+ * 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 <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/fs.h>
+#include <dirent.h>
+
+#define VOID   void
+#define CHAR   char
+#define UINT64 unsigned long long
+#define UINT32 unsigned int
+#define UINT16 unsigned short
+#define CHAR16 unsigned short
+#define UINT8  unsigned char
+
+UINT32 g_crc_table[256] = {
+  0x00000000,
+  0x77073096,
+  0xEE0E612C,
+  0x990951BA,
+  0x076DC419,
+  0x706AF48F,
+  0xE963A535,
+  0x9E6495A3,
+  0x0EDB8832,
+  0x79DCB8A4,
+  0xE0D5E91E,
+  0x97D2D988,
+  0x09B64C2B,
+  0x7EB17CBD,
+  0xE7B82D07,
+  0x90BF1D91,
+  0x1DB71064,
+  0x6AB020F2,
+  0xF3B97148,
+  0x84BE41DE,
+  0x1ADAD47D,
+  0x6DDDE4EB,
+  0xF4D4B551,
+  0x83D385C7,
+  0x136C9856,
+  0x646BA8C0,
+  0xFD62F97A,
+  0x8A65C9EC,
+  0x14015C4F,
+  0x63066CD9,
+  0xFA0F3D63,
+  0x8D080DF5,
+  0x3B6E20C8,
+  0x4C69105E,
+  0xD56041E4,
+  0xA2677172,
+  0x3C03E4D1,
+  0x4B04D447,
+  0xD20D85FD,
+  0xA50AB56B,
+  0x35B5A8FA,
+  0x42B2986C,
+  0xDBBBC9D6,
+  0xACBCF940,
+  0x32D86CE3,
+  0x45DF5C75,
+  0xDCD60DCF,
+  0xABD13D59,
+  0x26D930AC,
+  0x51DE003A,
+  0xC8D75180,
+  0xBFD06116,
+  0x21B4F4B5,
+  0x56B3C423,
+  0xCFBA9599,
+  0xB8BDA50F,
+  0x2802B89E,
+  0x5F058808,
+  0xC60CD9B2,
+  0xB10BE924,
+  0x2F6F7C87,
+  0x58684C11,
+  0xC1611DAB,
+  0xB6662D3D,
+  0x76DC4190,
+  0x01DB7106,
+  0x98D220BC,
+  0xEFD5102A,
+  0x71B18589,
+  0x06B6B51F,
+  0x9FBFE4A5,
+  0xE8B8D433,
+  0x7807C9A2,
+  0x0F00F934,
+  0x9609A88E,
+  0xE10E9818,
+  0x7F6A0DBB,
+  0x086D3D2D,
+  0x91646C97,
+  0xE6635C01,
+  0x6B6B51F4,
+  0x1C6C6162,
+  0x856530D8,
+  0xF262004E,
+  0x6C0695ED,
+  0x1B01A57B,
+  0x8208F4C1,
+  0xF50FC457,
+  0x65B0D9C6,
+  0x12B7E950,
+  0x8BBEB8EA,
+  0xFCB9887C,
+  0x62DD1DDF,
+  0x15DA2D49,
+  0x8CD37CF3,
+  0xFBD44C65,
+  0x4DB26158,
+  0x3AB551CE,
+  0xA3BC0074,
+  0xD4BB30E2,
+  0x4ADFA541,
+  0x3DD895D7,
+  0xA4D1C46D,
+  0xD3D6F4FB,
+  0x4369E96A,
+  0x346ED9FC,
+  0xAD678846,
+  0xDA60B8D0,
+  0x44042D73,
+  0x33031DE5,
+  0xAA0A4C5F,
+  0xDD0D7CC9,
+  0x5005713C,
+  0x270241AA,
+  0xBE0B1010,
+  0xC90C2086,
+  0x5768B525,
+  0x206F85B3,
+  0xB966D409,
+  0xCE61E49F,
+  0x5EDEF90E,
+  0x29D9C998,
+  0xB0D09822,
+  0xC7D7A8B4,
+  0x59B33D17,
+  0x2EB40D81,
+  0xB7BD5C3B,
+  0xC0BA6CAD,
+  0xEDB88320,
+  0x9ABFB3B6,
+  0x03B6E20C,
+  0x74B1D29A,
+  0xEAD54739,
+  0x9DD277AF,
+  0x04DB2615,
+  0x73DC1683,
+  0xE3630B12,
+  0x94643B84,
+  0x0D6D6A3E,
+  0x7A6A5AA8,
+  0xE40ECF0B,
+  0x9309FF9D,
+  0x0A00AE27,
+  0x7D079EB1,
+  0xF00F9344,
+  0x8708A3D2,
+  0x1E01F268,
+  0x6906C2FE,
+  0xF762575D,
+  0x806567CB,
+  0x196C3671,
+  0x6E6B06E7,
+  0xFED41B76,
+  0x89D32BE0,
+  0x10DA7A5A,
+  0x67DD4ACC,
+  0xF9B9DF6F,
+  0x8EBEEFF9,
+  0x17B7BE43,
+  0x60B08ED5,
+  0xD6D6A3E8,
+  0xA1D1937E,
+  0x38D8C2C4,
+  0x4FDFF252,
+  0xD1BB67F1,
+  0xA6BC5767,
+  0x3FB506DD,
+  0x48B2364B,
+  0xD80D2BDA,
+  0xAF0A1B4C,
+  0x36034AF6,
+  0x41047A60,
+  0xDF60EFC3,
+  0xA867DF55,
+  0x316E8EEF,
+  0x4669BE79,
+  0xCB61B38C,
+  0xBC66831A,
+  0x256FD2A0,
+  0x5268E236,
+  0xCC0C7795,
+  0xBB0B4703,
+  0x220216B9,
+  0x5505262F,
+  0xC5BA3BBE,
+  0xB2BD0B28,
+  0x2BB45A92,
+  0x5CB36A04,
+  0xC2D7FFA7,
+  0xB5D0CF31,
+  0x2CD99E8B,
+  0x5BDEAE1D,
+  0x9B64C2B0,
+  0xEC63F226,
+  0x756AA39C,
+  0x026D930A,
+  0x9C0906A9,
+  0xEB0E363F,
+  0x72076785,
+  0x05005713,
+  0x95BF4A82,
+  0xE2B87A14,
+  0x7BB12BAE,
+  0x0CB61B38,
+  0x92D28E9B,
+  0xE5D5BE0D,
+  0x7CDCEFB7,
+  0x0BDBDF21,
+  0x86D3D2D4,
+  0xF1D4E242,
+  0x68DDB3F8,
+  0x1FDA836E,
+  0x81BE16CD,
+  0xF6B9265B,
+  0x6FB077E1,
+  0x18B74777,
+  0x88085AE6,
+  0xFF0F6A70,
+  0x66063BCA,
+  0x11010B5C,
+  0x8F659EFF,
+  0xF862AE69,
+  0x616BFFD3,
+  0x166CCF45,
+  0xA00AE278,
+  0xD70DD2EE,
+  0x4E048354,
+  0x3903B3C2,
+  0xA7672661,
+  0xD06016F7,
+  0x4969474D,
+  0x3E6E77DB,
+  0xAED16A4A,
+  0xD9D65ADC,
+  0x40DF0B66,
+  0x37D83BF0,
+  0xA9BCAE53,
+  0xDEBB9EC5,
+  0x47B2CF7F,
+  0x30B5FFE9,
+  0xBDBDF21C,
+  0xCABAC28A,
+  0x53B39330,
+  0x24B4A3A6,
+  0xBAD03605,
+  0xCDD70693,
+  0x54DE5729,
+  0x23D967BF,
+  0xB3667A2E,
+  0xC4614AB8,
+  0x5D681B02,
+  0x2A6F2B94,
+  0xB40BBE37,
+  0xC30C8EA1,
+  0x5A05DF1B,
+  0x2D02EF8D
+};
+
+UINT32 VtoyCrc32(VOID *Buffer, UINT32 Length)
+{
+    UINT32  i;
+    UINT8  *Ptr = Buffer;
+    UINT32  Crc = 0xFFFFFFFF;
+
+    for (i = 0; i < Length; i++, Ptr++) 
+    {
+        Crc = (Crc >> 8) ^ g_crc_table[(UINT8) Crc ^ *Ptr];
+    }
+
+    return Crc ^ 0xffffffff;
+}
+
diff --git a/vtoygpt/vtoygpt.c b/vtoygpt/vtoygpt.c
new file mode 100644 (file)
index 0000000..705f750
--- /dev/null
@@ -0,0 +1,320 @@
+/******************************************************************************
+ * vtoygpt.c  ---- ventoy gpt util
+ *
+ * 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 <stdio.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/types.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <linux/fs.h>
+#include <dirent.h>
+
+#define VOID   void
+#define CHAR   char
+#define UINT64 unsigned long long
+#define UINT32 unsigned int
+#define UINT16 unsigned short
+#define CHAR16 unsigned short
+#define UINT8  unsigned char
+
+UINT32 VtoyCrc32(VOID *Buffer, UINT32 Length);
+
+#define COMPILE_ASSERT(expr)  extern char __compile_assert[(expr) ? 1 : -1]
+
+#pragma pack(1)
+
+typedef struct PART_TABLE
+{
+    UINT8  Active;
+
+    UINT8  StartHead;
+    UINT16 StartSector : 6;
+    UINT16 StartCylinder : 10;
+
+    UINT8  FsFlag;
+
+    UINT8  EndHead;
+    UINT16 EndSector : 6;
+    UINT16 EndCylinder : 10;
+
+    UINT32 StartSectorId;
+    UINT32 SectorCount;
+}PART_TABLE;
+
+typedef struct MBR_HEAD
+{
+    UINT8 BootCode[446];
+    PART_TABLE PartTbl[4];
+    UINT8 Byte55;
+    UINT8 ByteAA;
+}MBR_HEAD;
+
+typedef struct GUID
+{
+    UINT32   data1;
+    UINT16   data2;
+    UINT16   data3;
+    UINT8    data4[8];
+}GUID;
+
+typedef struct VTOY_GPT_HDR
+{
+    CHAR   Signature[8]; /* EFI PART */
+    UINT8  Version[4];
+    UINT32 Length;
+    UINT32 Crc;
+    UINT8  Reserved1[4];
+    UINT64 EfiStartLBA;
+    UINT64 EfiBackupLBA;
+    UINT64 PartAreaStartLBA;
+    UINT64 PartAreaEndLBA;
+    GUID   DiskGuid;
+    UINT64 PartTblStartLBA;
+    UINT32 PartTblTotNum;
+    UINT32 PartTblEntryLen;
+    UINT32 PartTblCrc;
+    UINT8  Reserved2[420];
+}VTOY_GPT_HDR;
+
+COMPILE_ASSERT(sizeof(VTOY_GPT_HDR) == 512);
+
+typedef struct VTOY_GPT_PART_TBL
+{
+    GUID   PartType;
+    GUID   PartGuid;
+    UINT64 StartLBA;
+    UINT64 LastLBA;
+    UINT64 Attr;
+    CHAR16 Name[36];
+}VTOY_GPT_PART_TBL;
+COMPILE_ASSERT(sizeof(VTOY_GPT_PART_TBL) == 128);
+
+typedef struct VTOY_GPT_INFO
+{
+    MBR_HEAD MBR;
+    VTOY_GPT_HDR Head;
+    VTOY_GPT_PART_TBL PartTbl[128];
+}VTOY_GPT_INFO;
+
+typedef struct VTOY_BK_GPT_INFO
+{
+    VTOY_GPT_PART_TBL PartTbl[128];
+    VTOY_GPT_HDR Head;
+}VTOY_BK_GPT_INFO;
+
+COMPILE_ASSERT(sizeof(VTOY_GPT_INFO) == 512 * 34);
+COMPILE_ASSERT(sizeof(VTOY_BK_GPT_INFO) == 512 * 33);
+
+#pragma pack()
+
+void DumpGuid(const char *prefix, GUID *guid)
+{
+    printf("%s: %08x-%04x-%04x-%02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n",
+        prefix,
+        guid->data1, guid->data2, guid->data3,
+        guid->data4[0], guid->data4[1], guid->data4[2], guid->data4[3],
+        guid->data4[4], guid->data4[5], guid->data4[6], guid->data4[7]
+        );
+}
+
+void DumpHead(VTOY_GPT_HDR *pHead)
+{
+    UINT32 CrcRead;
+    UINT32 CrcCalc;
+    
+    printf("Signature:<%s>\n", pHead->Signature);
+    printf("Version:<%02x %02x %02x %02x>\n", pHead->Version[0], pHead->Version[1], pHead->Version[2], pHead->Version[3]);
+    printf("Length:%u\n", pHead->Length);
+    printf("Crc:0x%08x\n", pHead->Crc);
+    printf("EfiStartLBA:%lu\n", pHead->EfiStartLBA);
+    printf("EfiBackupLBA:%lu\n", pHead->EfiBackupLBA);
+    printf("PartAreaStartLBA:%lu\n", pHead->PartAreaStartLBA);
+    printf("PartAreaEndLBA:%lu\n", pHead->PartAreaEndLBA);
+    DumpGuid("DiskGuid", &pHead->DiskGuid);
+    
+    printf("PartTblStartLBA:%lu\n", pHead->PartTblStartLBA);
+    printf("PartTblTotNum:%u\n", pHead->PartTblTotNum);
+    printf("PartTblEntryLen:%u\n", pHead->PartTblEntryLen);
+    printf("PartTblCrc:0x%08x\n", pHead->PartTblCrc);
+
+    CrcRead = pHead->Crc;
+    pHead->Crc = 0;
+    CrcCalc = VtoyCrc32(pHead, pHead->Length);
+
+    if (CrcCalc != CrcRead)
+    {
+        printf("Head CRC Check Failed\n");
+    }
+    else
+    {
+        printf("Head CRC Check SUCCESS [%x] [%x]\n", CrcCalc, CrcRead);
+    }
+
+    CrcRead = pHead->PartTblCrc;
+    CrcCalc = VtoyCrc32(pHead + 1, pHead->PartTblEntryLen * pHead->PartTblTotNum);
+    if (CrcCalc != CrcRead)
+    {
+        printf("Part Table CRC Check Failed\n");
+    }
+    else
+    {
+        printf("Part Table CRC Check SUCCESS [%x] [%x]\n", CrcCalc, CrcRead);
+    }
+}
+
+void DumpPartTable(VTOY_GPT_PART_TBL *Tbl)
+{
+    int i;
+    
+    DumpGuid("PartType", &Tbl->PartType);
+    DumpGuid("PartGuid", &Tbl->PartGuid);
+    printf("StartLBA:%lu\n", Tbl->StartLBA);
+    printf("LastLBA:%lu\n", Tbl->LastLBA);
+    printf("Attr:0x%lx\n", Tbl->Attr);
+    printf("Name:");
+
+    for (i = 0; i < 36 && Tbl->Name[i]; i++)
+    {
+        printf("%c", (CHAR)(Tbl->Name[i]));
+    }
+    printf("\n");    
+}
+
+void DumpMBR(MBR_HEAD *pMBR)
+{
+    int i;
+    
+    for (i = 0; i < 4; i++)
+    {
+        printf("=========== Partition Table %d ============\n", i + 1);
+        printf("PartTbl.Active = 0x%x\n", pMBR->PartTbl[i].Active);
+        printf("PartTbl.FsFlag = 0x%x\n", pMBR->PartTbl[i].FsFlag);
+        printf("PartTbl.StartSectorId = %u\n", pMBR->PartTbl[i].StartSectorId);
+        printf("PartTbl.SectorCount = %u\n", pMBR->PartTbl[i].SectorCount);
+        printf("PartTbl.StartHead = %u\n", pMBR->PartTbl[i].StartHead);
+        printf("PartTbl.StartSector = %u\n", pMBR->PartTbl[i].StartSector);
+        printf("PartTbl.StartCylinder = %u\n", pMBR->PartTbl[i].StartCylinder);
+        printf("PartTbl.EndHead = %u\n", pMBR->PartTbl[i].EndHead);
+        printf("PartTbl.EndSector = %u\n", pMBR->PartTbl[i].EndSector);
+        printf("PartTbl.EndCylinder = %u\n", pMBR->PartTbl[i].EndCylinder);
+    }
+}
+
+int DumpGptInfo(VTOY_GPT_INFO *pGptInfo)
+{
+    int i;
+
+    DumpMBR(&pGptInfo->MBR);
+    DumpHead(&pGptInfo->Head);
+
+    for (i = 0; i < 128; i++)
+    {
+        if (pGptInfo->PartTbl[i].StartLBA == 0)
+        {
+            break;
+        }
+    
+        printf("=====Part %d=====\n", i);
+        DumpPartTable(pGptInfo->PartTbl + i);
+    }
+
+    return 0;
+}
+
+#define VENTOY_EFI_PART_ATTR   0xC000000000000001ULL
+
+int main(int argc, const char **argv)
+{
+    int i;
+    int fd;
+    UINT64 DiskSize;
+    CHAR16 *Name = NULL;
+    VTOY_GPT_INFO *pMainGptInfo = NULL;
+    VTOY_BK_GPT_INFO *pBackGptInfo = NULL;
+
+    if (argc != 3)
+    {
+        printf("usage: vtoygpt -f /dev/sdb\n");
+        return 1;
+    }
+
+    fd = open(argv[2], O_RDWR);
+    if (fd < 0)
+    {
+        printf("Failed to open %s\n", argv[2]);
+        return 1;
+    }
+
+    pMainGptInfo = malloc(sizeof(VTOY_GPT_INFO));
+    pBackGptInfo = malloc(sizeof(VTOY_BK_GPT_INFO));
+    if (NULL == pMainGptInfo || NULL == pBackGptInfo)
+    {
+        close(fd);
+        return 1;
+    }
+
+    read(fd, pMainGptInfo, sizeof(VTOY_GPT_INFO));
+    
+    if (argv[1][0] == '-' && argv[1][1] == 'd')
+    {
+        DumpGptInfo(pMainGptInfo);
+    }
+    else
+    {
+        DiskSize = lseek(fd, 0, SEEK_END);
+        lseek(fd, DiskSize - 33 * 512, SEEK_SET);
+        read(fd, pBackGptInfo, sizeof(VTOY_BK_GPT_INFO));
+
+        Name = pMainGptInfo->PartTbl[1].Name;
+        if (Name[0] == 'V' && Name[1] == 'T' && Name[2] == 'O' && Name[3] == 'Y')
+        {
+            pMainGptInfo->PartTbl[1].Attr = VENTOY_EFI_PART_ATTR;
+            pMainGptInfo->Head.PartTblCrc = VtoyCrc32(pMainGptInfo->PartTbl, sizeof(pMainGptInfo->PartTbl));
+            pMainGptInfo->Head.Crc = 0;
+            pMainGptInfo->Head.Crc = VtoyCrc32(&pMainGptInfo->Head, pMainGptInfo->Head.Length);
+
+            pBackGptInfo->PartTbl[1].Attr = VENTOY_EFI_PART_ATTR;
+            pBackGptInfo->Head.PartTblCrc = VtoyCrc32(pBackGptInfo->PartTbl, sizeof(pBackGptInfo->PartTbl));
+            pBackGptInfo->Head.Crc = 0;
+            pBackGptInfo->Head.Crc = VtoyCrc32(&pBackGptInfo->Head, pBackGptInfo->Head.Length);
+
+            lseek(fd, 512, SEEK_SET);
+            write(fd, (UINT8 *)pMainGptInfo + 512, sizeof(VTOY_GPT_INFO) - 512);
+
+            lseek(fd, DiskSize - 33 * 512, SEEK_SET);
+            write(fd, pBackGptInfo, sizeof(VTOY_BK_GPT_INFO));
+
+            fsync(fd);
+        }
+    }
+
+    free(pMainGptInfo);
+    free(pBackGptInfo);
+    close(fd);
+
+    return 0;
+}
+