]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - vtoyjump/vtoyjump/vtoyjump.c
update vtoytool
[Ventoy.git] / vtoyjump / vtoyjump / vtoyjump.c
1 /******************************************************************************
2 * vtoyjump.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
21 #include <stdio.h>
22 #include <stdlib.h>
23 #include <string.h>
24 #include <Windows.h>
25 #include <virtdisk.h>
26 #include <winioctl.h>
27 #include <VersionHelpers.h>
28 #include "vtoyjump.h"
29 #include "fat_filelib.h"
30
31 static ventoy_os_param g_os_param;
32 static ventoy_windows_data g_windows_data;
33 static UINT8 g_os_param_reserved[32];
34 static BOOL g_64bit_system = FALSE;
35 static ventoy_guid g_ventoy_guid = VENTOY_GUID;
36
37 void Log(const char *Fmt, ...)
38 {
39 va_list Arg;
40 int Len = 0;
41 FILE *File = NULL;
42 SYSTEMTIME Sys;
43 char szBuf[1024];
44
45 GetLocalTime(&Sys);
46 Len += sprintf_s(szBuf, sizeof(szBuf),
47 "[%4d/%02d/%02d %02d:%02d:%02d.%03d] ",
48 Sys.wYear, Sys.wMonth, Sys.wDay,
49 Sys.wHour, Sys.wMinute, Sys.wSecond,
50 Sys.wMilliseconds);
51
52 va_start(Arg, Fmt);
53 Len += vsnprintf_s(szBuf + Len, sizeof(szBuf)-Len, sizeof(szBuf)-Len, Fmt, Arg);
54 va_end(Arg);
55
56 fopen_s(&File, "ventoy.log", "a+");
57 if (File)
58 {
59 fwrite(szBuf, 1, Len, File);
60 fwrite("\n", 1, 1, File);
61 fclose(File);
62 }
63 }
64
65
66 static int LoadNtDriver(const char *DrvBinPath)
67 {
68 int i;
69 int rc = 0;
70 BOOL Ret;
71 DWORD Status;
72 SC_HANDLE hServiceMgr;
73 SC_HANDLE hService;
74 char name[256] = { 0 };
75
76 for (i = (int)strlen(DrvBinPath) - 1; i >= 0; i--)
77 {
78 if (DrvBinPath[i] == '\\' || DrvBinPath[i] == '/')
79 {
80 sprintf_s(name, sizeof(name), "%s", DrvBinPath + i + 1);
81 break;
82 }
83 }
84
85 Log("Load NT driver: %s %s", DrvBinPath, name);
86
87 hServiceMgr = OpenSCManagerA(NULL, NULL, SC_MANAGER_ALL_ACCESS);
88 if (hServiceMgr == NULL)
89 {
90 Log("OpenSCManager failed Error:%u", GetLastError());
91 return 1;
92 }
93
94 Log("OpenSCManager OK");
95
96 hService = CreateServiceA(hServiceMgr,
97 name,
98 name,
99 SERVICE_ALL_ACCESS,
100 SERVICE_KERNEL_DRIVER,
101 SERVICE_DEMAND_START,
102 SERVICE_ERROR_NORMAL,
103 DrvBinPath,
104 NULL, NULL, NULL, NULL, NULL);
105 if (hService == NULL)
106 {
107 Status = GetLastError();
108 if (Status != ERROR_IO_PENDING && Status != ERROR_SERVICE_EXISTS)
109 {
110 Log("CreateService failed v %u", Status);
111 CloseServiceHandle(hServiceMgr);
112 return 1;
113 }
114
115 hService = OpenServiceA(hServiceMgr, name, SERVICE_ALL_ACCESS);
116 if (hService == NULL)
117 {
118 Log("OpenService failed %u", Status);
119 CloseServiceHandle(hServiceMgr);
120 return 1;
121 }
122 }
123
124 Log("CreateService imdisk OK");
125
126 Ret = StartServiceA(hService, 0, NULL);
127 if (Ret)
128 {
129 Log("StartService OK");
130 }
131 else
132 {
133 Status = GetLastError();
134 if (Status == ERROR_SERVICE_ALREADY_RUNNING)
135 {
136 rc = 0;
137 }
138 else
139 {
140 Log("StartService error %u", Status);
141 rc = 1;
142 }
143 }
144
145 CloseServiceHandle(hService);
146 CloseServiceHandle(hServiceMgr);
147
148 Log("Load NT driver %s", rc ? "failed" : "success");
149
150 return rc;
151 }
152
153 static int ReadWholeFile2Buf(const char *Fullpath, void **Data, DWORD *Size)
154 {
155 int rc = 1;
156 DWORD FileSize;
157 DWORD dwSize;
158 HANDLE Handle;
159 BYTE *Buffer = NULL;
160
161 Log("ReadWholeFile2Buf <%s>", Fullpath);
162
163 Handle = CreateFileA(Fullpath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
164 if (Handle == INVALID_HANDLE_VALUE)
165 {
166 Log("Could not open the file<%s>, error:%u", Fullpath, GetLastError());
167 goto End;
168 }
169
170 FileSize = SetFilePointer(Handle, 0, NULL, FILE_END);
171
172 Buffer = malloc(FileSize);
173 if (!Buffer)
174 {
175 Log("Failed to alloc memory size:%u", FileSize);
176 goto End;
177 }
178
179 SetFilePointer(Handle, 0, NULL, FILE_BEGIN);
180 if (!ReadFile(Handle, Buffer, FileSize, &dwSize, NULL))
181 {
182 Log("ReadFile failed, dwSize:%u error:%u", dwSize, GetLastError());
183 goto End;
184 }
185
186 *Data = Buffer;
187 *Size = FileSize;
188
189 Log("Success read file size:%u", FileSize);
190
191 rc = 0;
192
193 End:
194 SAFE_CLOSE_HANDLE(Handle);
195
196 return rc;
197 }
198
199 static BOOL CheckPeHead(BYTE *Head)
200 {
201 UINT32 PeOffset;
202
203 if (Head[0] != 'M' || Head[1] != 'Z')
204 {
205 return FALSE;
206 }
207
208 PeOffset = *(UINT32 *)(Head + 60);
209 if (*(UINT32 *)(Head + PeOffset) != 0x00004550)
210 {
211 return FALSE;
212 }
213
214 return TRUE;
215 }
216
217 static BOOL IsPe64(BYTE *buffer)
218 {
219 DWORD pe_off;
220
221 if (!CheckPeHead(buffer))
222 {
223 return FALSE;
224 }
225
226 pe_off = *(UINT32 *)(buffer + 60);
227 if (*(UINT16 *)(buffer + pe_off + 24) == 0x020b)
228 {
229 return TRUE;
230 }
231
232 return FALSE;
233 }
234
235
236 static BOOL CheckOsParam(ventoy_os_param *param)
237 {
238 UINT32 i;
239 BYTE Sum = 0;
240
241 if (memcmp(&param->guid, &g_ventoy_guid, sizeof(ventoy_guid)))
242 {
243 return FALSE;
244 }
245
246 for (i = 0; i < sizeof(ventoy_os_param); i++)
247 {
248 Sum += *((BYTE *)param + i);
249 }
250
251 if (Sum)
252 {
253 return FALSE;
254 }
255
256 if (param->vtoy_img_location_addr % 4096)
257 {
258 return FALSE;
259 }
260
261 return TRUE;
262 }
263
264 static int SaveBuffer2File(const char *Fullpath, void *Buffer, DWORD Length)
265 {
266 int rc = 1;
267 DWORD dwSize;
268 HANDLE Handle;
269
270 Log("SaveBuffer2File <%s> len:%u", Fullpath, Length);
271
272 Handle = CreateFileA(Fullpath, GENERIC_READ | GENERIC_WRITE,
273 FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, 0, 0);
274 if (Handle == INVALID_HANDLE_VALUE)
275 {
276 Log("Could not create new file, error:%u", GetLastError());
277 goto End;
278 }
279
280 WriteFile(Handle, Buffer, Length, &dwSize, NULL);
281
282 rc = 0;
283
284 End:
285 SAFE_CLOSE_HANDLE(Handle);
286
287 return rc;
288 }
289
290 static int IsUTF8Encode(const char *src)
291 {
292 int i;
293 const UCHAR *Byte = (const UCHAR *)src;
294
295 for (i = 0; i < MAX_PATH && Byte[i]; i++)
296 {
297 if (Byte[i] > 127)
298 {
299 return 1;
300 }
301 }
302
303 return 0;
304 }
305
306 static int Utf8ToUtf16(const char* src, WCHAR * dst)
307 {
308 int size = MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, 0);
309 return MultiByteToWideChar(CP_UTF8, 0, src, -1, dst, size + 1);
310 }
311
312 static BOOL IsPathExist(BOOL Dir, const char *Fmt, ...)
313 {
314 va_list Arg;
315 HANDLE hFile;
316 DWORD Attr;
317 int UTF8 = 0;
318 CHAR FilePathA[MAX_PATH];
319 WCHAR FilePathW[MAX_PATH];
320
321 va_start(Arg, Fmt);
322 vsnprintf_s(FilePathA, sizeof(FilePathA), sizeof(FilePathA), Fmt, Arg);
323 va_end(Arg);
324
325 UTF8 = IsUTF8Encode(FilePathA);
326
327 if (UTF8)
328 {
329 Utf8ToUtf16(FilePathA, FilePathW);
330 hFile = CreateFileW(FilePathW, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
331 }
332 else
333 {
334 hFile = CreateFileA(FilePathA, FILE_READ_EA, FILE_SHARE_READ, 0, OPEN_EXISTING, 0, 0);
335 }
336 if (INVALID_HANDLE_VALUE == hFile)
337 {
338 return FALSE;
339 }
340
341 CloseHandle(hFile);
342
343 if (UTF8)
344 {
345 Attr = GetFileAttributesW(FilePathW);
346 }
347 else
348 {
349 Attr = GetFileAttributesA(FilePathA);
350 }
351
352 if (Dir)
353 {
354 if ((Attr & FILE_ATTRIBUTE_DIRECTORY) == 0)
355 {
356 return FALSE;
357 }
358 }
359 else
360 {
361 if (Attr & FILE_ATTRIBUTE_DIRECTORY)
362 {
363 return FALSE;
364 }
365 }
366
367 return TRUE;
368 }
369
370 static int GetPhyDiskUUID(const char LogicalDrive, UINT8 *UUID, DISK_EXTENT *DiskExtent)
371 {
372 BOOL Ret;
373 DWORD dwSize;
374 HANDLE Handle;
375 VOLUME_DISK_EXTENTS DiskExtents;
376 CHAR PhyPath[128];
377 UINT8 SectorBuf[512];
378
379 Log("GetPhyDiskUUID %C", LogicalDrive);
380
381 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", LogicalDrive);
382 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
383 if (Handle == INVALID_HANDLE_VALUE)
384 {
385 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
386 return 1;
387 }
388
389 Ret = DeviceIoControl(Handle,
390 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
391 NULL,
392 0,
393 &DiskExtents,
394 (DWORD)(sizeof(DiskExtents)),
395 (LPDWORD)&dwSize,
396 NULL);
397 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
398 {
399 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed, error:%u", GetLastError());
400 CloseHandle(Handle);
401 return 1;
402 }
403 CloseHandle(Handle);
404
405 memcpy(DiskExtent, DiskExtents.Extents, sizeof(DiskExtent));
406 Log("%C: is in PhysicalDrive%d ", LogicalDrive, DiskExtents.Extents[0].DiskNumber);
407
408 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", DiskExtents.Extents[0].DiskNumber);
409 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
410 if (Handle == INVALID_HANDLE_VALUE)
411 {
412 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
413 return 1;
414 }
415
416 if (!ReadFile(Handle, SectorBuf, sizeof(SectorBuf), &dwSize, NULL))
417 {
418 Log("ReadFile failed, dwSize:%u error:%u", dwSize, GetLastError());
419 CloseHandle(Handle);
420 return 1;
421 }
422
423 memcpy(UUID, SectorBuf + 0x180, 16);
424 CloseHandle(Handle);
425 return 0;
426 }
427
428 int VentoyMountISOByAPI(const char *IsoPath)
429 {
430 HANDLE Handle;
431 DWORD Status;
432 WCHAR wFilePath[512] = { 0 };
433 VIRTUAL_STORAGE_TYPE StorageType;
434 OPEN_VIRTUAL_DISK_PARAMETERS OpenParameters;
435 ATTACH_VIRTUAL_DISK_PARAMETERS AttachParameters;
436
437 Log("VentoyMountISOByAPI <%s>", IsoPath);
438
439 if (IsUTF8Encode(IsoPath))
440 {
441 MultiByteToWideChar(CP_UTF8, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));
442 }
443 else
444 {
445 MultiByteToWideChar(CP_ACP, 0, IsoPath, (int)strlen(IsoPath), wFilePath, (int)(sizeof(wFilePath) / sizeof(WCHAR)));
446 }
447
448 memset(&StorageType, 0, sizeof(StorageType));
449 memset(&OpenParameters, 0, sizeof(OpenParameters));
450 memset(&AttachParameters, 0, sizeof(AttachParameters));
451
452 OpenParameters.Version = OPEN_VIRTUAL_DISK_VERSION_1;
453 AttachParameters.Version = ATTACH_VIRTUAL_DISK_VERSION_1;
454
455 Status = OpenVirtualDisk(&StorageType, wFilePath, VIRTUAL_DISK_ACCESS_READ, 0, &OpenParameters, &Handle);
456 if (Status != ERROR_SUCCESS)
457 {
458 if (ERROR_VIRTDISK_PROVIDER_NOT_FOUND == Status)
459 {
460 Log("VirtualDisk for ISO file is not supported in current system");
461 }
462 else
463 {
464 Log("Failed to open virtual disk ErrorCode:%u", Status);
465 }
466 return 1;
467 }
468
469 Log("OpenVirtualDisk success");
470
471 Status = AttachVirtualDisk(Handle, NULL, ATTACH_VIRTUAL_DISK_FLAG_READ_ONLY | ATTACH_VIRTUAL_DISK_FLAG_PERMANENT_LIFETIME, 0, &AttachParameters, NULL);
472 if (Status != ERROR_SUCCESS)
473 {
474 Log("Failed to attach virtual disk ErrorCode:%u", Status);
475 CloseHandle(Handle);
476 return 1;
477 }
478
479 CloseHandle(Handle);
480 return 0;
481 }
482
483
484 static HANDLE g_FatPhyDrive;
485 static UINT64 g_Part2StartSec;
486
487 static int CopyFileFromFatDisk(const CHAR* SrcFile, const CHAR *DstFile)
488 {
489 int rc = 1;
490 int size = 0;
491 char *buf = NULL;
492 void *flfile = NULL;
493
494 Log("CopyFileFromFatDisk (%s)==>(%s)", SrcFile, DstFile);
495
496 flfile = fl_fopen(SrcFile, "rb");
497 if (flfile)
498 {
499 fl_fseek(flfile, 0, SEEK_END);
500 size = (int)fl_ftell(flfile);
501 fl_fseek(flfile, 0, SEEK_SET);
502
503 buf = (char *)malloc(size);
504 if (buf)
505 {
506 fl_fread(buf, 1, size, flfile);
507
508 rc = 0;
509 SaveBuffer2File(DstFile, buf, size);
510 free(buf);
511 }
512
513 fl_fclose(flfile);
514 }
515
516 return rc;
517 }
518
519 static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
520 {
521 DWORD dwSize;
522 BOOL bRet;
523 DWORD ReadSize;
524 LARGE_INTEGER liCurrentPosition;
525
526 liCurrentPosition.QuadPart = Sector + g_Part2StartSec;
527 liCurrentPosition.QuadPart *= 512;
528 SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
529
530 ReadSize = (DWORD)(SectorCount * 512);
531
532 bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);
533 if (bRet == FALSE || dwSize != ReadSize)
534 {
535 Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u\n", bRet, ReadSize, dwSize, GetLastError());
536 }
537
538 return 1;
539 }
540
541 static CHAR GetMountLogicalDrive(void)
542 {
543 CHAR Letter = 'Y';
544 DWORD Drives;
545 DWORD Mask = 0x1000000;
546
547 Drives = GetLogicalDrives();
548 Log("Drives=0x%x", Drives);
549
550 while (Mask)
551 {
552 if ((Drives & Mask) == 0)
553 {
554 break;
555 }
556
557 Letter--;
558 Mask >>= 1;
559 }
560
561 return Letter;
562 }
563
564 UINT64 GetVentoyEfiPartStartSector(HANDLE hDrive)
565 {
566 BOOL bRet;
567 DWORD dwSize;
568 MBR_HEAD MBR;
569 VTOY_GPT_INFO *pGpt = NULL;
570 UINT64 StartSector = 0;
571
572 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
573
574 bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
575 Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);
576
577 if ((!bRet) || (dwSize != sizeof(MBR)))
578 {
579 0;
580 }
581
582 if (MBR.PartTbl[0].FsFlag == 0xEE)
583 {
584 Log("GPT partition style");
585
586 pGpt = malloc(sizeof(VTOY_GPT_INFO));
587 if (!pGpt)
588 {
589 return 0;
590 }
591
592 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
593 bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);
594 if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))
595 {
596 Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);
597 return 0;
598 }
599
600 StartSector = pGpt->PartTbl[1].StartLBA;
601 free(pGpt);
602 }
603 else
604 {
605 Log("MBR partition style");
606 StartSector = MBR.PartTbl[1].StartSectorId;
607 }
608
609 Log("GetVentoyEfiPart StartSector: %llu", StartSector);
610 return StartSector;
611 }
612
613 int VentoyMountISOByImdisk(const char *IsoPath, DWORD PhyDrive)
614 {
615 int rc = 1;
616 BOOL bRet;
617 CHAR Letter;
618 DWORD dwBytes;
619 HANDLE hDrive;
620 CHAR PhyPath[MAX_PATH];
621 WCHAR PhyPathW[MAX_PATH];
622 STARTUPINFOA Si;
623 PROCESS_INFORMATION Pi;
624 GET_LENGTH_INFORMATION LengthInfo;
625
626 Log("VentoyMountISOByImdisk %s", IsoPath);
627
628 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\PhysicalDrive%d", PhyDrive);
629 if (IsUTF8Encode(PhyPath))
630 {
631 Utf8ToUtf16(PhyPath, PhyPathW);
632 hDrive = CreateFileW(PhyPathW, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
633 }
634 else
635 {
636 hDrive = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
637 }
638
639 if (hDrive == INVALID_HANDLE_VALUE)
640 {
641 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
642 goto End;
643 }
644
645 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
646 if (!bRet)
647 {
648 Log("Could not get phy disk %s size, error:%u", PhyPath, GetLastError());
649 goto End;
650 }
651
652 g_FatPhyDrive = hDrive;
653 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
654
655 Log("Parse FAT fs...");
656
657 fl_init();
658
659 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
660 {
661 if (g_64bit_system)
662 {
663 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.sys", "ventoy\\imdisk.sys");
664 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.exe", "ventoy\\imdisk.exe");
665 CopyFileFromFatDisk("/ventoy/imdisk/64/imdisk.cpl", "ventoy\\imdisk.cpl");
666 }
667 else
668 {
669 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.sys", "ventoy\\imdisk.sys");
670 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.exe", "ventoy\\imdisk.exe");
671 CopyFileFromFatDisk("/ventoy/imdisk/32/imdisk.cpl", "ventoy\\imdisk.cpl");
672 }
673
674 GetCurrentDirectoryA(sizeof(PhyPath), PhyPath);
675 strcat_s(PhyPath, sizeof(PhyPath), "\\ventoy\\imdisk.sys");
676
677 if (LoadNtDriver(PhyPath) == 0)
678 {
679 rc = 0;
680
681 Letter = GetMountLogicalDrive();
682 sprintf_s(PhyPath, sizeof(PhyPath), "ventoy\\imdisk.exe -a -o ro -f %s -m %C:", IsoPath, Letter);
683
684 Log("mount iso to %C: use imdisk cmd <%s>", Letter, PhyPath);
685
686 GetStartupInfoA(&Si);
687
688 Si.dwFlags |= STARTF_USESHOWWINDOW;
689 Si.wShowWindow = SW_HIDE;
690
691 CreateProcessA(NULL, PhyPath, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
692 WaitForSingleObject(Pi.hProcess, INFINITE);
693 }
694 }
695 fl_shutdown();
696
697 End:
698
699 SAFE_CLOSE_HANDLE(hDrive);
700
701 return rc;
702 }
703
704 static int MountIsoFile(CONST CHAR *IsoPath, DWORD PhyDrive)
705 {
706 if (IsWindows8OrGreater())
707 {
708 Log("This is Windows 8 or latter...");
709 if (VentoyMountISOByAPI(IsoPath) == 0)
710 {
711 Log("Mount iso by API success");
712 return 0;
713 }
714 else
715 {
716 Log("Mount iso by API failed, maybe not supported, try imdisk");
717 return VentoyMountISOByImdisk(IsoPath, PhyDrive);
718 }
719 }
720 else
721 {
722 Log("This is before Windows 8 ...");
723 if (VentoyMountISOByImdisk(IsoPath, PhyDrive) == 0)
724 {
725 Log("Mount iso by imdisk success");
726 return 0;
727 }
728 else
729 {
730 return VentoyMountISOByAPI(IsoPath);
731 }
732 }
733 }
734
735 static int GetPhyDriveByLogicalDrive(int DriveLetter)
736 {
737 BOOL Ret;
738 DWORD dwSize;
739 HANDLE Handle;
740 VOLUME_DISK_EXTENTS DiskExtents;
741 CHAR PhyPath[128];
742
743 sprintf_s(PhyPath, sizeof(PhyPath), "\\\\.\\%C:", (CHAR)DriveLetter);
744
745 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
746 if (Handle == INVALID_HANDLE_VALUE)
747 {
748 Log("Could not open the disk<%s>, error:%u", PhyPath, GetLastError());
749 return -1;
750 }
751
752 Ret = DeviceIoControl(Handle,
753 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
754 NULL,
755 0,
756 &DiskExtents,
757 (DWORD)(sizeof(DiskExtents)),
758 (LPDWORD)&dwSize,
759 NULL);
760
761 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
762 {
763 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, GetLastError());
764 SAFE_CLOSE_HANDLE(Handle);
765 return -1;
766 }
767 SAFE_CLOSE_HANDLE(Handle);
768
769 Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",
770 PhyPath,
771 DiskExtents.Extents[0].DiskNumber,
772 DiskExtents.Extents[0].StartingOffset.QuadPart,
773 DiskExtents.Extents[0].ExtentLength.QuadPart
774 );
775
776 return (int)DiskExtents.Extents[0].DiskNumber;
777 }
778
779
780 static int DeleteVentoyPart2MountPoint(DWORD PhyDrive)
781 {
782 CHAR Letter = 'A';
783 DWORD Drives;
784 DWORD PhyDisk;
785 CHAR DriveName[] = "?:\\";
786
787 Log("DeleteVentoyPart2MountPoint Phy%u ...", PhyDrive);
788
789 Drives = GetLogicalDrives();
790 while (Drives)
791 {
792 if ((Drives & 0x01) && IsPathExist(FALSE, "%C:\\ventoy\\ventoy.cpio", Letter))
793 {
794 Log("File %C:\\ventoy\\ventoy.cpio exist", Letter);
795
796 PhyDisk = GetPhyDriveByLogicalDrive(Letter);
797 Log("PhyDisk=%u for %C", PhyDisk, Letter);
798
799 if (PhyDisk == PhyDrive)
800 {
801 DriveName[0] = Letter;
802 DeleteVolumeMountPointA(DriveName);
803 return 0;
804 }
805 }
806
807 Letter++;
808 Drives >>= 1;
809 }
810
811 return 1;
812 }
813
814 static BOOL check_tar_archive(const char *archive, CHAR *tarName)
815 {
816 int len;
817 int nameLen;
818 const char *pos = archive;
819 const char *slash = archive;
820
821 while (*pos)
822 {
823 if (*pos == '\\' || *pos == '/')
824 {
825 slash = pos;
826 }
827 pos++;
828 }
829
830 len = (int)strlen(slash);
831
832 if (len > 7 && (strncmp(slash + len - 7, ".tar.gz", 7) == 0 || strncmp(slash + len - 7, ".tar.xz", 7) == 0))
833 {
834 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
835 tarName[nameLen - 3] = 0;
836 return TRUE;
837 }
838 else if (len > 8 && strncmp(slash + len - 8, ".tar.bz2", 8) == 0)
839 {
840 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
841 tarName[nameLen - 4] = 0;
842 return TRUE;
843 }
844 else if (len > 9 && strncmp(slash + len - 9, ".tar.lzma", 9) == 0)
845 {
846 nameLen = (int)sprintf_s(tarName, MAX_PATH, "X:%s", slash);
847 tarName[nameLen - 5] = 0;
848 return TRUE;
849 }
850
851 return FALSE;
852 }
853
854 static int DecompressInjectionArchive(const char *archive, DWORD PhyDrive)
855 {
856 int rc = 1;
857 BOOL bRet;
858 DWORD dwBytes;
859 HANDLE hDrive;
860 HANDLE hOut;
861 DWORD flags = CREATE_NO_WINDOW;
862 CHAR StrBuf[MAX_PATH];
863 CHAR tarName[MAX_PATH];
864 STARTUPINFOA Si;
865 PROCESS_INFORMATION Pi;
866 PROCESS_INFORMATION NewPi;
867 GET_LENGTH_INFORMATION LengthInfo;
868 SECURITY_ATTRIBUTES Sa = { sizeof(SECURITY_ATTRIBUTES), NULL, TRUE };
869
870 Log("DecompressInjectionArchive %s", archive);
871
872 sprintf_s(StrBuf, sizeof(StrBuf), "\\\\.\\PhysicalDrive%d", PhyDrive);
873 hDrive = CreateFileA(StrBuf, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
874 if (hDrive == INVALID_HANDLE_VALUE)
875 {
876 Log("Could not open the disk<%s>, error:%u", StrBuf, GetLastError());
877 goto End;
878 }
879
880 bRet = DeviceIoControl(hDrive, IOCTL_DISK_GET_LENGTH_INFO, NULL, 0, &LengthInfo, sizeof(LengthInfo), &dwBytes, NULL);
881 if (!bRet)
882 {
883 Log("Could not get phy disk %s size, error:%u", StrBuf, GetLastError());
884 goto End;
885 }
886
887 g_FatPhyDrive = hDrive;
888 g_Part2StartSec = GetVentoyEfiPartStartSector(hDrive);
889
890 Log("Parse FAT fs...");
891
892 fl_init();
893
894 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
895 {
896 if (g_64bit_system)
897 {
898 CopyFileFromFatDisk("/ventoy/7z/64/7za.exe", "ventoy\\7za.exe");
899 }
900 else
901 {
902 CopyFileFromFatDisk("/ventoy/7z/32/7za.exe", "ventoy\\7za.exe");
903 }
904
905 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", archive);
906
907 Log("extract inject to X:");
908 Log("cmdline:<%s>", StrBuf);
909
910 GetStartupInfoA(&Si);
911
912 hOut = CreateFileA("ventoy\\7z.log",
913 FILE_APPEND_DATA,
914 FILE_SHARE_WRITE | FILE_SHARE_READ,
915 &Sa,
916 OPEN_ALWAYS,
917 FILE_ATTRIBUTE_NORMAL,
918 NULL);
919
920 Si.dwFlags |= STARTF_USESTDHANDLES;
921
922 if (hOut != INVALID_HANDLE_VALUE)
923 {
924 Si.hStdError = hOut;
925 Si.hStdOutput = hOut;
926 }
927
928 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &Pi);
929 WaitForSingleObject(Pi.hProcess, INFINITE);
930
931 //
932 // decompress tar archive, for tar.gz/tar.xz/tar.bz2
933 //
934 if (check_tar_archive(archive, tarName))
935 {
936 Log("Decompress tar archive...<%s>", tarName);
937
938 sprintf_s(StrBuf, sizeof(StrBuf), "ventoy\\7za.exe x -y -aoa -oX:\\ %s", tarName);
939
940 CreateProcessA(NULL, StrBuf, NULL, NULL, TRUE, flags, NULL, NULL, &Si, &NewPi);
941 WaitForSingleObject(NewPi.hProcess, INFINITE);
942
943 Log("Now delete %s", tarName);
944 DeleteFileA(tarName);
945 }
946
947 SAFE_CLOSE_HANDLE(hOut);
948 }
949 fl_shutdown();
950
951 End:
952
953 SAFE_CLOSE_HANDLE(hDrive);
954
955 return rc;
956 }
957
958 static int ProcessUnattendedInstallation(const char *script)
959 {
960 DWORD dw;
961 HKEY hKey;
962 LSTATUS Ret;
963 CHAR Letter;
964 CHAR CurDir[MAX_PATH];
965
966 Log("Copy unattended XML ...");
967
968 GetCurrentDirectory(sizeof(CurDir), CurDir);
969 Letter = CurDir[0];
970 if ((Letter >= 'A' && Letter <= 'Z') || (Letter >= 'a' && Letter <= 'z'))
971 {
972 Log("Current Drive Letter: %C", Letter);
973 }
974 else
975 {
976 Letter = 'X';
977 }
978
979 sprintf_s(CurDir, sizeof(CurDir), "%C:\\Autounattend.xml", Letter);
980 Log("Copy file <%s> --> <%s>", script, CurDir);
981 CopyFile(script, CurDir, FALSE);
982
983 Ret = RegCreateKeyEx(HKEY_LOCAL_MACHINE, "System\\Setup", 0, NULL, REG_OPTION_NON_VOLATILE, KEY_ALL_ACCESS, NULL, &hKey, &dw);
984 if (ERROR_SUCCESS == Ret)
985 {
986 Ret = RegSetValueEx(hKey, "UnattendFile", 0, REG_SZ, CurDir, (DWORD)(strlen(CurDir) + 1));
987 }
988
989 return 0;
990 }
991
992 static int VentoyHook(ventoy_os_param *param)
993 {
994 int rc;
995 CHAR Letter = 'A';
996 DISK_EXTENT DiskExtent;
997 DWORD Drives = GetLogicalDrives();
998 UINT8 UUID[16];
999 CHAR IsoPath[MAX_PATH];
1000
1001 Log("Logical Drives=0x%x Path:<%s>", Drives, param->vtoy_img_path);
1002
1003 if (IsUTF8Encode(param->vtoy_img_path))
1004 {
1005 Log("This file is UTF8 encoding\n");
1006 }
1007
1008 while (Drives)
1009 {
1010 if (Drives & 0x01)
1011 {
1012 sprintf_s(IsoPath, sizeof(IsoPath), "%C:\\%s", Letter, param->vtoy_img_path);
1013 if (IsPathExist(FALSE, "%s", IsoPath))
1014 {
1015 Log("File exist under %C:", Letter);
1016 if (GetPhyDiskUUID(Letter, UUID, &DiskExtent) == 0)
1017 {
1018 if (memcmp(UUID, param->vtoy_disk_guid, 16) == 0)
1019 {
1020 Log("Disk UUID match");
1021 break;
1022 }
1023 }
1024 }
1025 else
1026 {
1027 Log("File NOT exist under %C:", Letter);
1028 }
1029 }
1030
1031 Drives >>= 1;
1032 Letter++;
1033 }
1034
1035 if (Drives == 0)
1036 {
1037 Log("Failed to find ISO file");
1038 return 1;
1039 }
1040
1041 Log("Find ISO file <%s>", IsoPath);
1042
1043 rc = MountIsoFile(IsoPath, DiskExtent.DiskNumber);
1044 Log("Mount ISO FILE: %s", rc == 0 ? "SUCCESS" : "FAILED");
1045
1046 // for protect
1047 rc = DeleteVentoyPart2MountPoint(DiskExtent.DiskNumber);
1048 Log("Delete ventoy mountpoint: %s", rc == 0 ? "SUCCESS" : "NO NEED");
1049
1050 if (g_windows_data.auto_install_script[0])
1051 {
1052 sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", Letter, g_windows_data.auto_install_script);
1053 if (IsPathExist(FALSE, "%s", IsoPath))
1054 {
1055 Log("use auto install script %s...", IsoPath);
1056 ProcessUnattendedInstallation(IsoPath);
1057 }
1058 else
1059 {
1060 Log("auto install script %s not exist", IsoPath);
1061 }
1062 }
1063 else
1064 {
1065 Log("auto install no need");
1066 }
1067
1068 if (g_windows_data.injection_archive[0])
1069 {
1070 sprintf_s(IsoPath, sizeof(IsoPath), "%C:%s", Letter, g_windows_data.injection_archive);
1071 if (IsPathExist(FALSE, "%s", IsoPath))
1072 {
1073 Log("decompress injection archive %s...", IsoPath);
1074 DecompressInjectionArchive(IsoPath, DiskExtent.DiskNumber);
1075 }
1076 else
1077 {
1078 Log("injection archive %s not exist", IsoPath);
1079 }
1080 }
1081 else
1082 {
1083 Log("no injection archive found");
1084 }
1085
1086 return 0;
1087 }
1088
1089 const char * GetFileNameInPath(const char *fullpath)
1090 {
1091 int i;
1092 const char *pos = NULL;
1093
1094 if (strstr(fullpath, ":"))
1095 {
1096 for (i = (int)strlen(fullpath); i > 0; i--)
1097 {
1098 if (fullpath[i - 1] == '/' || fullpath[i - 1] == '\\')
1099 {
1100 return fullpath + i;
1101 }
1102 }
1103 }
1104
1105 return fullpath;
1106 }
1107
1108 int VentoyJump(INT argc, CHAR **argv, CHAR *LunchFile)
1109 {
1110 int rc = 1;
1111 DWORD Pos;
1112 DWORD PeStart;
1113 DWORD FileSize;
1114 BYTE *Buffer = NULL;
1115 CHAR ExeFileName[MAX_PATH];
1116
1117 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s", argv[0]);
1118 if (!IsPathExist(FALSE, "%s", ExeFileName))
1119 {
1120 Log("File %s NOT exist, now try %s.exe", ExeFileName, ExeFileName);
1121 sprintf_s(ExeFileName, sizeof(ExeFileName), "%s.exe", argv[0]);
1122
1123 Log("File %s exist ? %s", ExeFileName, IsPathExist(FALSE, "%s", ExeFileName) ? "YES" : "NO");
1124 }
1125
1126 if (ReadWholeFile2Buf(ExeFileName, (void **)&Buffer, &FileSize))
1127 {
1128 goto End;
1129 }
1130
1131 g_64bit_system = IsPe64(Buffer);
1132
1133 if (!IsPathExist(TRUE, "ventoy"))
1134 {
1135 if (!CreateDirectoryA("ventoy", NULL))
1136 {
1137 Log("Failed to create ventoy directory err:%u", GetLastError());
1138 goto End;
1139 }
1140 }
1141
1142 for (PeStart = 0; PeStart < FileSize; PeStart += 16)
1143 {
1144 if (CheckOsParam((ventoy_os_param *)(Buffer + PeStart)) &&
1145 CheckPeHead(Buffer + PeStart + sizeof(ventoy_os_param) + sizeof(ventoy_windows_data)))
1146 {
1147 Log("Find os pararm at %u", PeStart);
1148
1149 memcpy(&g_os_param, Buffer + PeStart, sizeof(ventoy_os_param));
1150 memcpy(&g_windows_data, Buffer + PeStart + sizeof(ventoy_os_param), sizeof(ventoy_windows_data));
1151 memcpy(g_os_param_reserved, g_os_param.vtoy_reserved, sizeof(g_os_param_reserved));
1152
1153 if (g_os_param_reserved[0] == 1)
1154 {
1155 Log("break here for debug .....");
1156 goto End;
1157 }
1158
1159 // convert / to \\
1160 for (Pos = 0; Pos < sizeof(g_os_param.vtoy_img_path) && g_os_param.vtoy_img_path[Pos]; Pos++)
1161 {
1162 if (g_os_param.vtoy_img_path[Pos] == '/')
1163 {
1164 g_os_param.vtoy_img_path[Pos] = '\\';
1165 }
1166 }
1167
1168 PeStart += sizeof(ventoy_os_param) + sizeof(ventoy_windows_data);
1169 sprintf_s(LunchFile, MAX_PATH, "ventoy\\%s", GetFileNameInPath(ExeFileName));
1170 SaveBuffer2File(LunchFile, Buffer + PeStart, FileSize - PeStart);
1171 break;
1172 }
1173 }
1174
1175 if (PeStart >= FileSize)
1176 {
1177 Log("OS param not found");
1178 goto End;
1179 }
1180
1181 if (g_os_param_reserved[0] == 2)
1182 {
1183 Log("skip hook for debug .....");
1184 rc = 0;
1185 goto End;
1186 }
1187
1188 rc = VentoyHook(&g_os_param);
1189
1190 End:
1191
1192 if (Buffer)
1193 {
1194 free(Buffer);
1195 }
1196
1197 return rc;
1198 }
1199
1200 int main(int argc, char **argv)
1201 {
1202 int i = 0;
1203 int rc = 0;
1204 CHAR *Pos = NULL;
1205 CHAR CurDir[MAX_PATH];
1206 CHAR LunchFile[MAX_PATH];
1207 STARTUPINFOA Si;
1208 PROCESS_INFORMATION Pi;
1209
1210 if (argv[0] && argv[0][0] && argv[0][1] == ':')
1211 {
1212 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
1213
1214 strcpy_s(LunchFile, sizeof(LunchFile), argv[0]);
1215 Pos = (char *)GetFileNameInPath(LunchFile);
1216
1217 strcat_s(CurDir, sizeof(CurDir), "\\");
1218 strcat_s(CurDir, sizeof(CurDir), Pos);
1219
1220 if (_stricmp(argv[0], CurDir) != 0)
1221 {
1222 *Pos = 0;
1223 SetCurrentDirectoryA(LunchFile);
1224 }
1225 }
1226
1227 Log("######## VentoyJump ##########");
1228 Log("argc = %d argv[0] = <%s>", argc, argv[0]);
1229
1230 if (Pos && *Pos == 0)
1231 {
1232 Log("Old current directory = <%s>", CurDir);
1233 Log("New current directory = <%s>", LunchFile);
1234 }
1235 else
1236 {
1237 GetCurrentDirectoryA(sizeof(CurDir), CurDir);
1238 Log("Current directory = <%s>", CurDir);
1239 }
1240
1241 GetStartupInfoA(&Si);
1242
1243 memset(LunchFile, 0, sizeof(LunchFile));
1244 rc = VentoyJump(argc, argv, LunchFile);
1245
1246 if (g_os_param_reserved[0] == 3)
1247 {
1248 Log("Open log for debug ...");
1249 sprintf_s(LunchFile, sizeof(LunchFile), "%s", "notepad.exe ventoy.log");
1250 }
1251 else
1252 {
1253 Si.dwFlags |= STARTF_USESHOWWINDOW;
1254 Si.wShowWindow = SW_HIDE;
1255 Log("Ventoy jump %s ...", rc == 0 ? "success" : "failed");
1256 }
1257
1258 CreateProcessA(NULL, LunchFile, NULL, NULL, FALSE, 0, NULL, NULL, &Si, &Pi);
1259
1260 while (rc)
1261 {
1262 Log("Ventoy hook failed, now wait and retry ...");
1263 Sleep(1000);
1264
1265 rc = VentoyHook(&g_os_param);
1266 }
1267
1268 WaitForSingleObject(Pi.hProcess, INFINITE);
1269
1270 return 0;
1271 }