[SETUPLIB] Fixes and improvements for the file copying code.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Sun, 7 Jan 2018 00:35:48 +0000 (01:35 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 5 Nov 2018 22:35:14 +0000 (23:35 +0100)
- In PrepareCopyInfFile(), explicitly use AddSectionToCopyQueueCab()
  to retrieve the files from the CAB INF.

  Otherwise if one continued to use and rely on AddSectionToCopyQueue()
  to do this job instead, bad things could happen like, re-enumerating
  twice or more (and adding them to the file queue) the same files.
  This is because in the new code AddSectionToCopyQueue() can be called
  many times to deal with different SIF file sections. The old code then
  called AddSectionToCopyQueueCab() in turn, but on the same list...
  Now the steps performed are clear, and everything works as intended.

- Simplify the code that computes the full source and destination paths
  for the files to be copied and directories to be created, using helper
  functions.

- Compute the source file and target location from the TXTSETUP.SIF
  entries in a NT-compatible manner.

base/setup/lib/install.c

index 31ece47..f2875d0 100644 (file)
 
 /* FUNCTIONS ****************************************************************/
 
+static BOOL
+LookupDirectoryById(
+    IN HINF InfHandle,
+    IN OUT PINFCONTEXT InfContext,
+    IN PCWSTR DirId,
+    OUT PCWSTR* pDirectory)
+{
+    BOOL Success;
+
+    // ReactOS-specific
+    Success = SpInfFindFirstLine(InfHandle, L"Directories", DirId, InfContext);
+    if (!Success)
+    {
+        // Windows-compatible
+        Success = SpInfFindFirstLine(InfHandle, L"WinntDirectories", DirId, InfContext);
+        if (!Success)
+            DPRINT1("SpInfFindFirstLine() failed\n");
+    }
+    if (Success)
+    {
+        Success = INF_GetData(InfContext, NULL, pDirectory);
+        if (!Success)
+            DPRINT1("INF_GetData() failed\n");
+    }
+
+    if (!Success)
+        DPRINT1("LookupDirectoryById(%S) - directory not found!\n", DirId);
+
+    return Success;
+}
+
+/*
+ * Note: Modeled after SetupGetSourceFileLocation(), SetupGetSourceInfo()
+ * and SetupGetTargetPath() APIs.
+ * Technically the target path is the same for a given file section,
+ * but here we try to remove this constraint.
+ *
+ * TXTSETUP.SIF entries syntax explained at:
+ * http://www.msfn.org/board/topic/125480-txtsetupsif-syntax/
+ */
+static NTSTATUS
+GetSourceFileAndTargetLocation(
+    IN HINF InfHandle,
+    IN PINFCONTEXT InfContext OPTIONAL,
+    IN PCWSTR SourceFileName OPTIONAL,
+    OUT PCWSTR* pSourceRootPath,
+    OUT PCWSTR* pSourcePath,
+    OUT PCWSTR* pTargetDirectory,
+    OUT PCWSTR* pTargetFileName)
+{
+    BOOL Success;
+    INFCONTEXT FileContext;
+    INFCONTEXT DirContext;
+    PCWSTR SourceRootDirId;
+    PCWSTR SourceRootDir;
+    PCWSTR SourceRelativePath;
+    PCWSTR TargetDirId;
+    PCWSTR TargetDir;
+    PCWSTR TargetFileName;
+
+    /* Either InfContext or SourceFileName must be specified */
+    if (!InfContext && !SourceFileName)
+        return STATUS_INVALID_PARAMETER;
+
+    /* InfContext to a file was not given, retrieve one corresponding to SourceFileName */
+    if (!InfContext)
+    {
+        /* Search for the SourceDisksFiles section */
+
+        /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
+        Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles." INF_ARCH, SourceFileName, &FileContext);
+        if (!Success)
+        {
+            /* Search in the global section */
+            Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles", SourceFileName, &FileContext);
+        }
+        if (!Success)
+        {
+            // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+            // if (pSetupData->ErrorRoutine)
+                // pSetupData->ErrorRoutine(pSetupData, SectionName);
+            return STATUS_NOT_FOUND;
+        }
+        InfContext = &FileContext;
+    }
+    // else, InfContext != NULL and ignore SourceFileName (that may or may not be == NULL).
+
+    /*
+     * Getting Source File Location -- SetupGetSourceFileLocation()
+     */
+
+    /* Get source root directory id */
+    if (!INF_GetDataField(InfContext, 1, &SourceRootDirId))
+    {
+        /* FIXME: Handle error! */
+        DPRINT1("INF_GetData() failed\n");
+        return STATUS_NOT_FOUND;
+    }
+
+    /* Lookup source root directory -- SetupGetSourceInfo() */
+    /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
+    Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames." INF_ARCH, SourceRootDirId, &DirContext);
+    if (!Success)
+    {
+        /* Search in the global section */
+        Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames", SourceRootDirId, &DirContext);
+        if (!Success)
+            DPRINT1("SpInfFindFirstLine(\"SourceDisksNames\", \"%S\") failed\n", SourceRootDirId);
+    }
+    INF_FreeData(SourceRootDirId);
+    if (!Success)
+    {
+        /* FIXME: Handle error! */
+        // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+        // if (pSetupData->ErrorRoutine)
+            // pSetupData->ErrorRoutine(pSetupData, SectionName);
+        return STATUS_NOT_FOUND;
+    }
+    if (!INF_GetDataField(&DirContext, 4, &SourceRootDir))
+    {
+        /* FIXME: Handle error! */
+        DPRINT1("INF_GetData() failed\n");
+        return STATUS_NOT_FOUND;
+    }
+
+    /* Get optional source relative directory */
+    if (!INF_GetDataField(InfContext, 2, &SourceRelativePath))
+    {
+        SourceRelativePath = NULL;
+    }
+    else if (!*SourceRelativePath)
+    {
+        INF_FreeData(SourceRelativePath);
+        SourceRelativePath = NULL;
+    }
+    if (!SourceRelativePath)
+    {
+        /* Use WinPE directory instead */
+        if (INF_GetDataField(InfContext, 13, &TargetDirId))
+        {
+            /* Lookup directory */
+            Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &SourceRelativePath);
+            INF_FreeData(TargetDirId);
+            if (!Success)
+            {
+                SourceRelativePath = NULL;
+            }
+            else if (!*SourceRelativePath)
+            {
+                INF_FreeData(SourceRelativePath);
+                SourceRelativePath = NULL;
+            }
+        }
+    }
+
+    /*
+     * Getting Target File Location -- SetupGetTargetPath()
+     */
+
+    /* Get target directory id */
+    if (!INF_GetDataField(InfContext, 8, &TargetDirId))
+    {
+        /* FIXME: Handle error! */
+        DPRINT1("INF_GetData() failed\n");
+        INF_FreeData(SourceRelativePath);
+        INF_FreeData(SourceRootDir);
+        return STATUS_NOT_FOUND;
+    }
+
+    /* Lookup target directory */
+    Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &TargetDir);
+    INF_FreeData(TargetDirId);
+    if (!Success)
+    {
+        /* FIXME: Handle error! */
+        INF_FreeData(SourceRelativePath);
+        INF_FreeData(SourceRootDir);
+        return STATUS_NOT_FOUND;
+    }
+
+    /* Get optional target file name */
+    if (!INF_GetDataField(InfContext, 11, &TargetFileName))
+        TargetFileName = NULL;
+    else if (!*TargetFileName)
+        TargetFileName = NULL;
+
+    DPRINT("GetSourceFileAndTargetLocation(%S) = "
+           "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
+           SourceFileName, SourceRootDir, SourceRelativePath, TargetDir, TargetFileName);
+
+#if 0
+    INF_FreeData(TargetDir);
+    INF_FreeData(TargetFileName);
+    INF_FreeData(SourceRelativePath);
+    INF_FreeData(SourceRootDir);
+#endif
+
+    *pSourceRootPath  = SourceRootDir;
+    *pSourcePath      = SourceRelativePath;
+    *pTargetDirectory = TargetDir;
+    *pTargetFileName  = TargetFileName;
+
+    return STATUS_SUCCESS;
+}
+
+static NTSTATUS
+BuildFullDirectoryPath(
+    IN PCWSTR RootPath,
+    IN PCWSTR BasePath,
+    IN PCWSTR RelativePath,
+    OUT PWSTR FullPath,
+    IN SIZE_T cchFullPathSize)
+{
+    NTSTATUS Status;
+
+    if ((RelativePath[0] == UNICODE_NULL) || (RelativePath[0] == L'\\' && RelativePath[1] == UNICODE_NULL))
+    {
+        /* Installation path */
+        DPRINT("InstallationPath: '%S'\n", RelativePath);
+
+        Status = CombinePaths(FullPath, cchFullPathSize, 2,
+                              RootPath, BasePath);
+
+        DPRINT("InstallationPath(2): '%S'\n", FullPath);
+    }
+    else if (RelativePath[0] == L'\\')
+    {
+        /* Absolute path */
+        DPRINT("AbsolutePath: '%S'\n", RelativePath);
+
+        Status = CombinePaths(FullPath, cchFullPathSize, 2,
+                              RootPath, RelativePath);
+
+        DPRINT("AbsolutePath(2): '%S'\n", FullPath);
+    }
+    else // if (RelativePath[0] != L'\\')
+    {
+        /* Path relative to the installation path */
+        DPRINT("RelativePath: '%S'\n", RelativePath);
+
+        Status = CombinePaths(FullPath, cchFullPathSize, 3,
+                              RootPath, BasePath, RelativePath);
+
+        DPRINT("RelativePath(2): '%S'\n", FullPath);
+    }
+
+    return Status;
+}
+
+
 /*
  * This code enumerates the list of files in reactos.dff / reactos.inf
  * that need to be extracted from reactos.cab and be installed in their
@@ -40,20 +290,20 @@ AddSectionToCopyQueueCab(
     IN PCWSTR SourceCabinet,
     IN PCUNICODE_STRING DestinationPath)
 {
+    BOOLEAN Success;
+    NTSTATUS Status;
     INFCONTEXT FilesContext;
     INFCONTEXT DirContext;
-    PCWSTR FileKeyName;
-    PCWSTR FileKeyValue;
-    PCWSTR DirKeyValue;
+    PCWSTR SourceFileName;
+    PCWSTR TargetDirId;
+    PCWSTR TargetDir;
     PCWSTR TargetFileName;
     WCHAR FileDstPath[MAX_PATH];
 
     /* Search for the SectionName section */
     if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
     {
-        pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
-        if (pSetupData->ErrorRoutine)
-            pSetupData->ErrorRoutine(pSetupData, SectionName);
+        DPRINT1("AddSectionToCopyQueueCab(): Unable to find section '%S' in cabinet file\n", SectionName);
         return FALSE;
     }
 
