https://git.reactos.org/?p=reactos.git;a=commitdiff;h=ea5728b5f3238038e31654eddea44b393d267c30

commit ea5728b5f3238038e31654eddea44b393d267c30
Author:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
AuthorDate: Wed Aug 7 22:31:01 2024 +0200
Commit:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
CommitDate: Thu Aug 22 20:40:35 2024 +0200

    [SETUPLIB] SetupCreateDirectory(): Don't assume the form of the directory 
prefix (#7257)
    
    Addendum to commit 32e6eed760 (r63715)
    CORE-5982
    
    The function assumed that the directory path name to be created
    always starts with a harddisk-partition root device name of the form:
    
      \Device\HarddiskX\PartitionY\
    
    Indeed, it can be (when using the volume manager) of the form:
    
      \Device\HarddiskVolumeN\
    
    and could even have a different format if trying to install ReactOS
    on an external removable drive or other weird device.
    
    Since the format of this prefix is not 100% always the same,
    a different way to create the sub-directories is needed.
    The nested-directory creation algorithm is changed as follows:
    
    Suppose that the directory to be created is:
    
      \Device\HarddiskVolume1\ReactOS\system32\drivers
    
    The function first loops backwards each path component in order
    to find the deepest existing sub-directory: it will try to verify
    whether each of the following sub-directories exist, successively:
    
      \Device\HarddiskVolume1\ReactOS\system32\drivers
      \Device\HarddiskVolume1\ReactOS\system32\
      \Device\HarddiskVolume1\ReactOS\
      \Device\HarddiskVolume1\
    
    (Notice the trailing path separators kept in this step.)
    In principle, this root device FS directory must exist (since the
    volume has been formatted previously). Once found, the function will
    then create each of the sub-directories in turn:
    
      \Device\HarddiskVolume1\ReactOS
      \Device\HarddiskVolume1\ReactOS\system32
      \Device\HarddiskVolume1\ReactOS\system32\drivers
    
    ----
    
    An alternative to the fix could be to always specify the root device
    name in a separate parameter, but this hasn't been pursued here so as
    to not modify all the callers of this function.
---
 base/setup/lib/utils/filesup.c | 149 +++++++++++++++++++++--------------------
 base/setup/lib/utils/filesup.h |  14 ++--
 2 files changed, 88 insertions(+), 75 deletions(-)

diff --git a/base/setup/lib/utils/filesup.c b/base/setup/lib/utils/filesup.c
index 5ddd641be34..81da91faa12 100644
--- a/base/setup/lib/utils/filesup.c
+++ b/base/setup/lib/utils/filesup.c
@@ -27,27 +27,24 @@
 static
 NTSTATUS
 SetupCreateSingleDirectory(
-    IN PCWSTR DirectoryName)
+    _In_ PCUNICODE_STRING DirectoryName)
 {
+    NTSTATUS Status;
+    UNICODE_STRING PathName = *DirectoryName;
     OBJECT_ATTRIBUTES ObjectAttributes;
     IO_STATUS_BLOCK IoStatusBlock;
-    UNICODE_STRING PathName;
     HANDLE DirectoryHandle;
-    NTSTATUS Status;
-
-    if (!RtlCreateUnicodeString(&PathName, DirectoryName))
-        return STATUS_NO_MEMORY;
 
-    if (PathName.Length > sizeof(WCHAR) &&
-        PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'\\')
+    /* Remove the trailing separator if needed */
+    if (PathName.Length >= 2 * sizeof(WCHAR) &&
+        PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == 
OBJ_NAME_PATH_SEPARATOR)
     {
         PathName.Length -= sizeof(WCHAR);
-        PathName.Buffer[PathName.Length / sizeof(WCHAR)] = UNICODE_NULL;
     }
 
     InitializeObjectAttributes(&ObjectAttributes,
                                &PathName,
-                               OBJ_CASE_INSENSITIVE | OBJ_INHERIT,
+                               OBJ_CASE_INSENSITIVE,
                                NULL,
                                NULL);
 
@@ -63,79 +60,80 @@ SetupCreateSingleDirectory(
                           NULL,
                           0);
     if (NT_SUCCESS(Status))
-    {
         NtClose(DirectoryHandle);
-    }
-
-    RtlFreeUnicodeString(&PathName);
 
     return Status;
 }
 
