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