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-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
6 * Copyright 2017-2018 Hermes Belusca-Maito
10 // This is basically the code for listing available FileSystem providers
11 // (currently hardcoded in a list), and for performing a basic FileSystem
12 // recognition for a given disk partition.
14 // See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
15 // for how to get FS providers in a dynamic way. In the (near) future we may
16 // consider merging some of this code with us into a fmifs / fsutil / fslib library...
19 /* INCLUDES *****************************************************************/
26 #include <fslib/vfatlib.h>
27 // #include <fslib/ext2lib.h>
28 // #include <fslib/ntfslib.h>
34 FILE_SYSTEM RegisteredFileSystems
[] =
36 { L
"FAT" , VfatFormat
, VfatChkdsk
},
37 // { L"FAT32", VfatFormat, VfatChkdsk },
39 { L
"FATX" , VfatxFormat
, VfatxChkdsk
},
40 { L
"NTFS" , NtfsFormat
, NtfsChkdsk
},
42 { L
"EXT2" , Ext2Format
, Ext2Chkdsk
},
43 { L
"EXT3" , Ext2Format
, Ext2Chkdsk
},
44 { L
"EXT4" , Ext2Format
, Ext2Chkdsk
},
45 { L
"BTRFS", BtrfsFormatEx
, BtrfsChkdskEx
},
46 { L
"FFS" , FfsFormat
, FfsChkdsk
},
47 { L
"REISERFS", ReiserfsFormat
, ReiserfsChkdsk
},
52 /* FUNCTIONS ****************************************************************/
55 GetRegisteredFileSystems(OUT PULONG Count
)
57 *Count
= ARRAYSIZE(RegisteredFileSystems
);
58 return RegisteredFileSystems
;
63 // IN PFILE_SYSTEM_LIST List,
64 IN PCWSTR FileSystemName
)
66 #if 0 // Reenable when the list of registered FSes will again be dynamic
68 PLIST_ENTRY ListEntry
;
69 PFILE_SYSTEM_ITEM Item
;
71 ListEntry
= List
->ListHead
.Flink
;
72 while (ListEntry
!= &List
->ListHead
)
74 Item
= CONTAINING_RECORD(ListEntry
, FILE_SYSTEM_ITEM
, ListEntry
);
75 if (Item
->FileSystemName
&& wcsicmp(FileSystemName
, Item
->FileSystemName
) == 0)
78 ListEntry
= ListEntry
->Flink
;
84 PFILE_SYSTEM FileSystems
;
86 FileSystems
= GetRegisteredFileSystems(&Count
);
87 if (!FileSystems
|| Count
== 0)
92 if (FileSystems
->FileSystemName
&& wcsicmp(FileSystemName
, FileSystems
->FileSystemName
) == 0)
105 // FileSystem recognition (using NT OS functionality)
108 #if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
110 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
113 IN
struct _PARTENTRY
* PartEntry
,
114 IN OUT PWSTR FileSystemName
,
115 IN SIZE_T FileSystemNameSize
)
119 IO_STATUS_BLOCK IoStatusBlock
;
120 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
121 UCHAR Buffer
[sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
)];
123 OBJECT_ATTRIBUTES ObjectAttributes
;
124 UNICODE_STRING PartitionRootPath
;
125 WCHAR PathBuffer
[MAX_PATH
];
127 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
129 /* Set PartitionRootPath */
131 // L"\\Device\\Harddisk%lu\\Partition%lu", // Should work! But because ReactOS sucks atm. it actually doesn't work!!
132 L
"\\Device\\Harddisk%lu\\Partition%lu\\", // HACK: Use this as a temporary hack!
133 PartEntry
->DiskEntry
->DiskNumber
,
134 PartEntry
->PartitionNumber
);
135 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
136 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
138 /* Open the partition */
139 InitializeObjectAttributes(&ObjectAttributes
,
141 OBJ_CASE_INSENSITIVE
,
144 Status
= NtOpenFile(&FileHandle
, // PartitionHandle,
145 FILE_GENERIC_READ
/* | SYNCHRONIZE */,
149 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
150 if (!NT_SUCCESS(Status
))
152 DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath
, Status
);
156 /* Retrieve the FS attributes */
157 Status
= NtQueryVolumeInformationFile(FileHandle
,
161 FileFsAttributeInformation
);
164 if (!NT_SUCCESS(Status
))
166 DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath
, Status
);
170 if (FileSystemNameSize
* sizeof(WCHAR
) < FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
171 return STATUS_BUFFER_TOO_SMALL
;
173 RtlCopyMemory(FileSystemName
,
174 FileFsAttribute
->FileSystemName
,
175 FileFsAttribute
->FileSystemNameLength
);
176 FileSystemName
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
178 return STATUS_SUCCESS
;
185 // IN PFILE_SYSTEM_LIST FileSystemList,
186 IN
struct _PARTENTRY
* PartEntry
)
188 PFILE_SYSTEM CurrentFileSystem
;
189 PWSTR FileSystemName
= NULL
;
190 #if 0 // For code temporarily disabled below
192 WCHAR FsRecFileSystemName
[MAX_PATH
];
195 CurrentFileSystem
= PartEntry
->FileSystem
;
197 /* We have a file system, return it */
198 if (CurrentFileSystem
!= NULL
&& CurrentFileSystem
->FileSystemName
!= NULL
)
199 return CurrentFileSystem
;
201 DPRINT1("File system not found, try to guess one...\n");
203 CurrentFileSystem
= NULL
;
205 #if 0 // This is an example of old code...
207 if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
208 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
209 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
210 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
211 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
212 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
214 if (CheckFatFormat())
215 FileSystemName
= L
"FAT";
217 FileSystemName
= NULL
;
219 else if (PartEntry
->PartitionType
== PARTITION_EXT2
)
221 if (CheckExt2Format())
222 FileSystemName
= L
"EXT2";
224 FileSystemName
= NULL
;
226 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
228 if (CheckNtfsFormat())
229 FileSystemName
= L
"NTFS";
230 else if (CheckHpfsFormat())
231 FileSystemName
= L
"HPFS";
233 FileSystemName
= NULL
;
237 FileSystemName
= NULL
;
242 #if 0 // FIXME: To be fully enabled when our storage stack & al. work better!
245 * We don't have one...
247 * Try to infer one using NT file system recognition.
249 Status
= _MyGetFileSystem(PartEntry
, FsRecFileSystemName
, ARRAYSIZE(FsRecFileSystemName
));
250 if (NT_SUCCESS(Status
) && *FsRecFileSystemName
)
252 /* Temporary HACK: map FAT32 back to FAT */
253 if (wcscmp(FsRecFileSystemName
, L
"FAT32") == 0)
254 wcscpy(FsRecFileSystemName
, L
"FAT");
256 FileSystemName
= FsRecFileSystemName
;
263 * We don't have one...
265 * Try to infer a preferred file system for this partition, given its ID.
267 * WARNING: This is partly a hack, since partitions with the same ID can
268 * be formatted with different file systems: for example, usual Linux
269 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
270 * same partition ID 0x83.
272 * The proper fix is to make a function that detects the existing FS
273 * from a given partition (not based on the partition ID).
274 * On the contrary, for unformatted partitions with a given ID, the
275 * following code is OK.
277 if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
278 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
279 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
280 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
281 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
282 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
284 FileSystemName
= L
"FAT";
286 else if (PartEntry
->PartitionType
== PARTITION_EXT2
)
288 // WARNING: See the warning above.
289 FileSystemName
= L
"EXT2";
290 // FIXME: We may have EXT3, 4 too...
292 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
294 // WARNING: See the warning above.
295 FileSystemName
= L
"NTFS"; /* FIXME: Not quite correct! */
296 // FIXME: We may have HPFS too...
300 Quit
: // For code temporarily disabled above
303 // HACK: WARNING: We cannot write on this FS yet!
306 if (PartEntry
->PartitionType
== PARTITION_EXT2
|| PartEntry
->PartitionType
== PARTITION_IFS
)
307 DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName
);
310 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
311 PartEntry
->PartitionType
, FileSystemName
? FileSystemName
: L
"None");
313 if (FileSystemName
!= NULL
)
314 CurrentFileSystem
= GetFileSystemByName(FileSystemName
);
316 return CurrentFileSystem
;
321 // Formatting routines
325 PreparePartitionForFormatting(
326 IN
struct _PARTENTRY
* PartEntry
,
327 IN PFILE_SYSTEM FileSystem
)
331 DPRINT1("No file system specified?\n");
335 if (wcscmp(FileSystem
->FileSystemName
, L
"FAT") == 0)
337 if (PartEntry
->SectorCount
.QuadPart
< 8192)
339 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
340 SetPartitionType(PartEntry
, PARTITION_FAT_12
);
342 else if (PartEntry
->StartSector
.QuadPart
< 1450560)
344 /* Partition starts below the 8.4GB boundary ==> CHS partition */
346 if (PartEntry
->SectorCount
.QuadPart
< 65536)
348 /* FAT16 CHS partition (partition size < 32MB) */
349 SetPartitionType(PartEntry
, PARTITION_FAT_16
);
351 else if (PartEntry
->SectorCount
.QuadPart
< 1048576)
353 /* FAT16 CHS partition (partition size < 512MB) */
354 SetPartitionType(PartEntry
, PARTITION_HUGE
);
358 /* FAT32 CHS partition (partition size >= 512MB) */
359 SetPartitionType(PartEntry
, PARTITION_FAT32
);
364 /* Partition starts above the 8.4GB boundary ==> LBA partition */
366 if (PartEntry
->SectorCount
.QuadPart
< 1048576)
368 /* FAT16 LBA partition (partition size < 512MB) */
369 SetPartitionType(PartEntry
, PARTITION_XINT13
);
373 /* FAT32 LBA partition (partition size >= 512MB) */
374 SetPartitionType(PartEntry
, PARTITION_FAT32_XINT13
);
379 else if (wcscmp(FileSystem
->FileSystemName
, L
"EXT2") == 0)
381 SetPartitionType(PartEntry
, PARTITION_EXT2
);
383 else if (wcscmp(FileSystem
->FileSystemName
, L
"NTFS") == 0)
385 SetPartitionType(PartEntry
, PARTITION_IFS
);
390 /* Unknown file system? */
391 DPRINT1("Unknown file system \"%S\"?\n", FileSystem
->FileSystemName
);
396 // FIXME: Do this now, or after the partition was actually formatted??
398 /* Set the new partition's file system proper */
399 PartEntry
->FormatState
= Formatted
; // Well... This may be set after the real formatting takes place (in which case we should change the FormatState to another value)
400 PartEntry
->FileSystem
= FileSystem
;