16f19c83bSHermès Bélusca-Maïto /*
26f19c83bSHermès Bélusca-Maïto * PROJECT: ReactOS Setup Library
36f19c83bSHermès Bélusca-Maïto * LICENSE: GPL-2.0+ (https://spdx.org/licenses/GPL-2.0+)
46f19c83bSHermès Bélusca-Maïto * PURPOSE: File support functions.
59c64b57dSHermès Bélusca-Maïto * COPYRIGHT: Casper S. Hornstrup (chorns@users.sourceforge.net)
69c64b57dSHermès Bélusca-Maïto * Copyright 2017-2018 Hermes Belusca-Maito
76f19c83bSHermès Bélusca-Maïto */
86f19c83bSHermès Bélusca-Maïto
96f19c83bSHermès Bélusca-Maïto /* INCLUDES *****************************************************************/
106f19c83bSHermès Bélusca-Maïto
116f19c83bSHermès Bélusca-Maïto #include "precomp.h"
126f19c83bSHermès Bélusca-Maïto #include "filesup.h"
13*31334ebcSTimo Kreuzer #include <pseh/pseh2.h>
146f19c83bSHermès Bélusca-Maïto
156f19c83bSHermès Bélusca-Maïto #define NDEBUG
166f19c83bSHermès Bélusca-Maïto #include <debug.h>
176f19c83bSHermès Bélusca-Maïto
186f19c83bSHermès Bélusca-Maïto /* FUNCTIONS ****************************************************************/
196f19c83bSHermès Bélusca-Maïto
209c64b57dSHermès Bélusca-Maïto static
219c64b57dSHermès Bélusca-Maïto NTSTATUS
SetupCreateSingleDirectory(_In_ PCUNICODE_STRING DirectoryName)229c64b57dSHermès Bélusca-Maïto SetupCreateSingleDirectory(
23ea5728b5SHermès Bélusca-Maïto _In_ PCUNICODE_STRING DirectoryName)
249c64b57dSHermès Bélusca-Maïto {
25ea5728b5SHermès Bélusca-Maïto NTSTATUS Status;
26ea5728b5SHermès Bélusca-Maïto UNICODE_STRING PathName = *DirectoryName;
279c64b57dSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
289c64b57dSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
299c64b57dSHermès Bélusca-Maïto HANDLE DirectoryHandle;
309c64b57dSHermès Bélusca-Maïto
31ea5728b5SHermès Bélusca-Maïto /* Remove the trailing separator if needed */
32ea5728b5SHermès Bélusca-Maïto if (PathName.Length >= 2 * sizeof(WCHAR) &&
33ea5728b5SHermès Bélusca-Maïto PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == OBJ_NAME_PATH_SEPARATOR)
349c64b57dSHermès Bélusca-Maïto {
359c64b57dSHermès Bélusca-Maïto PathName.Length -= sizeof(WCHAR);
369c64b57dSHermès Bélusca-Maïto }
379c64b57dSHermès Bélusca-Maïto
389c64b57dSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
399c64b57dSHermès Bélusca-Maïto &PathName,
40ea5728b5SHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
419c64b57dSHermès Bélusca-Maïto NULL,
429c64b57dSHermès Bélusca-Maïto NULL);
439c64b57dSHermès Bélusca-Maïto
449c64b57dSHermès Bélusca-Maïto Status = NtCreateFile(&DirectoryHandle,
459c64b57dSHermès Bélusca-Maïto FILE_LIST_DIRECTORY | SYNCHRONIZE,
469c64b57dSHermès Bélusca-Maïto &ObjectAttributes,
479c64b57dSHermès Bélusca-Maïto &IoStatusBlock,
489c64b57dSHermès Bélusca-Maïto NULL,
499c64b57dSHermès Bélusca-Maïto FILE_ATTRIBUTE_DIRECTORY,
509c64b57dSHermès Bélusca-Maïto FILE_SHARE_READ | FILE_SHARE_WRITE,
519c64b57dSHermès Bélusca-Maïto FILE_OPEN_IF,
529c64b57dSHermès Bélusca-Maïto FILE_OPEN_FOR_BACKUP_INTENT | FILE_DIRECTORY_FILE,
539c64b57dSHermès Bélusca-Maïto NULL,
549c64b57dSHermès Bélusca-Maïto 0);
559c64b57dSHermès Bélusca-Maïto if (NT_SUCCESS(Status))
569c64b57dSHermès Bélusca-Maïto NtClose(DirectoryHandle);
579c64b57dSHermès Bélusca-Maïto
589c64b57dSHermès Bélusca-Maïto return Status;
599c64b57dSHermès Bélusca-Maïto }
609c64b57dSHermès Bélusca-Maïto
61ea5728b5SHermès Bélusca-Maïto /**
62ea5728b5SHermès Bélusca-Maïto * @brief
63ea5728b5SHermès Bélusca-Maïto * Create a new directory, specified by the given path.
64ea5728b5SHermès Bélusca-Maïto * Any intermediate non-existing directory is created as well.
65ea5728b5SHermès Bélusca-Maïto *
66ea5728b5SHermès Bélusca-Maïto * @param[in] PathName
67ea5728b5SHermès Bélusca-Maïto * The path of the directory to be created.
68ea5728b5SHermès Bélusca-Maïto *
69ea5728b5SHermès Bélusca-Maïto * @return An NTSTATUS code indicating success or failure.
70ea5728b5SHermès Bélusca-Maïto **/
719c64b57dSHermès Bélusca-Maïto NTSTATUS
SetupCreateDirectory(_In_ PCWSTR PathName)729c64b57dSHermès Bélusca-Maïto SetupCreateDirectory(
73ea5728b5SHermès Bélusca-Maïto _In_ PCWSTR PathName)
749c64b57dSHermès Bélusca-Maïto {
759c64b57dSHermès Bélusca-Maïto NTSTATUS Status = STATUS_SUCCESS;
76ea5728b5SHermès Bélusca-Maïto UNICODE_STRING PathNameU;
77ea5728b5SHermès Bélusca-Maïto PCWSTR Buffer;
78ea5728b5SHermès Bélusca-Maïto PCWCH Ptr, End;
799c64b57dSHermès Bélusca-Maïto
80ea5728b5SHermès Bélusca-Maïto RtlInitUnicodeString(&PathNameU, PathName);
81ea5728b5SHermès Bélusca-Maïto Buffer = PathNameU.Buffer;
82ea5728b5SHermès Bélusca-Maïto End = Buffer + (PathNameU.Length / sizeof(WCHAR));
839c64b57dSHermès Bélusca-Maïto
84ea5728b5SHermès Bélusca-Maïto /* Find the deepest existing sub-directory: start from the
85ea5728b5SHermès Bélusca-Maïto * end and go back, verifying each sub-directory in turn */
86ea5728b5SHermès Bélusca-Maïto for (Ptr = End; Ptr > Buffer;)
879c64b57dSHermès Bélusca-Maïto {
88ea5728b5SHermès Bélusca-Maïto BOOLEAN bExists;
899c64b57dSHermès Bélusca-Maïto
90ea5728b5SHermès Bélusca-Maïto /* If we are on a separator, truncate at the next character.
91ea5728b5SHermès Bélusca-Maïto * The trailing separator is kept for the existence check. */
92ea5728b5SHermès Bélusca-Maïto if ((Ptr < End) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
93ea5728b5SHermès Bélusca-Maïto PathNameU.Length = (ULONG_PTR)(Ptr+1) - (ULONG_PTR)Buffer;
94ea5728b5SHermès Bélusca-Maïto
95ea5728b5SHermès Bélusca-Maïto /* Check if the sub-directory exists and stop
96ea5728b5SHermès Bélusca-Maïto * if so: this is the deepest existing one */
97ea5728b5SHermès Bélusca-Maïto DPRINT("PathName: %wZ\n", &PathNameU);
98ea5728b5SHermès Bélusca-Maïto bExists = DoesPathExist_UStr(NULL, &PathNameU, TRUE);
99ea5728b5SHermès Bélusca-Maïto if (bExists)
100ea5728b5SHermès Bélusca-Maïto break;
101ea5728b5SHermès Bélusca-Maïto
102ea5728b5SHermès Bélusca-Maïto /* Skip back any consecutive path separators */
103ea5728b5SHermès Bélusca-Maïto while ((Ptr > Buffer) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
104ea5728b5SHermès Bélusca-Maïto --Ptr;
105ea5728b5SHermès Bélusca-Maïto /* Go to the beginning of the path component, stop at the separator */
106ea5728b5SHermès Bélusca-Maïto while ((Ptr > Buffer) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
107ea5728b5SHermès Bélusca-Maïto --Ptr;
1089c64b57dSHermès Bélusca-Maïto }
1099c64b57dSHermès Bélusca-Maïto
110ea5728b5SHermès Bélusca-Maïto /* Skip any consecutive path separators */
111ea5728b5SHermès Bélusca-Maïto while ((Ptr < End) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
112ea5728b5SHermès Bélusca-Maïto ++Ptr;
1139c64b57dSHermès Bélusca-Maïto
114ea5728b5SHermès Bélusca-Maïto /* Create all the remaining sub-directories */
115ea5728b5SHermès Bélusca-Maïto for (; Ptr < End; ++Ptr)
1169c64b57dSHermès Bélusca-Maïto {
117ea5728b5SHermès Bélusca-Maïto /* Go to the end of the current path component, stop at
118ea5728b5SHermès Bélusca-Maïto * the separator or terminating NUL and truncate it */
119ea5728b5SHermès Bélusca-Maïto while ((Ptr < End) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
120ea5728b5SHermès Bélusca-Maïto ++Ptr;
121ea5728b5SHermès Bélusca-Maïto PathNameU.Length = (ULONG_PTR)Ptr - (ULONG_PTR)Buffer;
122ea5728b5SHermès Bélusca-Maïto
123ea5728b5SHermès Bélusca-Maïto DPRINT("Create: %wZ\n", &PathNameU);
124ea5728b5SHermès Bélusca-Maïto Status = SetupCreateSingleDirectory(&PathNameU);
1259c64b57dSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
126ea5728b5SHermès Bélusca-Maïto break;
1279c64b57dSHermès Bélusca-Maïto }
1289c64b57dSHermès Bélusca-Maïto
1299c64b57dSHermès Bélusca-Maïto DPRINT("Done.\n");
1309c64b57dSHermès Bélusca-Maïto return Status;
1319c64b57dSHermès Bélusca-Maïto }
1326f19c83bSHermès Bélusca-Maïto
1336f19c83bSHermès Bélusca-Maïto NTSTATUS
SetupDeleteFile(IN PCWSTR FileName,IN BOOLEAN ForceDelete)1346f19c83bSHermès Bélusca-Maïto SetupDeleteFile(
1356f19c83bSHermès Bélusca-Maïto IN PCWSTR FileName,
1366f19c83bSHermès Bélusca-Maïto IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files
1376f19c83bSHermès Bélusca-Maïto {
1386f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
1396f19c83bSHermès Bélusca-Maïto UNICODE_STRING NtPathU;
1406f19c83bSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
1416f19c83bSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
1426f19c83bSHermès Bélusca-Maïto HANDLE FileHandle;
1436f19c83bSHermès Bélusca-Maïto FILE_DISPOSITION_INFORMATION FileDispInfo;
1446f19c83bSHermès Bélusca-Maïto BOOLEAN RetryOnce = FALSE;
1456f19c83bSHermès Bélusca-Maïto
1466f19c83bSHermès Bélusca-Maïto /* Open the directory name that was passed in */
1476f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&NtPathU, FileName);
1486f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
1496f19c83bSHermès Bélusca-Maïto &NtPathU,
1506f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
1516f19c83bSHermès Bélusca-Maïto NULL,
1526f19c83bSHermès Bélusca-Maïto NULL);
1536f19c83bSHermès Bélusca-Maïto
1546f19c83bSHermès Bélusca-Maïto Retry: // We go back there once if RetryOnce == TRUE
1556f19c83bSHermès Bélusca-Maïto Status = NtOpenFile(&FileHandle,
1566f19c83bSHermès Bélusca-Maïto DELETE | FILE_READ_ATTRIBUTES |
1576f19c83bSHermès Bélusca-Maïto (RetryOnce ? FILE_WRITE_ATTRIBUTES : 0),
1586f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
1596f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
1606f19c83bSHermès Bélusca-Maïto FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
1616f19c83bSHermès Bélusca-Maïto FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
1626f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
1636f19c83bSHermès Bélusca-Maïto {
1646f19c83bSHermès Bélusca-Maïto DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status);
1656f19c83bSHermès Bélusca-Maïto return Status;
1666f19c83bSHermès Bélusca-Maïto }
1676f19c83bSHermès Bélusca-Maïto
1686f19c83bSHermès Bélusca-Maïto if (RetryOnce)
1696f19c83bSHermès Bélusca-Maïto {
1706f19c83bSHermès Bélusca-Maïto FILE_BASIC_INFORMATION FileInformation;
1716f19c83bSHermès Bélusca-Maïto
1726f19c83bSHermès Bélusca-Maïto Status = NtQueryInformationFile(FileHandle,
1736f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
1746f19c83bSHermès Bélusca-Maïto &FileInformation,
1756f19c83bSHermès Bélusca-Maïto sizeof(FILE_BASIC_INFORMATION),
1766f19c83bSHermès Bélusca-Maïto FileBasicInformation);
1776f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
1786f19c83bSHermès Bélusca-Maïto {
1796f19c83bSHermès Bélusca-Maïto DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n", Status);
1806f19c83bSHermès Bélusca-Maïto NtClose(FileHandle);
1816f19c83bSHermès Bélusca-Maïto return Status;
1826f19c83bSHermès Bélusca-Maïto }
1836f19c83bSHermès Bélusca-Maïto
1846f19c83bSHermès Bélusca-Maïto FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
1856f19c83bSHermès Bélusca-Maïto Status = NtSetInformationFile(FileHandle,
1866f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
1876f19c83bSHermès Bélusca-Maïto &FileInformation,
1886f19c83bSHermès Bélusca-Maïto sizeof(FILE_BASIC_INFORMATION),
1896f19c83bSHermès Bélusca-Maïto FileBasicInformation);
1906f19c83bSHermès Bélusca-Maïto NtClose(FileHandle);
1916f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
1926f19c83bSHermès Bélusca-Maïto {
1936f19c83bSHermès Bélusca-Maïto DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n", Status);
1946f19c83bSHermès Bélusca-Maïto return Status;
1956f19c83bSHermès Bélusca-Maïto }
1966f19c83bSHermès Bélusca-Maïto }
1976f19c83bSHermès Bélusca-Maïto
1986f19c83bSHermès Bélusca-Maïto /* Ask for the file to be deleted */
1996f19c83bSHermès Bélusca-Maïto FileDispInfo.DeleteFile = TRUE;
2006f19c83bSHermès Bélusca-Maïto Status = NtSetInformationFile(FileHandle,
2016f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
2026f19c83bSHermès Bélusca-Maïto &FileDispInfo,
2036f19c83bSHermès Bélusca-Maïto sizeof(FILE_DISPOSITION_INFORMATION),
2046f19c83bSHermès Bélusca-Maïto FileDispositionInformation);
2056f19c83bSHermès Bélusca-Maïto NtClose(FileHandle);
2066f19c83bSHermès Bélusca-Maïto
2076f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
2086f19c83bSHermès Bélusca-Maïto DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n", FileName, Status);
2096f19c83bSHermès Bélusca-Maïto
2106f19c83bSHermès Bélusca-Maïto // FIXME: Check the precise value of Status!
2116f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce)
2126f19c83bSHermès Bélusca-Maïto {
2136f19c83bSHermès Bélusca-Maïto /* Retry once */
2146f19c83bSHermès Bélusca-Maïto RetryOnce = TRUE;
2156f19c83bSHermès Bélusca-Maïto goto Retry;
2166f19c83bSHermès Bélusca-Maïto }
2176f19c83bSHermès Bélusca-Maïto
2186f19c83bSHermès Bélusca-Maïto /* Return result to the caller */
2196f19c83bSHermès Bélusca-Maïto return Status;
2206f19c83bSHermès Bélusca-Maïto }
2216f19c83bSHermès Bélusca-Maïto
2226f19c83bSHermès Bélusca-Maïto NTSTATUS
SetupCopyFile(IN PCWSTR SourceFileName,IN PCWSTR DestinationFileName,IN BOOLEAN FailIfExists)2236f19c83bSHermès Bélusca-Maïto SetupCopyFile(
2246f19c83bSHermès Bélusca-Maïto IN PCWSTR SourceFileName,
2256f19c83bSHermès Bélusca-Maïto IN PCWSTR DestinationFileName,
2266f19c83bSHermès Bélusca-Maïto IN BOOLEAN FailIfExists)
2276f19c83bSHermès Bélusca-Maïto {
2286f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
2296f19c83bSHermès Bélusca-Maïto UNICODE_STRING FileName;
2306f19c83bSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
2316f19c83bSHermès Bélusca-Maïto HANDLE FileHandleSource;
2326f19c83bSHermès Bélusca-Maïto HANDLE FileHandleDest;
2336f19c83bSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
2346f19c83bSHermès Bélusca-Maïto FILE_STANDARD_INFORMATION FileStandard;
2356f19c83bSHermès Bélusca-Maïto FILE_BASIC_INFORMATION FileBasic;
2366f19c83bSHermès Bélusca-Maïto ULONG RegionSize;
2376f19c83bSHermès Bélusca-Maïto HANDLE SourceFileSection;
2386f19c83bSHermès Bélusca-Maïto PVOID SourceFileMap = NULL;
2396f19c83bSHermès Bélusca-Maïto SIZE_T SourceSectionSize = 0;
2406f19c83bSHermès Bélusca-Maïto LARGE_INTEGER ByteOffset;
2416f19c83bSHermès Bélusca-Maïto
2426f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&FileName, SourceFileName);
2436f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
2446f19c83bSHermès Bélusca-Maïto &FileName,
2456f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
2466f19c83bSHermès Bélusca-Maïto NULL,
2476f19c83bSHermès Bélusca-Maïto NULL);
2486f19c83bSHermès Bélusca-Maïto
2496f19c83bSHermès Bélusca-Maïto Status = NtOpenFile(&FileHandleSource,
2506f19c83bSHermès Bélusca-Maïto GENERIC_READ,
2516f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
2526f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
2536f19c83bSHermès Bélusca-Maïto FILE_SHARE_READ,
2546f19c83bSHermès Bélusca-Maïto FILE_SEQUENTIAL_ONLY);
2556f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
2566f19c83bSHermès Bélusca-Maïto {
2576f19c83bSHermès Bélusca-Maïto DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName);
2586f19c83bSHermès Bélusca-Maïto goto done;
2596f19c83bSHermès Bélusca-Maïto }
2606f19c83bSHermès Bélusca-Maïto
2616f19c83bSHermès Bélusca-Maïto Status = NtQueryInformationFile(FileHandleSource,
2626f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
2636f19c83bSHermès Bélusca-Maïto &FileStandard,
2646f19c83bSHermès Bélusca-Maïto sizeof(FILE_STANDARD_INFORMATION),
2656f19c83bSHermès Bélusca-Maïto FileStandardInformation);
2666f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
2676f19c83bSHermès Bélusca-Maïto {
2686f19c83bSHermès Bélusca-Maïto DPRINT1("NtQueryInformationFile failed: %x\n", Status);
2696f19c83bSHermès Bélusca-Maïto goto closesrc;
2706f19c83bSHermès Bélusca-Maïto }
2716f19c83bSHermès Bélusca-Maïto
2726f19c83bSHermès Bélusca-Maïto Status = NtQueryInformationFile(FileHandleSource,
2736f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
2746f19c83bSHermès Bélusca-Maïto &FileBasic,
2756f19c83bSHermès Bélusca-Maïto sizeof(FILE_BASIC_INFORMATION),
2766f19c83bSHermès Bélusca-Maïto FileBasicInformation);
2776f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
2786f19c83bSHermès Bélusca-Maïto {
2796f19c83bSHermès Bélusca-Maïto DPRINT1("NtQueryInformationFile failed: %x\n", Status);
2806f19c83bSHermès Bélusca-Maïto goto closesrc;
2816f19c83bSHermès Bélusca-Maïto }
2826f19c83bSHermès Bélusca-Maïto
2836f19c83bSHermès Bélusca-Maïto Status = NtCreateSection(&SourceFileSection,
2846f19c83bSHermès Bélusca-Maïto SECTION_MAP_READ,
2856f19c83bSHermès Bélusca-Maïto NULL,
2866f19c83bSHermès Bélusca-Maïto NULL,
2876f19c83bSHermès Bélusca-Maïto PAGE_READONLY,
2886f19c83bSHermès Bélusca-Maïto SEC_COMMIT,
2896f19c83bSHermès Bélusca-Maïto FileHandleSource);
2906f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
2916f19c83bSHermès Bélusca-Maïto {
2926f19c83bSHermès Bélusca-Maïto DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName);
2936f19c83bSHermès Bélusca-Maïto goto closesrc;
2946f19c83bSHermès Bélusca-Maïto }
2956f19c83bSHermès Bélusca-Maïto
2966f19c83bSHermès Bélusca-Maïto Status = NtMapViewOfSection(SourceFileSection,
2976f19c83bSHermès Bélusca-Maïto NtCurrentProcess(),
2986f19c83bSHermès Bélusca-Maïto &SourceFileMap,
2996f19c83bSHermès Bélusca-Maïto 0,
3006f19c83bSHermès Bélusca-Maïto 0,
3016f19c83bSHermès Bélusca-Maïto NULL,
3026f19c83bSHermès Bélusca-Maïto &SourceSectionSize,
3036f19c83bSHermès Bélusca-Maïto ViewUnmap,
3046f19c83bSHermès Bélusca-Maïto 0,
3056f19c83bSHermès Bélusca-Maïto PAGE_READONLY);
3066f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
3076f19c83bSHermès Bélusca-Maïto {
3086f19c83bSHermès Bélusca-Maïto DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName);
3096f19c83bSHermès Bélusca-Maïto goto closesrcsec;
3106f19c83bSHermès Bélusca-Maïto }
3116f19c83bSHermès Bélusca-Maïto
3126f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&FileName, DestinationFileName);
3136f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
3146f19c83bSHermès Bélusca-Maïto &FileName,
3156f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
3166f19c83bSHermès Bélusca-Maïto NULL,
3176f19c83bSHermès Bélusca-Maïto NULL);
3186f19c83bSHermès Bélusca-Maïto
3196f19c83bSHermès Bélusca-Maïto Status = NtCreateFile(&FileHandleDest,
3206f19c83bSHermès Bélusca-Maïto GENERIC_WRITE | SYNCHRONIZE,
3216f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
3226f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
3236f19c83bSHermès Bélusca-Maïto NULL,
3246f19c83bSHermès Bélusca-Maïto FileBasic.FileAttributes, // FILE_ATTRIBUTE_NORMAL,
3256f19c83bSHermès Bélusca-Maïto 0,
3266f19c83bSHermès Bélusca-Maïto FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,
3276f19c83bSHermès Bélusca-Maïto FILE_NO_INTERMEDIATE_BUFFERING |
3286f19c83bSHermès Bélusca-Maïto FILE_SEQUENTIAL_ONLY |
3296f19c83bSHermès Bélusca-Maïto FILE_SYNCHRONOUS_IO_NONALERT,
3306f19c83bSHermès Bélusca-Maïto NULL,
3316f19c83bSHermès Bélusca-Maïto 0);
3326f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
3336f19c83bSHermès Bélusca-Maïto {
3346f19c83bSHermès Bélusca-Maïto /*
3356f19c83bSHermès Bélusca-Maïto * Open may have failed because the file to overwrite
3366f19c83bSHermès Bélusca-Maïto * is in readonly mode.
3376f19c83bSHermès Bélusca-Maïto */
3386f19c83bSHermès Bélusca-Maïto if (Status == STATUS_ACCESS_DENIED)
3396f19c83bSHermès Bélusca-Maïto {
3406f19c83bSHermès Bélusca-Maïto FILE_BASIC_INFORMATION FileBasicInfo;
3416f19c83bSHermès Bélusca-Maïto
3426f19c83bSHermès Bélusca-Maïto /* Reattempt to open it with limited access */
3436f19c83bSHermès Bélusca-Maïto Status = NtCreateFile(&FileHandleDest,
3446f19c83bSHermès Bélusca-Maïto FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
3456f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
3466f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
3476f19c83bSHermès Bélusca-Maïto NULL,
3486f19c83bSHermès Bélusca-Maïto FILE_ATTRIBUTE_NORMAL,
3496f19c83bSHermès Bélusca-Maïto 0,
3506f19c83bSHermès Bélusca-Maïto FILE_OPEN,
3516f19c83bSHermès Bélusca-Maïto FILE_NO_INTERMEDIATE_BUFFERING |
3526f19c83bSHermès Bélusca-Maïto FILE_SEQUENTIAL_ONLY |
3536f19c83bSHermès Bélusca-Maïto FILE_SYNCHRONOUS_IO_NONALERT,
3546f19c83bSHermès Bélusca-Maïto NULL,
3556f19c83bSHermès Bélusca-Maïto 0);
3566f19c83bSHermès Bélusca-Maïto /* Fail for real if we cannot open it that way */
3576f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
3586f19c83bSHermès Bélusca-Maïto {
3596f19c83bSHermès Bélusca-Maïto DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName);
3606f19c83bSHermès Bélusca-Maïto goto unmapsrcsec;
3616f19c83bSHermès Bélusca-Maïto }
3626f19c83bSHermès Bélusca-Maïto
3636f19c83bSHermès Bélusca-Maïto /* Zero our basic info, just to set attributes */
3646f19c83bSHermès Bélusca-Maïto RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
3656f19c83bSHermès Bélusca-Maïto /* Reset attributes to normal, no read-only */
3666f19c83bSHermès Bélusca-Maïto FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
3676f19c83bSHermès Bélusca-Maïto /*
3686f19c83bSHermès Bélusca-Maïto * We basically don't care about whether it succeed:
3696f19c83bSHermès Bélusca-Maïto * if it didn't, later open will fail.
3706f19c83bSHermès Bélusca-Maïto */
3716f19c83bSHermès Bélusca-Maïto NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasicInfo,
3726f19c83bSHermès Bélusca-Maïto sizeof(FileBasicInfo), FileBasicInformation);
3736f19c83bSHermès Bélusca-Maïto
3746f19c83bSHermès Bélusca-Maïto /* Close file */
3756f19c83bSHermès Bélusca-Maïto NtClose(FileHandleDest);
3766f19c83bSHermès Bélusca-Maïto
3776f19c83bSHermès Bélusca-Maïto /* And re-attempt overwrite */
3786f19c83bSHermès Bélusca-Maïto Status = NtCreateFile(&FileHandleDest,
3796f19c83bSHermès Bélusca-Maïto GENERIC_WRITE | SYNCHRONIZE,
3806f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
3816f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
3826f19c83bSHermès Bélusca-Maïto NULL,
3836f19c83bSHermès Bélusca-Maïto FILE_ATTRIBUTE_NORMAL,
3846f19c83bSHermès Bélusca-Maïto 0,
3856f19c83bSHermès Bélusca-Maïto FILE_OVERWRITE_IF,
3866f19c83bSHermès Bélusca-Maïto FILE_NO_INTERMEDIATE_BUFFERING |
3876f19c83bSHermès Bélusca-Maïto FILE_SEQUENTIAL_ONLY |
3886f19c83bSHermès Bélusca-Maïto FILE_SYNCHRONOUS_IO_NONALERT,
3896f19c83bSHermès Bélusca-Maïto NULL,
3906f19c83bSHermès Bélusca-Maïto 0);
3916f19c83bSHermès Bélusca-Maïto }
3926f19c83bSHermès Bélusca-Maïto
3936f19c83bSHermès Bélusca-Maïto /* We failed */
3946f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
3956f19c83bSHermès Bélusca-Maïto {
3966f19c83bSHermès Bélusca-Maïto DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName);
3976f19c83bSHermès Bélusca-Maïto goto unmapsrcsec;
3986f19c83bSHermès Bélusca-Maïto }
3996f19c83bSHermès Bélusca-Maïto }
4006f19c83bSHermès Bélusca-Maïto
4016f19c83bSHermès Bélusca-Maïto RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
4026f19c83bSHermès Bélusca-Maïto IoStatusBlock.Status = 0;
4036f19c83bSHermès Bélusca-Maïto ByteOffset.QuadPart = 0ULL;
4046f19c83bSHermès Bélusca-Maïto Status = NtWriteFile(FileHandleDest,
4056f19c83bSHermès Bélusca-Maïto NULL,
4066f19c83bSHermès Bélusca-Maïto NULL,
4076f19c83bSHermès Bélusca-Maïto NULL,
4086f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
4096f19c83bSHermès Bélusca-Maïto SourceFileMap,
4106f19c83bSHermès Bélusca-Maïto RegionSize,
4116f19c83bSHermès Bélusca-Maïto &ByteOffset,
4126f19c83bSHermès Bélusca-Maïto NULL);
4136f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
4146f19c83bSHermès Bélusca-Maïto {
4156f19c83bSHermès Bélusca-Maïto DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n",
4166f19c83bSHermès Bélusca-Maïto Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
4176f19c83bSHermès Bélusca-Maïto goto closedest;
4186f19c83bSHermès Bélusca-Maïto }
4196f19c83bSHermès Bélusca-Maïto
4206f19c83bSHermès Bélusca-Maïto /* Copy file date/time from source file */
4216f19c83bSHermès Bélusca-Maïto Status = NtSetInformationFile(FileHandleDest,
4226f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
4236f19c83bSHermès Bélusca-Maïto &FileBasic,
4246f19c83bSHermès Bélusca-Maïto sizeof(FILE_BASIC_INFORMATION),
4256f19c83bSHermès Bélusca-Maïto FileBasicInformation);
4266f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
4276f19c83bSHermès Bélusca-Maïto {
4286f19c83bSHermès Bélusca-Maïto DPRINT1("NtSetInformationFile failed: %x\n", Status);
4296f19c83bSHermès Bélusca-Maïto goto closedest;
4306f19c83bSHermès Bélusca-Maïto }
4316f19c83bSHermès Bélusca-Maïto
4326f19c83bSHermès Bélusca-Maïto /* Shorten the file back to its real size after completing the write */
4336f19c83bSHermès Bélusca-Maïto Status = NtSetInformationFile(FileHandleDest,
4346f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
4356f19c83bSHermès Bélusca-Maïto &FileStandard.EndOfFile,
4366f19c83bSHermès Bélusca-Maïto sizeof(FILE_END_OF_FILE_INFORMATION),
4376f19c83bSHermès Bélusca-Maïto FileEndOfFileInformation);
4386f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
4396f19c83bSHermès Bélusca-Maïto {
4406f19c83bSHermès Bélusca-Maïto DPRINT1("NtSetInformationFile failed: %x\n", Status);
4416f19c83bSHermès Bélusca-Maïto }
4426f19c83bSHermès Bélusca-Maïto
4436f19c83bSHermès Bélusca-Maïto closedest:
4446f19c83bSHermès Bélusca-Maïto NtClose(FileHandleDest);
4456f19c83bSHermès Bélusca-Maïto
4466f19c83bSHermès Bélusca-Maïto unmapsrcsec:
4476f19c83bSHermès Bélusca-Maïto NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap);
4486f19c83bSHermès Bélusca-Maïto
4496f19c83bSHermès Bélusca-Maïto closesrcsec:
4506f19c83bSHermès Bélusca-Maïto NtClose(SourceFileSection);
4516f19c83bSHermès Bélusca-Maïto
4526f19c83bSHermès Bélusca-Maïto closesrc:
4536f19c83bSHermès Bélusca-Maïto NtClose(FileHandleSource);
4546f19c83bSHermès Bélusca-Maïto
4556f19c83bSHermès Bélusca-Maïto done:
4566f19c83bSHermès Bélusca-Maïto return Status;
4576f19c83bSHermès Bélusca-Maïto }
4586f19c83bSHermès Bélusca-Maïto
4596f19c83bSHermès Bélusca-Maïto /*
4606f19c83bSHermès Bélusca-Maïto * Synchronized with its kernel32 counterpart, but we don't manage reparse points here.
4616f19c83bSHermès Bélusca-Maïto */
4626f19c83bSHermès Bélusca-Maïto NTSTATUS
SetupMoveFile(IN PCWSTR ExistingFileName,IN PCWSTR NewFileName,IN ULONG Flags)4636f19c83bSHermès Bélusca-Maïto SetupMoveFile(
4646f19c83bSHermès Bélusca-Maïto IN PCWSTR ExistingFileName,
4656f19c83bSHermès Bélusca-Maïto IN PCWSTR NewFileName,
4666f19c83bSHermès Bélusca-Maïto IN ULONG Flags)
4676f19c83bSHermès Bélusca-Maïto {
4686f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
4696f19c83bSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
4706f19c83bSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
4716f19c83bSHermès Bélusca-Maïto PFILE_RENAME_INFORMATION RenameInfo;
4726f19c83bSHermès Bélusca-Maïto UNICODE_STRING NewPathU, ExistingPathU;
4736f19c83bSHermès Bélusca-Maïto HANDLE SourceHandle = NULL;
4746f19c83bSHermès Bélusca-Maïto BOOLEAN ReplaceIfExists;
4756f19c83bSHermès Bélusca-Maïto
4766f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&ExistingPathU, ExistingFileName);
4776f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&NewPathU, NewFileName);
4786f19c83bSHermès Bélusca-Maïto
4796f19c83bSHermès Bélusca-Maïto _SEH2_TRY
4806f19c83bSHermès Bélusca-Maïto {
4816f19c83bSHermès Bélusca-Maïto ReplaceIfExists = !!(Flags & MOVEFILE_REPLACE_EXISTING);
4826f19c83bSHermès Bélusca-Maïto
4836f19c83bSHermès Bélusca-Maïto /* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
4846f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
4856f19c83bSHermès Bélusca-Maïto &ExistingPathU,
4866f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
4876f19c83bSHermès Bélusca-Maïto NULL,
4886f19c83bSHermès Bélusca-Maïto NULL);
4896f19c83bSHermès Bélusca-Maïto /* Attempt to open source file */
4906f19c83bSHermès Bélusca-Maïto Status = NtOpenFile(&SourceHandle,
4916f19c83bSHermès Bélusca-Maïto FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
4926f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
4936f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
4946f19c83bSHermès Bélusca-Maïto FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
4956f19c83bSHermès Bélusca-Maïto FILE_OPEN_FOR_BACKUP_INTENT | ((Flags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
4966f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
4976f19c83bSHermès Bélusca-Maïto {
4986f19c83bSHermès Bélusca-Maïto if (Status != STATUS_INVALID_PARAMETER)
4996f19c83bSHermès Bélusca-Maïto {
5006f19c83bSHermès Bélusca-Maïto _SEH2_LEAVE;
5016f19c83bSHermès Bélusca-Maïto }
5026f19c83bSHermès Bélusca-Maïto }
5036f19c83bSHermès Bélusca-Maïto
5046f19c83bSHermès Bélusca-Maïto /* At that point, we MUST have a source handle */
5056f19c83bSHermès Bélusca-Maïto ASSERT(SourceHandle);
5066f19c83bSHermès Bélusca-Maïto
5076f19c83bSHermès Bélusca-Maïto /* Allocate renaming buffer and fill it */
5086f19c83bSHermès Bélusca-Maïto RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
5096f19c83bSHermès Bélusca-Maïto if (RenameInfo == NULL)
5106f19c83bSHermès Bélusca-Maïto {
5116f19c83bSHermès Bélusca-Maïto Status = STATUS_NO_MEMORY;
5126f19c83bSHermès Bélusca-Maïto _SEH2_LEAVE;
5136f19c83bSHermès Bélusca-Maïto }
5146f19c83bSHermès Bélusca-Maïto
5156f19c83bSHermès Bélusca-Maïto RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
5166f19c83bSHermès Bélusca-Maïto RenameInfo->ReplaceIfExists = ReplaceIfExists;
5176f19c83bSHermès Bélusca-Maïto RenameInfo->RootDirectory = NULL;
5186f19c83bSHermès Bélusca-Maïto RenameInfo->FileNameLength = NewPathU.Length;
5196f19c83bSHermès Bélusca-Maïto
5206f19c83bSHermès Bélusca-Maïto /* Attempt to rename the file */
5216f19c83bSHermès Bélusca-Maïto Status = NtSetInformationFile(SourceHandle,
5226f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
5236f19c83bSHermès Bélusca-Maïto RenameInfo,
5246f19c83bSHermès Bélusca-Maïto NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
5256f19c83bSHermès Bélusca-Maïto FileRenameInformation);
5266f19c83bSHermès Bélusca-Maïto RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
5276f19c83bSHermès Bélusca-Maïto if (NT_SUCCESS(Status))
5286f19c83bSHermès Bélusca-Maïto {
5296f19c83bSHermès Bélusca-Maïto /* If it succeeded, all fine, quit */
5306f19c83bSHermès Bélusca-Maïto _SEH2_LEAVE;
5316f19c83bSHermès Bélusca-Maïto }
5326f19c83bSHermès Bélusca-Maïto /*
5336f19c83bSHermès Bélusca-Maïto * If we failed for any other reason than not the same device, fail.
5346f19c83bSHermès Bélusca-Maïto * If we failed because of different devices, only allow renaming
5356f19c83bSHermès Bélusca-Maïto * if user allowed copy.
5366f19c83bSHermès Bélusca-Maïto */
5376f19c83bSHermès Bélusca-Maïto if (Status != STATUS_NOT_SAME_DEVICE || !(Flags & MOVEFILE_COPY_ALLOWED))
5386f19c83bSHermès Bélusca-Maïto {
5396f19c83bSHermès Bélusca-Maïto /* ReactOS hack! To be removed once all FSD have proper renaming support
5406f19c83bSHermès Bélusca-Maïto * Just leave status to error and leave
5416f19c83bSHermès Bélusca-Maïto */
5426f19c83bSHermès Bélusca-Maïto if (Status == STATUS_NOT_IMPLEMENTED)
5436f19c83bSHermès Bélusca-Maïto {
5446f19c83bSHermès Bélusca-Maïto DPRINT1("Forcing copy, renaming not supported by FSD\n");
5456f19c83bSHermès Bélusca-Maïto }
5466f19c83bSHermès Bélusca-Maïto else
5476f19c83bSHermès Bélusca-Maïto {
5486f19c83bSHermès Bélusca-Maïto _SEH2_LEAVE;
5496f19c83bSHermès Bélusca-Maïto }
5506f19c83bSHermès Bélusca-Maïto }
5516f19c83bSHermès Bélusca-Maïto
5526f19c83bSHermès Bélusca-Maïto /* Close the source file */
5536f19c83bSHermès Bélusca-Maïto NtClose(SourceHandle);
5546f19c83bSHermès Bélusca-Maïto SourceHandle = NULL;
5556f19c83bSHermès Bélusca-Maïto
5566f19c83bSHermès Bélusca-Maïto /* Perform the file copy */
5576f19c83bSHermès Bélusca-Maïto Status = SetupCopyFile(ExistingFileName,
5586f19c83bSHermès Bélusca-Maïto NewFileName,
5596f19c83bSHermès Bélusca-Maïto !ReplaceIfExists);
5606f19c83bSHermès Bélusca-Maïto
5616f19c83bSHermès Bélusca-Maïto /* If it succeeded, delete the source file */
5626f19c83bSHermès Bélusca-Maïto if (NT_SUCCESS(Status))
5636f19c83bSHermès Bélusca-Maïto {
5646f19c83bSHermès Bélusca-Maïto /* Force-delete files even if read-only */
5656f19c83bSHermès Bélusca-Maïto SetupDeleteFile(ExistingFileName, TRUE);
5666f19c83bSHermès Bélusca-Maïto }
5676f19c83bSHermès Bélusca-Maïto }
5686f19c83bSHermès Bélusca-Maïto _SEH2_FINALLY
5696f19c83bSHermès Bélusca-Maïto {
5706f19c83bSHermès Bélusca-Maïto if (SourceHandle)
5716f19c83bSHermès Bélusca-Maïto NtClose(SourceHandle);
5726f19c83bSHermès Bélusca-Maïto }
5736f19c83bSHermès Bélusca-Maïto _SEH2_END;
5746f19c83bSHermès Bélusca-Maïto
5756f19c83bSHermès Bélusca-Maïto return Status;
5766f19c83bSHermès Bélusca-Maïto }
5776f19c83bSHermès Bélusca-Maïto
5786f19c83bSHermès Bélusca-Maïto NTSTATUS
ConcatPathsV(IN OUT PWSTR PathBuffer,IN SIZE_T cchPathSize,IN ULONG NumberOfPathComponents,IN va_list PathComponentsList)5796f19c83bSHermès Bélusca-Maïto ConcatPathsV(
5806f19c83bSHermès Bélusca-Maïto IN OUT PWSTR PathBuffer,
5816f19c83bSHermès Bélusca-Maïto IN SIZE_T cchPathSize,
5826f19c83bSHermès Bélusca-Maïto IN ULONG NumberOfPathComponents,
5836f19c83bSHermès Bélusca-Maïto IN va_list PathComponentsList)
5846f19c83bSHermès Bélusca-Maïto {
5856f19c83bSHermès Bélusca-Maïto NTSTATUS Status = STATUS_SUCCESS;
5866f19c83bSHermès Bélusca-Maïto SIZE_T cchPathLen;
5876f19c83bSHermès Bélusca-Maïto PCWSTR PathComponent;
5886f19c83bSHermès Bélusca-Maïto
5896f19c83bSHermès Bélusca-Maïto if (cchPathSize < 1)
5906f19c83bSHermès Bélusca-Maïto return STATUS_SUCCESS;
5916f19c83bSHermès Bélusca-Maïto
5926f19c83bSHermès Bélusca-Maïto while (NumberOfPathComponents--)
5936f19c83bSHermès Bélusca-Maïto {
5946f19c83bSHermès Bélusca-Maïto PathComponent = va_arg(PathComponentsList, PCWSTR);
5956f19c83bSHermès Bélusca-Maïto if (!PathComponent)
5966f19c83bSHermès Bélusca-Maïto continue;
5976f19c83bSHermès Bélusca-Maïto
5986f19c83bSHermès Bélusca-Maïto cchPathLen = min(cchPathSize, wcslen(PathBuffer));
5996f19c83bSHermès Bélusca-Maïto if (cchPathLen >= cchPathSize)
6006f19c83bSHermès Bélusca-Maïto return STATUS_BUFFER_OVERFLOW;
6016f19c83bSHermès Bélusca-Maïto
6026f19c83bSHermès Bélusca-Maïto if (PathComponent[0] != OBJ_NAME_PATH_SEPARATOR &&
6036f19c83bSHermès Bélusca-Maïto cchPathLen > 0 && PathBuffer[cchPathLen-1] != OBJ_NAME_PATH_SEPARATOR)
6046f19c83bSHermès Bélusca-Maïto {
6056f19c83bSHermès Bélusca-Maïto /* PathComponent does not start with '\' and PathBuffer does not end with '\' */
6066f19c83bSHermès Bélusca-Maïto Status = RtlStringCchCatW(PathBuffer, cchPathSize, L"\\");
6076f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
6086f19c83bSHermès Bélusca-Maïto return Status;
6096f19c83bSHermès Bélusca-Maïto }
6106f19c83bSHermès Bélusca-Maïto else if (PathComponent[0] == OBJ_NAME_PATH_SEPARATOR &&
6116f19c83bSHermès Bélusca-Maïto cchPathLen > 0 && PathBuffer[cchPathLen-1] == OBJ_NAME_PATH_SEPARATOR)
6126f19c83bSHermès Bélusca-Maïto {
6136f19c83bSHermès Bélusca-Maïto /* PathComponent starts with '\' and PathBuffer ends with '\' */
6146f19c83bSHermès Bélusca-Maïto while (*PathComponent == OBJ_NAME_PATH_SEPARATOR)
6156f19c83bSHermès Bélusca-Maïto ++PathComponent; // Skip any backslash
6166f19c83bSHermès Bélusca-Maïto }
6176f19c83bSHermès Bélusca-Maïto Status = RtlStringCchCatW(PathBuffer, cchPathSize, PathComponent);
6186f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
6196f19c83bSHermès Bélusca-Maïto return Status;
6206f19c83bSHermès Bélusca-Maïto }
6216f19c83bSHermès Bélusca-Maïto
6226f19c83bSHermès Bélusca-Maïto return Status;
6236f19c83bSHermès Bélusca-Maïto }
6246f19c83bSHermès Bélusca-Maïto
6256f19c83bSHermès Bélusca-Maïto NTSTATUS
CombinePathsV(OUT PWSTR PathBuffer,IN SIZE_T cchPathSize,IN ULONG NumberOfPathComponents,IN va_list PathComponentsList)6266f19c83bSHermès Bélusca-Maïto CombinePathsV(
6276f19c83bSHermès Bélusca-Maïto OUT PWSTR PathBuffer,
6286f19c83bSHermès Bélusca-Maïto IN SIZE_T cchPathSize,
6296f19c83bSHermès Bélusca-Maïto IN ULONG NumberOfPathComponents,
6306f19c83bSHermès Bélusca-Maïto IN va_list PathComponentsList)
6316f19c83bSHermès Bélusca-Maïto {
6326f19c83bSHermès Bélusca-Maïto if (cchPathSize < 1)
6336f19c83bSHermès Bélusca-Maïto return STATUS_SUCCESS;
6346f19c83bSHermès Bélusca-Maïto
6356f19c83bSHermès Bélusca-Maïto *PathBuffer = UNICODE_NULL;
6366f19c83bSHermès Bélusca-Maïto return ConcatPathsV(PathBuffer, cchPathSize,
6376f19c83bSHermès Bélusca-Maïto NumberOfPathComponents,
6386f19c83bSHermès Bélusca-Maïto PathComponentsList);
6396f19c83bSHermès Bélusca-Maïto }
6406f19c83bSHermès Bélusca-Maïto
6416f19c83bSHermès Bélusca-Maïto NTSTATUS
ConcatPaths(IN OUT PWSTR PathBuffer,IN SIZE_T cchPathSize,IN ULONG NumberOfPathComponents,IN...)6426f19c83bSHermès Bélusca-Maïto ConcatPaths(
6436f19c83bSHermès Bélusca-Maïto IN OUT PWSTR PathBuffer,
6446f19c83bSHermès Bélusca-Maïto IN SIZE_T cchPathSize,
6456f19c83bSHermès Bélusca-Maïto IN ULONG NumberOfPathComponents,
6466f19c83bSHermès Bélusca-Maïto IN /* PCWSTR */ ...)
6476f19c83bSHermès Bélusca-Maïto {
6486f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
6496f19c83bSHermès Bélusca-Maïto va_list PathComponentsList;
6506f19c83bSHermès Bélusca-Maïto
6516f19c83bSHermès Bélusca-Maïto if (cchPathSize < 1)
6526f19c83bSHermès Bélusca-Maïto return STATUS_SUCCESS;
6536f19c83bSHermès Bélusca-Maïto
6546f19c83bSHermès Bélusca-Maïto va_start(PathComponentsList, NumberOfPathComponents);
6556f19c83bSHermès Bélusca-Maïto Status = ConcatPathsV(PathBuffer, cchPathSize,
6566f19c83bSHermès Bélusca-Maïto NumberOfPathComponents,
6576f19c83bSHermès Bélusca-Maïto PathComponentsList);
6586f19c83bSHermès Bélusca-Maïto va_end(PathComponentsList);
6596f19c83bSHermès Bélusca-Maïto
6606f19c83bSHermès Bélusca-Maïto return Status;
6616f19c83bSHermès Bélusca-Maïto }
6626f19c83bSHermès Bélusca-Maïto
6636f19c83bSHermès Bélusca-Maïto NTSTATUS
CombinePaths(OUT PWSTR PathBuffer,IN SIZE_T cchPathSize,IN ULONG NumberOfPathComponents,IN...)6646f19c83bSHermès Bélusca-Maïto CombinePaths(
6656f19c83bSHermès Bélusca-Maïto OUT PWSTR PathBuffer,
6666f19c83bSHermès Bélusca-Maïto IN SIZE_T cchPathSize,
6676f19c83bSHermès Bélusca-Maïto IN ULONG NumberOfPathComponents,
6686f19c83bSHermès Bélusca-Maïto IN /* PCWSTR */ ...)
6696f19c83bSHermès Bélusca-Maïto {
6706f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
6716f19c83bSHermès Bélusca-Maïto va_list PathComponentsList;
6726f19c83bSHermès Bélusca-Maïto
6736f19c83bSHermès Bélusca-Maïto if (cchPathSize < 1)
6746f19c83bSHermès Bélusca-Maïto return STATUS_SUCCESS;
6756f19c83bSHermès Bélusca-Maïto
6766f19c83bSHermès Bélusca-Maïto *PathBuffer = UNICODE_NULL;
6776f19c83bSHermès Bélusca-Maïto
6786f19c83bSHermès Bélusca-Maïto va_start(PathComponentsList, NumberOfPathComponents);
6796f19c83bSHermès Bélusca-Maïto Status = CombinePathsV(PathBuffer, cchPathSize,
6806f19c83bSHermès Bélusca-Maïto NumberOfPathComponents,
6816f19c83bSHermès Bélusca-Maïto PathComponentsList);
6826f19c83bSHermès Bélusca-Maïto va_end(PathComponentsList);
6836f19c83bSHermès Bélusca-Maïto
6846f19c83bSHermès Bélusca-Maïto return Status;
6856f19c83bSHermès Bélusca-Maïto }
6866f19c83bSHermès Bélusca-Maïto
6876f19c83bSHermès Bélusca-Maïto BOOLEAN
DoesPathExist_UStr(_In_opt_ HANDLE RootDirectory,_In_ PCUNICODE_STRING PathName,_In_ BOOLEAN IsDirectory)688ea5728b5SHermès Bélusca-Maïto DoesPathExist_UStr(
689ea5728b5SHermès Bélusca-Maïto _In_opt_ HANDLE RootDirectory,
690ea5728b5SHermès Bélusca-Maïto _In_ PCUNICODE_STRING PathName,
691ea5728b5SHermès Bélusca-Maïto _In_ BOOLEAN IsDirectory)
6926f19c83bSHermès Bélusca-Maïto {
6936f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
6946f19c83bSHermès Bélusca-Maïto HANDLE FileHandle;
6956f19c83bSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
6966f19c83bSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
6976f19c83bSHermès Bélusca-Maïto
6986f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
699ea5728b5SHermès Bélusca-Maïto (PUNICODE_STRING)PathName,
7006f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
7016f19c83bSHermès Bélusca-Maïto RootDirectory,
7026f19c83bSHermès Bélusca-Maïto NULL);
7036f19c83bSHermès Bélusca-Maïto
7046f19c83bSHermès Bélusca-Maïto Status = NtOpenFile(&FileHandle,
7056f19c83bSHermès Bélusca-Maïto IsDirectory ? (FILE_LIST_DIRECTORY | SYNCHRONIZE)
7066f19c83bSHermès Bélusca-Maïto : FILE_GENERIC_READ, // Contains SYNCHRONIZE
7076f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
7086f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
7096f19c83bSHermès Bélusca-Maïto FILE_SHARE_READ | FILE_SHARE_WRITE,
7106f19c83bSHermès Bélusca-Maïto FILE_SYNCHRONOUS_IO_NONALERT |
7116f19c83bSHermès Bélusca-Maïto (IsDirectory ? FILE_DIRECTORY_FILE
7126f19c83bSHermès Bélusca-Maïto : FILE_NON_DIRECTORY_FILE));
7136f19c83bSHermès Bélusca-Maïto if (NT_SUCCESS(Status))
7146f19c83bSHermès Bélusca-Maïto {
7156f19c83bSHermès Bélusca-Maïto NtClose(FileHandle);
7166f19c83bSHermès Bélusca-Maïto }
7176f19c83bSHermès Bélusca-Maïto else
7186f19c83bSHermès Bélusca-Maïto {
7196f19c83bSHermès Bélusca-Maïto DPRINT("Failed to open %s '%wZ', Status 0x%08lx\n",
7206f19c83bSHermès Bélusca-Maïto IsDirectory ? "directory" : "file",
721ea5728b5SHermès Bélusca-Maïto PathName, Status);
7226f19c83bSHermès Bélusca-Maïto }
7236f19c83bSHermès Bélusca-Maïto
7246f19c83bSHermès Bélusca-Maïto return NT_SUCCESS(Status);
7256f19c83bSHermès Bélusca-Maïto }
7266f19c83bSHermès Bélusca-Maïto
727ea5728b5SHermès Bélusca-Maïto BOOLEAN
DoesPathExist(_In_opt_ HANDLE RootDirectory,_In_ PCWSTR PathName,_In_ BOOLEAN IsDirectory)728ea5728b5SHermès Bélusca-Maïto DoesPathExist(
729ea5728b5SHermès Bélusca-Maïto _In_opt_ HANDLE RootDirectory,
730ea5728b5SHermès Bélusca-Maïto _In_ PCWSTR PathName,
731ea5728b5SHermès Bélusca-Maïto _In_ BOOLEAN IsDirectory)
732ea5728b5SHermès Bélusca-Maïto {
733ea5728b5SHermès Bélusca-Maïto UNICODE_STRING PathNameU;
734ea5728b5SHermès Bélusca-Maïto RtlInitUnicodeString(&PathNameU, PathName);
735ea5728b5SHermès Bélusca-Maïto return DoesPathExist_UStr(RootDirectory, &PathNameU, IsDirectory);
736ea5728b5SHermès Bélusca-Maïto }
737ea5728b5SHermès Bélusca-Maïto
7386f19c83bSHermès Bélusca-Maïto // FIXME: DEPRECATED! HACKish function that needs to be deprecated!
7396f19c83bSHermès Bélusca-Maïto BOOLEAN
DoesFileExist_2(IN PCWSTR PathName OPTIONAL,IN PCWSTR FileName)7406f19c83bSHermès Bélusca-Maïto DoesFileExist_2(
7416f19c83bSHermès Bélusca-Maïto IN PCWSTR PathName OPTIONAL,
7426f19c83bSHermès Bélusca-Maïto IN PCWSTR FileName)
7436f19c83bSHermès Bélusca-Maïto {
7446f19c83bSHermès Bélusca-Maïto WCHAR FullName[MAX_PATH];
7456f19c83bSHermès Bélusca-Maïto CombinePaths(FullName, ARRAYSIZE(FullName), 2, PathName, FileName);
7466f19c83bSHermès Bélusca-Maïto return DoesFileExist(NULL, FullName);
7476f19c83bSHermès Bélusca-Maïto }
7486f19c83bSHermès Bélusca-Maïto
7496f19c83bSHermès Bélusca-Maïto /*
7506f19c83bSHermès Bélusca-Maïto * The format of NtPath should be:
7516f19c83bSHermès Bélusca-Maïto * \Device\HarddiskXXX\PartitionYYY[\path] ,
7526f19c83bSHermès Bélusca-Maïto * where XXX and YYY respectively represent the hard disk and partition numbers,
7536f19c83bSHermès Bélusca-Maïto * and [\path] represent an optional path (separated by '\\').
7546f19c83bSHermès Bélusca-Maïto *
7556f19c83bSHermès Bélusca-Maïto * If a NT path of such a form is correctly parsed, the function returns respectively:
7566f19c83bSHermès Bélusca-Maïto * - in pDiskNumber: the hard disk number XXX,
7576f19c83bSHermès Bélusca-Maïto * - in pPartNumber: the partition number YYY,
7586f19c83bSHermès Bélusca-Maïto * - in PathComponent: pointer value (inside NtPath) to the beginning of \path.
7596f19c83bSHermès Bélusca-Maïto *
7606f19c83bSHermès Bélusca-Maïto * NOTE: The function does not accept leading whitespace.
7616f19c83bSHermès Bélusca-Maïto */
7626f19c83bSHermès Bélusca-Maïto BOOLEAN
NtPathToDiskPartComponents(IN PCWSTR NtPath,OUT PULONG pDiskNumber,OUT PULONG pPartNumber,OUT PCWSTR * PathComponent OPTIONAL)7636f19c83bSHermès Bélusca-Maïto NtPathToDiskPartComponents(
7646f19c83bSHermès Bélusca-Maïto IN PCWSTR NtPath,
7656f19c83bSHermès Bélusca-Maïto OUT PULONG pDiskNumber,
7666f19c83bSHermès Bélusca-Maïto OUT PULONG pPartNumber,
7676f19c83bSHermès Bélusca-Maïto OUT PCWSTR* PathComponent OPTIONAL)
7686f19c83bSHermès Bélusca-Maïto {
7696f19c83bSHermès Bélusca-Maïto ULONG DiskNumber, PartNumber;
7706f19c83bSHermès Bélusca-Maïto PCWSTR Path;
7716f19c83bSHermès Bélusca-Maïto
7726f19c83bSHermès Bélusca-Maïto *pDiskNumber = 0;
7736f19c83bSHermès Bélusca-Maïto *pPartNumber = 0;
7746f19c83bSHermès Bélusca-Maïto if (PathComponent) *PathComponent = NULL;
7756f19c83bSHermès Bélusca-Maïto
7766f19c83bSHermès Bélusca-Maïto Path = NtPath;
7776f19c83bSHermès Bélusca-Maïto
7786f19c83bSHermès Bélusca-Maïto if (_wcsnicmp(Path, L"\\Device\\Harddisk", 16) != 0)
7796f19c83bSHermès Bélusca-Maïto {
7806f19c83bSHermès Bélusca-Maïto /* The NT path doesn't start with the prefix string, thus it cannot be a hard disk device path */
7816f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : Not a possible hard disk device.\n", NtPath);
7826f19c83bSHermès Bélusca-Maïto return FALSE;
7836f19c83bSHermès Bélusca-Maïto }
7846f19c83bSHermès Bélusca-Maïto
7856f19c83bSHermès Bélusca-Maïto Path += 16;
7866f19c83bSHermès Bélusca-Maïto
7876f19c83bSHermès Bélusca-Maïto /* A number must be present now */
7886f19c83bSHermès Bélusca-Maïto if (!iswdigit(*Path))
7896f19c83bSHermès Bélusca-Maïto {
7906f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : expected a number! Not a regular hard disk device.\n", Path);
7916f19c83bSHermès Bélusca-Maïto return FALSE;
7926f19c83bSHermès Bélusca-Maïto }
7936f19c83bSHermès Bélusca-Maïto DiskNumber = wcstoul(Path, (PWSTR*)&Path, 10);
7946f19c83bSHermès Bélusca-Maïto
7956f19c83bSHermès Bélusca-Maïto /* Either NULL termination, or a path separator must be present now */
7966f19c83bSHermès Bélusca-Maïto if (*Path && *Path != OBJ_NAME_PATH_SEPARATOR)
7976f19c83bSHermès Bélusca-Maïto {
7986f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : expected a path separator!\n", Path);
7996f19c83bSHermès Bélusca-Maïto return FALSE;
8006f19c83bSHermès Bélusca-Maïto }
8016f19c83bSHermès Bélusca-Maïto
8026f19c83bSHermès Bélusca-Maïto if (!*Path)
8036f19c83bSHermès Bélusca-Maïto {
8046f19c83bSHermès Bélusca-Maïto DPRINT1("The path only specified a hard disk (and nothing else, like a partition...), so we stop there.\n");
8056f19c83bSHermès Bélusca-Maïto goto Quit;
8066f19c83bSHermès Bélusca-Maïto }
8076f19c83bSHermès Bélusca-Maïto
8086f19c83bSHermès Bélusca-Maïto /* Here, *Path == L'\\' */
8096f19c83bSHermès Bélusca-Maïto
8106f19c83bSHermès Bélusca-Maïto if (_wcsnicmp(Path, L"\\Partition", 10) != 0)
8116f19c83bSHermès Bélusca-Maïto {
8126f19c83bSHermès Bélusca-Maïto /* Actually, \Partition is optional so, if we don't have it, we still return success. Or should we? */
8136f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : unexpected format!\n", NtPath);
8146f19c83bSHermès Bélusca-Maïto goto Quit;
8156f19c83bSHermès Bélusca-Maïto }
8166f19c83bSHermès Bélusca-Maïto
8176f19c83bSHermès Bélusca-Maïto Path += 10;
8186f19c83bSHermès Bélusca-Maïto
8196f19c83bSHermès Bélusca-Maïto /* A number must be present now */
8206f19c83bSHermès Bélusca-Maïto if (!iswdigit(*Path))
8216f19c83bSHermès Bélusca-Maïto {
8226f19c83bSHermès Bélusca-Maïto /* 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? */
8236f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : expected a number!\n", Path);
8246f19c83bSHermès Bélusca-Maïto goto Quit;
8256f19c83bSHermès Bélusca-Maïto }
8266f19c83bSHermès Bélusca-Maïto PartNumber = wcstoul(Path, (PWSTR*)&Path, 10);
8276f19c83bSHermès Bélusca-Maïto
8286f19c83bSHermès Bélusca-Maïto /* Either NULL termination, or a path separator must be present now */
8296f19c83bSHermès Bélusca-Maïto if (*Path && *Path != OBJ_NAME_PATH_SEPARATOR)
8306f19c83bSHermès Bélusca-Maïto {
8316f19c83bSHermès Bélusca-Maïto /* We shouldn't fail here because it just means this part of path is actually not a partition specifier. Or should we? */
8326f19c83bSHermès Bélusca-Maïto DPRINT1("'%S' : expected a path separator!\n", Path);
8336f19c83bSHermès Bélusca-Maïto goto Quit;
8346f19c83bSHermès Bélusca-Maïto }
8356f19c83bSHermès Bélusca-Maïto
8366f19c83bSHermès Bélusca-Maïto /* OK, here we really have a partition specifier: return its number */
8376f19c83bSHermès Bélusca-Maïto *pPartNumber = PartNumber;
8386f19c83bSHermès Bélusca-Maïto
8396f19c83bSHermès Bélusca-Maïto Quit:
8406f19c83bSHermès Bélusca-Maïto /* Return the disk number */
8416f19c83bSHermès Bélusca-Maïto *pDiskNumber = DiskNumber;
8426f19c83bSHermès Bélusca-Maïto
8436f19c83bSHermès Bélusca-Maïto /* Return the path component also, if the user wants it */
8446f19c83bSHermès Bélusca-Maïto if (PathComponent) *PathComponent = Path;
8456f19c83bSHermès Bélusca-Maïto
8466f19c83bSHermès Bélusca-Maïto return TRUE;
8476f19c83bSHermès Bélusca-Maïto }
8486f19c83bSHermès Bélusca-Maïto
84968c2a289SHermès Bélusca-Maïto /**
85068c2a289SHermès Bélusca-Maïto * @brief
85168c2a289SHermès Bélusca-Maïto * Opens and maps a file in memory.
85268c2a289SHermès Bélusca-Maïto *
85368c2a289SHermès Bélusca-Maïto * @param[in] RootDirectory
85468c2a289SHermès Bélusca-Maïto * @param[in] PathNameToFile
85568c2a289SHermès Bélusca-Maïto * Path to the file, either in absolute form, or relative to the opened
85668c2a289SHermès Bélusca-Maïto * root directory given by the RootDirectory handle.
85768c2a289SHermès Bélusca-Maïto *
85868c2a289SHermès Bélusca-Maïto * @param[out] FileHandle
85968c2a289SHermès Bélusca-Maïto * An optional pointer to a variable receiving a handle to the opened file.
86068c2a289SHermès Bélusca-Maïto * If NULL, the underlying file handle is closed.
86168c2a289SHermès Bélusca-Maïto *
86268c2a289SHermès Bélusca-Maïto * @param[out] FileSize
86368c2a289SHermès Bélusca-Maïto * An optional pointer to a variable receiving the size of the opened file.
86468c2a289SHermès Bélusca-Maïto *
86568c2a289SHermès Bélusca-Maïto * @param[out] SectionHandle
86668c2a289SHermès Bélusca-Maïto * A pointer to a variable receiving a handle to a section mapping the file.
86768c2a289SHermès Bélusca-Maïto *
86868c2a289SHermès Bélusca-Maïto * @param[out] BaseAddress
86968c2a289SHermès Bélusca-Maïto * A pointer to a variable receiving the address where the file is mapped.
87068c2a289SHermès Bélusca-Maïto *
87168c2a289SHermès Bélusca-Maïto * @param[in] ReadWriteAccess
87268c2a289SHermès Bélusca-Maïto * A boolean variable specifying whether to map the file for read and write
87368c2a289SHermès Bélusca-Maïto * access (TRUE), or read-only access (FALSE).
87468c2a289SHermès Bélusca-Maïto *
87568c2a289SHermès Bélusca-Maïto * @return
87668c2a289SHermès Bélusca-Maïto * STATUS_SUCCESS in case of success, or a status code in case of error.
87768c2a289SHermès Bélusca-Maïto **/
8786f19c83bSHermès Bélusca-Maïto NTSTATUS
OpenAndMapFile(_In_opt_ HANDLE RootDirectory,_In_ PCWSTR PathNameToFile,_Out_opt_ PHANDLE FileHandle,_Out_opt_ PULONG FileSize,_Out_ PHANDLE SectionHandle,_Out_ PVOID * BaseAddress,_In_ BOOLEAN ReadWriteAccess)8796f19c83bSHermès Bélusca-Maïto OpenAndMapFile(
88068c2a289SHermès Bélusca-Maïto _In_opt_ HANDLE RootDirectory,
88168c2a289SHermès Bélusca-Maïto _In_ PCWSTR PathNameToFile,
88268c2a289SHermès Bélusca-Maïto _Out_opt_ PHANDLE FileHandle,
88368c2a289SHermès Bélusca-Maïto _Out_opt_ PULONG FileSize,
88468c2a289SHermès Bélusca-Maïto _Out_ PHANDLE SectionHandle,
88568c2a289SHermès Bélusca-Maïto _Out_ PVOID* BaseAddress,
88668c2a289SHermès Bélusca-Maïto _In_ BOOLEAN ReadWriteAccess)
8876f19c83bSHermès Bélusca-Maïto {
8886f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
8896f19c83bSHermès Bélusca-Maïto UNICODE_STRING FileName;
8906f19c83bSHermès Bélusca-Maïto OBJECT_ATTRIBUTES ObjectAttributes;
8916f19c83bSHermès Bélusca-Maïto IO_STATUS_BLOCK IoStatusBlock;
89268c2a289SHermès Bélusca-Maïto HANDLE LocalFileHandle;
8936f19c83bSHermès Bélusca-Maïto
8946f19c83bSHermès Bélusca-Maïto /* Open the file */
8956f19c83bSHermès Bélusca-Maïto RtlInitUnicodeString(&FileName, PathNameToFile);
8966f19c83bSHermès Bélusca-Maïto InitializeObjectAttributes(&ObjectAttributes,
8976f19c83bSHermès Bélusca-Maïto &FileName,
8986f19c83bSHermès Bélusca-Maïto OBJ_CASE_INSENSITIVE,
8996f19c83bSHermès Bélusca-Maïto RootDirectory,
9006f19c83bSHermès Bélusca-Maïto NULL);
9016f19c83bSHermès Bélusca-Maïto
90268c2a289SHermès Bélusca-Maïto if (FileHandle) *FileHandle = NULL;
90368c2a289SHermès Bélusca-Maïto Status = NtOpenFile(&LocalFileHandle,
9046f19c83bSHermès Bélusca-Maïto FILE_GENERIC_READ | // Contains SYNCHRONIZE
9056f19c83bSHermès Bélusca-Maïto (ReadWriteAccess ? FILE_GENERIC_WRITE : 0),
9066f19c83bSHermès Bélusca-Maïto &ObjectAttributes,
9076f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
9086f19c83bSHermès Bélusca-Maïto FILE_SHARE_READ,
9096f19c83bSHermès Bélusca-Maïto FILE_SYNCHRONOUS_IO_NONALERT | FILE_NON_DIRECTORY_FILE);
9106f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
9116f19c83bSHermès Bélusca-Maïto {
91268c2a289SHermès Bélusca-Maïto DPRINT1("Failed to open file '%wZ' (Status 0x%08lx)\n", &FileName, Status);
9136f19c83bSHermès Bélusca-Maïto return Status;
9146f19c83bSHermès Bélusca-Maïto }
9156f19c83bSHermès Bélusca-Maïto
9166f19c83bSHermès Bélusca-Maïto if (FileSize)
9176f19c83bSHermès Bélusca-Maïto {
9186f19c83bSHermès Bélusca-Maïto /* Query the file size */
9196f19c83bSHermès Bélusca-Maïto FILE_STANDARD_INFORMATION FileInfo;
92068c2a289SHermès Bélusca-Maïto Status = NtQueryInformationFile(LocalFileHandle,
9216f19c83bSHermès Bélusca-Maïto &IoStatusBlock,
9226f19c83bSHermès Bélusca-Maïto &FileInfo,
9236f19c83bSHermès Bélusca-Maïto sizeof(FileInfo),
9246f19c83bSHermès Bélusca-Maïto FileStandardInformation);
9256f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
9266f19c83bSHermès Bélusca-Maïto {
92768c2a289SHermès Bélusca-Maïto DPRINT("NtQueryInformationFile() failed (Status 0x%08lx)\n", Status);
92868c2a289SHermès Bélusca-Maïto goto Quit;
9296f19c83bSHermès Bélusca-Maïto }
9306f19c83bSHermès Bélusca-Maïto
9316f19c83bSHermès Bélusca-Maïto if (FileInfo.EndOfFile.HighPart != 0)
9326f19c83bSHermès Bélusca-Maïto DPRINT1("WARNING!! The file '%wZ' is too large!\n", &FileName);
9336f19c83bSHermès Bélusca-Maïto
9346f19c83bSHermès Bélusca-Maïto *FileSize = FileInfo.EndOfFile.LowPart;
9356f19c83bSHermès Bélusca-Maïto DPRINT("File size: %lu\n", *FileSize);
9366f19c83bSHermès Bélusca-Maïto }
9376f19c83bSHermès Bélusca-Maïto
93868c2a289SHermès Bélusca-Maïto /* Map the whole file into memory */
93968c2a289SHermès Bélusca-Maïto Status = MapFile(LocalFileHandle,
94068c2a289SHermès Bélusca-Maïto SectionHandle,
94168c2a289SHermès Bélusca-Maïto BaseAddress,
94268c2a289SHermès Bélusca-Maïto ReadWriteAccess);
94368c2a289SHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
94468c2a289SHermès Bélusca-Maïto {
94568c2a289SHermès Bélusca-Maïto DPRINT1("Failed to map file '%wZ' (Status 0x%08lx)\n", &FileName, Status);
94668c2a289SHermès Bélusca-Maïto goto Quit;
94768c2a289SHermès Bélusca-Maïto }
94868c2a289SHermès Bélusca-Maïto
94968c2a289SHermès Bélusca-Maïto Quit:
95068c2a289SHermès Bélusca-Maïto /* If we succeeded, return the opened file handle if needed.
95168c2a289SHermès Bélusca-Maïto * If we failed or the caller does not need the handle, close it now. */
95268c2a289SHermès Bélusca-Maïto if (NT_SUCCESS(Status) && FileHandle)
95368c2a289SHermès Bélusca-Maïto *FileHandle = LocalFileHandle;
95468c2a289SHermès Bélusca-Maïto else
95568c2a289SHermès Bélusca-Maïto NtClose(LocalFileHandle);
95668c2a289SHermès Bélusca-Maïto
95768c2a289SHermès Bélusca-Maïto return Status;
95868c2a289SHermès Bélusca-Maïto }
95968c2a289SHermès Bélusca-Maïto
96068c2a289SHermès Bélusca-Maïto /**
96168c2a289SHermès Bélusca-Maïto * @brief
96268c2a289SHermès Bélusca-Maïto * Maps an opened file in memory.
96368c2a289SHermès Bélusca-Maïto *
96468c2a289SHermès Bélusca-Maïto * @param[in] FileHandle
96568c2a289SHermès Bélusca-Maïto * A handle to an opened file to map.
96668c2a289SHermès Bélusca-Maïto *
96768c2a289SHermès Bélusca-Maïto * @param[out] SectionHandle
96868c2a289SHermès Bélusca-Maïto * A pointer to a variable receiving a handle to a section mapping the file.
96968c2a289SHermès Bélusca-Maïto *
97068c2a289SHermès Bélusca-Maïto * @param[out] BaseAddress
97168c2a289SHermès Bélusca-Maïto * A pointer to a variable receiving the address where the file is mapped.
97268c2a289SHermès Bélusca-Maïto *
97368c2a289SHermès Bélusca-Maïto * @param[in] ReadWriteAccess
97468c2a289SHermès Bélusca-Maïto * A boolean variable specifying whether to map the file for read and write
97568c2a289SHermès Bélusca-Maïto * access (TRUE), or read-only access (FALSE).
97668c2a289SHermès Bélusca-Maïto *
97768c2a289SHermès Bélusca-Maïto * @return
97868c2a289SHermès Bélusca-Maïto * STATUS_SUCCESS in case of success, or a status code in case of error.
97968c2a289SHermès Bélusca-Maïto **/
98068c2a289SHermès Bélusca-Maïto NTSTATUS
MapFile(_In_ HANDLE FileHandle,_Out_ PHANDLE SectionHandle,_Out_ PVOID * BaseAddress,_In_ BOOLEAN ReadWriteAccess)98168c2a289SHermès Bélusca-Maïto MapFile(
98268c2a289SHermès Bélusca-Maïto _In_ HANDLE FileHandle,
98368c2a289SHermès Bélusca-Maïto _Out_ PHANDLE SectionHandle,
98468c2a289SHermès Bélusca-Maïto _Out_ PVOID* BaseAddress,
98568c2a289SHermès Bélusca-Maïto _In_ BOOLEAN ReadWriteAccess)
98668c2a289SHermès Bélusca-Maïto {
98768c2a289SHermès Bélusca-Maïto NTSTATUS Status;
98868c2a289SHermès Bélusca-Maïto ULONG SectionPageProtection;
98968c2a289SHermès Bélusca-Maïto SIZE_T ViewSize;
99068c2a289SHermès Bélusca-Maïto PVOID ViewBase;
9916f19c83bSHermès Bélusca-Maïto
9926f19c83bSHermès Bélusca-Maïto SectionPageProtection = (ReadWriteAccess ? PAGE_READWRITE : PAGE_READONLY);
9936f19c83bSHermès Bélusca-Maïto
9946f19c83bSHermès Bélusca-Maïto /* Create the section */
99568c2a289SHermès Bélusca-Maïto *SectionHandle = NULL;
9966f19c83bSHermès Bélusca-Maïto Status = NtCreateSection(SectionHandle,
9976f19c83bSHermès Bélusca-Maïto STANDARD_RIGHTS_REQUIRED | SECTION_QUERY |
9986f19c83bSHermès Bélusca-Maïto SECTION_MAP_READ |
9996f19c83bSHermès Bélusca-Maïto (ReadWriteAccess ? SECTION_MAP_WRITE : 0),
10006f19c83bSHermès Bélusca-Maïto NULL,
10016f19c83bSHermès Bélusca-Maïto NULL,
10026f19c83bSHermès Bélusca-Maïto SectionPageProtection,
10036f19c83bSHermès Bélusca-Maïto SEC_COMMIT /* | SEC_IMAGE (_NO_EXECUTE) */,
100468c2a289SHermès Bélusca-Maïto FileHandle);
10056f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
10066f19c83bSHermès Bélusca-Maïto {
100768c2a289SHermès Bélusca-Maïto DPRINT1("Failed to create a memory section for file 0x%p (Status 0x%08lx)\n",
100868c2a289SHermès Bélusca-Maïto FileHandle, Status);
10096f19c83bSHermès Bélusca-Maïto return Status;
10106f19c83bSHermès Bélusca-Maïto }
10116f19c83bSHermès Bélusca-Maïto
10126f19c83bSHermès Bélusca-Maïto /* Map the section */
10136f19c83bSHermès Bélusca-Maïto ViewSize = 0;
10146f19c83bSHermès Bélusca-Maïto ViewBase = NULL;
10156f19c83bSHermès Bélusca-Maïto Status = NtMapViewOfSection(*SectionHandle,
10166f19c83bSHermès Bélusca-Maïto NtCurrentProcess(),
10176f19c83bSHermès Bélusca-Maïto &ViewBase,
10186f19c83bSHermès Bélusca-Maïto 0, 0,
10196f19c83bSHermès Bélusca-Maïto NULL,
10206f19c83bSHermès Bélusca-Maïto &ViewSize,
10216f19c83bSHermès Bélusca-Maïto ViewShare,
10226f19c83bSHermès Bélusca-Maïto 0,
10236f19c83bSHermès Bélusca-Maïto SectionPageProtection);
10246f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
10256f19c83bSHermès Bélusca-Maïto {
102668c2a289SHermès Bélusca-Maïto DPRINT1("Failed to map a view for file 0x%p (Status 0x%08lx)\n",
102768c2a289SHermès Bélusca-Maïto FileHandle, Status);
10286f19c83bSHermès Bélusca-Maïto NtClose(*SectionHandle);
10296f19c83bSHermès Bélusca-Maïto *SectionHandle = NULL;
10306f19c83bSHermès Bélusca-Maïto return Status;
10316f19c83bSHermès Bélusca-Maïto }
10326f19c83bSHermès Bélusca-Maïto
10336f19c83bSHermès Bélusca-Maïto *BaseAddress = ViewBase;
10346f19c83bSHermès Bélusca-Maïto return STATUS_SUCCESS;
10356f19c83bSHermès Bélusca-Maïto }
10366f19c83bSHermès Bélusca-Maïto
103768c2a289SHermès Bélusca-Maïto /**
103868c2a289SHermès Bélusca-Maïto * @brief
103968c2a289SHermès Bélusca-Maïto * Unmaps a mapped file by section.
104068c2a289SHermès Bélusca-Maïto *
104168c2a289SHermès Bélusca-Maïto * @param[in] SectionHandle
104268c2a289SHermès Bélusca-Maïto * The handle to the section mapping the file.
104368c2a289SHermès Bélusca-Maïto *
104468c2a289SHermès Bélusca-Maïto * @param[in] BaseAddress
104568c2a289SHermès Bélusca-Maïto * The base address where the file is mapped.
104668c2a289SHermès Bélusca-Maïto *
104768c2a289SHermès Bélusca-Maïto * @return
104868c2a289SHermès Bélusca-Maïto * TRUE if the file was successfully unmapped; FALSE if an error occurred.
104968c2a289SHermès Bélusca-Maïto **/
10506f19c83bSHermès Bélusca-Maïto BOOLEAN
UnMapFile(_In_ HANDLE SectionHandle,_In_ PVOID BaseAddress)10516f19c83bSHermès Bélusca-Maïto UnMapFile(
105268c2a289SHermès Bélusca-Maïto _In_ HANDLE SectionHandle,
105368c2a289SHermès Bélusca-Maïto _In_ PVOID BaseAddress)
10546f19c83bSHermès Bélusca-Maïto {
10556f19c83bSHermès Bélusca-Maïto NTSTATUS Status;
10566f19c83bSHermès Bélusca-Maïto BOOLEAN Success = TRUE;
10576f19c83bSHermès Bélusca-Maïto
10586f19c83bSHermès Bélusca-Maïto Status = NtUnmapViewOfSection(NtCurrentProcess(), BaseAddress);
10596f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
10606f19c83bSHermès Bélusca-Maïto {
106168c2a289SHermès Bélusca-Maïto DPRINT1("NtUnmapViewOfSection(0x%p) failed (Status 0x%08lx)\n",
10626f19c83bSHermès Bélusca-Maïto BaseAddress, Status);
10636f19c83bSHermès Bélusca-Maïto Success = FALSE;
10646f19c83bSHermès Bélusca-Maïto }
10656f19c83bSHermès Bélusca-Maïto Status = NtClose(SectionHandle);
10666f19c83bSHermès Bélusca-Maïto if (!NT_SUCCESS(Status))
10676f19c83bSHermès Bélusca-Maïto {
106868c2a289SHermès Bélusca-Maïto DPRINT1("NtClose(0x%p) failed (Status 0x%08lx)\n",
10696f19c83bSHermès Bélusca-Maïto SectionHandle, Status);
10706f19c83bSHermès Bélusca-Maïto Success = FALSE;
10716f19c83bSHermès Bélusca-Maïto }
10726f19c83bSHermès Bélusca-Maïto
10736f19c83bSHermès Bélusca-Maïto return Success;
10746f19c83bSHermès Bélusca-Maïto }
10756f19c83bSHermès Bélusca-Maïto
10766f19c83bSHermès Bélusca-Maïto /* EOF */
1077