ReactOS 0.4.15-dev-7931-gfd331f1
fsrec.c
Go to the documentation of this file.
1/*
2 * PROJECT: ReactOS Setup Library
3 * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
4 * PURPOSE: Filesystem Recognition support functions,
5 * using NT OS functionality.
6 * COPYRIGHT: Copyright 2017-2020 Hermes Belusca-Maito
7 */
8
9/* INCLUDES *****************************************************************/
10
11#include "precomp.h"
12
13#include "fsrec.h"
14
15#define NDEBUG
16#include <debug.h>
17
18
19/* FUNCTIONS ****************************************************************/
20
21/* NOTE: Ripped & adapted from base/system/autochk/autochk.c */
22static inline
25 IN HANDLE PartitionHandle,
27 IN OUT PWSTR FileSystemName,
28 IN SIZE_T FileSystemNameSize)
29{
33
34 /* Retrieve the FS attributes */
35 Status = NtQueryVolumeInformationFile(PartitionHandle,
37 FileFsAttribute,
38 sizeof(Buffer),
40 if (!NT_SUCCESS(Status))
41 {
42 DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status);
43 return Status;
44 }
45
46 if (FileSystemNameSize < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR))
48
49 return RtlStringCbCopyNW(FileSystemName, FileSystemNameSize,
50 FileFsAttribute->FileSystemName,
51 FileFsAttribute->FileSystemNameLength);
52}
53
56 IN PUNICODE_STRING PartitionPath OPTIONAL,
57 IN HANDLE PartitionHandle OPTIONAL,
58 IN OUT PWSTR FileSystemName,
59 IN SIZE_T FileSystemNameSize)
60{
64
65 if (PartitionPath && PartitionHandle)
67
68 /* Open the partition if a path has been given;
69 * otherwise just use the provided handle. */
70 if (PartitionPath)
71 {
73 PartitionPath,
75 NULL,
76 NULL);
77 Status = NtOpenFile(&PartitionHandle,
78 FILE_GENERIC_READ /* | SYNCHRONIZE */,
82 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
83 if (!NT_SUCCESS(Status))
84 {
85 DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n",
86 PartitionPath, Status);
87 return Status;
88 }
89 }
90
91 /* Retrieve the FS attributes */
92 Status = GetFileSystemNameWorker(PartitionHandle,
94 FileSystemName,
95 FileSystemNameSize);
96 if (!NT_SUCCESS(Status))
97 {
98 DPRINT1("GetFileSystemName() failed for partition '%wZ' (0x%p), Status 0x%08lx\n",
99 PartitionPath, PartitionHandle, Status);
100 }
101
102 if (PartitionPath)
103 {
104 /* Close the partition */
105 NtClose(PartitionHandle);
106 }
107
108 return Status;
109}
110
113 IN PCWSTR PartitionPath OPTIONAL,
114 IN HANDLE PartitionHandle OPTIONAL,
115 IN OUT PWSTR FileSystemName,
116 IN SIZE_T FileSystemNameSize)
117{
118 UNICODE_STRING PartitionPathU;
119
120 if (PartitionPath && PartitionHandle)
122
123 if (PartitionPath)
124 RtlInitUnicodeString(&PartitionPathU, PartitionPath);
125
126 return GetFileSystemName_UStr(PartitionPath ? &PartitionPathU : NULL,
127 PartitionPath ? NULL : PartitionHandle,
128 FileSystemName,
129 FileSystemNameSize);
130}
131
132static inline
135 IN HANDLE PartitionHandle,
137 IN OUT PWSTR FileSystemName,
138 IN SIZE_T FileSystemNameSize)
139{
140 NTSTATUS Status, Status2;
141 union
142 {
145 } PartInfo;
147
148 if (FileSystemNameSize < sizeof(WCHAR))
150
151 *FileSystemName = L'\0';
152
153 /* Try to infer a file system using NT file system recognition */
154 Status = GetFileSystemName_UStr(NULL, PartitionHandle,
155 FileSystemName,
156 FileSystemNameSize);
157 if (NT_SUCCESS(Status) && *FileSystemName)
158 goto Quit;
159
160 /*
161 * Check whether the partition is MBR, and if so, retrieve its MBR
162 * partition type and try to infer a preferred file system for it.
163 */
164
165 // NOTE: Use Status2 in order not to clobber the original Status.
166 Status2 = NtDeviceIoControlFile(PartitionHandle,
167 NULL,
168 NULL,
169 NULL,
172 NULL,
173 0,
174 &PartInfo.InfoEx,
175 sizeof(PartInfo.InfoEx));
176 if (!NT_SUCCESS(Status2))
177 {
178 DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status2);
179
180 if (Status2 != STATUS_INVALID_DEVICE_REQUEST)
181 goto Quit;
182
183 /*
184 * We could have failed because the partition is on a dynamic
185 * MBR or GPT data disk, so retry with the non-EX IOCTL.
186 */
187 Status2 = NtDeviceIoControlFile(PartitionHandle,
188 NULL,
189 NULL,
190 NULL,
193 NULL,
194 0,
195 &PartInfo.Info,
196 sizeof(PartInfo.Info));
197 if (!NT_SUCCESS(Status2))
198 {
199 /* We failed again, bail out */
200 DPRINT1("IOCTL_DISK_GET_PARTITION_INFO failed (Status %lx)\n", Status2);
201 goto Quit;
202 }
203
204 /* The partition is supposed to be on an MBR disk; retrieve its type */
205 PartitionType = PartInfo.Info.PartitionType;
206 }
207 else
208 {
209 /* We succeeded; retrieve the partition type only if it is on an MBR disk */
210 if (PartInfo.InfoEx.PartitionStyle != PARTITION_STYLE_MBR)
211 {
212 /* Disk is not MBR, bail out */
213 goto Quit;
214 }
215 PartitionType = PartInfo.InfoEx.Mbr.PartitionType;
216 }
217
218 /*
219 * Given an MBR partition type, try to infer a preferred file system.
220 *
221 * WARNING: This is partly a hack, since partitions with the same type
222 * can be formatted with different file systems: for example, usual Linux
223 * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the
224 * same partition type 0x83.
225 *
226 * The proper fix is to make a function that detects the existing FS
227 * from a given partition (not based on the partition type).
228 * On the contrary, for unformatted partitions with a given type, the
229 * following code is OK.
230 */
235 {
236 /* FAT12 or FAT16 */
237 Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"FAT");
238 }
239 else if ((PartitionType == PARTITION_FAT32) ||
241 {
242 Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"FAT32");
243 }
244 else if (PartitionType == PARTITION_LINUX)
245 {
246 // WARNING: See the warning above.
247 /* Could also be EXT2/3/4, ReiserFS, ... */
248 Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"BTRFS");
249 }
250 else if (PartitionType == PARTITION_IFS)
251 {
252 // WARNING: See the warning above.
253 /* Could also be HPFS */
254 Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"NTFS");
255 }
256
257Quit:
258 if (*FileSystemName && wcsicmp(FileSystemName, L"NTFS") == 0)
259 {
260 // WARNING: We cannot write on this FS yet!
261 DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n",
262 FileSystemName);
263 }
264
265 return Status;
266}
267
270 IN PCWSTR PartitionPath OPTIONAL,
271 IN HANDLE PartitionHandle OPTIONAL,
272 IN OUT PWSTR FileSystemName,
273 IN SIZE_T FileSystemNameSize)
274{
276 UNICODE_STRING PartitionPathU;
279
280 if (PartitionPath && PartitionHandle)
282
283 /* Open the partition if a path has been given;
284 * otherwise just use the provided handle. */
285 if (PartitionPath)
286 {
287 RtlInitUnicodeString(&PartitionPathU, PartitionPath);
289 &PartitionPathU,
291 NULL,
292 NULL);
293 Status = NtOpenFile(&PartitionHandle,
294 FILE_GENERIC_READ /* | SYNCHRONIZE */,
298 0 /* FILE_SYNCHRONOUS_IO_NONALERT */);
299 if (!NT_SUCCESS(Status))
300 {
301 DPRINT1("Failed to open partition '%S', Status 0x%08lx\n",
302 PartitionPath, Status);
303 return Status;
304 }
305 }
306
307 /* Retrieve the FS */
308 Status = InferFileSystemWorker(PartitionHandle,
310 FileSystemName,
311 FileSystemNameSize);
312 if (!NT_SUCCESS(Status))
313 {
314 DPRINT1("InferFileSystem() failed for partition '%S' (0x%p), Status 0x%08lx\n",
315 PartitionPath, PartitionHandle, Status);
316 }
317 else
318 {
319 DPRINT1("InferFileSystem(): FileSystem (guessed): %S\n",
320 *FileSystemName ? FileSystemName : L"None");
321 }
322
323 if (PartitionPath)
324 {
325 /* Close the partition */
326 NtClose(PartitionHandle);
327 }
328
329 return Status;
330}
331
332UCHAR
335 IN ULONGLONG StartSector,
337{
339
340 if (SectorCount == 0)
342
343 if (wcsicmp(FileSystem, L"FAT") == 0 ||
344 wcsicmp(FileSystem, L"FAT32") == 0 ||
345 wcsicmp(FileSystem, L"RAW") == 0)
346 {
347 if (SectorCount < 8192ULL)
348 {
349 /* FAT12 CHS partition (disk is smaller than 4.1MB) */
350 return PARTITION_FAT_12;
351 }
352 else if (StartSector < 1450560ULL)
353 {
354 /* Partition starts below the 8.4GB boundary ==> CHS partition */
355
356 if (SectorCount < 65536ULL)
357 {
358 /* FAT16 CHS partition (partition size < 32MB) */
359 return PARTITION_FAT_16;
360 }
361 else if (SectorCount < 1048576ULL)
362 {
363 /* FAT16 CHS partition (partition size < 512MB) */
364 return PARTITION_HUGE;
365 }
366 else
367 {
368 /* FAT32 CHS partition (partition size >= 512MB) */
369 return PARTITION_FAT32;
370 }
371 }
372 else
373 {
374 /* Partition starts above the 8.4GB boundary ==> LBA partition */
375
376 if (SectorCount < 1048576ULL)
377 {
378 /* FAT16 LBA partition (partition size < 512MB) */
379 return PARTITION_XINT13;
380 }
381 else
382 {
383 /* FAT32 LBA partition (partition size >= 512MB) */
385 }
386 }
387 }
388 else if (wcsicmp(FileSystem, L"NTFS") == 0)
389 {
390 return PARTITION_IFS;
391 }
392 else if (wcsicmp(FileSystem, L"BTRFS") == 0 ||
393 wcsicmp(FileSystem, L"EXT2") == 0 ||
394 wcsicmp(FileSystem, L"EXT3") == 0 ||
395 wcsicmp(FileSystem, L"EXT4") == 0)
396 {
397 return PARTITION_LINUX;
398 }
399 else
400 {
401 /* Unknown file system */
402 DPRINT1("Unknown file system '%S'\n", FileSystem);
404 }
405}
406
407/* EOF */
LONG NTSTATUS
Definition: precomp.h:26
#define DPRINT1
Definition: precomp.h:8
PWCHAR FileSystem
Definition: format.c:72
#define PARTITION_IFS
Definition: disk.h:93
#define PARTITION_ENTRY_UNUSED
Definition: disk.h:86
#define PARTITION_XINT13
Definition: disk.h:97
#define PARTITION_FAT32
Definition: disk.h:95
#define PARTITION_FAT_12
Definition: disk.h:87
#define PARTITION_HUGE
Definition: disk.h:92
#define PARTITION_FAT_16
Definition: disk.h:90
#define PARTITION_FAT32_XINT13
Definition: disk.h:96
Definition: bufpool.h:45
IN PUNICODE_STRING IN POBJECT_ATTRIBUTES ObjectAttributes
Definition: conport.c:36
#define NULL
Definition: types.h:112
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define MAX_PATH
Definition: compat.h:34
#define FILE_SHARE_READ
Definition: compat.h:136
#define wcsicmp
Definition: compat.h:15
#define IOCTL_DISK_GET_PARTITION_INFO_EX
Definition: ntddk_ex.h:206
struct _FILE_FS_ATTRIBUTE_INFORMATION FILE_FS_ATTRIBUTE_INFORMATION
@ FileFsAttributeInformation
Definition: from_kernel.h:223
struct _FILE_FS_ATTRIBUTE_INFORMATION * PFILE_FS_ATTRIBUTE_INFORMATION
NTSTATUS InferFileSystem(IN PCWSTR PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:269
UCHAR FileSystemToMBRPartitionType(IN PCWSTR FileSystem, IN ULONGLONG StartSector, IN ULONGLONG SectorCount)
Definition: fsrec.c:333
NTSTATUS GetFileSystemName_UStr(IN PUNICODE_STRING PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:55
static NTSTATUS GetFileSystemNameWorker(IN HANDLE PartitionHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:24
static NTSTATUS InferFileSystemWorker(IN HANDLE PartitionHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:134
NTSTATUS GetFileSystemName(IN PCWSTR PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize)
Definition: fsrec.c:112
Status
Definition: gdiplustypes.h:25
#define OBJ_CASE_INSENSITIVE
Definition: winternl.h:228
#define ASSERT(a)
Definition: mode.c:44
@ PARTITION_STYLE_MBR
Definition: imports.h:201
static OUT PIO_STATUS_BLOCK IoStatusBlock
Definition: pipe.c:75
#define InitializeObjectAttributes(p, n, a, r, s)
Definition: reg.c:106
NTSYSAPI NTSTATUS NTAPI NtOpenFile(OUT PHANDLE phFile, IN ACCESS_MASK DesiredAccess, IN POBJECT_ATTRIBUTES ObjectAttributes, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG ShareMode, IN ULONG OpenMode)
Definition: file.c:3952
#define FILE_SHARE_WRITE
Definition: nt_native.h:681
NTSYSAPI VOID NTAPI RtlInitUnicodeString(PUNICODE_STRING DestinationString, PCWSTR SourceString)
NTSYSAPI NTSTATUS NTAPI NtDeviceIoControlFile(IN HANDLE hFile, IN HANDLE hEvent OPTIONAL, IN PIO_APC_ROUTINE IoApcRoutine OPTIONAL, IN PVOID IoApcContext OPTIONAL, OUT PIO_STATUS_BLOCK pIoStatusBlock, IN ULONG DeviceIoControlCode, IN PVOID InBuffer OPTIONAL, IN ULONG InBufferLength, OUT PVOID OutBuffer OPTIONAL, IN ULONG OutBufferLength)
NTSTATUS NTAPI NtClose(IN HANDLE Handle)
Definition: obhandle.c:3402
#define FILE_GENERIC_READ
Definition: nt_native.h:653
#define IOCTL_DISK_GET_PARTITION_INFO
Definition: ntdddisk.h:106
NTSTRSAFEAPI RtlStringCbCopyW(_Out_writes_bytes_(cbDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:174
NTSTRSAFEAPI RtlStringCbCopyNW(_Out_writes_bytes_(cbDest) NTSTRSAFE_PWSTR pszDest, _In_ size_t cbDest, _In_reads_bytes_(cbToCopy) STRSAFE_LPCWSTR pszSrc, _In_ size_t cbToCopy)
Definition: ntstrsafe.h:416
#define L(x)
Definition: ntvdm.h:50
ULONG SectorCount
Definition: part_xbox.c:31
CHAR PartitionType
Definition: part_xbox.c:32
NTSTATUS NTAPI NtQueryVolumeInformationFile(HANDLE FileHandle, PIO_STATUS_BLOCK IoStatusBlock, PVOID FsInformation, ULONG Length, FS_INFORMATION_CLASS FsInformationClass)
#define STATUS_BUFFER_TOO_SMALL
Definition: shellext.h:69
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
#define PARTITION_LINUX
Definition: partlist.c:36
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
ULONG_PTR SIZE_T
Definition: typedefs.h:80
#define IN
Definition: typedefs.h:39
uint64_t ULONGLONG
Definition: typedefs.h:67
#define OUT
Definition: typedefs.h:40
#define STATUS_INVALID_DEVICE_REQUEST
Definition: udferr_usr.h:138
#define STATUS_INVALID_PARAMETER
Definition: udferr_usr.h:135
_Must_inspect_result_ _In_ WDFCHILDLIST _In_ PWDF_CHILD_LIST_ITERATOR _Out_ WDFDEVICE _Inout_opt_ PWDF_CHILD_RETRIEVE_INFO Info
Definition: wdfchildlist.h:690
unsigned char UCHAR
Definition: xmlstorage.h:181
__wchar_t WCHAR
Definition: xmlstorage.h:180