1 /*
2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS Setup Library
4 * FILE: base/setup/lib/install.c
5 * PURPOSE: Installation functions
6 * PROGRAMMERS: Hervé Poussineau (hpoussin@reactos.org)
7 * Hermes Belusca-Maito (hermes.belusca@sfr.fr)
8 */
9
10 /* INCLUDES *****************************************************************/
11
12 #include "precomp.h"
13 #include "filesup.h"
14 #include "infsupp.h"
15
16 #include "setuplib.h" // HAXX for USETUP_DATA!!
17
18 #include "install.h"
19
20 #define NDEBUG
21 #include <debug.h>
22
23
24 /* FUNCTIONS ****************************************************************/
25
26 static BOOL
LookupDirectoryById(IN HINF InfHandle,IN OUT PINFCONTEXT InfContext,IN PCWSTR DirId,OUT PCWSTR * pDirectory)27 LookupDirectoryById(
28 IN HINF InfHandle,
29 IN OUT PINFCONTEXT InfContext,
30 IN PCWSTR DirId,
31 OUT PCWSTR* pDirectory)
32 {
33 BOOL Success;
34
35 // ReactOS-specific
36 Success = SpInfFindFirstLine(InfHandle, L"Directories", DirId, InfContext);
37 if (!Success)
38 {
39 // Windows-compatible
40 Success = SpInfFindFirstLine(InfHandle, L"WinntDirectories", DirId, InfContext);
41 if (!Success)
42 DPRINT1("SpInfFindFirstLine() failed\n");
43 }
44 if (Success)
45 {
46 Success = INF_GetData(InfContext, NULL, pDirectory);
47 if (!Success)
48 DPRINT1("INF_GetData() failed\n");
49 }
50
51 if (!Success)
52 DPRINT1("LookupDirectoryById(%S) - directory not found!\n", DirId);
53
54 return Success;
55 }
56
57 /*
58 * Note: Modeled after SetupGetSourceFileLocation(), SetupGetSourceInfo()
59 * and SetupGetTargetPath() APIs.
60 * Technically the target path is the same for a given file section,
61 * but here we try to remove this constraint.
62 *
63 * TXTSETUP.SIF entries syntax explained at:
64 * http://www.msfn.org/board/topic/125480-txtsetupsif-syntax/
65 */
66 static NTSTATUS
GetSourceFileAndTargetLocation(IN HINF InfHandle,IN PINFCONTEXT InfContext OPTIONAL,IN PCWSTR SourceFileName OPTIONAL,OUT PCWSTR * pSourceRootPath,OUT PCWSTR * pSourcePath,OUT PCWSTR * pTargetDirectory,OUT PCWSTR * pTargetFileName)67 GetSourceFileAndTargetLocation(
68 IN HINF InfHandle,
69 IN PINFCONTEXT InfContext OPTIONAL,
70 IN PCWSTR SourceFileName OPTIONAL,
71 OUT PCWSTR* pSourceRootPath,
72 OUT PCWSTR* pSourcePath,
73 OUT PCWSTR* pTargetDirectory,
74 OUT PCWSTR* pTargetFileName)
75 {
76 BOOL Success;
77 INFCONTEXT FileContext;
78 INFCONTEXT DirContext;
79 PCWSTR SourceRootDirId;
80 PCWSTR SourceRootDir;
81 PCWSTR SourceRelativePath;
82 PCWSTR TargetDirId;
83 PCWSTR TargetDir;
84 PCWSTR TargetFileName;
85
86 /* Either InfContext or SourceFileName must be specified */
87 if (!InfContext && !SourceFileName)
88 return STATUS_INVALID_PARAMETER;
89
90 /* InfContext to a file was not given, retrieve one corresponding to SourceFileName */
91 if (!InfContext)
92 {
93 /* Search for the SourceDisksFiles section */
94
95 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
96 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles." INF_ARCH, SourceFileName, &FileContext);
97 if (!Success)
98 {
99 /* Search in the global section */
100 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksFiles", SourceFileName, &FileContext);
101 }
102 if (!Success)
103 {
104 // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
105 // if (pSetupData->ErrorRoutine)
106 // pSetupData->ErrorRoutine(pSetupData, SectionName);
107 return STATUS_NOT_FOUND;
108 }
109 InfContext = &FileContext;
110 }
111 // else, InfContext != NULL and ignore SourceFileName (that may or may not be == NULL).
112
113 /*
114 * Getting Source File Location -- SetupGetSourceFileLocation()
115 */
116
117 /* Get source root directory id */
118 if (!INF_GetDataField(InfContext, 1, &SourceRootDirId))
119 {
120 /* FIXME: Handle error! */
121 DPRINT1("INF_GetData() failed\n");
122 return STATUS_NOT_FOUND;
123 }
124
125 /* Lookup source root directory -- SetupGetSourceInfo() */
126 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
127 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames." INF_ARCH, SourceRootDirId, &DirContext);
128 if (!Success)
129 {
130 /* Search in the global section */
131 Success = SpInfFindFirstLine(InfHandle, L"SourceDisksNames", SourceRootDirId, &DirContext);
132 if (!Success)
133 DPRINT1("SpInfFindFirstLine(\"SourceDisksNames\", \"%S\") failed\n", SourceRootDirId);
134 }
135 INF_FreeData(SourceRootDirId);
136 if (!Success)
137 {
138 /* FIXME: Handle error! */
139 // pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
140 // if (pSetupData->ErrorRoutine)
141 // pSetupData->ErrorRoutine(pSetupData, SectionName);
142 return STATUS_NOT_FOUND;
143 }
144 if (!INF_GetDataField(&DirContext, 4, &SourceRootDir))
145 {
146 /* FIXME: Handle error! */
147 DPRINT1("INF_GetData() failed\n");
148 return STATUS_NOT_FOUND;
149 }
150
151 /* Get optional source relative directory */
152 if (!INF_GetDataField(InfContext, 2, &SourceRelativePath))
153 {
154 SourceRelativePath = NULL;
155 }
156 else if (!*SourceRelativePath)
157 {
158 INF_FreeData(SourceRelativePath);
159 SourceRelativePath = NULL;
160 }
161 if (!SourceRelativePath)
162 {
163 /* Use WinPE directory instead */
164 if (INF_GetDataField(InfContext, 13, &TargetDirId))
165 {
166 /* Lookup directory */
167 Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &SourceRelativePath);
168 INF_FreeData(TargetDirId);
169 if (!Success)
170 {
171 SourceRelativePath = NULL;
172 }
173 else if (!*SourceRelativePath)
174 {
175 INF_FreeData(SourceRelativePath);
176 SourceRelativePath = NULL;
177 }
178 }
179 }
180
181 /*
182 * Getting Target File Location -- SetupGetTargetPath()
183 */
184
185 /* Get target directory id */
186 if (!INF_GetDataField(InfContext, 8, &TargetDirId))
187 {
188 /* FIXME: Handle error! */
189 DPRINT1("INF_GetData() failed\n");
190 INF_FreeData(SourceRelativePath);
191 INF_FreeData(SourceRootDir);
192 return STATUS_NOT_FOUND;
193 }
194
195 /* Lookup target directory */
196 Success = LookupDirectoryById(InfHandle, &DirContext, TargetDirId, &TargetDir);
197 INF_FreeData(TargetDirId);
198 if (!Success)
199 {
200 /* FIXME: Handle error! */
201 INF_FreeData(SourceRelativePath);
202 INF_FreeData(SourceRootDir);
203 return STATUS_NOT_FOUND;
204 }
205
206 /* Get optional target file name */
207 if (!INF_GetDataField(InfContext, 11, &TargetFileName))
208 TargetFileName = NULL;
209 else if (!*TargetFileName)
210 TargetFileName = NULL;
211
212 DPRINT("GetSourceFileAndTargetLocation(%S) = "
213 "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
214 SourceFileName, SourceRootDir, SourceRelativePath, TargetDir, TargetFileName);
215
216 #if 0
217 INF_FreeData(TargetDir);
218 INF_FreeData(TargetFileName);
219 INF_FreeData(SourceRelativePath);
220 INF_FreeData(SourceRootDir);
221 #endif
222
223 *pSourceRootPath = SourceRootDir;
224 *pSourcePath = SourceRelativePath;
225 *pTargetDirectory = TargetDir;
226 *pTargetFileName = TargetFileName;
227
228 return STATUS_SUCCESS;
229 }
230
231 static NTSTATUS
BuildFullDirectoryPath(IN PCWSTR RootPath,IN PCWSTR BasePath,IN PCWSTR RelativePath,OUT PWSTR FullPath,IN SIZE_T cchFullPathSize)232 BuildFullDirectoryPath(
233 IN PCWSTR RootPath,
234 IN PCWSTR BasePath,
235 IN PCWSTR RelativePath,
236 OUT PWSTR FullPath,
237 IN SIZE_T cchFullPathSize)
238 {
239 NTSTATUS Status;
240
241 if ((RelativePath[0] == UNICODE_NULL) || (RelativePath[0] == L'\\' && RelativePath[1] == UNICODE_NULL))
242 {
243 /* Installation path */
244 DPRINT("InstallationPath: '%S'\n", RelativePath);
245
246 Status = CombinePaths(FullPath, cchFullPathSize, 2,
247 RootPath, BasePath);
248
249 DPRINT("InstallationPath(2): '%S'\n", FullPath);
250 }
251 else if (RelativePath[0] == L'\\')
252 {
253 /* Absolute path */
254 DPRINT("AbsolutePath: '%S'\n", RelativePath);
255
256 Status = CombinePaths(FullPath, cchFullPathSize, 2,
257 RootPath, RelativePath);
258
259 DPRINT("AbsolutePath(2): '%S'\n", FullPath);
260 }
261 else // if (RelativePath[0] != L'\\')
262 {
263 /* Path relative to the installation path */
264 DPRINT("RelativePath: '%S'\n", RelativePath);
265
266 Status = CombinePaths(FullPath, cchFullPathSize, 3,
267 RootPath, BasePath, RelativePath);
268
269 DPRINT("RelativePath(2): '%S'\n", FullPath);
270 }
271
272 return Status;
273 }
274
275
276 /*
277 * This code enumerates the list of files in reactos.dff / reactos.inf
278 * that need to be extracted from reactos.cab and be installed in their
279 * respective directories.
280 */
281 /*
282 * IMPORTANT NOTE: The INF file specification used for the .CAB in ReactOS
283 * is not compliant with respect to TXTSETUP.SIF syntax or the standard syntax.
284 */
285 static BOOLEAN
AddSectionToCopyQueueCab(IN PUSETUP_DATA pSetupData,IN HINF InfFile,IN PCWSTR SectionName,IN PCWSTR SourceCabinet,IN PCUNICODE_STRING DestinationPath)286 AddSectionToCopyQueueCab(
287 IN PUSETUP_DATA pSetupData,
288 IN HINF InfFile,
289 IN PCWSTR SectionName,
290 IN PCWSTR SourceCabinet,
291 IN PCUNICODE_STRING DestinationPath)
292 {
293 BOOLEAN Success;
294 NTSTATUS Status;
295 INFCONTEXT FilesContext;
296 INFCONTEXT DirContext;
297 PCWSTR SourceFileName;
298 PCWSTR TargetDirId;
299 PCWSTR TargetDir;
300 PCWSTR TargetFileName;
301 WCHAR FileDstPath[MAX_PATH];
302
303 /* Search for the SectionName section */
304 if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
305 {
306 DPRINT1("AddSectionToCopyQueueCab(): Unable to find section '%S' in cabinet file\n", SectionName);
307 return FALSE;
308 }
309
310 /*
311 * Enumerate the files in the section and add them to the file queue.
312 */
313 do
314 {
315 /* Get source file name and target directory id */
316 if (!INF_GetData(&FilesContext, &SourceFileName, &TargetDirId))
317 {
318 /* FIXME: Handle error! */
319 DPRINT1("INF_GetData() failed\n");
320 break;
321 }
322
323 /* Get optional target file name */
324 if (!INF_GetDataField(&FilesContext, 2, &TargetFileName))
325 {
326 TargetFileName = NULL;
327 }
328 else if (!*TargetFileName)
329 {
330 INF_FreeData(TargetFileName);
331 TargetFileName = NULL;
332 }
333
334 /* Lookup target directory */
335 Success = LookupDirectoryById(InfFile, &DirContext, TargetDirId, &TargetDir);
336 INF_FreeData(TargetDirId);
337 if (!Success)
338 {
339 /* FIXME: Handle error! */
340 INF_FreeData(TargetFileName);
341 INF_FreeData(SourceFileName);
342 break;
343 }
344
345 DPRINT("GetSourceTargetFromCab(%S) = "
346 "SrcRootDir: '%S', SrcRelPath: '%S' --> TargetDir: '%S', TargetFileName: '%S'\n",
347 SourceFileName,
348 pSetupData->SourcePath.Buffer,
349 pSetupData->SourceRootDir.Buffer,
350 TargetDir, TargetFileName);
351
352 Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
353 pSetupData->DestinationPath.Buffer,
354 TargetDir);
355 UNREFERENCED_PARAMETER(Status);
356 DPRINT(" --> FileDstPath = '%S'\n", FileDstPath);
357
358 INF_FreeData(TargetDir);
359
360 if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
361 pSetupData->SourcePath.Buffer, // SourcePath == SourceRootPath ++ SourceRootDir
362 NULL,
363 SourceFileName,
364 NULL,
365 SourceCabinet,
366 NULL,
367 FileDstPath,
368 TargetFileName,
369 0 /* FIXME */))
370 {
371 /* FIXME: Handle error! */
372 DPRINT1("SpFileQueueCopy() failed\n");
373 }
374
375 INF_FreeData(TargetFileName);
376 INF_FreeData(SourceFileName);
377
378 } while (SpInfFindNextLine(&FilesContext, &FilesContext));
379
380 return TRUE;
381 }
382
383 // Note: Modeled after the SetupQueueCopySection() API
384 /*
385 BOOL SetupQueueCopySection(
386 _In_ HSPFILEQ QueueHandle,
387 _In_ PCTSTR SourceRootPath,
388 _In_ HINF InfHandle,
389 _In_ HINF ListInfHandle,
390 _In_ PCTSTR Section,
391 _In_ DWORD CopyStyle
392 );
393 */
394 static BOOLEAN
AddSectionToCopyQueue(IN PUSETUP_DATA pSetupData,IN HINF InfFile,IN PCWSTR SectionName,IN PCUNICODE_STRING DestinationPath)395 AddSectionToCopyQueue(
396 IN PUSETUP_DATA pSetupData,
397 IN HINF InfFile,
398 IN PCWSTR SectionName,
399 IN PCUNICODE_STRING DestinationPath)
400 {
401 NTSTATUS Status;
402 INFCONTEXT FilesContext;
403 PCWSTR SourceFileName;
404 PCWSTR SourceRootPath;
405 PCWSTR SourcePath;
406 PCWSTR TargetDirectory;
407 PCWSTR TargetFileName;
408 WCHAR FileSrcRootPath[MAX_PATH];
409 WCHAR FileDstPath[MAX_PATH];
410
411 /*
412 * This code enumerates the list of files in txtsetup.sif
413 * that need to be installed in their respective directories.
414 */
415
416 /* Search for the SectionName section */
417 if (!SpInfFindFirstLine(InfFile, SectionName, NULL, &FilesContext))
418 {
419 DPRINT1("AddSectionToCopyQueue(): Unable to find section '%S' in TXTSETUP.SIF\n", SectionName);
420 return FALSE;
421 }
422
423 /*
424 * Enumerate the files in the section and add them to the file queue.
425 */
426 do
427 {
428 /* Get source file name */
429 if (!INF_GetDataField(&FilesContext, 0, &SourceFileName))
430 {
431 /* FIXME: Handle error! */
432 DPRINT1("INF_GetData() failed\n");
433 break;
434 }
435
436 Status = GetSourceFileAndTargetLocation(InfFile,
437 &FilesContext,
438 SourceFileName,
439 &SourceRootPath, // SourceRootDir
440 &SourcePath,
441 &TargetDirectory,
442 &TargetFileName);
443 if (!NT_SUCCESS(Status))
444 {
445 DPRINT1("Could not find source and target location for file '%S'\n", SourceFileName);
446 INF_FreeData(SourceFileName);
447
448 // FIXME: Another error?
449 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
450 if (pSetupData->ErrorRoutine)
451 pSetupData->ErrorRoutine(pSetupData, SectionName);
452 return FALSE;
453 // break;
454 }
455 /*
456 * SourcePath: '\Device\CdRom0\I386'
457 * SourceRootPath: '\Device\CdRom0'
458 * SourceRootDir: '\I386'
459 */
460
461 Status = CombinePaths(FileSrcRootPath, ARRAYSIZE(FileSrcRootPath), 2,
462 pSetupData->SourceRootPath.Buffer,
463 SourceRootPath);
464 UNREFERENCED_PARAMETER(Status);
465 // DPRINT1("Could not build the full path for '%S', skipping...\n", SourceRootPath);
466 DPRINT(" --> FileSrcRootPath = '%S'\n", FileSrcRootPath);
467
468 INF_FreeData(SourceRootPath);
469
470 Status = CombinePaths(FileDstPath, ARRAYSIZE(FileDstPath), 2,
471 pSetupData->DestinationPath.Buffer,
472 TargetDirectory);
473 UNREFERENCED_PARAMETER(Status);
474 // DPRINT1("Could not build the full path for '%S', skipping...\n", TargetDirectory);
475 DPRINT(" --> FileDstPath = '%S'\n", FileDstPath);
476
477 INF_FreeData(TargetDirectory);
478
479 if (!SpFileQueueCopy((HSPFILEQ)pSetupData->SetupFileQueue,
480 FileSrcRootPath,
481 SourcePath,
482 SourceFileName,
483 NULL,
484 NULL, // No SourceCabinet
485 NULL,
486 FileDstPath,
487 TargetFileName,
488 0 /* FIXME */))
489 {
490 /* FIXME: Handle error! */
491 DPRINT1("SpFileQueueCopy() failed\n");
492 }
493
494 INF_FreeData(TargetFileName);
495 INF_FreeData(SourcePath);
496 INF_FreeData(SourceFileName);
497
498 } while (SpInfFindNextLine(&FilesContext, &FilesContext));
499
500 return TRUE;
501 }
502
503 BOOLEAN // ERROR_NUMBER
PrepareCopyInfFile(IN OUT PUSETUP_DATA pSetupData,IN HINF InfFile,IN PCWSTR SourceCabinet OPTIONAL)504 PrepareCopyInfFile(
505 IN OUT PUSETUP_DATA pSetupData,
506 IN HINF InfFile,
507 IN PCWSTR SourceCabinet OPTIONAL)
508 {
509 BOOLEAN Success;
510 NTSTATUS Status;
511 INFCONTEXT DirContext;
512 PWCHAR AdditionalSectionName = NULL;
513 PCWSTR DirKeyValue;
514 WCHAR PathBuffer[MAX_PATH];
515
516 if (SourceCabinet == NULL)
517 {
518 /* Add common files -- Search for the SourceDisksFiles section */
519 /* Search in the optional platform-specific first (currently hardcoded; make it runtime-dependent?) */
520 Success = AddSectionToCopyQueue(pSetupData, InfFile,
521 L"SourceDisksFiles." INF_ARCH,
522 &pSetupData->DestinationPath);
523 if (!Success)
524 {
525 DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles." INF_ARCH);
526 }
527 /* Search in the global section */
528 Success = AddSectionToCopyQueue(pSetupData, InfFile,
529 L"SourceDisksFiles",
530 &pSetupData->DestinationPath);
531 if (!Success)
532 {
533 DPRINT1("AddSectionToCopyQueue(%S) failed!\n", L"SourceDisksFiles");
534 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
535 if (pSetupData->ErrorRoutine)
536 pSetupData->ErrorRoutine(pSetupData, L"SourceDisksFiles");
537 return FALSE;
538 }
539
540 /* Add specific files depending of computer type */
541 {
542 PGENERIC_LIST_ENTRY Entry;
543 Entry = GetCurrentListEntry(pSetupData->ComputerList);
544 ASSERT(Entry);
545 pSetupData->ComputerType = ((PGENENTRY)GetListEntryData(Entry))->Id;
546 ASSERT(pSetupData->ComputerType);
547
548 if (!ProcessComputerFiles(InfFile, pSetupData->ComputerType, &AdditionalSectionName))
549 return FALSE;
550 }
551
552 if (AdditionalSectionName &&
553 !AddSectionToCopyQueue(pSetupData, InfFile,
554 AdditionalSectionName,
555 &pSetupData->DestinationPath))
556 {
557 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
558 if (pSetupData->ErrorRoutine)
559 pSetupData->ErrorRoutine(pSetupData, AdditionalSectionName);
560 return FALSE;
561 }
562 }
563 else
564 {
565 /* Process a cabinet INF */
566 Success = AddSectionToCopyQueueCab(pSetupData, InfFile,
567 L"SourceFiles",
568 SourceCabinet,
569 &pSetupData->DestinationPath);
570 if (!Success)
571 {
572 DPRINT1("AddSectionToCopyQueueCab(%S) failed!\n", SourceCabinet);
573 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
574 if (pSetupData->ErrorRoutine)
575 pSetupData->ErrorRoutine(pSetupData, L"SourceFiles");
576 return FALSE;
577 }
578 }
579
580 /* Create directories */
581
582 /*
583 * NOTE: This is technically optional since SpFileQueueCommit()
584 * does that. This is however needed if one wants to create
585 * empty directories.
586 */
587
588 /*
589 * FIXME:
590 * Copying files to pSetupData->DestinationRootPath should be done from within
591 * the SystemPartitionFiles section.
592 * At the moment we check whether we specify paths like '\foo' or '\\' for that.
593 * For installing to pSetupData->DestinationPath specify just '\' .
594 */
595
596 /* Get destination path */
597 RtlStringCchCopyW(PathBuffer, ARRAYSIZE(PathBuffer),
598 pSetupData->DestinationPath.Buffer);
599
600 DPRINT("FullPath(1): '%S'\n", PathBuffer);
601
602 /* Create the install directory */
603 Status = SetupCreateDirectory(PathBuffer);
604 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
605 {
606 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
607 pSetupData->LastErrorNumber = ERROR_CREATE_INSTALL_DIR;
608 if (pSetupData->ErrorRoutine)
609 pSetupData->ErrorRoutine(pSetupData, PathBuffer);
610 return FALSE;
611 }
612
613 /* Search for the 'Directories' section */
614 // ReactOS-specific
615 if (!SpInfFindFirstLine(InfFile, L"Directories", NULL, &DirContext))
616 {
617 // Windows-compatible
618 if (!SpInfFindFirstLine(InfFile, L"WinntDirectories", NULL, &DirContext))
619 {
620 if (SourceCabinet)
621 pSetupData->LastErrorNumber = ERROR_CABINET_SECTION;
622 else
623 pSetupData->LastErrorNumber = ERROR_TXTSETUP_SECTION;
624
625 if (pSetupData->ErrorRoutine)
626 pSetupData->ErrorRoutine(pSetupData, L"Directories");
627 return FALSE;
628 }
629 }
630
631 /* Enumerate the directory values and create the subdirectories */
632 do
633 {
634 if (!INF_GetData(&DirContext, NULL, &DirKeyValue))
635 {
636 DPRINT1("break\n");
637 break;
638 }
639
640 Status = BuildFullDirectoryPath(pSetupData->DestinationRootPath.Buffer,
641 pSetupData->InstallPath.Buffer,
642 DirKeyValue,
643 PathBuffer,
644 ARRAYSIZE(PathBuffer));
645 if (!NT_SUCCESS(Status))
646 {
647 DPRINT1("Could not build the full path for '%S', skipping...\n", DirKeyValue);
648 INF_FreeData(DirKeyValue);
649 continue;
650 }
651
652 if ((DirKeyValue[0] == UNICODE_NULL) || (DirKeyValue[0] == L'\\' && DirKeyValue[1] == UNICODE_NULL))
653 {
654 /*
655 * Installation path -- No need to create it
656 * because it has been already created above.
657 */
658 }
659 else
660 {
661 /* Arbitrary path -- Create it */
662 Status = SetupCreateDirectory(PathBuffer);
663 if (!NT_SUCCESS(Status) && Status != STATUS_OBJECT_NAME_COLLISION)
664 {
665 INF_FreeData(DirKeyValue);
666 DPRINT1("Creating directory '%S' failed: Status = 0x%08lx\n", PathBuffer, Status);
667 pSetupData->LastErrorNumber = ERROR_CREATE_DIR;
668 if (pSetupData->ErrorRoutine)
669 pSetupData->ErrorRoutine(pSetupData, PathBuffer);
670 return FALSE;
671 }
672 }
673
674 INF_FreeData(DirKeyValue);
675 } while (SpInfFindNextLine(&DirContext, &DirContext));
676
677 return TRUE;
678 }
679
680
681 // #define USE_CABINET_INF
682
683 BOOLEAN // ERROR_NUMBER
PrepareFileCopy(IN OUT PUSETUP_DATA pSetupData,IN PFILE_COPY_STATUS_ROUTINE StatusRoutine OPTIONAL)684 PrepareFileCopy(
685 IN OUT PUSETUP_DATA pSetupData,
686 IN PFILE_COPY_STATUS_ROUTINE StatusRoutine OPTIONAL)
687 {
688 HINF InfHandle;
689 INFCONTEXT CabinetsContext;
690 PCWSTR CabinetName;
691 UINT ErrorLine;
692 #if defined(__REACTOS__) && defined(USE_CABINET_INF)
693 ULONG InfFileSize;
694 PVOID InfFileData;
695 CABINET_CONTEXT CabinetContext;
696 #endif
697 WCHAR PathBuffer[MAX_PATH];
698
699 /* Create the file queue */
700 pSetupData->SetupFileQueue = (PVOID)SpFileQueueOpen();
701 if (pSetupData->SetupFileQueue == NULL)
702 {
703 pSetupData->LastErrorNumber = ERROR_COPY_QUEUE;
704 if (pSetupData->ErrorRoutine)
705 pSetupData->ErrorRoutine(pSetupData);
706 return FALSE;
707 }
708
709 /* Prepare the copy of the common files that are not in installation cabinets */
710 if (!PrepareCopyInfFile(pSetupData, pSetupData->SetupInf, NULL))
711 {
712 /* FIXME: show an error dialog */
713 return FALSE;
714 }
715
716 /* Search for the 'Cabinets' section */
717 if (!SpInfFindFirstLine(pSetupData->SetupInf, L"Cabinets", NULL, &CabinetsContext))
718 {
719 /* Skip this step and return success if no cabinet file is listed */
720 return TRUE;
721 }
722
723 /*
724 * Enumerate the installation cabinets listed in the
725 * 'Cabinets' section and parse their inf files.
726 */
727 do
728 {
729 if (!INF_GetData(&CabinetsContext, NULL, &CabinetName))
730 break;
731
732 CombinePaths(PathBuffer, ARRAYSIZE(PathBuffer), 2,
733 pSetupData->SourcePath.Buffer, CabinetName);
734
735 #if defined(__REACTOS__) && defined(USE_CABINET_INF)
736 INF_FreeData(CabinetName);
737
738 CabinetInitialize(&CabinetContext);
739 CabinetSetEventHandlers(&CabinetContext, NULL, NULL, NULL);
740 CabinetSetCabinetName(&CabinetContext, PathBuffer);
741
742 if (CabinetOpen(&CabinetContext) == CAB_STATUS_SUCCESS)
743 {
744 DPRINT("Cabinet %S\n", PathBuffer);
745
746 InfFileData = CabinetGetCabinetReservedArea(&CabinetContext, &InfFileSize);
747 if (InfFileData == NULL)
748 {
749 CabinetCleanup(&CabinetContext);
750
751 pSetupData->LastErrorNumber = ERROR_CABINET_SCRIPT;
752 if (pSetupData->ErrorRoutine)
753 pSetupData->ErrorRoutine(pSetupData, PathBuffer);
754 return FALSE;
755 }
756 }
757 else
758 {
759 DPRINT("Cannot open cabinet: %S.\n", PathBuffer);
760 CabinetCleanup(&CabinetContext);
761
762 pSetupData->LastErrorNumber = ERROR_CABINET_MISSING;
763 if (pSetupData->ErrorRoutine)
764 pSetupData->ErrorRoutine(pSetupData, PathBuffer);
765 return FALSE;
766 }
767
768 InfHandle = INF_OpenBufferedFileA((PSTR)InfFileData,
769 InfFileSize,
770 NULL,
771 INF_STYLE_WIN4,
772 pSetupData->LanguageId,
773 &ErrorLine);
774
775 CabinetCleanup(&CabinetContext);
776 #else
777 {
778 PWCHAR ptr;
779
780 /* First find the filename */
781 ptr = wcsrchr(PathBuffer, L'\\');
782 if (!ptr) ptr = PathBuffer;
783
784 /* Then find its extension */
785 ptr = wcsrchr(ptr, L'.');
786 if (!ptr)
787 ptr = PathBuffer + wcslen(PathBuffer);
788
789 /* Replace it by '.inf' */
790 wcscpy(ptr, L".inf");
791
792 InfHandle = SpInfOpenInfFile(PathBuffer,
793 NULL,
794 INF_STYLE_WIN4,
795 pSetupData->LanguageId,
796 &ErrorLine);
797 }
798 #endif
799
800 if (InfHandle == INVALID_HANDLE_VALUE)
801 {
802 pSetupData->LastErrorNumber = ERROR_INVALID_CABINET_INF;
803 if (pSetupData->ErrorRoutine)
804 pSetupData->ErrorRoutine(pSetupData, PathBuffer);
805 return FALSE;
806 }
807
808 if (!PrepareCopyInfFile(pSetupData, InfHandle, CabinetName))
809 {
810 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF))
811 SpInfCloseInfFile(InfHandle);
812 #endif
813 /* FIXME: show an error dialog */
814 return FALSE;
815 }
816
817 #if !(defined(__REACTOS__) && defined(USE_CABINET_INF))
818 SpInfCloseInfFile(InfHandle);
819 #endif
820 } while (SpInfFindNextLine(&CabinetsContext, &CabinetsContext));
821
822 return TRUE;
823 }
824
825 BOOLEAN
DoFileCopy(IN OUT PUSETUP_DATA pSetupData,IN PSP_FILE_CALLBACK_W MsgHandler,IN PVOID Context OPTIONAL)826 DoFileCopy(
827 IN OUT PUSETUP_DATA pSetupData,
828 IN PSP_FILE_CALLBACK_W MsgHandler,
829 IN PVOID Context OPTIONAL)
830 {
831 BOOLEAN Success;
832
833 Success = SpFileQueueCommit(NULL,
834 (HSPFILEQ)pSetupData->SetupFileQueue,
835 MsgHandler,
836 Context);
837
838 SpFileQueueClose((HSPFILEQ)pSetupData->SetupFileQueue);
839 pSetupData->SetupFileQueue = NULL;
840
841 return Success;
842 }
843
844 /* EOF */
845