[USETUP] Improve SetupCommitFileQueueW() to make it compatible with its Win32 counter...
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Mon, 15 Jan 2018 17:48:51 +0000 (18:48 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 1 Nov 2018 17:55:44 +0000 (18:55 +0100)
This means, call in the correct order the user callback with the correct
parameters (in particular the correct paths for file copy operations),
and check also for the callback returned value to know whether or not to
continue the file operations.

base/setup/usetup/spapisup/fileqsup.c
base/setup/usetup/usetup.c

index 75f6b36..b82fcd8 100644 (file)
@@ -621,12 +621,12 @@ SetupCommitFileQueueW(
     IN PVOID Context OPTIONAL)
 {
     BOOL Success = TRUE; // Suppose success
+    UINT Result;
     NTSTATUS Status;
     PFILEQUEUEHEADER QueueHeader;
     PLIST_ENTRY ListEntry;
     PQUEUEENTRY Entry;
     FILEPATHS_W FilePathInfo;
-    WCHAR CabinetName[MAX_PATH];
     WCHAR FileSrcPath[MAX_PATH];
     WCHAR FileDstPath[MAX_PATH];
 
@@ -635,32 +635,40 @@ SetupCommitFileQueueW(
 
     QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
 
-    MsgHandler(Context,
-               SPFILENOTIFY_STARTQUEUE,
-               (UINT_PTR)Owner,
-               0);
+    Result = MsgHandler(Context,
+                        SPFILENOTIFY_STARTQUEUE,
+                        (UINT_PTR)Owner,
+                        0);
+    if (Result == FILEOP_ABORT)
+        return FALSE;
 
 
     /*
      * Commit the delete queue
      */
 
-    MsgHandler(Context,
-               SPFILENOTIFY_STARTSUBQUEUE,
-               FILEOP_DELETE,
-               QueueHeader->DeleteCount);
+    if (!IsListEmpty(&QueueHeader->DeleteQueue))
+    {
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTSUBQUEUE,
+                            FILEOP_DELETE,
+                            QueueHeader->DeleteCount);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto Quit;
+        }
+    }
 
-    ListEntry = QueueHeader->DeleteQueue.Flink;
-    while (ListEntry != &QueueHeader->DeleteQueue)
+    for (ListEntry = QueueHeader->DeleteQueue.Flink;
+         ListEntry != &QueueHeader->DeleteQueue;
+         ListEntry = ListEntry->Flink)
     {
         Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
-        ListEntry = ListEntry->Flink;
 
         /* Build the full target path */
         CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
                      Entry->TargetDirectory, Entry->TargetFileName);
-        // RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
-        // ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
 
         DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath);
 
@@ -669,52 +677,85 @@ SetupCommitFileQueueW(
         FilePathInfo.Win32Error = STATUS_SUCCESS;
         FilePathInfo.Flags = 0; // FIXME: Unused yet...
 
-        MsgHandler(Context,
-                   SPFILENOTIFY_STARTDELETE,
-                   (UINT_PTR)&FilePathInfo,
-                   FILEOP_DELETE);
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTDELETE,
+                            (UINT_PTR)&FilePathInfo,
+                            FILEOP_DELETE);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto EndDelete;
+        }
+        else if (Result == FILEOP_SKIP)
+            goto EndDelete;
+        // else (Result == FILEOP_DOIT)
 
+RetryDelete:
         /* Force-delete the file */
         Status = SetupDeleteFile(FileDstPath, TRUE);
         if (!NT_SUCCESS(Status))
         {
             /* An error happened */
             FilePathInfo.Win32Error = (UINT)Status;
-            MsgHandler(Context,
-                       SPFILENOTIFY_DELETEERROR,
-                       (UINT_PTR)&FilePathInfo,
-                       0);
+            Result = MsgHandler(Context,
+                                SPFILENOTIFY_DELETEERROR,
+                                (UINT_PTR)&FilePathInfo,
+                                0);
+            if (Result == FILEOP_ABORT)
+            {
+                Success = FALSE;
+                goto EndDelete;
+            }
+            else if (Result == FILEOP_SKIP)
+                goto EndDelete;
+            else if (Result == FILEOP_RETRY)
+                goto RetryDelete;
+
             Success = FALSE;
         }
 
