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
39 typedef struct _QUEUEENTRY
40 {
41 LIST_ENTRY ListEntry;
42 PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */
43 PWSTR SourceRootPath;
44 PWSTR SourcePath;
45 PWSTR SourceFileName;
46 PWSTR TargetDirectory;
47 PWSTR TargetFileName;
48 } QUEUEENTRY, *PQUEUEENTRY;
49
50 typedef struct _FILEQUEUEHEADER
51 {
52 LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
53 ULONG DeleteCount;
54
55 LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
56 ULONG RenameCount;
57
58 LIST_ENTRY CopyQueue; // PQUEUEENTRY entries
59 ULONG CopyCount;
60
61 BOOLEAN HasCurrentCabinet;
62 CABINET_CONTEXT CabinetContext;
63 CAB_SEARCH Search;
64 WCHAR CurrentCabinetName[MAX_PATH];
65 } FILEQUEUEHEADER, *PFILEQUEUEHEADER;
66
67
68 /* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
69
70 static NTSTATUS
SetupExtractFile(IN OUT PFILEQUEUEHEADER QueueHeader,IN PCWSTR CabinetFileName,IN PCWSTR SourceFileName,IN PCWSTR DestinationPathName)71 SetupExtractFile(
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
161 HSPFILEQ
162 WINAPI
SetupOpenFileQueue(VOID)163 SetupOpenFileQueue(VOID)
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
187 static VOID
SetupDeleteQueueEntry(IN PQUEUEENTRY Entry)188 SetupDeleteQueueEntry(
189 IN PQUEUEENTRY Entry)
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 */
214 RtlFreeHeap(ProcessHeap, 0, Entry);
215 }
216
217 BOOL
218 WINAPI
SetupCloseFileQueue(IN HSPFILEQ QueueHandle)219 SetupCloseFileQueue(
220 IN HSPFILEQ QueueHandle)
221 {
222 PFILEQUEUEHEADER QueueHeader;
223 PLIST_ENTRY ListEntry;
224 PQUEUEENTRY Entry;
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);
236 SetupDeleteQueueEntry(Entry);
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);
244 SetupDeleteQueueEntry(Entry);
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);
252 SetupDeleteQueueEntry(Entry);
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 */
262 BOOL
263 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)264 SetupQueueCopyWithCab(
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;
277 PQUEUEENTRY Entry;
278 ULONG Length;
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 */
296 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
297 if (Entry == NULL)
298 return FALSE;
299
300 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
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 {
312 RtlFreeHeap(ProcessHeap, 0, Entry);
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
328 RtlFreeHeap(ProcessHeap, 0, Entry);
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);
349 RtlFreeHeap(ProcessHeap, 0, Entry);
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
370 RtlFreeHeap(ProcessHeap, 0, Entry);
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
394 RtlFreeHeap(ProcessHeap, 0, Entry);
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
420 RtlFreeHeap(ProcessHeap, 0, Entry);
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
433 BOOL
434 WINAPI
SetupQueueDeleteW(IN HSPFILEQ QueueHandle,IN PCWSTR PathPart1,IN PCWSTR PathPart2 OPTIONAL)435 SetupQueueDeleteW(
436 IN HSPFILEQ QueueHandle,
437 IN PCWSTR PathPart1,
438 IN PCWSTR PathPart2 OPTIONAL)
439 {
440 PFILEQUEUEHEADER QueueHeader;
441 PQUEUEENTRY Entry;
442 ULONG Length;
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 */
455 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
456 if (Entry == NULL)
457 return FALSE;
458
459 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
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 {
475 RtlFreeHeap(ProcessHeap, 0, Entry);
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);
490 RtlFreeHeap(ProcessHeap, 0, Entry);
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
503 BOOL
504 WINAPI
SetupQueueRenameW(IN HSPFILEQ QueueHandle,IN PCWSTR SourcePath,IN PCWSTR SourceFileName OPTIONAL,IN PCWSTR TargetPath OPTIONAL,IN PCWSTR TargetFileName)505 SetupQueueRenameW(
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;
513 PQUEUEENTRY Entry;
514 ULONG Length;
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 */
529 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
530 if (Entry == NULL)
531 return FALSE;
532
533 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
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 {
547 RtlFreeHeap(ProcessHeap, 0, Entry);
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);
563 RtlFreeHeap(ProcessHeap, 0, Entry);
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);
585 RtlFreeHeap(ProcessHeap, 0, Entry);
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);
605 RtlFreeHeap(ProcessHeap, 0, Entry);
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
617 BOOL
618 WINAPI
SetupCommitFileQueueW(IN HWND Owner,IN HSPFILEQ QueueHandle,IN PSP_FILE_CALLBACK_W MsgHandler,IN PVOID Context OPTIONAL)619 SetupCommitFileQueueW(
620 IN HWND Owner,
621 IN HSPFILEQ QueueHandle,
622 IN PSP_FILE_CALLBACK_W MsgHandler,
623 IN PVOID Context OPTIONAL)
624 {
625 BOOL Success = TRUE; // Suppose success
626 UINT Result;
627 NTSTATUS Status;
628 PFILEQUEUEHEADER QueueHeader;
629 PLIST_ENTRY ListEntry;
630 PQUEUEENTRY Entry;
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,
641 SPFILENOTIFY_STARTQUEUE,
642 (UINT_PTR)Owner,
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,
655 SPFILENOTIFY_STARTSUBQUEUE,
656 FILEOP_DELETE,
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,
683 SPFILENOTIFY_STARTDELETE,
684 (UINT_PTR)&FilePathInfo,
685 FILEOP_DELETE);
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
695 RetryDelete:
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,
703 SPFILENOTIFY_DELETEERROR,
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
719 EndDelete:
720 /* This notification is always sent, even in case of error */
721 FilePathInfo.Win32Error = (UINT)Status;
722 MsgHandler(Context,
723 SPFILENOTIFY_ENDDELETE,
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,
733 SPFILENOTIFY_ENDSUBQUEUE,
734 FILEOP_DELETE,
735 0);
736 }
737
738
739 /*
740 * Commit the rename queue
741 */
742
743 if (!IsListEmpty(&QueueHeader->RenameQueue))
744 {
745 Result = MsgHandler(Context,
746 SPFILENOTIFY_STARTSUBQUEUE,
747 FILEOP_RENAME,
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,
778 SPFILENOTIFY_STARTRENAME,
779 (UINT_PTR)&FilePathInfo,
780 FILEOP_RENAME);
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
790 RetryRename:
791 /* Move or rename the file */
792 Status = SetupMoveFile(FileSrcPath, FileDstPath,
793 MOVEFILE_REPLACE_EXISTING
794 | MOVEFILE_COPY_ALLOWED
795 | MOVEFILE_WRITE_THROUGH);
796 if (!NT_SUCCESS(Status))
797 {
798 /* An error happened */
799 FilePathInfo.Win32Error = (UINT)Status;
800 Result = MsgHandler(Context,
801 SPFILENOTIFY_RENAMEERROR,
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
817 EndRename:
818 /* This notification is always sent, even in case of error */
819 FilePathInfo.Win32Error = (UINT)Status;
820 MsgHandler(Context,
821 SPFILENOTIFY_ENDRENAME,
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,
831 SPFILENOTIFY_ENDSUBQUEUE,
832 FILEOP_RENAME,
833 0);
834 }
835
836
837 /*
838 * Commit the copy queue
839 */
840
841 if (!IsListEmpty(&QueueHeader->CopyQueue))
842 {
843 Result = MsgHandler(Context,
844 SPFILENOTIFY_STARTSUBQUEUE,
845 FILEOP_COPY,
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,
913 SPFILENOTIFY_STARTCOPY,
914 (UINT_PTR)&FilePathInfo,
915 FILEOP_COPY);
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
925 RetryCopy:
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,
949 SPFILENOTIFY_COPYERROR,
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
967 EndCopy:
968 /* This notification is always sent, even in case of error */
969 FilePathInfo.Win32Error = (UINT)Status;
970 MsgHandler(Context,
971 SPFILENOTIFY_ENDCOPY,
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,
981 SPFILENOTIFY_ENDSUBQUEUE,
982 FILEOP_COPY,
983 0);
984 }
985
986
987 Quit:
988 /* All the queues have been committed */
989 MsgHandler(Context,
990 SPFILENOTIFY_ENDQUEUE,
991 (UINT_PTR)Success,
992 0);
993
994 return Success;
995 }
996
997
998 /* GLOBALS *******************************************************************/
999
1000 pSpFileQueueOpen SpFileQueueOpen = SetupOpenFileQueue;
1001 pSpFileQueueClose SpFileQueueClose = SetupCloseFileQueue;
1002 pSpFileQueueCopy SpFileQueueCopy = SetupQueueCopyWithCab;
1003 pSpFileQueueDelete SpFileQueueDelete = SetupQueueDeleteW;
1004 pSpFileQueueRename SpFileQueueRename = SetupQueueRenameW;
1005 pSpFileQueueCommit SpFileQueueCommit = SetupCommitFileQueueW;
1006
1007 /* EOF */
1008