[SETUPLIB][USETUP] Add support for setup error handling.
[reactos.git] / base / setup / usetup / usetup.c
index edd98fd..4dbf388 100644 (file)
@@ -21,7 +21,7 @@
  * PROJECT:         ReactOS text-mode setup
  * FILE:            base/setup/usetup/usetup.c
  * PURPOSE:         Text-mode setup
- * PROGRAMMER     Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * PROGRAMMERS:     Casper S. Hornstrup (chorns@users.sourceforge.net)
  *                  HervĂ© Poussineau (hpoussin@reactos.org)
  */
 
@@ -3481,19 +3481,43 @@ InstallDirectoryPage(PINPUT_RECORD Ir)
 }
 
 
+// PSETUP_ERROR_ROUTINE
+static VOID
+__cdecl
+USetupErrorRoutine(
+    IN PUSETUP_DATA pSetupData,
+    ...)
+{
+    INPUT_RECORD Ir;
+    va_list arg_ptr;
+
+    va_start(arg_ptr, pSetupData);
+
+    if (pSetupData->LastErrorNumber >= ERROR_SUCCESS &&
+        pSetupData->LastErrorNumber <  ERROR_LAST_ERROR_CODE)
+    {
+        // Note: the "POPUP_WAIT_ENTER" actually depends on the LastErrorNumber...
+        MUIDisplayErrorV(pSetupData->LastErrorNumber, &Ir, POPUP_WAIT_ENTER, arg_ptr);
+    }
+
+    va_end(arg_ptr);
+}
+
+
 static BOOLEAN
 AddSectionToCopyQueueCab(HINF InfFile,
-                         PWCHAR SectionName,
-                         PWCHAR SourceCabinet,
+                         PCWSTR SectionName,
+                         PCWSTR SourceCabinet,
                          PCUNICODE_STRING DestinationPath,
                          PINPUT_RECORD Ir)
 {
     INFCONTEXT FilesContext;
     INFCONTEXT DirContext;
-    PWCHAR FileKeyName;
-    PWCHAR FileKeyValue;
-    PWCHAR DirKeyValue;
-    PWCHAR TargetFileName;
+    PCWSTR FileKeyName;
+    PCWSTR FileKeyValue;
+    PCWSTR DirKeyValue;
+    PCWSTR TargetFileName;
+    WCHAR FileDstPath[MAX_PATH];
 
     /*
      * This code enumerates the list of files in reactos.dff / reactos.inf
@@ -3502,7 +3526,7 @@ AddSectionToCopyQueueCab(HINF InfFile,
      */
 
     /* Search for the SectionName section */
-    if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
+    if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
     {
         MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
         return FALSE;
@@ -3528,7 +3552,7 @@ AddSectionToCopyQueueCab(HINF InfFile,
         DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
 
         /* Lookup target directory */
-        if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
+        if (!SpInfFindFirstLine(InfFile, L"Directories", FileKeyValue, &DirContext))
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
@@ -3549,22 +3573,59 @@ AddSectionToCopyQueueCab(HINF InfFile,
             break;
         }
 
-        if (!SetupQueueCopy(USetupData.SetupFileQueue,
-                            SourceCabinet,
-                            USetupData.SourceRootPath.Buffer,
-                            USetupData.SourceRootDir.Buffer,
-                            FileKeyName,
-                            DirKeyValue,
-                            TargetFileName))
+#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),
+                          USetupData.DestinationRootPath.Buffer);
+        if (DirKeyValue[0] == UNICODE_NULL)
+        {
+            /* Installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, USetupData.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,
+                        USetupData.InstallPath.Buffer, DirKeyValue);
+        }
+#endif
+
+        if (!SpFileQueueCopy((HSPFILEQ)USetupData.SetupFileQueue,
+                             USetupData.SourceRootPath.Buffer,
+                             USetupData.SourceRootDir.Buffer,
+                             FileKeyName,
+                             NULL,
+                             SourceCabinet,
+                             NULL,
+                             FileDstPath,
+                             TargetFileName,
+                             0 /* FIXME */))
         {
             /* FIXME: Handle error! */
-            DPRINT1("SetupQueueCopy() failed\n");
+            DPRINT1("SpFileQueueCopy() failed\n");
         }
 
         INF_FreeData(FileKeyName);
         INF_FreeData(TargetFileName);
         INF_FreeData(DirKeyValue);
-    } while (SetupFindNextLine(&FilesContext, &FilesContext));
+    } while (SpInfFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
 }
