*/
/* COPYRIGHT: See COPYING in the top level directory
* PROJECT: ReactOS text-mode setup
- * FILE: subsys/system/usetup/filequeue.c
+ * FILE: base/setup/usetup/filequeue.c
* PURPOSE: File queue functions
- * PROGRAMMER: Eric Kohl
- * Casper S. Hornstrup (chorns@users.sourceforge.net)
+ * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES *****************************************************************/
typedef struct _QUEUEENTRY
{
- struct _QUEUEENTRY *Prev;
- struct _QUEUEENTRY *Next;
-
- PWSTR SourceCabinet; /* May be NULL if file is not in a cabinet */
- PWSTR SourceRootPath;
- PWSTR SourcePath;
- PWSTR SourceFilename;
- PWSTR TargetDirectory;
- PWSTR TargetFilename;
-
+ LIST_ENTRY ListEntry;
+ PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */
+ PWSTR SourceRootPath;
+ PWSTR SourcePath;
+ PWSTR SourceFileName;
+ PWSTR TargetDirectory;
+ PWSTR TargetFileName;
} QUEUEENTRY, *PQUEUEENTRY;
-
typedef struct _FILEQUEUEHEADER
{
- PQUEUEENTRY CopyHead;
- PQUEUEENTRY CopyTail;
- ULONG CopyCount;
+ LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
+ ULONG DeleteCount;
+
+ LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
+ ULONG RenameCount;
+
+ LIST_ENTRY CopyQueue; // PQUEUEENTRY entries
+ ULONG CopyCount;
+
+ BOOLEAN HasCurrentCabinet;
+ CABINET_CONTEXT CabinetContext;
+ CAB_SEARCH Search;
+ WCHAR CurrentCabinetName[MAX_PATH];
} FILEQUEUEHEADER, *PFILEQUEUEHEADER;
-/* FUNCTIONS ****************************************************************/
+/* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
+
+static NTSTATUS
+SetupExtractFile(
+ IN OUT PFILEQUEUEHEADER QueueHeader,
+ IN PCWSTR CabinetFileName,
+ IN PCWSTR SourceFileName,
+ IN PCWSTR DestinationPathName)
+{
+ ULONG CabStatus;
+
+ DPRINT("SetupExtractFile(CabinetFileName: '%S', SourceFileName: '%S', DestinationPathName: '%S')\n",
+ CabinetFileName, SourceFileName, DestinationPathName);
+
+ if (QueueHeader->HasCurrentCabinet)
+ {
+ DPRINT("CurrentCabinetName: '%S'\n", QueueHeader->CurrentCabinetName);
+ }
+
+ 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 */
+ 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 */
+ CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
+ SourceFileName,
+ &QueueHeader->Search);
+ }
+ }
+ else
+ {
+ DPRINT("Using new cabinet\n");
+
+ if (QueueHeader->HasCurrentCabinet)
+ {
+ QueueHeader->HasCurrentCabinet = FALSE;
+ CabinetCleanup(&QueueHeader->CabinetContext);
+ }
+
+ RtlStringCchCopyW(QueueHeader->CurrentCabinetName,
+ ARRAYSIZE(QueueHeader->CurrentCabinetName),
+ CabinetFileName);
+
+ CabinetInitialize(&QueueHeader->CabinetContext);
+ CabinetSetEventHandlers(&QueueHeader->CabinetContext,
+ NULL, NULL, NULL);
+ CabinetSetCabinetName(&QueueHeader->CabinetContext, CabinetFileName);
+
+ CabStatus = CabinetOpen(&QueueHeader->CabinetContext);
+ if (CabStatus == CAB_STATUS_SUCCESS)
+ {
+ DPRINT("Opened cabinet %S\n", CabinetFileName /*CabinetGetCabinetName(&QueueHeader->CabinetContext)*/);
+ QueueHeader->HasCurrentCabinet = TRUE;
+ }
+ else
+ {
+ DPRINT("Cannot open cabinet (%d)\n", CabStatus);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ /* We have to start at the beginning here */
+ CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
+ SourceFileName,
+ &QueueHeader->Search);
+ }
-HSPFILEQ WINAPI
+ if (CabStatus != CAB_STATUS_SUCCESS)
+ {
+ DPRINT1("Unable to find '%S' in cabinet '%S'\n",
+ SourceFileName, CabinetGetCabinetName(&QueueHeader->CabinetContext));
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ CabinetSetDestinationPath(&QueueHeader->CabinetContext, DestinationPathName);
+ CabStatus = CabinetExtractFile(&QueueHeader->CabinetContext, &QueueHeader->Search);
+ if (CabStatus != CAB_STATUS_SUCCESS)
+ {
+ DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
+ return STATUS_UNSUCCESSFUL;
+ }
+
+ return STATUS_SUCCESS;
+}
+
+HSPFILEQ
+WINAPI
SetupOpenFileQueue(VOID)
{
- PFILEQUEUEHEADER QueueHeader;
+ PFILEQUEUEHEADER QueueHeader;
+
+ /* Allocate the queue header */
+ QueueHeader = RtlAllocateHeap(ProcessHeap, 0, sizeof(FILEQUEUEHEADER));
+ if (QueueHeader == NULL)
+ return NULL;
- /* Allocate queue header */
- QueueHeader = (PFILEQUEUEHEADER)RtlAllocateHeap(ProcessHeap,
- 0,
- sizeof(FILEQUEUEHEADER));
- if (QueueHeader == NULL)
- return(NULL);
+ RtlZeroMemory(QueueHeader, sizeof(FILEQUEUEHEADER));
- /* Initialize queue header */
- 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);
-VOID WINAPI
-SetupCloseFileQueue(HSPFILEQ QueueHandle)
+ 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(
+ IN HSPFILEQ QueueHandle)
{
- PFILEQUEUEHEADER QueueHeader;
- PQUEUEENTRY Entry;
+ PFILEQUEUEHEADER QueueHeader;
+ PLIST_ENTRY ListEntry;
+ PQUEUEENTRY Entry;
- if (QueueHandle == NULL)
- return;
+ if (QueueHandle == NULL)
+ return;
- QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
+ QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
+
+ /* Delete the delete queue */
+ while (!IsListEmpty(&QueueHeader->DeleteQueue))
+ {
+ ListEntry = RemoveHeadList(&QueueHeader->DeleteQueue);
+ Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+ SetupDeleteQueueEntry(Entry);
+ }
+
+ /* Delete the rename queue */
+ while (!IsListEmpty(&QueueHeader->RenameQueue))
+ {
+ ListEntry = RemoveHeadList(&QueueHeader->RenameQueue);
+ Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
+ SetupDeleteQueueEntry(Entry);
+ }
- /* Delete copy queue */
- Entry = QueueHeader->CopyHead;
- while (Entry != NULL)
+ /* Delete the copy queue */
+ while (!IsListEmpty(&QueueHeader->CopyQueue))
{
- /* 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;
- }
-
- /* Delete queue entry */
- RtlFreeHeap(ProcessHeap, 0, Entry);
-
- /* Get next queue entry */
- Entry = QueueHeader->CopyHead;
+ 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
+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;
+
+ if (QueueHandle == NULL ||
+ SourceRootPath == NULL ||
+ SourceFileName == NULL ||
+ TargetDirectory == NULL)
+ {
+ return FALSE;
+ }
+
+ 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 */
+ Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
+ if (Entry == NULL)
+ return FALSE;
+
+ RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
+
+ /* Copy source cabinet if available */
+ Entry->SourceCabinet = NULL;
+ if (SourceCabinet != NULL)
+ {
+ Length = wcslen(SourceCabinet);
+ Entry->SourceCabinet = RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
+ if (Entry->SourceCabinet == NULL)
+ {
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->SourceCabinet, Length + 1, SourceCabinet);
+ }
+
+ /* Copy source root path */
+ Length = wcslen(SourceRootPath);
+ Entry->SourceRootPath = RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
+ if (Entry->SourceRootPath == NULL)
+ {
+ if (Entry->SourceCabinet != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->SourceRootPath, Length + 1, SourceRootPath);
+
+ /* Copy source path */
+ Entry->SourcePath = NULL;
+ if (SourcePath != NULL)
+ {
+ Length = wcslen(SourcePath);
+ if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
+ Length--;
+ Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
+ if (Entry->SourcePath == NULL)
+ {
+ if (Entry->SourceCabinet != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
+ }
+
+ /* Copy source file name */
+ Length = wcslen(SourceFileName);
+ Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
+ if (Entry->SourceFileName == NULL)
+ {
+ if (Entry->SourcePath != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
+
+ if (Entry->SourceCabinet != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
+
+ /* Copy target directory */
+ Length = wcslen(TargetDirectory);
+ if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
+ Length--;
+ Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
+ 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)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetDirectory);
+
+ /* Copy optional target filename */
+ Entry->TargetFileName = NULL;
+ if (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)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
+ }
+ RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
+ }
+
+ /* Append queue entry */
+ InsertTailList(&QueueHeader->CopyQueue, &Entry->ListEntry);
+ ++QueueHeader->CopyCount;
+
+ return TRUE;
+}
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)
{
- PFILEQUEUEHEADER QueueHeader;
- PQUEUEENTRY Entry;
- ULONG Length;
-
- /* SourceCabinet may be NULL */
- if (QueueHandle == NULL ||
- SourceRootPath == NULL ||
- SourceFilename == NULL ||
- TargetDirectory == NULL)
- return(FALSE);
-
- QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
-
- /* Allocate new queue entry */
- Entry = (PQUEUEENTRY)RtlAllocateHeap(ProcessHeap,
- 0,
- sizeof(QUEUEENTRY));
- if (Entry == NULL)
- return(FALSE);
-
- RtlZeroMemory(Entry,
- sizeof(QUEUEENTRY));
-
- /* Copy source cabinet if available */
- if (SourceCabinet != NULL)
+ PFILEQUEUEHEADER QueueHeader;
+ PQUEUEENTRY Entry;
+ ULONG Length;
+
+ if (QueueHandle == NULL || PathPart1 == NULL)
+ {
+ return FALSE;
+ }
+
+ 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)
{
- Length = wcslen(SourceCabinet);
- Entry->SourceCabinet = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
- if (Entry->SourceCabinet == NULL)
- {
RtlFreeHeap(ProcessHeap, 0, Entry);
- return(FALSE);
- }
- wcsncpy(Entry->SourceCabinet, SourceCabinet, Length);
- Entry->SourceCabinet[Length] = (WCHAR)0;
+ return FALSE;
}
- else
+ RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, PathPart1);
+
+ /* Copy optional second part of path */
+ if (PathPart2 != NULL)
{
- Entry->SourceCabinet = 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);
}
- /* Copy source root path */
- Length = wcslen(SourceRootPath);
- Entry->SourceRootPath = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
- if (Entry->SourceRootPath == NULL)
- {
- if (Entry->SourceCabinet != NULL)
- {
- RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
- }
- RtlFreeHeap(ProcessHeap, 0, Entry);
- return(FALSE);
- }
- wcsncpy(Entry->SourceRootPath, SourceRootPath, Length);
- Entry->SourceRootPath[Length] = (WCHAR)0;
-
- /* Copy source path */
- if (SourcePath != NULL)
- {
+ /* Append the queue entry */
+ InsertTailList(&QueueHeader->DeleteQueue, &Entry->ListEntry);
+ ++QueueHeader->DeleteCount;
+
+ 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);
- Entry->SourcePath = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
+ if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
+ Length--;
+ Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
+ 0,
+ (Length + 1) * sizeof(WCHAR));
if (Entry->SourcePath == NULL)
{
- if (Entry->SourceCabinet != 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->SourceCabinet);
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
}
- RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
- RtlFreeHeap(ProcessHeap, 0, Entry);
- return(FALSE);
+ RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
}
- wcsncpy(Entry->SourcePath, SourcePath, Length);
- Entry->SourcePath[Length] = (WCHAR)0;
- }
-
- /* Copy source file name */
- Length = wcslen(SourceFilename);
- Entry->SourceFilename = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
- if (Entry->SourceFilename == NULL)
- {
- if (Entry->SourceCabinet != NULL)
- {
- RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
- }
- RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
- RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
- RtlFreeHeap(ProcessHeap, 0, Entry);
- return(FALSE);
- }
- wcsncpy(Entry->SourceFilename, SourceFilename, Length);
- Entry->SourceFilename[Length] = (WCHAR)0;
-
- /* Copy target directory */
- Length = wcslen(TargetDirectory);
- if (TargetDirectory[Length] == '\\')
- Length--;
- Entry->TargetDirectory = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
- if (Entry->TargetDirectory == NULL)
- {
- if (Entry->SourceCabinet != NULL)
- {
- 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);
- }
- wcsncpy(Entry->TargetDirectory, TargetDirectory, Length);
- Entry->TargetDirectory[Length] = (WCHAR)0;
-
- /* Copy optional target filename */
- if (TargetFilename != NULL)
- {
- Length = wcslen(TargetFilename);
- Entry->TargetFilename = (WCHAR*) RtlAllocateHeap(ProcessHeap,
- 0,
- (Length + 1) * sizeof(WCHAR));
- if (Entry->TargetFilename == NULL)
+
+ /* Copy optional target directory */
+ Entry->TargetDirectory = NULL;
+ if (TargetPath != NULL)
{
- if (Entry->SourceCabinet != 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)
{
- RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
+ if (Entry->SourceFileName != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
+
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
}
- 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);
+ RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetPath);
}
- wcsncpy(Entry->TargetFilename, TargetFilename, Length);
- Entry->TargetFilename[Length] = (WCHAR)0;
- }
-
- /* Append queue entry */
- if (QueueHeader->CopyHead == NULL) // && QueueHeader->CopyTail == NULL)
- {
- Entry->Prev = NULL;
- Entry->Next = NULL;
- QueueHeader->CopyHead = Entry;
- QueueHeader->CopyTail = Entry;
- }
- else
- {
- Entry->Prev = QueueHeader->CopyTail;
- Entry->Next = NULL;
- QueueHeader->CopyTail->Next = Entry;
- QueueHeader->CopyTail = Entry;
- }
- QueueHeader->CopyCount++;
-
- return(TRUE);
-}
+ /* 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);
-BOOL WINAPI
-SetupCommitFileQueueW(HWND Owner,
- HSPFILEQ QueueHandle,
- PSP_FILE_CALLBACK_W MsgHandler,
- PVOID Context)
-{
- WCHAR CabinetName[MAX_PATH];
- PFILEQUEUEHEADER QueueHeader;
- PQUEUEENTRY Entry;
- NTSTATUS Status;
- PCWSTR TargetRootPath, TargetPath;
-
- WCHAR FileSrcPath[MAX_PATH];
- WCHAR FileDstPath[MAX_PATH];
-
- TargetRootPath = ((PCOPYCONTEXT)Context)->DestinationRootPath;
- TargetPath = ((PCOPYCONTEXT)Context)->InstallPath;
-
- if (QueueHandle == NULL)
- return(FALSE);
-
- QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
-
- MsgHandler(Context,
- SPFILENOTIFY_STARTQUEUE,
- 0,
- 0);
-
- MsgHandler(Context,
- SPFILENOTIFY_STARTSUBQUEUE,
- FILEOP_COPY,
- QueueHeader->CopyCount);
-
- /* Commit copy queue */
- Entry = QueueHeader->CopyHead;
- while (Entry != NULL)
- {
- wcscpy(FileSrcPath, Entry->SourceRootPath);
- if (Entry->SourcePath != NULL)
- wcscat(FileSrcPath, Entry->SourcePath);
- wcscat(FileSrcPath, L"\\");
- wcscat(FileSrcPath, Entry->SourceFilename);
+ if (Entry->SourceFileName != NULL)
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
- /* Build the full target path */
- wcscpy(FileDstPath, TargetRootPath);
- if (Entry->TargetDirectory[0] == L'\\')
- {
- wcscat(FileDstPath, Entry->TargetDirectory);
+ RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
+ RtlFreeHeap(ProcessHeap, 0, Entry);
+ return FALSE;
}
- else
+ RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
+
+ /* Append the queue entry */
+ InsertTailList(&QueueHeader->RenameQueue, &Entry->ListEntry);
+ ++QueueHeader->RenameCount;
+
+ return TRUE;
+}
+
+BOOL
+WINAPI
+SetupCommitFileQueueW(
+ IN HWND Owner,
+ IN HSPFILEQ QueueHandle,
+ IN PSP_FILE_CALLBACK_W MsgHandler,
+ IN PVOID Context OPTIONAL)
+{
+ BOOL Success = TRUE; // Suppose success
+ NTSTATUS Status;
+ PFILEQUEUEHEADER QueueHeader;
+ PLIST_ENTRY ListEntry;
+ PQUEUEENTRY Entry;
+ FILEPATHS_W FilePathInfo;
+ WCHAR CabinetName[MAX_PATH];
+ WCHAR FileSrcPath[MAX_PATH];
+ WCHAR FileDstPath[MAX_PATH];
+
+ if (QueueHandle == NULL)
+ return FALSE;
+
+ QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
+
+ MsgHandler(Context,
+ SPFILENOTIFY_STARTQUEUE,
+ (UINT_PTR)Owner,
+ 0);
+
+
+ /*
+ * Commit the delete queue
+ */
+
+ MsgHandler(Context,
+ SPFILENOTIFY_STARTSUBQUEUE,
+ FILEOP_DELETE,
+ QueueHeader->DeleteCount);
+
+ ListEntry = QueueHeader->DeleteQueue.Flink;
+ while (ListEntry != &QueueHeader->DeleteQueue)
{
- if (TargetPath != NULL)
- {
- if (TargetPath[0] != L'\\')
- wcscat(FileDstPath, L"\\");
- wcscat(FileDstPath, TargetPath);
- }
- wcscat(FileDstPath, L"\\");
- wcscat(FileDstPath, Entry->TargetDirectory);
+ 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);
+
+ 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))
+ {
+ /* An error happened */
+ FilePathInfo.Win32Error = (UINT)Status;
+ MsgHandler(Context,
+ SPFILENOTIFY_DELETEERROR,
+ (UINT_PTR)&FilePathInfo,
+ 0);
+ Success = FALSE;
+ }
+
+ /* This notification is always sent, even in case of error */
+ FilePathInfo.Win32Error = (UINT)Status;
+ MsgHandler(Context,
+ SPFILENOTIFY_ENDDELETE,
+ (UINT_PTR)&FilePathInfo,
+ 0);
}
- /* Use only the destination path if the file is in a cabinet */
- if (Entry->SourceCabinet == NULL)
- {
- wcscat(FileDstPath, L"\\");
- if (Entry->TargetFilename != NULL)
- wcscat(FileDstPath, Entry->TargetFilename);
- else
- wcscat(FileDstPath, Entry->SourceFilename);
- }
+ MsgHandler(Context,
+ SPFILENOTIFY_ENDSUBQUEUE,
+ FILEOP_DELETE,
+ 0);
- /* FIXME: Do it! */
- DPRINT("'%S' ==> '%S'\n",
- FileSrcPath,
- FileDstPath);
+
+ /*
+ * Commit the rename queue
+ */
MsgHandler(Context,
- SPFILENOTIFY_STARTCOPY,
- (UINT_PTR)Entry->SourceFilename,
- FILEOP_COPY);
+ SPFILENOTIFY_STARTSUBQUEUE,
+ FILEOP_RENAME,
+ QueueHeader->RenameCount);
- if (Entry->SourceCabinet != NULL)
- {
- /* Extract the file */
- wcscpy(CabinetName, Entry->SourceRootPath);
- if (Entry->SourcePath != NULL)
- wcscat(CabinetName, Entry->SourcePath);
- wcscat(CabinetName, L"\\");
- wcscat(CabinetName, Entry->SourceCabinet);
- Status = SetupExtractFile(CabinetName, Entry->SourceFilename, FileDstPath);
- }
- else
- {
- /* Copy the file */
- Status = SetupCopyFile(FileSrcPath, FileDstPath);
- }
- if (!NT_SUCCESS(Status))
+ ListEntry = QueueHeader->RenameQueue.Flink;
+ while (ListEntry != &QueueHeader->RenameQueue)
{
- MsgHandler(Context,
- SPFILENOTIFY_COPYERROR,
- (UINT_PTR)Entry->SourceFilename,
- FILEOP_COPY);
+ 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);
}
- else
+
+ 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)
{
- MsgHandler(Context,
- SPFILENOTIFY_ENDCOPY,
- (UINT_PTR)Entry->SourceFilename,
- FILEOP_COPY);
+ 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 (Entry->TargetFileName != NULL)
+ ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
+ else
+ ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
+ }
+
+ 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,
+ (UINT_PTR)&FilePathInfo,
+ FILEOP_COPY);
+
+ if (Entry->SourceCabinet != NULL)
+ {
+ /*
+ * 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);
+ Status = SetupExtractFile(QueueHeader,
+ CabinetName,
+ Entry->SourceFileName,
+ FileDstPath);
+ }
+ else
+ {
+ /* Copy the file */
+ Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
+ }
+
+ if (!NT_SUCCESS(Status))
+ {
+ /* An error happened */
+ FilePathInfo.Win32Error = (UINT)Status;
+ MsgHandler(Context,
+ SPFILENOTIFY_COPYERROR,
+ (UINT_PTR)&FilePathInfo,
+ (UINT_PTR)NULL); // FIXME: Unused yet...
+ Success = FALSE;
+ }
+
+ /* This notification is always sent, even in case of error */
+ FilePathInfo.Win32Error = (UINT)Status;
+ MsgHandler(Context,
+ SPFILENOTIFY_ENDCOPY,
+ (UINT_PTR)&FilePathInfo,
+ 0);
}
- Entry = Entry->Next;
- }
+ MsgHandler(Context,
+ SPFILENOTIFY_ENDSUBQUEUE,
+ FILEOP_COPY,
+ 0);
- MsgHandler(Context,
- SPFILENOTIFY_ENDSUBQUEUE,
- FILEOP_COPY,
- 0);
- MsgHandler(Context,
- SPFILENOTIFY_ENDQUEUE,
- 0,
- 0);
+ /* All the queues have been committed */
+ MsgHandler(Context,
+ SPFILENOTIFY_ENDQUEUE,
+ (UINT_PTR)Success,
+ 0);
- return(TRUE);
+ return Success;
}
/* EOF */