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