+/**
+ * @brief
+ * Create a new directory, specified by the given path.
+ * Any intermediate non-existing directory is created as well.
+ *
+ * @param[in]   PathName
+ * The path of the directory to be created.
+ *
+ * @return  An NTSTATUS code indicating success or failure.
+ **/
 NTSTATUS
 SetupCreateDirectory(
-    IN PCWSTR PathName)
+    _In_ PCWSTR PathName)
 {
     NTSTATUS Status = STATUS_SUCCESS;
-    PWCHAR PathBuffer = NULL;
-    PWCHAR Ptr, EndPtr;
-    ULONG BackslashCount;
-    ULONG Size;
-
-    Size = (wcslen(PathName) + 1) * sizeof(WCHAR);
-    PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Size);
-    if (PathBuffer == NULL)
-        return STATUS_INSUFFICIENT_RESOURCES;
+    UNICODE_STRING PathNameU;
+    PCWSTR Buffer;
+    PCWCH Ptr, End;
 
-    wcscpy(PathBuffer, PathName);
-    EndPtr = PathBuffer + wcslen(PathName);
+    RtlInitUnicodeString(&PathNameU, PathName);
+    Buffer = PathNameU.Buffer;
+    End = Buffer + (PathNameU.Length / sizeof(WCHAR));
 
