[SNDVOL32] Advanced controls dialog: Remove the TBS_AUTOTICKS style from the trackbar...
[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 // 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...
13 //
14
15 /* INCLUDES *****************************************************************/
16
17 #include "precomp.h"
18
19 #include "fsutil.h"
20 #include "partlist.h"
21
22 #include <fslib/vfatlib.h>
23 #include <fslib/btrfslib.h>
24 // #include <fslib/ext2lib.h>
25 // #include <fslib/ntfslib.h>
26
27 #define NDEBUG
28 #include <debug.h>
29
30
31 /* GLOBALS ******************************************************************/
32
33 /* The list of file systems on which we can install ReactOS */
34 FILE_SYSTEM RegisteredFileSystems[] =
35 {
36 /* NOTE: The FAT formatter automatically determines
37 * whether it will use FAT-16 or FAT-32. */
38 { L"FAT" , VfatFormat, VfatChkdsk },
39 #if 0
40 { L"FAT32", VfatFormat, VfatChkdsk }, // Do we support specific FAT sub-formats specifications?
41 { L"FATX" , VfatxFormat, VfatxChkdsk },
42 { L"NTFS" , NtfsFormat, NtfsChkdsk },
43 #endif
44 { L"BTRFS", BtrfsFormatEx, BtrfsChkdskEx },
45 #if 0
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 },
51 #endif
52 };
53
54
55 /* FUNCTIONS ****************************************************************/
56
57 PFILE_SYSTEM
58 GetRegisteredFileSystems(OUT PULONG Count)
59 {
60 *Count = ARRAYSIZE(RegisteredFileSystems);
61 return RegisteredFileSystems;
62 }
63
64 PFILE_SYSTEM
65 GetFileSystemByName(
66 // IN PFILE_SYSTEM_LIST List,
67 IN PCWSTR FileSystemName)
68 {
69 #if 0 // Reenable when the list of registered FSes will again be dynamic
70
71 PLIST_ENTRY ListEntry;
72 PFILE_SYSTEM_ITEM Item;
73
74 ListEntry = List->ListHead.Flink;
75 while (ListEntry != &List->ListHead)
76 {
77 Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
78 if (Item->FileSystemName && wcsicmp(FileSystemName, Item->FileSystemName) == 0)
79 return Item;
80
81 ListEntry = ListEntry->Flink;
82 }
83
84 #else
85
86 ULONG Count;
87 PFILE_SYSTEM FileSystems;
88
89 FileSystems = GetRegisteredFileSystems(&Count);
90 if (!FileSystems || Count == 0)
91 return NULL;
92
93 while (Count--)
94 {
95 if (FileSystems->FileSystemName && wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0)
96 return FileSystems;
97
98 ++FileSystems;
99 }
100
101 #endif
102
103 return NULL;
104 }
105
106
107 //
108 // FileSystem recognition (using NT OS functionality)
109 //
110
111 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
112 static NTSTATUS
113 _MyGetFileSystem(
114 IN struct _PARTENTRY* PartEntry,
115 IN OUT PWSTR FileSystemName,
116 IN SIZE_T FileSystemNameSize)
117 {
118 NTSTATUS Status;
119 UNICODE_STRING PartitionRootPath;
120 OBJECT_ATTRIBUTES ObjectAttributes;
121 HANDLE FileHandle;
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;
126
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);
134
135 /* Open the partition */
136 InitializeObjectAttributes(&ObjectAttributes,
137 &PartitionRootPath,
138 OBJ_CASE_INSENSITIVE,
139 NULL,
140 NULL);
141 Status = NtOpenFile(&FileHandle, // PartitionHandle,
142 FILE_GENERIC_READ /* | SYNCHRONIZE */,
143 &ObjectAttributes,
144 &IoStatusBlock,
145 FILE_SHARE_READ | FILE_SHARE_WRITE,
146 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
147 if (!NT_SUCCESS(Status))
148 {
149 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", &PartitionRootPath, Status);
150 return Status;
151 }
152
153 /* Retrieve the FS attributes */
154 Status = NtQueryVolumeInformationFile(FileHandle,
155 &IoStatusBlock,
156 FileFsAttribute,
157 sizeof(Buffer),
158 FileFsAttributeInformation);
159 NtClose(FileHandle);
160
161 if (!NT_SUCCESS(Status))
162 {
163 DPRINT1("NtQueryVolumeInformationFile failed for partition '%wZ', Status 0x%08lx\n",
164 &PartitionRootPath, Status);
165 return Status;
166 }
167
168 if (FileSystemNameSize < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
169 return STATUS_BUFFER_TOO_SMALL;
170
171 return RtlStringCbCopyNW(FileSystemName, FileSystemNameSize,
172 FileFsAttribute->FileSystemName,
173 FileFsAttribute->FileSystemNameLength);
174 }
175
176 PFILE_SYSTEM
177 GetFileSystem(
178 // IN PFILE_SYSTEM_LIST FileSystemList,
179 IN struct _PARTENTRY* PartEntry)
180 {
181 PFILE_SYSTEM CurrentFileSystem;
182 NTSTATUS Status;
183 PWSTR FileSystemName = NULL;
184 WCHAR FsRecFileSystemName[MAX_PATH];
185
186 CurrentFileSystem = PartEntry->FileSystem;
187
188 /* We have a file system, return it */
189 if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL)
190 return CurrentFileSystem;
191
192 DPRINT1("File system not found, try to guess one...\n");
193
194 CurrentFileSystem = NULL;
195
196 /*
197 * We don't have one...
198 *
199 * Try to infer a file system using NT file system recognition.
200 */
201 Status = _MyGetFileSystem(PartEntry, FsRecFileSystemName, sizeof(FsRecFileSystemName));
202 if (NT_SUCCESS(Status) && *FsRecFileSystemName)
203 {
204 /* Temporary HACK: map FAT32 back to FAT */
205 if (wcscmp(FsRecFileSystemName, L"FAT32") == 0)
206 RtlStringCbCopyW(FsRecFileSystemName, sizeof(FsRecFileSystemName), L"FAT");
207
208 FileSystemName = FsRecFileSystemName;
209 goto Quit;
210 }
211
212 /*
213 * We don't have one...
214 *
215 * Try to infer a preferred file system for this partition, given its ID.
216 *
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.
221 *
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.
226 */
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))
233 {
234 FileSystemName = L"FAT";
235 }
236 else if (PartEntry->PartitionType == PARTITION_LINUX)
237 {
238 // WARNING: See the warning above.
239 /* Could also be EXT2/3/4, ReiserFS, ... */
240 FileSystemName = L"BTRFS";
241 }
242 else if (PartEntry->PartitionType == PARTITION_IFS)
243 {
244 // WARNING: See the warning above.
245 /* Could also be HPFS */
246 FileSystemName = L"NTFS";
247 }
248
249 Quit:
250 // HACK: WARNING: We cannot write on this FS yet!
251 if (FileSystemName)
252 {
253 if (PartEntry->PartitionType == PARTITION_IFS)
254 DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName);
255 }
256
257 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
258 PartEntry->PartitionType, FileSystemName ? FileSystemName : L"None");
259
260 if (FileSystemName)
261 CurrentFileSystem = GetFileSystemByName(FileSystemName);
262
263 return CurrentFileSystem;
264 }
265
266
267 //
268 // Formatting routines
269 //
270
271 BOOLEAN
272 PreparePartitionForFormatting(
273 IN struct _PARTENTRY* PartEntry,
274 IN PFILE_SYSTEM FileSystem)
275 {
276 if (!FileSystem)
277 {
278 DPRINT1("No file system specified?\n");
279 return FALSE;
280 }
281
282 if (wcscmp(FileSystem->FileSystemName, L"FAT") == 0)
283 {
284 if (PartEntry->SectorCount.QuadPart < 8192)
285 {
286 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
287 SetPartitionType(PartEntry, PARTITION_FAT_12);
288 }
289 else if (PartEntry->StartSector.QuadPart < 1450560)
290 {
291 /* Partition starts below the 8.4GB boundary ==> CHS partition */
292
293 if (PartEntry->SectorCount.QuadPart < 65536)
294 {
295 /* FAT16 CHS partition (partition size < 32MB) */
296 SetPartitionType(PartEntry, PARTITION_FAT_16);
297 }
298 else if (PartEntry->SectorCount.QuadPart < 1048576)
299 {
300 /* FAT16 CHS partition (partition size < 512MB) */
301 SetPartitionType(PartEntry, PARTITION_HUGE);
302 }
303 else
304 {
305 /* FAT32 CHS partition (partition size >= 512MB) */
306 SetPartitionType(PartEntry, PARTITION_FAT32);
307 }
308 }
309 else
310 {
311 /* Partition starts above the 8.4GB boundary ==> LBA partition */
312
313 if (PartEntry->SectorCount.QuadPart < 1048576)
314 {
315 /* FAT16 LBA partition (partition size < 512MB) */
316 SetPartitionType(PartEntry, PARTITION_XINT13);
317 }
318 else
319 {
320 /* FAT32 LBA partition (partition size >= 512MB) */
321 SetPartitionType(PartEntry, PARTITION_FAT32_XINT13);
322 }
323 }
324 }
325 else if (wcscmp(FileSystem->FileSystemName, L"BTRFS") == 0)
326 {
327 SetPartitionType(PartEntry, PARTITION_LINUX);
328 }
329 #if 0
330 else if (wcscmp(FileSystem->FileSystemName, L"EXT2") == 0)
331 {
332 SetPartitionType(PartEntry, PARTITION_LINUX);
333 }
334 else if (wcscmp(FileSystem->FileSystemName, L"NTFS") == 0)
335 {
336 SetPartitionType(PartEntry, PARTITION_IFS);
337 }
338 #endif
339 else
340 {
341 /* Unknown file system? */
342 DPRINT1("Unknown file system \"%S\"?\n", FileSystem->FileSystemName);
343 return FALSE;
344 }
345
346 //
347 // FIXME: Do this now, or after the partition was actually formatted??
348 //
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;
352
353 return TRUE;
354 }
355
356 /* EOF */