+EndDelete:
         /* This notification is always sent, even in case of error */
         FilePathInfo.Win32Error = (UINT)Status;
         MsgHandler(Context,
                    SPFILENOTIFY_ENDDELETE,
                    (UINT_PTR)&FilePathInfo,
                    0);
+        if (Success == FALSE /* && Result == FILEOP_ABORT */)
+            goto Quit;
     }
 
-    MsgHandler(Context,
-               SPFILENOTIFY_ENDSUBQUEUE,
-               FILEOP_DELETE,
-               0);
+    if (!IsListEmpty(&QueueHeader->DeleteQueue))
+    {
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDSUBQUEUE,
+                   FILEOP_DELETE,
+                   0);
+    }
 
 
     /*
      * Commit the rename queue
      */
 
-    MsgHandler(Context,
-               SPFILENOTIFY_STARTSUBQUEUE,
-               FILEOP_RENAME,
-               QueueHeader->RenameCount);
+    if (!IsListEmpty(&QueueHeader->RenameQueue))
+    {
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTSUBQUEUE,
+                            FILEOP_RENAME,
+                            QueueHeader->RenameCount);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto Quit;
+        }
+    }
 
-    ListEntry = QueueHeader->RenameQueue.Flink;
-    while (ListEntry != &QueueHeader->RenameQueue)
+    for (ListEntry = QueueHeader->RenameQueue.Flink;
+         ListEntry != &QueueHeader->RenameQueue;
+         ListEntry = ListEntry->Flink)
     {
         Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
-        ListEntry = ListEntry->Flink;
 
         /* Build the full source path */
         CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2,
@@ -723,8 +764,6 @@ SetupCommitFileQueueW(
         /* Build the full target path */
         CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
                      Entry->TargetDirectory, Entry->TargetFileName);
-        // RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
-        // ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
 
         DPRINT1(" -----> " "Rename: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
 
@@ -733,11 +772,20 @@ SetupCommitFileQueueW(
         FilePathInfo.Win32Error = STATUS_SUCCESS;
         FilePathInfo.Flags = 0; // FIXME: Unused yet...
 
-        MsgHandler(Context,
-                   SPFILENOTIFY_STARTRENAME,
-                   (UINT_PTR)&FilePathInfo,
-                   FILEOP_RENAME);
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTRENAME,
+                            (UINT_PTR)&FilePathInfo,
+                            FILEOP_RENAME);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto EndRename;
+        }
+        else if (Result == FILEOP_SKIP)
+            goto EndRename;
+        // else (Result == FILEOP_DOIT)
 
+RetryRename:
         /* Move or rename the file */
         Status = SetupMoveFile(FileSrcPath, FileDstPath,
                                MOVEFILE_REPLACE_EXISTING
@@ -747,61 +795,105 @@ SetupCommitFileQueueW(
         {
             /* An error happened */
             FilePathInfo.Win32Error = (UINT)Status;
-            MsgHandler(Context,
-                       SPFILENOTIFY_RENAMEERROR,
-                       (UINT_PTR)&FilePathInfo,
-                       0);
+            Result = MsgHandler(Context,
+                                SPFILENOTIFY_RENAMEERROR,
+                                (UINT_PTR)&FilePathInfo,
+                                0);
+            if (Result == FILEOP_ABORT)
+            {
+                Success = FALSE;
+                goto EndRename;
+            }
+            else if (Result == FILEOP_SKIP)
+                goto EndRename;
+            else if (Result == FILEOP_RETRY)
+                goto RetryRename;
+
             Success = FALSE;
         }
 
+EndRename:
         /* This notification is always sent, even in case of error */
         FilePathInfo.Win32Error = (UINT)Status;
         MsgHandler(Context,
                    SPFILENOTIFY_ENDRENAME,
                    (UINT_PTR)&FilePathInfo,
                    0);
+        if (Success == FALSE /* && Result == FILEOP_ABORT */)
+            goto Quit;
     }
 
-    MsgHandler(Context,
-               SPFILENOTIFY_ENDSUBQUEUE,
-               FILEOP_RENAME,
-               0);
+    if (!IsListEmpty(&QueueHeader->RenameQueue))
+    {
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDSUBQUEUE,
+                   FILEOP_RENAME,
+                   0);
+    }
 
 
     /*
      * Commit the copy queue
      */
 
-    MsgHandler(Context,
-               SPFILENOTIFY_STARTSUBQUEUE,
-               FILEOP_COPY,
-               QueueHeader->CopyCount);
+    if (!IsListEmpty(&QueueHeader->CopyQueue))
+    {
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTSUBQUEUE,
+                            FILEOP_COPY,
+                            QueueHeader->CopyCount);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto Quit;
+        }
+    }
 
