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