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