diff --git a/INSTALL/Ventoy2Disk.exe b/INSTALL/Ventoy2Disk.exe
index 7fed29a8..505927dd 100644
Binary files a/INSTALL/Ventoy2Disk.exe and b/INSTALL/Ventoy2Disk.exe differ
diff --git a/INSTALL/Ventoy2Disk_ARM.exe b/INSTALL/Ventoy2Disk_ARM.exe
index 295864b3..83073e1d 100644
Binary files a/INSTALL/Ventoy2Disk_ARM.exe and b/INSTALL/Ventoy2Disk_ARM.exe differ
diff --git a/INSTALL/Ventoy2Disk_ARM64.exe b/INSTALL/Ventoy2Disk_ARM64.exe
index 8d68a228..ef820063 100644
Binary files a/INSTALL/Ventoy2Disk_ARM64.exe and b/INSTALL/Ventoy2Disk_ARM64.exe differ
diff --git a/INSTALL/Ventoy2Disk_X64.exe b/INSTALL/Ventoy2Disk_X64.exe
index ff71dd16..44fe8e4b 100644
Binary files a/INSTALL/Ventoy2Disk_X64.exe and b/INSTALL/Ventoy2Disk_X64.exe differ
diff --git a/INSTALL/grub/grub.cfg b/INSTALL/grub/grub.cfg
index 5cc8079e..064542ba 100644
--- a/INSTALL/grub/grub.cfg
+++ b/INSTALL/grub/grub.cfg
@@ -2397,7 +2397,7 @@ function mimg_common_menuentry {
#############################################################
#############################################################
-set VENTOY_VERSION="1.0.85"
+set VENTOY_VERSION="1.0.86"
#ACPI not compatible with Window7/8, so disable by default
set VTOY_PARAM_NO_ACPI=1
diff --git a/Ventoy2Disk/Ventoy2Disk/PartDialog.c b/Ventoy2Disk/Ventoy2Disk/PartDialog.c
index 46450d1f..eb4aa0d9 100644
Binary files a/Ventoy2Disk/Ventoy2Disk/PartDialog.c and b/Ventoy2Disk/Ventoy2Disk/PartDialog.c differ
diff --git a/Ventoy2Disk/Ventoy2Disk/Utility.c b/Ventoy2Disk/Ventoy2Disk/Utility.c
index 80cd6baa..dc9464a8 100644
--- a/Ventoy2Disk/Ventoy2Disk/Utility.c
+++ b/Ventoy2Disk/Ventoy2Disk/Utility.c
@@ -56,21 +56,23 @@ void Log(const char *Fmt, ...)
Sys.wMilliseconds);
va_start(Arg, Fmt);
- Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);
+ Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len - 1, sizeof(szBuf)-Len-1, Fmt, Arg);
va_end(Arg);
- //printf("%s\n", szBuf);
-
-#if 1
- fopen_s(&File, VENTOY_FILE_LOG, "a+");
+ if (g_CLI_Mode)
+ {
+ fopen_s(&File, VENTOY_CLI_LOG, "a+");
+ }
+ else
+ {
+ fopen_s(&File, VENTOY_FILE_LOG, "a+");
+ }
if (File)
{
fwrite(szBuf, 1, Len, File);
fwrite("\n", 1, 1, File);
fclose(File);
}
-#endif
-
}
const char* GUID2String(void *guid, char *buf, int len)
diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
index 0e0fe67b..68520a06 100644
--- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
+++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
@@ -76,7 +76,7 @@ int ParseCmdLineOption(LPSTR lpCmdLine)
return 0;
}
-static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UINT64 *Part2StartSector, UINT64 *GptPart2Attr)
+BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UINT64 *Part2StartSector, UINT64 *GptPart2Attr)
{
int i;
BOOL bRet;
@@ -274,7 +274,7 @@ int GetVolumeClusterSize(char Drive)
return 0;
}
-static int GetVentoyFsNameInPhyDrive(PHY_DRIVE_INFO* CurDrive)
+int GetVentoyFsNameInPhyDrive(PHY_DRIVE_INFO* CurDrive)
{
int i = 0;
UINT64 Offset;
diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h
index 84d98b59..1a0a453f 100644
--- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h
+++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.h
@@ -48,6 +48,11 @@ typedef enum VTOY_FS
#define VENTOY_FILE_LOG "log.txt"
#define VENTOY_FILE_VERSION "ventoy\\version"
+#define VENTOY_CLI_LOG "cli_log.txt"
+#define VENTOY_CLI_PERCENT "cli_percent.txt"
+#define VENTOY_CLI_DONE "cli_done.txt"
+
+
#define DRIVE_ACCESS_TIMEOUT 15000 // How long we should retry drive access (in ms)
#define DRIVE_ACCESS_RETRIES 150 // How many times we should retry
@@ -345,6 +350,8 @@ extern int __static_assert__[sizeof(VTSI_FOOTER) == 512 ? 1 : -1];
extern HWND g_DialogHwnd;
+extern BOOL g_CLI_Mode;
+
#define SAFE_FREE(ptr) if (ptr) { free(ptr); (ptr) = NULL; }
int InstallVentoy2FileImage(PHY_DRIVE_INFO *pPhyDrive, int PartStyle);
void disk_io_set_imghook(FILE *fp, VTSI_SEGMENT *segment, int maxseg, UINT64 data_offset);
@@ -358,6 +365,11 @@ const char* GUID2String(void* guid, char* buf, int len);
void VentoyStringToUpper(CHAR* str);
BOOL AlertSuppressInit(void);
void SetAlertPromptHookEnable(BOOL enable);
+int VentoyCLIMain(int argc, char** argv);
+BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD* pMBR, UINT64* Part2StartSector, UINT64* GptPart2Attr);
+int GetVentoyFsNameInPhyDrive(PHY_DRIVE_INFO* CurDrive);
+void CLISetReserveSpace(int MB);
+void CLI_UpdatePercent(int Pos);
#define VTSI_SUPPORT 1
diff --git a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj
index 451dae83..e2df9e18 100644
--- a/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj
+++ b/Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.vcxproj
@@ -367,6 +367,7 @@
+
diff --git a/Ventoy2Disk/Ventoy2Disk/WinDialog.c b/Ventoy2Disk/Ventoy2Disk/WinDialog.c
index 2e4a3692..40a8ab63 100644
Binary files a/Ventoy2Disk/Ventoy2Disk/WinDialog.c and b/Ventoy2Disk/Ventoy2Disk/WinDialog.c differ
diff --git a/Ventoy2Disk/Ventoy2Disk/ventoy_cli.c b/Ventoy2Disk/Ventoy2Disk/ventoy_cli.c
new file mode 100644
index 00000000..10c8ffe9
--- /dev/null
+++ b/Ventoy2Disk/Ventoy2Disk/ventoy_cli.c
@@ -0,0 +1,411 @@
+#include
+#include
+#include
+#include
+#include
+#include "resource.h"
+#include "Language.h"
+#include "Ventoy2Disk.h"
+#include "DiskService.h"
+#include "VentoyJson.h"
+
+extern void CLISetReserveSpace(int MB);
+
+typedef struct CLI_CFG
+{
+ int op;
+ int PartStyle;
+ int ReserveMB;
+ BOOL USBCheck;
+}CLI_CFG;
+
+BOOL g_CLI_Mode = FALSE;
+static int g_CLI_OP;
+static int g_CLI_PhyDrive;
+
+static int CLI_GetPhyDriveInfo(int PhyDrive, PHY_DRIVE_INFO* pInfo)
+{
+ BOOL bRet;
+ DWORD dwBytes;
+ HANDLE Handle = INVALID_HANDLE_VALUE;
+ CHAR PhyDrivePath[128];
+ GET_LENGTH_INFORMATION LengthInfo;
+ STORAGE_PROPERTY_QUERY Query;
+ STORAGE_DESCRIPTOR_HEADER DevDescHeader;
+ STORAGE_DEVICE_DESCRIPTOR* pDevDesc;
+
+ safe_sprintf(PhyDrivePath, "\\\\.\\PhysicalDrive%d", PhyDrive);
+ Handle = CreateFileA(PhyDrivePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
+ Log("Create file Handle:%p %s status:%u", Handle, PhyDrivePath, LASTERR);
+
+ if (Handle == INVALID_HANDLE_VALUE)
+ {
+ return 1;
+ }
+
+ 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);
+ return 1;
+ }
+
+ Log("PHYSICALDRIVE%d size %llu bytes", PhyDrive, (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);
+ return 1;
+ }
+
+ if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))
+ {
+ Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);
+ return 1;
+ }
+
+ pDevDesc = (STORAGE_DEVICE_DESCRIPTOR*)malloc(DevDescHeader.Size);
+ if (!pDevDesc)
+ {
+ Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);
+ return 1;
+ }
+
+ 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);
+ return 1;
+ }
+
+ pInfo->PhyDrive = PhyDrive;
+ pInfo->SizeInBytes = LengthInfo.Length.QuadPart;
+ pInfo->DeviceType = pDevDesc->DeviceType;
+ pInfo->RemovableMedia = pDevDesc->RemovableMedia;
+ pInfo->BusType = pDevDesc->BusType;
+
+ if (pDevDesc->VendorIdOffset)
+ {
+ safe_strcpy(pInfo->VendorId, (char*)pDevDesc + pDevDesc->VendorIdOffset);
+ TrimString(pInfo->VendorId);
+ }
+
+ if (pDevDesc->ProductIdOffset)
+ {
+ safe_strcpy(pInfo->ProductId, (char*)pDevDesc + pDevDesc->ProductIdOffset);
+ TrimString(pInfo->ProductId);
+ }
+
+ if (pDevDesc->ProductRevisionOffset)
+ {
+ safe_strcpy(pInfo->ProductRev, (char*)pDevDesc + pDevDesc->ProductRevisionOffset);
+ TrimString(pInfo->ProductRev);
+ }
+
+ if (pDevDesc->SerialNumberOffset)
+ {
+ safe_strcpy(pInfo->SerialNumber, (char*)pDevDesc + pDevDesc->SerialNumberOffset);
+ TrimString(pInfo->SerialNumber);
+ }
+
+ free(pDevDesc);
+
+ CHECK_CLOSE_HANDLE(Handle);
+
+ return 0;
+}
+
+static int CLI_CheckParam(int argc, char** argv, PHY_DRIVE_INFO* pDrvInfo, CLI_CFG *pCfg)
+{
+ int i;
+ int op = -1;
+ char* opt = NULL;
+ int PhyDrive = -1;
+ int PartStyle = 0;
+ int ReserveMB = 0;
+ BOOL USBCheck = TRUE;
+ MBR_HEAD MBR;
+ UINT64 Part2GPTAttr = 0;
+ UINT64 Part2StartSector = 0;
+
+ for (i = 0; i < argc; i++)
+ {
+ opt = argv[i];
+ if (_stricmp(opt, "/I") == 0)
+ {
+ op = 0;
+ }
+ else if (_stricmp(opt, "/U") == 0)
+ {
+ op = 1;
+ }
+ else if (_stricmp(opt, "/GPT") == 0)
+ {
+ PartStyle = 1;
+ }
+ else if (_stricmp(opt, "/NoSB") == 0)
+ {
+ g_SecureBoot = FALSE;
+ }
+ else if (_stricmp(opt, "/NoUSBCheck") == 0)
+ {
+ USBCheck = FALSE;
+ }
+ else if (_strnicmp(opt, "/Drive:", 7) == 0)
+ {
+ Log("Get PhyDrive by logical drive %C:", opt[7]);
+ PhyDrive = GetPhyDriveByLogicalDrive(opt[7], NULL);
+ }
+ else if (_strnicmp(opt, "/PhyDrive:", 10) == 0)
+ {
+ PhyDrive = (int)strtol(opt + 10, NULL, 10);
+ }
+ else if (_strnicmp(opt, "/R:", 3) == 0)
+ {
+ ReserveMB = (int)strtol(opt + 3, NULL, 10);
+ }
+ }
+
+ if (op < 0 || PhyDrive < 0)
+ {
+ Log("[ERROR] Invalid parameters %d %d", op, PhyDrive);
+ return 1;
+ }
+
+ Log("Ventoy CLI %s PhyDrive:%d %s SecureBoot:%d ReserveSpace:%dMB USBCheck:%u",
+ op == 0 ? "install" : "update",
+ PhyDrive, PartStyle ? "GPT" : "MBR",
+ g_SecureBoot, ReserveMB, USBCheck
+ );
+
+ if (CLI_GetPhyDriveInfo(PhyDrive, pDrvInfo))
+ {
+ Log("[ERROR] Failed to get phydrive%d info", PhyDrive);
+ return 1;
+ }
+
+ Log("PhyDrive:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",
+ pDrvInfo->PhyDrive, GetBusTypeString(pDrvInfo->BusType), pDrvInfo->RemovableMedia,
+ GetHumanReadableGBSize(pDrvInfo->SizeInBytes), pDrvInfo->SizeInBytes,
+ pDrvInfo->VendorId, pDrvInfo->ProductId);
+
+ if (IsVentoyPhyDrive(PhyDrive, pDrvInfo->SizeInBytes, &MBR, &Part2StartSector, &Part2GPTAttr))
+ {
+ memcpy(&(pDrvInfo->MBR), &MBR, sizeof(MBR));
+ pDrvInfo->PartStyle = (MBR.PartTbl[0].FsFlag == 0xEE) ? 1 : 0;
+ pDrvInfo->Part2GPTAttr = Part2GPTAttr;
+ GetVentoyVerInPhyDrive(pDrvInfo, Part2StartSector, pDrvInfo->VentoyVersion, sizeof(pDrvInfo->VentoyVersion), &(pDrvInfo->SecureBootSupport));
+ Log("PhyDrive %d is Ventoy Disk ver:%s SecureBoot:%u", pDrvInfo->PhyDrive, pDrvInfo->VentoyVersion, pDrvInfo->SecureBootSupport);
+
+ GetVentoyFsNameInPhyDrive(pDrvInfo);
+
+ if (pDrvInfo->VentoyVersion[0] == 0)
+ {
+ pDrvInfo->VentoyVersion[0] = '?';
+ Log("Unknown Ventoy Version");
+ }
+ }
+
+ pCfg->op = op;
+ pCfg->PartStyle = PartStyle;
+ pCfg->ReserveMB = ReserveMB;
+ pCfg->USBCheck = USBCheck;
+
+ return 0;
+}
+
+static int Ventoy_CLI_Install(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG *pCfg)
+{
+ int rc;
+ int TryId = 1;
+
+ Log("Ventoy_CLI_Install start ...");
+
+ if (pCfg->ReserveMB > 0)
+ {
+ CLISetReserveSpace(pCfg->ReserveMB);
+ }
+
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);
+ if (rc)
+ {
+ Log("This time install failed, clean disk by disk, wait 3s and retry...");
+ DISK_CleanDisk(pDrvInfo->PhyDrive);
+
+ Sleep(3000);
+
+ Log("Now retry to install...");
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);
+
+ if (rc)
+ {
+ Log("This time install failed, clean disk by diskpart, wait 5s and retry...");
+ DSPT_CleanDisk(pDrvInfo->PhyDrive);
+
+ Sleep(5000);
+
+ Log("Now retry to install...");
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);
+ }
+ }
+
+ Log("Ventoy_CLI_Install [%s]", rc == 0 ? "SUCCESS" : "FAILED");
+
+ return rc;
+}
+
+static int Ventoy_CLI_Update(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG* pCfg)
+{
+ int rc;
+ int TryId = 1;
+
+ Log("Ventoy_CLI_Update start ...");
+
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);
+ if (rc)
+ {
+ Log("This time update failed, now wait and retry...");
+ Sleep(4000);
+
+ //Try2
+ Log("Now retry to update...");
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);
+ if (rc)
+ {
+ //Try3
+ Sleep(1000);
+ Log("Now retry to update...");
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);
+ if (rc)
+ {
+ //Try4 is dangerous ...
+ Sleep(3000);
+ Log("Now retry to update...");
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);
+ }
+ }
+ }
+
+ Log("Ventoy_CLI_Update [%s]", rc == 0 ? "SUCCESS" : "FAILED");
+
+ return rc;
+}
+
+void CLI_UpdatePercent(int Pos)
+{
+ int Len;
+ FILE* File = NULL;
+ CHAR szBuf[128];
+
+ Len = (int)sprintf_s(szBuf, sizeof(szBuf), "%d", Pos * 100 / PT_FINISH);
+ fopen_s(&File, VENTOY_CLI_PERCENT, "w+");
+ if (File)
+ {
+ fwrite(szBuf, 1, Len, File);
+ fwrite("\n", 1, 1, File);
+ fclose(File);
+ }
+}
+
+static void CLI_WriteDoneFile(int ret)
+{
+ FILE* File = NULL;
+
+ fopen_s(&File, VENTOY_CLI_DONE, "w+");
+ if (File)
+ {
+ if (ret == 0)
+ {
+ fwrite("0\n", 1, 2, File);
+ }
+ else
+ {
+ fwrite("1\n", 1, 2, File);
+ }
+ fclose(File);
+ }
+}
+
+/*
+ * Ventoy2Disk.exe VTOYCLI { /I | /U } { /Drive:F: | /PhyDrive:1 } /GPT /NoSB /R:4096 /NoUSBCheck
+ *
+ */
+int VentoyCLIMain(int argc, char** argv)
+{
+ int ret = 1;
+ PHY_DRIVE_INFO* pDrvInfo = NULL;
+ CLI_CFG CliCfg;
+
+ DeleteFileA(VENTOY_CLI_PERCENT);
+ DeleteFileA(VENTOY_CLI_DONE);
+
+ pDrvInfo = (PHY_DRIVE_INFO*)malloc(sizeof(PHY_DRIVE_INFO));
+ if (!pDrvInfo)
+ {
+ goto end;
+ }
+ memset(pDrvInfo, 0, sizeof(PHY_DRIVE_INFO));
+
+ if (CLI_CheckParam(argc, argv, pDrvInfo, &CliCfg))
+ {
+ goto end;
+ }
+
+ //Check USB type for install
+ if (CliCfg.op == 0 && CliCfg.USBCheck)
+ {
+ if (pDrvInfo->BusType != BusTypeUsb)
+ {
+ Log("[ERROR] PhyDrive %d is NOT USB type", pDrvInfo->PhyDrive);
+ goto end;
+ }
+ }
+
+ if (CliCfg.op == 0)
+ {
+ ret = Ventoy_CLI_Install(pDrvInfo, &CliCfg);
+ }
+ else
+ {
+ if (pDrvInfo->VentoyVersion[0] == 0)
+ {
+ Log("[ERROR] No Ventoy information detected in PhyDrive %d, so can not do update", pDrvInfo->PhyDrive);
+ goto end;
+ }
+
+ ret = Ventoy_CLI_Update(pDrvInfo, &CliCfg);
+ }
+
+end:
+ CHECK_FREE(pDrvInfo);
+
+ CLI_UpdatePercent(PT_FINISH);
+ CLI_WriteDoneFile(ret);
+
+ return ret;
+}