[SETUPLIB][REACTOS][USETUP] Further improve the interfacing with INF and File-Queue...
[reactos.git] / base / setup / usetup / spapisup / fileqsup.c
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 #include "usetup.h"
31
32 #define NDEBUG
33 #include <debug.h>
34
35 /* DEFINITIONS **************************************************************/
36
37 typedef struct _QUEUEENTRY
38 {
39 LIST_ENTRY ListEntry;
40 PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */
41 PWSTR SourceRootPath;
42 PWSTR SourcePath;
43 PWSTR SourceFileName;
44 PWSTR TargetDirectory;
45 PWSTR TargetFileName;
46 } QUEUEENTRY, *PQUEUEENTRY;
47
48 typedef struct _FILEQUEUEHEADER
49 {
50 LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
51 ULONG DeleteCount;
52
53 LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
54 ULONG RenameCount;
55
56 LIST_ENTRY CopyQueue; // PQUEUEENTRY entries
57 ULONG CopyCount;
58
59 BOOLEAN HasCurrentCabinet;
60 CABINET_CONTEXT CabinetContext;
61 CAB_SEARCH Search;
62 WCHAR CurrentCabinetName[MAX_PATH];
63 } FILEQUEUEHEADER, *PFILEQUEUEHEADER;
64
65
66 /* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
67
68 static NTSTATUS
69 SetupExtractFile(
70 IN OUT PFILEQUEUEHEADER QueueHeader,
71 IN PCWSTR CabinetFileName,
72 IN PCWSTR SourceFileName,
73 IN PCWSTR DestinationPathName)
74 {
75 ULONG CabStatus;
76
77 DPRINT("SetupExtractFile(CabinetFileName: '%S', SourceFileName: '%S', DestinationPathName: '%S')\n",
78 CabinetFileName, SourceFileName, DestinationPathName);
79
80 if (QueueHeader->HasCurrentCabinet)
81 {
82 DPRINT("CurrentCabinetName: '%S'\n", QueueHeader->CurrentCabinetName);
83 }
84
85 if (QueueHeader->HasCurrentCabinet &&
86 (wcscmp(CabinetFileName, QueueHeader->CurrentCabinetName) == 0))
87 {
88 DPRINT("Using same cabinet as last time\n");
89
90 /* Use our last location because the files should be sequential */
91 CabStatus = CabinetFindNextFileSequential(&QueueHeader->CabinetContext,
92 SourceFileName,
93 &QueueHeader->Search);
94 if (CabStatus != CAB_STATUS_SUCCESS)
95 {
96 DPRINT("Sequential miss on file: %S\n", SourceFileName);
97
98 /* Looks like we got unlucky */
99 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
100 SourceFileName,
101 &QueueHeader->Search);
102 }
103 }
104 else
105 {
106 DPRINT("Using new cabinet\n");
107
108 if (QueueHeader->HasCurrentCabinet)
109 {
110 QueueHeader->HasCurrentCabinet = FALSE;
111 CabinetCleanup(&QueueHeader->CabinetContext);
112 }
113
114 RtlStringCchCopyW(QueueHeader->CurrentCabinetName,
115 ARRAYSIZE(QueueHeader->CurrentCabinetName),
116 CabinetFileName);
117
118 CabinetInitialize(&QueueHeader->CabinetContext);
119 CabinetSetEventHandlers(&QueueHeader->CabinetContext,
120 NULL, NULL, NULL);
121 CabinetSetCabinetName(&QueueHeader->CabinetContext, CabinetFileName);
122
123 CabStatus = CabinetOpen(&QueueHeader->CabinetContext);
124 if (CabStatus == CAB_STATUS_SUCCESS)
125 {
126 DPRINT("Opened cabinet %S\n", CabinetFileName /*CabinetGetCabinetName(&QueueHeader->CabinetContext)*/);
127 QueueHeader->HasCurrentCabinet = TRUE;
128 }
129 else
130 {
131 DPRINT("Cannot open cabinet (%d)\n", CabStatus);
132 return STATUS_UNSUCCESSFUL;
133 }
134
135 /* We have to start at the beginning here */
136 CabStatus = CabinetFindFirst(&QueueHeader->CabinetContext,
137 SourceFileName,
138 &QueueHeader->Search);
139 }
140
141 if (CabStatus != CAB_STATUS_SUCCESS)
142 {
143 DPRINT1("Unable to find '%S' in cabinet '%S'\n",
144 SourceFileName, CabinetGetCabinetName(&QueueHeader->CabinetContext));
145 return STATUS_UNSUCCESSFUL;
146 }
147
148 CabinetSetDestinationPath(&QueueHeader->CabinetContext, DestinationPathName);
149 CabStatus = CabinetExtractFile(&QueueHeader->CabinetContext, &QueueHeader->Search);
150 if (CabStatus != CAB_STATUS_SUCCESS)
151 {
152 DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus);
153 return STATUS_UNSUCCESSFUL;
154 }
155
156 return STATUS_SUCCESS;
157 }
158
159 HSPFILEQ
160 WINAPI
161 SetupOpenFileQueue(VOID)
162 {
163 PFILEQUEUEHEADER QueueHeader;
164
165 /* Allocate the queue header */
166 QueueHeader = RtlAllocateHeap(ProcessHeap, 0, sizeof(FILEQUEUEHEADER));
167 if (QueueHeader == NULL)
168 return NULL;
169
170 RtlZeroMemory(QueueHeader, sizeof(FILEQUEUEHEADER));
171
172 /* Initialize the file queues */
173 InitializeListHead(&QueueHeader->DeleteQueue);
174 QueueHeader->DeleteCount = 0;
175 InitializeListHead(&QueueHeader->RenameQueue);
176 QueueHeader->RenameCount = 0;
177 InitializeListHead(&QueueHeader->CopyQueue);
178 QueueHeader->CopyCount = 0;
179
180 QueueHeader->HasCurrentCabinet = FALSE;
181
182 return (HSPFILEQ)QueueHeader;
183 }
184
185 static VOID
186 SetupDeleteQueueEntry(
187 IN PQUEUEENTRY Entry)
188 {
189 if (Entry == NULL)
190 return;
191
192 /* Delete all strings */
193 if (Entry->SourceCabinet != NULL)
194 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
195
196 if (Entry->SourceRootPath != NULL)
197 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
198
199 if (Entry->SourcePath != NULL)
200 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
201
202 if (Entry->SourceFileName != NULL)
203 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
204
205 if (Entry->TargetDirectory != NULL)
206 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
207
208 if (Entry->TargetFileName != NULL)
209 RtlFreeHeap(ProcessHeap, 0, Entry->TargetFileName);
210
211 /* Delete queue entry */
212 RtlFreeHeap(ProcessHeap, 0, Entry);
213 }
214
215 BOOL
216 WINAPI
217 SetupCloseFileQueue(
218 IN HSPFILEQ QueueHandle)
219 {
220 PFILEQUEUEHEADER QueueHeader;
221 PLIST_ENTRY ListEntry;
222 PQUEUEENTRY Entry;
223
224 if (QueueHandle == NULL)
225 return FALSE;
226
227 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
228
229 /* Delete the delete queue */
230 while (!IsListEmpty(&QueueHeader->DeleteQueue))
231 {
232 ListEntry = RemoveHeadList(&QueueHeader->DeleteQueue);
233 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
234 SetupDeleteQueueEntry(Entry);
235 }
236
237 /* Delete the rename queue */
238 while (!IsListEmpty(&QueueHeader->RenameQueue))
239 {
240 ListEntry = RemoveHeadList(&QueueHeader->RenameQueue);
241 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
242 SetupDeleteQueueEntry(Entry);
243 }
244
245 /* Delete the copy queue */
246 while (!IsListEmpty(&QueueHeader->CopyQueue))
247 {
248 ListEntry = RemoveHeadList(&QueueHeader->CopyQueue);
249 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
250 SetupDeleteQueueEntry(Entry);
251 }
252
253 /* Delete queue header */
254 RtlFreeHeap(ProcessHeap, 0, QueueHeader);
255
256 return TRUE;
257 }
258
259 /* A simplified version of SetupQueueCopyW that wraps Cabinet support around */
260 BOOL
261 WINAPI
262 SetupQueueCopyWithCab(
263 IN HSPFILEQ QueueHandle,
264 IN PCWSTR SourceRootPath,
265 IN PCWSTR SourcePath OPTIONAL,
266 IN PCWSTR SourceFileName,
267 IN PCWSTR SourceDescription OPTIONAL,
268 IN PCWSTR SourceCabinet OPTIONAL,
269 IN PCWSTR SourceTagFile OPTIONAL,
270 IN PCWSTR TargetDirectory,
271 IN PCWSTR TargetFileName OPTIONAL,
272 IN ULONG CopyStyle)
273 {
274 PFILEQUEUEHEADER QueueHeader;
275 PQUEUEENTRY Entry;
276 ULONG Length;
277
278 if (QueueHandle == NULL ||
279 SourceRootPath == NULL ||
280 SourceFileName == NULL ||
281 TargetDirectory == NULL)
282 {
283 return FALSE;
284 }
285
286 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
287
288 DPRINT("SetupQueueCopy(Cab '%S', SrcRootPath '%S', SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
289 SourceCabinet ? SourceCabinet : L"n/a",
290 SourceRootPath, SourcePath, SourceFileName,
291 TargetDirectory, TargetFileName);
292
293 /* Allocate new queue entry */
294 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
295 if (Entry == NULL)
296 return FALSE;
297
298 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
299
300 /* Copy source cabinet if available */
301 Entry->SourceCabinet = NULL;
302 if (SourceCabinet != NULL)
303 {
304 Length = wcslen(SourceCabinet);
305 Entry->SourceCabinet = RtlAllocateHeap(ProcessHeap,
306 0,
307 (Length + 1) * sizeof(WCHAR));
308 if (Entry->SourceCabinet == NULL)
309 {
310 RtlFreeHeap(ProcessHeap, 0, Entry);
311 return FALSE;
312 }
313 RtlStringCchCopyW(Entry->SourceCabinet, Length + 1, SourceCabinet);
314 }
315
316 /* Copy source root path */
317 Length = wcslen(SourceRootPath);
318 Entry->SourceRootPath = RtlAllocateHeap(ProcessHeap,
319 0,
320 (Length + 1) * sizeof(WCHAR));
321 if (Entry->SourceRootPath == NULL)
322 {
323 if (Entry->SourceCabinet != NULL)
324 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
325
326 RtlFreeHeap(ProcessHeap, 0, Entry);
327 return FALSE;
328 }
329 RtlStringCchCopyW(Entry->SourceRootPath, Length + 1, SourceRootPath);
330
331 /* Copy source path */
332 Entry->SourcePath = NULL;
333 if (SourcePath != NULL)
334 {
335 Length = wcslen(SourcePath);
336 if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
337 Length--;
338 Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
339 0,
340 (Length + 1) * sizeof(WCHAR));
341 if (Entry->SourcePath == NULL)
342 {
343 if (Entry->SourceCabinet != NULL)
344 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
345
346 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
347 RtlFreeHeap(ProcessHeap, 0, Entry);
348 return FALSE;
349 }
350 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
351 }
352
353 /* Copy source file name */
354 Length = wcslen(SourceFileName);
355 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
356 0,
357 (Length + 1) * sizeof(WCHAR));
358 if (Entry->SourceFileName == NULL)
359 {
360 if (Entry->SourcePath != NULL)
361 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
362
363 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
364
365 if (Entry->SourceCabinet != NULL)
366 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
367
368 RtlFreeHeap(ProcessHeap, 0, Entry);
369 return FALSE;
370 }
371 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
372
373 /* Copy target directory */
374 Length = wcslen(TargetDirectory);
375 if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
376 Length--;
377 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
378 0,
379 (Length + 1) * sizeof(WCHAR));
380 if (Entry->TargetDirectory == NULL)
381 {
382 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
383
384 if (Entry->SourcePath != NULL)
385 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
386
387 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
388
389 if (Entry->SourceCabinet != NULL)
390 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
391
392 RtlFreeHeap(ProcessHeap, 0, Entry);
393 return FALSE;
394 }
395 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetDirectory);
396
397 /* Copy optional target filename */
398 Entry->TargetFileName = NULL;
399 if (TargetFileName != NULL)
400 {
401 Length = wcslen(TargetFileName);
402 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
403 0,
404 (Length + 1) * sizeof(WCHAR));
405 if (Entry->TargetFileName == NULL)
406 {
407 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
408 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
409
410 if (Entry->SourcePath != NULL)
411 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
412
413 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
414
415 if (Entry->SourceCabinet != NULL)
416 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
417
418 RtlFreeHeap(ProcessHeap, 0, Entry);
419 return FALSE;
420 }
421 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
422 }
423
424 /* Append queue entry */
425 InsertTailList(&QueueHeader->CopyQueue, &Entry->ListEntry);
426 ++QueueHeader->CopyCount;
427
428 return TRUE;
429 }
430
431 BOOL
432 WINAPI
433 SetupQueueDeleteW(
434 IN HSPFILEQ QueueHandle,
435 IN PCWSTR PathPart1,
436 IN PCWSTR PathPart2 OPTIONAL)
437 {
438 PFILEQUEUEHEADER QueueHeader;
439 PQUEUEENTRY Entry;
440 ULONG Length;
441
442 if (QueueHandle == NULL || PathPart1 == NULL)
443 {
444 return FALSE;
445 }
446
447 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
448
449 DPRINT1("SetupQueueDeleteW(PathPart1 '%S', PathPart2 '%S')\n",
450 PathPart1, PathPart2);
451
452 /* Allocate new queue entry */
453 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
454 if (Entry == NULL)
455 return FALSE;
456
457 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
458
459 Entry->SourceCabinet = NULL;
460 Entry->SourceRootPath = NULL;
461 Entry->SourcePath = NULL;
462 Entry->SourceFileName = NULL;
463
464 /* Copy first part of path */
465 Length = wcslen(PathPart1);
466 // if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
467 // Length--;
468 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
469 0,
470 (Length + 1) * sizeof(WCHAR));
471 if (Entry->TargetDirectory == NULL)
472 {
473 RtlFreeHeap(ProcessHeap, 0, Entry);
474 return FALSE;
475 }
476 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, PathPart1);
477
478 /* Copy optional second part of path */
479 if (PathPart2 != NULL)
480 {
481 Length = wcslen(PathPart2);
482 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
483 0,
484 (Length + 1) * sizeof(WCHAR));
485 if (Entry->TargetFileName == NULL)
486 {
487 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
488 RtlFreeHeap(ProcessHeap, 0, Entry);
489 return FALSE;
490 }
491 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, PathPart2);
492 }
493
494 /* Append the queue entry */
495 InsertTailList(&QueueHeader->DeleteQueue, &Entry->ListEntry);
496 ++QueueHeader->DeleteCount;
497
498 return TRUE;
499 }
500
501 BOOL
502 WINAPI
503 SetupQueueRenameW(
504 IN HSPFILEQ QueueHandle,
505 IN PCWSTR SourcePath,
506 IN PCWSTR SourceFileName OPTIONAL,
507 IN PCWSTR TargetPath OPTIONAL,
508 IN PCWSTR TargetFileName)
509 {
510 PFILEQUEUEHEADER QueueHeader;
511 PQUEUEENTRY Entry;
512 ULONG Length;
513
514 if (QueueHandle == NULL ||
515 SourcePath == NULL ||
516 TargetFileName == NULL)
517 {
518 return FALSE;
519 }
520
521 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
522
523 DPRINT1("SetupQueueRenameW(SrcPath '%S', SrcFN '%S' --> DstPath '%S', DstFN '%S')\n",
524 SourcePath, SourceFileName, TargetPath, TargetFileName);
525
526 /* Allocate a new queue entry */
527 Entry = RtlAllocateHeap(ProcessHeap, 0, sizeof(QUEUEENTRY));
528 if (Entry == NULL)
529 return FALSE;
530
531 RtlZeroMemory(Entry, sizeof(QUEUEENTRY));
532
533 Entry->SourceCabinet = NULL;
534 Entry->SourceRootPath = NULL;
535
536 /* Copy source path */
537 Length = wcslen(SourcePath);
538 if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
539 Length--;
540 Entry->SourcePath = RtlAllocateHeap(ProcessHeap,
541 0,
542 (Length + 1) * sizeof(WCHAR));
543 if (Entry->SourcePath == NULL)
544 {
545 RtlFreeHeap(ProcessHeap, 0, Entry);
546 return FALSE;
547 }
548 RtlStringCchCopyW(Entry->SourcePath, Length + 1, SourcePath);
549
550 /* Copy optional source file name */
551 Entry->SourceFileName = NULL;
552 if (SourceFileName != NULL)
553 {
554 Length = wcslen(SourceFileName);
555 Entry->SourceFileName = (WCHAR*)RtlAllocateHeap(ProcessHeap,
556 0,
557 (Length + 1) * sizeof(WCHAR));
558 if (Entry->SourceFileName == NULL)
559 {
560 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
561 RtlFreeHeap(ProcessHeap, 0, Entry);
562 return FALSE;
563 }
564 RtlStringCchCopyW(Entry->SourceFileName, Length + 1, SourceFileName);
565 }
566
567 /* Copy optional target directory */
568 Entry->TargetDirectory = NULL;
569 if (TargetPath != NULL)
570 {
571 Length = wcslen(TargetPath);
572 if ((Length > 0) && (TargetPath[Length - 1] == L'\\'))
573 Length--;
574 Entry->TargetDirectory = RtlAllocateHeap(ProcessHeap,
575 0,
576 (Length + 1) * sizeof(WCHAR));
577 if (Entry->TargetDirectory == NULL)
578 {
579 if (Entry->SourceFileName != NULL)
580 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
581
582 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
583 RtlFreeHeap(ProcessHeap, 0, Entry);
584 return FALSE;
585 }
586 RtlStringCchCopyW(Entry->TargetDirectory, Length + 1, TargetPath);
587 }
588
589 /* Copy target filename */
590 Length = wcslen(TargetFileName);
591 Entry->TargetFileName = RtlAllocateHeap(ProcessHeap,
592 0,
593 (Length + 1) * sizeof(WCHAR));
594 if (Entry->TargetFileName == NULL)
595 {
596 if (Entry->TargetDirectory != NULL)
597 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
598
599 if (Entry->SourceFileName != NULL)
600 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFileName);
601
602 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
603 RtlFreeHeap(ProcessHeap, 0, Entry);
604 return FALSE;
605 }
606 RtlStringCchCopyW(Entry->TargetFileName, Length + 1, TargetFileName);
607
608 /* Append the queue entry */
609 InsertTailList(&QueueHeader->RenameQueue, &Entry->ListEntry);
610 ++QueueHeader->RenameCount;
611
612 return TRUE;
613 }
614
615 BOOL
616 WINAPI
617 SetupCommitFileQueueW(
618 IN HWND Owner,
619 IN HSPFILEQ QueueHandle,
620 IN PSP_FILE_CALLBACK_W MsgHandler,
621 IN PVOID Context OPTIONAL)
622 {
623 BOOL Success = TRUE; // Suppose success
624 NTSTATUS Status;
625 PFILEQUEUEHEADER QueueHeader;
626 PLIST_ENTRY ListEntry;
627 PQUEUEENTRY Entry;
628 FILEPATHS_W FilePathInfo;
629 WCHAR CabinetName[MAX_PATH];
630 WCHAR FileSrcPath[MAX_PATH];
631 WCHAR FileDstPath[MAX_PATH];
632
633 if (QueueHandle == NULL)
634 return FALSE;
635
636 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
637
638 MsgHandler(Context,
639 SPFILENOTIFY_STARTQUEUE,
640 (UINT_PTR)Owner,
641 0);
642
643
644 /*
645 * Commit the delete queue
646 */
647
648 MsgHandler(Context,
649 SPFILENOTIFY_STARTSUBQUEUE,
650 FILEOP_DELETE,
651 QueueHeader->DeleteCount);
652
653 ListEntry = QueueHeader->DeleteQueue.Flink;
654 while (ListEntry != &QueueHeader->DeleteQueue)
655 {
656 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
657 ListEntry = ListEntry->Flink;
658
659 /* Build the full target path */
660 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
661 Entry->TargetDirectory, Entry->TargetFileName);
662 // RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
663 // ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
664
665 DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath);
666
667 FilePathInfo.Target = FileDstPath;
668 FilePathInfo.Source = NULL;
669 FilePathInfo.Win32Error = STATUS_SUCCESS;
670 FilePathInfo.Flags = 0; // FIXME: Unused yet...
671
672 MsgHandler(Context,
673 SPFILENOTIFY_STARTDELETE,
674 (UINT_PTR)&FilePathInfo,
675 FILEOP_DELETE);
676
677 /* Force-delete the file */
678 Status = SetupDeleteFile(FileDstPath, TRUE);
679 if (!NT_SUCCESS(Status))
680 {
681 /* An error happened */
682 FilePathInfo.Win32Error = (UINT)Status;
683 MsgHandler(Context,
684 SPFILENOTIFY_DELETEERROR,
685 (UINT_PTR)&FilePathInfo,
686 0);
687 Success = FALSE;
688 }
689
690 /* This notification is always sent, even in case of error */
691 FilePathInfo.Win32Error = (UINT)Status;
692 MsgHandler(Context,
693 SPFILENOTIFY_ENDDELETE,
694 (UINT_PTR)&FilePathInfo,
695 0);
696 }
697
698 MsgHandler(Context,
699 SPFILENOTIFY_ENDSUBQUEUE,
700 FILEOP_DELETE,
701 0);
702
703
704 /*
705 * Commit the rename queue
706 */
707
708 MsgHandler(Context,
709 SPFILENOTIFY_STARTSUBQUEUE,
710 FILEOP_RENAME,
711 QueueHeader->RenameCount);
712
713 ListEntry = QueueHeader->RenameQueue.Flink;
714 while (ListEntry != &QueueHeader->RenameQueue)
715 {
716 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
717 ListEntry = ListEntry->Flink;
718
719 /* Build the full source path */
720 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2,
721 Entry->SourcePath, Entry->SourceFileName);
722
723 /* Build the full target path */
724 CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
725 Entry->TargetDirectory, Entry->TargetFileName);
726 // RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
727 // ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
728
729 DPRINT1(" -----> " "Rename: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
730
731 FilePathInfo.Target = FileDstPath;
732 FilePathInfo.Source = FileSrcPath;
733 FilePathInfo.Win32Error = STATUS_SUCCESS;
734 FilePathInfo.Flags = 0; // FIXME: Unused yet...
735
736 MsgHandler(Context,
737 SPFILENOTIFY_STARTRENAME,
738 (UINT_PTR)&FilePathInfo,
739 FILEOP_RENAME);
740
741 /* Move or rename the file */
742 Status = SetupMoveFile(FileSrcPath, FileDstPath,
743 MOVEFILE_REPLACE_EXISTING
744 | MOVEFILE_COPY_ALLOWED
745 | MOVEFILE_WRITE_THROUGH);
746 if (!NT_SUCCESS(Status))
747 {
748 /* An error happened */
749 FilePathInfo.Win32Error = (UINT)Status;
750 MsgHandler(Context,
751 SPFILENOTIFY_RENAMEERROR,
752 (UINT_PTR)&FilePathInfo,
753 0);
754 Success = FALSE;
755 }
756
757 /* This notification is always sent, even in case of error */
758 FilePathInfo.Win32Error = (UINT)Status;
759 MsgHandler(Context,
760 SPFILENOTIFY_ENDRENAME,
761 (UINT_PTR)&FilePathInfo,
762 0);
763 }
764
765 MsgHandler(Context,
766 SPFILENOTIFY_ENDSUBQUEUE,
767 FILEOP_RENAME,
768 0);
769
770
771 /*
772 * Commit the copy queue
773 */
774
775 MsgHandler(Context,
776 SPFILENOTIFY_STARTSUBQUEUE,
777 FILEOP_COPY,
778 QueueHeader->CopyCount);
779
780 ListEntry = QueueHeader->CopyQueue.Flink;
781 while (ListEntry != &QueueHeader->CopyQueue)
782 {
783 Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
784 ListEntry = ListEntry->Flink;
785
786 /* Build the full source path */
787 CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
788 Entry->SourceRootPath, Entry->SourcePath,
789 Entry->SourceFileName);
790
791 /* Build the full target path */
792 RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
793
794 /*
795 * If the file is in a cabinet, use only the destination path.
796 * Otherwise possibly use a different target name.
797 */
798 if (Entry->SourceCabinet == NULL)
799 {
800 if (Entry->TargetFileName != NULL)
801 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
802 else
803 ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
804 }
805
806 DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
807
808 //
809 // Technically, here we should create the target directory,
810 // if it does not already exist... before calling the handler!
811 //
812
813 FilePathInfo.Target = FileDstPath;
814 FilePathInfo.Source = FileSrcPath; // when SourceCabinet not NULL, use CabinetName ...
815 FilePathInfo.Win32Error = STATUS_SUCCESS;
816 FilePathInfo.Flags = 0; // FIXME: Unused yet...
817
818 MsgHandler(Context,
819 SPFILENOTIFY_STARTCOPY,
820 (UINT_PTR)&FilePathInfo,
821 FILEOP_COPY);
822
823 if (Entry->SourceCabinet != NULL)
824 {
825 /*
826 * Extract the file from the cabinet.
827 * The cabinet must be in Entry->SourceRootPath only!
828 * (ignore Entry->SourcePath).
829 */
830 CombinePaths(CabinetName, ARRAYSIZE(CabinetName), 3,
831 Entry->SourceRootPath, Entry->SourcePath,
832 Entry->SourceCabinet);
833 Status = SetupExtractFile(QueueHeader,
834 CabinetName,
835 Entry->SourceFileName,
836 FileDstPath);
837 }
838 else
839 {
840 /* Copy the file */
841 Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
842 }
843
844 if (!NT_SUCCESS(Status))
845 {
846 /* An error happened */
847 FilePathInfo.Win32Error = (UINT)Status;
848 MsgHandler(Context,
849 SPFILENOTIFY_COPYERROR,
850 (UINT_PTR)&FilePathInfo,
851 (UINT_PTR)NULL); // FIXME: Unused yet...
852 Success = FALSE;
853 }
854
855 /* This notification is always sent, even in case of error */
856 FilePathInfo.Win32Error = (UINT)Status;
857 MsgHandler(Context,
858 SPFILENOTIFY_ENDCOPY,
859 (UINT_PTR)&FilePathInfo,
860 0);
861 }
862
863 MsgHandler(Context,
864 SPFILENOTIFY_ENDSUBQUEUE,
865 FILEOP_COPY,
866 0);
867
868
869 /* All the queues have been committed */
870 MsgHandler(Context,
871 SPFILENOTIFY_ENDQUEUE,
872 (UINT_PTR)Success,
873 0);
874
875 return Success;
876 }
877
878
879 /* GLOBALS *******************************************************************/
880
881 pSpFileQueueOpen SpFileQueueOpen = SetupOpenFileQueue;
882 pSpFileQueueClose SpFileQueueClose = SetupCloseFileQueue;
883 pSpFileQueueCopy SpFileQueueCopy = SetupQueueCopyWithCab;
884 pSpFileQueueDelete SpFileQueueDelete = SetupQueueDeleteW;
885 pSpFileQueueRename SpFileQueueRename = SetupQueueRenameW;
886 pSpFileQueueCommit SpFileQueueCommit = SetupCommitFileQueueW;
887
888 /* EOF */