@@ -63,7 +313,7 @@ AddSectionToCopyQueueCab(
     do
     {
         /* Get source file name and target directory id */
-        if (!INF_GetData(&FilesContext, &FileKeyName, &FileKeyValue))
+        if (!INF_GetData(&FilesContext, &SourceFileName, &TargetDirId))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
@@ -72,70 +322,45 @@ AddSectionToCopyQueueCab(
 
         /* Get optional target file name */
         if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
+        {
             TargetFileName = NULL;
-
-        DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
-
-        /* Lookup target directory */
-        if (!SpInfFindFirstLine(InfFile, L"Directories", FileKeyValue, &DirContext))
+        }
+        else if (!*TargetFileName)
         {
-            /* FIXME: Handle error! */
-            DPRINT1("SetupFindFirstLine() failed\n");
-            INF_FreeData(FileKeyName);
-            INF_FreeData(FileKeyValue);
             INF_FreeData(TargetFileName);
-            break;
+            TargetFileName = NULL;
         }
 
-        INF_FreeData(FileKeyValue);
-
-        if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
+        /* Lookup target directory */
+        Success = LookupDirectoryById(InfFile, &DirContext, TargetDirId, &TargetDir);
+        INF_FreeData(TargetDirId);
+        if (!Success)
         {
             /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            INF_FreeData(FileKeyName);
             INF_FreeData(TargetFileName);
+            INF_FreeData(SourceFileName);
             break;
         }
 
-#if 1 // HACK moved! (r66604)
-        {
-        ULONG Length = wcslen(DirKeyValue);
-        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
-            Length--;
-        *((PWSTR)DirKeyValue + Length) = UNICODE_NULL;
-        }
-
-        /* Build the full target path */
-        RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath),
-                          pSetupData->DestinationRootPath.Buffer);
-        if (DirKeyValue[0] == UNICODE_NULL)
-        {
-            /* Installation path */
+        DPRINT("GetSourceTargetFromCab(%S) = "
+               "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
+               SourceFileName,
+               pSetupData->SourcePath.Buffer,
+               pSetupData->SourceRootDir.Buffer,
+               TargetDir, TargetFileName);
 
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, pSetupData->InstallPath.Buffer);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            // if (DirKeyValue[1] != UNICODE_NULL)
-                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, DirKeyValue);
-        }
-        else // if (DirKeyValue[0] != L'\\')
-        {
-            /* Path relative to the installation path */
+        Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
+                              pSetupData->DestinationPath.Buffer,
+                              TargetDir);
+        UNREFERENCED_PARAMETER(Status);
+        DPRINT("  --> FileDstPath = '%S'\n", FileDstPath);
 
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
-                        pSetupData->InstallPath.Buffer, DirKeyValue);
-        }
-#endif
+        INF_FreeData(TargetDir);
 
         if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
