1 /******************************************************************************
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 * Copyright (c) 2011-2020, Pete Batard <pete@akeo.ie>
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation; either version 3 of the
10 * License, or (at your option) any later version.
12 * This program is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, see <http://www.gnu.org/licenses/>.
22 #include "Ventoy2Disk.h"
24 void TraceOut(const char *Fmt
, ...)
32 Len
+= vsnprintf_s(szBuf
+ Len
, sizeof(szBuf
)-Len
, sizeof(szBuf
)-Len
, Fmt
, Arg
);
35 fopen_s(&File
, VENTOY_FILE_LOG
, "a+");
38 fwrite(szBuf
, 1, Len
, File
);
50 static BOOL g_LogCache
= FALSE
;
51 static LogBuf
* g_LogHead
= NULL
;
52 static LogBuf
* g_LogTail
= NULL
;
54 void LogCache(BOOL cache
)
67 fopen_s(&File
, VENTOY_CLI_LOG
, "a+");
71 fopen_s(&File
, VENTOY_FILE_LOG
, "a+");
76 for (Node
= g_LogHead
; Node
; Node
= Node
->next
)
78 fwrite(Node
->szBuf
, 1, Node
->Len
, File
);
79 fwrite("\n", 1, 1, File
);
84 for (Node
= g_LogHead
; Node
; Node
= Next
)
90 g_LogHead
= g_LogTail
= NULL
;
93 void Log(const char *Fmt
, ...)
102 Len
+= safe_sprintf(szBuf
,
103 "[%4d/%02d/%02d %02d:%02d:%02d.%03d] ",
104 Sys
.wYear
, Sys
.wMonth
, Sys
.wDay
,
105 Sys
.wHour
, Sys
.wMinute
, Sys
.wSecond
,
109 Len
+= vsnprintf_s(szBuf
+ Len
, sizeof(szBuf
)-Len
- 1, sizeof(szBuf
)-Len
-1, Fmt
, Arg
);
115 Node
= malloc(sizeof(LogBuf
));
118 memcpy(Node
->szBuf
, szBuf
, Len
);
124 g_LogTail
->next
= Node
;
129 g_LogHead
= g_LogTail
= Node
;
138 fopen_s(&File
, VENTOY_CLI_LOG
, "a+");
142 fopen_s(&File
, VENTOY_FILE_LOG
, "a+");
146 fwrite(szBuf
, 1, Len
, File
);
147 fwrite("\n", 1, 1, File
);
152 const char* GUID2String(void *guid
, char *buf
, int len
)
154 GUID
* pGUID
= (GUID
*)guid
;
155 sprintf_s(buf
, len
, "{%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x}",
156 pGUID
->Data1
, pGUID
->Data2
, pGUID
->Data3
,
157 pGUID
->Data4
[0], pGUID
->Data4
[1],
158 pGUID
->Data4
[2], pGUID
->Data4
[3], pGUID
->Data4
[4], pGUID
->Data4
[5], pGUID
->Data4
[6], pGUID
->Data4
[7]
163 BOOL
IsPathExist(BOOL Dir
, const char *Fmt
, ...)
168 CHAR FilePath
[MAX_PATH
];
171 vsnprintf_s(FilePath
, sizeof(FilePath
), sizeof(FilePath
), Fmt
, Arg
);
174 hFile
= CreateFileA(FilePath
, FILE_READ_EA
, FILE_SHARE_READ
, 0, OPEN_EXISTING
, 0, 0);
175 if (INVALID_HANDLE_VALUE
== hFile
)
182 Attr
= GetFileAttributesA(FilePath
);
186 if ((Attr
& FILE_ATTRIBUTE_DIRECTORY
) == 0)
193 if (Attr
& FILE_ATTRIBUTE_DIRECTORY
)
202 int SaveBufToFile(const CHAR
*FileName
, const void *Buffer
, int BufLen
)
207 fopen_s(&File
, FileName
, "wb");
210 Log("Failed to open file %s", FileName
);
214 fwrite(Buffer
, 1, BufLen
, File
);
219 int ReadWholeFileToBuf(const CHAR
*FileName
, int ExtLen
, void **Bufer
, int *BufLen
)
225 fopen_s(&File
, FileName
, "rb");
228 Log("Failed to open file %s", FileName
);
232 fseek(File
, 0, SEEK_END
);
233 FileSize
= (int)ftell(File
);
235 Data
= malloc(FileSize
+ ExtLen
);
242 fseek(File
, 0, SEEK_SET
);
243 fread(Data
, 1, FileSize
, File
);
253 const CHAR
* GetLocalVentoyVersion(void)
259 static CHAR LocalVersion
[64] = { 0 };
261 if (LocalVersion
[0] == 0)
263 rc
= ReadWholeFileToBuf(VENTOY_FILE_VERSION
, 1, (void **)&Buf
, &FileSize
);
270 for (Pos
= Buf
; *Pos
; Pos
++)
272 if (*Pos
== '\r' || *Pos
== '\n')
279 safe_sprintf(LocalVersion
, "%s", Buf
);
286 const CHAR
* ParseVentoyVersionFromString(CHAR
*Buf
)
290 static CHAR LocalVersion
[64] = { 0 };
292 Pos
= strstr(Buf
, "VENTOY_VERSION=");
295 Pos
+= strlen("VENTOY_VERSION=");
302 while (*End
!= 0 && *End
!= '"' && *End
!= '\r' && *End
!= '\n')
309 safe_sprintf(LocalVersion
, "%s", Pos
);
318 typedef BOOL(WINAPI
*LPFN_ISWOW64PROCESS
)(HANDLE
, PBOOL
);
319 LPFN_ISWOW64PROCESS fnIsWow64Process
;
320 BOOL bIsWow64
= FALSE
;
321 CHAR Wow64Dir
[MAX_PATH
];
323 fnIsWow64Process
= (LPFN_ISWOW64PROCESS
)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
324 if (NULL
!= fnIsWow64Process
)
326 fnIsWow64Process(GetCurrentProcess(), &bIsWow64
);
331 if (GetSystemWow64DirectoryA(Wow64Dir
, sizeof(Wow64Dir
)))
333 Log("GetSystemWow64DirectoryA=<%s>", Wow64Dir
);
342 * Some code and functions in the file are copied from rufus.
343 * https://github.com/pbatard/rufus
346 /* Windows versions */
347 enum WindowsVersion
{
348 WINDOWS_UNDEFINED
= -1,
349 WINDOWS_UNSUPPORTED
= 0,
351 WINDOWS_2003
= 0x52, // Also XP_64
352 WINDOWS_VISTA
= 0x60, // Also Server 2008
353 WINDOWS_7
= 0x61, // Also Server 2008_R2
354 WINDOWS_8
= 0x62, // Also Server 2012
355 WINDOWS_8_1
= 0x63, // Also Server 2012_R2
356 WINDOWS_10_PREVIEW1
= 0x64,
357 WINDOWS_10
= 0xA0, // Also Server 2016, also Server 2019
358 WINDOWS_11
= 0xB0, // Also Server 2022
362 static const char* GetEdition(DWORD ProductType
)
364 // From: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getproductinfo
365 // These values can be found in the winnt.h header.
366 switch (ProductType
) {
367 case 0x00000000: return ""; // Undefined
368 case 0x00000001: return "Ultimate";
369 case 0x00000002: return "Home Basic";
370 case 0x00000003: return "Home Premium";
371 case 0x00000004: return "Enterprise";
372 case 0x00000005: return "Home Basic N";
373 case 0x00000006: return "Business";
374 case 0x00000007: return "Server Standard";
375 case 0x00000008: return "Server Datacenter";
376 case 0x00000009: return "Smallbusiness Server";
377 case 0x0000000A: return "Server Enterprise";
378 case 0x0000000B: return "Starter";
379 case 0x0000000C: return "Server Datacenter (Core)";
380 case 0x0000000D: return "Server Standard (Core)";
381 case 0x0000000E: return "Server Enterprise (Core)";
382 case 0x00000010: return "Business N";
383 case 0x00000011: return "Web Server";
384 case 0x00000012: return "HPC Edition";
385 case 0x00000013: return "Storage Server (Essentials)";
386 case 0x0000001A: return "Home Premium N";
387 case 0x0000001B: return "Enterprise N";
388 case 0x0000001C: return "Ultimate N";
389 case 0x00000022: return "Home Server";
390 case 0x00000024: return "Server Standard without Hyper-V";
391 case 0x00000025: return "Server Datacenter without Hyper-V";
392 case 0x00000026: return "Server Enterprise without Hyper-V";
393 case 0x00000027: return "Server Datacenter without Hyper-V (Core)";
394 case 0x00000028: return "Server Standard without Hyper-V (Core)";
395 case 0x00000029: return "Server Enterprise without Hyper-V (Core)";
396 case 0x0000002A: return "Hyper-V Server";
397 case 0x0000002F: return "Starter N";
398 case 0x00000030: return "Pro";
399 case 0x00000031: return "Pro N";
400 case 0x00000034: return "Server Solutions Premium";
401 case 0x00000035: return "Server Solutions Premium (Core)";
402 case 0x00000040: return "Server Hyper Core V";
403 case 0x00000042: return "Starter E";
404 case 0x00000043: return "Home Basic E";
405 case 0x00000044: return "Premium E";
406 case 0x00000045: return "Pro E";
407 case 0x00000046: return "Enterprise E";
408 case 0x00000047: return "Ultimate E";
409 case 0x00000048: return "Enterprise (Eval)";
410 case 0x0000004F: return "Server Standard (Eval)";
411 case 0x00000050: return "Server Datacenter (Eval)";
412 case 0x00000054: return "Enterprise N (Eval)";
413 case 0x00000057: return "Thin PC";
414 case 0x00000058: case 0x00000059: case 0x0000005A: case 0x0000005B: case 0x0000005C: return "Embedded";
415 case 0x00000062: return "Home N";
416 case 0x00000063: return "Home China";
417 case 0x00000064: return "Home Single Language";
418 case 0x00000065: return "Home";
419 case 0x00000067: return "Pro with Media Center";
420 case 0x00000069: case 0x0000006A: case 0x0000006B: case 0x0000006C: return "Embedded";
421 case 0x0000006F: return "Home Connected";
422 case 0x00000070: return "Pro Student";
423 case 0x00000071: return "Home Connected N";
424 case 0x00000072: return "Pro Student N";
425 case 0x00000073: return "Home Connected Single Language";
426 case 0x00000074: return "Home Connected China";
427 case 0x00000079: return "Education";
428 case 0x0000007A: return "Education N";
429 case 0x0000007D: return "Enterprise LTSB";
430 case 0x0000007E: return "Enterprise LTSB N";
431 case 0x0000007F: return "Pro S";
432 case 0x00000080: return "Pro S N";
433 case 0x00000081: return "Enterprise LTSB (Eval)";
434 case 0x00000082: return "Enterprise LTSB N (Eval)";
435 case 0x0000008A: return "Pro Single Language";
436 case 0x0000008B: return "Pro China";
437 case 0x0000008C: return "Enterprise Subscription";
438 case 0x0000008D: return "Enterprise Subscription N";
439 case 0x00000091: return "Server Datacenter SA (Core)";
440 case 0x00000092: return "Server Standard SA (Core)";
441 case 0x00000095: return "Utility VM";
442 case 0x000000A1: return "Pro for Workstations";
443 case 0x000000A2: return "Pro for Workstations N";
444 case 0x000000A4: return "Pro for Education";
445 case 0x000000A5: return "Pro for Education N";
446 case 0x000000AB: return "Enterprise G"; // I swear Microsoft are just making up editions...
447 case 0x000000AC: return "Enterprise G N";
448 case 0x000000B6: return "Home OS";
449 case 0x000000B7: return "Cloud E";
450 case 0x000000B8: return "Cloud E N";
451 case 0x000000BD: return "Lite";
452 case 0xABCDABCD: return "(Unlicensed)";
453 default: return "(Unknown Edition)";
457 #define is_x64 IsWow64
458 #define static_strcpy safe_strcpy
459 #define REGKEY_HKCU HKEY_CURRENT_USER
460 #define REGKEY_HKLM HKEY_LOCAL_MACHINE
461 static int nWindowsVersion
= WINDOWS_UNDEFINED
;
462 static int nWindowsBuildNumber
= -1;
463 static char WindowsVersionStr
[128] = "";
465 /* Helpers for 32 bit registry operations */
468 * Read a generic registry key value. If a short key_name is used, assume that
469 * it belongs to the application and create the app subkey if required
471 static __inline BOOL
_GetRegistryKey(HKEY key_root
, const char* key_name
, DWORD reg_type
,
472 LPBYTE dest
, DWORD dest_size
)
474 const char software_prefix
[] = "SOFTWARE\\";
475 char long_key_name
[MAX_PATH
] = { 0 };
479 HKEY hSoftware
= NULL
, hApp
= NULL
;
480 DWORD dwType
= -1, dwSize
= dest_size
;
482 memset(dest
, 0, dest_size
);
484 if (key_name
== NULL
)
487 for (i
= strlen(key_name
); i
>0; i
--) {
488 if (key_name
[i
] == '\\')
493 // Prefix with "SOFTWARE" if needed
494 if (_strnicmp(key_name
, software_prefix
, sizeof(software_prefix
)-1) != 0) {
495 if (i
+ sizeof(software_prefix
) >= sizeof(long_key_name
))
497 strcpy_s(long_key_name
, sizeof(long_key_name
), software_prefix
);
498 strcat_s(long_key_name
, sizeof(long_key_name
), key_name
);
499 long_key_name
[sizeof(software_prefix
)+i
- 1] = 0;
502 if (i
>= sizeof(long_key_name
))
504 static_strcpy(long_key_name
, key_name
);
505 long_key_name
[i
] = 0;
508 if (RegOpenKeyExA(key_root
, long_key_name
, 0, KEY_READ
, &hApp
) != ERROR_SUCCESS
) {
514 if (RegOpenKeyExA(key_root
, "SOFTWARE", 0, KEY_READ
| KEY_CREATE_SUB_KEY
, &hSoftware
) != ERROR_SUCCESS
) {
520 s
= RegQueryValueExA(hApp
, &key_name
[i
], NULL
, &dwType
, (LPBYTE
)dest
, &dwSize
);
521 // No key means default value of 0 or empty string
522 if ((s
== ERROR_FILE_NOT_FOUND
) || ((s
== ERROR_SUCCESS
) && (dwType
== reg_type
) && (dwSize
> 0))) {
526 if (hSoftware
!= NULL
)
527 RegCloseKey(hSoftware
);
533 #define GetRegistryKey32(root, key, pval) _GetRegistryKey(root, key, REG_DWORD, (LPBYTE)pval, sizeof(DWORD))
534 static __inline INT32
ReadRegistryKey32(HKEY root
, const char* key
) {
536 GetRegistryKey32(root
, key
, &val
);
541 * Modified from smartmontools' os_win32.cpp
543 void GetWindowsVersion(void)
545 OSVERSIONINFOEXA vi
, vi2
;
548 const char* w64
= "32 bit";
551 unsigned major
, minor
;
552 ULONGLONG major_equal
, minor_equal
;
555 nWindowsVersion
= WINDOWS_UNDEFINED
;
556 static_strcpy(WindowsVersionStr
, "Windows Undefined");
558 // suppress the C4996 warning for GetVersionExA
559 #pragma warning(push)
560 #pragma warning(disable:4996)
562 memset(&vi
, 0, sizeof(vi
));
563 vi
.dwOSVersionInfoSize
= sizeof(vi
);
564 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
)) {
565 memset(&vi
, 0, sizeof(vi
));
566 vi
.dwOSVersionInfoSize
= sizeof(OSVERSIONINFOA
);
567 if (!GetVersionExA((OSVERSIONINFOA
*)&vi
))
573 if (vi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
) {
575 if (vi
.dwMajorVersion
> 6 || (vi
.dwMajorVersion
== 6 && vi
.dwMinorVersion
>= 2)) {
576 // Starting with Windows 8.1 Preview, GetVersionEx() does no longer report the actual OS version
577 // See: http://msdn.microsoft.com/en-us/library/windows/desktop/dn302074.aspx
578 // And starting with Windows 10 Preview 2, Windows enforces the use of the application/supportedOS
579 // manifest in order for VerSetConditionMask() to report the ACTUAL OS major and minor...
581 major_equal
= VerSetConditionMask(0, VER_MAJORVERSION
, VER_EQUAL
);
582 for (major
= vi
.dwMajorVersion
; major
<= 9; major
++) {
583 memset(&vi2
, 0, sizeof(vi2
));
584 vi2
.dwOSVersionInfoSize
= sizeof(vi2
); vi2
.dwMajorVersion
= major
;
585 if (!VerifyVersionInfoA(&vi2
, VER_MAJORVERSION
, major_equal
))
587 if (vi
.dwMajorVersion
< major
) {
588 vi
.dwMajorVersion
= major
; vi
.dwMinorVersion
= 0;
591 minor_equal
= VerSetConditionMask(0, VER_MINORVERSION
, VER_EQUAL
);
592 for (minor
= vi
.dwMinorVersion
; minor
<= 9; minor
++) {
593 memset(&vi2
, 0, sizeof(vi2
)); vi2
.dwOSVersionInfoSize
= sizeof(vi2
);
594 vi2
.dwMinorVersion
= minor
;
595 if (!VerifyVersionInfoA(&vi2
, VER_MINORVERSION
, minor_equal
))
597 vi
.dwMinorVersion
= minor
;
605 if (vi
.dwMajorVersion
<= 0xf && vi
.dwMinorVersion
<= 0xf) {
606 ws
= (vi
.wProductType
<= VER_NT_WORKSTATION
);
607 nWindowsVersion
= vi
.dwMajorVersion
<< 4 | vi
.dwMinorVersion
;
608 switch (nWindowsVersion
) {
609 case WINDOWS_XP
: w
= "XP";
611 case WINDOWS_2003
: w
= (ws
? "XP_64" : (!GetSystemMetrics(89) ? "Server 2003" : "Server 2003_R2"));
613 case WINDOWS_VISTA
: w
= (ws
? "Vista" : "Server 2008");
615 case WINDOWS_7
: w
= (ws
? "7" : "Server 2008_R2");
617 case WINDOWS_8
: w
= (ws
? "8" : "Server 2012");
619 case WINDOWS_8_1
: w
= (ws
? "8.1" : "Server 2012_R2");
621 case WINDOWS_10_PREVIEW1
: w
= (ws
? "10 (Preview 1)" : "Server 10 (Preview 1)");
623 // Starting with Windows 10 Preview 2, the major is the same as the public-facing version
625 if (vi
.dwBuildNumber
< 20000) {
626 w
= (ws
? "10" : ((vi
.dwBuildNumber
< 17763) ? "Server 2016" : "Server 2019"));
629 nWindowsVersion
= WINDOWS_11
;
631 case WINDOWS_11
: w
= (ws
? "11" : "Server 2022");
634 if (nWindowsVersion
< WINDOWS_XP
)
635 nWindowsVersion
= WINDOWS_UNSUPPORTED
;
646 GetProductInfo(vi
.dwMajorVersion
, vi
.dwMinorVersion
, vi
.wServicePackMajor
, vi
.wServicePackMinor
, &dwProductType
);
647 vptr
= WindowsVersionStr
;
648 vlen
= sizeof(WindowsVersionStr
) - 1;
651 sprintf_s(vptr
, vlen
, "%s %u.%u %s", (vi
.dwPlatformId
== VER_PLATFORM_WIN32_NT
? "NT" : "??"),
652 (unsigned)vi
.dwMajorVersion
, (unsigned)vi
.dwMinorVersion
, w64
);
653 else if (vi
.wServicePackMinor
)
654 sprintf_s(vptr
, vlen
, "%s SP%u.%u %s", w
, vi
.wServicePackMajor
, vi
.wServicePackMinor
, w64
);
655 else if (vi
.wServicePackMajor
)
656 sprintf_s(vptr
, vlen
, "%s SP%u %s", w
, vi
.wServicePackMajor
, w64
);
658 sprintf_s(vptr
, vlen
, "%s%s%s, %s",
659 w
, (dwProductType
!= PRODUCT_UNDEFINED
) ? " " : "", GetEdition(dwProductType
), w64
);
661 // Add the build number (including UBR if available) for Windows 8.0 and later
662 nWindowsBuildNumber
= vi
.dwBuildNumber
;
663 if (nWindowsVersion
>= 0x62) {
664 int nUbr
= ReadRegistryKey32(REGKEY_HKLM
, "Software\\Microsoft\\Windows NT\\CurrentVersion\\UBR");
665 vptr
= WindowsVersionStr
+ strlen(WindowsVersionStr
);
666 vlen
= sizeof(WindowsVersionStr
) - strlen(WindowsVersionStr
) - 1;
668 sprintf_s(vptr
, vlen
, " (Build %d.%d)", nWindowsBuildNumber
, nUbr
);
670 sprintf_s(vptr
, vlen
, " (Build %d)", nWindowsBuildNumber
);
676 void DumpWindowsVersion(void)
679 Log("Windows Version: <<Windows %s>>", WindowsVersionStr
);
684 BOOL
IsVentoyLogicalDrive(CHAR DriveLetter
)
687 CONST CHAR
*Files
[] =
689 "EFI\\BOOT\\BOOTX64.EFI",
690 "grub\\themes\\ventoy\\theme.txt",
691 "ventoy\\ventoy.cpio",
694 for (i
= 0; i
< sizeof(Files
) / sizeof(Files
[0]); i
++)
696 if (!IsFileExist("%C:\\%s", DriveLetter
, Files
[i
]))
706 int VentoyFillMBRLocation(UINT64 DiskSizeInBytes
, UINT32 StartSectorId
, UINT32 SectorCount
, PART_TABLE
*Table
)
715 while (nHead
!= 0 && (DiskSizeInBytes
/ 512 / nSector
/ nHead
) > 1024)
717 nHead
= (BYTE
)nHead
* 2;
725 Cylinder
= StartSectorId
/ nSector
/ nHead
;
726 Head
= StartSectorId
/ nSector
% nHead
;
727 Sector
= StartSectorId
% nSector
+ 1;
729 Table
->StartHead
= Head
;
730 Table
->StartSector
= Sector
;
731 Table
->StartCylinder
= Cylinder
;
733 EndSectorId
= StartSectorId
+ SectorCount
- 1;
734 Cylinder
= EndSectorId
/ nSector
/ nHead
;
735 Head
= EndSectorId
/ nSector
% nHead
;
736 Sector
= EndSectorId
% nSector
+ 1;
738 Table
->EndHead
= Head
;
739 Table
->EndSector
= Sector
;
740 Table
->EndCylinder
= Cylinder
;
742 Table
->StartSectorId
= StartSectorId
;
743 Table
->SectorCount
= SectorCount
;
748 int VentoyFillMBR(UINT64 DiskSizeBytes
, MBR_HEAD
*pMBR
, int PartStyle
, UINT8 FsFlag
)
752 UINT32 DiskSignature
;
753 UINT32 DiskSectorCount
;
754 UINT32 PartSectorCount
;
755 UINT32 PartStartSector
;
756 UINT32 ReservedSector
;
758 VentoyGetLocalBootImg(pMBR
);
762 memcpy(&DiskSignature
, &Guid
, sizeof(UINT32
));
764 Log("Disk signature: 0x%08x", DiskSignature
);
766 *((UINT32
*)(pMBR
->BootCode
+ 0x1B8)) = DiskSignature
;
767 memcpy(pMBR
->BootCode
+ 0x180, &Guid
, 16);
769 if (DiskSizeBytes
/ 512 > 0xFFFFFFFF)
771 DiskSectorCount
= 0xFFFFFFFF;
775 DiskSectorCount
= (UINT32
)(DiskSizeBytes
/ 512);
778 ReservedValue
= GetReservedSpaceInMB();
779 if (ReservedValue
<= 0)
785 ReservedSector
= (UINT32
)(ReservedValue
* 2048);
790 ReservedSector
+= 33; // backup GPT part table
793 // check aligned with 4KB
794 if (IsPartNeed4KBAlign())
796 UINT64 sectors
= DiskSizeBytes
/ 512;
799 Log("Disk need to align with 4KB %u", (UINT32
)(sectors
% 8));
800 ReservedSector
+= (UINT32
)(sectors
% 8);
804 Log("ReservedSector: %u", ReservedSector
);
807 PartStartSector
= VENTOY_PART1_START_SECTOR
;
808 PartSectorCount
= DiskSectorCount
- ReservedSector
- VENTOY_EFI_PART_SIZE
/ 512 - PartStartSector
;
809 VentoyFillMBRLocation(DiskSizeBytes
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
);
811 pMBR
->PartTbl
[0].Active
= 0x80; // bootable
812 pMBR
->PartTbl
[0].FsFlag
= FsFlag
; // File system flag 07:exFAT/NTFS/HPFS 0C:FAT32
815 PartStartSector
+= PartSectorCount
;
816 PartSectorCount
= VENTOY_EFI_PART_SIZE
/ 512;
817 VentoyFillMBRLocation(DiskSizeBytes
, PartStartSector
, PartSectorCount
, pMBR
->PartTbl
+ 1);
819 pMBR
->PartTbl
[1].Active
= 0x00;
820 pMBR
->PartTbl
[1].FsFlag
= 0xEF; // EFI System Partition
829 static int VentoyFillProtectMBR(UINT64 DiskSizeBytes
, MBR_HEAD
*pMBR
)
832 UINT32 DiskSignature
;
833 UINT64 DiskSectorCount
;
835 VentoyGetLocalBootImg(pMBR
);
839 memcpy(&DiskSignature
, &Guid
, sizeof(UINT32
));
841 Log("Disk signature: 0x%08x", DiskSignature
);
843 *((UINT32
*)(pMBR
->BootCode
+ 0x1B8)) = DiskSignature
;
844 memcpy(pMBR
->BootCode
+ 0x180, &Guid
, 16);
846 DiskSectorCount
= DiskSizeBytes
/ 512 - 1;
847 if (DiskSectorCount
> 0xFFFFFFFF)
849 DiskSectorCount
= 0xFFFFFFFF;
852 memset(pMBR
->PartTbl
, 0, sizeof(pMBR
->PartTbl
));
854 pMBR
->PartTbl
[0].Active
= 0x00;
855 pMBR
->PartTbl
[0].FsFlag
= 0xee; // EE
857 pMBR
->PartTbl
[0].StartHead
= 0;
858 pMBR
->PartTbl
[0].StartSector
= 1;
859 pMBR
->PartTbl
[0].StartCylinder
= 0;
860 pMBR
->PartTbl
[0].EndHead
= 254;
861 pMBR
->PartTbl
[0].EndSector
= 63;
862 pMBR
->PartTbl
[0].EndCylinder
= 1023;
864 pMBR
->PartTbl
[0].StartSectorId
= 1;
865 pMBR
->PartTbl
[0].SectorCount
= (UINT32
)DiskSectorCount
;
870 pMBR
->BootCode
[92] = 0x22;
875 int VentoyFillWholeGpt(UINT64 DiskSizeBytes
, VTOY_GPT_INFO
*pInfo
)
877 UINT64 Part1SectorCount
= 0;
878 UINT64 DiskSectorCount
= DiskSizeBytes
/ 512;
879 VTOY_GPT_HDR
*Head
= &pInfo
->Head
;
880 VTOY_GPT_PART_TBL
*Table
= pInfo
->PartTbl
;
881 static GUID WindowsDataPartType
= { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
883 VentoyFillProtectMBR(DiskSizeBytes
, &pInfo
->MBR
);
885 Part1SectorCount
= DiskSectorCount
- 33 - 2048;
887 memcpy(Head
->Signature
, "EFI PART", 8);
888 Head
->Version
[2] = 0x01;
891 Head
->EfiStartLBA
= 1;
892 Head
->EfiBackupLBA
= DiskSectorCount
- 1;
893 Head
->PartAreaStartLBA
= 34;
894 Head
->PartAreaEndLBA
= DiskSectorCount
- 34;
895 CoCreateGuid(&Head
->DiskGuid
);
896 Head
->PartTblStartLBA
= 2;
897 Head
->PartTblTotNum
= 128;
898 Head
->PartTblEntryLen
= 128;
901 memcpy(&(Table
[0].PartType
), &WindowsDataPartType
, sizeof(GUID
));
902 CoCreateGuid(&(Table
[0].PartGuid
));
903 Table
[0].StartLBA
= 2048;
904 Table
[0].LastLBA
= 2048 + Part1SectorCount
- 1;
906 memcpy(Table
[0].Name
, L
"Data", 4 * 2);
909 Head
->PartTblCrc
= VentoyCrc32(Table
, sizeof(pInfo
->PartTbl
));
910 Head
->Crc
= VentoyCrc32(Head
, Head
->Length
);
915 int VentoyFillGpt(UINT64 DiskSizeBytes
, VTOY_GPT_INFO
*pInfo
)
917 INT64 ReservedValue
= 0;
918 UINT64 ModSectorCount
= 0;
919 UINT64 ReservedSector
= 33;
920 UINT64 Part1SectorCount
= 0;
921 UINT64 DiskSectorCount
= DiskSizeBytes
/ 512;
922 VTOY_GPT_HDR
*Head
= &pInfo
->Head
;
923 VTOY_GPT_PART_TBL
*Table
= pInfo
->PartTbl
;
924 static GUID WindowsDataPartType
= { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
925 static GUID EspPartType
= { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
926 static GUID BiosGrubPartType
= { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };
928 VentoyFillProtectMBR(DiskSizeBytes
, &pInfo
->MBR
);
930 ReservedValue
= GetReservedSpaceInMB();
931 if (ReservedValue
> 0)
933 ReservedSector
+= ReservedValue
* 2048;
936 Part1SectorCount
= DiskSectorCount
- ReservedSector
- (VENTOY_EFI_PART_SIZE
/ 512) - 2048;
938 ModSectorCount
= (Part1SectorCount
% 8);
941 Log("Part1SectorCount:%llu is not aligned by 4KB (%llu)", (ULONGLONG
)Part1SectorCount
, (ULONGLONG
)ModSectorCount
);
944 // check aligned with 4KB
945 if (IsPartNeed4KBAlign())
949 Log("Disk need to align with 4KB %u", (UINT32
)ModSectorCount
);
950 Part1SectorCount
-= ModSectorCount
;
954 Log("no need to align with 4KB");
958 memcpy(Head
->Signature
, "EFI PART", 8);
959 Head
->Version
[2] = 0x01;
962 Head
->EfiStartLBA
= 1;
963 Head
->EfiBackupLBA
= DiskSectorCount
- 1;
964 Head
->PartAreaStartLBA
= 34;
965 Head
->PartAreaEndLBA
= DiskSectorCount
- 34;
966 CoCreateGuid(&Head
->DiskGuid
);
967 Head
->PartTblStartLBA
= 2;
968 Head
->PartTblTotNum
= 128;
969 Head
->PartTblEntryLen
= 128;
972 memcpy(&(Table
[0].PartType
), &WindowsDataPartType
, sizeof(GUID
));
973 CoCreateGuid(&(Table
[0].PartGuid
));
974 Table
[0].StartLBA
= 2048;
975 Table
[0].LastLBA
= 2048 + Part1SectorCount
- 1;
977 memcpy(Table
[0].Name
, L
"Ventoy", 6 * 2);
979 // to fix windows issue
980 //memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));
981 memcpy(&(Table
[1].PartType
), &WindowsDataPartType
, sizeof(GUID
));
982 CoCreateGuid(&(Table
[1].PartGuid
));
983 Table
[1].StartLBA
= Table
[0].LastLBA
+ 1;
984 Table
[1].LastLBA
= Table
[1].StartLBA
+ VENTOY_EFI_PART_SIZE
/ 512 - 1;
985 Table
[1].Attr
= VENTOY_EFI_PART_ATTR
;
986 memcpy(Table
[1].Name
, L
"VTOYEFI", 7 * 2);
989 memcpy(&(Table
[2].PartType
), &BiosGrubPartType
, sizeof(GUID
));
990 CoCreateGuid(&(Table
[2].PartGuid
));
991 Table
[2].StartLBA
= 34;
992 Table
[2].LastLBA
= 2047;
997 Head
->PartTblCrc
= VentoyCrc32(Table
, sizeof(pInfo
->PartTbl
));
998 Head
->Crc
= VentoyCrc32(Head
, Head
->Length
);
1003 int VentoyFillBackupGptHead(VTOY_GPT_INFO
*pInfo
, VTOY_GPT_HDR
*pHead
)
1008 memcpy(pHead
, &pInfo
->Head
, sizeof(VTOY_GPT_HDR
));
1010 LBA
= pHead
->EfiStartLBA
;
1011 BackupLBA
= pHead
->EfiBackupLBA
;
1013 pHead
->EfiStartLBA
= BackupLBA
;
1014 pHead
->EfiBackupLBA
= LBA
;
1015 pHead
->PartTblStartLBA
= BackupLBA
+ 1 - 33;
1018 pHead
->Crc
= VentoyCrc32(pHead
, pHead
->Length
);
1023 CHAR
GetFirstUnusedDriveLetter(void)
1026 DWORD Drives
= GetLogicalDrives();
1029 while (Drives
& 0x1)
1038 const CHAR
* GetBusTypeString(STORAGE_BUS_TYPE Type
)
1042 case BusTypeUnknown
: return "unknown";
1043 case BusTypeScsi
: return "SCSI";
1044 case BusTypeAtapi
: return "Atapi";
1045 case BusTypeAta
: return "ATA";
1046 case BusType1394
: return "1394";
1047 case BusTypeSsa
: return "SSA";
1048 case BusTypeFibre
: return "Fibre";
1049 case BusTypeUsb
: return "USB";
1050 case BusTypeRAID
: return "RAID";
1051 case BusTypeiScsi
: return "iSCSI";
1052 case BusTypeSas
: return "SAS";
1053 case BusTypeSata
: return "SATA";
1054 case BusTypeSd
: return "SD";
1055 case BusTypeMmc
: return "MMC";
1056 case BusTypeVirtual
: return "Virtual";
1057 case BusTypeFileBackedVirtual
: return "FileBackedVirtual";
1058 case BusTypeSpaces
: return "Spaces";
1059 case BusTypeNvme
: return "Nvme";
1064 int VentoyGetLocalBootImg(MBR_HEAD
*pMBR
)
1067 BYTE
*ImgBuf
= NULL
;
1068 static int Loaded
= 0;
1069 static MBR_HEAD MBR
;
1073 memcpy(pMBR
, &MBR
, 512);
1077 if (0 == ReadWholeFileToBuf(VENTOY_FILE_BOOT_IMG
, 0, (void **)&ImgBuf
, &Len
))
1079 Log("Copy boot img success");
1080 memcpy(pMBR
, ImgBuf
, 512);
1083 CoCreateGuid((GUID
*)(pMBR
->BootCode
+ 0x180));
1085 memcpy(&MBR
, pMBR
, 512);
1092 Log("Copy boot img failed");
1097 int GetHumanReadableGBSize(UINT64 SizeBytes
)
1102 double GB
= SizeBytes
* 1.0 / 1000 / 1000 / 1000;
1104 if ((SizeBytes
% 1073741824) == 0)
1106 return (int)(SizeBytes
/ 1073741824);
1109 for (i
= 0; i
< 12; i
++)
1113 Delta
= (Pow2
- GB
) / Pow2
;
1117 Delta
= (GB
- Pow2
) / Pow2
;
1131 void TrimString(CHAR
*String
)
1133 CHAR
*Pos1
= String
;
1134 CHAR
*Pos2
= String
;
1135 size_t Len
= strlen(String
);
1139 if (String
[Len
- 1] != ' ' && String
[Len
- 1] != '\t')
1143 String
[Len
- 1] = 0;
1147 while (*Pos1
== ' ' || *Pos1
== '\t')
1161 int GetRegDwordValue(HKEY Key
, LPCSTR SubKey
, LPCSTR ValueName
, DWORD
*pValue
)
1169 lRet
= RegOpenKeyExA(Key
, SubKey
, 0, KEY_QUERY_VALUE
, &hKey
);
1170 Log("RegOpenKeyExA <%s> Ret:%ld", SubKey
, lRet
);
1172 if (ERROR_SUCCESS
== lRet
)
1174 Size
= sizeof(Value
);
1175 lRet
= RegQueryValueExA(hKey
, ValueName
, NULL
, &Type
, (LPBYTE
)&Value
, &Size
);
1176 Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName
, lRet
, Size
, Value
);
1189 int GetPhysicalDriveCount(void)
1194 if (GetRegDwordValue(HKEY_LOCAL_MACHINE
, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value
) == 0)
1199 Log("GetPhysicalDriveCount: %d", Count
);
1203 void VentoyStringToUpper(CHAR
* str
)
1207 if (*str
>= 'a' && *str
<= 'z')
1209 *str
= toupper(*str
);