]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Ventoy2Disk/Ventoy2Disk/PhyDrive.c
ed25f9677b752b0734cccc55a8f644913bcf04ce
[Ventoy.git] / Ventoy2Disk / Ventoy2Disk / PhyDrive.c
1 /******************************************************************************
2 * PhyDrive.c
3 *
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
5 * Copyright (c) 2011-2020, Pete Batard <pete@akeo.ie>
6 *
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.
11 *
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.
16 *
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/>.
19 *
20 */
21
22 #include <Windows.h>
23 #include <winternl.h>
24 #include <commctrl.h>
25 #include <initguid.h>
26 #include <vds.h>
27 #include "resource.h"
28 #include "Language.h"
29 #include "Ventoy2Disk.h"
30 #include "fat_filelib.h"
31 #include "ff.h"
32
33 /*
34 * Some code and functions in the file are copied from rufus.
35 * https://github.com/pbatard/rufus
36 */
37 #define VDS_SET_ERROR SetLastError
38 #define IVdsServiceLoader_LoadService(This, pwszMachineName, ppService) (This)->lpVtbl->LoadService(This, pwszMachineName, ppService)
39 #define IVdsServiceLoader_Release(This) (This)->lpVtbl->Release(This)
40 #define IVdsService_QueryProviders(This, masks, ppEnum) (This)->lpVtbl->QueryProviders(This, masks, ppEnum)
41 #define IVdsService_WaitForServiceReady(This) ((This)->lpVtbl->WaitForServiceReady(This))
42 #define IVdsService_CleanupObsoleteMountPoints(This) ((This)->lpVtbl->CleanupObsoleteMountPoints(This))
43 #define IVdsService_Refresh(This) ((This)->lpVtbl->Refresh(This))
44 #define IVdsService_Reenumerate(This) ((This)->lpVtbl->Reenumerate(This))
45 #define IVdsSwProvider_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
46 #define IVdsProvider_Release(This) (This)->lpVtbl->Release(This)
47 #define IVdsSwProvider_QueryPacks(This, ppEnum) (This)->lpVtbl->QueryPacks(This, ppEnum)
48 #define IVdsSwProvider_Release(This) (This)->lpVtbl->Release(This)
49 #define IVdsPack_QueryDisks(This, ppEnum) (This)->lpVtbl->QueryDisks(This, ppEnum)
50 #define IVdsDisk_GetProperties(This, pDiskProperties) (This)->lpVtbl->GetProperties(This, pDiskProperties)
51 #define IVdsDisk_Release(This) (This)->lpVtbl->Release(This)
52 #define IVdsDisk_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
53 #define IVdsAdvancedDisk_QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions) (This)->lpVtbl->QueryPartitions(This, ppPartitionPropArray, plNumberOfPartitions)
54 #define IVdsAdvancedDisk_DeletePartition(This, ullOffset, bForce, bForceProtected) (This)->lpVtbl->DeletePartition(This, ullOffset, bForce, bForceProtected)
55 #define IVdsAdvancedDisk_Clean(This, bForce, bForceOEM, bFullClean, ppAsync) (This)->lpVtbl->Clean(This, bForce, bForceOEM, bFullClean, ppAsync)
56 #define IVdsAdvancedDisk_Release(This) (This)->lpVtbl->Release(This)
57 #define IEnumVdsObject_Next(This, celt, ppObjectArray, pcFetched) (This)->lpVtbl->Next(This, celt, ppObjectArray, pcFetched)
58 #define IVdsPack_QueryVolumes(This, ppEnum) (This)->lpVtbl->QueryVolumes(This, ppEnum)
59 #define IVdsVolume_QueryInterface(This, riid, ppvObject) (This)->lpVtbl->QueryInterface(This, riid, ppvObject)
60 #define IVdsVolume_Release(This) (This)->lpVtbl->Release(This)
61 #define IVdsVolumeMF3_QueryVolumeGuidPathnames(This, pwszPathArray, pulNumberOfPaths) (This)->lpVtbl->QueryVolumeGuidPathnames(This,pwszPathArray,pulNumberOfPaths)
62 #define IVdsVolumeMF3_FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync) (This)->lpVtbl->FormatEx2(This, pwszFileSystemTypeName, usFileSystemRevision, ulDesiredUnitAllocationSize, pwszLabel, Options, ppAsync)
63 #define IVdsVolumeMF3_Release(This) (This)->lpVtbl->Release(This)
64 #define IVdsVolume_GetProperties(This, pVolumeProperties) (This)->lpVtbl->GetProperties(This,pVolumeProperties)
65 #define IVdsAsync_Cancel(This) (This)->lpVtbl->Cancel(This)
66 #define IVdsAsync_QueryStatus(This,pHrResult,pulPercentCompleted) (This)->lpVtbl->QueryStatus(This,pHrResult,pulPercentCompleted)
67 #define IVdsAsync_Wait(This,pHrResult,pAsyncOut) (This)->lpVtbl->Wait(This,pHrResult,pAsyncOut)
68 #define IVdsAsync_Release(This) (This)->lpVtbl->Release(This)
69
70 #define IUnknown_QueryInterface(This, a, b) (This)->lpVtbl->QueryInterface(This,a,b)
71 #define IUnknown_Release(This) (This)->lpVtbl->Release(This)
72
73 /*
74 * Delete all the partitions from a disk, using VDS
75 * Mostly copied from https://social.msdn.microsoft.com/Forums/vstudio/en-US/b90482ae-4e44-4b08-8731-81915030b32a/createpartition-using-vds-interface-throw-error-enointerface-dcom?forum=vcgeneral
76 */
77 BOOL DeletePartitions(DWORD DriveIndex, BOOL OnlyPart2)
78 {
79 BOOL r = FALSE;
80 HRESULT hr;
81 ULONG ulFetched;
82 wchar_t wPhysicalName[48];
83 IVdsServiceLoader *pLoader;
84 IVdsService *pService;
85 IEnumVdsObject *pEnum;
86 IUnknown *pUnk;
87
88 swprintf_s(wPhysicalName, ARRAYSIZE(wPhysicalName), L"\\\\?\\PhysicalDrive%lu", DriveIndex);
89
90 // Initialize COM
91 CoInitializeEx(NULL, COINIT_APARTMENTTHREADED);
92 CoInitializeSecurity(NULL, -1, NULL, NULL, RPC_C_AUTHN_LEVEL_CONNECT,
93 RPC_C_IMP_LEVEL_IMPERSONATE, NULL, 0, NULL);
94
95 // Create a VDS Loader Instance
96 hr = CoCreateInstance(&CLSID_VdsLoader, NULL, CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER,
97 &IID_IVdsServiceLoader, (void **)&pLoader);
98 if (hr != S_OK) {
99 VDS_SET_ERROR(hr);
100 Log("Could not create VDS Loader Instance: %u", LASTERR);
101 goto out;
102 }
103
104 // Load the VDS Service
105 hr = IVdsServiceLoader_LoadService(pLoader, L"", &pService);
106 IVdsServiceLoader_Release(pLoader);
107 if (hr != S_OK) {
108 VDS_SET_ERROR(hr);
109 Log("Could not load VDS Service: %u", LASTERR);
110 goto out;
111 }
112
113 // Wait for the Service to become ready if needed
114 hr = IVdsService_WaitForServiceReady(pService);
115 if (hr != S_OK) {
116 VDS_SET_ERROR(hr);
117 Log("VDS Service is not ready: %u", LASTERR);
118 goto out;
119 }
120
121 // Query the VDS Service Providers
122 hr = IVdsService_QueryProviders(pService, VDS_QUERY_SOFTWARE_PROVIDERS, &pEnum);
123 if (hr != S_OK) {
124 VDS_SET_ERROR(hr);
125 Log("Could not query VDS Service Providers: %u", LASTERR);
126 goto out;
127 }
128
129 while (IEnumVdsObject_Next(pEnum, 1, &pUnk, &ulFetched) == S_OK) {
130 IVdsProvider *pProvider;
131 IVdsSwProvider *pSwProvider;
132 IEnumVdsObject *pEnumPack;
133 IUnknown *pPackUnk;
134
135 // Get VDS Provider
136 hr = IUnknown_QueryInterface(pUnk, &IID_IVdsProvider, (void **)&pProvider);
137 IUnknown_Release(pUnk);
138 if (hr != S_OK) {
139 VDS_SET_ERROR(hr);
140 Log("Could not get VDS Provider: %u", LASTERR);
141 goto out;
142 }
143
144 // Get VDS Software Provider
145 hr = IVdsSwProvider_QueryInterface(pProvider, &IID_IVdsSwProvider, (void **)&pSwProvider);
146 IVdsProvider_Release(pProvider);
147 if (hr != S_OK) {
148 VDS_SET_ERROR(hr);
149 Log("Could not get VDS Software Provider: %u", LASTERR);
150 goto out;
151 }
152
153 // Get VDS Software Provider Packs
154 hr = IVdsSwProvider_QueryPacks(pSwProvider, &pEnumPack);
155 IVdsSwProvider_Release(pSwProvider);
156 if (hr != S_OK) {
157 VDS_SET_ERROR(hr);
158 Log("Could not get VDS Software Provider Packs: %u", LASTERR);
159 goto out;
160 }
161
162 // Enumerate Provider Packs
163 while (IEnumVdsObject_Next(pEnumPack, 1, &pPackUnk, &ulFetched) == S_OK) {
164 IVdsPack *pPack;
165 IEnumVdsObject *pEnumDisk;
166 IUnknown *pDiskUnk;
167
168 hr = IUnknown_QueryInterface(pPackUnk, &IID_IVdsPack, (void **)&pPack);
169 IUnknown_Release(pPackUnk);
170 if (hr != S_OK) {
171 VDS_SET_ERROR(hr);
172 Log("Could not query VDS Software Provider Pack: %u", LASTERR);
173 goto out;
174 }
175
176 // Use the pack interface to access the disks
177 hr = IVdsPack_QueryDisks(pPack, &pEnumDisk);
178 if (hr != S_OK) {
179 VDS_SET_ERROR(hr);
180 Log("Could not query VDS disks: %u", LASTERR);
181 goto out;
182 }
183
184 // List disks
185 while (IEnumVdsObject_Next(pEnumDisk, 1, &pDiskUnk, &ulFetched) == S_OK) {
186 VDS_DISK_PROP diskprop;
187 VDS_PARTITION_PROP* prop_array;
188 LONG i, prop_array_size;
189 IVdsDisk *pDisk;
190 IVdsAdvancedDisk *pAdvancedDisk;
191
192 // Get the disk interface.
193 hr = IUnknown_QueryInterface(pDiskUnk, &IID_IVdsDisk, (void **)&pDisk);
194 if (hr != S_OK) {
195 VDS_SET_ERROR(hr);
196 Log("Could not query VDS Disk Interface: %u", LASTERR);
197 goto out;
198 }
199
200 // Get the disk properties
201 hr = IVdsDisk_GetProperties(pDisk, &diskprop);
202 if (hr != S_OK) {
203 VDS_SET_ERROR(hr);
204 Log("Could not query VDS Disk Properties: %u", LASTERR);
205 goto out;
206 }
207
208 // Isolate the disk we want
209 if (_wcsicmp(wPhysicalName, diskprop.pwszName) != 0) {
210 IVdsDisk_Release(pDisk);
211 continue;
212 }
213
214 // Instantiate the AdvanceDisk interface for our disk.
215 hr = IVdsDisk_QueryInterface(pDisk, &IID_IVdsAdvancedDisk, (void **)&pAdvancedDisk);
216 IVdsDisk_Release(pDisk);
217 if (hr != S_OK) {
218 VDS_SET_ERROR(hr);
219 Log("Could not access VDS Advanced Disk interface: %u", LASTERR);
220 goto out;
221 }
222
223 // Query the partition data, so we can get the start offset, which we need for deletion
224 hr = IVdsAdvancedDisk_QueryPartitions(pAdvancedDisk, &prop_array, &prop_array_size);
225 if (hr == S_OK) {
226 Log("Deleting ALL partition(s) from disk '%S':", diskprop.pwszName);
227 // Now go through each partition
228 for (i = 0; i < prop_array_size; i++) {
229
230 Log("* Partition %d (offset: %lld, size: %llu)", prop_array[i].ulPartitionNumber,
231 prop_array[i].ullOffset, (ULONGLONG)prop_array[i].ullSize);
232
233 if (OnlyPart2 && prop_array[i].ullOffset == 2048*512)
234 {
235 Log("Skip this partition...");
236 continue;
237 }
238
239
240 hr = IVdsAdvancedDisk_DeletePartition(pAdvancedDisk, prop_array[i].ullOffset, TRUE, TRUE);
241 if (hr != S_OK) {
242 r = FALSE;
243 VDS_SET_ERROR(hr);
244 Log("Could not delete partitions: %u", LASTERR);
245 }
246 }
247 r = TRUE;
248 }
249 else {
250 Log("No partition to delete on disk '%S'", diskprop.pwszName);
251 r = TRUE;
252 }
253 CoTaskMemFree(prop_array);
254
255 #if 0
256 // Issue a Clean while we're at it
257 HRESULT hr2 = E_FAIL;
258 ULONG completed;
259 IVdsAsync* pAsync;
260 hr = IVdsAdvancedDisk_Clean(pAdvancedDisk, TRUE, FALSE, FALSE, &pAsync);
261 while (SUCCEEDED(hr)) {
262 if (IS_ERROR(FormatStatus)) {
263 IVdsAsync_Cancel(pAsync);
264 break;
265 }
266 hr = IVdsAsync_QueryStatus(pAsync, &hr2, &completed);
267 if (SUCCEEDED(hr)) {
268 hr = hr2;
269 if (hr == S_OK)
270 break;
271 if (hr == VDS_E_OPERATION_PENDING)
272 hr = S_OK;
273 }
274 Sleep(500);
275 }
276 if (hr != S_OK) {
277 VDS_SET_ERROR(hr);
278 Log("Could not clean disk: %s", LASTERR);
279 }
280 #endif
281 IVdsAdvancedDisk_Release(pAdvancedDisk);
282 goto out;
283 }
284 }
285 }
286
287 out:
288 return r;
289 }
290
291
292 static DWORD GetVentoyVolumeName(int PhyDrive, UINT32 StartSectorId, CHAR *NameBuf, UINT32 BufLen, BOOL DelSlash)
293 {
294 size_t len;
295 BOOL bRet;
296 DWORD dwSize;
297 HANDLE hDrive;
298 HANDLE hVolume;
299 UINT64 PartOffset;
300 DWORD Status = ERROR_NOT_FOUND;
301 DISK_EXTENT *pExtents = NULL;
302 CHAR VolumeName[MAX_PATH] = { 0 };
303 VOLUME_DISK_EXTENTS DiskExtents;
304
305 PartOffset = 512ULL * StartSectorId;
306
307 Log("GetVentoyVolumeName PhyDrive %d PartOffset:%llu", PhyDrive, (ULONGLONG)PartOffset);
308
309 hVolume = FindFirstVolumeA(VolumeName, sizeof(VolumeName));
310 if (hVolume == INVALID_HANDLE_VALUE)
311 {
312 return 1;
313 }
314
315 do {
316
317 len = strlen(VolumeName);
318 Log("Find volume:%s", VolumeName);
319
320 VolumeName[len - 1] = 0;
321
322 hDrive = CreateFileA(VolumeName, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
323 if (hDrive == INVALID_HANDLE_VALUE)
324 {
325 continue;
326 }
327
328 bRet = DeviceIoControl(hDrive,
329 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
330 NULL,
331 0,
332 &DiskExtents,
333 (DWORD)(sizeof(DiskExtents)),
334 (LPDWORD)&dwSize,
335 NULL);
336
337 Log("IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS bRet:%u code:%u", bRet, LASTERR);
338 Log("NumberOfDiskExtents:%u DiskNumber:%u", DiskExtents.NumberOfDiskExtents, DiskExtents.Extents[0].DiskNumber);
339
340 if (bRet && DiskExtents.NumberOfDiskExtents == 1)
341 {
342 pExtents = DiskExtents.Extents;
343
344 Log("This volume DiskNumber:%u offset:%llu", pExtents->DiskNumber, (ULONGLONG)pExtents->StartingOffset.QuadPart);
345 if ((int)pExtents->DiskNumber == PhyDrive && pExtents->StartingOffset.QuadPart == PartOffset)
346 {
347 Log("This volume match");
348
349 if (!DelSlash)
350 {
351 VolumeName[len - 1] = '\\';
352 }
353
354 sprintf_s(NameBuf, BufLen, "%s", VolumeName);
355 Status = ERROR_SUCCESS;
356 CloseHandle(hDrive);
357 break;
358 }
359 }
360
361 CloseHandle(hDrive);
362 } while (FindNextVolumeA(hVolume, VolumeName, sizeof(VolumeName)));
363
364 FindVolumeClose(hVolume);
365
366 Log("GetVentoyVolumeName return %u", Status);
367 return Status;
368 }
369
370 static int GetLettersBelongPhyDrive(int PhyDrive, char *DriveLetters, size_t Length)
371 {
372 int n = 0;
373 DWORD DataSize = 0;
374 CHAR *Pos = NULL;
375 CHAR *StringBuf = NULL;
376
377 DataSize = GetLogicalDriveStringsA(0, NULL);
378 StringBuf = (CHAR *)malloc(DataSize + 1);
379 if (StringBuf == NULL)
380 {
381 return 1;
382 }
383
384 GetLogicalDriveStringsA(DataSize, StringBuf);
385
386 for (Pos = StringBuf; *Pos; Pos += strlen(Pos) + 1)
387 {
388 if (n < (int)Length && PhyDrive == GetPhyDriveByLogicalDrive(Pos[0]))
389 {
390 Log("%C: is belong to phydrive%d", Pos[0], PhyDrive);
391 DriveLetters[n++] = Pos[0];
392 }
393 }
394
395 free(StringBuf);
396 return 0;
397 }
398
399 static HANDLE GetPhysicalHandle(int Drive, BOOLEAN bLockDrive, BOOLEAN bWriteAccess, BOOLEAN bWriteShare)
400 {
401 int i;
402 DWORD dwSize;
403 DWORD LastError;
404 UINT64 EndTime;
405 HANDLE hDrive = INVALID_HANDLE_VALUE;
406 CHAR PhyDrive[128];
407 CHAR DevPath[MAX_PATH] = { 0 };
408
409 safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", Drive);
410
411 if (0 == QueryDosDeviceA(PhyDrive + 4, DevPath, sizeof(DevPath)))
412 {
413 Log("QueryDosDeviceA failed error:%u", GetLastError());
414 strcpy_s(DevPath, sizeof(DevPath), "???");
415 }
416 else
417 {
418 Log("QueryDosDeviceA success %s", DevPath);
419 }
420
421 for (i = 0; i < DRIVE_ACCESS_RETRIES; i++)
422 {
423 // Try without FILE_SHARE_WRITE (unless specifically requested) so that
424 // we won't be bothered by the OS or other apps when we set up our data.
425 // However this means we might have to wait for an access gap...
426 // We keep FILE_SHARE_READ though, as this shouldn't hurt us any, and is
427 // required for enumeration.
428 hDrive = CreateFileA(PhyDrive,
429 GENERIC_READ | (bWriteAccess ? GENERIC_WRITE : 0),
430 FILE_SHARE_READ | (bWriteShare ? FILE_SHARE_WRITE : 0),
431 NULL,
432 OPEN_EXISTING,
433 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
434 NULL);
435
436 LastError = GetLastError();
437 Log("[%d] CreateFileA %s code:%u %p", i, PhyDrive, LastError, hDrive);
438
439 if (hDrive != INVALID_HANDLE_VALUE)
440 {
441 break;
442 }
443
444 if ((LastError != ERROR_SHARING_VIOLATION) && (LastError != ERROR_ACCESS_DENIED))
445 {
446 break;
447 }
448
449 if (i == 0)
450 {
451 Log("Waiting for access on %s [%s]...", PhyDrive, DevPath);
452 }
453 else if (!bWriteShare && (i > DRIVE_ACCESS_RETRIES / 3))
454 {
455 // If we can't seem to get a hold of the drive for some time, try to enable FILE_SHARE_WRITE...
456 Log("Warning: Could not obtain exclusive rights. Retrying with write sharing enabled...");
457 bWriteShare = TRUE;
458
459 // Try to report the process that is locking the drive
460 // We also use bit 6 as a flag to indicate that SearchProcess was called.
461 //access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE) | 0x40;
462
463 }
464 Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
465 }
466
467 if (hDrive == INVALID_HANDLE_VALUE)
468 {
469 Log("Could not open %s %u", PhyDrive, LASTERR);
470 goto End;
471 }
472
473 if (bWriteAccess)
474 {
475 Log("Opened %s for %s write access", PhyDrive, bWriteShare ? "shared" : "exclusive");
476 }
477
478 if (bLockDrive)
479 {
480 if (DeviceIoControl(hDrive, FSCTL_ALLOW_EXTENDED_DASD_IO, NULL, 0, NULL, 0, &dwSize, NULL))
481 {
482 Log("I/O boundary checks disabled");
483 }
484
485 EndTime = GetTickCount64() + DRIVE_ACCESS_TIMEOUT;
486
487 do {
488 if (DeviceIoControl(hDrive, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL))
489 {
490 Log("FSCTL_LOCK_VOLUME success");
491 goto End;
492 }
493 Sleep(DRIVE_ACCESS_TIMEOUT / DRIVE_ACCESS_RETRIES);
494 } while (GetTickCount64() < EndTime);
495
496 // If we reached this section, either we didn't manage to get a lock or the user cancelled
497 Log("Could not lock access to %s %u", PhyDrive, LASTERR);
498
499 // See if we can report the processes are accessing the drive
500 //if (!IS_ERROR(FormatStatus) && (access_mask == 0))
501 // access_mask = SearchProcess(DevPath, SEARCH_PROCESS_TIMEOUT, TRUE, TRUE, FALSE);
502 // Try to continue if the only access rights we saw were for read-only
503 //if ((access_mask & 0x07) != 0x01)
504 // safe_closehandle(hDrive);
505
506 CHECK_CLOSE_HANDLE(hDrive);
507 }
508
509 End:
510
511 if (hDrive == INVALID_HANDLE_VALUE)
512 {
513 Log("Can get handle of %s, maybe some process control it.", DevPath);
514 }
515
516 return hDrive;
517 }
518
519 int GetPhyDriveByLogicalDrive(int DriveLetter)
520 {
521 BOOL Ret;
522 DWORD dwSize;
523 HANDLE Handle;
524 VOLUME_DISK_EXTENTS DiskExtents;
525 CHAR PhyPath[128];
526
527 safe_sprintf(PhyPath, "\\\\.\\%C:", (CHAR)DriveLetter);
528
529 Handle = CreateFileA(PhyPath, GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, OPEN_EXISTING, 0, 0);
530 if (Handle == INVALID_HANDLE_VALUE)
531 {
532 Log("Could not open the disk<%s>, error:%u", PhyPath, LASTERR);
533 return -1;
534 }
535
536 Ret = DeviceIoControl(Handle,
537 IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS,
538 NULL,
539 0,
540 &DiskExtents,
541 (DWORD)(sizeof(DiskExtents)),
542 (LPDWORD)&dwSize,
543 NULL);
544
545 if (!Ret || DiskExtents.NumberOfDiskExtents == 0)
546 {
547 Log("DeviceIoControl IOCTL_VOLUME_GET_VOLUME_DISK_EXTENTS failed %s, error:%u", PhyPath, LASTERR);
548 CHECK_CLOSE_HANDLE(Handle);
549 return -1;
550 }
551 CHECK_CLOSE_HANDLE(Handle);
552
553 Log("LogicalDrive:%s PhyDrive:%d Offset:%llu ExtentLength:%llu",
554 PhyPath,
555 DiskExtents.Extents[0].DiskNumber,
556 DiskExtents.Extents[0].StartingOffset.QuadPart,
557 DiskExtents.Extents[0].ExtentLength.QuadPart
558 );
559
560 return (int)DiskExtents.Extents[0].DiskNumber;
561 }
562
563 int GetAllPhysicalDriveInfo(PHY_DRIVE_INFO *pDriveList, DWORD *pDriveCount)
564 {
565 int i;
566 int Count;
567 int id;
568 int Letter = 'A';
569 BOOL bRet;
570 DWORD dwBytes;
571 DWORD DriveCount = 0;
572 HANDLE Handle = INVALID_HANDLE_VALUE;
573 CHAR PhyDrive[128];
574 PHY_DRIVE_INFO *CurDrive = pDriveList;
575 GET_LENGTH_INFORMATION LengthInfo;
576 STORAGE_PROPERTY_QUERY Query;
577 STORAGE_DESCRIPTOR_HEADER DevDescHeader;
578 STORAGE_DEVICE_DESCRIPTOR *pDevDesc;
579 int PhyDriveId[VENTOY_MAX_PHY_DRIVE];
580
581 Count = GetPhysicalDriveCount();
582
583 for (i = 0; i < Count && i < VENTOY_MAX_PHY_DRIVE; i++)
584 {
585 PhyDriveId[i] = i;
586 }
587
588 dwBytes = GetLogicalDrives();
589 Log("Logical Drives: 0x%x", dwBytes);
590 while (dwBytes)
591 {
592 if (dwBytes & 0x01)
593 {
594 id = GetPhyDriveByLogicalDrive(Letter);
595 Log("%C --> %d", Letter, id);
596 if (id >= 0)
597 {
598 for (i = 0; i < Count; i++)
599 {
600 if (PhyDriveId[i] == id)
601 {
602 break;
603 }
604 }
605
606 if (i >= Count)
607 {
608 Log("Add phy%d to list", i);
609 PhyDriveId[Count] = id;
610 Count++;
611 }
612 }
613 }
614
615 Letter++;
616 dwBytes >>= 1;
617 }
618
619 for (i = 0; i < Count && DriveCount < VENTOY_MAX_PHY_DRIVE; i++)
620 {
621 CHECK_CLOSE_HANDLE(Handle);
622
623 safe_sprintf(PhyDrive, "\\\\.\\PhysicalDrive%d", PhyDriveId[i]);
624 Handle = CreateFileA(PhyDrive, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
625 Log("Create file Handle:%p %s status:%u", Handle, PhyDrive, LASTERR);
626
627 if (Handle == INVALID_HANDLE_VALUE)
628 {
629 continue;
630 }
631
632 bRet = DeviceIoControl(Handle,
633 IOCTL_DISK_GET_LENGTH_INFO, NULL,
634 0,
635 &LengthInfo,
636 sizeof(LengthInfo),
637 &dwBytes,
638 NULL);
639 if (!bRet)
640 {
641 Log("DeviceIoControl IOCTL_DISK_GET_LENGTH_INFO failed error:%u", LASTERR);
642 continue;
643 }
644
645 Log("PHYSICALDRIVE%d size %llu bytes", i, (ULONGLONG)LengthInfo.Length.QuadPart);
646
647 Query.PropertyId = StorageDeviceProperty;
648 Query.QueryType = PropertyStandardQuery;
649
650 bRet = DeviceIoControl(Handle,
651 IOCTL_STORAGE_QUERY_PROPERTY,
652 &Query,
653 sizeof(Query),
654 &DevDescHeader,
655 sizeof(STORAGE_DESCRIPTOR_HEADER),
656 &dwBytes,
657 NULL);
658 if (!bRet)
659 {
660 Log("DeviceIoControl1 error:%u dwBytes:%u", LASTERR, dwBytes);
661 continue;
662 }
663
664 pDevDesc = (STORAGE_DEVICE_DESCRIPTOR *)malloc(DevDescHeader.Size);
665 if (!pDevDesc)
666 {
667 Log("failed to malloc error:%u len:%u", LASTERR, DevDescHeader.Size);
668 continue;
669 }
670
671 bRet = DeviceIoControl(Handle,
672 IOCTL_STORAGE_QUERY_PROPERTY,
673 &Query,
674 sizeof(Query),
675 pDevDesc,
676 DevDescHeader.Size,
677 &dwBytes,
678 NULL);
679 if (!bRet)
680 {
681 Log("DeviceIoControl2 error:%u dwBytes:%u", LASTERR, dwBytes);
682 free(pDevDesc);
683 continue;
684 }
685
686 CurDrive->PhyDrive = i;
687 CurDrive->SizeInBytes = LengthInfo.Length.QuadPart;
688 CurDrive->DeviceType = pDevDesc->DeviceType;
689 CurDrive->RemovableMedia = pDevDesc->RemovableMedia;
690 CurDrive->BusType = pDevDesc->BusType;
691
692 if (pDevDesc->VendorIdOffset)
693 {
694 safe_strcpy(CurDrive->VendorId, (char *)pDevDesc + pDevDesc->VendorIdOffset);
695 TrimString(CurDrive->VendorId);
696 }
697
698 if (pDevDesc->ProductIdOffset)
699 {
700 safe_strcpy(CurDrive->ProductId, (char *)pDevDesc + pDevDesc->ProductIdOffset);
701 TrimString(CurDrive->ProductId);
702 }
703
704 if (pDevDesc->ProductRevisionOffset)
705 {
706 safe_strcpy(CurDrive->ProductRev, (char *)pDevDesc + pDevDesc->ProductRevisionOffset);
707 TrimString(CurDrive->ProductRev);
708 }
709
710 if (pDevDesc->SerialNumberOffset)
711 {
712 safe_strcpy(CurDrive->SerialNumber, (char *)pDevDesc + pDevDesc->SerialNumberOffset);
713 TrimString(CurDrive->SerialNumber);
714 }
715
716 CurDrive++;
717 DriveCount++;
718
719 free(pDevDesc);
720
721 CHECK_CLOSE_HANDLE(Handle);
722 }
723
724 for (i = 0, CurDrive = pDriveList; i < (int)DriveCount; i++, CurDrive++)
725 {
726 Log("PhyDrv:%d BusType:%-4s Removable:%u Size:%dGB(%llu) Name:%s %s",
727 CurDrive->PhyDrive, GetBusTypeString(CurDrive->BusType), CurDrive->RemovableMedia,
728 GetHumanReadableGBSize(CurDrive->SizeInBytes), CurDrive->SizeInBytes,
729 CurDrive->VendorId, CurDrive->ProductId);
730 }
731
732 *pDriveCount = DriveCount;
733
734 return 0;
735 }
736
737
738 static HANDLE g_FatPhyDrive;
739 static UINT64 g_Part2StartSec;
740 static int GetVentoyVersionFromFatFile(CHAR *VerBuf, size_t BufLen)
741 {
742 int rc = 1;
743 int size = 0;
744 char *buf = NULL;
745 void *flfile = NULL;
746
747 flfile = fl_fopen("/grub/grub.cfg", "rb");
748 if (flfile)
749 {
750 fl_fseek(flfile, 0, SEEK_END);
751 size = (int)fl_ftell(flfile);
752
753 fl_fseek(flfile, 0, SEEK_SET);
754
755 buf = (char *)malloc(size + 1);
756 if (buf)
757 {
758 fl_fread(buf, 1, size, flfile);
759 buf[size] = 0;
760
761 rc = 0;
762 sprintf_s(VerBuf, BufLen, "%s", ParseVentoyVersionFromString(buf));
763 free(buf);
764 }
765
766 fl_fclose(flfile);
767 }
768
769 return rc;
770 }
771
772 static int VentoyFatDiskRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
773 {
774 DWORD dwSize;
775 BOOL bRet;
776 DWORD ReadSize;
777 LARGE_INTEGER liCurrentPosition;
778
779 liCurrentPosition.QuadPart = Sector + g_Part2StartSec;
780 liCurrentPosition.QuadPart *= 512;
781 SetFilePointerEx(g_FatPhyDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
782
783 ReadSize = (DWORD)(SectorCount * 512);
784
785 bRet = ReadFile(g_FatPhyDrive, Buffer, ReadSize, &dwSize, NULL);
786 if (bRet == FALSE || dwSize != ReadSize)
787 {
788 Log("ReadFile error bRet:%u WriteSize:%u dwSize:%u ErrCode:%u\n", bRet, ReadSize, dwSize, LASTERR);
789 }
790
791 return 1;
792 }
793
794
795 int GetVentoyVerInPhyDrive(const PHY_DRIVE_INFO *pDriveInfo, CHAR *VerBuf, size_t BufLen)
796 {
797 int rc = 0;
798 HANDLE hDrive;
799
800 hDrive = GetPhysicalHandle(pDriveInfo->PhyDrive, FALSE, FALSE, FALSE);
801 if (hDrive == INVALID_HANDLE_VALUE)
802 {
803 return 1;
804 }
805
806 g_FatPhyDrive = hDrive;
807 g_Part2StartSec = (pDriveInfo->SizeInBytes - VENTOY_EFI_PART_SIZE) / 512;
808
809 Log("Parse FAT fs...");
810
811 fl_init();
812
813 if (0 == fl_attach_media(VentoyFatDiskRead, NULL))
814 {
815 rc = GetVentoyVersionFromFatFile(VerBuf, BufLen);
816 }
817 else
818 {
819 rc = 1;
820 }
821
822 fl_shutdown();
823
824 CHECK_CLOSE_HANDLE(hDrive);
825
826 return rc;
827 }
828
829
830
831
832
833 static unsigned int g_disk_unxz_len = 0;
834 static BYTE *g_part_img_pos = NULL;
835 static BYTE *g_part_img_buf[VENTOY_EFI_PART_SIZE / SIZE_1MB];
836
837
838 static int VentoyFatMemRead(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
839 {
840 uint32 i;
841 uint32 offset;
842 BYTE *MbBuf = NULL;
843
844 for (i = 0; i < SectorCount; i++)
845 {
846 offset = (Sector + i) * 512;
847
848 if (g_part_img_buf[1] == NULL)
849 {
850 MbBuf = g_part_img_buf[0] + offset;
851 memcpy(Buffer + i * 512, MbBuf, 512);
852 }
853 else
854 {
855 MbBuf = g_part_img_buf[offset / SIZE_1MB];
856 memcpy(Buffer + i * 512, MbBuf + (offset % SIZE_1MB), 512);
857 }
858 }
859
860 return 1;
861 }
862
863
864 static int VentoyFatMemWrite(uint32 Sector, uint8 *Buffer, uint32 SectorCount)
865 {
866 uint32 i;
867 uint32 offset;
868 BYTE *MbBuf = NULL;
869
870 for (i = 0; i < SectorCount; i++)
871 {
872 offset = (Sector + i) * 512;
873
874 if (g_part_img_buf[1] == NULL)
875 {
876 MbBuf = g_part_img_buf[0] + offset;
877 memcpy(MbBuf, Buffer + i * 512, 512);
878 }
879 else
880 {
881 MbBuf = g_part_img_buf[offset / SIZE_1MB];
882 memcpy(MbBuf + (offset % SIZE_1MB), Buffer + i * 512, 512);
883 }
884 }
885
886 return 1;
887 }
888
889 int VentoyProcSecureBoot(BOOL SecureBoot)
890 {
891 int rc = 0;
892 int size;
893 char *filebuf = NULL;
894 void *file = NULL;
895
896 Log("VentoyProcSecureBoot %d ...", SecureBoot);
897
898 if (SecureBoot)
899 {
900 Log("Secure boot is enabled ...");
901 return 0;
902 }
903
904 fl_init();
905
906 if (0 == fl_attach_media(VentoyFatMemRead, VentoyFatMemWrite))
907 {
908 file = fl_fopen("/EFI/BOOT/grubx64_real.efi", "rb");
909 Log("Open ventoy efi file %p ", file);
910 if (file)
911 {
912 fl_fseek(file, 0, SEEK_END);
913 size = (int)fl_ftell(file);
914 fl_fseek(file, 0, SEEK_SET);
915
916 Log("ventoy efi file size %d ...", size);
917
918 filebuf = (char *)malloc(size);
919 if (filebuf)
920 {
921 fl_fread(filebuf, 1, size, file);
922 }
923
924 fl_fclose(file);
925
926 Log("Now delete all efi files ...");
927 fl_remove("/EFI/BOOT/BOOTX64.EFI");
928 fl_remove("/EFI/BOOT/grubx64.efi");
929 fl_remove("/EFI/BOOT/grubx64_real.efi");
930 fl_remove("/EFI/BOOT/MokManager.efi");
931
932 file = fl_fopen("/EFI/BOOT/BOOTX64.EFI", "wb");
933 Log("Open bootx64 efi file %p ", file);
934 if (file)
935 {
936 if (filebuf)
937 {
938 fl_fwrite(filebuf, 1, size, file);
939 }
940
941 fl_fflush(file);
942 fl_fclose(file);
943 }
944
945 if (filebuf)
946 {
947 free(filebuf);
948 }
949 }
950 }
951 else
952 {
953 rc = 1;
954 }
955
956 fl_shutdown();
957
958 return rc;
959 }
960
961
962
963 static int disk_xz_flush(void *src, unsigned int size)
964 {
965 unsigned int i;
966 BYTE *buf = (BYTE *)src;
967
968 for (i = 0; i < size; i++)
969 {
970 *g_part_img_pos = *buf++;
971
972 g_disk_unxz_len++;
973 if ((g_disk_unxz_len % SIZE_1MB) == 0)
974 {
975 g_part_img_pos = g_part_img_buf[g_disk_unxz_len / SIZE_1MB];
976 }
977 else
978 {
979 g_part_img_pos++;
980 }
981 }
982
983 return (int)size;
984 }
985
986 static void unxz_error(char *x)
987 {
988 Log("%s", x);
989 }
990
991 static BOOL TryWritePart2(HANDLE hDrive, UINT64 StartSectorId)
992 {
993 BOOL bRet;
994 DWORD TrySize = 16 * 1024;
995 DWORD dwSize;
996 BYTE *Buffer = NULL;
997 unsigned char *data = NULL;
998 LARGE_INTEGER liCurrentPosition;
999
1000 liCurrentPosition.QuadPart = StartSectorId * 512;
1001 SetFilePointerEx(hDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
1002
1003 Buffer = malloc(TrySize);
1004
1005 bRet = WriteFile(hDrive, Buffer, TrySize, &dwSize, NULL);
1006
1007 free(Buffer);
1008
1009 Log("Try write part2 bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
1010
1011 if (bRet && dwSize == TrySize)
1012 {
1013 return TRUE;
1014 }
1015
1016 return FALSE;
1017 }
1018
1019 static int FormatPart2Fat(HANDLE hDrive, UINT64 StartSectorId)
1020 {
1021 int i;
1022 int rc = 0;
1023 int len = 0;
1024 int writelen = 0;
1025 int partwrite = 0;
1026 DWORD dwSize = 0;
1027 BOOL bRet;
1028 unsigned char *data = NULL;
1029 LARGE_INTEGER liCurrentPosition;
1030
1031 Log("FormatPart2Fat ...");
1032
1033 rc = ReadWholeFileToBuf(VENTOY_FILE_DISK_IMG, 0, (void **)&data, &len);
1034 if (rc)
1035 {
1036 Log("Failed to read img file %p %u", data, len);
1037 return 1;
1038 }
1039
1040 liCurrentPosition.QuadPart = StartSectorId * 512;
1041 SetFilePointerEx(hDrive, liCurrentPosition, &liCurrentPosition, FILE_BEGIN);
1042
1043 memset(g_part_img_buf, 0, sizeof(g_part_img_buf));
1044
1045 g_part_img_buf[0] = (BYTE *)malloc(VENTOY_EFI_PART_SIZE);
1046 if (g_part_img_buf[0])
1047 {
1048 Log("Malloc whole img buffer success, now decompress ...");
1049 unxz(data, len, NULL, NULL, g_part_img_buf[0], &writelen, unxz_error);
1050
1051 if (len == writelen)
1052 {
1053 Log("decompress finished success");
1054
1055 VentoyProcSecureBoot(g_SecureBoot);
1056
1057 for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
1058 {
1059 dwSize = 0;
1060 bRet = WriteFile(hDrive, g_part_img_buf[0] + i * SIZE_1MB, SIZE_1MB, &dwSize, NULL);
1061 Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
1062
1063 if (!bRet)
1064 {
1065 rc = 1;
1066 goto End;
1067 }
1068
1069 PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i);
1070 }
1071 }
1072 else
1073 {
1074 rc = 1;
1075 Log("decompress finished failed");
1076 goto End;
1077 }
1078 }
1079 else
1080 {
1081 Log("Failed to malloc whole img size %u, now split it", VENTOY_EFI_PART_SIZE);
1082
1083 partwrite = 1;
1084 for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
1085 {
1086 g_part_img_buf[i] = (BYTE *)malloc(SIZE_1MB);
1087 if (g_part_img_buf[i] == NULL)
1088 {
1089 rc = 1;
1090 goto End;
1091 }
1092 }
1093
1094 Log("Malloc part img buffer success, now decompress ...");
1095
1096 g_part_img_pos = g_part_img_buf[0];
1097
1098 unxz(data, len, NULL, disk_xz_flush, NULL, NULL, unxz_error);
1099
1100 if (g_disk_unxz_len == VENTOY_EFI_PART_SIZE)
1101 {
1102 Log("decompress finished success");
1103
1104 VentoyProcSecureBoot(g_SecureBoot);
1105
1106 for (int i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
1107 {
1108 dwSize = 0;
1109 bRet = WriteFile(hDrive, g_part_img_buf[i], SIZE_1MB, &dwSize, NULL);
1110 Log("Write part data bRet:%u dwSize:%u code:%u", bRet, dwSize, LASTERR);
1111
1112 if (!bRet)
1113 {
1114 rc = 1;
1115 goto End;
1116 }
1117
1118 PROGRESS_BAR_SET_POS(PT_WRITE_VENTOY_START + i);
1119 }
1120 }
1121 else
1122 {
1123 rc = 1;
1124 Log("decompress finished failed");
1125 goto End;
1126 }
1127 }
1128
1129 End:
1130
1131 if (data) free(data);
1132
1133 if (partwrite)
1134 {
1135 for (i = 0; i < VENTOY_EFI_PART_SIZE / SIZE_1MB; i++)
1136 {
1137 if (g_part_img_buf[i]) free(g_part_img_buf[i]);
1138 }
1139 }
1140 else
1141 {
1142 if (g_part_img_buf[0]) free(g_part_img_buf[0]);
1143 }
1144
1145 return rc;
1146 }
1147
1148 static int WriteGrubStage1ToPhyDrive(HANDLE hDrive)
1149 {
1150 int Len = 0;
1151 int readLen = 0;
1152 BOOL bRet;
1153 DWORD dwSize;
1154 BYTE *ImgBuf = NULL;
1155 BYTE *RawBuf = NULL;
1156
1157 Log("WriteGrubStage1ToPhyDrive ...");
1158
1159 RawBuf = (BYTE *)malloc(SIZE_1MB);
1160 if (!RawBuf)
1161 {
1162 return 1;
1163 }
1164
1165 if (ReadWholeFileToBuf(VENTOY_FILE_STG1_IMG, 0, (void **)&ImgBuf, &Len))
1166 {
1167 Log("Failed to read stage1 img");
1168 free(RawBuf);
1169 return 1;
1170 }
1171
1172 unxz(ImgBuf, Len, NULL, NULL, RawBuf, &readLen, unxz_error);
1173
1174 SetFilePointer(hDrive, 512, NULL, FILE_BEGIN);
1175
1176 bRet = WriteFile(hDrive, RawBuf, SIZE_1MB - 512, &dwSize, NULL);
1177 Log("WriteFile Ret:%u dwSize:%u ErrCode:%u", bRet, dwSize, GetLastError());
1178
1179 free(RawBuf);
1180 free(ImgBuf);
1181 return 0;
1182 }
1183
1184
1185
1186 static int FormatPart1exFAT(UINT64 DiskSizeBytes)
1187 {
1188 MKFS_PARM Option;
1189 FRESULT Ret;
1190 FATFS fs;
1191
1192 Option.fmt = FM_EXFAT;
1193 Option.n_fat = 1;
1194 Option.align = 8;
1195 Option.n_root = 1;
1196
1197 // < 32GB select 32KB as cluster size
1198 // > 32GB select 128KB as cluster size
1199 if (DiskSizeBytes / 1024 / 1024 / 1024 <= 32)
1200 {
1201 Option.au_size = 32768;
1202 }
1203 else
1204 {
1205 Option.au_size = 131072;
1206 }
1207
1208 Log("Formatting Part1 exFAT ...");
1209
1210 Ret = f_mkfs(TEXT("0:"), &Option, 0, 8 * 1024 * 1024);
1211
1212 if (FR_OK == Ret)
1213 {
1214 Log("Formatting Part1 exFAT success");
1215
1216 Ret = f_mount(&fs, TEXT("0:"), 1);
1217 Log("mount part %d", Ret);
1218
1219 if (FR_OK == Ret)
1220 {
1221 Ret = f_setlabel(TEXT("Ventoy"));
1222 Log("f_setlabel %d", Ret);
1223
1224 Ret = f_mount(0, TEXT("0:"), 1);
1225 Log("umount part %d", Ret);
1226 }
1227
1228 return 0;
1229 }
1230 else
1231 {
1232 Log("Formatting Part1 exFAT failed");
1233 return 1;
1234 }
1235 }
1236
1237
1238 int InstallVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive)
1239 {
1240 int i;
1241 int rc = 0;
1242 int state = 0;
1243 HANDLE hDrive;
1244 DWORD dwSize;
1245 BOOL bRet;
1246 CHAR MountDrive;
1247 CHAR DriveName[] = "?:\\";
1248 CHAR DriveLetters[MAX_PATH] = { 0 };
1249 MBR_HEAD MBR;
1250
1251 Log("InstallVentoy2PhyDrive PhyDrive%d <<%s %s %dGB>>",
1252 pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
1253 GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
1254
1255 PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
1256
1257 VentoyFillMBR(pPhyDrive->SizeInBytes, &MBR);
1258
1259 Log("Lock disk for clean ............................. ");
1260
1261 hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);
1262 if (hDrive == INVALID_HANDLE_VALUE)
1263 {
1264 Log("Failed to open physical disk");
1265 return 1;
1266 }
1267
1268 GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
1269
1270 if (DriveLetters[0] == 0)
1271 {
1272 Log("No drive letter was assigned...");
1273 DriveName[0] = GetFirstUnusedDriveLetter();
1274 Log("GetFirstUnusedDriveLetter %C: ...", DriveName[0]);
1275 }
1276 else
1277 {
1278 // Unmount all mounted volumes that belong to this drive
1279 // Do it in reverse so that we always end on the first volume letter
1280 for (i = (int)strlen(DriveLetters); i > 0; i--)
1281 {
1282 DriveName[0] = DriveLetters[i - 1];
1283 bRet = DeleteVolumeMountPointA(DriveName);
1284 Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, GetLastError());
1285 }
1286 }
1287
1288 MountDrive = DriveName[0];
1289 Log("Will use '%C:' as volume mountpoint", DriveName[0]);
1290
1291 // It kind of blows, but we have to relinquish access to the physical drive
1292 // for VDS to be able to delete the partitions that reside on it...
1293 DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
1294 CHECK_CLOSE_HANDLE(hDrive);
1295
1296 PROGRESS_BAR_SET_POS(PT_DEL_ALL_PART);
1297
1298 if (!DeletePartitions(pPhyDrive->PhyDrive, FALSE))
1299 {
1300 Log("Notice: Could not delete partitions: %u", GetLastError());
1301 }
1302
1303 Log("Deleting all partitions ......................... OK");
1304
1305 PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);
1306
1307 Log("Lock disk for write ............................. ");
1308 hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
1309 if (hDrive == INVALID_HANDLE_VALUE)
1310 {
1311 Log("Failed to GetPhysicalHandle for write.");
1312 rc = 1;
1313 goto End;
1314 }
1315
1316 //Refresh Drive Layout
1317 DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
1318
1319 disk_io_set_param(hDrive, MBR.PartTbl[0].StartSectorId + MBR.PartTbl[0].SectorCount);
1320
1321 PROGRESS_BAR_SET_POS(PT_FORMAT_PART1);
1322
1323 Log("Formatting part1 exFAT ...");
1324 if (0 != FormatPart1exFAT(pPhyDrive->SizeInBytes))
1325 {
1326 rc = 1;
1327 goto End;
1328 }
1329
1330 PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);
1331 Log("Writing part2 FAT img ...");
1332 if (0 != FormatPart2Fat(hDrive, MBR.PartTbl[1].StartSectorId))
1333 {
1334 rc = 1;
1335 goto End;
1336 }
1337
1338 PROGRESS_BAR_SET_POS(PT_WRITE_STG1_IMG);
1339 Log("Writting Boot Image ............................. ");
1340 if (WriteGrubStage1ToPhyDrive(hDrive) != 0)
1341 {
1342 rc = 1;
1343 goto End;
1344 }
1345
1346
1347 PROGRESS_BAR_SET_POS(PT_WRITE_PART_TABLE);
1348 Log("Writting Partition Table ........................ ");
1349 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
1350 if (!WriteFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL))
1351 {
1352 rc = 1;
1353 Log("Write MBR Failed, dwSize:%u ErrCode:%u", dwSize, GetLastError());
1354 goto End;
1355 }
1356
1357 Log("Write MBR OK ...");
1358
1359 //Refresh Drive Layout
1360 DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
1361
1362 End:
1363 CHECK_CLOSE_HANDLE(hDrive);
1364
1365 PROGRESS_BAR_SET_POS(PT_MOUNT_VOLUME);
1366 Log("Mounting Ventoy Partition ....................... ");
1367 Sleep(1000);
1368
1369 state = 0;
1370 memset(DriveLetters, 0, sizeof(DriveLetters));
1371 GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
1372 Log("Logical drive letter after write ventoy: <%s>", DriveLetters);
1373
1374 for (i = 0; i < sizeof(DriveLetters) && DriveLetters[i]; i++)
1375 {
1376 DriveName[0] = DriveLetters[i];
1377 if (IsVentoyLogicalDrive(DriveName[0]))
1378 {
1379 Log("%s is ventoy part2, delete mountpoint", DriveName);
1380 DeleteVolumeMountPointA(DriveName);
1381 }
1382 else
1383 {
1384 Log("%s is ventoy part1, already mounted", DriveName);
1385 state = 1;
1386 }
1387 }
1388
1389 if (state != 1)
1390 {
1391 Log("need to mount ventoy part1...");
1392 if (0 == GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[0].StartSectorId, DriveLetters, sizeof(DriveLetters), FALSE))
1393 {
1394 DriveName[0] = MountDrive;
1395 bRet = SetVolumeMountPointA(DriveName, DriveLetters);
1396 Log("SetVolumeMountPoint <%s> <%s> bRet:%u code:%u", DriveName, DriveLetters, bRet, GetLastError());
1397 }
1398 else
1399 {
1400 Log("Failed to find ventoy volume");
1401 }
1402 }
1403
1404 Log("OK\n");
1405
1406 return rc;
1407 }
1408
1409 int UpdateVentoy2PhyDrive(PHY_DRIVE_INFO *pPhyDrive)
1410 {
1411 int i;
1412 int rc = 0;
1413 BOOL ForceMBR = FALSE;
1414 HANDLE hVolume;
1415 HANDLE hDrive;
1416 DWORD Status;
1417 DWORD dwSize;
1418 BOOL bRet;
1419 CHAR DriveName[] = "?:\\";
1420 CHAR DriveLetters[MAX_PATH] = { 0 };
1421 UINT32 StartSector;
1422 MBR_HEAD BootImg;
1423 MBR_HEAD MBR;
1424
1425 StartSector = (UINT32)(pPhyDrive->SizeInBytes / 512 - VENTOY_EFI_PART_SIZE / 512);
1426
1427 Log("UpdateVentoy2PhyDrive PhyDrive%d <<%s %s %dGB>>",
1428 pPhyDrive->PhyDrive, pPhyDrive->VendorId, pPhyDrive->ProductId,
1429 GetHumanReadableGBSize(pPhyDrive->SizeInBytes));
1430
1431 PROGRESS_BAR_SET_POS(PT_LOCK_FOR_CLEAN);
1432
1433 Log("Lock disk for umount ............................ ");
1434
1435 hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, FALSE, FALSE);
1436 if (hDrive == INVALID_HANDLE_VALUE)
1437 {
1438 Log("Failed to open physical disk");
1439 return 1;
1440 }
1441
1442 // Read MBR
1443 ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
1444
1445 GetLettersBelongPhyDrive(pPhyDrive->PhyDrive, DriveLetters, sizeof(DriveLetters));
1446
1447 if (DriveLetters[0] == 0)
1448 {
1449 Log("No drive letter was assigned...");
1450 }
1451 else
1452 {
1453 // Unmount all mounted volumes that belong to this drive
1454 // Do it in reverse so that we always end on the first volume letter
1455 for (i = (int)strlen(DriveLetters); i > 0; i--)
1456 {
1457 DriveName[0] = DriveLetters[i - 1];
1458 if (IsVentoyLogicalDrive(DriveName[0]))
1459 {
1460 Log("%s is ventoy logical drive", DriveName);
1461 bRet = DeleteVolumeMountPointA(DriveName);
1462 Log("Delete mountpoint %s ret:%u code:%u", DriveName, bRet, LASTERR);
1463 break;
1464 }
1465 }
1466 }
1467
1468 // It kind of blows, but we have to relinquish access to the physical drive
1469 // for VDS to be able to delete the partitions that reside on it...
1470 DeviceIoControl(hDrive, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
1471 CHECK_CLOSE_HANDLE(hDrive);
1472
1473 PROGRESS_BAR_SET_POS(PT_LOCK_FOR_WRITE);
1474
1475 Log("Lock disk for update ............................ ");
1476 hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
1477 if (hDrive == INVALID_HANDLE_VALUE)
1478 {
1479 Log("Failed to GetPhysicalHandle for write.");
1480 rc = 1;
1481 goto End;
1482 }
1483
1484 PROGRESS_BAR_SET_POS(PT_LOCK_VOLUME);
1485
1486 Log("Lock volume for update .......................... ");
1487 hVolume = INVALID_HANDLE_VALUE;
1488 Status = GetVentoyVolumeName(pPhyDrive->PhyDrive, MBR.PartTbl[1].StartSectorId, DriveLetters, sizeof(DriveLetters), TRUE);
1489 if (ERROR_SUCCESS == Status)
1490 {
1491 Log("Now lock and dismount volume <%s>", DriveLetters);
1492 hVolume = CreateFileA(DriveLetters,
1493 GENERIC_READ | GENERIC_WRITE,
1494 FILE_SHARE_READ,
1495 NULL,
1496 OPEN_EXISTING,
1497 FILE_ATTRIBUTE_NORMAL | FILE_FLAG_NO_BUFFERING | FILE_FLAG_WRITE_THROUGH,
1498 NULL);
1499
1500 if (hVolume == INVALID_HANDLE_VALUE)
1501 {
1502 Log("Failed to create file volume, errcode:%u", LASTERR);
1503 rc = 1;
1504 goto End;
1505 }
1506
1507 bRet = DeviceIoControl(hVolume, FSCTL_LOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
1508 Log("FSCTL_LOCK_VOLUME bRet:%u code:%u", bRet, LASTERR);
1509
1510 bRet = DeviceIoControl(hVolume, FSCTL_DISMOUNT_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
1511 Log("FSCTL_DISMOUNT_VOLUME bRet:%u code:%u", bRet, LASTERR);
1512 }
1513 else if (ERROR_NOT_FOUND == Status)
1514 {
1515 Log("Volume not found, maybe not supported");
1516 }
1517 else
1518 {
1519 rc = 1;
1520 goto End;
1521 }
1522
1523
1524 if (!TryWritePart2(hDrive, StartSector))
1525 {
1526 ForceMBR = TRUE;
1527 Log("Try write failed, now delete partition 2...");
1528
1529 CHECK_CLOSE_HANDLE(hDrive);
1530
1531 Log("Now delete partition 2...");
1532 DeletePartitions(pPhyDrive->PhyDrive, TRUE);
1533
1534 hDrive = GetPhysicalHandle(pPhyDrive->PhyDrive, TRUE, TRUE, FALSE);
1535 if (hDrive == INVALID_HANDLE_VALUE)
1536 {
1537 Log("Failed to GetPhysicalHandle for write.");
1538 rc = 1;
1539 goto End;
1540 }
1541 }
1542
1543
1544 PROGRESS_BAR_SET_POS(PT_FORMAT_PART2);
1545
1546 Log("Write Ventoy to disk ............................ ");
1547 if (0 != FormatPart2Fat(hDrive, StartSector))
1548 {
1549 rc = 1;
1550 goto End;
1551 }
1552
1553 if (hVolume != INVALID_HANDLE_VALUE)
1554 {
1555 bRet = DeviceIoControl(hVolume, FSCTL_UNLOCK_VOLUME, NULL, 0, NULL, 0, &dwSize, NULL);
1556 Log("FSCTL_UNLOCK_VOLUME bRet:%u code:%u", bRet, LASTERR);
1557 CHECK_CLOSE_HANDLE(hVolume);
1558 }
1559
1560 Log("Updating Boot Image ............................. ");
1561 if (WriteGrubStage1ToPhyDrive(hDrive) != 0)
1562 {
1563 rc = 1;
1564 goto End;
1565 }
1566
1567 // Boot Image
1568 VentoyGetLocalBootImg(&BootImg);
1569
1570 // Use Old UUID
1571 memcpy(BootImg.BootCode + 0x180, MBR.BootCode + 0x180, 16);
1572
1573 if (ForceMBR == FALSE && memcmp(BootImg.BootCode, MBR.BootCode, 440) == 0)
1574 {
1575 Log("Boot image has no difference, no need to write.");
1576 }
1577 else
1578 {
1579 Log("Boot image need to write %u.", ForceMBR);
1580
1581 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
1582
1583 memcpy(MBR.BootCode, BootImg.BootCode, 440);
1584 bRet = WriteFile(hDrive, &MBR, 512, &dwSize, NULL);
1585 Log("Write Boot Image ret:%u dwSize:%u Error:%u", bRet, dwSize, LASTERR);
1586 }
1587
1588 //Refresh Drive Layout
1589 DeviceIoControl(hDrive, IOCTL_DISK_UPDATE_PROPERTIES, NULL, 0, NULL, 0, &dwSize, NULL);
1590
1591 End:
1592 CHECK_CLOSE_HANDLE(hDrive);
1593
1594 return rc;
1595 }
1596