468fed92849bc74642826c981bea206f912aaa3e
[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 2002-2018 Eric Kohl
6 * Copyright 2003-2018 Casper S. Hornstrup (chorns@users.sourceforge.net)
7 * Copyright 2017-2018 Hermes Belusca-Maito
8 */
9
10 //
11 // This is basically the code for listing available FileSystem providers
12 // (currently hardcoded in a list), and for performing a basic FileSystem
13 // recognition for a given disk partition.
14 //
15 // See also: https://git.reactos.org/?p=reactos.git;a=blob;f=reactos/dll/win32/fmifs/init.c;h=e895f5ef9cae4806123f6bbdd3dfed37ec1c8d33;hb=b9db9a4e377a2055f635b2fb69fef4e1750d219c
16 // for how to get FS providers in a dynamic way. In the (near) future we may
17 // consider merging some of this code with us into a fmifs / fsutil / fslib library...
18 //
19
20 /* INCLUDES *****************************************************************/
21
22 #include "precomp.h"
23
24 #include "fsutil.h"
25 #include "partlist.h"
26
27 /** For FileSystems **/
28 #include <fslib/vfatlib.h>
29 #include <fslib/ext2lib.h>
30 // #include <fslib/ntfslib.h>
31
32 #define NDEBUG
33 #include <debug.h>
34
35
36
37 FILE_SYSTEM RegisteredFileSystems[] =
38 {
39 { L"FAT" , VfatFormat, VfatChkdsk },
40 // { L"FAT32", VfatFormat, VfatChkdsk },
41 #if 0
42 { L"EXT2" , Ext2Format, Ext2Chkdsk },
43 { L"NTFS" , NtfsFormat, NtfsChkdsk }
44 #endif
45 };
46
47
48 /* FUNCTIONS ****************************************************************/
49
50 PFILE_SYSTEM
51 GetRegisteredFileSystems(OUT PULONG Count)
52 {
53 *Count = ARRAYSIZE(RegisteredFileSystems);
54 return RegisteredFileSystems;
55 }
56
57 PFILE_SYSTEM
58 GetFileSystemByName(
59 // IN PFILE_SYSTEM_LIST List,
60 IN PCWSTR FileSystemName)
61 {
62 #if 0 // Reenable when the list of registered FSes will again be dynamic
63
64 PLIST_ENTRY ListEntry;
65 PFILE_SYSTEM_ITEM Item;
66
67 ListEntry = List->ListHead.Flink;
68 while (ListEntry != &List->ListHead)
69 {
70 Item = CONTAINING_RECORD(ListEntry, FILE_SYSTEM_ITEM, ListEntry);
71 if (Item->FileSystemName && wcsicmp(FileSystemName, Item->FileSystemName) == 0)
72 return Item;
73
74 ListEntry = ListEntry->Flink;
75 }
76
77 #else
78
79 ULONG Count;
80 PFILE_SYSTEM FileSystems;
81
82 FileSystems = GetRegisteredFileSystems(&Count);
83 if (!FileSystems || Count == 0)
84 return NULL;
85
86 while (Count--)
87 {
88 if (FileSystems->FileSystemName && wcsicmp(FileSystemName, FileSystems->FileSystemName) == 0)
89 return FileSystems;
90
91 ++FileSystems;
92 }
93
94 #endif
95
96 return NULL;
97 }
98
99
100 //
101 // FileSystem recognition (using NT OS functionality)
102 //
103
104 #if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
105
106 /* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
107 static NTSTATUS
108 _MyGetFileSystem(
109 IN struct _PARTENTRY* PartEntry,
110 IN OUT PWSTR FileSystemName,
111 IN SIZE_T FileSystemNameSize)
112 {
113 NTSTATUS Status;
114 HANDLE FileHandle;
115 IO_STATUS_BLOCK IoStatusBlock;
116 PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute;
117 UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)];
118
119 OBJECT_ATTRIBUTES ObjectAttributes;
120 UNICODE_STRING PartitionRootPath;
121 WCHAR PathBuffer[MAX_PATH];
122
123 FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
124
125 /* Set PartitionRootPath */
126 swprintf(PathBuffer,
127 // L"\\Device\\Harddisk%lu\\Partition%lu", // Should work! But because ReactOS sucks atm. it actually doesn't work!!
128 L"\\Device\\Harddisk%lu\\Partition%lu\\", // HACK: Use this as a temporary hack!
129 PartEntry->DiskEntry->DiskNumber,
130 PartEntry->PartitionNumber);
131 RtlInitUnicodeString(&PartitionRootPath, PathBuffer);
132 DPRINT("PartitionRootPath: %wZ\n", &PartitionRootPath);
133
134 /* Open the partition */
135 InitializeObjectAttributes(&ObjectAttributes,
136 &PartitionRootPath,
137 OBJ_CASE_INSENSITIVE,
138 NULL,
139 NULL);
140 Status = NtOpenFile(&FileHandle, // PartitionHandle,
141 FILE_GENERIC_READ /* | SYNCHRONIZE */,
142 &ObjectAttributes,
143 &IoStatusBlock,
144 FILE_SHARE_READ,
145 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
146 if (!NT_SUCCESS(Status))
147 {
148 DPRINT1("Failed to open partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
149 return Status;
150 }
151
152 /* Retrieve the FS attributes */
153 Status = NtQueryVolumeInformationFile(FileHandle,
154 &IoStatusBlock,
155 FileFsAttribute,
156 sizeof(Buffer),
157 FileFsAttributeInformation);
158 NtClose(FileHandle);
159
160 if (!NT_SUCCESS(Status))
161 {
162 DPRINT1("NtQueryVolumeInformationFile failed for partition %wZ, Status 0x%08lx\n", &PartitionRootPath, Status);
163 return Status;
164 }
165
166 if (FileSystemNameSize * sizeof(WCHAR) < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
167 return STATUS_BUFFER_TOO_SMALL;
168
169 RtlCopyMemory(FileSystemName,
170 FileFsAttribute->FileSystemName,
171 FileFsAttribute->FileSystemNameLength);
172 FileSystemName[FileFsAttribute->FileSystemNameLength / sizeof(WCHAR)] = UNICODE_NULL;
173
174 return STATUS_SUCCESS;
175 }
176
177 #endif
178
179 PFILE_SYSTEM
180 GetFileSystem(
181 // IN PFILE_SYSTEM_LIST FileSystemList,
182 IN struct _PARTENTRY* PartEntry)
183 {
184 PFILE_SYSTEM CurrentFileSystem;
185 PWSTR FileSystemName = NULL;
186 #if 0 // For code temporarily disabled below
187 NTSTATUS Status;
188 WCHAR FsRecFileSystemName[MAX_PATH];
189 #endif
190
191 CurrentFileSystem = PartEntry->FileSystem;
192
193 /* We have a file system, return it */
194 if (CurrentFileSystem != NULL && CurrentFileSystem->FileSystemName != NULL)
195 return CurrentFileSystem;
196
197 DPRINT1("File system not found, try to guess one...\n");
198
199 CurrentFileSystem = NULL;
200
201 #if 0 // FIXME: To be fully enabled when our storage stack & al. will work better!
202
203 /*
204 * We don't have one...
205 *
206 * Try to infer one using NT file system recognition.
207 */
208 Status = _MyGetFileSystem(PartEntry, FsRecFileSystemName, ARRAYSIZE(FsRecFileSystemName));
209 if (NT_SUCCESS(Status) && *FsRecFileSystemName)
210 {
211 /* Temporary HACK: map FAT32 back to FAT */
212 if (wcscmp(FsRecFileSystemName, L"FAT32") == 0)
213 wcscpy(FsRecFileSystemName, L"FAT");
214
215 FileSystemName = FsRecFileSystemName;
216 goto Quit;
217 }
218
219 #endif
220
221 /*
222 * We don't have one...
223 *
224 * Try to infer a preferred file system for this partition, given its ID.
225 *
226 * WARNING: This is partly a hack, since partitions with the same ID can
227 * be formatted with different file systems: for example, usual Linux
228 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
229 * same partition ID 0x83.
230 *
231 * The proper fix is to make a function that detects the existing FS
232 * from a given partition (not based on the partition ID).
233 * On the contrary, for unformatted partitions with a given ID, the
234 * following code is OK.
235 */
236 if ((PartEntry->PartitionType == PARTITION_FAT_12) ||
237 (PartEntry->PartitionType == PARTITION_FAT_16) ||
238 (PartEntry->PartitionType == PARTITION_HUGE ) ||
239 (PartEntry->PartitionType == PARTITION_XINT13) ||
240 (PartEntry->PartitionType == PARTITION_FAT32 ) ||
241 (PartEntry->PartitionType == PARTITION_FAT32_XINT13))
242 {
243 FileSystemName = L"FAT";
244 }
245 else if (PartEntry->PartitionType == PARTITION_EXT2)
246 {
247 // WARNING: See the warning above.
248 FileSystemName = L"EXT2";
249 }
250 else if (PartEntry->PartitionType == PARTITION_IFS)
251 {
252 // WARNING: See the warning above.
253 FileSystemName = L"NTFS"; /* FIXME: Not quite correct! */
254 }
255
256 #if 0
257 Quit: // For code temporarily disabled above
258 #endif
259
260 // HACK: WARNING: We cannot write on this FS yet!
261 if (FileSystemName)
262 {
263 if (PartEntry->PartitionType == PARTITION_EXT2 || PartEntry->PartitionType == PARTITION_IFS)
264 DPRINT1("Recognized file system %S that doesn't support write support yet!\n", FileSystemName);
265 }
266
267 DPRINT1("GetFileSystem -- PartitionType: 0x%02X ; FileSystemName (guessed): %S\n",
268 PartEntry->PartitionType, FileSystemName ? FileSystemName : L"None");
269
270 if (FileSystemName != NULL)
271 CurrentFileSystem = GetFileSystemByName(/*FileSystemList,*/ FileSystemName);
272
273 return CurrentFileSystem;
274 }
275
276 /* EOF */