xref: /reactos/base/setup/lib/utils/filesup.c (revision 31334ebc)
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