@@ -3572,18 +3633,19 @@ AddSectionToCopyQueueCab(HINF InfFile,
 
 static BOOLEAN
 AddSectionToCopyQueue(HINF InfFile,
-                      PWCHAR SectionName,
-                      PWCHAR SourceCabinet,
+                      PCWSTR SectionName,
+                      PCWSTR SourceCabinet,
                       PCUNICODE_STRING DestinationPath,
                       PINPUT_RECORD Ir)
 {
     INFCONTEXT FilesContext;
     INFCONTEXT DirContext;
-    PWCHAR FileKeyName;
-    PWCHAR FileKeyValue;
-    PWCHAR DirKeyValue;
-    PWCHAR TargetFileName;
+    PCWSTR FileKeyName;
+    PCWSTR FileKeyValue;
+    PCWSTR DirKeyValue;
+    PCWSTR TargetFileName;
     WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
+    WCHAR FileDstPath[MAX_PATH];
 
     if (SourceCabinet)
         return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
@@ -3594,7 +3656,7 @@ AddSectionToCopyQueue(HINF InfFile,
      */
 
     /* Search for the SectionName section */
-    if (!SetupFindFirstLineW(InfFile, SectionName, NULL, &FilesContext))
+    if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
     {
         MUIDisplayError(ERROR_TXTSETUP_SECTION, Ir, POPUP_WAIT_ENTER, SectionName);
         return FALSE;
@@ -3631,7 +3693,7 @@ AddSectionToCopyQueue(HINF InfFile,
         DPRINT("FileKeyName: '%S'  FileKeyValue: '%S'\n", FileKeyName, FileKeyValue);
 
         /* Lookup target directory */
-        if (!SetupFindFirstLineW(InfFile, L"Directories", FileKeyValue, &DirContext))
+        if (!SpInfFindFirstLine(InfFile, L"Directories", FileKeyValue, &DirContext))
         {
             /* FIXME: Handle error! */
             DPRINT1("SetupFindFirstLine() failed\n");
@@ -3683,22 +3745,59 @@ AddSectionToCopyQueue(HINF InfFile,
             DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
-        if (!SetupQueueCopy(USetupData.SetupFileQueue,
-                            SourceCabinet,
-                            USetupData.SourceRootPath.Buffer,
-                            CompleteOrigDirName,
-                            FileKeyName,
-                            DirKeyValue,
-                            TargetFileName))
+#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),
+                          USetupData.DestinationRootPath.Buffer);
+        if (DirKeyValue[0] == UNICODE_NULL)
+        {
+            /* Installation path */
+
+            /* Add the installation path */
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, USetupData.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,
+                        USetupData.InstallPath.Buffer, DirKeyValue);
+        }
+#endif
+
+        if (!SpFileQueueCopy((HSPFILEQ)USetupData.SetupFileQueue,
+                             USetupData.SourceRootPath.Buffer,
+                             CompleteOrigDirName,
+                             FileKeyName,
+                             NULL,
+                             SourceCabinet,
+                             NULL,
+                             FileDstPath,
+                             TargetFileName,
+                             0 /* FIXME */))
         {
             /* FIXME: Handle error! */
-            DPRINT1("SetupQueueCopy() failed\n");
+            DPRINT1("SpFileQueueCopy() failed\n");
         }
 
         INF_FreeData(FileKeyName);
         INF_FreeData(TargetFileName);
         INF_FreeData(DirKeyValue);
-    } while (SetupFindNextLine(&FilesContext, &FilesContext));
+    } while (SpInfFindNextLine(&FilesContext, &FilesContext));
 
     return TRUE;
 }
@@ -3706,13 +3805,13 @@ AddSectionToCopyQueue(HINF InfFile,
 
 static BOOLEAN
 PrepareCopyPageInfFile(HINF InfFile,
-                       PWCHAR SourceCabinet,
+                       PCWSTR SourceCabinet,
                        PINPUT_RECORD Ir)
 {
     NTSTATUS Status;
     INFCONTEXT DirContext;
     PWCHAR AdditionalSectionName = NULL;
-    PWCHAR DirKeyValue;
+    PCWSTR DirKeyValue;
     WCHAR PathBuffer[MAX_PATH];
 
     /* Add common files */
@@ -3757,7 +3856,7 @@ PrepareCopyPageInfFile(HINF InfFile,
     }
 
     /* Search for the 'Directories' section */
-    if (!SetupFindFirstLineW(InfFile, L"Directories", NULL, &DirContext))
+    if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
     {
         if (SourceCabinet)
             MUIDisplayError(ERROR_CABINET_SECTION, Ir, POPUP_WAIT_ENTER, L"Directories");
@@ -3826,7 +3925,7 @@ PrepareCopyPageInfFile(HINF InfFile,
         }
 
         INF_FreeData(DirKeyValue);
-    } while (SetupFindNextLine(&DirContext, &DirContext));
+    } while (SpInfFindNextLine(&DirContext, &DirContext));
 
     return TRUE;
 }
@@ -3853,14 +3952,14 @@ PrepareCopyPage(PINPUT_RECORD Ir)
     WCHAR PathBuffer[MAX_PATH];
     INFCONTEXT CabinetsContext;
     ULONG InfFileSize;
-    PWCHAR KeyValue;
+    PCWSTR KeyValue;
     UINT ErrorLine;
     PVOID InfFileData;
 
     MUIDisplayPage(PREPARE_COPY_PAGE);
 
     /* Create the file queue */
-    USetupData.SetupFileQueue = SetupOpenFileQueue();
+    USetupData.SetupFileQueue = SpFileQueueOpen();
     if (USetupData.SetupFileQueue == NULL)
     {
         MUIDisplayError(ERROR_COPY_QUEUE, Ir, POPUP_WAIT_ENTER);
@@ -3874,7 +3973,7 @@ PrepareCopyPage(PINPUT_RECORD Ir)
     }
 
     /* Search for the 'Cabinets' section */
-    if (!SetupFindFirstLineW(USetupData.SetupInf, L"Cabinets", NULL, &CabinetsContext))
+    if (!SpInfFindFirstLine(USetupData.SetupInf, L"Cabinets", NULL, &CabinetsContext))
     {
         return FILE_COPY_PAGE;
     }
@@ -3933,14 +4032,20 @@ PrepareCopyPage(PINPUT_RECORD Ir)
             /* FIXME: show an error dialog */
             return QUIT_PAGE;
         }
-    } while (SetupFindNextLine(&CabinetsContext, &CabinetsContext));
+    } while (SpInfFindNextLine(&CabinetsContext, &CabinetsContext));
 
     return FILE_COPY_PAGE;
 }
 