-    ListEntry = QueueHeader->CopyQueue.Flink;
-    while (ListEntry != &QueueHeader->CopyQueue)
+    for (ListEntry = QueueHeader->CopyQueue.Flink;
+         ListEntry != &QueueHeader->CopyQueue;
+         ListEntry = ListEntry->Flink)
     {
         Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
-        ListEntry = ListEntry->Flink;
+
+        //
+        // TODO: Send a SPFILENOTIFY_NEEDMEDIA notification
+        // when we switch to a new installation media.
+        // Param1 = (UINT_PTR)(PSOURCE_MEDIA)SourceMediaInfo;
+        // Param2 = (UINT_PTR)(TCHAR[MAX_PATH])NewPathInfo;
+        //
 
         /* Build the full source path */
-        CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
-                     Entry->SourceRootPath, Entry->SourcePath,
-                     Entry->SourceFileName);
+        if (Entry->SourceCabinet == NULL)
+        {
+            CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
+                         Entry->SourceRootPath, Entry->SourcePath,
+                         Entry->SourceFileName);
+        }
+        else
+        {
+            /*
+             * The cabinet must be in Entry->SourceRootPath only!
+             * (Should we ignore Entry->SourcePath?)
+             */
+            CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
+                         Entry->SourceRootPath, Entry->SourcePath,
+                         Entry->SourceCabinet);
+        }
 
         /* Build the full target path */
         RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
-
-        /*
-         * If the file is in a cabinet, use only the destination path.
-         * Otherwise possibly use a different target name.
-         */
         if (Entry->SourceCabinet == NULL)
         {
+            /* If the file is not in a cabinet, possibly use a different target name */
             if (Entry->TargetFileName != NULL)
                 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
             else
                 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
         }
+        else
+        {
+            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
+        }
 
         DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
 
