Something went wrong. Try again.
Reactos
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408/* * PROJECT: ReactOS Setup Library * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+) * PURPOSE: Filesystem Recognition support functions, * using NT OS functionality. * COPYRIGHT: Copyright 2017-2020 Hermes Belusca-Maito */
/* INCLUDES *****************************************************************/
#include "precomp.h"
#include "fsrec.h"
#define NDEBUG#include <debug.h>
/* FUNCTIONS ****************************************************************/
/* NOTE: Ripped & adapted from base/system/autochk/autochk.c */static inlineNTSTATUSGetFileSystemNameWorker( IN HANDLE PartitionHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize){ NTSTATUS Status; UCHAR Buffer[sizeof(FILE_FS_ATTRIBUTE_INFORMATION) + MAX_PATH * sizeof(WCHAR)]; PFILE_FS_ATTRIBUTE_INFORMATION FileFsAttribute = (PFILE_FS_ATTRIBUTE_INFORMATION)Buffer;
/* Retrieve the FS attributes */ Status = NtQueryVolumeInformationFile(PartitionHandle, IoStatusBlock, FileFsAttribute, sizeof(Buffer), FileFsAttributeInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryVolumeInformationFile() failed, Status 0x%08lx\n", Status); return Status; }
if (FileSystemNameSize < FileFsAttribute->FileSystemNameLength + sizeof(WCHAR)) return STATUS_BUFFER_TOO_SMALL;
return RtlStringCbCopyNW(FileSystemName, FileSystemNameSize, FileFsAttribute->FileSystemName, FileFsAttribute->FileSystemNameLength);}
NTSTATUSGetFileSystemName_UStr( IN PUNICODE_STRING PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize){ NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock;
if (PartitionPath && PartitionHandle) return STATUS_INVALID_PARAMETER;
/* Open the partition if a path has been given; * otherwise just use the provided handle. */ if (PartitionPath) { InitializeObjectAttributes(&ObjectAttributes, PartitionPath, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&PartitionHandle, FILE_GENERIC_READ /* | SYNCHRONIZE */, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* FILE_SYNCHRONOUS_IO_NONALERT */); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to open partition '%wZ', Status 0x%08lx\n", PartitionPath, Status); return Status; } }
/* Retrieve the FS attributes */ Status = GetFileSystemNameWorker(PartitionHandle, &IoStatusBlock, FileSystemName, FileSystemNameSize); if (!NT_SUCCESS(Status)) { DPRINT1("GetFileSystemName() failed for partition '%wZ' (0x%p), Status 0x%08lx\n", PartitionPath, PartitionHandle, Status); }
if (PartitionPath) { /* Close the partition */ NtClose(PartitionHandle); }
return Status;}
NTSTATUSGetFileSystemName( IN PCWSTR PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize){ UNICODE_STRING PartitionPathU;
if (PartitionPath && PartitionHandle) return STATUS_INVALID_PARAMETER;
if (PartitionPath) RtlInitUnicodeString(&PartitionPathU, PartitionPath);
return GetFileSystemName_UStr(PartitionPath ? &PartitionPathU : NULL, PartitionPath ? NULL : PartitionHandle, FileSystemName, FileSystemNameSize);}
static inlineNTSTATUSInferFileSystemWorker( IN HANDLE PartitionHandle, OUT PIO_STATUS_BLOCK IoStatusBlock, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize){ NTSTATUS Status, Status2; union { PARTITION_INFORMATION_EX InfoEx; PARTITION_INFORMATION Info; } PartInfo; UCHAR PartitionType;
if (FileSystemNameSize < sizeof(WCHAR)) return STATUS_BUFFER_TOO_SMALL;
*FileSystemName = L'\0';
/* Try to infer a file system using NT file system recognition */ Status = GetFileSystemName_UStr(NULL, PartitionHandle, FileSystemName, FileSystemNameSize); if (NT_SUCCESS(Status) && *FileSystemName) goto Quit;
/* * Check whether the partition is MBR, and if so, retrieve its MBR * partition type and try to infer a preferred file system for it. */
// NOTE: Use Status2 in order not to clobber the original Status. Status2 = NtDeviceIoControlFile(PartitionHandle, NULL, NULL, NULL, IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL, 0, &PartInfo.InfoEx, sizeof(PartInfo.InfoEx)); if (!NT_SUCCESS(Status2)) { DPRINT1("IOCTL_DISK_GET_PARTITION_INFO_EX failed (Status %lx)\n", Status2);
if (Status2 != STATUS_INVALID_DEVICE_REQUEST) goto Quit;
/* * We could have failed because the partition is on a dynamic * MBR or GPT data disk, so retry with the non-EX IOCTL. */ Status2 = NtDeviceIoControlFile(PartitionHandle, NULL, NULL, NULL, IoStatusBlock, IOCTL_DISK_GET_PARTITION_INFO, NULL, 0, &PartInfo.Info, sizeof(PartInfo.Info)); if (!NT_SUCCESS(Status2)) { /* We failed again, bail out */ DPRINT1("IOCTL_DISK_GET_PARTITION_INFO failed (Status %lx)\n", Status2); goto Quit; }
/* The partition is supposed to be on an MBR disk; retrieve its type */ PartitionType = PartInfo.Info.PartitionType; } else { /* We succeeded; retrieve the partition type only if it is on an MBR disk */ if (PartInfo.InfoEx.PartitionStyle != PARTITION_STYLE_MBR) { /* Disk is not MBR, bail out */ goto Quit; } PartitionType = PartInfo.InfoEx.Mbr.PartitionType; }
/* * Given an MBR partition type, try to infer a preferred file system. * * WARNING: This is partly a hack, since partitions with the same type * can be formatted with different file systems: for example, usual Linux * partitions that are formatted in EXT2/3/4, ReiserFS, etc... have the * same partition type 0x83. * * The proper fix is to make a function that detects the existing FS * from a given partition (not based on the partition type). * On the contrary, for unformatted partitions with a given type, the * following code is OK. */ if ((PartitionType == PARTITION_FAT_12) || (PartitionType == PARTITION_FAT_16) || (PartitionType == PARTITION_HUGE ) || (PartitionType == PARTITION_XINT13)) { /* FAT12 or FAT16 */ Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"FAT"); } else if ((PartitionType == PARTITION_FAT32) || (PartitionType == PARTITION_FAT32_XINT13)) { Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"FAT32"); } else if (PartitionType == PARTITION_LINUX) { // WARNING: See the warning above. /* Could also be EXT2/3/4, ReiserFS, ... */ Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"BTRFS"); } else if (PartitionType == PARTITION_IFS) { // WARNING: See the warning above. /* Could also be HPFS */ Status = RtlStringCbCopyW(FileSystemName, FileSystemNameSize, L"NTFS"); }
Quit: if (*FileSystemName && _wcsicmp(FileSystemName, L"NTFS") == 0) { // WARNING: We cannot write on this FS yet! DPRINT1("Recognized file system '%S' that doesn't have write support yet!\n", FileSystemName); }
return Status;}
NTSTATUSInferFileSystem( IN PCWSTR PartitionPath OPTIONAL, IN HANDLE PartitionHandle OPTIONAL, IN OUT PWSTR FileSystemName, IN SIZE_T FileSystemNameSize){ NTSTATUS Status; UNICODE_STRING PartitionPathU; OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock;
if (PartitionPath && PartitionHandle) return STATUS_INVALID_PARAMETER;
/* Open the partition if a path has been given; * otherwise just use the provided handle. */ if (PartitionPath) { RtlInitUnicodeString(&PartitionPathU, PartitionPath); InitializeObjectAttributes(&ObjectAttributes, &PartitionPathU, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&PartitionHandle, FILE_GENERIC_READ /* | SYNCHRONIZE */, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ | FILE_SHARE_WRITE, 0 /* FILE_SYNCHRONOUS_IO_NONALERT */); if (!NT_SUCCESS(Status)) { DPRINT1("Failed to open partition '%S', Status 0x%08lx\n", PartitionPath, Status); return Status; } }
/* Retrieve the FS */ Status = InferFileSystemWorker(PartitionHandle, &IoStatusBlock, FileSystemName, FileSystemNameSize); if (!NT_SUCCESS(Status)) { DPRINT1("InferFileSystem() failed for partition '%S' (0x%p), Status 0x%08lx\n", PartitionPath, PartitionHandle, Status); } else { DPRINT1("InferFileSystem(): FileSystem (guessed): %S\n", *FileSystemName ? FileSystemName : L"None"); }
if (PartitionPath) { /* Close the partition */ NtClose(PartitionHandle); }
return Status;}
UCHARFileSystemToMBRPartitionType( IN PCWSTR FileSystem, IN ULONGLONG StartSector, IN ULONGLONG SectorCount){ ASSERT(FileSystem);
if (SectorCount == 0) return PARTITION_ENTRY_UNUSED;
if (_wcsicmp(FileSystem, L"FAT") == 0 || _wcsicmp(FileSystem, L"FAT32") == 0 || _wcsicmp(FileSystem, L"RAW") == 0) { if (SectorCount < 8192ULL) { /* FAT12 CHS partition (disk is smaller than 4.1MB) */ return PARTITION_FAT_12; } else if (StartSector < 1450560ULL) { /* Partition starts below the 8.4GB boundary ==> CHS partition */
if (SectorCount < 65536ULL) { /* FAT16 CHS partition (partition size < 32MB) */ return PARTITION_FAT_16; } else if (SectorCount < 1048576ULL) { /* FAT16 CHS partition (partition size < 512MB) */ return PARTITION_HUGE; } else { /* FAT32 CHS partition (partition size >= 512MB) */ return PARTITION_FAT32; } } else { /* Partition starts above the 8.4GB boundary ==> LBA partition */
if (SectorCount < 1048576ULL) { /* FAT16 LBA partition (partition size < 512MB) */ return PARTITION_XINT13; } else { /* FAT32 LBA partition (partition size >= 512MB) */ return PARTITION_FAT32_XINT13; } } } else if (_wcsicmp(FileSystem, L"NTFS") == 0) { return PARTITION_IFS; } else if (_wcsicmp(FileSystem, L"BTRFS") == 0 || _wcsicmp(FileSystem, L"EXT2") == 0 || _wcsicmp(FileSystem, L"EXT3") == 0 || _wcsicmp(FileSystem, L"EXT4") == 0) { return PARTITION_LINUX; } else { /* Unknown file system */ DPRINT1("Unknown file system '%S'\n", FileSystem); return PARTITION_ENTRY_UNUSED; }}
/* EOF */