-                             pSetupData->SourceRootPath.Buffer,
-                             pSetupData->SourceRootDir.Buffer,
-                             FileKeyName,
+                             pSetupData->SourcePath.Buffer, // SourcePath == SourceRootPath ++ SourceRootDir
+                             NULL,
+                             SourceFileName,
                              NULL,
                              SourceCabinet,
                              NULL,
@@ -147,9 +372,9 @@ AddSectionToCopyQueueCab(
             DPRINT1("SpFileQueueCopy() failed\n");
         }
 
-        INF_FreeData(FileKeyName);
         INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
+        INF_FreeData(SourceFileName);
+
     } while (SpInfFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -171,21 +396,18 @@ AddSectionToCopyQueue(
     IN PUSETUP_DATA pSetupData,
     IN HINF InfFile,
     IN PCWSTR SectionName,
-    IN PCWSTR SourceCabinet,
     IN PCUNICODE_STRING DestinationPath)
 {
+    NTSTATUS Status;
     INFCONTEXT FilesContext;
-    INFCONTEXT DirContext;
-    PCWSTR FileKeyName;
-    PCWSTR FileKeyValue;
-    PCWSTR DirKeyValue;
+    PCWSTR SourceFileName;
+    PCWSTR SourceRootPath;
+    PCWSTR SourcePath;
+    PCWSTR TargetDirectory;
     PCWSTR TargetFileName;
-    WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
+    WCHAR FileSrcRootPath[MAX_PATH];
     WCHAR FileDstPath[MAX_PATH];
 
-    if (SourceCabinet)
-        return AddSectionToCopyQueueCab(pSetupData, InfFile, L"SourceFiles", SourceCabinet, DestinationPath);
-
     /*
      * This code enumerates the list of files in txtsetup.sif
      * that need to be installed in their respective directories.
@@ -194,9 +416,7 @@ AddSectionToCopyQueue(
     /* Search for the SectionName section */
     if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
     {
-        pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
-        if (pSetupData->ErrorRoutine)
-            pSetupData->ErrorRoutine(pSetupData, SectionName);
+        DPRINT1("AddSectionToCopyQueue(): Unable to find section '%S' in TXTSETUP.SIF\n", SectionName);
         return FALSE;
     }
 
@@ -206,123 +426,62 @@ AddSectionToCopyQueue(
     do
     {
         /* Get source file name */
-        if (!INF_GetDataField(&FilesContext, 0, &FileKeyName))
+        if (!INF_GetDataField(&FilesContext, 0, &SourceFileName))
         {
             /* FIXME: Handle error! */
             DPRINT1("INF_GetData() failed\n");
             break;
         }
 
-        /* Get target directory id */
-        if (!INF_GetDataField(&FilesContext, 13, &FileKeyValue))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            INF_FreeData(FileKeyName);
-            break;
-        }
-
-        /* Get optional target file name */
-        if (!INF_GetDataField(&FilesContext, 11, &TargetFileName))
-            TargetFileName = NULL;
-        else if (!*TargetFileName)
-            TargetFileName = NULL;
-
-        DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
-
-        /* Lookup target directory */
-        if (!SpInfFindFirstLine(InfFile, L"Directories", FileKeyValue, &DirContext))
-        {
-            /* FIXME: Handle error! */
-            DPRINT1("SetupFindFirstLine() failed\n");
-            INF_FreeData(FileKeyName);
-            INF_FreeData(FileKeyValue);
-            INF_FreeData(TargetFileName);
-            break;
-        }
-
-        INF_FreeData(FileKeyValue);
-
-        if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
+        Status = GetSourceFileAndTargetLocation(InfFile,
+                                                &FilesContext,
+                                                SourceFileName,
+                                                &SourceRootPath, // SourceRootDir
+                                                &SourcePath,
+                                                &TargetDirectory,
+                                                &TargetFileName);
+        if (!NT_SUCCESS(Status))
         {
-            /* FIXME: Handle error! */
-            DPRINT1("INF_GetData() failed\n");
-            INF_FreeData(FileKeyName);
-            INF_FreeData(TargetFileName);
-            break;
-        }
+            DPRINT1("Could not find source and target location for file '%S'\n", SourceFileName);
+            INF_FreeData(SourceFileName);
 
-        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
-        {
-            /* Installation path */
-            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
-
-            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                              pSetupData->SourceRootDir.Buffer);
-
-            DPRINT("InstallationPath(2): '%S'\n", CompleteOrigDirName);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
-
-            RtlStringCchCopyW(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName),
-                              DirKeyValue);
-
-            DPRINT("AbsolutePath(2): '%S'\n", CompleteOrigDirName);
-        }
-        else // if (DirKeyValue[0] != L'\\')
-        {
-            /* Path relative to the installation path */
-            DPRINT("RelativePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(CompleteOrigDirName, ARRAYSIZE(CompleteOrigDirName), 2,
-                         pSetupData->SourceRootDir.Buffer, DirKeyValue);
-
-            DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
-        }
-
-#if 1 // HACK moved! (r66604)
-        {
-        ULONG Length = wcslen(DirKeyValue);
-        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
-            Length--;
-        *((PWSTR)DirKeyValue + Length) = UNICODE_NULL;
-        }
-
-        /* Build the full target path */
-        RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath),
-                          pSetupData->DestinationRootPath.Buffer);
-        if (DirKeyValue[0] == UNICODE_NULL)
-        {
-            /* Installation path */
-
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, pSetupData->InstallPath.Buffer);
-        }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            // if (DirKeyValue[1] != UNICODE_NULL)
-                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, DirKeyValue);
-        }
-        else // if (DirKeyValue[0] != L'\\')
-        {
-            /* Path relative to the installation path */
-
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
-                        pSetupData->InstallPath.Buffer, DirKeyValue);
+            // FIXME: Another error?
+            pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+            if (pSetupData->ErrorRoutine)
+                pSetupData->ErrorRoutine(pSetupData, SectionName);
+            return FALSE;
+            // break;
         }
