+#include <Windows.h>\r
+#include <Shlobj.h>\r
+#include <tlhelp32.h>\r
+#include <Psapi.h>\r
+#include <commctrl.h>\r
+#include "resource.h"\r
+#include "Language.h"\r
+#include "Ventoy2Disk.h"\r
+#include "DiskService.h"\r
+#include "VentoyJson.h"\r
+\r
+extern void CLISetReserveSpace(int MB);\r
+\r
+typedef struct CLI_CFG\r
+{\r
+ int op;\r
+ int PartStyle;\r
+ int ReserveMB;\r
+ BOOL USBCheck;\r
+}CLI_CFG;\r
+\r
+BOOL g_CLI_Mode = FALSE;\r
+static int g_CLI_OP;\r
+static int g_CLI_PhyDrive;\r
+\r
+static int CLI_GetPhyDriveInfo(int PhyDrive, PHY_DRIVE_INFO* pInfo)\r
+{\r
+ BOOL bRet;\r
+ DWORD dwBytes;\r
+ HANDLE Handle = INVALID_HANDLE_VALUE;\r
+ CHAR PhyDrivePath[128];\r
+ GET_LENGTH_INFORMATION LengthInfo;\r
+ STORAGE_PROPERTY_QUERY Query;\r
+ STORAGE_DESCRIPTOR_HEADER DevDescHeader;\r
+ STORAGE_DEVICE_DESCRIPTOR* pDevDesc;\r
+\r
+ safe_sprintf(PhyDrivePath, "\\\\.\\PhysicalDrive%d", PhyDrive);\r
+ Handle = CreateFileA(PhyDrivePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);\r
+ Log("Create file Handle:%p %s status:%u", Handle, PhyDrivePath, LASTERR);\r
+\r
+ if (Handle == INVALID_HANDLE_VALUE)\r
+ {\r
+ return 1;\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
+ return 1;\r
+ }\r
+\r
+ Log("PHYSICALDRIVE%d size %llu bytes", PhyDrive, (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
+ return 1;\r
+ }\r
+\r
+ if (DevDescHeader.Size < sizeof(STORAGE_DEVICE_DESCRIPTOR))\r
+ {\r
+ Log("Invalid DevDescHeader.Size:%u", DevDescHeader.Size);\r
+ return 1;\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
+ return 1;\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
+ return 1;\r
+ }\r
+\r
+ pInfo->PhyDrive = PhyDrive;\r
+ pInfo->SizeInBytes = LengthInfo.Length.QuadPart;\r
+ pInfo->DeviceType = pDevDesc->DeviceType;\r
+ pInfo->RemovableMedia = pDevDesc->RemovableMedia;\r
+ pInfo->BusType = pDevDesc->BusType;\r
+\r
+ if (pDevDesc->VendorIdOffset)\r
+ {\r
+ safe_strcpy(pInfo->VendorId, (char*)pDevDesc + pDevDesc->VendorIdOffset);\r
+ TrimString(pInfo->VendorId);\r
+ }\r
+\r
+ if (pDevDesc->ProductIdOffset)\r
+ {\r
+ safe_strcpy(pInfo->ProductId, (char*)pDevDesc + pDevDesc->ProductIdOffset);\r
+ TrimString(pInfo->ProductId);\r
+ }\r
+\r
+ if (pDevDesc->ProductRevisionOffset)\r
+ {\r
+ safe_strcpy(pInfo->ProductRev, (char*)pDevDesc + pDevDesc->ProductRevisionOffset);\r
+ TrimString(pInfo->ProductRev);\r
+ }\r
+\r
+ if (pDevDesc->SerialNumberOffset)\r
+ {\r
+ safe_strcpy(pInfo->SerialNumber, (char*)pDevDesc + pDevDesc->SerialNumberOffset);\r
+ TrimString(pInfo->SerialNumber);\r
+ }\r
+\r
+ free(pDevDesc);\r
+\r
+ CHECK_CLOSE_HANDLE(Handle);\r
+\r
+ return 0;\r
+}\r
+\r
+static int CLI_CheckParam(int argc, char** argv, PHY_DRIVE_INFO* pDrvInfo, CLI_CFG *pCfg)\r
+{\r
+ int i;\r
+ int op = -1;\r
+ char* opt = NULL;\r
+ int PhyDrive = -1;\r
+ int PartStyle = 0;\r
+ int ReserveMB = 0;\r
+ BOOL USBCheck = TRUE;\r
+ MBR_HEAD MBR;\r
+ UINT64 Part2GPTAttr = 0;\r
+ UINT64 Part2StartSector = 0;\r
+\r
+ for (i = 0; i < argc; i++)\r
+ {\r
+ opt = argv[i];\r
+ if (_stricmp(opt, "/I") == 0)\r
+ {\r
+ op = 0;\r
+ }\r
+ else if (_stricmp(opt, "/U") == 0)\r
+ {\r
+ op = 1;\r
+ }\r
+ else if (_stricmp(opt, "/GPT") == 0)\r
+ {\r
+ PartStyle = 1;\r
+ }\r
+ else if (_stricmp(opt, "/NoSB") == 0)\r
+ {\r
+ g_SecureBoot = FALSE;\r
+ }\r
+ else if (_stricmp(opt, "/NoUSBCheck") == 0)\r
+ {\r
+ USBCheck = FALSE;\r
+ }\r
+ else if (_strnicmp(opt, "/Drive:", 7) == 0)\r
+ {\r
+ Log("Get PhyDrive by logical drive %C:", opt[7]);\r
+ PhyDrive = GetPhyDriveByLogicalDrive(opt[7], NULL); \r
+ }\r
+ else if (_strnicmp(opt, "/PhyDrive:", 10) == 0)\r
+ {\r
+ PhyDrive = (int)strtol(opt + 10, NULL, 10);\r
+ }\r
+ else if (_strnicmp(opt, "/R:", 3) == 0)\r
+ {\r
+ ReserveMB = (int)strtol(opt + 3, NULL, 10);\r
+ }\r
+ }\r
+\r
+ if (op < 0 || PhyDrive < 0)\r
+ {\r
+ Log("[ERROR] Invalid parameters %d %d", op, PhyDrive);\r
+ return 1;\r
+ }\r
+\r
+ Log("Ventoy CLI %s PhyDrive:%d %s SecureBoot:%d ReserveSpace:%dMB USBCheck:%u",\r
+ op == 0 ? "install" : "update",\r
+ PhyDrive, PartStyle ? "GPT" : "MBR",\r
+ g_SecureBoot, ReserveMB, USBCheck\r
+ );\r
+\r
+ if (CLI_GetPhyDriveInfo(PhyDrive, pDrvInfo))\r
+ {\r
+ Log("[ERROR] Failed to get phydrive%d info", PhyDrive);\r
+ return 1;\r
+ }\r
+\r
+ Log("PhyDrive:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",\r
+ pDrvInfo->PhyDrive, GetBusTypeString(pDrvInfo->BusType), pDrvInfo->RemovableMedia,\r
+ GetHumanReadableGBSize(pDrvInfo->SizeInBytes), pDrvInfo->SizeInBytes,\r
+ pDrvInfo->VendorId, pDrvInfo->ProductId);\r
+\r
+ if (IsVentoyPhyDrive(PhyDrive, pDrvInfo->SizeInBytes, &MBR, &Part2StartSector, &Part2GPTAttr))\r
+ {\r
+ memcpy(&(pDrvInfo->MBR), &MBR, sizeof(MBR));\r
+ pDrvInfo->PartStyle = (MBR.PartTbl[0].FsFlag == 0xEE) ? 1 : 0;\r
+ pDrvInfo->Part2GPTAttr = Part2GPTAttr;\r
+ GetVentoyVerInPhyDrive(pDrvInfo, Part2StartSector, pDrvInfo->VentoyVersion, sizeof(pDrvInfo->VentoyVersion), &(pDrvInfo->SecureBootSupport));\r
+ Log("PhyDrive %d is Ventoy Disk ver:%s SecureBoot:%u", pDrvInfo->PhyDrive, pDrvInfo->VentoyVersion, pDrvInfo->SecureBootSupport);\r
+\r
+ GetVentoyFsNameInPhyDrive(pDrvInfo);\r
+\r
+ if (pDrvInfo->VentoyVersion[0] == 0)\r
+ {\r
+ pDrvInfo->VentoyVersion[0] = '?';\r
+ Log("Unknown Ventoy Version");\r
+ }\r
+ }\r
+\r
+ pCfg->op = op;\r
+ pCfg->PartStyle = PartStyle;\r
+ pCfg->ReserveMB = ReserveMB;\r
+ pCfg->USBCheck = USBCheck;\r
+\r
+ return 0;\r
+}\r
+\r
+static int Ventoy_CLI_Install(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG *pCfg)\r
+{\r
+ int rc; \r
+ int TryId = 1; \r
+\r
+ Log("Ventoy_CLI_Install start ...");\r
+ \r
+ if (pCfg->ReserveMB > 0)\r
+ {\r
+ CLISetReserveSpace(pCfg->ReserveMB);\r
+ }\r
+\r
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);\r
+ if (rc)\r
+ {\r
+ Log("This time install failed, clean disk by disk, wait 3s and retry...");\r
+ DISK_CleanDisk(pDrvInfo->PhyDrive);\r
+\r
+ Sleep(3000);\r
+\r
+ Log("Now retry to install...");\r
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);\r
+\r
+ if (rc)\r
+ {\r
+ Log("This time install failed, clean disk by diskpart, wait 5s and retry...");\r
+ DSPT_CleanDisk(pDrvInfo->PhyDrive);\r
+\r
+ Sleep(5000);\r
+\r
+ Log("Now retry to install...");\r
+ rc = InstallVentoy2PhyDrive(pDrvInfo, pCfg->PartStyle, TryId++);\r
+ }\r
+ }\r
+\r
+ Log("Ventoy_CLI_Install [%s]", rc == 0 ? "SUCCESS" : "FAILED");\r
+\r
+ return rc;\r
+}\r
+\r
+static int Ventoy_CLI_Update(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG* pCfg)\r
+{\r
+ int rc; \r
+ int TryId = 1;\r
+ \r
+ Log("Ventoy_CLI_Update start ...");\r
+\r
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);\r
+ if (rc)\r
+ {\r
+ Log("This time update failed, now wait and retry...");\r
+ Sleep(4000);\r
+\r
+ //Try2\r
+ Log("Now retry to update...");\r
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);\r
+ if (rc)\r
+ {\r
+ //Try3\r
+ Sleep(1000);\r
+ Log("Now retry to update...");\r
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);\r
+ if (rc)\r
+ {\r
+ //Try4 is dangerous ...\r
+ Sleep(3000);\r
+ Log("Now retry to update...");\r
+ rc = UpdateVentoy2PhyDrive(pDrvInfo, TryId++);\r
+ }\r
+ }\r
+ }\r
+\r
+ Log("Ventoy_CLI_Update [%s]", rc == 0 ? "SUCCESS" : "FAILED");\r
+\r
+ return rc;\r
+}\r
+\r
+void CLI_UpdatePercent(int Pos)\r
+{\r
+ int Len;\r
+ FILE* File = NULL;\r
+ CHAR szBuf[128];\r
+\r
+ Len = (int)sprintf_s(szBuf, sizeof(szBuf), "%d", Pos * 100 / PT_FINISH);\r
+ fopen_s(&File, VENTOY_CLI_PERCENT, "w+");\r
+ if (File)\r
+ {\r
+ fwrite(szBuf, 1, Len, File);\r
+ fwrite("\n", 1, 1, File);\r
+ fclose(File);\r
+ }\r
+}\r
+\r
+static void CLI_WriteDoneFile(int ret)\r
+{\r
+ FILE* File = NULL;\r
+\r
+ fopen_s(&File, VENTOY_CLI_DONE, "w+");\r
+ if (File)\r
+ {\r
+ if (ret == 0)\r
+ {\r
+ fwrite("0\n", 1, 2, File);\r
+ }\r
+ else\r
+ {\r
+ fwrite("1\n", 1, 2, File);\r
+ }\r
+ fclose(File);\r
+ }\r
+}\r
+\r
+/*\r
+ * Ventoy2Disk.exe VTOYCLI { /I | /U } { /Drive:F: | /PhyDrive:1 } /GPT /NoSB /R:4096 /NoUSBCheck\r
+ * \r
+ */\r
+int VentoyCLIMain(int argc, char** argv)\r
+{\r
+ int ret = 1;\r
+ PHY_DRIVE_INFO* pDrvInfo = NULL;\r
+ CLI_CFG CliCfg;\r
+\r
+ DeleteFileA(VENTOY_CLI_PERCENT);\r
+ DeleteFileA(VENTOY_CLI_DONE);\r
+\r
+ pDrvInfo = (PHY_DRIVE_INFO*)malloc(sizeof(PHY_DRIVE_INFO));\r
+ if (!pDrvInfo)\r
+ {\r
+ goto end;\r
+ }\r
+ memset(pDrvInfo, 0, sizeof(PHY_DRIVE_INFO));\r
+\r
+ if (CLI_CheckParam(argc, argv, pDrvInfo, &CliCfg))\r
+ {\r
+ goto end;\r
+ }\r
+\r
+ //Check USB type for install\r
+ if (CliCfg.op == 0 && CliCfg.USBCheck)\r
+ {\r
+ if (pDrvInfo->BusType != BusTypeUsb)\r
+ {\r
+ Log("[ERROR] PhyDrive %d is NOT USB type", pDrvInfo->PhyDrive);\r
+ goto end;\r
+ }\r
+ }\r
+\r
+ if (CliCfg.op == 0)\r
+ {\r
+ ret = Ventoy_CLI_Install(pDrvInfo, &CliCfg);\r
+ }\r
+ else\r
+ {\r
+ if (pDrvInfo->VentoyVersion[0] == 0)\r
+ {\r
+ Log("[ERROR] No Ventoy information detected in PhyDrive %d, so can not do update", pDrvInfo->PhyDrive);\r
+ goto end;\r
+ }\r
+\r
+ ret = Ventoy_CLI_Update(pDrvInfo, &CliCfg);\r
+ }\r
+\r
+end:\r
+ CHECK_FREE(pDrvInfo);\r
+\r
+ CLI_UpdatePercent(PT_FINISH);\r
+ CLI_WriteDoneFile(ret);\r
+\r
+ return ret;\r
+}\r