Sync with trunk r63270.
[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: subsys/system/usetup/filequeue.c
22 * PURPOSE: File queue functions
23 * PROGRAMMER: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
25 */
26
27 /* INCLUDES *****************************************************************/
28
29 #include "usetup.h"
30
31 #define NDEBUG
32 #include <debug.h>
33
34 /* INCLUDES *****************************************************************/
35
36 typedef struct _QUEUEENTRY
37 {
38 struct _QUEUEENTRY *Prev;
39 struct _QUEUEENTRY *Next;
40
41 PWSTR SourceCabinet; /* May be NULL if file is not in a cabinet */
42 PWSTR SourceRootPath;
43 PWSTR SourcePath;
44 PWSTR SourceFilename;
45 PWSTR TargetDirectory;
46 PWSTR TargetFilename;
47 } QUEUEENTRY, *PQUEUEENTRY;
48
49
50 typedef struct _FILEQUEUEHEADER
51 {
52 PQUEUEENTRY CopyHead;
53 PQUEUEENTRY CopyTail;
54 ULONG CopyCount;
55 } FILEQUEUEHEADER, *PFILEQUEUEHEADER;
56
57
58 /* FUNCTIONS ****************************************************************/
59
60 HSPFILEQ
61 WINAPI
62 SetupOpenFileQueue(VOID)
63 {
64 PFILEQUEUEHEADER QueueHeader;
65
66 /* Allocate queue header */
67 QueueHeader = (PFILEQUEUEHEADER)RtlAllocateHeap(ProcessHeap,
68 0,
69 sizeof(FILEQUEUEHEADER));
70 if (QueueHeader == NULL)
71 return NULL;
72
73 /* Initialize queue header */
74 RtlZeroMemory(QueueHeader,
75 sizeof(FILEQUEUEHEADER));
76
77 return (HSPFILEQ)QueueHeader;
78 }
79
80
81 VOID
82 WINAPI
83 SetupCloseFileQueue(
84 HSPFILEQ QueueHandle)
85 {
86 PFILEQUEUEHEADER QueueHeader;
87 PQUEUEENTRY Entry;
88
89 if (QueueHandle == NULL)
90 return;
91
92 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
93
94 /* Delete copy queue */
95 Entry = QueueHeader->CopyHead;
96 while (Entry != NULL)
97 {
98 /* Delete all strings */
99 if (Entry->SourceCabinet != NULL)
100 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
101
102 if (Entry->SourceRootPath != NULL)
103 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
104
105 if (Entry->SourcePath != NULL)
106 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
107
108 if (Entry->SourceFilename != NULL)
109 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
110
111 if (Entry->TargetDirectory != NULL)
112 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
113
114 if (Entry->TargetFilename != NULL)
115 RtlFreeHeap(ProcessHeap, 0, Entry->TargetFilename);
116
117 /* Unlink current queue entry */
118 if (Entry->Next != NULL)
119 {
120 QueueHeader->CopyHead = Entry->Next;
121 QueueHeader->CopyHead->Prev = NULL;
122 }
123 else
124 {
125 QueueHeader->CopyHead = NULL;
126 QueueHeader->CopyTail = NULL;
127 }
128
129 /* Delete queue entry */
130 RtlFreeHeap(ProcessHeap, 0, Entry);
131
132 /* Get next queue entry */
133 Entry = QueueHeader->CopyHead;
134 }
135
136 /* Delete queue header */
137 RtlFreeHeap(ProcessHeap, 0, QueueHeader);
138 }
139
140
141 BOOL
142 SetupQueueCopy(
143 HSPFILEQ QueueHandle,
144 PCWSTR SourceCabinet,
145 PCWSTR SourceRootPath,
146 PCWSTR SourcePath,
147 PCWSTR SourceFilename,
148 PCWSTR TargetDirectory,
149 PCWSTR TargetFilename)
150 {
151 PFILEQUEUEHEADER QueueHeader;
152 PQUEUEENTRY Entry;
153 ULONG Length;
154
155 /* SourceCabinet may be NULL */
156 if (QueueHandle == NULL ||
157 SourceRootPath == NULL ||
158 SourceFilename == NULL ||
159 TargetDirectory == NULL)
160 return FALSE;
161
162 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
163
164 /* Allocate new queue entry */
165 Entry = (PQUEUEENTRY)RtlAllocateHeap(ProcessHeap,
166 0,
167 sizeof(QUEUEENTRY));
168 if (Entry == NULL)
169 return FALSE;
170
171 RtlZeroMemory(Entry,
172 sizeof(QUEUEENTRY));
173
174 /* Copy source cabinet if available */
175 if (SourceCabinet != NULL)
176 {
177 Length = wcslen(SourceCabinet);
178 Entry->SourceCabinet = (WCHAR*)RtlAllocateHeap(ProcessHeap,
179 0,
180 (Length + 1) * sizeof(WCHAR));
181 if (Entry->SourceCabinet == NULL)
182 {
183 RtlFreeHeap(ProcessHeap, 0, Entry);
184 return FALSE;
185 }
186
187 wcsncpy(Entry->SourceCabinet, SourceCabinet, Length);
188 Entry->SourceCabinet[Length] = (WCHAR)0;
189 }
190 else
191 {
192 Entry->SourceCabinet = NULL;
193 }
194
195 /* Copy source root path */
196 Length = wcslen(SourceRootPath);
197 Entry->SourceRootPath = (WCHAR*)RtlAllocateHeap(ProcessHeap,
198 0,
199 (Length + 1) * sizeof(WCHAR));
200 if (Entry->SourceRootPath == NULL)
201 {
202 if (Entry->SourceCabinet != NULL)
203 {
204 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
205 }
206
207 RtlFreeHeap(ProcessHeap, 0, Entry);
208 return FALSE;
209 }
210
211 wcsncpy(Entry->SourceRootPath, SourceRootPath, Length);
212 Entry->SourceRootPath[Length] = (WCHAR)0;
213
214 /* Copy source path */
215 if (SourcePath != NULL)
216 {
217 Length = wcslen(SourcePath);
218 Entry->SourcePath = (WCHAR*)RtlAllocateHeap(ProcessHeap,
219 0,
220 (Length + 1) * sizeof(WCHAR));
221 if (Entry->SourcePath == NULL)
222 {
223 if (Entry->SourceCabinet != NULL)
224 {
225 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
226 }
227
228 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
229 RtlFreeHeap(ProcessHeap, 0, Entry);
230 return FALSE;
231 }
232
233 wcsncpy(Entry->SourcePath, SourcePath, Length);
234 Entry->SourcePath[Length] = (WCHAR)0;
235 }
236
237 /* Copy source file name */
238 Length = wcslen(SourceFilename);
239 Entry->SourceFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
240 0,
241 (Length + 1) * sizeof(WCHAR));
242 if (Entry->SourceFilename == NULL)
243 {
244 if (Entry->SourceCabinet != NULL)
245 {
246 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
247 }
248
249 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
250 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
251 RtlFreeHeap(ProcessHeap, 0, Entry);
252 return FALSE;
253 }
254
255 wcsncpy(Entry->SourceFilename, SourceFilename, Length);
256 Entry->SourceFilename[Length] = (WCHAR)0;
257
258 /* Copy target directory */
259 Length = wcslen(TargetDirectory);
260 if (TargetDirectory[Length] == '\\')
261 Length--;
262 Entry->TargetDirectory = (WCHAR*)RtlAllocateHeap(ProcessHeap,
263 0,
264 (Length + 1) * sizeof(WCHAR));
265 if (Entry->TargetDirectory == NULL)
266 {
267 if (Entry->SourceCabinet != NULL)
268 {
269 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
270 }
271
272 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
273 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
274 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
275 RtlFreeHeap(ProcessHeap, 0, Entry);
276 return FALSE;
277 }
278
279 wcsncpy(Entry->TargetDirectory, TargetDirectory, Length);
280 Entry->TargetDirectory[Length] = (WCHAR)0;
281
282 /* Copy optional target filename */
283 if (TargetFilename != NULL)
284 {
285 Length = wcslen(TargetFilename);
286 Entry->TargetFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
287 0,
288 (Length + 1) * sizeof(WCHAR));
289 if (Entry->TargetFilename == NULL)
290 {
291 if (Entry->SourceCabinet != NULL)
292 {
293 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
294 }
295
296 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
297 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
298 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
299 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
300 RtlFreeHeap(ProcessHeap, 0, Entry);
301 return FALSE;
302 }
303
304 wcsncpy(Entry->TargetFilename, TargetFilename, Length);
305 Entry->TargetFilename[Length] = (WCHAR)0;
306 }
307
308 /* Append queue entry */
309 if (QueueHeader->CopyHead == NULL) // && QueueHeader->CopyTail == NULL)
310 {
311 Entry->Prev = NULL;
312 Entry->Next = NULL;
313 QueueHeader->CopyHead = Entry;
314 QueueHeader->CopyTail = Entry;
315 }
316 else
317 {
318 Entry->Prev = QueueHeader->CopyTail;
319 Entry->Next = NULL;
320 QueueHeader->CopyTail->Next = Entry;
321 QueueHeader->CopyTail = Entry;
322 }
323
324 QueueHeader->CopyCount++;
325
326 return TRUE;
327 }
328
329
330 BOOL
331 WINAPI
332 SetupCommitFileQueueW(
333 HWND Owner,
334 HSPFILEQ QueueHandle,
335 PSP_FILE_CALLBACK_W MsgHandler,
336 PVOID Context)
337 {
338 WCHAR CabinetName[MAX_PATH];
339 PFILEQUEUEHEADER QueueHeader;
340 PQUEUEENTRY Entry;
341 NTSTATUS Status;
342 PCWSTR TargetRootPath, TargetPath;
343
344 WCHAR FileSrcPath[MAX_PATH];
345 WCHAR FileDstPath[MAX_PATH];
346
347 TargetRootPath = ((PCOPYCONTEXT)Context)->DestinationRootPath;
348 TargetPath = ((PCOPYCONTEXT)Context)->InstallPath;
349
350 if (QueueHandle == NULL)
351 return FALSE;
352
353 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
354
355 MsgHandler(Context,
356 SPFILENOTIFY_STARTQUEUE,
357 0,
358 0);
359
360 MsgHandler(Context,
361 SPFILENOTIFY_STARTSUBQUEUE,
362 FILEOP_COPY,
363 QueueHeader->CopyCount);
364
365 /* Commit copy queue */
366 Entry = QueueHeader->CopyHead;
367 while (Entry != NULL)
368 {
369 wcscpy(FileSrcPath, Entry->SourceRootPath);
370 if (Entry->SourcePath != NULL)
371 wcscat(FileSrcPath, Entry->SourcePath);
372 wcscat(FileSrcPath, L"\\");
373 wcscat(FileSrcPath, Entry->SourceFilename);
374
375 /* Build the full target path */
376 wcscpy(FileDstPath, TargetRootPath);
377 if (Entry->TargetDirectory[0] == L'\\')
378 {
379 wcscat(FileDstPath, Entry->TargetDirectory);
380 }
381 else
382 {
383 if (TargetPath != NULL)
384 {
385 if (TargetPath[0] != L'\\')
386 wcscat(FileDstPath, L"\\");
387 wcscat(FileDstPath, TargetPath);
388 }
389
390 wcscat(FileDstPath, L"\\");
391 wcscat(FileDstPath, Entry->TargetDirectory);
392 }
393
394 /* Use only the destination path if the file is in a cabinet */
395 if (Entry->SourceCabinet == NULL)
396 {
397 wcscat(FileDstPath, L"\\");
398 if (Entry->TargetFilename != NULL)
399 wcscat(FileDstPath, Entry->TargetFilename);
400 else
401 wcscat(FileDstPath, Entry->SourceFilename);
402 }
403
404 /* FIXME: Do it! */
405 DPRINT("'%S' ==> '%S'\n", FileSrcPath, FileDstPath);
406
407 MsgHandler(Context,
408 SPFILENOTIFY_STARTCOPY,
409 (UINT_PTR)Entry->SourceFilename,
410 FILEOP_COPY);
411
412 if (Entry->SourceCabinet != NULL)
413 {
414 /* Extract the file */
415 wcscpy(CabinetName, Entry->SourceRootPath);
416 if (Entry->SourcePath != NULL)
417 wcscat(CabinetName, Entry->SourcePath);
418 wcscat(CabinetName, L"\\");
419 wcscat(CabinetName, Entry->SourceCabinet);
420 Status = SetupExtractFile(CabinetName, Entry->SourceFilename, FileDstPath);
421 }
422 else
423 {
424 /* Copy the file */
425 Status = SetupCopyFile(FileSrcPath, FileDstPath);
426 }
427
428 if (!NT_SUCCESS(Status))
429 {
430 MsgHandler(Context,
431 SPFILENOTIFY_COPYERROR,
432 (UINT_PTR)Entry->SourceFilename,
433 FILEOP_COPY);
434 }
435 else
436 {
437 MsgHandler(Context,
438 SPFILENOTIFY_ENDCOPY,
439 (UINT_PTR)Entry->SourceFilename,
440 FILEOP_COPY);
441 }
442
443 Entry = Entry->Next;
444 }
445
446 MsgHandler(Context,
447 SPFILENOTIFY_ENDSUBQUEUE,
448 FILEOP_COPY,
449 0);
450
451 MsgHandler(Context,
452 SPFILENOTIFY_ENDQUEUE,
453 0,
454 0);
455
456 return TRUE;
457 }
458
459 /* EOF */