-#endif
+        /*
+         * SourcePath: '\Device\CdRom0\I386'
+         * SourceRootPath: '\Device\CdRom0'
+         * SourceRootDir: '\I386'
+         */
+
+        Status = CombinePaths(FileSrcRootPath, ARRAYSIZE(FileSrcRootPath), 2,
+                              pSetupData->SourceRootPath.Buffer,
+                              SourceRootPath);
+        UNREFERENCED_PARAMETER(Status);
+        // DPRINT1("Could not build the full path for '%S', skipping...\n", SourceRootPath);
+        DPRINT("  --> FileSrcRootPath = '%S'\n", FileSrcRootPath);
+
+        INF_FreeData(SourceRootPath);
+
+        Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
+                              pSetupData->DestinationPath.Buffer,
+                              TargetDirectory);
+        UNREFERENCED_PARAMETER(Status);
+        // DPRINT1("Could not build the full path for '%S', skipping...\n", TargetDirectory);
+        DPRINT("  --> FileDstPath = '%S'\n", FileDstPath);
+
+        INF_FreeData(TargetDirectory);
 
         if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
-                             pSetupData->SourceRootPath.Buffer,
-                             CompleteOrigDirName,
-                             FileKeyName,
+                             FileSrcRootPath,
+                             SourcePath,
+                             SourceFileName,
                              NULL,
