From 38e988ace7a68e1890bdd3625fe73a5341cc1bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Herm=C3=A8s=20B=C3=A9lusca-Ma=C3=AFto?= Date: Sun, 21 May 2017 23:45:43 +0000 Subject: [PATCH] [USETUP] Improve the FileSup module. - Add a NtPathToDiskPartComponents() helper, that takes in input a fully qualified NT path to a file on hard disk, e.g.: \Device\Harddisk1\Partition2\foo\bar, and returns in output the disk number ('1'), the partition number ('2'), and the the path component "\foo\bar" that is after the device-harddisk-partition identifier. - Make the OpenAndMapFile() return the file size of the opened file. Both of these additions will be used soon. - Turn a isspace() call into a iswspace() one. svn path=/branches/setup_improvements/; revision=74619 --- base/setup/usetup/filesup.c | 141 +++++++++++++++++++++++++++++++++++- base/setup/usetup/filesup.h | 10 ++- 2 files changed, 148 insertions(+), 3 deletions(-) diff --git a/base/setup/usetup/filesup.c b/base/setup/usetup/filesup.c index 293e590b767..49defff5535 100644 --- a/base/setup/usetup/filesup.c +++ b/base/setup/usetup/filesup.c @@ -501,7 +501,7 @@ IsValidPath( /* Path must not contain whitespace characters */ for (i = 0; i < Length; i++) { - if (isspace(InstallDir[i])) + if (iswspace(InstallDir[i])) return FALSE; } @@ -633,6 +633,117 @@ DoesFileExist( return NT_SUCCESS(Status); } +/* + * The format of NtPath should be: + * \Device\HarddiskXXX\PartitionYYY[\path] , + * where XXX and YYY respectively represent the hard disk and partition numbers, + * and [\path] represent an optional path (separated by '\\'). + * + * If a NT path of such a form is correctly parsed, the function returns respectively: + * - in pDiskNumber: the hard disk number XXX, + * - in pPartNumber: the partition number YYY, + * - in PathComponent: pointer value (inside NtPath) to the beginning of \path. + * + * NOTE: The function does not accept leading whitespace. + */ +BOOLEAN +NtPathToDiskPartComponents( + IN PCWSTR NtPath, + OUT PULONG pDiskNumber, + OUT PULONG pPartNumber, + OUT PCWSTR* PathComponent OPTIONAL) +{ + ULONG DiskNumber, PartNumber; + PCWSTR Path; + + *pDiskNumber = 0; + *pPartNumber = 0; + if (PathComponent) *PathComponent = NULL; + + Path = NtPath; + + if (_wcsnicmp(Path, L"\\Device\\Harddisk", 16) != 0) + { + /* The NT path doesn't start with the prefix string, thus it cannot be a hard disk device path */ + DPRINT1("'%S' : Not a possible hard disk device.\n", NtPath); + return FALSE; + } + + Path += 16; + + /* A number must be present now */ + if (!iswdigit(*Path)) + { + DPRINT1("'%S' : expected a number! Not a regular hard disk device.\n", Path); + return FALSE; + } + DiskNumber = wcstoul(Path, (PWSTR*)&Path, 10); + + /* Either NULL termination, or a path separator must be present now */ + if (!Path) + { + DPRINT1("An error happened!\n"); + return FALSE; + } + else if (*Path && *Path != OBJ_NAME_PATH_SEPARATOR) + { + DPRINT1("'%S' : expected a path separator!\n", Path); + return FALSE; + } + + if (!*Path) + { + DPRINT1("The path only specified a hard disk (and nothing else, like a partition...), so we stop there.\n"); + goto Quit; + } + + /* Here, *Path == L'\\' */ + + if (_wcsnicmp(Path, L"\\Partition", 10) != 0) + { + /* Actually, \Partition is optional so, if we don't have it, we still return success. Or should we? */ + DPRINT1("'%S' : unexpected format!\n", NtPath); + goto Quit; + } + + Path += 10; + + /* A number must be present now */ + if (!iswdigit(*Path)) + { + /* If we don't have a number it means this part of path is actually not a partition specifier, so we shouldn't fail either. Or should we? */ + DPRINT1("'%S' : expected a number!\n", Path); + goto Quit; + } + PartNumber = wcstoul(Path, (PWSTR*)&Path, 10); + + /* Either NULL termination, or a path separator must be present now */ + if (!Path) + { + /* We fail here because wcstoul failed for whatever reason */ + DPRINT1("An error happened!\n"); + return FALSE; + } + else if (*Path && *Path != OBJ_NAME_PATH_SEPARATOR) + { + /* We shouldn't fail here because it just means this part of path is actually not a partition specifier. Or should we? */ + DPRINT1("'%S' : expected a path separator!\n", Path); + goto Quit; + } + + /* OK, here we really have a partition specifier: return its number */ + *pPartNumber = PartNumber; + +Quit: + /* Return the disk number */ + *pDiskNumber = DiskNumber; + + /* Return the path component also, if the user wants it */ + if (PathComponent) *PathComponent = Path; + + return TRUE; +} + NTSTATUS OpenAndMapFile( IN HANDLE RootDirectory OPTIONAL, @@ -640,7 +751,8 @@ OpenAndMapFile( IN PCWSTR FileName, // OPTIONAL OUT PHANDLE FileHandle, // IN OUT PHANDLE OPTIONAL OUT PHANDLE SectionHandle, - OUT PVOID* BaseAddress) + OUT PVOID* BaseAddress, + OUT PULONG FileSize OPTIONAL) { NTSTATUS Status; OBJECT_ATTRIBUTES ObjectAttributes; @@ -681,6 +793,31 @@ OpenAndMapFile( return Status; } + if (FileSize) + { + /* Query the file size */ + FILE_STANDARD_INFORMATION FileInfo; + Status = NtQueryInformationFile(*FileHandle, + &IoStatusBlock, + &FileInfo, + sizeof(FileInfo), + FileStandardInformation); + if (!NT_SUCCESS(Status)) + { + DPRINT("NtQueryInformationFile() failed (Status %lx)\n", Status); + NtClose(*FileHandle); + *FileHandle = NULL; + return Status; + } + + if (FileInfo.EndOfFile.HighPart != 0) + DPRINT1("WARNING!! The file %wZ is too large!\n", Name); + + *FileSize = FileInfo.EndOfFile.LowPart; + + DPRINT("File size: %lu\n", *FileSize); + } + /* Map the file in memory */ /* Create the section */ diff --git a/base/setup/usetup/filesup.h b/base/setup/usetup/filesup.h index 492dff0e87f..317fad93bed 100644 --- a/base/setup/usetup/filesup.h +++ b/base/setup/usetup/filesup.h @@ -63,6 +63,13 @@ DoesFileExist( IN PCWSTR PathName OPTIONAL, IN PCWSTR FileName); +BOOLEAN +NtPathToDiskPartComponents( + IN PCWSTR NtPath, + OUT PULONG pDiskNumber, + OUT PULONG pPartNumber, + OUT PCWSTR* PathComponent OPTIONAL); + NTSTATUS OpenAndMapFile( IN HANDLE RootDirectory OPTIONAL, @@ -70,7 +77,8 @@ OpenAndMapFile( IN PCWSTR FileName, // OPTIONAL OUT PHANDLE FileHandle, // IN OUT PHANDLE OPTIONAL OUT PHANDLE SectionHandle, - OUT PVOID* BaseAddress); + OUT PVOID* BaseAddress, + OUT PULONG FileSize OPTIONAL); BOOLEAN UnMapFile(