@@ -811,29 +903,35 @@ SetupCommitFileQueueW(
         //
 
         FilePathInfo.Target = FileDstPath;
-        FilePathInfo.Source = FileSrcPath; // when SourceCabinet not NULL, use CabinetName ...
+        FilePathInfo.Source = FileSrcPath;
         FilePathInfo.Win32Error = STATUS_SUCCESS;
         FilePathInfo.Flags = 0; // FIXME: Unused yet...
 
-        MsgHandler(Context,
-                   SPFILENOTIFY_STARTCOPY,
-                   (UINT_PTR)&FilePathInfo,
-                   FILEOP_COPY);
+        Result = MsgHandler(Context,
+                            SPFILENOTIFY_STARTCOPY,
+                            (UINT_PTR)&FilePathInfo,
+                            FILEOP_COPY);
+        if (Result == FILEOP_ABORT)
+        {
+            Success = FALSE;
+            goto EndCopy;
+        }
+        else if (Result == FILEOP_SKIP)
+            goto EndCopy;
+        // else (Result == FILEOP_DOIT)
 
+RetryCopy:
         if (Entry->SourceCabinet != NULL)
         {
             /*
-             * Extract the file from the cabinet.
-             * The cabinet must be in Entry->SourceRootPath only!
-             * (ignore Entry->SourcePath).
+             * The file is in a cabinet, use only the destination path
+             * and keep the source name as the target name.
              */
-            CombinePaths(CabinetName, ARRAYSIZE(CabinetName), 3,
-                         Entry->SourceRootPath, Entry->SourcePath,
-                         Entry->SourceCabinet);
+            /* Extract the file from the cabinet */
             Status = SetupExtractFile(QueueHeader,
-                                      CabinetName,
+                                      FileSrcPath, // Specifies the cabinet path
                                       Entry->SourceFileName,
-                                      FileDstPath);
+                                      Entry->TargetDirectory);
         }
         else
         {
@@ -845,27 +943,46 @@ SetupCommitFileQueueW(
         {
             /* An error happened */
             FilePathInfo.Win32Error = (UINT)Status;
-            MsgHandler(Context,
-                       SPFILENOTIFY_COPYERROR,
-                       (UINT_PTR)&FilePathInfo,
-                       (UINT_PTR)NULL); // FIXME: Unused yet...
+            Result = MsgHandler(Context,
+                                SPFILENOTIFY_COPYERROR,
+                                (UINT_PTR)&FilePathInfo,
+                                (UINT_PTR)NULL); // FIXME: Unused yet...
+            if (Result == FILEOP_ABORT)
+            {
+                Success = FALSE;
+                goto EndCopy;
+            }
+            else if (Result == FILEOP_SKIP)
+                goto EndCopy;
+            else if (Result == FILEOP_RETRY)
+                goto RetryCopy;
+            else if (Result == FILEOP_NEWPATH)
+                goto RetryCopy; // TODO!
+
             Success = FALSE;
         }
 
+EndCopy:
         /* This notification is always sent, even in case of error */
         FilePathInfo.Win32Error = (UINT)Status;
         MsgHandler(Context,
                    SPFILENOTIFY_ENDCOPY,
                    (UINT_PTR)&FilePathInfo,
                    0);
+        if (Success == FALSE /* && Result == FILEOP_ABORT */)
+            goto Quit;
     }
 
-    MsgHandler(Context,
-               SPFILENOTIFY_ENDSUBQUEUE,
-               FILEOP_COPY,
-               0);
+    if (!IsListEmpty(&QueueHeader->CopyQueue))
+    {
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDSUBQUEUE,
+                   FILEOP_COPY,
+                   0);
+    }
 
 
+Quit:
     /* All the queues have been committed */
     MsgHandler(Context,
                SPFILENOTIFY_ENDQUEUE,
index 7fe24fc..46da942 100644 (file)
@@ -4103,8 +4103,12 @@ FileCopyCallback(PVOID Context,
                 if (DstFileName) ++DstFileName;
                 else DstFileName = FilePathInfo->Target;
 
-                // TODO: Determine whether using STRING_RENAMING or STRING_MOVING
-                CONSOLE_SetStatusText(MUIGetString(STRING_MOVING),
+                if (!wcsicmp(SrcFileName, DstFileName))
+                    Param2 = STRING_MOVING;
+                else
+                    Param2 = STRING_RENAMING;
+
+                CONSOLE_SetStatusText(MUIGetString(Param2),
                                       SrcFileName, DstFileName);
             }
             else if (Notification == SPFILENOTIFY_STARTCOPY)
@@ -4112,18 +4116,28 @@ FileCopyCallback(PVOID Context,
                 /* Display copy message */
                 ASSERT(Param2 == FILEOP_COPY);
 
-                SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
-                if (SrcFileName) ++SrcFileName;
-                else SrcFileName = FilePathInfo->Source;
+                /* 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),
-                                      SrcFileName);
+                                      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: