2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Filesystem support functions
5 * COPYRIGHT: Copyright 2003-2019 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2017-2019 Hermes Belusca-Maito
10 // See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
11 // for how to get FS providers in a dynamic way. In the (near) future we may
12 // consider merging some of this code with us into a fmifs / fsutil / fslib library...
15 /* INCLUDES *****************************************************************/
22 #include <fslib/vfatlib.h>
23 #include <fslib/btrfslib.h>
24 // #include <fslib/ext2lib.h>
25 // #include <fslib/ntfslib.h>
31 /* LOCALS *******************************************************************/
34 typedef struct _FILE_SYSTEM
36 PCWSTR FileSystemName
;
39 } FILE_SYSTEM
, *PFILE_SYSTEM
;
41 /* The list of file systems on which we can install ReactOS */
42 static FILE_SYSTEM RegisteredFileSystems
[] =
44 /* NOTE: The FAT formatter automatically determines
45 * whether it will use FAT-16 or FAT-32. */
46 { L
"FAT" , VfatFormat
, VfatChkdsk
},
48 { L
"FAT32", VfatFormat
, VfatChkdsk
}, // Do we support specific FAT sub-formats specifications?
49 { L
"FATX" , VfatxFormat
, VfatxChkdsk
},
50 { L
"NTFS" , NtfsFormat
, NtfsChkdsk
},
52 { L
"BTRFS", BtrfsFormatEx
, BtrfsChkdskEx
},
54 { L
"EXT2" , Ext2Format
, Ext2Chkdsk
},
55 { L
"EXT3" , Ext2Format
, Ext2Chkdsk
},
56 { L
"EXT4" , Ext2Format
, Ext2Chkdsk
},
57 { L
"FFS" , FfsFormat
, FfsChkdsk
},
58 { L
"REISERFS", ReiserfsFormat
, ReiserfsChkdsk
},
63 /* FUNCTIONS ****************************************************************/
65 /** QueryAvailableFileSystemFormat() **/
67 GetRegisteredFileSystems(
69 OUT PCWSTR
* FileSystemName
)
71 if (Index
>= ARRAYSIZE(RegisteredFileSystems
))
74 *FileSystemName
= RegisteredFileSystems
[Index
].FileSystemName
;
83 IN PCWSTR FileSystemName
)
85 #if 0 // Reenable when the list of registered FSes will again be dynamic
87 PLIST_ENTRY ListEntry
;
88 PFILE_SYSTEM_ITEM Item
;
90 ListEntry
= List
->ListHead
.Flink
;
91 while (ListEntry
!= &List
->ListHead
)
93 Item
= CONTAINING_RECORD(ListEntry
, FILE_SYSTEM_ITEM
, ListEntry
);
94 if (Item
->FileSystemName
&&
95 (wcsicmp(FileSystemName
, Item
->FileSystemName
) == 0 ||
96 /* Map FAT32 back to FAT */
97 (wcsicmp(FileSystemName
, L
"FAT32") == 0 && wcsicmp(Item
->FileSystemName
, L
"FAT") == 0)))
102 ListEntry
= ListEntry
->Flink
;
107 ULONG Count
= ARRAYSIZE(RegisteredFileSystems
);
108 PFILE_SYSTEM FileSystems
= RegisteredFileSystems
;
110 ASSERT(FileSystems
&& Count
!= 0);
114 if (FileSystems
->FileSystemName
&&
115 (wcsicmp(FileSystemName
, FileSystems
->FileSystemName
) == 0 ||
116 /* Map FAT32 back to FAT */
117 (wcsicmp(FileSystemName
, L
"FAT32") == 0 && wcsicmp(FileSystems
->FileSystemName
, L
"FAT") == 0)))
132 // FileSystem recognition, using NT OS functionality
135 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
137 GetFileSystemNameByHandle(
138 IN HANDLE PartitionHandle
,
139 IN OUT PWSTR FileSystemName
,
140 IN SIZE_T FileSystemNameSize
)
143 IO_STATUS_BLOCK IoStatusBlock
;
144 UCHAR Buffer
[sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
)];
145 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
147 /* Retrieve the FS attributes */
148 Status
= NtQueryVolumeInformationFile(PartitionHandle
,
152 FileFsAttributeInformation
);
153 if (!NT_SUCCESS(Status
))
155 DPRINT1("NtQueryVolumeInformationFile failed, Status 0x%08lx\n", Status
);
159 if (FileSystemNameSize
< FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
160 return STATUS_BUFFER_TOO_SMALL
;
162 return RtlStringCbCopyNW(FileSystemName
, FileSystemNameSize
,
163 FileFsAttribute
->FileSystemName
,
164 FileFsAttribute
->FileSystemNameLength
);
168 GetFileSystemName_UStr(
169 IN PUNICODE_STRING PartitionPath
,
170 IN OUT PWSTR FileSystemName
,
171 IN SIZE_T FileSystemNameSize
)
174 OBJECT_ATTRIBUTES ObjectAttributes
;
175 HANDLE PartitionHandle
;
176 IO_STATUS_BLOCK IoStatusBlock
;
178 /* Open the partition */
179 InitializeObjectAttributes(&ObjectAttributes
,
181 OBJ_CASE_INSENSITIVE
,
184 Status
= NtOpenFile(&PartitionHandle
,
185 FILE_GENERIC_READ
/* | SYNCHRONIZE */,
188 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
189 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
190 if (!NT_SUCCESS(Status
))
192 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", PartitionPath
, Status
);
196 /* Retrieve the FS attributes */
197 Status
= GetFileSystemNameByHandle(PartitionHandle
, FileSystemName
, FileSystemNameSize
);
198 if (!NT_SUCCESS(Status
))
200 DPRINT1("GetFileSystemNameByHandle() failed for partition '%wZ', Status 0x%08lx\n",
201 PartitionPath
, Status
);
204 /* Close the partition */
205 NtClose(PartitionHandle
);
213 IN OUT PWSTR FileSystemName
,
214 IN SIZE_T FileSystemNameSize
)
216 UNICODE_STRING PartitionPath
;
218 RtlInitUnicodeString(&PartitionPath
, Partition
);
219 return GetFileSystemName_UStr(&PartitionPath
,
225 InferFileSystemByHandle(
226 IN HANDLE PartitionHandle
,
227 IN UCHAR PartitionType
,
228 IN OUT PWSTR FileSystemName
,
229 IN SIZE_T FileSystemNameSize
)
233 if (FileSystemNameSize
< sizeof(WCHAR
))
234 return STATUS_BUFFER_TOO_SMALL
;
236 *FileSystemName
= L
'\0';
238 /* Try to infer a file system using NT file system recognition */
239 Status
= GetFileSystemNameByHandle(PartitionHandle
,
242 if (NT_SUCCESS(Status
) && *FileSystemName
)
248 * Try to infer a preferred file system for this partition, given its ID.
250 * WARNING: This is partly a hack, since partitions with the same ID can
251 * be formatted with different file systems: for example, usual Linux
252 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
253 * same partition ID 0x83.
255 * The proper fix is to make a function that detects the existing FS
256 * from a given partition (not based on the partition ID).
257 * On the contrary, for unformatted partitions with a given ID, the
258 * following code is OK.
260 if ((PartitionType
== PARTITION_FAT_12
) ||
261 (PartitionType
== PARTITION_FAT_16
) ||
262 (PartitionType
== PARTITION_HUGE
) ||
263 (PartitionType
== PARTITION_XINT13
))
266 Status
= RtlStringCbCopyW(FileSystemName
, FileSystemNameSize
, L
"FAT");
268 else if ((PartitionType
== PARTITION_FAT32
) ||
269 (PartitionType
== PARTITION_FAT32_XINT13
))
271 Status
= RtlStringCbCopyW(FileSystemName
, FileSystemNameSize
, L
"FAT32");
273 else if (PartitionType
== PARTITION_LINUX
)
275 // WARNING: See the warning above.
276 /* Could also be EXT2/3/4, ReiserFS, ... */
277 Status
= RtlStringCbCopyW(FileSystemName
, FileSystemNameSize
, L
"BTRFS");
279 else if (PartitionType
== PARTITION_IFS
)
281 // WARNING: See the warning above.
282 /* Could also be HPFS */
283 Status
= RtlStringCbCopyW(FileSystemName
, FileSystemNameSize
, L
"NTFS");
289 // WARNING: We cannot write on this FS yet!
290 if (PartitionType
== PARTITION_IFS
)
292 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
297 DPRINT1("InferFileSystem -- PartitionType: 0x%02X ; FileSystem (guessed): %S\n",
298 PartitionType
, *FileSystemName
? FileSystemName
: L
"None");
306 IN UCHAR PartitionType
,
307 IN OUT PWSTR FileSystemName
,
308 IN SIZE_T FileSystemNameSize
)
311 UNICODE_STRING PartitionPath
;
312 OBJECT_ATTRIBUTES ObjectAttributes
;
313 HANDLE PartitionHandle
;
314 IO_STATUS_BLOCK IoStatusBlock
;
316 /* Open the partition */
317 RtlInitUnicodeString(&PartitionPath
, Partition
);
318 InitializeObjectAttributes(&ObjectAttributes
,
320 OBJ_CASE_INSENSITIVE
,
323 Status
= NtOpenFile(&PartitionHandle
,
324 FILE_GENERIC_READ
/* | SYNCHRONIZE */,
327 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
328 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
329 if (!NT_SUCCESS(Status
))
331 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionPath
, Status
);
335 /* Retrieve the FS */
336 Status
= InferFileSystemByHandle(PartitionHandle
,
341 /* Close the partition */
342 NtClose(PartitionHandle
);
349 ChkdskFileSystem_UStr(
350 IN PUNICODE_STRING DriveRoot
,
351 IN PCWSTR FileSystemName
,
352 IN BOOLEAN FixErrors
,
354 IN BOOLEAN CheckOnlyIfDirty
,
355 IN BOOLEAN ScanDrive
,
356 IN PFMIFSCALLBACK Callback
)
358 PFILE_SYSTEM FileSystem
;
360 FileSystem
= GetFileSystemByName(FileSystemName
);
362 if (!FileSystem
|| !FileSystem
->ChkdskFunc
)
364 // BOOLEAN Argument = FALSE;
365 // Callback(DONE, 0, &Argument);
366 return STATUS_NOT_SUPPORTED
;
369 return FileSystem
->ChkdskFunc(DriveRoot
,
380 IN PCWSTR FileSystemName
,
381 IN BOOLEAN FixErrors
,
383 IN BOOLEAN CheckOnlyIfDirty
,
384 IN BOOLEAN ScanDrive
,
385 IN PFMIFSCALLBACK Callback
)
387 UNICODE_STRING DriveRootU
;
389 RtlInitUnicodeString(&DriveRootU
, DriveRoot
);
390 return ChkdskFileSystem_UStr(&DriveRootU
,
402 FormatFileSystem_UStr(
403 IN PUNICODE_STRING DriveRoot
,
404 IN PCWSTR FileSystemName
,
405 IN FMIFS_MEDIA_FLAG MediaFlag
,
406 IN PUNICODE_STRING Label
,
407 IN BOOLEAN QuickFormat
,
408 IN ULONG ClusterSize
,
409 IN PFMIFSCALLBACK Callback
)
411 PFILE_SYSTEM FileSystem
;
413 FileSystem
= GetFileSystemByName(FileSystemName
);
415 if (!FileSystem
|| !FileSystem
->FormatFunc
)
417 // BOOLEAN Argument = FALSE;
418 // Callback(DONE, 0, &Argument);
419 return STATUS_NOT_SUPPORTED
;
422 return FileSystem
->FormatFunc(DriveRoot
,
433 IN PCWSTR FileSystemName
,
434 IN FMIFS_MEDIA_FLAG MediaFlag
,
436 IN BOOLEAN QuickFormat
,
437 IN ULONG ClusterSize
,
438 IN PFMIFSCALLBACK Callback
)
440 UNICODE_STRING DriveRootU
;
441 UNICODE_STRING LabelU
;
443 RtlInitUnicodeString(&DriveRootU
, DriveRoot
);
444 RtlInitUnicodeString(&LabelU
, Label
);
446 return FormatFileSystem_UStr(&DriveRootU
,
457 FileSystemToPartitionType(
458 IN PCWSTR FileSystem
,
459 IN PULARGE_INTEGER StartSector
,
460 IN PULARGE_INTEGER SectorCount
)
462 ASSERT(FileSystem
&& StartSector
&& SectorCount
);
464 if (wcsicmp(FileSystem
, L
"FAT") == 0 ||
465 wcsicmp(FileSystem
, L
"FAT32") == 0 ||
466 wcsicmp(FileSystem
, L
"RAW") == 0)
468 if (SectorCount
->QuadPart
< 8192)
470 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
471 return PARTITION_FAT_12
;
473 else if (StartSector
->QuadPart
< 1450560)
475 /* Partition starts below the 8.4GB boundary ==> CHS partition */
477 if (SectorCount
->QuadPart
< 65536)
479 /* FAT16 CHS partition (partition size < 32MB) */
480 return PARTITION_FAT_16
;
482 else if (SectorCount
->QuadPart
< 1048576)
484 /* FAT16 CHS partition (partition size < 512MB) */
485 return PARTITION_HUGE
;
489 /* FAT32 CHS partition (partition size >= 512MB) */
490 return PARTITION_FAT32
;
495 /* Partition starts above the 8.4GB boundary ==> LBA partition */
497 if (SectorCount
->QuadPart
< 1048576)
499 /* FAT16 LBA partition (partition size < 512MB) */
500 return PARTITION_XINT13
;
504 /* FAT32 LBA partition (partition size >= 512MB) */
505 return PARTITION_FAT32_XINT13
;
509 else if (wcsicmp(FileSystem
, L
"NTFS") == 0)
511 return PARTITION_IFS
;
513 else if (wcsicmp(FileSystem
, L
"BTRFS") == 0 ||
514 wcsicmp(FileSystem
, L
"EXT2") == 0 ||
515 wcsicmp(FileSystem
, L
"EXT3") == 0 ||
516 wcsicmp(FileSystem
, L
"EXT4") == 0 ||
517 wcsicmp(FileSystem
, L
"FFS") == 0 ||
518 wcsicmp(FileSystem
, L
"REISERFS") == 0)
520 return PARTITION_LINUX
;
524 /* Unknown file system */
525 DPRINT1("Unknown file system '%S'\n", FileSystem
);
526 return PARTITION_ENTRY_UNUSED
;
532 // Formatting routines
536 PreparePartitionForFormatting(
537 IN
struct _PARTENTRY
* PartEntry
,
538 IN PCWSTR FileSystemName
)
542 if (!FileSystemName
|| !*FileSystemName
)
544 DPRINT1("No file system specified?\n");
548 PartitionType
= FileSystemToPartitionType(FileSystemName
,
549 &PartEntry
->StartSector
,
550 &PartEntry
->SectorCount
);
551 if (PartitionType
== PARTITION_ENTRY_UNUSED
)
553 /* Unknown file system */
554 DPRINT1("Unknown file system '%S'\n", FileSystemName
);
558 SetPartitionType(PartEntry
, PartitionType
);
561 // FIXME: Do this now, or after the partition was actually formatted??
563 /* Set the new partition's file system proper */
564 RtlStringCbCopyW(PartEntry
->FileSystem
,
565 sizeof(PartEntry
->FileSystem
),