[SETUP] Remove myself from the 1st stage setup code
[reactos.git] / base / setup / lib / fsutil.c
1 /*
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
7 */
8
9 //
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.
13 //
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...
17 //
18
19 /* INCLUDES *****************************************************************/
20
21 #include "precomp.h"
22
23 #include "fsutil.h"
24 #include "partlist.h"
25
26 #include <fslib/vfatlib.h>
27 // #include <fslib/ext2lib.h>
28 // #include <fslib/ntfslib.h>
29
30 #define NDEBUG
31 #include <debug.h>
32
33
34 FILE_SYSTEM RegisteredFileSystems[] =
35 {
36 { L"FAT" , VfatFormat, VfatChkdsk },
37 // { L"FAT32", VfatFormat, VfatChkdsk },
38 #if 0
39 { L"FATX" , VfatxFormat, VfatxChkdsk },
40 { L"NTFS" , NtfsFormat, NtfsChkdsk },
41
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 },
48 #endif
49 };
50
51
52 /* FUNCTIONS ****************************************************************/
53
54 PFILE_SYSTEM
55 GetRegisteredFileSystems(OUT PULONG Count)
56 {
57 *Count = ARRAYSIZE(RegisteredFileSystems);
58 return RegisteredFileSystems;
59 }
60
61 PFILE_SYSTEM
62 GetFileSystemByName(
63 // IN PFILE_SYSTEM_LIST List,
64 IN PCWSTR FileSystemName)
65 {
66 #if 0 // Reenable when the list of registered FSes will again be dynamic
67
68 PLIST_ENTRY ListEntry;
69 PFILE_SYSTEM_ITEM Item;
70
71 ListEntry = List->ListHead.Flink;
72 while (ListEntry != &List->ListHead)
73 {
74 Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
75 if (Item->FileSystemName && wcsicmp(FileSystemName, Item->FileSystemName) == 0)
76 return Item;
77
78 ListEntry = ListEntry->Flink;
79 }
80
81 #else
82
83 ULONG Count;
84 PFILE_SYSTEM FileSystems;
85
86 FileSystems = GetRegisteredFileSystems(&Count);
87 if (!FileSystems || Count == 0)
88 return NULL;
89
90 while (Count--)
91 {
92 if (FileSystems->FileSystemName && wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0)
93 return FileSystems;
94
95 ++FileSystems;
96 }
97
98 #endif
99
100 return NULL;
101 }
102
103
104 //
105 // FileSystem recognition (using NT OS functionality)
106 //
107
108 #if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
109
110 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
111 static NTSTATUS
112 _MyGetFileSystem(
113 IN struct _PARTENTRY* PartEntry,
114 IN OUT PWSTR FileSystemName,
115 IN SIZE_T FileSystemNameSize)
116 {
117 NTSTATUS Status;
118 HANDLE FileHandle;
119 IO_STATUS_BLOCK IoStatusBlock;
120 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
121 UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
122
123 OBJECT_ATTRIBUTES ObjectAttributes;
124 UNICODE_STRING PartitionRootPath;
125 WCHAR PathBuffer[MAX_PATH];
126
127 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
128
129 /* Set PartitionRootPath */
130 swprintf(PathBuffer,
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);
137
138 /* Open the partition */
139 InitializeObjectAttributes(&ObjectAttributes,
140 &PartitionRootPath,
141 OBJ_CASE_INSENSITIVE,
142 NULL,
143 NULL);
144 Status = NtOpenFile(&FileHandle, // PartitionHandle,
145 FILE_GENERIC_READ /* | SYNCHRONIZE */,
146 &ObjectAttributes,
147 &IoStatusBlock,
148 FILE_SHARE_READ,
149 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
150 if (!NT_SUCCESS(Status))
151 {
152 DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
153 return Status;
154 }
155
156 /* Retrieve the FS attributes */
157 Status = NtQueryVolumeInformationFile(FileHandle,
158 &IoStatusBlock,
159 FileFsAttribute,
160 sizeof(Buffer),
161 FileFsAttributeInformation);
162 NtClose(FileHandle);
163
164 if (!NT_SUCCESS(Status))
165 {
166 DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
167 return Status;
168 }
169
170 if (FileSystemNameSize * sizeof(WCHAR) < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
171 return STATUS_BUFFER_TOO_SMALL;
172
173 RtlCopyMemory(FileSystemName,
174 FileFsAttribute->FileSystemName,
175 FileFsAttribute->FileSystemNameLength);
176 FileSystemName[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
177
178 return STATUS_SUCCESS;
179 }
180
181 #endif
182
183 PFILE_SYSTEM
184 GetFileSystem(
185 // IN PFILE_SYSTEM_LIST FileSystemList,
186 IN struct _PARTENTRY* PartEntry)
187 {
188 PFILE_SYSTEM CurrentFileSystem;
189 PWSTR FileSystemName = NULL;
190 #if 0 // For code temporarily disabled below
191 NTSTATUS Status;
192 WCHAR FsRecFileSystemName[MAX_PATH];
193 #endif
194
195 CurrentFileSystem = PartEntry->FileSystem;
196
197 /* We have a file system, return it */
198 if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL)
199 return CurrentFileSystem;
200
201 DPRINT1("File system not found, try to guess one...\n");
202
203 CurrentFileSystem = NULL;
204
205 #if 0 // This is an example of old code...
206
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))
213 {
214 if (CheckFatFormat())
215 FileSystemName = L"FAT";
216 else
217 FileSystemName = NULL;
218 }
219 else if (PartEntry->PartitionType == PARTITION_EXT2)
220 {
221 if (CheckExt2Format())
222 FileSystemName = L"EXT2";
223 else
224 FileSystemName = NULL;
225 }
226 else if (PartEntry->PartitionType == PARTITION_IFS)
227 {
228 if (CheckNtfsFormat())
229 FileSystemName = L"NTFS";
230 else if (CheckHpfsFormat())
231 FileSystemName = L"HPFS";
232 else
233 FileSystemName = NULL;
234 }
235 else
236 {
237 FileSystemName = NULL;
238 }
239
240 #endif
241
242 #if 0 // FIXME: To be fully enabled when our storage stack & al. work better!
243
244 /*
245 * We don't have one...
246 *
247 * Try to infer one using NT file system recognition.
248 */
249 Status = _MyGetFileSystem(PartEntry, FsRecFileSystemName, ARRAYSIZE(FsRecFileSystemName));
250 if (NT_SUCCESS(Status) && *FsRecFileSystemName)
251 {
252 /* Temporary HACK: map FAT32 back to FAT */
253 if (wcscmp(FsRecFileSystemName, L"FAT32") == 0)
254 wcscpy(FsRecFileSystemName, L"FAT");
255
256 FileSystemName = FsRecFileSystemName;
257 goto Quit;
258 }
259
260 #endif
261
262 /*
263 * We don't have one...
264 *
265 * Try to infer a preferred file system for this partition, given its ID.
266 *
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.
271 *
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.
276 */
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))
283 {
284 FileSystemName = L"FAT";
285 }
286 else if (PartEntry->PartitionType == PARTITION_EXT2)
287 {
288 // WARNING: See the warning above.
289 FileSystemName = L"EXT2";
290 // FIXME: We may have EXT3, 4 too...
291 }
292 else if (PartEntry->PartitionType == PARTITION_IFS)
293 {
294 // WARNING: See the warning above.
295 FileSystemName = L"NTFS"; /* FIXME: Not quite correct! */
296 // FIXME: We may have HPFS too...
297 }
298
299 #if 0
300 Quit: // For code temporarily disabled above
301 #endif
302
303 // HACK: WARNING: We cannot write on this FS yet!
304 if (FileSystemName)
305 {
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);
308 }
309
310 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
311 PartEntry->PartitionType, FileSystemName ? FileSystemName : L"None");
312
313 if (FileSystemName != NULL)
314 CurrentFileSystem = GetFileSystemByName(FileSystemName);
315
316 return CurrentFileSystem;
317 }
318
319
320 //
321 // Formatting routines
322 //
323
324 BOOLEAN
325 PreparePartitionForFormatting(
326 IN struct _PARTENTRY* PartEntry,
327 IN PFILE_SYSTEM FileSystem)
328 {
329 if (!FileSystem)
330 {
331 DPRINT1("No file system specified?\n");
332 return FALSE;
333 }
334
335 if (wcscmp(FileSystem->FileSystemName, L"FAT") == 0)
336 {
337 if (PartEntry->SectorCount.QuadPart < 8192)
338 {
339 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
340 SetPartitionType(PartEntry, PARTITION_FAT_12);
341 }
342 else if (PartEntry->StartSector.QuadPart < 1450560)
343 {
344 /* Partition starts below the 8.4GB boundary ==> CHS partition */
345
346 if (PartEntry->SectorCount.QuadPart < 65536)
347 {
348 /* FAT16 CHS partition (partition size < 32MB) */
349 SetPartitionType(PartEntry, PARTITION_FAT_16);
350 }
351 else if (PartEntry->SectorCount.QuadPart < 1048576)
352 {
353 /* FAT16 CHS partition (partition size < 512MB) */
354 SetPartitionType(PartEntry, PARTITION_HUGE);
355 }
356 else
357 {
358 /* FAT32 CHS partition (partition size >= 512MB) */
359 SetPartitionType(PartEntry, PARTITION_FAT32);
360 }
361 }
362 else
363 {
364 /* Partition starts above the 8.4GB boundary ==> LBA partition */
365
366 if (PartEntry->SectorCount.QuadPart < 1048576)
367 {
368 /* FAT16 LBA partition (partition size < 512MB) */
369 SetPartitionType(PartEntry, PARTITION_XINT13);
370 }
371 else
372 {
373 /* FAT32 LBA partition (partition size >= 512MB) */
374 SetPartitionType(PartEntry, PARTITION_FAT32_XINT13);
375 }
376 }
377 }
378 #if 0
379 else if (wcscmp(FileSystem->FileSystemName, L"EXT2") == 0)
380 {
381 SetPartitionType(PartEntry, PARTITION_EXT2);
382 }
383 else if (wcscmp(FileSystem->FileSystemName, L"NTFS") == 0)
384 {
385 SetPartitionType(PartEntry, PARTITION_IFS);
386 }
387 #endif
388 else
389 {
390 /* Unknown file system? */
391 DPRINT1("Unknown file system \"%S\"?\n", FileSystem->FileSystemName);
392 return FALSE;
393 }
394
395 //
396 // FIXME: Do this now, or after the partition was actually formatted??
397 //
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;
401
402 return TRUE;
403 }
404
405 /* EOF */