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