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/btrfslib.h>
28 // #include <fslib/ext2lib.h>
29 // #include <fslib/ntfslib.h>
35 FILE_SYSTEM RegisteredFileSystems
[] =
37 { L
"FAT" , VfatFormat
, VfatChkdsk
},
38 // { L"FAT32", VfatFormat, VfatChkdsk },
40 { L
"FATX" , VfatxFormat
, VfatxChkdsk
},
41 { L
"NTFS" , NtfsFormat
, NtfsChkdsk
},
43 { L
"EXT2" , Ext2Format
, Ext2Chkdsk
},
44 { L
"EXT3" , Ext2Format
, Ext2Chkdsk
},
45 { L
"EXT4" , Ext2Format
, Ext2Chkdsk
},
47 { L
"BTRFS", BtrfsFormatEx
, BtrfsChkdskEx
},
49 { L
"FFS" , FfsFormat
, FfsChkdsk
},
50 { L
"REISERFS", ReiserfsFormat
, ReiserfsChkdsk
},
55 /* FUNCTIONS ****************************************************************/
58 GetRegisteredFileSystems(OUT PULONG Count
)
60 *Count
= ARRAYSIZE(RegisteredFileSystems
);
61 return RegisteredFileSystems
;
66 // IN PFILE_SYSTEM_LIST List,
67 IN PCWSTR FileSystemName
)
69 #if 0 // Reenable when the list of registered FSes will again be dynamic
71 PLIST_ENTRY ListEntry
;
72 PFILE_SYSTEM_ITEM Item
;
74 ListEntry
= List
->ListHead
.Flink
;
75 while (ListEntry
!= &List
->ListHead
)
77 Item
= CONTAINING_RECORD(ListEntry
, FILE_SYSTEM_ITEM
, ListEntry
);
78 if (Item
->FileSystemName
&& wcsicmp(FileSystemName
, Item
->FileSystemName
) == 0)
81 ListEntry
= ListEntry
->Flink
;
87 PFILE_SYSTEM FileSystems
;
89 FileSystems
= GetRegisteredFileSystems(&Count
);
90 if (!FileSystems
|| Count
== 0)
95 if (FileSystems
->FileSystemName
&& wcsicmp(FileSystemName
, FileSystems
->FileSystemName
) == 0)
108 // FileSystem recognition (using NT OS functionality)
111 #if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
113 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
116 IN
struct _PARTENTRY
* PartEntry
,
117 IN OUT PWSTR FileSystemName
,
118 IN SIZE_T FileSystemNameSize
)
122 IO_STATUS_BLOCK IoStatusBlock
;
123 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
;
124 UCHAR Buffer
[sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
)];
126 OBJECT_ATTRIBUTES ObjectAttributes
;
127 UNICODE_STRING PartitionRootPath
;
128 WCHAR PathBuffer
[MAX_PATH
];
130 FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
132 /* Set PartitionRootPath */
133 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
134 // L"\\Device\\Harddisk%lu\\Partition%lu", // Should work! But because ReactOS sucks atm. it actually doesn't work!!
135 L
"\\Device\\Harddisk%lu\\Partition%lu\\", // HACK: Use this as a temporary hack!
136 PartEntry
->DiskEntry
->DiskNumber
,
137 PartEntry
->PartitionNumber
);
138 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
139 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
141 /* Open the partition */
142 InitializeObjectAttributes(&ObjectAttributes
,
144 OBJ_CASE_INSENSITIVE
,
147 Status
= NtOpenFile(&FileHandle
, // PartitionHandle,
148 FILE_GENERIC_READ
/* | SYNCHRONIZE */,
152 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
153 if (!NT_SUCCESS(Status
))
155 DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath
, Status
);
159 /* Retrieve the FS attributes */
160 Status
= NtQueryVolumeInformationFile(FileHandle
,
164 FileFsAttributeInformation
);
167 if (!NT_SUCCESS(Status
))
169 DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath
, Status
);
173 if (FileSystemNameSize
* sizeof(WCHAR
) < FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
174 return STATUS_BUFFER_TOO_SMALL
;
176 RtlCopyMemory(FileSystemName
,
177 FileFsAttribute
->FileSystemName
,
178 FileFsAttribute
->FileSystemNameLength
);
179 FileSystemName
[FileFsAttribute
->FileSystemNameLength
/ sizeof(WCHAR
)] = UNICODE_NULL
;
181 return STATUS_SUCCESS
;
188 // IN PFILE_SYSTEM_LIST FileSystemList,
189 IN
struct _PARTENTRY
* PartEntry
)
191 PFILE_SYSTEM CurrentFileSystem
;
192 PWSTR FileSystemName
= NULL
;
193 #if 0 // For code temporarily disabled below
195 WCHAR FsRecFileSystemName
[MAX_PATH
];
198 CurrentFileSystem
= PartEntry
->FileSystem
;
200 /* We have a file system, return it */
201 if (CurrentFileSystem
!= NULL
&& CurrentFileSystem
->FileSystemName
!= NULL
)
202 return CurrentFileSystem
;
204 DPRINT1("File system not found, try to guess one...\n");
206 CurrentFileSystem
= NULL
;
208 #if 0 // This is an example of old code...
210 if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
211 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
212 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
213 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
214 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
215 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
217 if (CheckFatFormat())
218 FileSystemName
= L
"FAT";
220 FileSystemName
= NULL
;
222 else if (PartEntry
->PartitionType
== PARTITION_EXT2
)
224 if (CheckExt2Format())
225 FileSystemName
= L
"EXT2";
227 FileSystemName
= NULL
;
229 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
231 if (CheckNtfsFormat())
232 FileSystemName
= L
"NTFS";
233 else if (CheckHpfsFormat())
234 FileSystemName
= L
"HPFS";
236 FileSystemName
= NULL
;
240 FileSystemName
= NULL
;
245 #if 0 // FIXME: To be fully enabled when our storage stack & al. work better!
248 * We don't have one...
250 * Try to infer one using NT file system recognition.
252 Status
= _MyGetFileSystem(PartEntry
, FsRecFileSystemName
, ARRAYSIZE(FsRecFileSystemName
));
253 if (NT_SUCCESS(Status
) && *FsRecFileSystemName
)
255 /* Temporary HACK: map FAT32 back to FAT */
256 if (wcscmp(FsRecFileSystemName
, L
"FAT32") == 0)
257 wcscpy(FsRecFileSystemName
, L
"FAT");
259 FileSystemName
= FsRecFileSystemName
;
266 * We don't have one...
268 * Try to infer a preferred file system for this partition, given its ID.
270 * WARNING: This is partly a hack, since partitions with the same ID can
271 * be formatted with different file systems: for example, usual Linux
272 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
273 * same partition ID 0x83.
275 * The proper fix is to make a function that detects the existing FS
276 * from a given partition (not based on the partition ID).
277 * On the contrary, for unformatted partitions with a given ID, the
278 * following code is OK.
280 if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
281 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
282 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
283 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
284 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
285 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
287 FileSystemName
= L
"FAT";
289 else if (PartEntry
->PartitionType
== PARTITION_LINUX
)
291 // WARNING: See the warning above.
292 FileSystemName
= L
"BTRFS";
294 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
296 // WARNING: See the warning above.
297 FileSystemName
= L
"NTFS"; /* FIXME: Not quite correct! */
298 // FIXME: We may have HPFS too...
302 Quit
: // For code temporarily disabled above
305 // HACK: WARNING: We cannot write on this FS yet!
308 if (PartEntry
->PartitionType
== PARTITION_IFS
)
309 DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName
);
312 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
313 PartEntry
->PartitionType
, FileSystemName
? FileSystemName
: L
"None");
315 if (FileSystemName
!= NULL
)
316 CurrentFileSystem
= GetFileSystemByName(FileSystemName
);
318 return CurrentFileSystem
;
323 // Formatting routines
327 PreparePartitionForFormatting(
328 IN
struct _PARTENTRY
* PartEntry
,
329 IN PFILE_SYSTEM FileSystem
)
333 DPRINT1("No file system specified?\n");
337 if (wcscmp(FileSystem
->FileSystemName
, L
"FAT") == 0)
339 if (PartEntry
->SectorCount
.QuadPart
< 8192)
341 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
342 SetPartitionType(PartEntry
, PARTITION_FAT_12
);
344 else if (PartEntry
->StartSector
.QuadPart
< 1450560)
346 /* Partition starts below the 8.4GB boundary ==> CHS partition */
348 if (PartEntry
->SectorCount
.QuadPart
< 65536)
350 /* FAT16 CHS partition (partition size < 32MB) */
351 SetPartitionType(PartEntry
, PARTITION_FAT_16
);
353 else if (PartEntry
->SectorCount
.QuadPart
< 1048576)
355 /* FAT16 CHS partition (partition size < 512MB) */
356 SetPartitionType(PartEntry
, PARTITION_HUGE
);
360 /* FAT32 CHS partition (partition size >= 512MB) */
361 SetPartitionType(PartEntry
, PARTITION_FAT32
);
366 /* Partition starts above the 8.4GB boundary ==> LBA partition */
368 if (PartEntry
->SectorCount
.QuadPart
< 1048576)
370 /* FAT16 LBA partition (partition size < 512MB) */
371 SetPartitionType(PartEntry
, PARTITION_XINT13
);
375 /* FAT32 LBA partition (partition size >= 512MB) */
376 SetPartitionType(PartEntry
, PARTITION_FAT32_XINT13
);
380 else if (wcscmp(FileSystem
->FileSystemName
, L
"BTRFS") == 0)
382 SetPartitionType(PartEntry
, PARTITION_LINUX
);
385 else if (wcscmp(FileSystem
->FileSystemName
, L
"EXT2") == 0)
387 SetPartitionType(PartEntry
, PARTITION_EXT2
);
389 else if (wcscmp(FileSystem
->FileSystemName
, L
"NTFS") == 0)
391 SetPartitionType(PartEntry
, PARTITION_IFS
);
396 /* Unknown file system? */
397 DPRINT1("Unknown file system \"%S\"?\n", FileSystem
->FileSystemName
);
402 // FIXME: Do this now, or after the partition was actually formatted??
404 /* Set the new partition's file system proper */
405 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)
406 PartEntry
->FileSystem
= FileSystem
;