]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Ventoy2Disk/Ventoy2Disk/Utility.c
1. Optimization for WIMBOOT mode.
[Ventoy.git] / Ventoy2Disk / Ventoy2Disk / Utility.c
1 /******************************************************************************
2 * Utility.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 *
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.
10 *
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.
15 *
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/>.
18 *
19 */
20 #include <Windows.h>
21 #include "Ventoy2Disk.h"
22
23 void Log(const char *Fmt, ...)
24 {
25 va_list Arg;
26 int Len = 0;
27 FILE *File = NULL;
28 SYSTEMTIME Sys;
29 char szBuf[1024];
30
31 GetLocalTime(&Sys);
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,
36 Sys.wMilliseconds);
37
38 va_start(Arg, Fmt);
39 Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);
40 va_end(Arg);
41
42 //printf("%s\n", szBuf);
43
44 #if 1
45 fopen_s(&File, VENTOY_FILE_LOG, "a+");
46 if (File)
47 {
48 fwrite(szBuf, 1, Len, File);
49 fwrite("\n", 1, 1, File);
50 fclose(File);
51 }
52 #endif
53
54 }
55
56 BOOL IsPathExist(BOOL Dir, const char *Fmt, ...)
57 {
58 va_list Arg;
59 HANDLE hFile;
60 DWORD Attr;
61 CHAR FilePath[MAX_PATH];
62
63 va_start(Arg, Fmt);
64 vsnprintf_s(FilePath, sizeof(FilePath), sizeof(FilePath), Fmt, Arg);
65 va_end(Arg);
66
67 hFile = CreateFileA(FilePath, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
68 if (INVALID_HANDLE_VALUE == hFile)
69 {
70 return FALSE;
71 }
72
73 CloseHandle(hFile);
74
75 Attr = GetFileAttributesA(FilePath);
76
77 if (Dir)
78 {
79 if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
80 {
81 return FALSE;
82 }
83 }
84 else
85 {
86 if (Attr & FILE_ATTRIBUTE_DIRECTORY)
87 {
88 return FALSE;
89 }
90 }
91
92 return TRUE;
93 }
94
95
96 int ReadWholeFileToBuf(const CHAR *FileName, int ExtLen, void **Bufer, int *BufLen)
97 {
98 int FileSize;
99 FILE *File = NULL;
100 void *Data = NULL;
101
102 fopen_s(&File, FileName, "rb");
103 if (File == NULL)
104 {
105 Log("Failed to open file %s", FileName);
106 return 1;
107 }
108
109 fseek(File, 0, SEEK_END);
110 FileSize = (int)ftell(File);
111
112 Data = malloc(FileSize + ExtLen);
113 if (!Data)
114 {
115 fclose(File);
116 return 1;
117 }
118
119 fseek(File, 0, SEEK_SET);
120 fread(Data, 1, FileSize, File);
121
122 fclose(File);
123
124 *Bufer = Data;
125 *BufLen = FileSize;
126
127 return 0;
128 }
129
130 const CHAR* GetLocalVentoyVersion(void)
131 {
132 int rc;
133 int FileSize;
134 CHAR *Pos = NULL;
135 CHAR *Buf = NULL;
136 static CHAR LocalVersion[64] = { 0 };
137
138 if (LocalVersion[0] == 0)
139 {
140 rc = ReadWholeFileToBuf(VENTOY_FILE_VERSION, 1, (void **)&Buf, &FileSize);
141 if (rc)
142 {
143 return "";
144 }
145 Buf[FileSize] = 0;
146
147 for (Pos = Buf; *Pos; Pos++)
148 {
149 if (*Pos == '\r' || *Pos == '\n')
150 {
151 *Pos = 0;
152 break;
153 }
154 }
155
156 safe_sprintf(LocalVersion, "%s", Buf);
157 free(Buf);
158 }
159
160 return LocalVersion;
161 }
162
163 const CHAR* ParseVentoyVersionFromString(CHAR *Buf)
164 {
165 CHAR *Pos = NULL;
166 CHAR *End = NULL;
167 static CHAR LocalVersion[64] = { 0 };
168
169 Pos = strstr(Buf, "VENTOY_VERSION=");
170 if (Pos)
171 {
172 Pos += strlen("VENTOY_VERSION=");
173 if (*Pos == '"')
174 {
175 Pos++;
176 }
177
178 End = Pos;
179 while (*End != 0 && *End != '"' && *End != '\r' && *End != '\n')
180 {
181 End++;
182 }
183
184 *End = 0;
185
186 safe_sprintf(LocalVersion, "%s", Pos);
187 return LocalVersion;
188 }
189
190 return "";
191 }
192
193 BOOL IsWow64(void)
194 {
195 typedef BOOL(WINAPI *LPFN_ISWOW64PROCESS)(HANDLE, PBOOL);
196 LPFN_ISWOW64PROCESS fnIsWow64Process;
197 BOOL bIsWow64 = FALSE;
198
199 fnIsWow64Process = (LPFN_ISWOW64PROCESS)GetProcAddress(GetModuleHandleA("kernel32"), "IsWow64Process");
200 if (NULL != fnIsWow64Process)
201 {
202 fnIsWow64Process(GetCurrentProcess(), &bIsWow64);
203 }
204
205 return bIsWow64;
206 }
207
208 void DumpWindowsVersion(void)
209 {
210 int Bit;
211 BOOL WsVer;
212 DWORD Major, Minor;
213 ULONGLONG MajorEqual, MinorEqual;
214 OSVERSIONINFOEXA Ver1, Ver2;
215 const CHAR *Ver = NULL;
216 CHAR WinVer[256] = { 0 };
217
218 memset(&Ver1, 0, sizeof(Ver1));
219 memset(&Ver2, 0, sizeof(Ver2));
220
221 Ver1.dwOSVersionInfoSize = sizeof(Ver1);
222
223 // suppress the C4996 warning for GetVersionExA
224 #pragma warning(push)
225 #pragma warning(disable:4996)
226 if (!GetVersionExA((OSVERSIONINFOA *)&Ver1))
227 {
228 memset(&Ver1, 0, sizeof(Ver1));
229 Ver1.dwOSVersionInfoSize = sizeof(OSVERSIONINFOA);
230 if (!GetVersionExA((OSVERSIONINFOA *)&Ver1))
231 {
232 return;
233 }
234 }
235 #pragma warning(pop)
236
237 if (Ver1.dwPlatformId == VER_PLATFORM_WIN32_NT)
238 {
239 if (Ver1.dwMajorVersion > 6 || (Ver1.dwMajorVersion == 6 && Ver1.dwMinorVersion >= 2))
240 {
241 // GetVersionEx() has problem on some Windows version
242
243 MajorEqual = VerSetConditionMask(0, VER_MAJORVERSION, VER_EQUAL);
244 for (Major = Ver1.dwMajorVersion; Major <= 9; Major++)
245 {
246 memset(&Ver2, 0, sizeof(Ver2));
247 Ver2.dwOSVersionInfoSize = sizeof(Ver2);
248 Ver2.dwMajorVersion = Major;
249
250 if (!VerifyVersionInfoA(&Ver2, VER_MAJORVERSION, MajorEqual))
251 {
252 continue;
253 }
254
255 if (Ver1.dwMajorVersion < Major)
256 {
257 Ver1.dwMajorVersion = Major;
258 Ver1.dwMinorVersion = 0;
259 }
260
261 MinorEqual = VerSetConditionMask(0, VER_MINORVERSION, VER_EQUAL);
262 for (Minor = Ver1.dwMinorVersion; Minor <= 9; Minor++)
263 {
264 memset(&Ver2, 0, sizeof(Ver2));
265
266 Ver2.dwOSVersionInfoSize = sizeof(Ver2);
267 Ver2.dwMinorVersion = Minor;
268
269 if (!VerifyVersionInfoA(&Ver2, VER_MINORVERSION, MinorEqual))
270 {
271 continue;
272 }
273
274 Ver1.dwMinorVersion = Minor;
275 break;
276 }
277
278 break;
279 }
280 }
281
282 if (Ver1.dwMajorVersion <= 0xF && Ver1.dwMinorVersion <= 0xF)
283 {
284 WsVer = (Ver1.wProductType <= VER_NT_WORKSTATION);
285 switch ((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion)
286 {
287 case 0x51:
288 {
289 Ver = "XP";
290 break;
291 }
292 case 0x52:
293 {
294 Ver = GetSystemMetrics(89) ? "Server 2003 R2" : "Server 2003";
295 break;
296 }
297 case 0x60:
298 {
299 Ver = WsVer ? "Vista" : "Server 2008";
300 break;
301 }
302 case 0x61:
303 {
304 Ver = WsVer ? "7" : "Server 2008 R2";
305 break;
306 }
307 case 0x62:
308 {
309 Ver = WsVer ? "8" : "Server 2012";
310 break;
311 }
312 case 0x63:
313 {
314 Ver = WsVer ? "8.1" : "Server 2012 R2";
315 break;
316 }
317 case 0x64:
318 {
319 Ver = WsVer ? "10 (Preview 1)" : "Server 10 (Preview 1)";
320 break;
321 }
322 case 0xA0:
323 {
324 Ver = WsVer ? "10" : ((Ver1.dwBuildNumber > 15000) ? "Server 2019" : "Server 2016");
325 break;
326 }
327 default:
328 {
329 Ver = "10 or later";
330 break;
331 }
332 }
333 }
334 }
335
336 Bit = IsWow64() ? 64 : 32;
337
338 if (Ver1.wServicePackMinor)
339 {
340 safe_sprintf(WinVer, "Windows %s SP%u.%u %d-bit", Ver, Ver1.wServicePackMajor, Ver1.wServicePackMinor, Bit);
341 }
342 else if (Ver1.wServicePackMajor)
343 {
344 safe_sprintf(WinVer, "Windows %s SP%u %d-bit", Ver, Ver1.wServicePackMajor, Bit);
345 }
346 else
347 {
348 safe_sprintf(WinVer, "Windows %s %d-bit", Ver, Bit);
349 }
350
351 if (((Ver1.dwMajorVersion << 4) | Ver2.dwMinorVersion) >= 0x62)
352 {
353 Log("Windows Version : %s (Build %u)", WinVer, Ver1.dwBuildNumber);
354 }
355 else
356 {
357 Log("Windows Version : %s", WinVer);
358 }
359
360 return;
361 }
362
363 BOOL IsVentoyLogicalDrive(CHAR DriveLetter)
364 {
365 int i;
366 CONST CHAR *Files[] =
367 {
368 "EFI\\BOOT\\BOOTX64.EFI",
369 "grub\\themes\\ventoy\\theme.txt",
370 "ventoy\\ventoy.cpio",
371 };
372
373 for (i = 0; i < sizeof(Files) / sizeof(Files[0]); i++)
374 {
375 if (!IsFileExist("%C:\\%s", DriveLetter, Files[i]))
376 {
377 return FALSE;
378 }
379 }
380
381 return TRUE;
382 }
383
384
385 int VentoyFillMBRLocation(UINT64 DiskSizeInBytes, UINT32 StartSectorId, UINT32 SectorCount, PART_TABLE *Table)
386 {
387 BYTE Head;
388 BYTE Sector;
389 BYTE nSector = 63;
390 BYTE nHead = 8;
391 UINT32 Cylinder;
392 UINT32 EndSectorId;
393
394 while (nHead != 0 && (DiskSizeInBytes / 512 / nSector / nHead) > 1024)
395 {
396 nHead = (BYTE)nHead * 2;
397 }
398
399 if (nHead == 0)
400 {
401 nHead = 255;
402 }
403
404 Cylinder = StartSectorId / nSector / nHead;
405 Head = StartSectorId / nSector % nHead;
406 Sector = StartSectorId % nSector + 1;
407
408 Table->StartHead = Head;
409 Table->StartSector = Sector;
410 Table->StartCylinder = Cylinder;
411
412 EndSectorId = StartSectorId + SectorCount - 1;
413 Cylinder = EndSectorId / nSector / nHead;
414 Head = EndSectorId / nSector % nHead;
415 Sector = EndSectorId % nSector + 1;
416
417 Table->EndHead = Head;
418 Table->EndSector = Sector;
419 Table->EndCylinder = Cylinder;
420
421 Table->StartSectorId = StartSectorId;
422 Table->SectorCount = SectorCount;
423
424 return 0;
425 }
426
427 int VentoyFillMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR, int PartStyle)
428 {
429 GUID Guid;
430 int ReservedValue;
431 UINT32 DiskSignature;
432 UINT32 DiskSectorCount;
433 UINT32 PartSectorCount;
434 UINT32 PartStartSector;
435 UINT32 ReservedSector;
436
437 VentoyGetLocalBootImg(pMBR);
438
439 CoCreateGuid(&Guid);
440
441 memcpy(&DiskSignature, &Guid, sizeof(UINT32));
442
443 Log("Disk signature: 0x%08x", DiskSignature);
444
445 *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;
446
447 if (DiskSizeBytes / 512 > 0xFFFFFFFF)
448 {
449 DiskSectorCount = 0xFFFFFFFF;
450 }
451 else
452 {
453 DiskSectorCount = (UINT32)(DiskSizeBytes / 512);
454 }
455
456 ReservedValue = GetReservedSpaceInMB();
457 if (ReservedValue <= 0)
458 {
459 ReservedSector = 0;
460 }
461 else
462 {
463 ReservedSector = (UINT32)(ReservedValue * 2048);
464 }
465
466 if (PartStyle)
467 {
468 ReservedSector += 33; // backup GPT part table
469 }
470
471 // check aligned with 4KB
472 if (IsPartNeed4KBAlign())
473 {
474 UINT64 sectors = DiskSizeBytes / 512;
475 if (sectors % 8)
476 {
477 Log("Disk need to align with 4KB %u", (UINT32)(sectors % 8));
478 ReservedSector += (UINT32)(sectors % 8);
479 }
480 }
481
482 Log("ReservedSector: %u", ReservedSector);
483
484 //Part1
485 PartStartSector = VENTOY_PART1_START_SECTOR;
486 PartSectorCount = DiskSectorCount - ReservedSector - VENTOY_EFI_PART_SIZE / 512 - PartStartSector;
487 VentoyFillMBRLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl);
488
489 pMBR->PartTbl[0].Active = 0x80; // bootable
490 pMBR->PartTbl[0].FsFlag = 0x07; // exFAT/NTFS/HPFS
491
492 //Part2
493 PartStartSector += PartSectorCount;
494 PartSectorCount = VENTOY_EFI_PART_SIZE / 512;
495 VentoyFillMBRLocation(DiskSizeBytes, PartStartSector, PartSectorCount, pMBR->PartTbl + 1);
496
497 pMBR->PartTbl[1].Active = 0x00;
498 pMBR->PartTbl[1].FsFlag = 0xEF; // EFI System Partition
499
500 pMBR->Byte55 = 0x55;
501 pMBR->ByteAA = 0xAA;
502
503 return 0;
504 }
505
506
507 static int VentoyFillProtectMBR(UINT64 DiskSizeBytes, MBR_HEAD *pMBR)
508 {
509 GUID Guid;
510 UINT32 DiskSignature;
511 UINT64 DiskSectorCount;
512
513 VentoyGetLocalBootImg(pMBR);
514
515 CoCreateGuid(&Guid);
516
517 memcpy(&DiskSignature, &Guid, sizeof(UINT32));
518
519 Log("Disk signature: 0x%08x", DiskSignature);
520
521 *((UINT32 *)(pMBR->BootCode + 0x1B8)) = DiskSignature;
522
523 DiskSectorCount = DiskSizeBytes / 512 - 1;
524 if (DiskSectorCount > 0xFFFFFFFF)
525 {
526 DiskSectorCount = 0xFFFFFFFF;
527 }
528
529 memset(pMBR->PartTbl, 0, sizeof(pMBR->PartTbl));
530
531 pMBR->PartTbl[0].Active = 0x00;
532 pMBR->PartTbl[0].FsFlag = 0xee; // EE
533
534 pMBR->PartTbl[0].StartHead = 0;
535 pMBR->PartTbl[0].StartSector = 1;
536 pMBR->PartTbl[0].StartCylinder = 0;
537 pMBR->PartTbl[0].EndHead = 254;
538 pMBR->PartTbl[0].EndSector = 63;
539 pMBR->PartTbl[0].EndCylinder = 1023;
540
541 pMBR->PartTbl[0].StartSectorId = 1;
542 pMBR->PartTbl[0].SectorCount = (UINT32)DiskSectorCount;
543
544 pMBR->Byte55 = 0x55;
545 pMBR->ByteAA = 0xAA;
546
547 pMBR->BootCode[92] = 0x22;
548
549 return 0;
550 }
551
552 int VentoyFillWholeGpt(UINT64 DiskSizeBytes, VTOY_GPT_INFO *pInfo)
553 {
554 UINT64 Part1SectorCount = 0;
555 UINT64 DiskSectorCount = DiskSizeBytes / 512;
556 VTOY_GPT_HDR *Head = &pInfo->Head;
557 VTOY_GPT_PART_TBL *Table = pInfo->PartTbl;
558 static GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
559
560 VentoyFillProtectMBR(DiskSizeBytes, &pInfo->MBR);
561
562 Part1SectorCount = DiskSectorCount - 33 - 2048;
563
564 memcpy(Head->Signature, "EFI PART", 8);
565 Head->Version[2] = 0x01;
566 Head->Length = 92;
567 Head->Crc = 0;
568 Head->EfiStartLBA = 1;
569 Head->EfiBackupLBA = DiskSectorCount - 1;
570 Head->PartAreaStartLBA = 34;
571 Head->PartAreaEndLBA = DiskSectorCount - 34;
572 CoCreateGuid(&Head->DiskGuid);
573 Head->PartTblStartLBA = 2;
574 Head->PartTblTotNum = 128;
575 Head->PartTblEntryLen = 128;
576
577
578 memcpy(&(Table[0].PartType), &WindowsDataPartType, sizeof(GUID));
579 CoCreateGuid(&(Table[0].PartGuid));
580 Table[0].StartLBA = 2048;
581 Table[0].LastLBA = 2048 + Part1SectorCount - 1;
582 Table[0].Attr = 0;
583 memcpy(Table[0].Name, L"Data", 4 * 2);
584
585 //Update CRC
586 Head->PartTblCrc = VentoyCrc32(Table, sizeof(pInfo->PartTbl));
587 Head->Crc = VentoyCrc32(Head, Head->Length);
588
589 return 0;
590 }
591
592 int VentoyFillGpt(UINT64 DiskSizeBytes, VTOY_GPT_INFO *pInfo)
593 {
594 INT64 ReservedValue = 0;
595 UINT64 ModSectorCount = 0;
596 UINT64 ReservedSector = 33;
597 UINT64 Part1SectorCount = 0;
598 UINT64 DiskSectorCount = DiskSizeBytes / 512;
599 VTOY_GPT_HDR *Head = &pInfo->Head;
600 VTOY_GPT_PART_TBL *Table = pInfo->PartTbl;
601 static GUID WindowsDataPartType = { 0xebd0a0a2, 0xb9e5, 0x4433, { 0x87, 0xc0, 0x68, 0xb6, 0xb7, 0x26, 0x99, 0xc7 } };
602 static GUID EspPartType = { 0xc12a7328, 0xf81f, 0x11d2, { 0xba, 0x4b, 0x00, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b } };
603 static GUID BiosGrubPartType = { 0x21686148, 0x6449, 0x6e6f, { 0x74, 0x4e, 0x65, 0x65, 0x64, 0x45, 0x46, 0x49 } };
604
605 VentoyFillProtectMBR(DiskSizeBytes, &pInfo->MBR);
606
607 ReservedValue = GetReservedSpaceInMB();
608 if (ReservedValue > 0)
609 {
610 ReservedSector += ReservedValue * 2048;
611 }
612
613 Part1SectorCount = DiskSectorCount - ReservedSector - (VENTOY_EFI_PART_SIZE / 512) - 2048;
614
615 ModSectorCount = (Part1SectorCount % 8);
616 if (ModSectorCount)
617 {
618 Log("Part1SectorCount:%llu is not aligned by 4KB (%llu)", (ULONGLONG)Part1SectorCount, (ULONGLONG)ModSectorCount);
619 }
620
621 // check aligned with 4KB
622 if (IsPartNeed4KBAlign())
623 {
624 if (ModSectorCount)
625 {
626 Log("Disk need to align with 4KB %u", (UINT32)ModSectorCount);
627 Part1SectorCount -= ModSectorCount;
628 }
629 else
630 {
631 Log("no need to align with 4KB");
632 }
633 }
634
635 memcpy(Head->Signature, "EFI PART", 8);
636 Head->Version[2] = 0x01;
637 Head->Length = 92;
638 Head->Crc = 0;
639 Head->EfiStartLBA = 1;
640 Head->EfiBackupLBA = DiskSectorCount - 1;
641 Head->PartAreaStartLBA = 34;
642 Head->PartAreaEndLBA = DiskSectorCount - 34;
643 CoCreateGuid(&Head->DiskGuid);
644 Head->PartTblStartLBA = 2;
645 Head->PartTblTotNum = 128;
646 Head->PartTblEntryLen = 128;
647
648
649 memcpy(&(Table[0].PartType), &WindowsDataPartType, sizeof(GUID));
650 CoCreateGuid(&(Table[0].PartGuid));
651 Table[0].StartLBA = 2048;
652 Table[0].LastLBA = 2048 + Part1SectorCount - 1;
653 Table[0].Attr = 0;
654 memcpy(Table[0].Name, L"Ventoy", 6 * 2);
655
656 // to fix windows issue
657 //memcpy(&(Table[1].PartType), &EspPartType, sizeof(GUID));
658 memcpy(&(Table[1].PartType), &WindowsDataPartType, sizeof(GUID));
659 CoCreateGuid(&(Table[1].PartGuid));
660 Table[1].StartLBA = Table[0].LastLBA + 1;
661 Table[1].LastLBA = Table[1].StartLBA + VENTOY_EFI_PART_SIZE / 512 - 1;
662 Table[1].Attr = 0x8000000000000001ULL;
663 memcpy(Table[1].Name, L"VTOYEFI", 7 * 2);
664
665 #if 0
666 memcpy(&(Table[2].PartType), &BiosGrubPartType, sizeof(GUID));
667 CoCreateGuid(&(Table[2].PartGuid));
668 Table[2].StartLBA = 34;
669 Table[2].LastLBA = 2047;
670 Table[2].Attr = 0;
671 #endif
672
673 //Update CRC
674 Head->PartTblCrc = VentoyCrc32(Table, sizeof(pInfo->PartTbl));
675 Head->Crc = VentoyCrc32(Head, Head->Length);
676
677 return 0;
678 }
679
680 int VentoyFillBackupGptHead(VTOY_GPT_INFO *pInfo, VTOY_GPT_HDR *pHead)
681 {
682 UINT64 LBA;
683 UINT64 BackupLBA;
684
685 memcpy(pHead, &pInfo->Head, sizeof(VTOY_GPT_HDR));
686
687 LBA = pHead->EfiStartLBA;
688 BackupLBA = pHead->EfiBackupLBA;
689
690 pHead->EfiStartLBA = BackupLBA;
691 pHead->EfiBackupLBA = LBA;
692 pHead->PartTblStartLBA = BackupLBA + 1 - 33;
693
694 pHead->Crc = 0;
695 pHead->Crc = VentoyCrc32(pHead, pHead->Length);
696
697 return 0;
698 }
699
700 CHAR GetFirstUnusedDriveLetter(void)
701 {
702 CHAR Letter = 'D';
703 DWORD Drives = GetLogicalDrives();
704
705 Drives >>= 3;
706 while (Drives & 0x1)
707 {
708 Letter++;
709 Drives >>= 1;
710 }
711
712 return Letter;
713 }
714
715 const CHAR * GetBusTypeString(STORAGE_BUS_TYPE Type)
716 {
717 switch (Type)
718 {
719 case BusTypeUnknown: return "unknown";
720 case BusTypeScsi: return "SCSI";
721 case BusTypeAtapi: return "Atapi";
722 case BusTypeAta: return "ATA";
723 case BusType1394: return "1394";
724 case BusTypeSsa: return "SSA";
725 case BusTypeFibre: return "Fibre";
726 case BusTypeUsb: return "USB";
727 case BusTypeRAID: return "RAID";
728 case BusTypeiScsi: return "iSCSI";
729 case BusTypeSas: return "SAS";
730 case BusTypeSata: return "SATA";
731 case BusTypeSd: return "SD";
732 case BusTypeMmc: return "MMC";
733 case BusTypeVirtual: return "Virtual";
734 case BusTypeFileBackedVirtual: return "FileBackedVirtual";
735 case BusTypeSpaces: return "Spaces";
736 case BusTypeNvme: return "Nvme";
737 }
738 return "unknown";
739 }
740
741 int VentoyGetLocalBootImg(MBR_HEAD *pMBR)
742 {
743 int Len = 0;
744 BYTE *ImgBuf = NULL;
745 static int Loaded = 0;
746 static MBR_HEAD MBR;
747
748 if (Loaded)
749 {
750 memcpy(pMBR, &MBR, 512);
751 return 0;
752 }
753
754 if (0 == ReadWholeFileToBuf(VENTOY_FILE_BOOT_IMG, 0, (void **)&ImgBuf, &Len))
755 {
756 Log("Copy boot img success");
757 memcpy(pMBR, ImgBuf, 512);
758 free(ImgBuf);
759
760 CoCreateGuid((GUID *)(pMBR->BootCode + 0x180));
761
762 memcpy(&MBR, pMBR, 512);
763 Loaded = 1;
764
765 return 0;
766 }
767 else
768 {
769 Log("Copy boot img failed");
770 return 1;
771 }
772 }
773
774 int GetHumanReadableGBSize(UINT64 SizeBytes)
775 {
776 int i;
777 int Pow2 = 1;
778 double Delta;
779 double GB = SizeBytes * 1.0 / 1000 / 1000 / 1000;
780
781 if ((SizeBytes % 1073741824) == 0)
782 {
783 return (int)(SizeBytes / 1073741824);
784 }
785
786 for (i = 0; i < 12; i++)
787 {
788 if (Pow2 > GB)
789 {
790 Delta = (Pow2 - GB) / Pow2;
791 }
792 else
793 {
794 Delta = (GB - Pow2) / Pow2;
795 }
796
797 if (Delta < 0.05)
798 {
799 return Pow2;
800 }
801
802 Pow2 <<= 1;
803 }
804
805 return (int)GB;
806 }
807
808 void TrimString(CHAR *String)
809 {
810 CHAR *Pos1 = String;
811 CHAR *Pos2 = String;
812 size_t Len = strlen(String);
813
814 while (Len > 0)
815 {
816 if (String[Len - 1] != ' ' && String[Len - 1] != '\t')
817 {
818 break;
819 }
820 String[Len - 1] = 0;
821 Len--;
822 }
823
824 while (*Pos1 == ' ' || *Pos1 == '\t')
825 {
826 Pos1++;
827 }
828
829 while (*Pos1)
830 {
831 *Pos2++ = *Pos1++;
832 }
833 *Pos2++ = 0;
834
835 return;
836 }
837
838 int GetRegDwordValue(HKEY Key, LPCSTR SubKey, LPCSTR ValueName, DWORD *pValue)
839 {
840 HKEY hKey;
841 DWORD Type;
842 DWORD Size;
843 LSTATUS lRet;
844 DWORD Value;
845
846 lRet = RegOpenKeyExA(Key, SubKey, 0, KEY_QUERY_VALUE, &hKey);
847 Log("RegOpenKeyExA <%s> Ret:%ld", SubKey, lRet);
848
849 if (ERROR_SUCCESS == lRet)
850 {
851 Size = sizeof(Value);
852 lRet = RegQueryValueExA(hKey, ValueName, NULL, &Type, (LPBYTE)&Value, &Size);
853 Log("RegQueryValueExA <%s> ret:%u Size:%u Value:%u", ValueName, lRet, Size, Value);
854
855 *pValue = Value;
856 RegCloseKey(hKey);
857
858 return 0;
859 }
860 else
861 {
862 return 1;
863 }
864 }
865
866 int GetPhysicalDriveCount(void)
867 {
868 DWORD Value;
869 int Count = 0;
870
871 if (GetRegDwordValue(HKEY_LOCAL_MACHINE, "SYSTEM\\CurrentControlSet\\Services\\disk\\Enum", "Count", &Value) == 0)
872 {
873 Count = (int)Value;
874 }
875
876 Log("GetPhysicalDriveCount: %d", Count);
877 return Count;
878 }
879
880
881