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

commit 71197535a1031eb137700d9ba0821210edeb51be
Author:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
AuthorDate: Thu Jul 25 18:57:23 2024 +0200
Commit:     Hermès Bélusca-Maïto <hermes.belusca-ma...@reactos.org>
CommitDate: Wed Jul 31 11:41:24 2024 +0200

    [SETUPLIB][USETUP] Improve IsValidInstallDirectory() behaviour (#7187)
    
    CORE-6149, CORE-6179, CORE-9529
    
    See also commits d329fbebf (r66995), 7c3f4c94a (r68307), and 16daf6700.
    
    The function verifies that each path component of the directory is
    a valid 8.3 name, not . or .. nor empty. This behaviour is compatible
    with what can be observed from Windows XP/2003 installer.
    (To reliably test this with the Windows installer, you need to modify
    the TXTSETUP.SIF DefaultPath value in the [SetupData] section.)
---
 base/setup/lib/setuplib.c | 100 ++++++++++++++++++++++++++++++++++------------
 1 file changed, 74 insertions(+), 26 deletions(-)

diff --git a/base/setup/lib/setuplib.c b/base/setup/lib/setuplib.c
index 22ec4afc3fe..9fb91b24f80 100644
--- a/base/setup/lib/setuplib.c
+++ b/base/setup/lib/setuplib.c
@@ -712,51 +712,99 @@ InitSystemPartition(
     return TRUE;
 }
 
+
+#define IS_PATH_SEPARATOR(c)    ((c) == L'\\' || (c) == L'/')
+
+/**
+ * @brief
+ * Verify whether the given directory is suitable for ReactOS installation.
+ * Each path component must be a valid 8.3 name.
+ **/
 BOOLEAN
 IsValidInstallDirectory(
     _In_ PCWSTR InstallDir)
 {
-    UINT i, Length;
+    PCWCH p;
+
+    /* As with the NT installer, fail if the path is empty or "\\" */
+    p = InstallDir;
+    if (!*p || (IS_PATH_SEPARATOR(*p) && !*(p + 1)))
+        return FALSE;
 
-    Length = wcslen(InstallDir);
+    /* The path must contain only valid characters (alpha-numeric,
+     * '.', '\\', '-' and '_'). Spaces are not accepted. */
+    for (p = InstallDir; *p; ++p)
+    {
+        if (!IS_VALID_INSTALL_PATH_CHAR(*p))
+            return FALSE;
+    }
 
-    // TODO: Add check for 8.3 too.
+    /*
+     * Loop over each path component and verify that each is a valid 8.3 name.
+     */
+    for (p = InstallDir; *p;)
+    {
+        PCWSTR Path;
+        SIZE_T Length;
+        UNICODE_STRING Name;
+        BOOLEAN IsNameLegal, SpacesInName;
+
+        /* Skip any first separator */
+        if (IS_PATH_SEPARATOR(*p))
+            ++p;
+
+        /* Now skip past the path component until we reach the next separator 
*/
+        Path = p;
+        while (*p && !IS_PATH_SEPARATOR(*p))
+            ++p;
+        if (p == Path)
+        {
+            /* Succeed if nothing else follows this separator; otherwise
+             * it's a separator and consecutive ones are not supported */
+            return (!*p);
+        }
 
-    /* Path must be at least 2 characters long */
-//    if (Length < 2)
-//        return FALSE;
+        /* Calculate the path component length */
+        Length = p - Path;
 
-    /* Path must start with a backslash */
-//    if (InstallDir[0] != L'\\')
-//        return FALSE;
+        /* As with the NT installer, fail for '.' and '..';
+         * RtlIsNameLegalDOS8Dot3() would succeed otherwise */
+        if ((Length == 1 && *Path == '.') || (Length == 2 && *Path == '.' && 
*(Path + 1) == '.'))
+            return FALSE;
 
-    /* Path must not end with a backslash */
-    if (InstallDir[Length - 1] == L'\\')
-        return FALSE;
+        /* As with the NT installer, allow _only ONE trailing_ dot in
+         * the path component (but not 2 or more), by reducing Length
+         * in that case; RtlIsNameLegalDOS8Dot3() would fail otherwise */
+        if (Length > 1 && *(p - 2) != L'.' && *(p - 1) == L'.')
+            --Length;
 
-    /* Path must not contain whitespace characters */
-    for (i = 0; i < Length; i++)
-    {
-        if (iswspace(InstallDir[i]))
+        if (Length == 0)
             return FALSE;
-    }
 
-    /* Path component must not end with a dot */
-    for (i = 0; i < Length; i++)
-    {
-        if (InstallDir[i] == L'\\' && i > 0)
+        /* Verify that the path component is a valid 8.3 name */
+        // if (Length > 8+1+3)
+        //     return FALSE;
+        Name.Length = Name.MaximumLength = (USHORT)(Length * sizeof(WCHAR));
+        Name.Buffer = (PWCHAR)Path;
+        SpacesInName = FALSE;
+        IsNameLegal = RtlIsNameLegalDOS8Dot3(&Name, NULL, &SpacesInName);
+
+        /* If it isn't legal or contain spaces, fail */
+        if (!IsNameLegal || SpacesInName)
         {
-            if (InstallDir[i - 1] == L'.')
-                return FALSE;
+            DPRINT("'%wZ' is %s 8.3 filename %s spaces\n",
+                   &Name,
+                   (IsNameLegal ? "a valid" : "an invalid"),
+                   (SpacesInName ? "with" : "without"));
+            return FALSE;
         }
+        /* Go to the next path component */
     }
 
-    if (InstallDir[Length - 1] == L'.')
-        return FALSE;
-
     return TRUE;
 }
 
+
 NTSTATUS
 InitDestinationPaths(
     IN OUT PUSETUP_DATA pSetupData,

Reply via email to