3 * Copyright (C) 2002 ReactOS Team
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.
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.
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.
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)
26 /* INCLUDES *****************************************************************/
33 /* INCLUDES *****************************************************************/
35 typedef struct _QUEUEENTRY
37 struct _QUEUEENTRY
*Prev
;
38 struct _QUEUEENTRY
*Next
;
40 PWSTR SourceCabinet
; /* May be NULL if the file is not in a cabinet */
44 PWSTR TargetDirectory
;
46 } QUEUEENTRY
, *PQUEUEENTRY
;
49 typedef struct _FILEQUEUEHEADER
54 } FILEQUEUEHEADER
, *PFILEQUEUEHEADER
;
57 /* FUNCTIONS ****************************************************************/
59 static BOOLEAN HasCurrentCabinet
= FALSE
;
60 static WCHAR CurrentCabinetName
[MAX_PATH
];
61 static CAB_SEARCH Search
;
63 // HACK: Temporary compatibility code.
65 static CABINET_CONTEXT CabinetContext
;
66 #define CabinetInitialize() (CabinetInitialize(&CabinetContext))
67 #define CabinetSetEventHandlers(a,b,c) (CabinetSetEventHandlers(&CabinetContext,(a),(b),(c)))
68 #define CabinetSetCabinetName(a) (CabinetSetCabinetName(&CabinetContext,(a)))
69 #define CabinetOpen() (CabinetOpen(&CabinetContext))
70 #define CabinetGetCabinetName() (CabinetGetCabinetName(&CabinetContext))
71 #define CabinetGetCabinetReservedArea(a) (CabinetGetCabinetReservedArea(&CabinetContext,(a)))
72 #define CabinetFindNextFileSequential(a,b) (CabinetFindNextFileSequential(&CabinetContext,(a),(b)))
73 #define CabinetFindFirst(a,b) (CabinetFindFirst(&CabinetContext,(a),(b)))
74 #define CabinetSetDestinationPath(a) (CabinetSetDestinationPath(&CabinetContext,(a)))
75 #define CabinetExtractFile(a) (CabinetExtractFile(&CabinetContext,(a)))
76 #define CabinetCleanup() (CabinetCleanup(&CabinetContext))
81 PWCHAR CabinetFileName
,
82 PWCHAR SourceFileName
,
83 PWCHAR DestinationPathName
)
87 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
88 CabinetFileName
, SourceFileName
, DestinationPathName
);
90 if (HasCurrentCabinet
)
92 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName
);
95 if ((HasCurrentCabinet
) && (wcscmp(CabinetFileName
, CurrentCabinetName
) == 0))
97 DPRINT("Using same cabinet as last time\n");
99 /* Use our last location because the files should be sequential */
100 CabStatus
= CabinetFindNextFileSequential(SourceFileName
, &Search
);
101 if (CabStatus
!= CAB_STATUS_SUCCESS
)
103 DPRINT("Sequential miss on file: %S\n", SourceFileName
);
105 /* Looks like we got unlucky */
106 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
111 DPRINT("Using new cabinet\n");
113 if (HasCurrentCabinet
)
118 wcscpy(CurrentCabinetName
, CabinetFileName
);
121 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
122 CabinetSetCabinetName(CabinetFileName
);
124 CabStatus
= CabinetOpen();
125 if (CabStatus
== CAB_STATUS_SUCCESS
)
127 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
128 HasCurrentCabinet
= TRUE
;
132 DPRINT("Cannot open cabinet (%d)\n", CabStatus
);
133 return STATUS_UNSUCCESSFUL
;
136 /* We have to start at the beginning here */
137 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
140 if (CabStatus
!= CAB_STATUS_SUCCESS
)
142 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName
, CabinetGetCabinetName());
143 return STATUS_UNSUCCESSFUL
;
146 CabinetSetDestinationPath(DestinationPathName
);
147 CabStatus
= CabinetExtractFile(&Search
);
148 if (CabStatus
!= CAB_STATUS_SUCCESS
)
150 DPRINT("Cannot extract file %S (%d)\n", SourceFileName
, CabStatus
);
151 return STATUS_UNSUCCESSFUL
;
154 return STATUS_SUCCESS
;
159 SetupOpenFileQueue(VOID
)
161 PFILEQUEUEHEADER QueueHeader
;
163 /* Allocate queue header */
164 QueueHeader
= (PFILEQUEUEHEADER
)RtlAllocateHeap(ProcessHeap
,
166 sizeof(FILEQUEUEHEADER
));
167 if (QueueHeader
== NULL
)
170 /* Initialize queue header */
171 RtlZeroMemory(QueueHeader
,
172 sizeof(FILEQUEUEHEADER
));
174 return (HSPFILEQ
)QueueHeader
;
181 HSPFILEQ QueueHandle
)
183 PFILEQUEUEHEADER QueueHeader
;
186 if (QueueHandle
== NULL
)
189 QueueHeader
= (PFILEQUEUEHEADER
)QueueHandle
;
191 /* Delete copy queue */
192 Entry
= QueueHeader
->CopyHead
;
193 while (Entry
!= NULL
)
195 /* Delete all strings */
196 if (Entry
->SourceCabinet
!= NULL
)
197 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
199 if (Entry
->SourceRootPath
!= NULL
)
200 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceRootPath
);
202 if (Entry
->SourcePath
!= NULL
)
203 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourcePath
);
205 if (Entry
->SourceFilename
!= NULL
)
206 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceFilename
);
208 if (Entry
->TargetDirectory
!= NULL
)
209 RtlFreeHeap(ProcessHeap
, 0, Entry
->TargetDirectory
);
211 if (Entry
->TargetFilename
!= NULL
)
212 RtlFreeHeap(ProcessHeap
, 0, Entry
->TargetFilename
);
214 /* Unlink current queue entry */
215 if (Entry
->Next
!= NULL
)
217 QueueHeader
->CopyHead
= Entry
->Next
;
218 QueueHeader
->CopyHead
->Prev
= NULL
;
222 QueueHeader
->CopyHead
= NULL
;
223 QueueHeader
->CopyTail
= NULL
;
226 /* Delete queue entry */
227 RtlFreeHeap(ProcessHeap
, 0, Entry
);
229 /* Get next queue entry */
230 Entry
= QueueHeader
->CopyHead
;
233 /* Delete queue header */
234 RtlFreeHeap(ProcessHeap
, 0, QueueHeader
);
240 HSPFILEQ QueueHandle
,
241 PCWSTR SourceCabinet
,
242 PCWSTR SourceRootPath
,
244 PCWSTR SourceFilename
,
245 PCWSTR TargetDirectory
,
246 PCWSTR TargetFilename
)
248 PFILEQUEUEHEADER QueueHeader
;
252 /* SourceCabinet may be NULL */
253 if (QueueHandle
== NULL
||
254 SourceRootPath
== NULL
||
255 SourceFilename
== NULL
||
256 TargetDirectory
== NULL
)
261 QueueHeader
= (PFILEQUEUEHEADER
)QueueHandle
;
263 /* Allocate new queue entry */
264 Entry
= (PQUEUEENTRY
)RtlAllocateHeap(ProcessHeap
,
273 /* Copy source cabinet if available */
274 if (SourceCabinet
!= NULL
)
276 Length
= wcslen(SourceCabinet
);
277 Entry
->SourceCabinet
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
279 (Length
+ 1) * sizeof(WCHAR
));
280 if (Entry
->SourceCabinet
== NULL
)
282 RtlFreeHeap(ProcessHeap
, 0, Entry
);
286 wcsncpy(Entry
->SourceCabinet
, SourceCabinet
, Length
);
287 Entry
->SourceCabinet
[Length
] = UNICODE_NULL
;
291 Entry
->SourceCabinet
= NULL
;
294 /* Copy source root path */
295 Length
= wcslen(SourceRootPath
);
296 Entry
->SourceRootPath
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
298 (Length
+ 1) * sizeof(WCHAR
));
299 if (Entry
->SourceRootPath
== NULL
)
301 if (Entry
->SourceCabinet
!= NULL
)
303 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
306 RtlFreeHeap(ProcessHeap
, 0, Entry
);
310 wcsncpy(Entry
->SourceRootPath
, SourceRootPath
, Length
);
311 Entry
->SourceRootPath
[Length
] = UNICODE_NULL
;
313 /* Copy source path */
314 if (SourcePath
!= NULL
)
316 Length
= wcslen(SourcePath
);
317 if ((Length
> 0) && (SourcePath
[Length
- 1] == L
'\\'))
319 Entry
->SourcePath
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
321 (Length
+ 1) * sizeof(WCHAR
));
322 if (Entry
->SourcePath
== NULL
)
324 if (Entry
->SourceCabinet
!= NULL
)
326 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
329 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceRootPath
);
330 RtlFreeHeap(ProcessHeap
, 0, Entry
);
334 wcsncpy(Entry
->SourcePath
, SourcePath
, Length
);
335 Entry
->SourcePath
[Length
] = UNICODE_NULL
;
338 /* Copy source file name */
339 Length
= wcslen(SourceFilename
);
340 Entry
->SourceFilename
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
342 (Length
+ 1) * sizeof(WCHAR
));
343 if (Entry
->SourceFilename
== NULL
)
345 if (Entry
->SourceCabinet
!= NULL
)
347 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
350 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceRootPath
);
351 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourcePath
);
352 RtlFreeHeap(ProcessHeap
, 0, Entry
);
356 wcsncpy(Entry
->SourceFilename
, SourceFilename
, Length
);
357 Entry
->SourceFilename
[Length
] = UNICODE_NULL
;
359 /* Copy target directory */
360 Length
= wcslen(TargetDirectory
);
361 if ((Length
> 0) && (TargetDirectory
[Length
- 1] == L
'\\'))
363 Entry
->TargetDirectory
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
365 (Length
+ 1) * sizeof(WCHAR
));
366 if (Entry
->TargetDirectory
== NULL
)
368 if (Entry
->SourceCabinet
!= NULL
)
370 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
373 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceRootPath
);
374 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourcePath
);
375 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceFilename
);
376 RtlFreeHeap(ProcessHeap
, 0, Entry
);
380 wcsncpy(Entry
->TargetDirectory
, TargetDirectory
, Length
);
381 Entry
->TargetDirectory
[Length
] = UNICODE_NULL
;
383 /* Copy optional target filename */
384 if (TargetFilename
!= NULL
)
386 Length
= wcslen(TargetFilename
);
387 Entry
->TargetFilename
= (WCHAR
*)RtlAllocateHeap(ProcessHeap
,
389 (Length
+ 1) * sizeof(WCHAR
));
390 if (Entry
->TargetFilename
== NULL
)
392 if (Entry
->SourceCabinet
!= NULL
)
394 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceCabinet
);
397 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceRootPath
);
398 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourcePath
);
399 RtlFreeHeap(ProcessHeap
, 0, Entry
->SourceFilename
);
400 RtlFreeHeap(ProcessHeap
, 0, Entry
->TargetDirectory
);
401 RtlFreeHeap(ProcessHeap
, 0, Entry
);
405 wcsncpy(Entry
->TargetFilename
, TargetFilename
, Length
);
406 Entry
->TargetFilename
[Length
] = UNICODE_NULL
;
409 /* Append queue entry */
410 if (QueueHeader
->CopyHead
== NULL
) // && QueueHeader->CopyTail == NULL)
414 QueueHeader
->CopyHead
= Entry
;
415 QueueHeader
->CopyTail
= Entry
;
419 Entry
->Prev
= QueueHeader
->CopyTail
;
421 QueueHeader
->CopyTail
->Next
= Entry
;
422 QueueHeader
->CopyTail
= Entry
;
425 QueueHeader
->CopyCount
++;
433 SetupCommitFileQueueW(
435 HSPFILEQ QueueHandle
,
436 PSP_FILE_CALLBACK_W MsgHandler
,
439 WCHAR CabinetName
[MAX_PATH
];
440 PFILEQUEUEHEADER QueueHeader
;
443 PCWSTR TargetRootPath
, TargetPath
;
445 WCHAR FileSrcPath
[MAX_PATH
];
446 WCHAR FileDstPath
[MAX_PATH
];
448 TargetRootPath
= ((PCOPYCONTEXT
)Context
)->DestinationRootPath
;
449 TargetPath
= ((PCOPYCONTEXT
)Context
)->InstallPath
;
451 if (QueueHandle
== NULL
)
454 QueueHeader
= (PFILEQUEUEHEADER
)QueueHandle
;
457 SPFILENOTIFY_STARTQUEUE
,
462 SPFILENOTIFY_STARTSUBQUEUE
,
464 QueueHeader
->CopyCount
);
466 /* Commit copy queue */
467 Entry
= QueueHeader
->CopyHead
;
468 while (Entry
!= NULL
)
470 /* Build the full source path */
471 CombinePaths(FileSrcPath
, ARRAYSIZE(FileSrcPath
), 3,
472 Entry
->SourceRootPath
, Entry
->SourcePath
,
473 Entry
->SourceFilename
);
475 /* Build the full target path */
476 wcscpy(FileDstPath
, TargetRootPath
);
477 if (Entry
->TargetDirectory
[0] == UNICODE_NULL
)
479 /* Installation path */
481 /* Add the installation path */
482 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, TargetPath
);
484 else if (Entry
->TargetDirectory
[0] == L
'\\')
487 if (Entry
->TargetDirectory
[1] != UNICODE_NULL
)
488 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, Entry
->TargetDirectory
);
490 else // if (Entry->TargetDirectory[0] != L'\\')
492 /* Path relative to the installation path */
494 /* Add the installation path */
495 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 2,
496 TargetPath
, Entry
->TargetDirectory
);
500 * If the file is in a cabinet, use only the destination path.
501 * Otherwise possibly use a different target name.
503 if (Entry
->SourceCabinet
== NULL
)
505 if (Entry
->TargetFilename
!= NULL
)
506 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, Entry
->TargetFilename
);
508 ConcatPaths(FileDstPath
, ARRAYSIZE(FileDstPath
), 1, Entry
->SourceFilename
);
512 DPRINT("Copy: '%S' ==> '%S'\n", FileSrcPath
, FileDstPath
);
515 SPFILENOTIFY_STARTCOPY
,
516 (UINT_PTR
)Entry
->SourceFilename
,
519 if (Entry
->SourceCabinet
!= NULL
)
521 /* Extract the file */
522 CombinePaths(CabinetName
, ARRAYSIZE(CabinetName
), 3,
523 Entry
->SourceRootPath
, Entry
->SourcePath
,
524 Entry
->SourceCabinet
);
525 Status
= SetupExtractFile(CabinetName
, Entry
->SourceFilename
, FileDstPath
);
530 Status
= SetupCopyFile(FileSrcPath
, FileDstPath
, FALSE
);
533 if (!NT_SUCCESS(Status
))
536 SPFILENOTIFY_COPYERROR
,
537 (UINT_PTR
)Entry
->SourceFilename
,
543 SPFILENOTIFY_ENDCOPY
,
544 (UINT_PTR
)Entry
->SourceFilename
,
552 SPFILENOTIFY_ENDSUBQUEUE
,
557 SPFILENOTIFY_ENDQUEUE
,