[USETUP] Improvements for the File-queues code.
authorHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Fri, 5 Jan 2018 01:08:59 +0000 (02:08 +0100)
committerHermès Bélusca-Maïto <hermes.belusca-maito@reactos.org>
Thu, 1 Nov 2018 17:55:35 +0000 (18:55 +0100)
- Add support for delete and move/rename operations, which are needed
  for implementing ReactOS upgrading support.

- Use cabinet contexts.
- Use standard LIST_ENTRY structures for implementing the lists.

- Move the path-building hack code in SetupCommitFileQueueW() that had
  been introduced in r66604 (97bb83f) out of the file-queues code.

- Make the function prototypes compatible with win32's setupapi functions.
- Fix the format of the data passed to the custom notification handler.
- Adjust the file-copy callback to correctly use its arguments (setupapi-compatible).

base/setup/usetup/filequeue.c
base/setup/usetup/filequeue.h
base/setup/usetup/usetup.c

index bb1f712..c50203c 100644 (file)
 
 typedef struct _QUEUEENTRY
 {
 
 typedef struct _QUEUEENTRY
 {
-    struct _QUEUEENTRY *Prev;
-    struct _QUEUEENTRY *Next;
-
+    LIST_ENTRY ListEntry;
     PWSTR SourceCabinet;    /* May be NULL if the file is not in a cabinet */
     PWSTR SourceRootPath;
     PWSTR SourcePath;
     PWSTR SourceCabinet;    /* May be NULL if the file is not in a cabinet */
     PWSTR SourceRootPath;
     PWSTR SourcePath;
-    PWSTR SourceFilename;
+    PWSTR SourceFileName;
     PWSTR TargetDirectory;
     PWSTR TargetDirectory;
-    PWSTR TargetFilename;
+    PWSTR TargetFileName;
 } QUEUEENTRY, *PQUEUEENTRY;
 
 } QUEUEENTRY, *PQUEUEENTRY;
 
-
 typedef struct _FILEQUEUEHEADER
 {
 typedef struct _FILEQUEUEHEADER
 {
-    PQUEUEENTRY CopyHead;
-    PQUEUEENTRY CopyTail;
+    LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
+    ULONG DeleteCount;
+
+    LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
+    ULONG RenameCount;
+
+    LIST_ENTRY CopyQueue;   // PQUEUEENTRY entries
     ULONG CopyCount;
     ULONG CopyCount;
+
+    BOOLEAN HasCurrentCabinet;
+    CABINET_CONTEXT CabinetContext;
+    CAB_SEARCH Search;
+    WCHAR CurrentCabinetName[MAX_PATH];
 } FILEQUEUEHEADER, *PFILEQUEUEHEADER;
 
 
 } FILEQUEUEHEADER, *PFILEQUEUEHEADER;
 
 
-/* FUNCTIONS ****************************************************************/
-
-static BOOLEAN HasCurrentCabinet = FALSE;
-static WCHAR CurrentCabinetName[MAX_PATH];
-static CAB_SEARCH Search;
-
-// HACK: Temporary compatibility code.
-#if 1
-    static CABINET_CONTEXT CabinetContext;
-    #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
-    #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
-    #define CabinetSetCabinetName(a) (CabinetSetCabinetName(&CabinetContext,(a)))
-    #define CabinetOpen() (CabinetOpen(&CabinetContext))
-    #define CabinetGetCabinetName() (CabinetGetCabinetName(&CabinetContext))
-    #define CabinetGetCabinetReservedArea(a) (CabinetGetCabinetReservedArea(&CabinetContext,(a)))
-    #define CabinetFindNextFileSequential(a,b) (CabinetFindNextFileSequential(&CabinetContext,(a),(b)))
-    #define CabinetFindFirst(a,b) (CabinetFindFirst(&CabinetContext,(a),(b)))
-    #define CabinetSetDestinationPath(a) (CabinetSetDestinationPath(&CabinetContext,(a)))
-    #define CabinetExtractFile(a) (CabinetExtractFile(&CabinetContext,(a)))
-    #define CabinetCleanup() (CabinetCleanup(&CabinetContext))
-#endif
-
-NTSTATUS
+/* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
+
+static NTSTATUS
 SetupExtractFile(
 SetupExtractFile(
-    PWCHAR CabinetFileName,
-    PWCHAR SourceFileName,
-    PWCHAR DestinationPathName)
+    IN OUT PFILEQUEUEHEADER QueueHeader,
+    IN PCWSTR CabinetFileName,
+    IN PCWSTR SourceFileName,
+    IN PCWSTR DestinationPathName)
 {
     ULONG CabStatus;
 
 {
     ULONG CabStatus;
 
-    DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
+    DPRINT("SetupExtractFile(CabinetFileName: '%S', SourceFileName: '%S', DestinationPathName: '%S')\n",
            CabinetFileName, SourceFileName, DestinationPathName);
 
            CabinetFileName, SourceFileName, DestinationPathName);
 
-    if (HasCurrentCabinet)
+    if (QueueHeader->HasCurrentCabinet)
     {
     {
-        DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName);
+        DPRINT("CurrentCabinetName: '%S'\n", QueueHeader->CurrentCabinetName);
     }
 
     }
 
-    if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0))
+    if (QueueHeader->HasCurrentCabinet &&
+        (wcscmp(CabinetFileName, QueueHeader->CurrentCabinetName) == 0))
     {
         DPRINT("Using same cabinet as last time\n");
 
         /* Use our last location because the files should be sequential */
     {
         DPRINT("Using same cabinet as last time\n");
 
         /* Use our last location because the files should be sequential */
-        CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search);
+        CabStatus = CabinetFindNextFileSequential(&QueueHeader->CabinetContext,
+                                                  SourceFileName,
+                                                  &QueueHeader->Search);
         if (CabStatus != CAB_STATUS_SUCCESS)
         {
             DPRINT("Sequential miss on file: %S\n", SourceFileName);
 
             /* Looks like we got unlucky */
         if (CabStatus != CAB_STATUS_SUCCESS)
         {
             DPRINT("Sequential miss on file: %S\n", SourceFileName);
 
             /* Looks like we got unlucky */
-            CabStatus = CabinetFindFirst(SourceFileName, &Search);
+            CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
+                                         SourceFileName,
+                                         &QueueHeader->Search);
         }
     }
     else
     {
         DPRINT("Using new cabinet\n");
 
         }
     }
     else
     {
         DPRINT("Using new cabinet\n");
 
-        if (HasCurrentCabinet)
+        if (QueueHeader->HasCurrentCabinet)
         {
         {
-            CabinetCleanup();
+            QueueHeader->HasCurrentCabinet = FALSE;
+            CabinetCleanup(&QueueHeader->CabinetContext);
         }
 
         }
 
-        wcscpy(CurrentCabinetName, CabinetFileName);
+        RtlStringCchCopyW(QueueHeader->CurrentCabinetName,
+                          ARRAYSIZE(QueueHeader->CurrentCabinetName),
+                          CabinetFileName);
 
 
-        CabinetInitialize();
-        CabinetSetEventHandlers(NULL, NULL, NULL);
-        CabinetSetCabinetName(CabinetFileName);
+        CabinetInitialize(&QueueHeader->CabinetContext);
+        CabinetSetEventHandlers(&QueueHeader->CabinetContext,
+                                NULL, NULL, NULL);
+        CabinetSetCabinetName(&QueueHeader->CabinetContext, CabinetFileName);
 
 
-        CabStatus = CabinetOpen();
+        CabStatus = CabinetOpen(&QueueHeader->CabinetContext);
         if (CabStatus == CAB_STATUS_SUCCESS)
         {
         if (CabStatus == CAB_STATUS_SUCCESS)
         {
-            DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
-            HasCurrentCabinet = TRUE;
+            DPRINT("Opened cabinet %S\n", CabinetFileName /*CabinetGetCabinetName(&QueueHeader->CabinetContext)*/);
+            QueueHeader->HasCurrentCabinet = TRUE;
         }
         else
         {
         }
         else
         {
@@ -134,17 +131,20 @@ SetupExtractFile(
         }
 
         /* We have to start at the beginning here */
         }
 
         /* We have to start at the beginning here */
-        CabStatus = CabinetFindFirst(SourceFileName, &Search);
+        CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
+                                     SourceFileName,
+                                     &QueueHeader->Search);
     }
 
     if (CabStatus != CAB_STATUS_SUCCESS)
     {
     }
 
     if (CabStatus != CAB_STATUS_SUCCESS)
     {
-        DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName());
+        DPRINT1("Unable to find '%S' in cabinet '%S'\n",
+                SourceFileName, CabinetGetCabinetName(&QueueHeader->CabinetContext));
         return STATUS_UNSUCCESSFUL;
     }
 
         return STATUS_UNSUCCESSFUL;
     }
 
