[USETUP]
[reactos.git] / reactos / 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: 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 the 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 if ((Length > 0) && (SourcePath[Length - 1] == L'\\'))
219 Length--;
220 Entry->SourcePath = (WCHAR*)RtlAllocateHeap(ProcessHeap,
221 0,
222 (Length + 1) * sizeof(WCHAR));
223 if (Entry->SourcePath == NULL)
224 {
225 if (Entry->SourceCabinet != NULL)
226 {
227 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
228 }
229
230 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
231 RtlFreeHeap(ProcessHeap, 0, Entry);
232 return FALSE;
233 }
234
235 wcsncpy(Entry->SourcePath, SourcePath, Length);
236 Entry->SourcePath[Length] = (WCHAR)0;
237 }
238
239 /* Copy source file name */
240 Length = wcslen(SourceFilename);
241 Entry->SourceFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
242 0,
243 (Length + 1) * sizeof(WCHAR));
244 if (Entry->SourceFilename == NULL)
245 {
246 if (Entry->SourceCabinet != NULL)
247 {
248 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
249 }
250
251 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
252 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
253 RtlFreeHeap(ProcessHeap, 0, Entry);
254 return FALSE;
255 }
256
257 wcsncpy(Entry->SourceFilename, SourceFilename, Length);
258 Entry->SourceFilename[Length] = (WCHAR)0;
259
260 /* Copy target directory */
261 Length = wcslen(TargetDirectory);
262 if ((Length > 0) && (TargetDirectory[Length - 1] == L'\\'))
263 Length--;
264 Entry->TargetDirectory = (WCHAR*)RtlAllocateHeap(ProcessHeap,
265 0,
266 (Length + 1) * sizeof(WCHAR));
267 if (Entry->TargetDirectory == NULL)
268 {
269 if (Entry->SourceCabinet != NULL)
270 {
271 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
272 }
273
274 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
275 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
276 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
277 RtlFreeHeap(ProcessHeap, 0, Entry);
278 return FALSE;
279 }
280
281 wcsncpy(Entry->TargetDirectory, TargetDirectory, Length);
282 Entry->TargetDirectory[Length] = (WCHAR)0;
283
284 /* Copy optional target filename */
285 if (TargetFilename != NULL)
286 {
287 Length = wcslen(TargetFilename);
288 Entry->TargetFilename = (WCHAR*)RtlAllocateHeap(ProcessHeap,
289 0,
290 (Length + 1) * sizeof(WCHAR));
291 if (Entry->TargetFilename == NULL)
292 {
293 if (Entry->SourceCabinet != NULL)
294 {
295 RtlFreeHeap(ProcessHeap, 0, Entry->SourceCabinet);
296 }
297
298 RtlFreeHeap(ProcessHeap, 0, Entry->SourceRootPath);
299 RtlFreeHeap(ProcessHeap, 0, Entry->SourcePath);
300 RtlFreeHeap(ProcessHeap, 0, Entry->SourceFilename);
301 RtlFreeHeap(ProcessHeap, 0, Entry->TargetDirectory);
302 RtlFreeHeap(ProcessHeap, 0, Entry);
303 return FALSE;
304 }
305
306 wcsncpy(Entry->TargetFilename, TargetFilename, Length);
307 Entry->TargetFilename[Length] = (WCHAR)0;
308 }
309
310 /* Append queue entry */
311 if (QueueHeader->CopyHead == NULL) // && QueueHeader->CopyTail == NULL)
312 {
313 Entry->Prev = NULL;
314 Entry->Next = NULL;
315 QueueHeader->CopyHead = Entry;
316 QueueHeader->CopyTail = Entry;
317 }
318 else
319 {
320 Entry->Prev = QueueHeader->CopyTail;
321 Entry->Next = NULL;
322 QueueHeader->CopyTail->Next = Entry;
323 QueueHeader->CopyTail = Entry;
324 }
325
326 QueueHeader->CopyCount++;
327
328 return TRUE;
329 }
330
331
332 BOOL
333 WINAPI
334 SetupCommitFileQueueW(
335 HWND Owner,
336 HSPFILEQ QueueHandle,
337 PSP_FILE_CALLBACK_W MsgHandler,
338 PVOID Context)
339 {
340 WCHAR CabinetName[MAX_PATH];
341 PFILEQUEUEHEADER QueueHeader;
342 PQUEUEENTRY Entry;
343 NTSTATUS Status;
344 PCWSTR TargetRootPath, TargetPath;
345
346 WCHAR FileSrcPath[MAX_PATH];
347 WCHAR FileDstPath[MAX_PATH];
348
349 TargetRootPath = ((PCOPYCONTEXT)Context)->DestinationRootPath;
350 TargetPath = ((PCOPYCONTEXT)Context)->InstallPath;
351
352 if (QueueHandle == NULL)
353 return FALSE;
354
355 QueueHeader = (PFILEQUEUEHEADER)QueueHandle;
356
357 MsgHandler(Context,
358 SPFILENOTIFY_STARTQUEUE,
359 0,
360 0);
361
362 MsgHandler(Context,
363 SPFILENOTIFY_STARTSUBQUEUE,
364 FILEOP_COPY,
365 QueueHeader->CopyCount);
366
367 /* Commit copy queue */
368 Entry = QueueHeader->CopyHead;
369 while (Entry != NULL)
370 {
371 /* Build the full source path */
372 wcscpy(FileSrcPath, Entry->SourceRootPath);
373 if (Entry->SourcePath != NULL)
374 wcscat(FileSrcPath, Entry->SourcePath);
375 wcscat(FileSrcPath, L"\\");
376 wcscat(FileSrcPath, Entry->SourceFilename);
377
378 /* Build the full target path */
379 wcscpy(FileDstPath, TargetRootPath);
380 if (Entry->TargetDirectory[0] == 0)
381 {
382 /* Installation path */
383
384 /* Add the installation path */
385 if (TargetPath != NULL)
386 {
387 if (TargetPath[0] != L'\\')
388 wcscat(FileDstPath, L"\\");
389 wcscat(FileDstPath, TargetPath);
390 }
391 }
392 else if (Entry->TargetDirectory[0] == L'\\')
393 {
394 /* Absolute path */
395 if (Entry->TargetDirectory[1] != 0)
396 wcscat(FileDstPath, Entry->TargetDirectory);
397 }
398 else // if (Entry->TargetDirectory[0] != L'\\')
399 {
400 /* Path relative to the installation path */
401
402 /* Add the installation path */
403 if (TargetPath != NULL)
404 {
405 if (TargetPath[0] != L'\\')
406 wcscat(FileDstPath, L"\\");
407 wcscat(FileDstPath, TargetPath);
408 }
409
410 wcscat(FileDstPath, L"\\");
411 wcscat(FileDstPath, Entry->TargetDirectory);
412 }
413
414 /*
415 * If the file is in a cabinet, use only the destination path.
416 * Otherwise possibly use a different target name.
417 */
418 if (Entry->SourceCabinet == NULL)
419 {
420 wcscat(FileDstPath, L"\\");
421 if (Entry->TargetFilename != NULL)
422 wcscat(FileDstPath, Entry->TargetFilename);
423 else
424 wcscat(FileDstPath, Entry->SourceFilename);
425 }
426
427 /* FIXME: Do it! */
428 DPRINT("Copy: '%S' ==> '%S'\n", FileSrcPath, FileDstPath);
429
430 MsgHandler(Context,
431 SPFILENOTIFY_STARTCOPY,
432 (UINT_PTR)Entry->SourceFilename,
433 FILEOP_COPY);
434
435 if (Entry->SourceCabinet != NULL)
436 {
437 /* Extract the file */
438 wcscpy(CabinetName, Entry->SourceRootPath);
439 if (Entry->SourcePath != NULL)
440 wcscat(CabinetName, Entry->SourcePath);
441 wcscat(CabinetName, L"\\");
442 wcscat(CabinetName, Entry->SourceCabinet);
443 Status = SetupExtractFile(CabinetName, Entry->SourceFilename, FileDstPath);
444 }
445 else
446 {
447 /* Copy the file */
448 Status = SetupCopyFile(FileSrcPath, FileDstPath);
449 }
450
451 if (!NT_SUCCESS(Status))
452 {
453 MsgHandler(Context,
454 SPFILENOTIFY_COPYERROR,
455 (UINT_PTR)Entry->SourceFilename,
456 FILEOP_COPY);
457 }
458 else
459 {
460 MsgHandler(Context,
461 SPFILENOTIFY_ENDCOPY,
462 (UINT_PTR)Entry->SourceFilename,
463 FILEOP_COPY);
464 }
465
466 Entry = Entry->Next;
467 }
468
469 MsgHandler(Context,
470 SPFILENOTIFY_ENDSUBQUEUE,
471 FILEOP_COPY,
472 0);
473
474 MsgHandler(Context,
475 SPFILENOTIFY_ENDQUEUE,
476 0,
477 0);
478
479 return TRUE;
480 }
481
482 /* EOF */