-                             SourceCabinet,
+                             NULL, // No SourceCabinet
                              NULL,
                              FileDstPath,
                              TargetFileName,
@@ -332,9 +491,10 @@ AddSectionToCopyQueue(
             DPRINT1("SpFileQueueCopy() failed\n");
         }
 
-        INF_FreeData(FileKeyName);
         INF_FreeData(TargetFileName);
-        INF_FreeData(DirKeyValue);
+        INF_FreeData(SourcePath);
+        INF_FreeData(SourceFileName);
+
     } while (SpInfFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
@@ -346,31 +506,77 @@ PrepareCopyInfFile(
     IN HINF InfFile,
     IN PCWSTR SourceCabinet OPTIONAL)
 {
+    BOOLEAN Success;
     NTSTATUS Status;
     INFCONTEXT DirContext;
     PWCHAR AdditionalSectionName = NULL;
     PCWSTR DirKeyValue;
     WCHAR PathBuffer[MAX_PATH];
 
-    /* Add common files */
-    if (!AddSectionToCopyQueue(pSetupData, InfFile, L"SourceDisksFiles", SourceCabinet, &pSetupData->DestinationPath))
-        return FALSE;
-
-    /* Add specific files depending of computer type */
     if (SourceCabinet == NULL)
     {
+        /* Add common files -- Search for the SourceDisksFiles section */
+        /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
+        Success = AddSectionToCopyQueue(pSetupData, InfFile,
+                                        L"SourceDisksFiles." INF_ARCH,
+                                        &pSetupData->DestinationPath);
+        if (!Success)
+        {
+            DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles." INF_ARCH);
+        }
+        /* Search in the global section */
+        Success = AddSectionToCopyQueue(pSetupData, InfFile,
+                                        L"SourceDisksFiles",
+                                        &pSetupData->DestinationPath);
+        if (!Success)
+        {
+            DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles");
+            pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+            if (pSetupData->ErrorRoutine)
+                pSetupData->ErrorRoutine(pSetupData, L"SourceDisksFiles");
+            return FALSE;
+        }
+
+        /* Add specific files depending of computer type */
         if (!ProcessComputerFiles(InfFile, pSetupData->ComputerList, &AdditionalSectionName))
             return FALSE;
 
-        if (AdditionalSectionName)
+        if (AdditionalSectionName &&
+            !AddSectionToCopyQueue(pSetupData, InfFile,
+                                   AdditionalSectionName,
+                                   &pSetupData->DestinationPath))
         {
-            if (!AddSectionToCopyQueue(pSetupData, InfFile, AdditionalSectionName, SourceCabinet, &pSetupData->DestinationPath))
-                return FALSE;
+            pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+            if (pSetupData->ErrorRoutine)
+                pSetupData->ErrorRoutine(pSetupData, AdditionalSectionName);
+            return FALSE;
+        }
+    }
+    else
+    {
+        /* Process a cabinet INF */
+        Success = AddSectionToCopyQueueCab(pSetupData, InfFile,
+                                           L"SourceFiles",
+                                           SourceCabinet,
+                                           &pSetupData->DestinationPath);
+        if (!Success)
+        {
+            DPRINT1("AddSectionToCopyQueueCab(%S) failed!\n", SourceCabinet);
+            pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
+            if (pSetupData->ErrorRoutine)
+                pSetupData->ErrorRoutine(pSetupData, L"SourceFiles");
+            return FALSE;
         }
     }
 
     /* Create directories */
 
+    /*
+     * NOTE: This is technically optional since SpFileQueueCommit()
+     * does that. This is however needed if one wants to create
+     * empty directories.
+     */
+
     /*
      * FIXME:
      * Copying files to pSetupData->DestinationRootPath should be done from within
@@ -380,7 +586,8 @@ PrepareCopyInfFile(
      */
 
     /* Get destination path */
-    RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer), pSetupData->DestinationPath.Buffer);
+    RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
+                      pSetupData->DestinationPath.Buffer);
 
     DPRINT("FullPath(1): '%S'\n", PathBuffer);
 
