[SETUPLIB] Fixes and improvements for the file copying code.
[reactos.git] / 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)
             {