]> glassweightruler.freedombox.rocks Git - Ventoy.git/blob - Ventoy2Disk/Ventoy2Disk/Ventoy2Disk.c
9eb257015f9813ec7ff654c192681b3f5763c35e
[Ventoy.git] / Ventoy2Disk / Ventoy2Disk / Ventoy2Disk.c
1 /******************************************************************************
2 * Ventoy2Disk.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 "resource.h"
23 #include "Language.h"
24 #include "Ventoy2Disk.h"
25
26 PHY_DRIVE_INFO *g_PhyDriveList = NULL;
27 DWORD g_PhyDriveCount = 0;
28 static int g_FilterRemovable = 0;
29 int g_FilterUSB = 1;
30 int g_ForceOperation = 1;
31 int g_WriteImage = 0;
32
33 int ParseCmdLineOption(LPSTR lpCmdLine)
34 {
35 int i;
36 char cfgfile[MAX_PATH];
37
38 if (lpCmdLine && lpCmdLine[0])
39 {
40 Log("CmdLine:<%s>", lpCmdLine);
41 }
42
43 for (i = 0; i < __argc; i++)
44 {
45 if (strncmp(__argv[i], "-U", 2) == 0 ||
46 strncmp(__argv[i], "-u", 2) == 0)
47 {
48 g_FilterUSB = 0;
49 }
50 else if (strncmp(__argv[i], "-F", 2) == 0)
51 {
52 g_ForceOperation = 1;
53 }
54 }
55
56 GetCurrentDirectoryA(sizeof(cfgfile), cfgfile);
57 strcat_s(cfgfile, sizeof(cfgfile), "\\Ventoy2Disk.ini");
58
59 if (0 == GetPrivateProfileIntA("Filter", "USB", 1, cfgfile))
60 {
61 g_FilterUSB = 0;
62 }
63
64 if (1 == GetPrivateProfileIntA("Operation", "Force", 0, cfgfile))
65 {
66 g_ForceOperation = 1;
67 }
68
69 Log("Control Flag: %d %d %d", g_FilterRemovable, g_FilterUSB, g_ForceOperation);
70
71 return 0;
72 }
73
74 static BOOL IsVentoyPhyDrive(int PhyDrive, UINT64 SizeBytes, MBR_HEAD *pMBR, UINT64 *Part2StartSector)
75 {
76 int i;
77 BOOL bRet;
78 DWORD dwSize;
79 HANDLE hDrive;
80 MBR_HEAD MBR;
81 UINT32 PartStartSector;
82 UINT32 PartSectorCount;
83 CHAR PhyDrivePath[128];
84 VTOY_GPT_INFO *pGpt = NULL;
85
86 safe_sprintf(PhyDrivePath, "\\\\.\\PhysicalDrive%d", PhyDrive);
87 hDrive = CreateFileA(PhyDrivePath, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL);
88 Log("Create file Handle:%p %s status:%u", hDrive, PhyDrivePath, LASTERR);
89
90 if (hDrive == INVALID_HANDLE_VALUE)
91 {
92 return FALSE;
93 }
94
95 bRet = ReadFile(hDrive, &MBR, sizeof(MBR), &dwSize, NULL);
96 Log("Read MBR Ret:%u Size:%u code:%u", bRet, dwSize, LASTERR);
97
98 if ((!bRet) || (dwSize != sizeof(MBR)))
99 {
100 CHECK_CLOSE_HANDLE(hDrive);
101 return FALSE;
102 }
103
104 if (MBR.Byte55 != 0x55 || MBR.ByteAA != 0xAA)
105 {
106 Log("Byte55 ByteAA not match 0x%x 0x%x", MBR.Byte55, MBR.ByteAA);
107 CHECK_CLOSE_HANDLE(hDrive);
108 return FALSE;
109 }
110
111 for (i = 0; i < 4; i++)
112 {
113 Log("=========== Partition Table %d ============", i + 1);
114 Log("PartTbl.Active = 0x%x", MBR.PartTbl[i].Active);
115 Log("PartTbl.FsFlag = 0x%x", MBR.PartTbl[i].FsFlag);
116 Log("PartTbl.StartSectorId = %u", MBR.PartTbl[i].StartSectorId);
117 Log("PartTbl.SectorCount = %u", MBR.PartTbl[i].SectorCount);
118 Log("PartTbl.StartHead = %u", MBR.PartTbl[i].StartHead);
119 Log("PartTbl.StartSector = %u", MBR.PartTbl[i].StartSector);
120 Log("PartTbl.StartCylinder = %u", MBR.PartTbl[i].StartCylinder);
121 Log("PartTbl.EndHead = %u", MBR.PartTbl[i].EndHead);
122 Log("PartTbl.EndSector = %u", MBR.PartTbl[i].EndSector);
123 Log("PartTbl.EndCylinder = %u", MBR.PartTbl[i].EndCylinder);
124 }
125
126 if (MBR.PartTbl[0].FsFlag == 0xEE)
127 {
128 pGpt = malloc(sizeof(VTOY_GPT_INFO));
129 if (!pGpt)
130 {
131 CHECK_CLOSE_HANDLE(hDrive);
132 return FALSE;
133 }
134
135 SetFilePointer(hDrive, 0, NULL, FILE_BEGIN);
136 bRet = ReadFile(hDrive, pGpt, sizeof(VTOY_GPT_INFO), &dwSize, NULL);
137 CHECK_CLOSE_HANDLE(hDrive);
138 if ((!bRet) || (dwSize != sizeof(VTOY_GPT_INFO)))
139 {
140 Log("Failed to read gpt info %d %u %d", bRet, dwSize, LASTERR);
141 return FALSE;
142 }
143
144 if (memcmp(pGpt->Head.Signature, "EFI PART", 8))
145 {
146 Log("Invalid GPT signature");
147 return FALSE;
148 }
149
150 if (memcmp(pGpt->PartTbl[1].Name, L"VTOYEFI", 7 * 2))
151 {
152 Log("Invalid ventoy efi part name");
153 return FALSE;
154 }
155
156 if (pGpt->PartTbl[0].StartLBA != 2048)
157 {
158 Log("Part1 not match %llu", pGpt->PartTbl[0].StartLBA);
159 return FALSE;
160 }
161
162 PartSectorCount = VENTOY_EFI_PART_SIZE / 512;
163
164 if (pGpt->PartTbl[1].StartLBA != pGpt->PartTbl[0].LastLBA + 1 ||
165 (UINT32)(pGpt->PartTbl[1].LastLBA + 1 - pGpt->PartTbl[1].StartLBA) != PartSectorCount)
166 {
167 Log("Part2 not match [%llu %llu] [%llu %llu]",
168 pGpt->PartTbl[0].StartLBA, pGpt->PartTbl[0].LastLBA,
169 pGpt->PartTbl[1].StartLBA, pGpt->PartTbl[1].LastLBA);
170 return FALSE;
171 }
172
173 *Part2StartSector = pGpt->PartTbl[1].StartLBA;
174
175 memcpy(pMBR, &(pGpt->MBR), sizeof(MBR_HEAD));
176 }
177 else
178 {
179 CHECK_CLOSE_HANDLE(hDrive);
180
181 if (MBR.PartTbl[0].StartSectorId != 2048)
182 {
183 Log("Part1 not match %u", MBR.PartTbl[0].StartSectorId);
184 return FALSE;
185 }
186
187 PartStartSector = MBR.PartTbl[0].StartSectorId + MBR.PartTbl[0].SectorCount;
188 PartSectorCount = VENTOY_EFI_PART_SIZE / 512;
189
190 if (MBR.PartTbl[1].StartSectorId != PartStartSector ||
191 MBR.PartTbl[1].SectorCount != PartSectorCount)
192 {
193 Log("Part2 not match [0x%x 0x%x] [%u %u] [%u %u]",
194 MBR.PartTbl[1].FsFlag, 0xEF,
195 MBR.PartTbl[1].StartSectorId, PartStartSector,
196 MBR.PartTbl[1].SectorCount, PartSectorCount);
197 return FALSE;
198 }
199
200 if (MBR.PartTbl[0].Active != 0x80 && MBR.PartTbl[1].Active != 0x80)
201 {
202 Log("Part1 and Part2 are both NOT active 0x%x 0x%x", MBR.PartTbl[0].Active, MBR.PartTbl[1].Active);
203 if (MBR.PartTbl[2].Active != 0x80 && MBR.PartTbl[3].Active != 0x80)
204 {
205 Log("Part3 and Part4 are both NOT active 0x%x 0x%x", MBR.PartTbl[2].Active, MBR.PartTbl[3].Active);
206 //return FALSE;
207 }
208 }
209
210 *Part2StartSector = MBR.PartTbl[1].StartSectorId;
211
212 memcpy(pMBR, &MBR, sizeof(MBR_HEAD));
213 }
214
215 Log("PhysicalDrive%d is ventoy disk", PhyDrive);
216 return TRUE;
217 }
218
219
220 static int FilterPhysicalDrive(PHY_DRIVE_INFO *pDriveList, DWORD DriveCount)
221 {
222 DWORD i;
223 DWORD LogDrive;
224 int Count = 0;
225 int Letter = 'A';
226 int Id = 0;
227 int LetterCount = 0;
228 UINT64 Part2StartSector = 0;
229 PHY_DRIVE_INFO *CurDrive;
230 MBR_HEAD MBR;
231 int LogLetter[VENTOY_MAX_PHY_DRIVE];
232 int PhyDriveId[VENTOY_MAX_PHY_DRIVE];
233
234 for (LogDrive = GetLogicalDrives(); LogDrive > 0; LogDrive >>= 1)
235 {
236 if (LogDrive & 0x01)
237 {
238 LogLetter[LetterCount] = Letter;
239 PhyDriveId[LetterCount] = GetPhyDriveByLogicalDrive(Letter);
240
241 Log("Logical Drive:%C ===> PhyDrive:%d", LogLetter[LetterCount], PhyDriveId[LetterCount]);
242 LetterCount++;
243 }
244
245 Letter++;
246 }
247
248 for (i = 0; i < DriveCount; i++)
249 {
250 CurDrive = pDriveList + i;
251
252 CurDrive->Id = -1;
253 memset(CurDrive->DriveLetters, 0, sizeof(CurDrive->DriveLetters));
254
255 if (g_FilterRemovable && (!CurDrive->RemovableMedia))
256 {
257 Log("<%s %s> is filtered for not removable.", CurDrive->VendorId, CurDrive->ProductId);
258 continue;
259 }
260
261 if (g_FilterUSB && CurDrive->BusType != BusTypeUsb)
262 {
263 Log("<%s %s> is filtered for not USB type.", CurDrive->VendorId, CurDrive->ProductId);
264 continue;
265 }
266
267 CurDrive->Id = Id++;
268
269 for (Count = 0, Letter = 0; Letter < LetterCount; Letter++)
270 {
271 if (PhyDriveId[Letter] == CurDrive->PhyDrive)
272 {
273 if (Count + 1 < sizeof(CurDrive->DriveLetters) / sizeof(CHAR))
274 {
275 CurDrive->DriveLetters[Count] = LogLetter[Letter];
276 }
277 Count++;
278 }
279 }
280
281 if (IsVentoyPhyDrive(CurDrive->PhyDrive, CurDrive->SizeInBytes, &MBR, &Part2StartSector))
282 {
283 memcpy(&(CurDrive->MBR), &MBR, sizeof(MBR));
284 CurDrive->PartStyle = (MBR.PartTbl[0].FsFlag == 0xEE) ? 1 : 0;
285 GetVentoyVerInPhyDrive(CurDrive, Part2StartSector, CurDrive->VentoyVersion, sizeof(CurDrive->VentoyVersion), &(CurDrive->SecureBootSupport));
286 Log("PhyDrive %d is Ventoy Disk ver:%s SecureBoot:%u", CurDrive->PhyDrive, CurDrive->VentoyVersion, CurDrive->SecureBootSupport);
287
288 if (CurDrive->VentoyVersion[0] == 0)
289 {
290 CurDrive->VentoyVersion[0] = '?';
291 Log("Unknown Ventoy Version");
292 }
293 }
294 }
295
296 // for safe
297 for (i = 0; i < DriveCount; i++)
298 {
299 CurDrive = pDriveList + i;
300 if (CurDrive->Id < 0)
301 {
302 CurDrive->PhyDrive = 0x00FFFFFF;
303 }
304 }
305
306 return Id;
307 }
308
309 PHY_DRIVE_INFO * GetPhyDriveInfoById(int Id)
310 {
311 DWORD i;
312 for (i = 0; i < g_PhyDriveCount; i++)
313 {
314 if (g_PhyDriveList[i].Id >= 0 && g_PhyDriveList[i].Id == Id)
315 {
316 return g_PhyDriveList + i;
317 }
318 }
319
320 return NULL;
321 }
322
323 int SortPhysicalDrive(PHY_DRIVE_INFO *pDriveList, DWORD DriveCount)
324 {
325 DWORD i, j;
326 BOOL flag;
327 PHY_DRIVE_INFO TmpDriveInfo;
328
329 for (i = 0; i < DriveCount; i++)
330 {
331 for (j = i + 1; j < DriveCount; j++)
332 {
333 flag = FALSE;
334
335 if (pDriveList[i].BusType == BusTypeUsb && pDriveList[j].BusType == BusTypeUsb)
336 {
337 if (pDriveList[i].RemovableMedia == FALSE && pDriveList[j].RemovableMedia == TRUE)
338 {
339 flag = TRUE;
340 }
341 }
342 else if (pDriveList[j].BusType == BusTypeUsb)
343 {
344 flag = TRUE;
345 }
346 else
347 {
348 if (pDriveList[j].PhyDrive < pDriveList[i].PhyDrive)
349 {
350 flag = TRUE;
351 }
352 }
353
354 if (flag)
355 {
356 memcpy(&TmpDriveInfo, pDriveList + i, sizeof(PHY_DRIVE_INFO));
357 memcpy(pDriveList + i, pDriveList + j, sizeof(PHY_DRIVE_INFO));
358 memcpy(pDriveList + j, &TmpDriveInfo, sizeof(PHY_DRIVE_INFO));
359 }
360 }
361 }
362
363 return 0;
364 }
365
366 int Ventoy2DiskInit(void)
367 {
368 Log("\n===================== Enum All PhyDrives =====================");
369 g_PhyDriveList = (PHY_DRIVE_INFO *)malloc(sizeof(PHY_DRIVE_INFO)* VENTOY_MAX_PHY_DRIVE);
370 if (NULL == g_PhyDriveList)
371 {
372 Log("Failed to alloc phy drive memory");
373 return FALSE;
374 }
375 memset(g_PhyDriveList, 0, sizeof(PHY_DRIVE_INFO)* VENTOY_MAX_PHY_DRIVE);
376
377 GetAllPhysicalDriveInfo(g_PhyDriveList, &g_PhyDriveCount);
378
379 SortPhysicalDrive(g_PhyDriveList, g_PhyDriveCount);
380
381 FilterPhysicalDrive(g_PhyDriveList, g_PhyDriveCount);
382
383 return 0;
384 }
385
386 int Ventoy2DiskDestroy(void)
387 {
388 free(g_PhyDriveList);
389 return 0;
390 }