@@ -396,16 +603,21 @@ PrepareCopyInfFile(
     }
 
     /* Search for the 'Directories' section */
+    // ReactOS-specific
     if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
     {
-        if (SourceCabinet)
-            pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
-        else
-            pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
+        // Windows-compatible
+        if (!SpInfFindFirstLine(InfFile, L"WinntDirectories", NULL, &DirContext))
+        {
+            if (SourceCabinet)
+                pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
+            else
+                pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
 
-        if (pSetupData->ErrorRoutine)
-            pSetupData->ErrorRoutine(pSetupData, L"Directories");
-        return FALSE;
+            if (pSetupData->ErrorRoutine)
+                pSetupData->ErrorRoutine(pSetupData, L"Directories");
+            return FALSE;
+        }
     }
 
     /* Enumerate the directory values and create the subdirectories */
@@ -417,47 +629,28 @@ PrepareCopyInfFile(
             break;
         }
 
-        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
+        Status = BuildFullDirectoryPath(pSetupData->DestinationRootPath.Buffer,
+                                        pSetupData->InstallPath.Buffer,
+                                        DirKeyValue,
+                                        PathBuffer,
+                                        ARRAYSIZE(PathBuffer));
+        if (!NT_SUCCESS(Status))
         {
-            /* Installation path */
-            DPRINT("InstallationPath: '%S'\n", DirKeyValue);
-
-            RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
-                              pSetupData->DestinationPath.Buffer);
-
-            DPRINT("InstallationPath(2): '%S'\n", PathBuffer);
+            DPRINT1("Could not build the full path for '%S', skipping...\n", DirKeyValue);
+            INF_FreeData(DirKeyValue);
+            continue;
         }