+typedef struct _COPYCONTEXT
+{
+    ULONG TotalOperations;
+    ULONG CompletedOperations;
+    PPROGRESSBAR ProgressBar;
+    PPROGRESSBAR MemoryBars[4];
+} COPYCONTEXT, *PCOPYCONTEXT;
 
-VOID
-NTAPI
+static VOID
 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
                       IN BOOLEAN First)
 {
@@ -3967,7 +4072,6 @@ SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
     ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
 }
 
-
 static UINT
 CALLBACK
 FileCopyCallback(PVOID Context,
@@ -3975,26 +4079,92 @@ FileCopyCallback(PVOID Context,
                  UINT_PTR Param1,
                  UINT_PTR Param2)
 {
-    PCOPYCONTEXT CopyContext;
-
-    CopyContext = (PCOPYCONTEXT)Context;
+    PCOPYCONTEXT CopyContext = (PCOPYCONTEXT)Context;
+    PFILEPATHS_W FilePathInfo;
+    PCWSTR SrcFileName, DstFileName;
 
     switch (Notification)
     {
         case SPFILENOTIFY_STARTSUBQUEUE:
+        {
             CopyContext->TotalOperations = (ULONG)Param2;
+            CopyContext->CompletedOperations = 0;
             ProgressSetStepCount(CopyContext->ProgressBar,
                                  CopyContext->TotalOperations);
             SetupUpdateMemoryInfo(CopyContext, TRUE);
             break;
+        }
 
+        case SPFILENOTIFY_STARTDELETE:
+        case SPFILENOTIFY_STARTRENAME:
         case SPFILENOTIFY_STARTCOPY:
-            /* Display copy message */
-            CONSOLE_SetStatusText(MUIGetString(STRING_COPYING), (PWSTR)Param1);
+        {
+            FilePathInfo = (PFILEPATHS_W)Param1;
+
+            if (Notification == SPFILENOTIFY_STARTDELETE)
+            {
+                /* Display delete message */
+                ASSERT(Param2 == FILEOP_DELETE);
+
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_DELETING),
+                                      DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTRENAME)
+            {
+                /* Display move/rename message */
+                ASSERT(Param2 == FILEOP_RENAME);
+
+                SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
+                if (SrcFileName) ++SrcFileName;
+                else SrcFileName = FilePathInfo->Source;
+
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                if (!wcsicmp(SrcFileName, DstFileName))
+                    Param2 = STRING_MOVING;
+                else
+                    Param2 = STRING_RENAMING;
+
+                CONSOLE_SetStatusText(MUIGetString(Param2),
+                                      SrcFileName, DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTCOPY)
+            {
+                /* Display copy message */
+                ASSERT(Param2 == FILEOP_COPY);
+
+                /* NOTE: When extracting from CABs the Source is the CAB name */
+                DstFileName = wcsrchr(FilePathInfo->Target, L'\\');
+                if (DstFileName) ++DstFileName;
+                else DstFileName = FilePathInfo->Target;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
+                                      DstFileName);
+            }
+
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
+
+        case SPFILENOTIFY_COPYERROR:
+        {
+            FilePathInfo = (PFILEPATHS_W)Param1;
+
+            DPRINT1("An error happened while trying to copy file '%S' (error 0x%08lx), skipping it...\n",
+                    FilePathInfo->Target, FilePathInfo->Win32Error);
+            return FILEOP_SKIP;
+        }
 
+        case SPFILENOTIFY_ENDDELETE:
+        case SPFILENOTIFY_ENDRENAME:
         case SPFILENOTIFY_ENDCOPY:
+        {
             CopyContext->CompletedOperations++;
 
             /* SYSREG checkpoint */
@@ -4004,9 +4174,10 @@ FileCopyCallback(PVOID Context,
             ProgressNextStep(CopyContext->ProgressBar);
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
     }
 
-    return 0;
+    return FILEOP_DOIT;
 }
 
 
@@ -4018,7 +4189,7 @@ FileCopyCallback(PVOID Context,
  *
  * SIDEEFFECTS
  *  Calls SetupCommitFileQueueW
- *  Calls SetupCloseFileQueue
+ *  Calls SpFileQueueClose
  *
  * RETURNS
  *   Number of the next page.
@@ -4027,13 +4198,11 @@ static PAGE_NUMBER
 FileCopyPage(PINPUT_RECORD Ir)
 {
     COPYCONTEXT CopyContext;
-    unsigned int mem_bar_width;
+    UINT MemBarWidth;
 
     MUIDisplayPage(FILE_COPY_PAGE);
 
     /* Create context for the copy process */
-    CopyContext.DestinationRootPath = USetupData.DestinationRootPath.Buffer;
-    CopyContext.InstallPath = USetupData.InstallPath.Buffer;
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
 
@@ -4048,13 +4217,13 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                 MUIGetString(STRING_SETUPCOPYINGFILES));
 
     // fit memory bars to screen width, distribute them uniform
-    mem_bar_width = (xScreen - 26) / 5;
-    mem_bar_width -= mem_bar_width % 2;  // make even
+    MemBarWidth = (xScreen - 26) / 5;
+    MemBarWidth -= MemBarWidth % 2;  // make even
     /* ATTENTION: The following progress bars are debug stuff, which should not be translated!! */
     /* Create the paged pool progress bar */
     CopyContext.MemoryBars[0] = CreateProgressBar(13,
                                                   40,
-                                                  13 + mem_bar_width,
+                                                  13 + MemBarWidth,
                                                   43,
                                                   13,
                                                   44,
@@ -4062,33 +4231,33 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                   "Kernel Pool");
 
     /* Create the non paged pool progress bar */
-    CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (mem_bar_width / 2),
+    CopyContext.MemoryBars[1] = CreateProgressBar((xScreen / 2)- (MemBarWidth / 2),
                                                   40,
-                                                  (xScreen / 2) + (mem_bar_width / 2),
+                                                  (xScreen / 2) + (MemBarWidth / 2),
                                                   43,
-                                                  (xScreen / 2)- (mem_bar_width / 2),
+                                                  (xScreen / 2)- (MemBarWidth / 2),
                                                   44,
                                                   FALSE,
                                                   "Kernel Cache");
 
     /* Create the global memory progress bar */
-    CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - mem_bar_width,
+    CopyContext.MemoryBars[2] = CreateProgressBar(xScreen - 13 - MemBarWidth,
                                                   40,
                                                   xScreen - 13,
                                                   43,
-                                                  xScreen - 13 - mem_bar_width,
+                                                  xScreen - 13 - MemBarWidth,
                                                   44,
                                                   FALSE,
                                                   "Free Memory");
 
     /* Do the file copying */
-    SetupCommitFileQueueW(NULL,
-                          USetupData.SetupFileQueue,
-                          FileCopyCallback,
-                          &CopyContext);
+    SpFileQueueCommit(NULL,
+                      USetupData.SetupFileQueue,
+                      FileCopyCallback,
+                      &CopyContext);
 
     /* If we get here, we're done, so cleanup the queue and progress bar */
-    SetupCloseFileQueue(USetupData.SetupFileQueue);
+    SpFileQueueClose(USetupData.SetupFileQueue);
     DestroyProgressBar(CopyContext.ProgressBar);
     DestroyProgressBar(CopyContext.MemoryBars[0]);
     DestroyProgressBar(CopyContext.MemoryBars[1]);
@@ -4154,15 +4323,11 @@ RegistryPage(PINPUT_RECORD Ir)
 
     MUIDisplayPage(REGISTRY_PAGE);
 
-    Error = UpdateRegistry(USetupData.SetupInf,
-                           &USetupData,
+    Error = UpdateRegistry(&USetupData,
                            RepairUpdateFlag,
                            PartitionList,
                            DestinationDriveLetter,
                            SelectedLanguageId,
-                           USetupData.DisplayList,
-                           USetupData.LayoutList,
-                           USetupData.LanguageList,
                            RegistryStatus);
     if (Error != ERROR_SUCCESS)
     {
@@ -4859,6 +5024,7 @@ RunUSetup(VOID)
 
     /* Initialize Setup, phase 0 */
     InitializeSetup(&USetupData, 0);
+    USetupData.ErrorRoutine = USetupErrorRoutine;
 
     /* Hide the cursor */
     CONSOLE_SetCursorType(TRUE, FALSE);