ReactOS 0.4.15-dev-8102-g108db8f
fileqsup.c
Go to the documentation of this file.
1/*
2 * ReactOS kernel
3 * Copyright (C) 2002 ReactOS Team
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License along
16 * with this program; if not, write to the Free Software Foundation, Inc.,
17 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 */
19/*
20 * COPYRIGHT: See COPYING in the top level directory
21 * PROJECT: ReactOS text-mode setup
22 * FILE: base/setup/lib/fileqsup.c
23 * PURPOSE: Interfacing with Setup* API File Queue support functions
24 * PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
25 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
26 */
27
28/* INCLUDES *****************************************************************/
29
30#ifndef _USETUP_PCH_
31#include "usetup.h"
32#endif
33
34#define NDEBUG
35#include <debug.h>
36
37/* DEFINITIONS **************************************************************/
38
39typedef struct _QUEUEENTRY
40{
42 PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */
49
50typedef struct _FILEQUEUEHEADER
51{
52 LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
54
55 LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
57
58 LIST_ENTRY CopyQueue; // PQUEUEENTRY entries
60
66
67
68/* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
69
70static NTSTATUS
72 IN OUT PFILEQUEUEHEADER QueueHeader,
73 IN PCWSTR CabinetFileName,
74 IN PCWSTR SourceFileName,
75 IN PCWSTR DestinationPathName)
76{
77 ULONG CabStatus;
78
79 DPRINT("SetupExtractFile(CabinetFileName: '%S', SourceFileName: '%S', DestinationPathName: '%S')\n",
80 CabinetFileName, SourceFileName, DestinationPathName);
81
82 if (QueueHeader->HasCurrentCabinet)
83 {
84 DPRINT("CurrentCabinetName: '%S'\n", QueueHeader->CurrentCabinetName);
85 }
86
87 if (QueueHeader->HasCurrentCabinet &&
88 (wcscmp(CabinetFileName, QueueHeader->CurrentCabinetName) == 0))
89 {
90 DPRINT("Using same cabinet as last time\n");
91
92 /* Use our last location because the files should be sequential */
93 CabStatus = CabinetFindNextFileSequential(&QueueHeader->CabinetContext,
94 SourceFileName,
95 &QueueHeader->Search);
96 if (CabStatus != CAB_STATUS_SUCCESS)
97 {
98 DPRINT("Sequential miss on file: %S\n", SourceFileName);
99
100 /* Looks like we got unlucky */
101 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
102 SourceFileName,
103 &QueueHeader->Search);
104 }
105 }
106 else
107 {
108 DPRINT("Using new cabinet\n");
109
110 if (QueueHeader->HasCurrentCabinet)
111 {
112 QueueHeader->HasCurrentCabinet = FALSE;
113 CabinetCleanup(&QueueHeader->CabinetContext);
114 }
115
116 RtlStringCchCopyW(QueueHeader->CurrentCabinetName,
117 ARRAYSIZE(QueueHeader->CurrentCabinetName),
118 CabinetFileName);
119
120 CabinetInitialize(&QueueHeader->CabinetContext);
121 CabinetSetEventHandlers(&QueueHeader->CabinetContext,
122 NULL, NULL, NULL, NULL);
123 CabinetSetCabinetName(&QueueHeader->CabinetContext, CabinetFileName);
124
125 CabStatus = CabinetOpen(&QueueHeader->CabinetContext);
126 if (CabStatus == CAB_STATUS_SUCCESS)
127 {
128 DPRINT("Opened cabinet %S\n", CabinetFileName /*CabinetGetCabinetName(&QueueHeader->CabinetContext)*/);
129 QueueHeader->HasCurrentCabinet = TRUE;
130 }
131 else
132 {
133 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
134 return STATUS_UNSUCCESSFUL;
135 }
136
137 /* We have to start at the beginning here */
138 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
139 SourceFileName,
140 &QueueHeader->Search);
141 }
142
143 if (CabStatus != CAB_STATUS_SUCCESS)
144 {
145 DPRINT1("Unable to find '%S' in cabinet '%S'\n",
146 SourceFileName, CabinetGetCabinetName(&QueueHeader->CabinetContext));
147 return STATUS_UNSUCCESSFUL;
148 }
149
150 CabinetSetDestinationPath(&QueueHeader->CabinetContext, DestinationPathName);
151 CabStatus = CabinetExtractFile(&QueueHeader->CabinetContext, &QueueHeader->Search);
152 if (CabStatus != CAB_STATUS_SUCCESS)
153 {
154 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
155 return STATUS_UNSUCCESSFUL;
156 }
157
158 return STATUS_SUCCESS;
159}
160
162WINAPI
164{
165 PFILEQUEUEHEADER QueueHeader;
166
167 /* Allocate the queue header */
168 QueueHeader = RtlAllocateHeap(ProcessHeap, 0, sizeof(FILEQUEUEHEADER));
169 if (QueueHeader == NULL)
170 return NULL;
171
172 RtlZeroMemory(QueueHeader, sizeof(FILEQUEUEHEADER));
173
174 /* Initialize the file queues */
175 InitializeListHead(&QueueHeader->DeleteQueue);
176 QueueHeader->DeleteCount = 0;
177 InitializeListHead(&QueueHeader->RenameQueue);
178 QueueHeader->RenameCount = 0;
179 InitializeListHead(&QueueHeader->CopyQueue);
180 QueueHeader->CopyCount = 0;
181
182 QueueHeader->HasCurrentCabinet = FALSE;
183
184 return (HSPFILEQ)QueueHeader;
185}
186
187static VOID
190{
191 if (Entry == NULL)
192 return;
193
194 /* Delete all strings */
195 if (Entry->SourceCabinet != NULL)
196 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
197
198 if (Entry->SourceRootPath != NULL)
199 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
200
201 if (Entry->SourcePath != NULL)
202 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
203
204 if (Entry->SourceFileName != NULL)
205 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
206
207 if (Entry->TargetDirectory != NULL)
208 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
209
210 if (Entry->TargetFileName != NULL)
211 RtlFreeHeap(ProcessHeap, 0, Entry->TargetFileName);
212
213 /* Delete queue entry */
215}
216
217BOOL
218WINAPI
220 IN HSPFILEQ QueueHandle)
221{
222 PFILEQUEUEHEADER QueueHeader;
223 PLIST_ENTRY ListEntry;
225
226 if (QueueHandle == NULL)
227 return FALSE;
228
229 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
230
231 /* Delete the delete queue */
232 while (!IsListEmpty(&QueueHeader->DeleteQueue))
233 {
234 ListEntry = RemoveHeadList(&QueueHeader->DeleteQueue);
235 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
237 }
238
239 /* Delete the rename queue */
240 while (!IsListEmpty(&QueueHeader->RenameQueue))
241 {
242 ListEntry = RemoveHeadList(&QueueHeader->RenameQueue);
243 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
245 }
246
247 /* Delete the copy queue */
248 while (!IsListEmpty(&QueueHeader->CopyQueue))
249 {
250 ListEntry = RemoveHeadList(&QueueHeader->CopyQueue);
251 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
253 }
254
255 /* Delete queue header */
256 RtlFreeHeap(ProcessHeap, 0, QueueHeader);
257
258 return TRUE;
259}
260
261/* A simplified version of SetupQueueCopyW that wraps Cabinet support around */
262BOOL
263WINAPI
265 IN HSPFILEQ QueueHandle,
266 IN PCWSTR SourceRootPath,
267 IN PCWSTR SourcePath OPTIONAL,
268 IN PCWSTR SourceFileName,
269 IN PCWSTR SourceDescription OPTIONAL,
270 IN PCWSTR SourceCabinet OPTIONAL,
271 IN PCWSTR SourceTagFile OPTIONAL,
272 IN PCWSTR TargetDirectory,
273 IN PCWSTR TargetFileName OPTIONAL,
274 IN ULONG CopyStyle)
275{
276 PFILEQUEUEHEADER QueueHeader;
279
280 if (QueueHandle == NULL ||
281 SourceRootPath == NULL ||
282 SourceFileName == NULL ||
283 TargetDirectory == NULL)
284 {
285 return FALSE;
286 }
287
288 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
289
290 DPRINT("SetupQueueCopy(Cab '%S', SrcRootPath '%S', SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
291 SourceCabinet ? SourceCabinet : L"n/a",
292 SourceRootPath, SourcePath, SourceFileName,
293 TargetDirectory, TargetFileName);
294
295 /* Allocate new queue entry */
297 if (Entry == NULL)
298 return FALSE;
299
301
302 /* Copy source cabinet if available */
303 Entry->SourceCabinet = NULL;
304 if (SourceCabinet != NULL)
305 {
306 Length = wcslen(SourceCabinet);
307 Entry->SourceCabinet = RtlAllocateHeap(ProcessHeap,
308 0,
309 (Length + 1) * sizeof(WCHAR));
310 if (Entry->SourceCabinet == NULL)
311 {
313 return FALSE;
314 }
315 RtlStringCchCopyW(Entry->SourceCabinet, Length + 1, SourceCabinet);
316 }
317
318 /* Copy source root path */
319 Length = wcslen(SourceRootPath);
320 Entry->SourceRootPath = RtlAllocateHeap(ProcessHeap,
321 0,
322 (Length + 1) * sizeof(WCHAR));
323 if (Entry->SourceRootPath == NULL)
324 {
325 if (Entry->SourceCabinet != NULL)
326 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
327
329 return FALSE;
330 }
331 RtlStringCchCopyW(Entry->SourceRootPath, Length + 1, SourceRootPath);
332
333 /* Copy source path */
334 Entry->SourcePath = NULL;
335 if (SourcePath != NULL)
336 {
337 Length = wcslen(SourcePath);
338 if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
339 Length--;
340 Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
341 0,
342 (Length + 1) * sizeof(WCHAR));
343 if (Entry->SourcePath == NULL)
344 {
345 if (Entry->SourceCabinet != NULL)
346 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
347
348 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
350 return FALSE;
351 }
352 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
353 }
354
355 /* Copy source file name */
356 Length = wcslen(SourceFileName);
357 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
358 0,
359 (Length + 1) * sizeof(WCHAR));
360 if (Entry->SourceFileName == NULL)
361 {
362 if (Entry->SourcePath != NULL)
363 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
364
365 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
366
367 if (Entry->SourceCabinet != NULL)
368 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
369
371 return FALSE;
372 }
373 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
374
375 /* Copy target directory */
376 Length = wcslen(TargetDirectory);
377 if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
378 Length--;
379 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
380 0,
381 (Length + 1) * sizeof(WCHAR));
382 if (Entry->TargetDirectory == NULL)
383 {
384 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
385
386 if (Entry->SourcePath != NULL)
387 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
388
389 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
390
391 if (Entry->SourceCabinet != NULL)
392 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
393
395 return FALSE;
396 }
397 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetDirectory);
398
399 /* Copy optional target filename */
400 Entry->TargetFileName = NULL;
401 if (TargetFileName != NULL)
402 {
403 Length = wcslen(TargetFileName);
404 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
405 0,
406 (Length + 1) * sizeof(WCHAR));
407 if (Entry->TargetFileName == NULL)
408 {
409 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
410 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
411
412 if (Entry->SourcePath != NULL)
413 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
414
415 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
416
417 if (Entry->SourceCabinet != NULL)
418 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
419
421 return FALSE;
422 }
423 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
424 }
425
426 /* Append queue entry */
427 InsertTailList(&QueueHeader->CopyQueue, &Entry->ListEntry);
428 ++QueueHeader->CopyCount;
429
430 return TRUE;
431}
432
433BOOL
434WINAPI
436 IN HSPFILEQ QueueHandle,
437 IN PCWSTR PathPart1,
438 IN PCWSTR PathPart2 OPTIONAL)
439{
440 PFILEQUEUEHEADER QueueHeader;
443
444 if (QueueHandle == NULL || PathPart1 == NULL)
445 {
446 return FALSE;
447 }
448
449 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
450
451 DPRINT1("SetupQueueDeleteW(PathPart1 '%S', PathPart2 '%S')\n",
452 PathPart1, PathPart2);
453
454 /* Allocate new queue entry */
456 if (Entry == NULL)
457 return FALSE;
458
460
461 Entry->SourceCabinet = NULL;
462 Entry->SourceRootPath = NULL;
463 Entry->SourcePath = NULL;
464 Entry->SourceFileName = NULL;
465
466 /* Copy first part of path */
467 Length = wcslen(PathPart1);
468 // if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
469 // Length--;
470 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
471 0,
472 (Length + 1) * sizeof(WCHAR));
473 if (Entry->TargetDirectory == NULL)
474 {
476 return FALSE;
477 }
478 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, PathPart1);
479
480 /* Copy optional second part of path */
481 if (PathPart2 != NULL)
482 {
483 Length = wcslen(PathPart2);
484 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
485 0,
486 (Length + 1) * sizeof(WCHAR));
487 if (Entry->TargetFileName == NULL)
488 {
489 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
491 return FALSE;
492 }
493 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, PathPart2);
494 }
495
496 /* Append the queue entry */
497 InsertTailList(&QueueHeader->DeleteQueue, &Entry->ListEntry);
498 ++QueueHeader->DeleteCount;
499
500 return TRUE;
501}
502
503BOOL
504WINAPI
506 IN HSPFILEQ QueueHandle,
507 IN PCWSTR SourcePath,
508 IN PCWSTR SourceFileName OPTIONAL,
509 IN PCWSTR TargetPath OPTIONAL,
510 IN PCWSTR TargetFileName)
511{
512 PFILEQUEUEHEADER QueueHeader;
515
516 if (QueueHandle == NULL ||
517 SourcePath == NULL ||
518 TargetFileName == NULL)
519 {
520 return FALSE;
521 }
522
523 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
524
525 DPRINT1("SetupQueueRenameW(SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
526 SourcePath, SourceFileName, TargetPath, TargetFileName);
527
528 /* Allocate a new queue entry */
530 if (Entry == NULL)
531 return FALSE;
532
534
535 Entry->SourceCabinet = NULL;
536 Entry->SourceRootPath = NULL;
537
538 /* Copy source path */
539 Length = wcslen(SourcePath);
540 if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
541 Length--;
542 Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
543 0,
544 (Length + 1) * sizeof(WCHAR));
545 if (Entry->SourcePath == NULL)
546 {
548 return FALSE;
549 }
550 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
551
552 /* Copy optional source file name */
553 Entry->SourceFileName = NULL;
554 if (SourceFileName != NULL)
555 {
556 Length = wcslen(SourceFileName);
557 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
558 0,
559 (Length + 1) * sizeof(WCHAR));
560 if (Entry->SourceFileName == NULL)
561 {
562 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
564 return FALSE;
565 }
566 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
567 }
568
569 /* Copy optional target directory */
570 Entry->TargetDirectory = NULL;
571 if (TargetPath != NULL)
572 {
573 Length = wcslen(TargetPath);
574 if ((Length > 0) && (TargetPath[Length - 1] == L'\\'))
575 Length--;
576 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
577 0,
578 (Length + 1) * sizeof(WCHAR));
579 if (Entry->TargetDirectory == NULL)
580 {
581 if (Entry->SourceFileName != NULL)
582 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
583
584 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
586 return FALSE;
587 }
588 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetPath);
589 }
590
591 /* Copy target filename */
592 Length = wcslen(TargetFileName);
593 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
594 0,
595 (Length + 1) * sizeof(WCHAR));
596 if (Entry->TargetFileName == NULL)
597 {
598 if (Entry->TargetDirectory != NULL)
599 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
600
601 if (Entry->SourceFileName != NULL)
602 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
603
604 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
606 return FALSE;
607 }
608 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
609
610 /* Append the queue entry */
611 InsertTailList(&QueueHeader->RenameQueue, &Entry->ListEntry);
612 ++QueueHeader->RenameCount;
613
614 return TRUE;
615}
616
617BOOL
618WINAPI
620 IN HWND Owner,
621 IN HSPFILEQ QueueHandle,
622 IN PSP_FILE_CALLBACK_W MsgHandler,
624{
625 BOOL Success = TRUE; // Suppose success
626 UINT Result;
628 PFILEQUEUEHEADER QueueHeader;
629 PLIST_ENTRY ListEntry;
631 FILEPATHS_W FilePathInfo;
632 WCHAR FileSrcPath[MAX_PATH];
633 WCHAR FileDstPath[MAX_PATH];
634
635 if (QueueHandle == NULL)
636 return FALSE;
637
638 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
639
640 Result = MsgHandler(Context,
643 0);
644 if (Result == FILEOP_ABORT)
645 return FALSE;
646
647
648 /*
649 * Commit the delete queue
650 */
651
652 if (!IsListEmpty(&QueueHeader->DeleteQueue))
653 {
654 Result = MsgHandler(Context,
657 QueueHeader->DeleteCount);
658 if (Result == FILEOP_ABORT)
659 {
660 Success = FALSE;
661 goto Quit;
662 }
663 }
664
665 for (ListEntry = QueueHeader->DeleteQueue.Flink;
666 ListEntry != &QueueHeader->DeleteQueue;
667 ListEntry = ListEntry->Flink)
668 {
669 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
670
671 /* Build the full target path */
672 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
673 Entry->TargetDirectory, Entry->TargetFileName);
674
675 DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath);
676
677 FilePathInfo.Target = FileDstPath;
678 FilePathInfo.Source = NULL;
679 FilePathInfo.Win32Error = STATUS_SUCCESS;
680 FilePathInfo.Flags = 0; // FIXME: Unused yet...
681
682 Result = MsgHandler(Context,
684 (UINT_PTR)&FilePathInfo,
686 if (Result == FILEOP_ABORT)
687 {
688 Success = FALSE;
689 goto EndDelete;
690 }
691 else if (Result == FILEOP_SKIP)
692 goto EndDelete;
693 // else (Result == FILEOP_DOIT)
694
695RetryDelete:
696 /* Force-delete the file */
697 Status = SetupDeleteFile(FileDstPath, TRUE);
698 if (!NT_SUCCESS(Status))
699 {
700 /* An error happened */
701 FilePathInfo.Win32Error = (UINT)Status;
702 Result = MsgHandler(Context,
704 (UINT_PTR)&FilePathInfo,
705 0);
706 if (Result == FILEOP_ABORT)
707 {
708 Success = FALSE;
709 goto EndDelete;
710 }
711 else if (Result == FILEOP_SKIP)
712 goto EndDelete;
713 else if (Result == FILEOP_RETRY)
714 goto RetryDelete;
715
716 Success = FALSE;
717 }
718
719EndDelete:
720 /* This notification is always sent, even in case of error */
721 FilePathInfo.Win32Error = (UINT)Status;
722 MsgHandler(Context,
724 (UINT_PTR)&FilePathInfo,
725 0);
726 if (Success == FALSE /* && Result == FILEOP_ABORT */)
727 goto Quit;
728 }
729
730 if (!IsListEmpty(&QueueHeader->DeleteQueue))
731 {
732 MsgHandler(Context,
735 0);
736 }
737
738
739 /*
740 * Commit the rename queue
741 */
742
743 if (!IsListEmpty(&QueueHeader->RenameQueue))
744 {
745 Result = MsgHandler(Context,
748 QueueHeader->RenameCount);
749 if (Result == FILEOP_ABORT)
750 {
751 Success = FALSE;
752 goto Quit;
753 }
754 }
755
756 for (ListEntry = QueueHeader->RenameQueue.Flink;
757 ListEntry != &QueueHeader->RenameQueue;
758 ListEntry = ListEntry->Flink)
759 {
760 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
761
762 /* Build the full source path */
763 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2,
764 Entry->SourcePath, Entry->SourceFileName);
765
766 /* Build the full target path */
767 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
768 Entry->TargetDirectory, Entry->TargetFileName);
769
770 DPRINT1(" -----> " "Rename: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
771
772 FilePathInfo.Target = FileDstPath;
773 FilePathInfo.Source = FileSrcPath;
774 FilePathInfo.Win32Error = STATUS_SUCCESS;
775 FilePathInfo.Flags = 0; // FIXME: Unused yet...
776
777 Result = MsgHandler(Context,
779 (UINT_PTR)&FilePathInfo,
781 if (Result == FILEOP_ABORT)
782 {
783 Success = FALSE;
784 goto EndRename;
785 }
786 else if (Result == FILEOP_SKIP)
787 goto EndRename;
788 // else (Result == FILEOP_DOIT)
789
790RetryRename:
791 /* Move or rename the file */
792 Status = SetupMoveFile(FileSrcPath, FileDstPath,
796 if (!NT_SUCCESS(Status))
797 {
798 /* An error happened */
799 FilePathInfo.Win32Error = (UINT)Status;
800 Result = MsgHandler(Context,
802 (UINT_PTR)&FilePathInfo,
803 0);
804 if (Result == FILEOP_ABORT)
805 {
806 Success = FALSE;
807 goto EndRename;
808 }
809 else if (Result == FILEOP_SKIP)
810 goto EndRename;
811 else if (Result == FILEOP_RETRY)
812 goto RetryRename;
813
814 Success = FALSE;
815 }
816
817EndRename:
818 /* This notification is always sent, even in case of error */
819 FilePathInfo.Win32Error = (UINT)Status;
820 MsgHandler(Context,
822 (UINT_PTR)&FilePathInfo,
823 0);
824 if (Success == FALSE /* && Result == FILEOP_ABORT */)
825 goto Quit;
826 }
827
828 if (!IsListEmpty(&QueueHeader->RenameQueue))
829 {
830 MsgHandler(Context,
833 0);
834 }
835
836
837 /*
838 * Commit the copy queue
839 */
840
841 if (!IsListEmpty(&QueueHeader->CopyQueue))
842 {
843 Result = MsgHandler(Context,
846 QueueHeader->CopyCount);
847 if (Result == FILEOP_ABORT)
848 {
849 Success = FALSE;
850 goto Quit;
851 }
852 }
853
854 for (ListEntry = QueueHeader->CopyQueue.Flink;
855 ListEntry != &QueueHeader->CopyQueue;
856 ListEntry = ListEntry->Flink)
857 {
858 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
859
860 //
861 // TODO: Send a SPFILENOTIFY_NEEDMEDIA notification
862 // when we switch to a new installation media.
863 // Param1 = (UINT_PTR)(PSOURCE_MEDIA)SourceMediaInfo;
864 // Param2 = (UINT_PTR)(TCHAR[MAX_PATH])NewPathInfo;
865 //
866
867 /* Build the full source path */
868 if (Entry->SourceCabinet == NULL)
869 {
870 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
871 Entry->SourceRootPath, Entry->SourcePath,
872 Entry->SourceFileName);
873 }
874 else
875 {
876 /*
877 * The cabinet must be in Entry->SourceRootPath only!
878 * (Should we ignore Entry->SourcePath?)
879 */
880 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
881 Entry->SourceRootPath, Entry->SourcePath,
882 Entry->SourceCabinet);
883 }
884
885 /* Build the full target path */
886 RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
887 if (Entry->SourceCabinet == NULL)
888 {
889 /* If the file is not in a cabinet, possibly use a different target name */
890 if (Entry->TargetFileName != NULL)
891 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
892 else
893 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
894 }
895 else
896 {
897 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
898 }
899
900 DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
901
902 //
903 // Technically, here we should create the target directory,
904 // if it does not already exist... before calling the handler!
905 //
906
907 FilePathInfo.Target = FileDstPath;
908 FilePathInfo.Source = FileSrcPath;
909 FilePathInfo.Win32Error = STATUS_SUCCESS;
910 FilePathInfo.Flags = 0; // FIXME: Unused yet...
911
912 Result = MsgHandler(Context,
914 (UINT_PTR)&FilePathInfo,
916 if (Result == FILEOP_ABORT)
917 {
918 Success = FALSE;
919 goto EndCopy;
920 }
921 else if (Result == FILEOP_SKIP)
922 goto EndCopy;
923 // else (Result == FILEOP_DOIT)
924
925RetryCopy:
926 if (Entry->SourceCabinet != NULL)
927 {
928 /*
929 * The file is in a cabinet, use only the destination path
930 * and keep the source name as the target name.
931 */
932 /* Extract the file from the cabinet */
933 Status = SetupExtractFile(QueueHeader,
934 FileSrcPath, // Specifies the cabinet path
935 Entry->SourceFileName,
936 Entry->TargetDirectory);
937 }
938 else
939 {
940 /* Copy the file */
941 Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
942 }
943
944 if (!NT_SUCCESS(Status))
945 {
946 /* An error happened */
947 FilePathInfo.Win32Error = (UINT)Status;
948 Result = MsgHandler(Context,
950 (UINT_PTR)&FilePathInfo,
951 (UINT_PTR)NULL); // FIXME: Unused yet...
952 if (Result == FILEOP_ABORT)
953 {
954 Success = FALSE;
955 goto EndCopy;
956 }
957 else if (Result == FILEOP_SKIP)
958 goto EndCopy;
959 else if (Result == FILEOP_RETRY)
960 goto RetryCopy;
961 else if (Result == FILEOP_NEWPATH)
962 goto RetryCopy; // TODO!
963
964 Success = FALSE;
965 }
966
967EndCopy:
968 /* This notification is always sent, even in case of error */
969 FilePathInfo.Win32Error = (UINT)Status;
970 MsgHandler(Context,
972 (UINT_PTR)&FilePathInfo,
973 0);
974 if (Success == FALSE /* && Result == FILEOP_ABORT */)
975 goto Quit;
976 }
977
978 if (!IsListEmpty(&QueueHeader->CopyQueue))
979 {
980 MsgHandler(Context,
983 0);
984 }
985
986
987Quit:
988 /* All the queues have been committed */
989 MsgHandler(Context,
992 0);
993
994 return Success;
995}
996
997
998/* GLOBALS *******************************************************************/
999
1006
1007/* EOF */
unsigned char BOOLEAN
LONG NTSTATUS
Definition: precomp.h:26
HANDLE ProcessHeap
Definition: servman.c:15
#define DPRINT1
Definition: precomp.h:8
#define CAB_STATUS_SUCCESS
Definition: cabinet.h:23
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:590
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:608
ULONG CabinetOpen(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:627
ULONG CabinetFindFirst(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName, IN OUT PCAB_SEARCH Search)
Definition: cabinet.c:826
PCWSTR CabinetGetCabinetName(IN PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:574
ULONG CabinetExtractFile(IN PCABINET_CONTEXT CabinetContext, IN PCAB_SEARCH Search)
Definition: cabinet.c:965
VOID CabinetSetEventHandlers(IN PCABINET_CONTEXT CabinetContext, IN PCABINET_OVERWRITE Overwrite, IN PCABINET_EXTRACT Extract, IN PCABINET_DISK_CHANGE DiskChange, IN PCABINET_CREATE_FILE CreateFile)
Definition: cabinet.c:1346
VOID CabinetInitialize(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:507
VOID CabinetCleanup(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:535
VOID CabinetSetCabinetName(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName)
Definition: cabinet.c:586
VOID CabinetSetDestinationPath(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR DestinationPath)
Definition: cabinet.c:599
ULONG CabinetFindNextFileSequential(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName, IN OUT PCAB_SEARCH Search)
Definition: cabinet.c:939
#define NULL
Definition: types.h:112
#define TRUE
Definition: types.h:120
#define FALSE
Definition: types.h:117
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define MAX_PATH
Definition: compat.h:34
#define InsertTailList(ListHead, Entry)
#define IsListEmpty(ListHead)
Definition: env_spec_w32.h:954
#define RemoveHeadList(ListHead)
Definition: env_spec_w32.h:964
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
@ Success
Definition: eventcreate.c:712
#define SPFILENOTIFY_ENDDELETE
Definition: fileqsup.h:28
#define FILEOP_COPY
Definition: fileqsup.h:42
#define SPFILENOTIFY_RENAMEERROR
Definition: fileqsup.h:33
BOOL(WINAPI * pSpFileQueueCommit)(IN HWND Owner, IN HSPFILEQ QueueHandle, IN PSP_FILE_CALLBACK_W MsgHandler, IN PVOID Context OPTIONAL)
Definition: fileqsup.h:128
pSpFileQueueDelete SpFileQueueDelete
Definition: fileqsup.c:1003
#define FILEOP_SKIP
Definition: fileqsup.h:49
#define SPFILENOTIFY_STARTDELETE
Definition: fileqsup.h:27
BOOL(WINAPI * pSpFileQueueClose)(IN HSPFILEQ QueueHandle)
Definition: fileqsup.h:85
BOOL(WINAPI * pSpFileQueueDelete)(IN HSPFILEQ QueueHandle, IN PCWSTR PathPart1, IN PCWSTR PathPart2 OPTIONAL)
Definition: fileqsup.h:108
pSpFileQueueClose SpFileQueueClose
Definition: fileqsup.c:1001
UINT(CALLBACK * PSP_FILE_CALLBACK_W)(IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
Definition: fileqsup.h:66
#define SPFILENOTIFY_STARTSUBQUEUE
Definition: fileqsup.h:24
#define FILEOP_RETRY
Definition: fileqsup.h:50
#define FILEOP_NEWPATH
Definition: fileqsup.h:51
#define SPFILENOTIFY_ENDQUEUE
Definition: fileqsup.h:23
pSpFileQueueCopy SpFileQueueCopy
Definition: fileqsup.c:1002
#define SPFILENOTIFY_ENDCOPY
Definition: fileqsup.h:36
#define SPFILENOTIFY_DELETEERROR
Definition: fileqsup.h:29
#define SPFILENOTIFY_STARTCOPY
Definition: fileqsup.h:35
#define SPFILENOTIFY_COPYERROR
Definition: fileqsup.h:37
#define FILEOP_RENAME
Definition: fileqsup.h:43
BOOL(WINAPI * pSpFileQueueCopy)(IN HSPFILEQ QueueHandle, IN PCWSTR SourceRootPath, IN PCWSTR SourcePath OPTIONAL, IN PCWSTR SourceFileName, IN PCWSTR SourceDescription OPTIONAL, IN PCWSTR SourceCabinet OPTIONAL, IN PCWSTR SourceTagFile OPTIONAL, IN PCWSTR TargetDirectory, IN PCWSTR TargetFileName OPTIONAL, IN ULONG CopyStyle)
Definition: fileqsup.h:92
HSPFILEQ(WINAPI * pSpFileQueueOpen)(VOID)
Definition: fileqsup.h:79
#define SPFILENOTIFY_ENDSUBQUEUE
Definition: fileqsup.h:25
#define SPFILENOTIFY_STARTRENAME
Definition: fileqsup.h:31
#define SPFILENOTIFY_ENDRENAME
Definition: fileqsup.h:32
pSpFileQueueOpen SpFileQueueOpen
Definition: fileqsup.c:1000
pSpFileQueueCommit SpFileQueueCommit
Definition: fileqsup.c:1005
pSpFileQueueRename SpFileQueueRename
Definition: fileqsup.c:1004
#define FILEOP_DELETE
Definition: fileqsup.h:44
#define FILEOP_ABORT
Definition: fileqsup.h:47
#define SPFILENOTIFY_STARTQUEUE
Definition: fileqsup.h:22
BOOL(WINAPI * pSpFileQueueRename)(IN HSPFILEQ QueueHandle, IN PCWSTR SourcePath, IN PCWSTR SourceFileName OPTIONAL, IN PCWSTR TargetPath OPTIONAL, IN PCWSTR TargetFileName)
Definition: fileqsup.h:117
NTSTATUS CombinePaths(OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:681
NTSTATUS SetupMoveFile(IN PCWSTR ExistingFileName, IN PCWSTR NewFileName, IN ULONG Flags)
Definition: filesup.c:480
NTSTATUS ConcatPaths(IN OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:659
NTSTATUS SetupCopyFile(IN PCWSTR SourceFileName, IN PCWSTR DestinationFileName, IN BOOLEAN FailIfExists)
Definition: filesup.c:240
NTSTATUS SetupDeleteFile(IN PCWSTR FileName, IN BOOLEAN ForceDelete)
Definition: filesup.c:151
#define MOVEFILE_WRITE_THROUGH
Definition: filesup.h:30
#define MOVEFILE_REPLACE_EXISTING
Definition: filesup.h:28
#define MOVEFILE_COPY_ALLOWED
Definition: filesup.h:29
unsigned int BOOL
Definition: ntddk_ex.h:94
Status
Definition: gdiplustypes.h:25
_CRTIMP size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
unsigned int UINT
Definition: ndis.h:50
_Out_writes_bytes_to_opt_ AbsoluteSecurityDescriptorSize PSECURITY_DESCRIPTOR _Inout_ PULONG _Out_writes_bytes_to_opt_ DaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ SaclSize PACL _Inout_ PULONG _Out_writes_bytes_to_opt_ OwnerSize PSID Owner
Definition: rtlfuncs.h:1597
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:102
NTSTRSAFEAPI RtlStringCchCopyW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:127
#define L(x)
Definition: ntvdm.h:50
#define SetupQueueDeleteW
Definition: fileqsup.c:31
#define SetupOpenFileQueue
Definition: fileqsup.c:29
#define SetupQueueRenameW
Definition: fileqsup.c:32
#define SetupCommitFileQueueW
Definition: fileqsup.c:33
#define SetupCloseFileQueue
Definition: fileqsup.c:30
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
#define STATUS_SUCCESS
Definition: shellext.h:65
#define DPRINT
Definition: sndvol32.h:73
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
base of all file and directory entries
Definition: entries.h:83
ULONG Flags
Definition: fileqsup.h:63
UINT Win32Error
Definition: fileqsup.h:62
PCWSTR Source
Definition: fileqsup.h:61
PCWSTR Target
Definition: fileqsup.h:60
CABINET_CONTEXT CabinetContext
Definition: fileqsup.c:62
WCHAR CurrentCabinetName[MAX_PATH]
Definition: fileqsup.c:64
ULONG RenameCount
Definition: fileqsup.c:56
CAB_SEARCH Search
Definition: fileqsup.c:63
LIST_ENTRY DeleteQueue
Definition: fileqsup.c:52
LIST_ENTRY RenameQueue
Definition: fileqsup.c:55
ULONG DeleteCount
Definition: fileqsup.c:53
LIST_ENTRY CopyQueue
Definition: fileqsup.c:58
ULONG CopyCount
Definition: fileqsup.c:59
BOOLEAN HasCurrentCabinet
Definition: fileqsup.c:61
Definition: typedefs.h:120
struct _LIST_ENTRY * Flink
Definition: typedefs.h:121
LIST_ENTRY ListEntry
Definition: fileqsup.c:41
PWSTR SourceFileName
Definition: fileqsup.c:45
PWSTR SourceCabinet
Definition: fileqsup.c:42
PWSTR SourceRootPath
Definition: fileqsup.c:43
PWSTR TargetFileName
Definition: fileqsup.c:47
PWSTR SourcePath
Definition: fileqsup.c:44
PWSTR TargetDirectory
Definition: fileqsup.c:46
uint16_t * PWSTR
Definition: typedefs.h:56
const uint16_t * PCWSTR
Definition: typedefs.h:57
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:262
#define IN
Definition: typedefs.h:39
#define CONTAINING_RECORD(address, type, field)
Definition: typedefs.h:260
uint32_t ULONG
Definition: typedefs.h:59
#define OUT
Definition: typedefs.h:40
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
struct _FILEQUEUEHEADER * PFILEQUEUEHEADER
static VOID SetupDeleteQueueEntry(IN PQUEUEENTRY Entry)
Definition: fileqsup.c:188
struct _FILEQUEUEHEADER FILEQUEUEHEADER
struct _QUEUEENTRY * PQUEUEENTRY
struct _QUEUEENTRY QUEUEENTRY
BOOL WINAPI SetupQueueCopyWithCab(IN HSPFILEQ QueueHandle, IN PCWSTR SourceRootPath, IN PCWSTR SourcePath OPTIONAL, IN PCWSTR SourceFileName, IN PCWSTR SourceDescription OPTIONAL, IN PCWSTR SourceCabinet OPTIONAL, IN PCWSTR SourceTagFile OPTIONAL, IN PCWSTR TargetDirectory, IN PCWSTR TargetFileName OPTIONAL, IN ULONG CopyStyle)
Definition: fileqsup.c:264
static NTSTATUS SetupExtractFile(IN OUT PFILEQUEUEHEADER QueueHeader, IN PCWSTR CabinetFileName, IN PCWSTR SourceFileName, IN PCWSTR DestinationPathName)
Definition: fileqsup.c:71
#define WINAPI
Definition: msvc.h:6
_At_(*)(_In_ PWSK_CLIENT Client, _In_opt_ PUNICODE_STRING NodeName, _In_opt_ PUNICODE_STRING ServiceName, _In_opt_ ULONG NameSpace, _In_opt_ GUID *Provider, _In_opt_ PADDRINFOEXW Hints, _Outptr_ PADDRINFOEXW *Result, _In_opt_ PEPROCESS OwningProcess, _In_opt_ PETHREAD OwningThread, _Inout_ PIRP Irp Result)(Mem)) NTSTATUS(WSKAPI *PFN_WSK_GET_ADDRESS_INFO
Definition: wsk.h:409
__wchar_t WCHAR
Definition: xmlstorage.h:180