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