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 // 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 /* GLOBALS ******************************************************************/
33 /* The list of file systems on which we can install ReactOS */
34 FILE_SYSTEM RegisteredFileSystems
[] =
36 /* NOTE: The FAT formatter automatically determines
37 * whether it will use FAT-16 or FAT-32. */
38 { L
"FAT" , VfatFormat
, VfatChkdsk
},
40 { L
"FAT32", VfatFormat
, VfatChkdsk
}, // Do we support specific FAT sub-formats specifications?
41 { L
"FATX" , VfatxFormat
, VfatxChkdsk
},
42 { L
"NTFS" , NtfsFormat
, NtfsChkdsk
},
44 { L
"BTRFS", BtrfsFormatEx
, BtrfsChkdskEx
},
46 { L
"EXT2" , Ext2Format
, Ext2Chkdsk
},
47 { L
"EXT3" , Ext2Format
, Ext2Chkdsk
},
48 { L
"EXT4" , Ext2Format
, Ext2Chkdsk
},
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 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
114 IN
struct _PARTENTRY
* PartEntry
,
115 IN OUT PWSTR FileSystemName
,
116 IN SIZE_T FileSystemNameSize
)
119 UNICODE_STRING PartitionRootPath
;
120 OBJECT_ATTRIBUTES ObjectAttributes
;
122 IO_STATUS_BLOCK IoStatusBlock
;
123 WCHAR PathBuffer
[MAX_PATH
];
124 UCHAR Buffer
[sizeof(FILE_FS_ATTRIBUTE_INFORMATION
) + MAX_PATH
* sizeof(WCHAR
)];
125 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute
= (PFILE_FS_ATTRIBUTE_INFORMATION
)Buffer
;
127 /* Set PartitionRootPath */
128 RtlStringCchPrintfW(PathBuffer
, ARRAYSIZE(PathBuffer
),
129 L
"\\Device\\Harddisk%lu\\Partition%lu",
130 PartEntry
->DiskEntry
->DiskNumber
,
131 PartEntry
->PartitionNumber
);
132 RtlInitUnicodeString(&PartitionRootPath
, PathBuffer
);
133 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath
);
135 /* Open the partition */
136 InitializeObjectAttributes(&ObjectAttributes
,
138 OBJ_CASE_INSENSITIVE
,
141 Status
= NtOpenFile(&FileHandle
, // PartitionHandle,
142 FILE_GENERIC_READ
/* | SYNCHRONIZE */,
145 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
146 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
147 if (!NT_SUCCESS(Status
))
149 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionRootPath
, Status
);
153 /* Retrieve the FS attributes */
154 Status
= NtQueryVolumeInformationFile(FileHandle
,
158 FileFsAttributeInformation
);
161 if (!NT_SUCCESS(Status
))
163 DPRINT1("NtQueryVolumeInformationFile failed for partition '%wZ', Status 0x%08lx\n",
164 &PartitionRootPath
, Status
);
168 if (FileSystemNameSize
< FileFsAttribute
->FileSystemNameLength
+ sizeof(WCHAR
))
169 return STATUS_BUFFER_TOO_SMALL
;
171 return RtlStringCbCopyNW(FileSystemName
, FileSystemNameSize
,
172 FileFsAttribute
->FileSystemName
,
173 FileFsAttribute
->FileSystemNameLength
);
178 // IN PFILE_SYSTEM_LIST FileSystemList,
179 IN
struct _PARTENTRY
* PartEntry
)
181 PFILE_SYSTEM CurrentFileSystem
;
183 PWSTR FileSystemName
= NULL
;
184 WCHAR FsRecFileSystemName
[MAX_PATH
];
186 CurrentFileSystem
= PartEntry
->FileSystem
;
188 /* We have a file system, return it */
189 if (CurrentFileSystem
!= NULL
&& CurrentFileSystem
->FileSystemName
!= NULL
)
190 return CurrentFileSystem
;
192 DPRINT1("File system not found, try to guess one...\n");
194 CurrentFileSystem
= NULL
;
197 * We don't have one...
199 * Try to infer a file system using NT file system recognition.
201 Status
= _MyGetFileSystem(PartEntry
, FsRecFileSystemName
, sizeof(FsRecFileSystemName
));
202 if (NT_SUCCESS(Status
) && *FsRecFileSystemName
)
204 /* Temporary HACK: map FAT32 back to FAT */
205 if (wcscmp(FsRecFileSystemName
, L
"FAT32") == 0)
206 RtlStringCbCopyW(FsRecFileSystemName
, sizeof(FsRecFileSystemName
), L
"FAT");
208 FileSystemName
= FsRecFileSystemName
;
213 * We don't have one...
215 * Try to infer a preferred file system for this partition, given its ID.
217 * WARNING: This is partly a hack, since partitions with the same ID can
218 * be formatted with different file systems: for example, usual Linux
219 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
220 * same partition ID 0x83.
222 * The proper fix is to make a function that detects the existing FS
223 * from a given partition (not based on the partition ID).
224 * On the contrary, for unformatted partitions with a given ID, the
225 * following code is OK.
227 if ((PartEntry
->PartitionType
== PARTITION_FAT_12
) ||
228 (PartEntry
->PartitionType
== PARTITION_FAT_16
) ||
229 (PartEntry
->PartitionType
== PARTITION_HUGE
) ||
230 (PartEntry
->PartitionType
== PARTITION_XINT13
) ||
231 (PartEntry
->PartitionType
== PARTITION_FAT32
) ||
232 (PartEntry
->PartitionType
== PARTITION_FAT32_XINT13
))
234 FileSystemName
= L
"FAT";
236 else if (PartEntry
->PartitionType
== PARTITION_LINUX
)
238 // WARNING: See the warning above.
239 /* Could also be EXT2/3/4, ReiserFS, ... */
240 FileSystemName
= L
"BTRFS";
242 else if (PartEntry
->PartitionType
== PARTITION_IFS
)
244 // WARNING: See the warning above.
245 /* Could also be HPFS */
246 FileSystemName
= L
"NTFS";
250 // HACK: WARNING: We cannot write on this FS yet!
253 if (PartEntry
->PartitionType
== PARTITION_IFS
)
254 DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName
);
257 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
258 PartEntry
->PartitionType
, FileSystemName
? FileSystemName
: L
"None");
261 CurrentFileSystem
= GetFileSystemByName(FileSystemName
);
263 return CurrentFileSystem
;
268 // Formatting routines
272 PreparePartitionForFormatting(
273 IN
struct _PARTENTRY
* PartEntry
,
274 IN PFILE_SYSTEM FileSystem
)
278 DPRINT1("No file system specified?\n");
282 if (wcscmp(FileSystem
->FileSystemName
, L
"FAT") == 0)
284 if (PartEntry
->SectorCount
.QuadPart
< 8192)
286 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
287 SetPartitionType(PartEntry
, PARTITION_FAT_12
);
289 else if (PartEntry
->StartSector
.QuadPart
< 1450560)
291 /* Partition starts below the 8.4GB boundary ==> CHS partition */
293 if (PartEntry
->SectorCount
.QuadPart
< 65536)
295 /* FAT16 CHS partition (partition size < 32MB) */
296 SetPartitionType(PartEntry
, PARTITION_FAT_16
);
298 else if (PartEntry
->SectorCount
.QuadPart
< 1048576)
300 /* FAT16 CHS partition (partition size < 512MB) */
301 SetPartitionType(PartEntry
, PARTITION_HUGE
);
305 /* FAT32 CHS partition (partition size >= 512MB) */
306 SetPartitionType(PartEntry
, PARTITION_FAT32
);
311 /* Partition starts above the 8.4GB boundary ==> LBA partition */
313 if (PartEntry
->SectorCount
.QuadPart
< 1048576)
315 /* FAT16 LBA partition (partition size < 512MB) */
316 SetPartitionType(PartEntry
, PARTITION_XINT13
);
320 /* FAT32 LBA partition (partition size >= 512MB) */
321 SetPartitionType(PartEntry
, PARTITION_FAT32_XINT13
);
325 else if (wcscmp(FileSystem
->FileSystemName
, L
"BTRFS") == 0)
327 SetPartitionType(PartEntry
, PARTITION_LINUX
);
330 else if (wcscmp(FileSystem
->FileSystemName
, L
"EXT2") == 0)
332 SetPartitionType(PartEntry
, PARTITION_LINUX
);
334 else if (wcscmp(FileSystem
->FileSystemName
, L
"NTFS") == 0)
336 SetPartitionType(PartEntry
, PARTITION_IFS
);
341 /* Unknown file system? */
342 DPRINT1("Unknown file system \"%S\"?\n", FileSystem
->FileSystemName
);
347 // FIXME: Do this now, or after the partition was actually formatted??
349 /* Set the new partition's file system proper */
350 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)
351 PartEntry
->FileSystem
= FileSystem
;