1 /******************************************************************************
4 * Copyright (c) 2021, longpanda <admin@ventoy.net>
5 * Copyright (c) 2011-2021 Pete Batard <pete@akeo.ie>
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.
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.
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/>.
27 #include "Ventoy2Disk.h"
28 #include "DiskService.h"
30 static CHAR g_WindowsDir
[MAX_PATH
] = {0};
32 const CHAR
* DISK_GetWindowsDir(void)
34 if (g_WindowsDir
[0] == 0)
36 GetEnvironmentVariableA("SystemRoot", g_WindowsDir
, MAX_PATH
);
37 if (g_WindowsDir
[0] == 0)
39 sprintf_s(g_WindowsDir
, MAX_PATH
, "C:\\Windows");
46 BOOL
DISK_CleanDisk(int DriveIndex
)
50 ret
= VDS_CleanDisk(DriveIndex
);
53 ret
= PSHELL_CleanDisk(DriveIndex
);
60 BOOL
DISK_DeleteVtoyEFIPartition(int DriveIndex
, UINT64 EfiPartOffset
)
64 ret
= VDS_DeleteVtoyEFIPartition(DriveIndex
, EfiPartOffset
);
67 ret
= PSHELL_DeleteVtoyEFIPartition(DriveIndex
, EfiPartOffset
);
73 BOOL
DISK_ChangeVtoyEFI2ESP(int DriveIndex
, UINT64 Offset
)
77 ret
= VDS_ChangeVtoyEFI2ESP(DriveIndex
, Offset
);
80 ret
= PSHELL_ChangeVtoyEFI2ESP(DriveIndex
, Offset
);
87 BOOL
DISK_ChangeVtoyEFI2Basic(int DriveIndex
, UINT64 Offset
)
91 ret
= VDS_ChangeVtoyEFI2Basic(DriveIndex
, Offset
);
94 ret
= PSHELL_ChangeVtoyEFI2Basic(DriveIndex
, Offset
);
100 BOOL
DISK_ChangeVtoyEFIAttr(int DriveIndex
, UINT64 Offset
, UINT64 Attr
)
104 ret
= VDS_ChangeVtoyEFIAttr(DriveIndex
, Offset
, Attr
);
109 BOOL
DISK_ShrinkVolume(int DriveIndex
, const char* VolumeGuid
, CHAR DriveLetter
, UINT64 OldBytes
, UINT64 ReduceBytes
)
113 ret
= VDS_ShrinkVolume(DriveIndex
, VolumeGuid
, DriveLetter
, OldBytes
, ReduceBytes
);
116 if (LASTERR
== VDS_E_SHRINK_DIRTY_VOLUME
)
118 Log("VDS shrink return dirty, no need to run powershell.");
122 ret
= PSHELL_ShrinkVolume(DriveIndex
, VolumeGuid
, DriveLetter
, OldBytes
, ReduceBytes
);
136 } TEXTOUTPUT
, * PTEXTOUTPUT
;
138 /* Callback command types (some errorcode were filled from HPUSBFW V2.2.3 and their
139 designation from docs.microsoft.com/windows/win32/api/vds/nf-vds-ivdsvolumemf2-formatex */
142 FCC_DONE_WITH_STRUCTURE
,
144 FCC_INCOMPATIBLE_FILE_SYSTEM
,
148 FCC_MEDIA_WRITE_PROTECTED
,
150 FCC_CANT_QUICK_FORMAT
,
156 FCC_STRUCTURE_PROGRESS
,
157 FCC_CLUSTER_SIZE_TOO_SMALL
,
158 FCC_CLUSTER_SIZE_TOO_BIG
,
159 FCC_VOLUME_TOO_SMALL
,
161 FCC_NO_MEDIA_IN_DRIVE
,
165 FCC_DEVICE_NOT_READY
,
166 FCC_CHECKDISK_PROGRESS
,
178 FCC_ALIGNMENT_VIOLATION
,
179 } FILE_SYSTEM_CALLBACK_COMMAND
;
181 // FMIFS callback definition
182 typedef BOOLEAN(__stdcall
* PFMIFSCALLBACK
)(FILE_SYSTEM_CALLBACK_COMMAND Command
, DWORD SubAction
, PVOID ActionInfo
);
185 // Chkdsk command in FMIFS
186 typedef VOID(__stdcall
* PCHKDSK
)(PWCHAR DriveRoot
,
190 BOOL CheckOnlyIfDirty
,
194 PFMIFSCALLBACK Callback
);
198 #define FMIFS_HARDDISK 0xC
199 #define FMIFS_FLOPPY 0x8
200 // Format command in FMIFS
201 typedef VOID(__stdcall
* PFORMATEX
)(PWCHAR DriveRoot
,
207 PFMIFSCALLBACK Callback
);
209 #define FP_FORCE 0x00000001
210 #define FP_QUICK 0x00000002
211 #define FP_COMPRESSION 0x00000004
212 #define FP_DUPLICATE_METADATA 0x00000008
213 #define FP_LARGE_FAT32 0x00010000
214 #define FP_NO_BOOT 0x00020000
215 #define FP_CREATE_PERSISTENCE_CONF 0x00040000
218 static int g_dll_format_error
= 0;
219 BOOLEAN __stdcall
FormatExCallback(FILE_SYSTEM_CALLBACK_COMMAND Command
, DWORD Modifier
, PVOID Argument
)
226 percent
= (PDWORD
)Argument
;
227 Log("Format percent: %u%%", *percent
);
229 case FCC_STRUCTURE_PROGRESS
: // No progress on quick format
230 Log("Creating file system...");
233 status
= (PBOOLEAN
)Argument
;
234 if (*status
== FALSE
)
236 Log("Format error: %u ERROR_NOT_SUPPORTED=%u", LASTERR
, ERROR_NOT_SUPPORTED
);
237 g_dll_format_error
= 1;
244 case FCC_DONE_WITH_STRUCTURE
:
245 Log("Format FCC_DONE_WITH_STRUCTURE");
247 case FCC_INCOMPATIBLE_FILE_SYSTEM
:
248 Log("Incompatible File System");
250 case FCC_ACCESS_DENIED
:
251 Log("Access denied");
253 case FCC_MEDIA_WRITE_PROTECTED
:
254 Log("Media is write protected");
256 case FCC_VOLUME_IN_USE
:
257 Log("Volume is in use");
259 case FCC_DEVICE_NOT_READY
:
260 Log("The device is not ready");
262 case FCC_CANT_QUICK_FORMAT
:
263 Log("Cannot quick format this volume");
269 Log("%s", ((PTEXTOUTPUT
)Argument
)->Output
);
271 case FCC_CLUSTER_SIZE_TOO_BIG
:
272 case FCC_CLUSTER_SIZE_TOO_SMALL
:
273 Log("Unsupported cluster size");
275 case FCC_VOLUME_TOO_BIG
:
276 case FCC_VOLUME_TOO_SMALL
:
277 Log("Volume is too %s", (Command
== FCC_VOLUME_TOO_BIG
) ? "big" : "small");
279 case FCC_NO_MEDIA_IN_DRIVE
:
280 Log("No media in drive");
282 case FCC_ALIGNMENT_VIOLATION
:
283 Log("Partition start offset is not aligned to the cluster size");
286 Log("FormatExCallback: Received unhandled command 0x%02X - aborting", Command
);
294 BOOL
DLL_FormatVolume(char DriveLetter
, int fs
, DWORD ClusterSize
)
296 PWCHAR Label
= L
"Ventoy";
297 PWCHAR Format
= NULL
;
298 WCHAR RootDirectory
[MAX_PATH
] = { 0 };
302 ifsModule
= LoadLibraryA("fmifs.dll");
303 if (NULL
== ifsModule
)
305 Log("LoadLibrary fmifs.dll failed %u", LASTERR
);
309 Log("Find ifsModule");
311 FormatEx
= (PFORMATEX
)GetProcAddress(ifsModule
, "FormatEx");
312 if (FormatEx
== NULL
)
314 Log("Failed to get FormatEx handler\n");
317 Log("Find FormatEx=%p", FormatEx
);
319 RootDirectory
[0] = DriveLetter
;
320 RootDirectory
[1] = L
':';
321 RootDirectory
[2] = L
'\\';
322 RootDirectory
[3] = (WCHAR
)0;
326 driveType
= GetDriveTypeW(RootDirectory
);
327 if (driveType
!= DRIVE_FIXED
)
328 media
= FMIFS_FLOPPY
;
329 if (driveType
== DRIVE_FIXED
)
330 media
= FMIFS_HARDDISK
;
332 Format
= GetVentoyFsFmtNameByTypeW(fs
);
334 g_dll_format_error
= 0;
336 Log("Call FormatEx Function for %C: %s ClusterSize=%u(%uKB)", DriveLetter
, GetVentoyFsFmtNameByTypeA(fs
), ClusterSize
, ClusterSize
/ 1024);
337 FormatEx(RootDirectory
, media
, Format
, Label
, FP_FORCE
| FP_QUICK
, ClusterSize
, FormatExCallback
);
338 FreeLibrary(ifsModule
);
340 if (g_dll_format_error
)
342 Log("Format failed by DLL");
346 Log("Format success by DLL");
351 BOOL
DISK_FormatVolume(char DriveLetter
, int fs
, UINT64 VolumeSize
)
354 DWORD ClusterSize
= 0;
356 FmtFunc astFmtFunc
[] =
358 FMT_DEF(VDS_FormatVolume
),
359 FMT_DEF(DLL_FormatVolume
),
360 FMT_DEF(PSHELL_FormatVolume
),
361 FMT_DEF(DSPT_FormatVolume
),
362 FMT_DEF(CMD_FormatVolume
),
366 ClusterSize
= (DWORD
)GetClusterSize();
367 Log("DISK_FormatVolume %C:\\ %s VolumeSize=%llu ClusterSize=%u(%uKB)",
368 DriveLetter
, GetVentoyFsNameByType(fs
), (ULONGLONG
)VolumeSize
, ClusterSize
, ClusterSize
/ 1024);
370 for (i
= 0; astFmtFunc
[i
].formatFunc
; i
++)
372 Log("%s ...", astFmtFunc
[i
].name
);
373 ret
= astFmtFunc
[i
].formatFunc(DriveLetter
, fs
, ClusterSize
);