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