-        else if (DirKeyValue[0] == L'\\')
-        {
-            /* Absolute path */
-            DPRINT("AbsolutePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         pSetupData->DestinationRootPath.Buffer, DirKeyValue);
 
-            DPRINT("AbsolutePath(2): '%S'\n", PathBuffer);
-
-            Status = SetupCreateDirectory(PathBuffer);
-            if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
-            {
-                INF_FreeData(DirKeyValue);
-                DPRINT("Creating directory '%S' failed: Status = 0x%08lx", PathBuffer, Status);
-                pSetupData->LastErrorNumber = ERROR_CREATE_DIR;
-                if (pSetupData->ErrorRoutine)
-                    pSetupData->ErrorRoutine(pSetupData, PathBuffer);
-                return FALSE;
-            }
+        if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
+        {
+            /*
+             * Installation path -- No need to create it
+             * because it has been already created above.
+             */
         }
-        else // if (DirKeyValue[0] != L'\\')
+        else
         {
-            /* Path relative to the installation path */
-            DPRINT("RelativePath: '%S'\n", DirKeyValue);
-
-            CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
-                         pSetupData->DestinationPath.Buffer, DirKeyValue);
-
-            DPRINT("RelativePath(2): '%S'\n", PathBuffer);
-
+            /* Arbitrary path -- Create it */
             Status = SetupCreateDirectory(PathBuffer);
             if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
             {