-    CabinetSetDestinationPath(DestinationPathName);
-    CabStatus = CabinetExtractFile(&Search);
+    CabinetSetDestinationPath(&QueueHeader->CabinetContext, DestinationPathName);
+    CabStatus = CabinetExtractFile(&QueueHeader->CabinetContext, &QueueHeader->Search);
     if (CabStatus != CAB_STATUS_SUCCESS)
     {
         DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
     if (CabStatus != CAB_STATUS_SUCCESS)
     {
         DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
@@ -160,27 +160,63 @@ SetupOpenFileQueue(VOID)
 {
     PFILEQUEUEHEADER QueueHeader;
 
 {
     PFILEQUEUEHEADER QueueHeader;
 
-    /* Allocate queue header */
-    QueueHeader = (PFILEQUEUEHEADER)RtlAllocateHeap(ProcessHeap,
-                                                    0,
-                                                    sizeof(FILEQUEUEHEADER));
+    /* Allocate the queue header */
+    QueueHeader = RtlAllocateHeap(ProcessHeap, 0, sizeof(FILEQUEUEHEADER));
     if (QueueHeader == NULL)
         return NULL;
 
     if (QueueHeader == NULL)
         return NULL;
 
-    /* Initialize queue header */
-    RtlZeroMemory(QueueHeader,
-                  sizeof(FILEQUEUEHEADER));
+    RtlZeroMemory(QueueHeader, sizeof(FILEQUEUEHEADER));
+
+    /* Initialize the file queues */
+    InitializeListHead(&QueueHeader->DeleteQueue);
+    QueueHeader->DeleteCount = 0;
+    InitializeListHead(&QueueHeader->RenameQueue);
+    QueueHeader->RenameCount = 0;
+    InitializeListHead(&QueueHeader->CopyQueue);
+    QueueHeader->CopyCount = 0;
+
+    QueueHeader->HasCurrentCabinet = FALSE;
 
     return (HSPFILEQ)QueueHeader;
 }
 
 
     return (HSPFILEQ)QueueHeader;
 }
 
+static VOID
+SetupDeleteQueueEntry(
+    IN PQUEUEENTRY Entry)
+{
+    if (Entry == NULL)
+        return;
+
+    /* Delete all strings */
+    if (Entry->SourceCabinet != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+    if (Entry->SourceRootPath != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+
+    if (Entry->SourcePath != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+
+    if (Entry->SourceFileName != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+    if (Entry->TargetDirectory != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
+
+    if (Entry->TargetFileName != NULL)
+        RtlFreeHeap(ProcessHeap, 0, Entry->TargetFileName);
+
+    /* Delete queue entry */
+    RtlFreeHeap(ProcessHeap, 0, Entry);
+}
 
 VOID
 WINAPI
 SetupCloseFileQueue(
 
 VOID
 WINAPI
 SetupCloseFileQueue(
-    HSPFILEQ QueueHandle)
+    IN HSPFILEQ QueueHandle)
 {
     PFILEQUEUEHEADER QueueHeader;
 {
     PFILEQUEUEHEADER QueueHeader;
+    PLIST_ENTRY ListEntry;
     PQUEUEENTRY Entry;
 
     if (QueueHandle == NULL)
     PQUEUEENTRY Entry;
 
     if (QueueHandle == NULL)
@@ -188,71 +224,53 @@ SetupCloseFileQueue(
 
     QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
 
 
     QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
 
-    /* Delete copy queue */
-    Entry = QueueHeader->CopyHead;
-    while (Entry != NULL)
+    /* Delete the delete queue */
+    while (!IsListEmpty(&QueueHeader->DeleteQueue))
     {
     {
-        /* Delete all strings */
-        if (Entry->SourceCabinet != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-
-        if (Entry->SourceRootPath != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
-
-        if (Entry->SourcePath != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
-
-        if (Entry->SourceFilename != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
-
-        if (Entry->TargetDirectory != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
-
-        if (Entry->TargetFilename != NULL)
-            RtlFreeHeap(ProcessHeap, 0, Entry->TargetFilename);
-
-        /* Unlink current queue entry */
-        if (Entry->Next != NULL)
-        {
-            QueueHeader->CopyHead = Entry->Next;
-            QueueHeader->CopyHead->Prev = NULL;
-        }
-        else
-        {
-            QueueHeader->CopyHead = NULL;
-            QueueHeader->CopyTail = NULL;
-        }
+        ListEntry = RemoveHeadList(&QueueHeader->DeleteQueue);
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        SetupDeleteQueueEntry(Entry);
+    }
 
 
-        /* Delete queue entry */
-        RtlFreeHeap(ProcessHeap, 0, Entry);
+    /* Delete the rename queue */
+    while (!IsListEmpty(&QueueHeader->RenameQueue))
+    {
+        ListEntry = RemoveHeadList(&QueueHeader->RenameQueue);
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        SetupDeleteQueueEntry(Entry);
+    }
 
 
-        /* Get next queue entry */
-        Entry = QueueHeader->CopyHead;
+    /* Delete the copy queue */
+    while (!IsListEmpty(&QueueHeader->CopyQueue))
+    {
+        ListEntry = RemoveHeadList(&QueueHeader->CopyQueue);
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        SetupDeleteQueueEntry(Entry);
     }
 
     /* Delete queue header */
     RtlFreeHeap(ProcessHeap, 0, QueueHeader);
 }
 
     }
 
     /* Delete queue header */
     RtlFreeHeap(ProcessHeap, 0, QueueHeader);
 }
 
-
+/* A simplified version of SetupQueueCopyW that wraps Cabinet support around */
 BOOL
 BOOL
-SetupQueueCopy(
-    HSPFILEQ QueueHandle,
-    PCWSTR SourceCabinet,
-    PCWSTR SourceRootPath,
-    PCWSTR SourcePath,
-    PCWSTR SourceFilename,
-    PCWSTR TargetDirectory,
-    PCWSTR TargetFilename)
+WINAPI
+SetupQueueCopyWithCab(          // SetupQueueCopyW
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR SourceCabinet OPTIONAL,
+    IN PCWSTR SourceRootPath,
+    IN PCWSTR SourcePath OPTIONAL,
+    IN PCWSTR SourceFileName,
+    IN PCWSTR TargetDirectory,
+    IN PCWSTR TargetFileName OPTIONAL)
 {
     PFILEQUEUEHEADER QueueHeader;
     PQUEUEENTRY Entry;
     ULONG Length;
 
 {
     PFILEQUEUEHEADER QueueHeader;
     PQUEUEENTRY Entry;
     ULONG Length;
 
-    /* SourceCabinet may be NULL */
     if (QueueHandle == NULL ||
         SourceRootPath == NULL ||
     if (QueueHandle == NULL ||
         SourceRootPath == NULL ||
-        SourceFilename == NULL ||
+        SourceFileName == NULL ||
         TargetDirectory == NULL)
     {
         return FALSE;
         TargetDirectory == NULL)
     {
         return FALSE;
@@ -260,194 +278,351 @@ SetupQueueCopy(
 
     QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
 
 
     QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
 
+    DPRINT("SetupQueueCopy(Cab '%S', SrcRootPath '%S', SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
+           SourceCabinet ? SourceCabinet : L"n/a",
+           SourceRootPath, SourcePath, SourceFileName,
+           TargetDirectory, TargetFileName);
+
     /* Allocate new queue entry */
     /* Allocate new queue entry */
-    Entry = (PQUEUEENTRY)RtlAllocateHeap(ProcessHeap,
-                                         0,
-                                         sizeof(QUEUEENTRY));
+    Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
     if (Entry == NULL)
         return FALSE;
 
     if (Entry == NULL)
         return FALSE;
 
-    RtlZeroMemory(Entry,
-                  sizeof(QUEUEENTRY));
+    RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
 
     /* Copy source cabinet if available */
 
     /* Copy source cabinet if available */
+    Entry->SourceCabinet = NULL;
     if (SourceCabinet != NULL)
     {
         Length = wcslen(SourceCabinet);
     if (SourceCabinet != NULL)
     {
         Length = wcslen(SourceCabinet);
-        Entry->SourceCabinet = (WCHAR*)RtlAllocateHeap(ProcessHeap,
-                                                       0,
-                                                       (Length + 1) * sizeof(WCHAR));
+        Entry->SourceCabinet = RtlAllocateHeap(ProcessHeap,
+                                               0,
+                                               (Length + 1) * sizeof(WCHAR));
         if (Entry->SourceCabinet == NULL)
         {
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
         if (Entry->SourceCabinet == NULL)
         {
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
-
-        wcsncpy(Entry->SourceCabinet, SourceCabinet, Length);
-        Entry->SourceCabinet[Length] = UNICODE_NULL;
-    }
-    else
-    {
-        Entry->SourceCabinet = NULL;
+        RtlStringCchCopyW(Entry->SourceCabinet, Length + 1, SourceCabinet);
     }
 
     /* Copy source root path */
     Length = wcslen(SourceRootPath);
     }
 
     /* Copy source root path */
     Length = wcslen(SourceRootPath);
-    Entry->SourceRootPath = (WCHAR*)RtlAllocateHeap(ProcessHeap,
-                                                    0,
-                                                    (Length + 1) * sizeof(WCHAR));
+    Entry->SourceRootPath = RtlAllocateHeap(ProcessHeap,
+                                            0,
+                                            (Length + 1) * sizeof(WCHAR));
     if (Entry->SourceRootPath == NULL)
     {
         if (Entry->SourceCabinet != NULL)
     if (Entry->SourceRootPath == NULL)
     {
         if (Entry->SourceCabinet != NULL)
-        {
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-        }
 
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
 
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
-
-    wcsncpy(Entry->SourceRootPath, SourceRootPath, Length);
-    Entry->SourceRootPath[Length] = UNICODE_NULL;
+    RtlStringCchCopyW(Entry->SourceRootPath, Length + 1, SourceRootPath);
 
     /* Copy source path */
 
     /* Copy source path */
+    Entry->SourcePath = NULL;
     if (SourcePath != NULL)
     {
         Length = wcslen(SourcePath);
         if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
             Length--;
     if (SourcePath != NULL)
     {
         Length = wcslen(SourcePath);
         if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
             Length--;
-        Entry->SourcePath = (WCHAR*)RtlAllocateHeap(ProcessHeap,
-                                                    0,
-                                                    (Length + 1) * sizeof(WCHAR));
+        Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
+                                            0,
+                                            (Length + 1) * sizeof(WCHAR));
         if (Entry->SourcePath == NULL)
         {
             if (Entry->SourceCabinet != NULL)
         if (Entry->SourcePath == NULL)
         {
             if (Entry->SourceCabinet != NULL)
-            {
                 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
                 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-            }
 
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
 
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
-
-        wcsncpy(Entry->SourcePath, SourcePath, Length);
-        Entry->SourcePath[Length] = UNICODE_NULL;
+        RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
     }
 
     /* Copy source file name */
     }
 
     /* Copy source file name */
-    Length = wcslen(SourceFilename);
-    Entry->SourceFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
+    Length = wcslen(SourceFileName);
+    Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
                                                     0,
                                                     (Length + 1) * sizeof(WCHAR));
                                                     0,
                                                     (Length + 1) * sizeof(WCHAR));
-    if (Entry->SourceFilename == NULL)
+    if (Entry->SourceFileName == NULL)
     {
     {
+        if (Entry->SourcePath != NULL)
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+
         if (Entry->SourceCabinet != NULL)
         if (Entry->SourceCabinet != NULL)
-        {
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-        }
 
 
-        RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
-        RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
-
-    wcsncpy(Entry->SourceFilename, SourceFilename, Length);
-    Entry->SourceFilename[Length] = UNICODE_NULL;
+    RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
 
     /* Copy target directory */
     Length = wcslen(TargetDirectory);
     if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
         Length--;
 
     /* Copy target directory */
     Length = wcslen(TargetDirectory);
     if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
         Length--;
-    Entry->TargetDirectory = (WCHAR*)RtlAllocateHeap(ProcessHeap,
-                                                     0,
-                                                     (Length + 1) * sizeof(WCHAR));
+    Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
+                                             0,
+                                             (Length + 1) * sizeof(WCHAR));
     if (Entry->TargetDirectory == NULL)
     {
     if (Entry->TargetDirectory == NULL)
     {
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+        if (Entry->SourcePath != NULL)
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+
         if (Entry->SourceCabinet != NULL)
         if (Entry->SourceCabinet != NULL)
-        {
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
             RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-        }
 
 
-        RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
-        RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
-        RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
         RtlFreeHeap(ProcessHeap, 0, Entry);
         return FALSE;
     }
-
-    wcsncpy(Entry->TargetDirectory, TargetDirectory, Length);
-    Entry->TargetDirectory[Length] = UNICODE_NULL;
+    RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetDirectory);
 
     /* Copy optional target filename */
 
     /* Copy optional target filename */
-    if (TargetFilename != NULL)
+    Entry->TargetFileName = NULL;
+    if (TargetFileName != NULL)
     {
     {
-        Length = wcslen(TargetFilename);
-        Entry->TargetFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
-                                                        0,
-                                                        (Length + 1) * sizeof(WCHAR));
-        if (Entry->TargetFilename == NULL)
+        Length = wcslen(TargetFileName);
+        Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
+                                                0,
+                                                (Length + 1) * sizeof(WCHAR));
+        if (Entry->TargetFileName == NULL)
         {
         {
+            RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+            if (Entry->SourcePath != NULL)
+                RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+
             if (Entry->SourceCabinet != NULL)
             if (Entry->SourceCabinet != NULL)
-            {
                 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
                 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
-            }
 
 
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
-            RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
-            RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
             RtlFreeHeap(ProcessHeap, 0, Entry);
             return FALSE;
         }
-
-        wcsncpy(Entry->TargetFilename, TargetFilename, Length);
-        Entry->TargetFilename[Length] = UNICODE_NULL;
+        RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
     }
 
     /* Append queue entry */
     }
 
     /* Append queue entry */
-    if (QueueHeader->CopyHead == NULL) // && QueueHeader->CopyTail == NULL)
+    InsertTailList(&QueueHeader->CopyQueue, &Entry->ListEntry);
+    ++QueueHeader->CopyCount;
+
+    return TRUE;
+}
+
+BOOL
+WINAPI
+SetupQueueDeleteW(
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR PathPart1,
+    IN PCWSTR PathPart2 OPTIONAL)
+{
+    PFILEQUEUEHEADER QueueHeader;
+    PQUEUEENTRY Entry;
+    ULONG Length;
+
+    if (QueueHandle == NULL || PathPart1 == NULL)
     {
     {
-        Entry->Prev = NULL;
-        Entry->Next = NULL;
-        QueueHeader->CopyHead = Entry;
-        QueueHeader->CopyTail = Entry;
+        return FALSE;
     }
     }
-    else
+
+    QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
+
+    DPRINT1("SetupQueueDeleteW(PathPart1 '%S', PathPart2 '%S')\n",
+           PathPart1, PathPart2);
+
+    /* Allocate new queue entry */
+    Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
+    if (Entry == NULL)
+        return FALSE;
+
+    RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
+
+    Entry->SourceCabinet = NULL;
+    Entry->SourceRootPath = NULL;
+    Entry->SourcePath = NULL;
+    Entry->SourceFileName = NULL;
+
+    /* Copy first part of path */
+    Length = wcslen(PathPart1);
+    // if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
+        // Length--;
+    Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
+                                             0,
+                                             (Length + 1) * sizeof(WCHAR));
+    if (Entry->TargetDirectory == NULL)
     {
     {
-        Entry->Prev = QueueHeader->CopyTail;
-        Entry->Next = NULL;
-        QueueHeader->CopyTail->Next = Entry;
-        QueueHeader->CopyTail = Entry;
+        RtlFreeHeap(ProcessHeap, 0, Entry);
+        return FALSE;
+    }
+    RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, PathPart1);
+
+    /* Copy optional second part of path */
+    if (PathPart2 != NULL)
+    {
+        Length = wcslen(PathPart2);
+        Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
+                                                0,
+                                                (Length + 1) * sizeof(WCHAR));
+        if (Entry->TargetFileName == NULL)
+        {
+            RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
+            RtlFreeHeap(ProcessHeap, 0, Entry);
+            return FALSE;
+        }
+        RtlStringCchCopyW(Entry->TargetFileName, Length + 1, PathPart2);
     }
 
     }
 
-    QueueHeader->CopyCount++;
+    /* Append the queue entry */
+    InsertTailList(&QueueHeader->DeleteQueue, &Entry->ListEntry);
+    ++QueueHeader->DeleteCount;
 
     return TRUE;
 }
 
 
     return TRUE;
 }
 
+BOOL
+WINAPI
+SetupQueueRenameW(
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR SourcePath,
+    IN PCWSTR SourceFileName OPTIONAL,
+    IN PCWSTR TargetPath OPTIONAL,
+    IN PCWSTR TargetFileName)
+{
+    PFILEQUEUEHEADER QueueHeader;
+    PQUEUEENTRY Entry;
+    ULONG Length;
+
+    if (QueueHandle == NULL ||
+        SourcePath  == NULL ||
+        TargetFileName == NULL)
+    {
+        return FALSE;
+    }
+
+    QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
+
+    DPRINT1("SetupQueueRenameW(SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
+           SourcePath, SourceFileName, TargetPath, TargetFileName);
+
+    /* Allocate a new queue entry */
+    Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
+    if (Entry == NULL)
+        return FALSE;
+
+    RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
+
+    Entry->SourceCabinet  = NULL;
+    Entry->SourceRootPath = NULL;
+
+    /* Copy source path */
+    Length = wcslen(SourcePath);
+    if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
+        Length--;
+    Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
+                                        0,
+                                        (Length + 1) * sizeof(WCHAR));
+    if (Entry->SourcePath == NULL)
+    {
+        RtlFreeHeap(ProcessHeap, 0, Entry);
+        return FALSE;
+    }
+    RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
+
+    /* Copy optional source file name */
+    Entry->SourceFileName = NULL;
+    if (SourceFileName != NULL)
+    {
+        Length = wcslen(SourceFileName);
+        Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
+                                                        0,
+                                                        (Length + 1) * sizeof(WCHAR));
+        if (Entry->SourceFileName == NULL)
+        {
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+            RtlFreeHeap(ProcessHeap, 0, Entry);
+            return FALSE;
+        }
+        RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
+    }
+
+    /* Copy optional target directory */
+    Entry->TargetDirectory = NULL;
+    if (TargetPath != NULL)
+    {
+        Length = wcslen(TargetPath);
+        if ((Length > 0) && (TargetPath[Length - 1] == L'\\'))
+            Length--;
+        Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
+                                                 0,
+                                                 (Length + 1) * sizeof(WCHAR));
+        if (Entry->TargetDirectory == NULL)
+        {
+            if (Entry->SourceFileName != NULL)
+                RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+            RtlFreeHeap(ProcessHeap, 0, Entry);
+            return FALSE;
+        }
+        RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetPath);
+    }
+
+    /* Copy target filename */
+    Length = wcslen(TargetFileName);
+    Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
+                                            0,
+                                            (Length + 1) * sizeof(WCHAR));
+    if (Entry->TargetFileName == NULL)
+    {
+        if (Entry->TargetDirectory != NULL)
+            RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
+
+        if (Entry->SourceFileName != NULL)
+            RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+        RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+        RtlFreeHeap(ProcessHeap, 0, Entry);
+        return FALSE;
+    }
+    RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
+
+    /* Append the queue entry */
+    InsertTailList(&QueueHeader->RenameQueue, &Entry->ListEntry);
+    ++QueueHeader->RenameCount;
+
+    return TRUE;
+}
 
 BOOL
 WINAPI
 SetupCommitFileQueueW(
 
 BOOL
 WINAPI
 SetupCommitFileQueueW(
-    HWND Owner,
-    HSPFILEQ QueueHandle,
-    PSP_FILE_CALLBACK_W MsgHandler,
-    PVOID Context)
+    IN HWND Owner,
+    IN HSPFILEQ QueueHandle,
+    IN PSP_FILE_CALLBACK_W MsgHandler,
+    IN PVOID Context OPTIONAL)
 {
 {
-    WCHAR CabinetName[MAX_PATH];
+    BOOL Success = TRUE; // Suppose success
+    NTSTATUS Status;
     PFILEQUEUEHEADER QueueHeader;
     PFILEQUEUEHEADER QueueHeader;
+    PLIST_ENTRY ListEntry;
     PQUEUEENTRY Entry;
     PQUEUEENTRY Entry;
-    NTSTATUS Status;
-    PCWSTR TargetRootPath, TargetPath;
-
+    FILEPATHS_W FilePathInfo;
+    WCHAR CabinetName[MAX_PATH];
     WCHAR FileSrcPath[MAX_PATH];
     WCHAR FileDstPath[MAX_PATH];
 
     WCHAR FileSrcPath[MAX_PATH];
     WCHAR FileDstPath[MAX_PATH];
 
-    TargetRootPath = ((PCOPYCONTEXT)Context)->DestinationRootPath;
-    TargetPath = ((PCOPYCONTEXT)Context)->InstallPath;
-
     if (QueueHandle == NULL)
         return FALSE;
 
     if (QueueHandle == NULL)
         return FALSE;
 
@@ -455,74 +630,203 @@ SetupCommitFileQueueW(
 
     MsgHandler(Context,
                SPFILENOTIFY_STARTQUEUE,
 
     MsgHandler(Context,
                SPFILENOTIFY_STARTQUEUE,
-               0,
+               (UINT_PTR)Owner,
                0);
 
                0);
 
+
+    /*
+     * Commit the delete queue
+     */
+
     MsgHandler(Context,
                SPFILENOTIFY_STARTSUBQUEUE,
     MsgHandler(Context,
                SPFILENOTIFY_STARTSUBQUEUE,
-               FILEOP_COPY,
-               QueueHeader->CopyCount);
+               FILEOP_DELETE,
+               QueueHeader->DeleteCount);
 
 
-    /* Commit copy queue */
-    Entry = QueueHeader->CopyHead;
-    while (Entry != NULL)
+    ListEntry = QueueHeader->DeleteQueue.Flink;
+    while (ListEntry != &QueueHeader->DeleteQueue)
     {
     {
-        /* Build the full source path */
-        CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
-                     Entry->SourceRootPath, Entry->SourcePath,
-                     Entry->SourceFilename);
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        ListEntry = ListEntry->Flink;
 
         /* Build the full target path */
 
         /* Build the full target path */
-        wcscpy(FileDstPath, TargetRootPath);
-        if (Entry->TargetDirectory[0] == UNICODE_NULL)
-        {
-            /* Installation path */
+        CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
+                     Entry->TargetDirectory, Entry->TargetFileName);
+        // RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
+        // ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
 
 
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, TargetPath);
-        }
-        else if (Entry->TargetDirectory[0] == L'\\')
+        DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath);
+
+        FilePathInfo.Target = FileDstPath;
+        FilePathInfo.Source = NULL;
+        FilePathInfo.Win32Error = STATUS_SUCCESS;
+        FilePathInfo.Flags = 0; // FIXME: Unused yet...
+
+        MsgHandler(Context,
+                   SPFILENOTIFY_STARTDELETE,
+                   (UINT_PTR)&FilePathInfo,
+                   FILEOP_DELETE);
+
+        /* Force-delete the file */
+        Status = SetupDeleteFile(FileDstPath, TRUE);
+        if (!NT_SUCCESS(Status))
         {
         {
-            /* Absolute path */
-            if (Entry->TargetDirectory[1] != UNICODE_NULL)
-                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetDirectory);
+            /* An error happened */
+            FilePathInfo.Win32Error = (UINT)Status;
+            MsgHandler(Context,
+                       SPFILENOTIFY_DELETEERROR,
+                       (UINT_PTR)&FilePathInfo,
+                       0);
+            Success = FALSE;
         }
         }
-        else // if (Entry->TargetDirectory[0] != L'\\')
-        {
-            /* Path relative to the installation path */
 
 
-            /* Add the installation path */
-            ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
-                        TargetPath, Entry->TargetDirectory);
+        /* This notification is always sent, even in case of error */
+        FilePathInfo.Win32Error = (UINT)Status;
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDDELETE,
+                   (UINT_PTR)&FilePathInfo,
+                   0);
+    }
+
+    MsgHandler(Context,
+               SPFILENOTIFY_ENDSUBQUEUE,
+               FILEOP_DELETE,
+               0);
+
+
+    /*
+     * Commit the rename queue
+     */
+
+    MsgHandler(Context,
+               SPFILENOTIFY_STARTSUBQUEUE,
+               FILEOP_RENAME,
+               QueueHeader->RenameCount);
+
+    ListEntry = QueueHeader->RenameQueue.Flink;
+    while (ListEntry != &QueueHeader->RenameQueue)
+    {
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        ListEntry = ListEntry->Flink;
+
+        /* Build the full source path */
+        CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2,
+                     Entry->SourcePath, Entry->SourceFileName);
+
+        /* 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);
+
+        FilePathInfo.Target = FileDstPath;
+        FilePathInfo.Source = FileSrcPath;
+        FilePathInfo.Win32Error = STATUS_SUCCESS;
+        FilePathInfo.Flags = 0; // FIXME: Unused yet...
+
+        MsgHandler(Context,
+                   SPFILENOTIFY_STARTRENAME,
+                   (UINT_PTR)&FilePathInfo,
+                   FILEOP_RENAME);
+
+        /* Move or rename the file */
+        Status = SetupMoveFile(FileSrcPath, FileDstPath,
+                               MOVEFILE_REPLACE_EXISTING
+                                    | MOVEFILE_COPY_ALLOWED
+                                    | MOVEFILE_WRITE_THROUGH);
+        if (!NT_SUCCESS(Status))
+        {
+            /* An error happened */
+            FilePathInfo.Win32Error = (UINT)Status;
+            MsgHandler(Context,
+                       SPFILENOTIFY_RENAMEERROR,
+                       (UINT_PTR)&FilePathInfo,
+                       0);
+            Success = FALSE;
         }
 
         }
 
+        /* This notification is always sent, even in case of error */
+        FilePathInfo.Win32Error = (UINT)Status;
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDRENAME,
+                   (UINT_PTR)&FilePathInfo,
+                   0);
+    }
+
+    MsgHandler(Context,
+               SPFILENOTIFY_ENDSUBQUEUE,
+               FILEOP_RENAME,
+               0);
+
+
+    /*
+     * Commit the copy queue
+     */
+
+    MsgHandler(Context,
+               SPFILENOTIFY_STARTSUBQUEUE,
+               FILEOP_COPY,
+               QueueHeader->CopyCount);
+
+    ListEntry = QueueHeader->CopyQueue.Flink;
+    while (ListEntry != &QueueHeader->CopyQueue)
+    {
+        Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+        ListEntry = ListEntry->Flink;
+
+        /* Build the full source path */
+        CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
+                     Entry->SourceRootPath, Entry->SourcePath,
+                     Entry->SourceFileName);
+
+        /* 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 in a cabinet, use only the destination path.
          * Otherwise possibly use a different target name.
          */
         if (Entry->SourceCabinet == NULL)
         {
-            if (Entry->TargetFilename != NULL)
-                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFilename);
+            if (Entry->TargetFileName != NULL)
+                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
             else
             else
-                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFilename);
+                ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
         }
 
         }
 
-        /* FIXME: Do it! */
-        DPRINT("Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
+        DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
+
+        //
+        // Technically, here we should create the target directory,
+        // if it does not already exist... before calling the handler!
+        //
+
+        FilePathInfo.Target = FileDstPath;
+        FilePathInfo.Source = FileSrcPath; // when SourceCabinet not NULL, use CabinetName ...
+        FilePathInfo.Win32Error = STATUS_SUCCESS;
+        FilePathInfo.Flags = 0; // FIXME: Unused yet...
 
         MsgHandler(Context,
                    SPFILENOTIFY_STARTCOPY,
 
         MsgHandler(Context,
                    SPFILENOTIFY_STARTCOPY,
-                   (UINT_PTR)Entry->SourceFilename,
+                   (UINT_PTR)&FilePathInfo,
                    FILEOP_COPY);
 
         if (Entry->SourceCabinet != NULL)
         {
                    FILEOP_COPY);
 
         if (Entry->SourceCabinet != NULL)
         {
-            /* Extract the file */
+            /*
+             * Extract the file from the cabinet.
+             * The cabinet must be in Entry->SourceRootPath only!
+             * (ignore Entry->SourcePath).
+             */
             CombinePaths(CabinetName, ARRAYSIZE(CabinetName), 3,
                          Entry->SourceRootPath, Entry->SourcePath,
                          Entry->SourceCabinet);
             CombinePaths(CabinetName, ARRAYSIZE(CabinetName), 3,
                          Entry->SourceRootPath, Entry->SourcePath,
                          Entry->SourceCabinet);
-            Status = SetupExtractFile(CabinetName, Entry->SourceFilename, FileDstPath);
+            Status = SetupExtractFile(QueueHeader,
+                                      CabinetName,
+                                      Entry->SourceFileName,
+                                      FileDstPath);
         }
         else
         {
         }
         else
         {
@@ -532,20 +836,21 @@ SetupCommitFileQueueW(
 
         if (!NT_SUCCESS(Status))
         {
 
         if (!NT_SUCCESS(Status))
         {
+            /* An error happened */
+            FilePathInfo.Win32Error = (UINT)Status;
             MsgHandler(Context,
                        SPFILENOTIFY_COPYERROR,
             MsgHandler(Context,
                        SPFILENOTIFY_COPYERROR,
-                       (UINT_PTR)Entry->SourceFilename,
-                       FILEOP_COPY);
-        }
-        else
-        {
-            MsgHandler(Context,
-                       SPFILENOTIFY_ENDCOPY,
-                       (UINT_PTR)Entry->SourceFilename,
-                       FILEOP_COPY);
+                       (UINT_PTR)&FilePathInfo,
+                       (UINT_PTR)NULL); // FIXME: Unused yet...
+            Success = FALSE;
         }
 
         }
 
-        Entry = Entry->Next;
+        /* This notification is always sent, even in case of error */
+        FilePathInfo.Win32Error = (UINT)Status;
+        MsgHandler(Context,
+                   SPFILENOTIFY_ENDCOPY,
+                   (UINT_PTR)&FilePathInfo,
+                   0);
     }
 
     MsgHandler(Context,
     }
 
     MsgHandler(Context,
@@ -553,12 +858,14 @@ SetupCommitFileQueueW(
                FILEOP_COPY,
                0);
 
                FILEOP_COPY,
                0);
 
+
+    /* All the queues have been committed */
     MsgHandler(Context,
                SPFILENOTIFY_ENDQUEUE,
     MsgHandler(Context,
                SPFILENOTIFY_ENDQUEUE,
-               0,
+               (UINT_PTR)Success,
                0);
 
                0);
 
-    return TRUE;
+    return Success;
 }
 
 /* EOF */
 }
 
 /* EOF */
index 1623440..cf60837 100644 (file)
 
 #pragma once
 
 
 #pragma once
 
-#define SPFILENOTIFY_STARTQUEUE       0x1
-#define SPFILENOTIFY_ENDQUEUE         0x2
-#define SPFILENOTIFY_STARTSUBQUEUE    0x3
-#define SPFILENOTIFY_ENDSUBQUEUE      0x4
+#define SPFILENOTIFY_STARTQUEUE         0x00000001
+#define SPFILENOTIFY_ENDQUEUE           0x00000002
+#define SPFILENOTIFY_STARTSUBQUEUE      0x00000003
+#define SPFILENOTIFY_ENDSUBQUEUE        0x00000004
 
 
-#define SPFILENOTIFY_STARTCOPY        0xb
-#define SPFILENOTIFY_ENDCOPY          0xc
-#define SPFILENOTIFY_COPYERROR        0xd
+#define SPFILENOTIFY_STARTDELETE        0x00000005
+#define SPFILENOTIFY_ENDDELETE          0x00000006
+#define SPFILENOTIFY_DELETEERROR        0x00000007
 
 
-#define FILEOP_COPY                   0x0
-#define FILEOP_RENAME                 0x1
-#define FILEOP_DELETE                 0x2
-#define FILEOP_BACKUP                 0x3
+#define SPFILENOTIFY_STARTRENAME        0x00000008
+#define SPFILENOTIFY_ENDRENAME          0x00000009
+#define SPFILENOTIFY_RENAMEERROR        0x0000000a
 
 
-#define FILEOP_ABORT                  0x0
-#define FILEOP_DOIT                   0x1
-#define FILEOP_SKIP                   0x2
-#define FILEOP_RETRY                  FILEOP_DOIT
-#define FILEOP_NEWPATH                0x4
+#define SPFILENOTIFY_STARTCOPY          0x0000000b
+#define SPFILENOTIFY_ENDCOPY            0x0000000c
+#define SPFILENOTIFY_COPYERROR          0x0000000d
+
+#define SPFILENOTIFY_NEEDMEDIA          0x0000000e
+#define SPFILENOTIFY_QUEUESCAN          0x0000000f
+
+#define FILEOP_COPY                     0
+#define FILEOP_RENAME                   1
+#define FILEOP_DELETE                   2
+#define FILEOP_BACKUP                   3
+
+#define FILEOP_ABORT                    0
+#define FILEOP_DOIT                     1
+#define FILEOP_SKIP                     2
+#define FILEOP_RETRY                    FILEOP_DOIT
+#define FILEOP_NEWPATH                  4
 
 
 /* TYPES ********************************************************************/
 
 typedef PVOID HSPFILEQ;
 
 
 
 /* TYPES ********************************************************************/
 
 typedef PVOID HSPFILEQ;
 
+typedef struct _FILEPATHS_W
+{
+    PCWSTR Target;
+    PCWSTR Source;
+    UINT   Win32Error;
+    ULONG  Flags;
+} FILEPATHS_W, *PFILEPATHS_W;
+
 typedef UINT (CALLBACK* PSP_FILE_CALLBACK_W)(
 typedef UINT (CALLBACK* PSP_FILE_CALLBACK_W)(
-    PVOID Context,
-    UINT Notification,
-    UINT_PTR Param1,
-    UINT_PTR Param2);
+    IN PVOID Context,
+    IN UINT Notification,
+    IN UINT_PTR Param1,
+    IN UINT_PTR Param2);
 
 
-typedef struct _COPYCONTEXT
-{
-    LPCWSTR DestinationRootPath; /* Not owned by this structure */
-    LPCWSTR InstallPath;         /* Not owned by this structure */
-    ULONG TotalOperations;
-    ULONG CompletedOperations;
-    PPROGRESSBAR ProgressBar;
-    PPROGRESSBAR MemoryBars[4];
-} COPYCONTEXT, *PCOPYCONTEXT;
 
 /* FUNCTIONS ****************************************************************/
 
 
 /* FUNCTIONS ****************************************************************/
 
-NTSTATUS
-SetupExtractFile(
-    PWCHAR CabinetFileName,
-    PWCHAR SourceFileName,
-    PWCHAR DestinationFileName);
-
 HSPFILEQ
 WINAPI
 SetupOpenFileQueue(VOID);
 HSPFILEQ
 WINAPI
 SetupOpenFileQueue(VOID);
@@ -99,22 +103,40 @@ SetupQueueCopyWNew(
     IN DWORD CopyStyle);
 #endif
 
     IN DWORD CopyStyle);
 #endif
 
+/* A simplified version of SetupQueueCopyW that wraps Cabinet support around */
+BOOL
+WINAPI
+SetupQueueCopyWithCab(          // SetupQueueCopyW
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR SourceCabinet OPTIONAL,
+    IN PCWSTR SourceRootPath,
+    IN PCWSTR SourcePath OPTIONAL,
+    IN PCWSTR SourceFileName,
+    IN PCWSTR TargetDirectory,
+    IN PCWSTR TargetFileName OPTIONAL);
+
 BOOL
 BOOL
-SetupQueueCopy(
-    HSPFILEQ QueueHandle,
-    PCWSTR SourceCabinet,
-    PCWSTR SourceRootPath,
-    PCWSTR SourcePath,
-    PCWSTR SourceFilename,
-    PCWSTR TargetDirectory,
-    PCWSTR TargetFilename);
+WINAPI
+SetupQueueDeleteW(
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR PathPart1,
+    IN PCWSTR PathPart2 OPTIONAL);
+
+BOOL
+WINAPI
+SetupQueueRenameW(
+    IN HSPFILEQ QueueHandle,
+    IN PCWSTR SourcePath,
+    IN PCWSTR SourceFileName OPTIONAL,
+    IN PCWSTR TargetPath OPTIONAL,
+    IN PCWSTR TargetFileName);
 
 BOOL
 WINAPI
 SetupCommitFileQueueW(
 
 BOOL
 WINAPI
 SetupCommitFileQueueW(
-    HWND Owner,
-    HSPFILEQ QueueHandle,
-    PSP_FILE_CALLBACK_W MsgHandler,
-    PVOID Context);
+    IN HWND Owner,
+    IN HSPFILEQ QueueHandle,
+    IN PSP_FILE_CALLBACK_W MsgHandler,
+    IN PVOID Context OPTIONAL);
 
 /* EOF */
 
 /* EOF */
index edd98fd..929a4dc 100644 (file)
@@ -71,6 +71,8 @@ static PGENERIC_LIST NtOsInstallsList = NULL;
 
 // HACK: Temporary compatibility code.
 #if 1
 
 // HACK: Temporary compatibility code.
 #if 1
+    #define SetupQueueCopy SetupQueueCopyWithCab
+
     static CABINET_CONTEXT CabinetContext;
     #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
     #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
     static CABINET_CONTEXT CabinetContext;
     #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
     #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
@@ -3494,6 +3496,7 @@ AddSectionToCopyQueueCab(HINF InfFile,
     PWCHAR FileKeyValue;
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
     PWCHAR FileKeyValue;
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
+    WCHAR FileDstPath[MAX_PATH];
 
     /*
      * This code enumerates the list of files in reactos.dff / reactos.inf
 
     /*
      * This code enumerates the list of files in reactos.dff / reactos.inf
@@ -3549,12 +3552,46 @@ AddSectionToCopyQueueCab(HINF InfFile,
             break;
         }
 
             break;
         }
 
+#if 1 // HACK moved! (r66604)
+        {
+        ULONG Length = wcslen(DirKeyValue);
+        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
+            Length--;
+        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 (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
                             USetupData.SourceRootPath.Buffer,
                             USetupData.SourceRootDir.Buffer,
                             FileKeyName,
         if (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
                             USetupData.SourceRootPath.Buffer,
                             USetupData.SourceRootDir.Buffer,
                             FileKeyName,
-                            DirKeyValue,
+                            FileDstPath,
                             TargetFileName))
         {
             /* FIXME: Handle error! */
                             TargetFileName))
         {
             /* FIXME: Handle error! */
@@ -3584,6 +3621,7 @@ AddSectionToCopyQueue(HINF InfFile,
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
     WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
     PWCHAR DirKeyValue;
     PWCHAR TargetFileName;
     WCHAR CompleteOrigDirName[512]; // FIXME: MAX_PATH is not enough?
+    WCHAR FileDstPath[MAX_PATH];
 
     if (SourceCabinet)
         return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
 
     if (SourceCabinet)
         return AddSectionToCopyQueueCab(InfFile, L"SourceFiles", SourceCabinet, DestinationPath, Ir);
@@ -3683,12 +3721,46 @@ AddSectionToCopyQueue(HINF InfFile,
             DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
             DPRINT("RelativePath(2): '%S'\n", CompleteOrigDirName);
         }
 
+#if 1 // HACK moved! (r66604)
+        {
+        ULONG Length = wcslen(DirKeyValue);
+        if ((Length > 0) && (DirKeyValue[Length - 1] == L'\\'))
+            Length--;
+        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 (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
                             USetupData.SourceRootPath.Buffer,
                             CompleteOrigDirName,
                             FileKeyName,
         if (!SetupQueueCopy(USetupData.SetupFileQueue,
                             SourceCabinet,
                             USetupData.SourceRootPath.Buffer,
                             CompleteOrigDirName,
                             FileKeyName,
-                            DirKeyValue,
+                            FileDstPath,
                             TargetFileName))
         {
             /* FIXME: Handle error! */
                             TargetFileName))
         {
             /* FIXME: Handle error! */
@@ -3938,9 +4010,15 @@ PrepareCopyPage(PINPUT_RECORD Ir)
     return FILE_COPY_PAGE;
 }
 
     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)
 {
 SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
                       IN BOOLEAN First)
 {
@@ -3967,7 +4045,6 @@ SetupUpdateMemoryInfo(IN PCOPYCONTEXT CopyContext,
     ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
 }
 
     ProgressSetStep(CopyContext->MemoryBars[2], PerfInfo.AvailablePages);
 }
 
-
 static UINT
 CALLBACK
 FileCopyCallback(PVOID Context,
 static UINT
 CALLBACK
 FileCopyCallback(PVOID Context,
@@ -3975,26 +4052,78 @@ FileCopyCallback(PVOID Context,
                  UINT_PTR Param1,
                  UINT_PTR Param2)
 {
                  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:
 
     switch (Notification)
     {
         case SPFILENOTIFY_STARTSUBQUEUE:
+        {
             CopyContext->TotalOperations = (ULONG)Param2;
             CopyContext->TotalOperations = (ULONG)Param2;
+            CopyContext->CompletedOperations = 0;
             ProgressSetStepCount(CopyContext->ProgressBar,
                                  CopyContext->TotalOperations);
             SetupUpdateMemoryInfo(CopyContext, TRUE);
             break;
             ProgressSetStepCount(CopyContext->ProgressBar,
                                  CopyContext->TotalOperations);
             SetupUpdateMemoryInfo(CopyContext, TRUE);
             break;
+        }
 
 
+        case SPFILENOTIFY_STARTDELETE:
+        case SPFILENOTIFY_STARTRENAME:
         case SPFILENOTIFY_STARTCOPY:
         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;
+
+                // TODO: Determine whether using STRING_RENAMING or STRING_MOVING
+                CONSOLE_SetStatusText(MUIGetString(STRING_MOVING),
+                                      SrcFileName, DstFileName);
+            }
+            else if (Notification == SPFILENOTIFY_STARTCOPY)
+            {
+                /* Display copy message */
+                ASSERT(Param2 == FILEOP_COPY);
+
+                SrcFileName = wcsrchr(FilePathInfo->Source, L'\\');
+                if (SrcFileName) ++SrcFileName;
+                else SrcFileName = FilePathInfo->Source;
+
+                CONSOLE_SetStatusText(MUIGetString(STRING_COPYING),
+                                      SrcFileName);
+            }
+
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
 
 
+        case SPFILENOTIFY_ENDDELETE:
+        case SPFILENOTIFY_ENDRENAME:
         case SPFILENOTIFY_ENDCOPY:
         case SPFILENOTIFY_ENDCOPY:
+        {
             CopyContext->CompletedOperations++;
 
             /* SYSREG checkpoint */
             CopyContext->CompletedOperations++;
 
             /* SYSREG checkpoint */
@@ -4004,9 +4133,10 @@ FileCopyCallback(PVOID Context,
             ProgressNextStep(CopyContext->ProgressBar);
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
             ProgressNextStep(CopyContext->ProgressBar);
             SetupUpdateMemoryInfo(CopyContext, FALSE);
             break;
+        }
     }
 
     }
 
-    return 0;
+    return FILEOP_DOIT;
 }
 
 
 }
 
 
@@ -4027,13 +4157,11 @@ static PAGE_NUMBER
 FileCopyPage(PINPUT_RECORD Ir)
 {
     COPYCONTEXT CopyContext;
 FileCopyPage(PINPUT_RECORD Ir)
 {
     COPYCONTEXT CopyContext;
-    unsigned int mem_bar_width;
+    UINT MemBarWidth;
 
     MUIDisplayPage(FILE_COPY_PAGE);
 
     /* Create context for the copy process */
 
     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;
 
     CopyContext.TotalOperations = 0;
     CopyContext.CompletedOperations = 0;
 
@@ -4048,13 +4176,13 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                 MUIGetString(STRING_SETUPCOPYINGFILES));
 
     // fit memory bars to screen width, distribute them uniform
                                                 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,
     /* 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,
                                                   43,
                                                   13,
                                                   44,
@@ -4062,21 +4190,21 @@ FileCopyPage(PINPUT_RECORD Ir)
                                                   "Kernel Pool");
 
     /* Create the non paged pool progress bar */
                                                   "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,
                                                   40,
-                                                  (xScreen / 2) + (mem_bar_width / 2),
+                                                  (xScreen / 2) + (MemBarWidth / 2),
                                                   43,
                                                   43,
-                                                  (xScreen / 2)- (mem_bar_width / 2),
+                                                  (xScreen / 2)- (MemBarWidth / 2),
                                                   44,
                                                   FALSE,
                                                   "Kernel Cache");
 
     /* Create the global memory progress bar */
                                                   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,
                                                   40,
                                                   xScreen - 13,
                                                   43,
-                                                  xScreen - 13 - mem_bar_width,
+                                                  xScreen - 13 - MemBarWidth,
                                                   44,
                                                   FALSE,
                                                   "Free Memory");
                                                   44,
                                                   FALSE,
                                                   "Free Memory");