-    Ptr = PathBuffer;
-
-    /* Skip the '\Device\HarddiskX\PartitionY\ part */
-    BackslashCount = 0;
-    while (Ptr < EndPtr && BackslashCount < 4)
+    /* Find the deepest existing sub-directory: start from the
+     * end and go back, verifying each sub-directory in turn */
+    for (Ptr = End; Ptr > Buffer;)
     {
-        if (*Ptr == L'\\')
-            BackslashCount++;
-
-        Ptr++;
+        BOOLEAN bExists;
+
+        /* If we are on a separator, truncate at the next character.
+         * The trailing separator is kept for the existence check. */
+        if ((Ptr < End) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
+            PathNameU.Length = (ULONG_PTR)(Ptr+1) - (ULONG_PTR)Buffer;
+
+        /* Check if the sub-directory exists and stop
+         * if so: this is the deepest existing one */
+        DPRINT("PathName: %wZ\n", &PathNameU);
+        bExists = DoesPathExist_UStr(NULL, &PathNameU, TRUE);
+        if (bExists)
+            break;
+
+        /* Skip back any consecutive path separators */
+        while ((Ptr > Buffer) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
+            --Ptr;
+        /* Go to the beginning of the path component, stop at the separator */
+        while ((Ptr > Buffer) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
+            --Ptr;
     }
 
-    while (Ptr < EndPtr)
-    {
-        if (*Ptr == L'\\')
-        {
-            *Ptr = 0;
-
-            DPRINT("PathBuffer: %S\n", PathBuffer);
-            if (!DoesDirExist(NULL, PathBuffer))
-            {
-                DPRINT("Create: %S\n", PathBuffer);
-                Status = SetupCreateSingleDirectory(PathBuffer);
-                if (!NT_SUCCESS(Status))
-                    goto done;
-            }
-
-            *Ptr = L'\\';
-        }
+    /* Skip any consecutive path separators */
+    while ((Ptr < End) && (*Ptr == OBJ_NAME_PATH_SEPARATOR))
+        ++Ptr;
 
-        Ptr++;
-    }
-
-    if (!DoesDirExist(NULL, PathBuffer))
+    /* Create all the remaining sub-directories */
+    for (; Ptr < End; ++Ptr)
     {
-        DPRINT("Create: %S\n", PathBuffer);
-        Status = SetupCreateSingleDirectory(PathBuffer);
+        /* Go to the end of the current path component, stop at
+         * the separator or terminating NUL and truncate it */
+        while ((Ptr < End) && (*Ptr != OBJ_NAME_PATH_SEPARATOR))
+            ++Ptr;
+        PathNameU.Length = (ULONG_PTR)Ptr - (ULONG_PTR)Buffer;
+
+        DPRINT("Create: %wZ\n", &PathNameU);
+        Status = SetupCreateSingleDirectory(&PathNameU);
         if (!NT_SUCCESS(Status))
-            goto done;
+            break;
     }
 
-done:
     DPRINT("Done.\n");
-    if (PathBuffer != NULL)
-        RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer);
-
     return Status;
 }
 
@@ -694,20 +692,18 @@ CombinePaths(
 }
 
 BOOLEAN
-DoesPathExist(
-    IN HANDLE RootDirectory OPTIONAL,
-    IN PCWSTR PathName,
-    IN BOOLEAN IsDirectory)
+DoesPathExist_UStr(
+    _In_opt_ HANDLE RootDirectory,
+    _In_ PCUNICODE_STRING PathName,
+    _In_ BOOLEAN IsDirectory)
 {
     NTSTATUS Status;
-    UNICODE_STRING Name;
     HANDLE FileHandle;
     OBJECT_ATTRIBUTES ObjectAttributes;
     IO_STATUS_BLOCK IoStatusBlock;
 
-    RtlInitUnicodeString(&Name, PathName);
     InitializeObjectAttributes(&ObjectAttributes,
-                               &Name,
+                               (PUNICODE_STRING)PathName,
                                OBJ_CASE_INSENSITIVE,
                                RootDirectory,
                                NULL);
@@ -729,12 +725,23 @@ DoesPathExist(
     {
         DPRINT("Failed to open %s '%wZ', Status 0x%08lx\n",
                IsDirectory ? "directory" : "file",
-               &Name, Status);
+               PathName, Status);
     }
 
     return NT_SUCCESS(Status);
 }
 
+BOOLEAN
+DoesPathExist(
+    _In_opt_ HANDLE RootDirectory,
+    _In_ PCWSTR PathName,
+    _In_ BOOLEAN IsDirectory)
+{
+    UNICODE_STRING PathNameU;
+    RtlInitUnicodeString(&PathNameU, PathName);
+    return DoesPathExist_UStr(RootDirectory, &PathNameU, IsDirectory);
+}
+
 // FIXME: DEPRECATED! HACKish function that needs to be deprecated!
 BOOLEAN
 DoesFileExist_2(
diff --git a/base/setup/lib/utils/filesup.h b/base/setup/lib/utils/filesup.h
index 2962819b53f..03de9235c0f 100644
--- a/base/setup/lib/utils/filesup.h
+++ b/base/setup/lib/utils/filesup.h
@@ -10,7 +10,7 @@
 
 NTSTATUS
 SetupCreateDirectory(
-    IN PCWSTR DirectoryName);
+    _In_ PCWSTR PathName);
 
 NTSTATUS
 SetupDeleteFile(
@@ -65,11 +65,17 @@ CombinePaths(
     IN ULONG NumberOfPathComponents,
     IN /* PCWSTR */ ...);
 
+BOOLEAN
+DoesPathExist_UStr(
+    _In_opt_ HANDLE RootDirectory,
+    _In_ PCUNICODE_STRING PathName,
+    _In_ BOOLEAN IsDirectory);
+
 BOOLEAN
 DoesPathExist(
-    IN HANDLE RootDirectory OPTIONAL,
-    IN PCWSTR PathName,
-    IN BOOLEAN IsDirectory);
+    _In_opt_ HANDLE RootDirectory,
+    _In_ PCWSTR PathName,
+    _In_ BOOLEAN IsDirectory);
 
 #define DoesDirExist(RootDirectory, DirName)    \
     DoesPathExist((RootDirectory), (DirName), TRUE)

Reply via email to