mirror of https://github.com/ventoy/Ventoy
You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
520 lines
14 KiB
C
520 lines
14 KiB
C
#include <Windows.h>
|
|
#include <Shlobj.h>
|
|
#include <tlhelp32.h>
|
|
#include <Psapi.h>
|
|
#include <commctrl.h>
|
|
#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;
|
|
BOOL NonDest;
|
|
int fstype;
|
|
}CLI_CFG;
|
|
|
|
BOOL g_CLI_Mode = FALSE;
|
|
static int g_CLI_OP;
|
|
static int g_CLI_PhyDrive;
|
|
|
|
static PHY_DRIVE_INFO* g_CLI_PhyDrvInfo = NULL;
|
|
|
|
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;
|
|
STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR diskAlignment;
|
|
|
|
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;
|
|
}
|
|
|
|
|
|
memset(&Query, 0, sizeof(STORAGE_PROPERTY_QUERY));
|
|
Query.PropertyId = StorageAccessAlignmentProperty;
|
|
Query.QueryType = PropertyStandardQuery;
|
|
memset(&diskAlignment, 0, sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR));
|
|
|
|
bRet = DeviceIoControl(Handle,
|
|
IOCTL_STORAGE_QUERY_PROPERTY,
|
|
&Query,
|
|
sizeof(STORAGE_PROPERTY_QUERY),
|
|
&diskAlignment,
|
|
sizeof(STORAGE_ACCESS_ALIGNMENT_DESCRIPTOR),
|
|
&dwBytes,
|
|
NULL);
|
|
if (!bRet)
|
|
{
|
|
Log("DeviceIoControl3 error:%u dwBytes:%u", LASTERR, dwBytes);
|
|
}
|
|
|
|
|
|
pInfo->PhyDrive = PhyDrive;
|
|
pInfo->SizeInBytes = LengthInfo.Length.QuadPart;
|
|
pInfo->DeviceType = pDevDesc->DeviceType;
|
|
pInfo->RemovableMedia = pDevDesc->RemovableMedia;
|
|
pInfo->BusType = pDevDesc->BusType;
|
|
|
|
pInfo->BytesPerLogicalSector = diskAlignment.BytesPerLogicalSector;
|
|
pInfo->BytesPerPhysicalSector = diskAlignment.BytesPerPhysicalSector;
|
|
|
|
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 fstype = VTOY_FS_EXFAT;
|
|
int op = -1;
|
|
char* opt = NULL;
|
|
int PhyDrive = -1;
|
|
int PartStyle = 0;
|
|
int ReserveMB = 0;
|
|
BOOL USBCheck = TRUE;
|
|
BOOL NonDest = FALSE;
|
|
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 (_stricmp(opt, "/NonDest") == 0)
|
|
{
|
|
NonDest = TRUE;
|
|
}
|
|
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);
|
|
}
|
|
else if (_strnicmp(opt, "/FS:", 4) == 0)
|
|
{
|
|
if (_stricmp(opt + 4, "NTFS") == 0)
|
|
{
|
|
fstype = VTOY_FS_NTFS;
|
|
}
|
|
else if (_stricmp(opt + 4, "FAT32") == 0)
|
|
{
|
|
fstype = VTOY_FS_FAT32;
|
|
}
|
|
}
|
|
}
|
|
|
|
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 FS:%s NonDest:%d",
|
|
op == 0 ? "install" : "update",
|
|
PhyDrive, PartStyle ? "GPT" : "MBR",
|
|
g_SecureBoot, ReserveMB, USBCheck, GetVentoyFsFmtNameByTypeA(fstype), NonDest
|
|
);
|
|
|
|
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");
|
|
}
|
|
}
|
|
|
|
if (op == 0 && NonDest)
|
|
{
|
|
GetLettersBelongPhyDrive(PhyDrive, pDrvInfo->DriveLetters, sizeof(pDrvInfo->DriveLetters));
|
|
}
|
|
|
|
pCfg->op = op;
|
|
pCfg->PartStyle = PartStyle;
|
|
pCfg->ReserveMB = ReserveMB;
|
|
pCfg->USBCheck = USBCheck;
|
|
pCfg->NonDest = NonDest;
|
|
pCfg->fstype = fstype;
|
|
|
|
return 0;
|
|
}
|
|
|
|
static int Ventoy_CLI_NonDestInstall(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG* pCfg)
|
|
{
|
|
int rc;
|
|
int TryId = 1;
|
|
|
|
Log("Ventoy_CLI_NonDestInstall start ...");
|
|
|
|
if (pDrvInfo->BytesPerLogicalSector == 4096 && pDrvInfo->BytesPerPhysicalSector == 4096)
|
|
{
|
|
Log("Ventoy does not support 4k native disk.");
|
|
rc = 1;
|
|
goto out;
|
|
}
|
|
|
|
if (!PartResizePreCheck(NULL))
|
|
{
|
|
Log("#### Part Resize PreCheck Failed ####");
|
|
rc = 1;
|
|
goto out;
|
|
}
|
|
|
|
rc = PartitionResizeForVentoy(pDrvInfo);
|
|
|
|
out:
|
|
Log("Ventoy_CLI_NonDestInstall [%s]", rc == 0 ? "SUCCESS" : "FAILED");
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
static int Ventoy_CLI_Install(PHY_DRIVE_INFO* pDrvInfo, CLI_CFG *pCfg)
|
|
{
|
|
int rc;
|
|
int TryId = 1;
|
|
|
|
Log("Ventoy_CLI_Install start ...");
|
|
|
|
if (pDrvInfo->BytesPerLogicalSector == 4096 && pDrvInfo->BytesPerPhysicalSector == 4096)
|
|
{
|
|
Log("Ventoy does not support 4k native disk.");
|
|
rc = 1;
|
|
goto out;
|
|
}
|
|
|
|
if (pCfg->ReserveMB > 0)
|
|
{
|
|
CLISetReserveSpace(pCfg->ReserveMB);
|
|
}
|
|
|
|
SetVentoyFsType(pCfg->fstype);
|
|
|
|
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++);
|
|
}
|
|
}
|
|
|
|
SetVentoyFsType(VTOY_FS_EXFAT);
|
|
|
|
out:
|
|
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);
|
|
}
|
|
}
|
|
|
|
PHY_DRIVE_INFO* CLI_PhyDrvInfo(void)
|
|
{
|
|
return g_CLI_PhyDrvInfo;
|
|
}
|
|
|
|
/*
|
|
* 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);
|
|
|
|
g_CLI_PhyDrvInfo = 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)
|
|
{
|
|
if (CliCfg.NonDest)
|
|
{
|
|
ret = Ventoy_CLI_NonDestInstall(pDrvInfo, &CliCfg);
|
|
}
|
|
else
|
|
{
|
|
AlertSuppressInit();
|
|
SetAlertPromptHookEnable(TRUE);
|
|
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;
|
|
}
|