1 /******************************************************************************
4 * Copyright (c) 2020, longpanda <admin@ventoy.net>
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.
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.
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/>.
24 #include "Ventoy2Disk.h"
26 PHY_DRIVE_INFO
*g_PhyDriveList
= NULL
;
27 DWORD g_PhyDriveCount
= 0;
28 static int g_FilterRemovable
= 0;
30 int g_ForceOperation
= 1;
31 int g_NoNeedInputYes
= 0;
34 int ParseCmdLineOption(LPSTR lpCmdLine
)
37 char cfgfile
[MAX_PATH
];
39 if (lpCmdLine
&& lpCmdLine
[0])
41 Log("CmdLine:<%s>", lpCmdLine
);
44 for (i
= 0; i
< __argc
; i
++)
46 if (strncmp(__argv
[i
], "-U", 2) == 0 ||
47 strncmp(__argv
[i
], "-u", 2) == 0)
51 else if (strncmp(__argv
[i
], "-F", 2) == 0)
55 else if (strncmp(__argv
[i
], "-Y", 2) == 0 || strncmp(__argv
[i
], "-y", 2) == 0)
61 GetCurrentDirectoryA(sizeof(cfgfile
), cfgfile
);
62 strcat_s(cfgfile
, sizeof(cfgfile
), "\\Ventoy2Disk.ini");
64 if (0 == GetPrivateProfileIntA("Filter", "USB", 1, cfgfile
))
69 if (1 == GetPrivateProfileIntA("Operation", "Force", 0, cfgfile
))
74 Log("Control Flag: %d %d %d", g_FilterRemovable
, g_FilterUSB
, g_ForceOperation
);
79 static BOOL
IsVentoyPhyDrive(int PhyDrive
, UINT64 SizeBytes
, MBR_HEAD
*pMBR
, UINT64
*Part2StartSector
, UINT64
*GptPart2Attr
)
86 UINT32 PartStartSector
;
87 UINT32 PartSectorCount
;
88 CHAR PhyDrivePath
[128];
90 GUID ZeroGuid
= { 0 };
91 VTOY_GPT_INFO
*pGpt
= NULL
;
93 safe_sprintf(PhyDrivePath
, "\\\\.\\PhysicalDrive%d", PhyDrive
);
94 hDrive
= CreateFileA(PhyDrivePath
, GENERIC_READ
, FILE_SHARE_READ
, NULL
, OPEN_EXISTING
, 0, NULL
);
95 Log("Create file Handle:%p %s status:%u", hDrive
, PhyDrivePath
, LASTERR
);
97 if (hDrive
== INVALID_HANDLE_VALUE
)
102 bRet
= ReadFile(hDrive
, &MBR
, sizeof(MBR
), &dwSize
, NULL
);
103 Log("Read MBR Ret:%u Size:%u code:%u", bRet
, dwSize
, LASTERR
);
105 if ((!bRet
) || (dwSize
!= sizeof(MBR
)))
107 CHECK_CLOSE_HANDLE(hDrive
);
111 if (MBR
.Byte55
!= 0x55 || MBR
.ByteAA
!= 0xAA)
113 Log("Byte55 ByteAA not match 0x%x 0x%x", MBR
.Byte55
, MBR
.ByteAA
);
114 CHECK_CLOSE_HANDLE(hDrive
);
120 if (MBR
.PartTbl
[0].FsFlag
== 0xEE)
122 pGpt
= malloc(sizeof(VTOY_GPT_INFO
));
125 CHECK_CLOSE_HANDLE(hDrive
);
129 SetFilePointer(hDrive
, 0, NULL
, FILE_BEGIN
);
130 bRet
= ReadFile(hDrive
, pGpt
, sizeof(VTOY_GPT_INFO
), &dwSize
, NULL
);
131 CHECK_CLOSE_HANDLE(hDrive
);
132 if ((!bRet
) || (dwSize
!= sizeof(VTOY_GPT_INFO
)))
134 Log("Failed to read gpt info %d %u %d", bRet
, dwSize
, LASTERR
);
138 if (memcmp(pGpt
->Head
.Signature
, "EFI PART", 8))
140 Log("Invalid GPT signature");
144 for (i
= 0; i
< 128; i
++)
146 if (memcmp(&(pGpt
->PartTbl
[i
].PartGuid
), &ZeroGuid
, sizeof(GUID
)) == 0)
151 Log("=========== Disk%d GPT Partition %d ============", PhyDrive
, i
+ 1);
153 Log("PartTbl.PartType = %s", GUID2String(&pGpt
->PartTbl
[i
].PartType
, GUIDStr
, sizeof(GUIDStr
)));
154 Log("PartTbl.PartGuid = %s", GUID2String(&pGpt
->PartTbl
[i
].PartGuid
, GUIDStr
, sizeof(GUIDStr
)));
155 Log("PartTbl.StartLBA = %llu", (ULONGLONG
)pGpt
->PartTbl
[i
].StartLBA
);
156 Log("PartTbl.LastLBA = %llu", (ULONGLONG
)pGpt
->PartTbl
[i
].LastLBA
);
157 Log("PartTbl.Attribute = 0x%llx", pGpt
->PartTbl
[i
].Attr
);
158 Log("PartTbl.Name = %S", pGpt
->PartTbl
[i
].Name
);
161 if (memcmp(pGpt
->PartTbl
[1].Name
, L
"VTOYEFI", 7 * 2))
163 if (pGpt
->PartTbl
[1].Name
[0])
165 Log("Invalid ventoy efi part name <%S>", pGpt
->PartTbl
[1].Name
);
169 Log("Invalid ventoy efi part name <null>");
175 if (pGpt
->PartTbl
[0].StartLBA
!= 2048)
177 Log("Part1 not match %llu", pGpt
->PartTbl
[0].StartLBA
);
181 PartSectorCount
= VENTOY_EFI_PART_SIZE
/ 512;
183 if (pGpt
->PartTbl
[1].StartLBA
!= pGpt
->PartTbl
[0].LastLBA
+ 1 ||
184 (UINT32
)(pGpt
->PartTbl
[1].LastLBA
+ 1 - pGpt
->PartTbl
[1].StartLBA
) != PartSectorCount
)
186 Log("Part2 not match [%llu %llu] [%llu %llu]",
187 pGpt
->PartTbl
[0].StartLBA
, pGpt
->PartTbl
[0].LastLBA
,
188 pGpt
->PartTbl
[1].StartLBA
, pGpt
->PartTbl
[1].LastLBA
);
192 *GptPart2Attr
= pGpt
->PartTbl
[1].Attr
;
193 *Part2StartSector
= pGpt
->PartTbl
[1].StartLBA
;
195 memcpy(pMBR
, &(pGpt
->MBR
), sizeof(MBR_HEAD
));
199 CHECK_CLOSE_HANDLE(hDrive
);
201 for (i
= 0; i
< 4; i
++)
203 Log("=========== Disk%d MBR Partition %d ============", PhyDrive
, i
+ 1);
204 Log("PartTbl.Active = 0x%x", MBR
.PartTbl
[i
].Active
);
205 Log("PartTbl.FsFlag = 0x%x", MBR
.PartTbl
[i
].FsFlag
);
206 Log("PartTbl.StartSectorId = %u", MBR
.PartTbl
[i
].StartSectorId
);
207 Log("PartTbl.SectorCount = %u", MBR
.PartTbl
[i
].SectorCount
);
208 Log("PartTbl.StartHead = %u", MBR
.PartTbl
[i
].StartHead
);
209 Log("PartTbl.StartSector = %u", MBR
.PartTbl
[i
].StartSector
);
210 Log("PartTbl.StartCylinder = %u", MBR
.PartTbl
[i
].StartCylinder
);
211 Log("PartTbl.EndHead = %u", MBR
.PartTbl
[i
].EndHead
);
212 Log("PartTbl.EndSector = %u", MBR
.PartTbl
[i
].EndSector
);
213 Log("PartTbl.EndCylinder = %u", MBR
.PartTbl
[i
].EndCylinder
);
216 if (MBR
.PartTbl
[0].StartSectorId
!= 2048)
218 Log("Part1 not match %u", MBR
.PartTbl
[0].StartSectorId
);
222 PartStartSector
= MBR
.PartTbl
[0].StartSectorId
+ MBR
.PartTbl
[0].SectorCount
;
223 PartSectorCount
= VENTOY_EFI_PART_SIZE
/ 512;
225 if (MBR
.PartTbl
[1].StartSectorId
!= PartStartSector
||
226 MBR
.PartTbl
[1].SectorCount
!= PartSectorCount
)
228 Log("Part2 not match [0x%x 0x%x] [%u %u] [%u %u]",
229 MBR
.PartTbl
[1].FsFlag
, 0xEF,
230 MBR
.PartTbl
[1].StartSectorId
, PartStartSector
,
231 MBR
.PartTbl
[1].SectorCount
, PartSectorCount
);
235 if (MBR
.PartTbl
[0].Active
!= 0x80 && MBR
.PartTbl
[1].Active
!= 0x80)
237 Log("Part1 and Part2 are both NOT active 0x%x 0x%x", MBR
.PartTbl
[0].Active
, MBR
.PartTbl
[1].Active
);
238 if (MBR
.PartTbl
[2].Active
!= 0x80 && MBR
.PartTbl
[3].Active
!= 0x80)
240 Log("Part3 and Part4 are both NOT active 0x%x 0x%x", MBR
.PartTbl
[2].Active
, MBR
.PartTbl
[3].Active
);
245 *Part2StartSector
= MBR
.PartTbl
[1].StartSectorId
;
247 memcpy(pMBR
, &MBR
, sizeof(MBR_HEAD
));
250 Log("PhysicalDrive%d is ventoy disk", PhyDrive
);
254 int GetVolumeClusterSize(char Drive
)
256 CHAR Volume
[32] = { 0 };
257 DWORD SectorsPerCluster
= 0;
258 DWORD BytesPerSector
= 0;
259 DWORD NumberOfFreeClusters
= 0;
260 DWORD TotalNumberOfClusters
= 0;
262 sprintf_s(Volume
, sizeof(Volume
), "%C:\\", Drive
);
264 if (GetDiskFreeSpaceA(Volume
, &SectorsPerCluster
, &BytesPerSector
, &NumberOfFreeClusters
, &TotalNumberOfClusters
))
266 Log("GetVolumeClusterSize %s SUCCESS %u %u %u", Volume
, SectorsPerCluster
, BytesPerSector
, SectorsPerCluster
* BytesPerSector
);
267 return (int)(SectorsPerCluster
* BytesPerSector
);
271 Log("GetVolumeClusterSize %s failed err:%u", Volume
, LASTERR
);
277 static int GetVentoyFsNameInPhyDrive(PHY_DRIVE_INFO
* CurDrive
)
282 CHAR Volume
[128] = { 0 };
283 CHAR FsName
[MAX_PATH
] = { 0 };
285 while (CurDrive
->DriveLetters
[i
])
287 if (GetPhyDriveByLogicalDrive(CurDrive
->DriveLetters
[i
], &Offset
) >= 0)
289 if (Offset
== SIZE_1MB
)
291 sprintf_s(Volume
, sizeof(Volume
), "%C:\\", CurDrive
->DriveLetters
[i
]);
292 Log("Find the partition 1 logical drive is %s", Volume
);
299 sprintf_s(CurDrive
->VentoyFsType
, sizeof(CurDrive
->VentoyFsType
), "??");
303 CurDrive
->VentoyFsClusterSize
= GetVolumeClusterSize(Volume
[0]);
305 if (GetVolumeInformationA(Volume
, NULL
, 0, NULL
, NULL
, NULL
, FsName
, MAX_PATH
))
307 if (_stricmp(FsName
, "exFAT") == 0)
309 sprintf_s(CurDrive
->VentoyFsType
, sizeof(CurDrive
->VentoyFsType
), "exFAT");
311 else if (_stricmp(FsName
, "NTFS") == 0)
313 sprintf_s(CurDrive
->VentoyFsType
, sizeof(CurDrive
->VentoyFsType
), "NTFS");
315 else if (_stricmp(FsName
, "FAT") == 0 || _stricmp(FsName
, "FAT32") == 0)
317 sprintf_s(CurDrive
->VentoyFsType
, sizeof(CurDrive
->VentoyFsType
), "FAT32");
321 sprintf_s(CurDrive
->VentoyFsType
, sizeof(CurDrive
->VentoyFsType
), "%s", FsName
);
324 Log("GetVentoyFsNameInPhyDrive %d %s <%s> <%s>", CurDrive
->PhyDrive
, Volume
, FsName
, CurDrive
->VentoyFsType
);
328 Log("GetVolumeInformationA %s failed %u", Volume
, LASTERR
);
333 Log("GetVentoyFsNameInPhyDrive %s not found", Volume
);
339 static int FilterPhysicalDrive(PHY_DRIVE_INFO
*pDriveList
, DWORD DriveCount
)
347 UINT64 Part2GPTAttr
= 0;
348 UINT64 Part2StartSector
= 0;
349 PHY_DRIVE_INFO
*CurDrive
;
351 int LogLetter
[VENTOY_MAX_PHY_DRIVE
];
352 int PhyDriveId
[VENTOY_MAX_PHY_DRIVE
];
354 for (LogDrive
= GetLogicalDrives(); LogDrive
> 0; LogDrive
>>= 1)
358 LogLetter
[LetterCount
] = Letter
;
359 PhyDriveId
[LetterCount
] = GetPhyDriveByLogicalDrive(Letter
, NULL
);
361 Log("Logical Drive:%C ===> PhyDrive:%d", LogLetter
[LetterCount
], PhyDriveId
[LetterCount
]);
368 for (i
= 0; i
< DriveCount
; i
++)
371 CurDrive
= pDriveList
+ i
;
374 memset(CurDrive
->DriveLetters
, 0, sizeof(CurDrive
->DriveLetters
));
376 if (g_FilterRemovable
&& (!CurDrive
->RemovableMedia
))
378 Log("<%s %s> is filtered for not removable.", CurDrive
->VendorId
, CurDrive
->ProductId
);
382 if (g_FilterUSB
&& CurDrive
->BusType
!= BusTypeUsb
)
384 Log("<%s %s> is filtered for not USB type.", CurDrive
->VendorId
, CurDrive
->ProductId
);
390 for (Count
= 0, Letter
= 0; Letter
< LetterCount
; Letter
++)
392 if (PhyDriveId
[Letter
] == CurDrive
->PhyDrive
)
394 if (Count
+ 1 < sizeof(CurDrive
->DriveLetters
) / sizeof(CHAR
))
396 CurDrive
->DriveLetters
[Count
] = LogLetter
[Letter
];
402 if (IsVentoyPhyDrive(CurDrive
->PhyDrive
, CurDrive
->SizeInBytes
, &MBR
, &Part2StartSector
, &Part2GPTAttr
))
404 memcpy(&(CurDrive
->MBR
), &MBR
, sizeof(MBR
));
405 CurDrive
->PartStyle
= (MBR
.PartTbl
[0].FsFlag
== 0xEE) ? 1 : 0;
406 CurDrive
->Part2GPTAttr
= Part2GPTAttr
;
407 GetVentoyVerInPhyDrive(CurDrive
, Part2StartSector
, CurDrive
->VentoyVersion
, sizeof(CurDrive
->VentoyVersion
), &(CurDrive
->SecureBootSupport
));
408 Log("PhyDrive %d is Ventoy Disk ver:%s SecureBoot:%u", CurDrive
->PhyDrive
, CurDrive
->VentoyVersion
, CurDrive
->SecureBootSupport
);
410 GetVentoyFsNameInPhyDrive(CurDrive
);
412 if (CurDrive
->VentoyVersion
[0] == 0)
414 CurDrive
->VentoyVersion
[0] = '?';
415 Log("Unknown Ventoy Version");
421 for (i
= 0; i
< DriveCount
; i
++)
423 CurDrive
= pDriveList
+ i
;
424 if (CurDrive
->Id
< 0)
426 CurDrive
->PhyDrive
= 0x00FFFFFF;
433 PHY_DRIVE_INFO
* GetPhyDriveInfoById(int Id
)
436 for (i
= 0; i
< g_PhyDriveCount
; i
++)
438 if (g_PhyDriveList
[i
].Id
>= 0 && g_PhyDriveList
[i
].Id
== Id
)
440 return g_PhyDriveList
+ i
;
448 PHY_DRIVE_INFO
* GetPhyDriveInfoByPhyDrive(int PhyDrive
)
451 for (i
= 0; i
< g_PhyDriveCount
; i
++)
453 if (g_PhyDriveList
[i
].PhyDrive
== PhyDrive
)
455 return g_PhyDriveList
+ i
;
464 int SortPhysicalDrive(PHY_DRIVE_INFO
*pDriveList
, DWORD DriveCount
)
468 PHY_DRIVE_INFO TmpDriveInfo
;
470 for (i
= 0; i
< DriveCount
; i
++)
472 for (j
= i
+ 1; j
< DriveCount
; j
++)
476 if (pDriveList
[i
].BusType
== BusTypeUsb
&& pDriveList
[j
].BusType
== BusTypeUsb
)
478 if (pDriveList
[i
].RemovableMedia
== FALSE
&& pDriveList
[j
].RemovableMedia
== TRUE
)
483 else if (pDriveList
[j
].BusType
== BusTypeUsb
)
489 if (pDriveList
[j
].PhyDrive
< pDriveList
[i
].PhyDrive
)
497 memcpy(&TmpDriveInfo
, pDriveList
+ i
, sizeof(PHY_DRIVE_INFO
));
498 memcpy(pDriveList
+ i
, pDriveList
+ j
, sizeof(PHY_DRIVE_INFO
));
499 memcpy(pDriveList
+ j
, &TmpDriveInfo
, sizeof(PHY_DRIVE_INFO
));
507 int Ventoy2DiskInit(void)
509 Log("\n===================== Enum All PhyDrives =====================");
510 g_PhyDriveList
= (PHY_DRIVE_INFO
*)malloc(sizeof(PHY_DRIVE_INFO
)* VENTOY_MAX_PHY_DRIVE
);
511 if (NULL
== g_PhyDriveList
)
513 Log("Failed to alloc phy drive memory");
516 memset(g_PhyDriveList
, 0, sizeof(PHY_DRIVE_INFO
)* VENTOY_MAX_PHY_DRIVE
);
518 GetAllPhysicalDriveInfo(g_PhyDriveList
, &g_PhyDriveCount
);
520 SortPhysicalDrive(g_PhyDriveList
, g_PhyDriveCount
);
522 FilterPhysicalDrive(g_PhyDriveList
, g_PhyDriveCount
);
527 int Ventoy2DiskDestroy(void)
529 free(g_PhyDriveList
);
530 g_PhyDriveList
= NULL
;