ReactOS  0.4.14-dev-358-gbef841c
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 #include "usetup.h"
31 
32 #define NDEBUG
33 #include <debug.h>
34 
35 /* DEFINITIONS **************************************************************/
36 
37 typedef struct _QUEUEENTRY
38 {
40  PWSTR SourceCabinet; /* May be NULL if the file is not in a cabinet */
47 
48 typedef struct _FILEQUEUEHEADER
49 {
50  LIST_ENTRY DeleteQueue; // PQUEUEENTRY entries
52 
53  LIST_ENTRY RenameQueue; // PQUEUEENTRY entries
55 
56  LIST_ENTRY CopyQueue; // PQUEUEENTRY entries
58 
64 
65 
66 /* SETUP* API COMPATIBILITY FUNCTIONS ****************************************/
67 
68 static NTSTATUS
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
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
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 */
213 }
214 
215 BOOL
216 WINAPI
218  IN HSPFILEQ QueueHandle)
219 {
220  PFILEQUEUEHEADER QueueHeader;
221  PLIST_ENTRY ListEntry;
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);
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);
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);
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
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;
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 */
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  {
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 
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);
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 
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 
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 
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
434  IN HSPFILEQ QueueHandle,
435  IN PCWSTR PathPart1,
436  IN PCWSTR PathPart2 OPTIONAL)
437 {
438  PFILEQUEUEHEADER QueueHeader;
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 */
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  {
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);
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
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;
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 */
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  {
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);
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);
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);
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
618  IN HWND Owner,
619  IN HSPFILEQ QueueHandle,
620  IN PSP_FILE_CALLBACK_W MsgHandler,
622 {
623  BOOL Success = TRUE; // Suppose success
624  UINT Result;
626  PFILEQUEUEHEADER QueueHeader;
627  PLIST_ENTRY ListEntry;
629  FILEPATHS_W FilePathInfo;
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  Result = MsgHandler(Context,
640  (UINT_PTR)Owner,
641  0);
642  if (Result == FILEOP_ABORT)
643  return FALSE;
644 
645 
646  /*
647  * Commit the delete queue
648  */
649 
650  if (!IsListEmpty(&QueueHeader->DeleteQueue))
651  {
652  Result = MsgHandler(Context,
655  QueueHeader->DeleteCount);
656  if (Result == FILEOP_ABORT)
657  {
658  Success = FALSE;
659  goto Quit;
660  }
661  }
662 
663  for (ListEntry = QueueHeader->DeleteQueue.Flink;
664  ListEntry != &QueueHeader->DeleteQueue;
665  ListEntry = ListEntry->Flink)
666  {
667  Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
668 
669  /* Build the full target path */
670  CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
671  Entry->TargetDirectory, Entry->TargetFileName);
672 
673  DPRINT1(" -----> " "Delete: '%S'\n", FileDstPath);
674 
675  FilePathInfo.Target = FileDstPath;
676  FilePathInfo.Source = NULL;
677  FilePathInfo.Win32Error = STATUS_SUCCESS;
678  FilePathInfo.Flags = 0; // FIXME: Unused yet...
679 
680  Result = MsgHandler(Context,
682  (UINT_PTR)&FilePathInfo,
683  FILEOP_DELETE);
684  if (Result == FILEOP_ABORT)
685  {
686  Success = FALSE;
687  goto EndDelete;
688  }
689  else if (Result == FILEOP_SKIP)
690  goto EndDelete;
691  // else (Result == FILEOP_DOIT)
692 
693 RetryDelete:
694  /* Force-delete the file */
695  Status = SetupDeleteFile(FileDstPath, TRUE);
696  if (!NT_SUCCESS(Status))
697  {
698  /* An error happened */
699  FilePathInfo.Win32Error = (UINT)Status;
700  Result = MsgHandler(Context,
702  (UINT_PTR)&FilePathInfo,
703  0);
704  if (Result == FILEOP_ABORT)
705  {
706  Success = FALSE;
707  goto EndDelete;
708  }
709  else if (Result == FILEOP_SKIP)
710  goto EndDelete;
711  else if (Result == FILEOP_RETRY)
712  goto RetryDelete;
713 
714  Success = FALSE;
715  }
716 
717 EndDelete:
718  /* This notification is always sent, even in case of error */
719  FilePathInfo.Win32Error = (UINT)Status;
720  MsgHandler(Context,
722  (UINT_PTR)&FilePathInfo,
723  0);
724  if (Success == FALSE /* && Result == FILEOP_ABORT */)
725  goto Quit;
726  }
727 
728  if (!IsListEmpty(&QueueHeader->DeleteQueue))
729  {
730  MsgHandler(Context,
733  0);
734  }
735 
736 
737  /*
738  * Commit the rename queue
739  */
740 
741  if (!IsListEmpty(&QueueHeader->RenameQueue))
742  {
743  Result = MsgHandler(Context,
746  QueueHeader->RenameCount);
747  if (Result == FILEOP_ABORT)
748  {
749  Success = FALSE;
750  goto Quit;
751  }
752  }
753 
754  for (ListEntry = QueueHeader->RenameQueue.Flink;
755  ListEntry != &QueueHeader->RenameQueue;
756  ListEntry = ListEntry->Flink)
757  {
758  Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
759 
760  /* Build the full source path */
761  CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 2,
762  Entry->SourcePath, Entry->SourceFileName);
763 
764  /* Build the full target path */
765  CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
766  Entry->TargetDirectory, Entry->TargetFileName);
767 
768  DPRINT1(" -----> " "Rename: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
769 
770  FilePathInfo.Target = FileDstPath;
771  FilePathInfo.Source = FileSrcPath;
772  FilePathInfo.Win32Error = STATUS_SUCCESS;
773  FilePathInfo.Flags = 0; // FIXME: Unused yet...
774 
775  Result = MsgHandler(Context,
777  (UINT_PTR)&FilePathInfo,
778  FILEOP_RENAME);
779  if (Result == FILEOP_ABORT)
780  {
781  Success = FALSE;
782  goto EndRename;
783  }
784  else if (Result == FILEOP_SKIP)
785  goto EndRename;
786  // else (Result == FILEOP_DOIT)
787 
788 RetryRename:
789  /* Move or rename the file */
790  Status = SetupMoveFile(FileSrcPath, FileDstPath,
794  if (!NT_SUCCESS(Status))
795  {
796  /* An error happened */
797  FilePathInfo.Win32Error = (UINT)Status;
798  Result = MsgHandler(Context,
800  (UINT_PTR)&FilePathInfo,
801  0);
802  if (Result == FILEOP_ABORT)
803  {
804  Success = FALSE;
805  goto EndRename;
806  }
807  else if (Result == FILEOP_SKIP)
808  goto EndRename;
809  else if (Result == FILEOP_RETRY)
810  goto RetryRename;
811 
812  Success = FALSE;
813  }
814 
815 EndRename:
816  /* This notification is always sent, even in case of error */
817  FilePathInfo.Win32Error = (UINT)Status;
818  MsgHandler(Context,
820  (UINT_PTR)&FilePathInfo,
821  0);
822  if (Success == FALSE /* && Result == FILEOP_ABORT */)
823  goto Quit;
824  }
825 
826  if (!IsListEmpty(&QueueHeader->RenameQueue))
827  {
828  MsgHandler(Context,
831  0);
832  }
833 
834 
835  /*
836  * Commit the copy queue
837  */
838 
839  if (!IsListEmpty(&QueueHeader->CopyQueue))
840  {
841  Result = MsgHandler(Context,
843  FILEOP_COPY,
844  QueueHeader->CopyCount);
845  if (Result == FILEOP_ABORT)
846  {
847  Success = FALSE;
848  goto Quit;
849  }
850  }
851 
852  for (ListEntry = QueueHeader->CopyQueue.Flink;
853  ListEntry != &QueueHeader->CopyQueue;
854  ListEntry = ListEntry->Flink)
855  {
856  Entry = CONTAINING_RECORD(ListEntry, QUEUEENTRY, ListEntry);
857 
858  //
859  // TODO: Send a SPFILENOTIFY_NEEDMEDIA notification
860  // when we switch to a new installation media.
861  // Param1 = (UINT_PTR)(PSOURCE_MEDIA)SourceMediaInfo;
862  // Param2 = (UINT_PTR)(TCHAR[MAX_PATH])NewPathInfo;
863  //
864 
865  /* Build the full source path */
866  if (Entry->SourceCabinet == NULL)
867  {
868  CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
869  Entry->SourceRootPath, Entry->SourcePath,
870  Entry->SourceFileName);
871  }
872  else
873  {
874  /*
875  * The cabinet must be in Entry->SourceRootPath only!
876  * (Should we ignore Entry->SourcePath?)
877  */
878  CombinePaths(FileSrcPath, ARRAYSIZE(FileSrcPath), 3,
879  Entry->SourceRootPath, Entry->SourcePath,
880  Entry->SourceCabinet);
881  }
882 
883  /* Build the full target path */
884  RtlStringCchCopyW(FileDstPath, ARRAYSIZE(FileDstPath), Entry->TargetDirectory);
885  if (Entry->SourceCabinet == NULL)
886  {
887  /* If the file is not in a cabinet, possibly use a different target name */
888  if (Entry->TargetFileName != NULL)
889  ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->TargetFileName);
890  else
891  ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
892  }
893  else
894  {
895  ConcatPaths(FileDstPath, ARRAYSIZE(FileDstPath), 1, Entry->SourceFileName);
896  }
897 
898  DPRINT(" -----> " "Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
899 
900  //
901  // Technically, here we should create the target directory,
902  // if it does not already exist... before calling the handler!
903  //
904 
905  FilePathInfo.Target = FileDstPath;
906  FilePathInfo.Source = FileSrcPath;
907  FilePathInfo.Win32Error = STATUS_SUCCESS;
908  FilePathInfo.Flags = 0; // FIXME: Unused yet...
909 
910  Result = MsgHandler(Context,
912  (UINT_PTR)&FilePathInfo,
913  FILEOP_COPY);
914  if (Result == FILEOP_ABORT)
915  {
916  Success = FALSE;
917  goto EndCopy;
918  }
919  else if (Result == FILEOP_SKIP)
920  goto EndCopy;
921  // else (Result == FILEOP_DOIT)
922 
923 RetryCopy:
924  if (Entry->SourceCabinet != NULL)
925  {
926  /*
927  * The file is in a cabinet, use only the destination path
928  * and keep the source name as the target name.
929  */
930  /* Extract the file from the cabinet */
931  Status = SetupExtractFile(QueueHeader,
932  FileSrcPath, // Specifies the cabinet path
933  Entry->SourceFileName,
934  Entry->TargetDirectory);
935  }
936  else
937  {
938  /* Copy the file */
939  Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
940  }
941 
942  if (!NT_SUCCESS(Status))
943  {
944  /* An error happened */
945  FilePathInfo.Win32Error = (UINT)Status;
946  Result = MsgHandler(Context,
948  (UINT_PTR)&FilePathInfo,
949  (UINT_PTR)NULL); // FIXME: Unused yet...
950  if (Result == FILEOP_ABORT)
951  {
952  Success = FALSE;
953  goto EndCopy;
954  }
955  else if (Result == FILEOP_SKIP)
956  goto EndCopy;
957  else if (Result == FILEOP_RETRY)
958  goto RetryCopy;
959  else if (Result == FILEOP_NEWPATH)
960  goto RetryCopy; // TODO!
961 
962  Success = FALSE;
963  }
964 
965 EndCopy:
966  /* This notification is always sent, even in case of error */
967  FilePathInfo.Win32Error = (UINT)Status;
968  MsgHandler(Context,
970  (UINT_PTR)&FilePathInfo,
971  0);
972  if (Success == FALSE /* && Result == FILEOP_ABORT */)
973  goto Quit;
974  }
975 
976  if (!IsListEmpty(&QueueHeader->CopyQueue))
977  {
978  MsgHandler(Context,
980  FILEOP_COPY,
981  0);
982  }
983 
984 
985 Quit:
986  /* All the queues have been committed */
987  MsgHandler(Context,
989  (UINT_PTR)Success,
990  0);
991 
992  return Success;
993 }
994 
995 
996 /* GLOBALS *******************************************************************/
997 
1004 
1005 /* EOF */
VOID CabinetInitialize(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:501
static NTSTATUS SetupExtractFile(IN OUT PFILEQUEUEHEADER QueueHeader, IN PCWSTR CabinetFileName, IN PCWSTR SourceFileName, IN PCWSTR DestinationPathName)
Definition: fileqsup.c:69
struct _QUEUEENTRY * PQUEUEENTRY
pSpFileQueueOpen SpFileQueueOpen
Definition: fileqsup.c:153
WCHAR CurrentCabinetName[MAX_PATH]
Definition: fileqsup.c:62
PCWSTR CabinetGetCabinetName(IN PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:568
const uint16_t * PCWSTR
Definition: typedefs.h:55
#define IN
Definition: typedefs.h:38
PWSTR SourcePath
Definition: fileqsup.c:42
ULONG CabinetExtractFile(IN PCABINET_CONTEXT CabinetContext, IN PCAB_SEARCH Search)
Definition: cabinet.c:952
#define TRUE
Definition: types.h:120
BOOL(WINAPI * pSpFileQueueRename)(IN HSPFILEQ QueueHandle, IN PCWSTR SourcePath, IN PCWSTR SourceFileName OPTIONAL, IN PCWSTR TargetPath OPTIONAL, IN PCWSTR TargetFileName)
Definition: fileqsup.h:117
#define FILEOP_RENAME
Definition: fileqsup.h:43
struct _Entry Entry
Definition: kefuncs.h:640
CABINET_CONTEXT CabinetContext
Definition: fileqsup.c:60
#define MOVEFILE_REPLACE_EXISTING
Definition: filesup.h:28
#define SPFILENOTIFY_STARTQUEUE
Definition: fileqsup.h:22
pSpFileQueueCommit SpFileQueueCommit
Definition: fileqsup.c:158
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
uint16_t * PWSTR
Definition: typedefs.h:54
NTSTATUS SetupDeleteFile(IN PCWSTR FileName, IN BOOLEAN ForceDelete)
Definition: filesup.c:151
BOOL WINAPI SetupQueueRenameW(IN HSPFILEQ QueueHandle, IN PCWSTR SourcePath, IN PCWSTR SourceFileName OPTIONAL, IN PCWSTR TargetPath OPTIONAL, IN PCWSTR TargetFileName)
Definition: fileqsup.c:503
#define SPFILENOTIFY_ENDCOPY
Definition: fileqsup.h:36
#define MOVEFILE_COPY_ALLOWED
Definition: filesup.h:29
LONG NTSTATUS
Definition: precomp.h:26
UINT Win32Error
Definition: fileqsup.h:62
BOOLEAN NTAPI RtlFreeHeap(IN PVOID HeapHandle, IN ULONG Flags, IN PVOID HeapBase)
Definition: heap.c:606
HSPFILEQ WINAPI SetupOpenFileQueue(VOID)
Definition: fileqsup.c:161
NTSTATUS SetupCopyFile(IN PCWSTR SourceFileName, IN PCWSTR DestinationFileName, IN BOOLEAN FailIfExists)
Definition: filesup.c:240
BOOL(WINAPI * pSpFileQueueClose)(IN HSPFILEQ QueueHandle)
Definition: fileqsup.h:85
LIST_ENTRY RenameQueue
Definition: fileqsup.c:53
#define ARRAYSIZE(array)
Definition: filtermapper.c:47
#define SPFILENOTIFY_STARTRENAME
Definition: fileqsup.h:31
NTSTATUS ConcatPaths(IN OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:659
#define InsertTailList(ListHead, Entry)
#define SPFILENOTIFY_ENDRENAME
Definition: fileqsup.h:32
_Must_inspect_result_ FORCEINLINE BOOLEAN IsListEmpty(_In_ const LIST_ENTRY *ListHead)
Definition: rtlfuncs.h:57
VOID CabinetSetCabinetName(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName)
Definition: cabinet.c:580
struct _FILEQUEUEHEADER * PFILEQUEUEHEADER
BOOLEAN HasCurrentCabinet
Definition: fileqsup.c:59
#define FILEOP_ABORT
Definition: fileqsup.h:47
pSpFileQueueClose SpFileQueueClose
Definition: fileqsup.c:154
PWSTR TargetDirectory
Definition: fileqsup.c:44
#define FILEOP_RETRY
Definition: fileqsup.h:50
#define SPFILENOTIFY_STARTSUBQUEUE
Definition: fileqsup.h:24
#define SPFILENOTIFY_ENDSUBQUEUE
Definition: fileqsup.h:25
#define SPFILENOTIFY_RENAMEERROR
Definition: fileqsup.h:33
CAB_SEARCH Search
Definition: fileqsup.c:61
NTSTATUS SetupMoveFile(IN PCWSTR ExistingFileName, IN PCWSTR NewFileName, IN ULONG Flags)
Definition: filesup.c:480
#define MOVEFILE_WRITE_THROUGH
Definition: filesup.h:30
#define FILEOP_COPY
Definition: fileqsup.h:42
unsigned int BOOL
Definition: ntddk_ex.h:94
#define SPFILENOTIFY_ENDDELETE
Definition: fileqsup.h:28
pSpFileQueueCopy SpFileQueueCopy
Definition: fileqsup.c:155
unsigned char BOOLEAN
smooth NULL
Definition: ftsmooth.c:416
_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:426
FORCEINLINE PLIST_ENTRY RemoveHeadList(_Inout_ PLIST_ENTRY ListHead)
Definition: rtlfuncs.h:128
void DPRINT(...)
Definition: polytest.cpp:61
#define SPFILENOTIFY_STARTCOPY
Definition: fileqsup.h:35
LIST_ENTRY ListEntry
Definition: fileqsup.c:39
PFLT_MESSAGE_WAITER_QUEUE CONTAINING_RECORD(Csq, DEVICE_EXTENSION, IrpQueue)) -> WaiterQ.mLock) _IRQL_raises_(DISPATCH_LEVEL) VOID NTAPI FltpAcquireMessageWaiterLock(_In_ PIO_CSQ Csq, _Out_ PKIRQL Irql)
Definition: Messaging.c:560
#define SPFILENOTIFY_STARTDELETE
Definition: fileqsup.h:27
PVOID NTAPI RtlAllocateHeap(IN PVOID HeapHandle, IN ULONG Flags, IN SIZE_T Size)
Definition: heap.c:588
struct _LIST_ENTRY * Flink
Definition: typedefs.h:119
__wchar_t WCHAR
Definition: xmlstorage.h:180
#define NT_SUCCESS(StatCode)
Definition: apphelp.c:32
ULONG CabinetFindNextFileSequential(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName, IN OUT PCAB_SEARCH Search)
Definition: cabinet.c:926
UINT(CALLBACK * PSP_FILE_CALLBACK_W)(IN PVOID Context, IN UINT Notification, IN UINT_PTR Param1, IN UINT_PTR Param2)
Definition: fileqsup.h:66
pSpFileQueueRename SpFileQueueRename
Definition: fileqsup.c:157
#define MAX_PATH
Definition: compat.h:26
#define WINAPI
Definition: msvc.h:8
struct _FILEQUEUEHEADER FILEQUEUEHEADER
BOOL WINAPI SetupQueueDeleteW(IN HSPFILEQ QueueHandle, IN PCWSTR PathPart1, IN PCWSTR PathPart2 OPTIONAL)
Definition: fileqsup.c:433
HSPFILEQ(WINAPI * pSpFileQueueOpen)(VOID)
Definition: fileqsup.h:79
unsigned __int3264 UINT_PTR
Definition: mstsclib_h.h:274
_In_ ULONG _In_ ULONG _In_ ULONG Length
Definition: ntddpcm.h:101
BOOL WINAPI SetupCommitFileQueueW(IN HWND Owner, IN HSPFILEQ QueueHandle, IN PSP_FILE_CALLBACK_W MsgHandler, IN PVOID Context OPTIONAL)
Definition: fileqsup.c:617
#define SPFILENOTIFY_COPYERROR
Definition: fileqsup.h:37
#define CAB_STATUS_SUCCESS
Definition: cabinet.h:23
#define STATUS_UNSUCCESSFUL
Definition: udferr_usr.h:132
static const WCHAR L[]
Definition: oid.c:1250
BOOL(WINAPI * pSpFileQueueDelete)(IN HSPFILEQ QueueHandle, IN PCWSTR PathPart1, IN PCWSTR PathPart2 OPTIONAL)
Definition: fileqsup.h:108
Definition: typedefs.h:117
ULONG CabinetOpen(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:621
struct _QUEUEENTRY QUEUEENTRY
PCWSTR Source
Definition: fileqsup.h:61
HANDLE ProcessHeap
Definition: servman.c:15
BOOL(WINAPI * pSpFileQueueCommit)(IN HWND Owner, IN HSPFILEQ QueueHandle, IN PSP_FILE_CALLBACK_W MsgHandler, IN PVOID Context OPTIONAL)
Definition: fileqsup.h:128
Status
Definition: gdiplustypes.h:24
static VOID SetupDeleteQueueEntry(IN PQUEUEENTRY Entry)
Definition: fileqsup.c:186
LIST_ENTRY CopyQueue
Definition: fileqsup.c:56
PWSTR SourceFileName
Definition: fileqsup.c:43
_Check_return_ _CRTIMP int __cdecl wcscmp(_In_z_ const wchar_t *_Str1, _In_z_ const wchar_t *_Str2)
PWSTR SourceCabinet
Definition: fileqsup.c:40
NTSTRSAFEAPI RtlStringCchCopyW(_Out_writes_(cchDest) _Always_(_Post_z_) NTSTRSAFE_PWSTR pszDest, _In_ size_t cchDest, _In_ NTSTRSAFE_PCWSTR pszSrc)
Definition: ntstrsafe.h:127
LIST_ENTRY DeleteQueue
Definition: fileqsup.c:50
#define FILEOP_SKIP
Definition: fileqsup.h:49
#define InitializeListHead(ListHead)
Definition: env_spec_w32.h:944
ULONG CabinetFindFirst(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR FileName, IN OUT PCAB_SEARCH Search)
Definition: cabinet.c:813
_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:1557
unsigned int UINT
Definition: ndis.h:50
PWSTR TargetFileName
Definition: fileqsup.c:45
ULONG RenameCount
Definition: fileqsup.c:54
PCWSTR Target
Definition: fileqsup.h:60
#define DPRINT1
Definition: precomp.h:8
#define SPFILENOTIFY_DELETEERROR
Definition: fileqsup.h:29
PWSTR SourceRootPath
Definition: fileqsup.c:41
#define SPFILENOTIFY_ENDQUEUE
Definition: fileqsup.h:23
#define OUT
Definition: typedefs.h:39
ULONG Flags
Definition: fileqsup.h:63
VOID CabinetSetDestinationPath(IN PCABINET_CONTEXT CabinetContext, IN PCWSTR DestinationPath)
Definition: cabinet.c:593
unsigned int ULONG
Definition: retypes.h:1
VOID CabinetSetEventHandlers(IN PCABINET_CONTEXT CabinetContext, IN PCABINET_OVERWRITE Overwrite, IN PCABINET_EXTRACT Extract, IN PCABINET_DISK_CHANGE DiskChange)
Definition: cabinet.c:1315
#define RtlZeroMemory(Destination, Length)
Definition: typedefs.h:261
pSpFileQueueDelete SpFileQueueDelete
Definition: fileqsup.c:156
return STATUS_SUCCESS
Definition: btrfs.c:2938
ULONG DeleteCount
Definition: fileqsup.c:51
VOID CabinetCleanup(IN OUT PCABINET_CONTEXT CabinetContext)
Definition: cabinet.c:529
NTSTATUS CombinePaths(OUT PWSTR PathBuffer, IN SIZE_T cchPathSize, IN ULONG NumberOfPathComponents, IN ...)
Definition: filesup.c:681
#define FILEOP_NEWPATH
Definition: fileqsup.h:51
BOOL WINAPI SetupCloseFileQueue(IN HSPFILEQ QueueHandle)
Definition: fileqsup.c:217
size_t __cdecl wcslen(_In_z_ const wchar_t *_Str)
base of all file and directory entries
Definition: entries.h:82
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:262
#define FILEOP_DELETE
Definition: fileqsup.h:44
PULONG MinorVersion OPTIONAL
Definition: CrossNt.h:68
ULONG CopyCount
Definition: fileqsup.c:57