1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 3 of the
9 * License, or (at your option) any later version.
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, see <http://www.gnu.org/licenses/>.
21 #include "Ventoy2Disk.h"
23 void Log(const char *Fmt
, ...)
32 Len
+= safe_sprintf(szBuf
,
33 "[%4d/%02d/%02d %02d:%02d:%02d.%03d] ",
34 Sys
.wYear
, Sys
.wMonth
, Sys
.wDay
,
35 Sys
.wHour
, Sys
.wMinute
, Sys
.wSecond
,
39 Len
+= vsnprintf_s(szBuf
+ Len
, sizeof(szBuf
)-Len
, sizeof(szBuf
)-Len
, Fmt
, Arg
);
42 //printf("%s\n", szBuf);
45 fopen_s(&File
, VENTOY_FILE_LOG
, "a+");
48 fwrite(szBuf
, 1, Len
, File
);
49 fwrite("\n", 1, 1, File
);
56 BOOL
IsPathExist(BOOL Dir
, const char *Fmt
, ...)
61 CHAR FilePath
[MAX_PATH
];
64 vsnprintf_s(FilePath
, sizeof(FilePath
), sizeof(FilePath
), Fmt
, Arg
);
67 hFile
= CreateFileA(FilePath
, FILE_READ_EA
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, 0, 0);
68 if (INVALID_HANDLE_VALUE
== hFile
)
75 Attr
= GetFileAttributesA(FilePath
);
79 if ((Attr
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
86 if (Attr
& FILE_ATTRIBUTE_DIRECTORY
)
96 int ReadWholeFileToBuf(const CHAR
*FileName
, int ExtLen
, void **Bufer
, int *BufLen
)
102 fopen_s(&File
, FileName
, "rb");
105 Log("Failed to open file %s", FileName
);
109 fseek(File
, 0, SEEK_END
);
110 FileSize
= (int)ftell(File
);
112 Data
= malloc(FileSize
+ ExtLen
);
119 fseek(File
, 0, SEEK_SET
);
120 fread(Data
, 1, FileSize
, File
);
130 const CHAR
* GetLocalVentoyVersion(void)
136 static CHAR LocalVersion
[64] = { 0 };
138 if (LocalVersion
[0] == 0)
140 rc
= ReadWholeFileToBuf(VENTOY_FILE_VERSION
, 1, (void **)&Buf
, &FileSize
);
147 for (Pos
= Buf
; *Pos
; Pos
++)
149 if (*Pos
== '\r' || *Pos
== '\n')
156 safe_sprintf(LocalVersion
, "%s", Buf
);
163 const CHAR
* ParseVentoyVersionFromString(CHAR
*Buf
)
167 static CHAR LocalVersion
[64] = { 0 };
169 Pos
= strstr(Buf
, "VENTOY_VERSION=");
172 Pos
+= strlen("VENTOY_VERSION=");
179 while (*End
!= 0 && *End
!= '"' && *End
!= '\r' && *End
!= '\n')
186 safe_sprintf(LocalVersion
, "%s", Pos
);
195 typedef BOOL(WINAPI
*LPFN_ISWOW64PROCESS
)(HANDLE
, PBOOL
);
196 LPFN_ISWOW64PROCESS fnIsWow64Process
;
197 BOOL bIsWow64
= FALSE
;
199 fnIsWow64Process
= (LPFN_ISWOW64PROCESS
)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
200 if (NULL
!= fnIsWow64Process
)
202 fnIsWow64Process(GetCurrentProcess(), &bIsWow64
);
208 void DumpWindowsVersion(void)
213 ULONGLONG MajorEqual
, MinorEqual
;
214 OSVERSIONINFOEXA Ver1
, Ver2
;
215 const CHAR
*Ver
= NULL
;
216 CHAR WinVer
[256] = { 0 };
218 memset(&Ver1
, 0, sizeof(Ver1
));
219 memset(&Ver2
, 0, sizeof(Ver2
));
221 Ver1
.dwOSVersionInfoSize
= sizeof(Ver1
);
223 // suppress the C4996 warning for GetVersionExA
224 #pragma warning(push)
225 #pragma warning(disable:4996)
226 if (!GetVersionExA((OSVERSIONINFOA
*)&Ver1
))
228 memset(&Ver1
, 0, sizeof(Ver1
));
229 Ver1
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
230 if (!GetVersionExA((OSVERSIONINFOA
*)&Ver1
))
237 if (Ver1
.dwPlatformId
== VER_PLATFORM_WIN32_NT
)
239 if (Ver1
.dwMajorVersion
> 6 || (Ver1
.dwMajorVersion
== 6 && Ver1
.dwMinorVersion
>= 2))
241 // GetVersionEx() has problem on some Windows version
243 MajorEqual
= VerSetConditionMask(0, VER_MAJORVERSION
, VER_EQUAL
);
244 for (Major
= Ver1
.dwMajorVersion
; Major
<= 9; Major
++)
246 memset(&Ver2
, 0, sizeof(Ver2
));
247 Ver2
.dwOSVersionInfoSize
= sizeof(Ver2
);
248 Ver2
.dwMajorVersion
= Major
;
250 if (!VerifyVersionInfoA(&Ver2
, VER_MAJORVERSION
, MajorEqual
))
255 if (Ver1
.dwMajorVersion
< Major
)
257 Ver1
.dwMajorVersion
= Major
;
258 Ver1
.dwMinorVersion
= 0;
261 MinorEqual
= VerSetConditionMask(0, VER_MINORVERSION
, VER_EQUAL
);
262 for (Minor
= Ver1
.dwMinorVersion
; Minor
<= 9; Minor
++)
264 memset(&Ver2
, 0, sizeof(Ver2
));
266 Ver2
.dwOSVersionInfoSize
= sizeof(Ver2
);
267 Ver2
.dwMinorVersion
= Minor
;
269 if (!VerifyVersionInfoA(&Ver2
, VER_MINORVERSION
, MinorEqual
))
274 Ver1
.dwMinorVersion
= Minor
;
282 if (Ver1
.dwMajorVersion
<= 0xF && Ver1
.dwMinorVersion
<= 0xF)
284 WsVer
= (Ver1
.wProductType
<= VER_NT_WORKSTATION
);
285 switch ((Ver1
.dwMajorVersion
<< 4) | Ver2
.dwMinorVersion
)
294 Ver
= GetSystemMetrics(89) ? "Server 2003 R2" : "Server 2003";
299 Ver
= WsVer
? "Vista" : "Server 2008";
304 Ver
= WsVer
? "7" : "Server 2008 R2";
309 Ver
= WsVer
? "8" : "Server 2012";
314 Ver
= WsVer
? "8.1" : "Server 2012 R2";
319 Ver
= WsVer
? "10 (Preview 1)" : "Server 10 (Preview 1)";
324 Ver
= WsVer
? "10" : ((Ver1
.dwBuildNumber
> 15000) ? "Server 2019" : "Server 2016");
336 Bit
= IsWow64() ? 64 : 32;
338 if (Ver1
.wServicePackMinor
)
340 safe_sprintf(WinVer
, "Windows %s SP%u.%u %d-bit", Ver
, Ver1
.wServicePackMajor
, Ver1
.wServicePackMinor
, Bit
);
342 else if (Ver1
.wServicePackMajor
)
344 safe_sprintf(WinVer
, "Windows %s SP%u %d-bit", Ver
, Ver1
.wServicePackMajor
, Bit
);
348 safe_sprintf(WinVer
, "Windows %s %d-bit", Ver
, Bit
);
351 if (((Ver1
.dwMajorVersion
<< 4) | Ver2
.dwMinorVersion
) >= 0x62)
353 Log("Windows Version : %s (Build %u)", WinVer
, Ver1
.dwBuildNumber
);
357 Log("Windows Version : %s", WinVer
);
363 BOOL
IsVentoyLogicalDrive(CHAR DriveLetter
)
366 CONST CHAR
*Files
[] =
368 "EFI\\BOOT\\BOOTX64.EFI",
369 "grub\\themes\\ventoy\\theme.txt",
370 "ventoy\\ventoy.cpio",
373 for (i
= 0; i
< sizeof(Files
) / sizeof(Files
[0]); i
++)
375 if (!IsFileExist("%C:\\%s", DriveLetter
, Files
[i
]))
385 static int VentoyFillLocation(UINT64 DiskSizeInBytes
, UINT32 StartSectorId
, UINT32 SectorCount
, PART_TABLE
*Table
)
394 while (nHead
!= 0 && (DiskSizeInBytes
/ 512 / nSector
/ nHead
) > 1024)
396 nHead
= (BYTE
)nHead
* 2;
404 Cylinder
= StartSectorId
/ nSector
/ nHead
;
405 Head
= StartSectorId
/ nSector
% nHead
;
406 Sector
= StartSectorId
% nSector
+ 1;
408 Table
->StartHead
= Head
;
409 Table
->StartSector
= Sector
;
410 Table
->StartCylinder
= Cylinder
;
412 EndSectorId
= StartSectorId
+ SectorCount
- 1;
413 Cylinder
= EndSectorId
/ nSector
/ nHead
;
414 Head
= EndSectorId
/ nSector
% nHead
;
415 Sector
= EndSectorId
% nSector
+ 1;
417 Table
->EndHead
= Head
;
418 Table
->EndSector
= Sector
;
419 Table
->EndCylinder
= Cylinder
;
421 Table
->StartSectorId
= StartSectorId
;
422 Table
->SectorCount
= SectorCount
;
427 int VentoyFillMBR(UINT64 DiskSizeBytes
, MBR_HEAD
*pMBR
)
430 UINT32 DiskSignature
;
431 UINT32 DiskSectorCount
;
432 UINT32 PartSectorCount
;
433 UINT32 PartStartSector
;
435 VentoyGetLocalBootImg(pMBR
);
439 memcpy(&DiskSignature
, &Guid
, sizeof(UINT32
));
441 Log("Disk signature: 0x%08x", DiskSignature
);
443 *((UINT32
*)(pMBR
->BootCode
+ 0x1B8)) = DiskSignature
;
445 DiskSectorCount
= (UINT32
)(DiskSizeBytes
/ 512);
448 PartStartSector
= VENTOY_PART1_START_SECTOR
;
449 PartSectorCount
= DiskSectorCount
- VENTOY_EFI_PART_SIZE
/ 512 - PartStartSector
;
450 VentoyFillLocation(DiskSizeBytes
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
);
452 pMBR
->PartTbl
[0].Active
= 0x00;
453 pMBR
->PartTbl
[0].FsFlag
= 0x07; // exFAT/NTFS/HPFS
456 PartStartSector
+= PartSectorCount
;
457 PartSectorCount
= VENTOY_EFI_PART_SIZE
/ 512;
458 VentoyFillLocation(DiskSizeBytes
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
+ 1);
460 pMBR
->PartTbl
[1].Active
= 0x80; // bootable
461 pMBR
->PartTbl
[1].FsFlag
= 0xEF; // EFI System Partition
469 CHAR
GetFirstUnusedDriveLetter(void)
472 DWORD Drives
= GetLogicalDrives();
484 const CHAR
* GetBusTypeString(STORAGE_BUS_TYPE Type
)
488 case BusTypeUnknown
: return "unknown";
489 case BusTypeScsi
: return "SCSI";
490 case BusTypeAtapi
: return "Atapi";
491 case BusTypeAta
: return "ATA";
492 case BusType1394
: return "1394";
493 case BusTypeSsa
: return "SSA";
494 case BusTypeFibre
: return "Fibre";
495 case BusTypeUsb
: return "USB";
496 case BusTypeRAID
: return "RAID";
497 case BusTypeiScsi
: return "iSCSI";
498 case BusTypeSas
: return "SAS";
499 case BusTypeSata
: return "SATA";
500 case BusTypeSd
: return "SD";
501 case BusTypeMmc
: return "MMC";
502 case BusTypeVirtual
: return "Virtual";
503 case BusTypeFileBackedVirtual
: return "FileBackedVirtual";
504 case BusTypeSpaces
: return "Spaces";
505 case BusTypeNvme
: return "Nvme";
510 int VentoyGetLocalBootImg(MBR_HEAD
*pMBR
)
514 static int Loaded
= 0;
519 memcpy(pMBR
, &MBR
, 512);
523 if (0 == ReadWholeFileToBuf(VENTOY_FILE_BOOT_IMG
, 0, (void **)&ImgBuf
, &Len
))
525 Log("Copy boot img success");
526 memcpy(pMBR
, ImgBuf
, 512);
529 CoCreateGuid((GUID
*)(pMBR
->BootCode
+ 0x180));
531 memcpy(&MBR
, pMBR
, 512);
538 Log("Copy boot img failed");
543 int GetHumanReadableGBSize(UINT64 SizeBytes
)
548 double GB
= SizeBytes
* 1.0 / 1000 / 1000 / 1000;
550 for (i
= 0; i
< 12; i
++)
554 Delta
= (Pow2
- GB
) / Pow2
;
558 Delta
= (GB
- Pow2
) / Pow2
;
572 void TrimString(CHAR
*String
)
576 size_t Len
= strlen(String
);
580 if (String
[Len
- 1] != ' ' && String
[Len
- 1] != '\t')
588 while (*Pos1
== ' ' || *Pos1
== '\t')
602 int GetRegDwordValue(HKEY Key
, LPCSTR SubKey
, LPCSTR ValueName
, DWORD
*pValue
)
610 lRet
= RegOpenKeyExA(Key
, SubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
611 Log("RegOpenKeyExA <%s> Ret:%ld", SubKey
, lRet
);
613 if (ERROR_SUCCESS
== lRet
)
615 Size
= sizeof(Value
);
616 lRet
= RegQueryValueExA(hKey
, ValueName
, NULL
, &Type
, (LPBYTE
)&Value
, &Size
);
617 Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName
, lRet
, Size
, Value
);
630 int GetPhysicalDriveCount(void)
635 if (GetRegDwordValue(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value
) == 0)
640 Log("GetPhysicalDriveCount: %d", Count
);