2 * COPYRIGHT: See COPYING in the top level directory
3 * PROJECT: ReactOS text-mode setup
4 * FILE: base/setup/usetup/filesup.c
5 * PURPOSE: File support functions
6 * PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
9 /* INCLUDES *****************************************************************/
16 /* FUNCTIONS ****************************************************************/
18 static BOOLEAN HasCurrentCabinet
= FALSE
;
19 static WCHAR CurrentCabinetName
[MAX_PATH
];
20 static CAB_SEARCH Search
;
24 SetupCreateSingleDirectory(
27 OBJECT_ATTRIBUTES ObjectAttributes
;
28 IO_STATUS_BLOCK IoStatusBlock
;
29 UNICODE_STRING PathName
;
30 HANDLE DirectoryHandle
;
33 if (!RtlCreateUnicodeString(&PathName
, DirectoryName
))
34 return STATUS_NO_MEMORY
;
36 if (PathName
.Length
> sizeof(WCHAR
) &&
37 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 2] == L
'\\' &&
38 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 1] == L
'.')
40 PathName
.Length
-= sizeof(WCHAR
);
41 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
)] = 0;
44 if (PathName
.Length
> sizeof(WCHAR
) &&
45 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
47 PathName
.Length
-= sizeof(WCHAR
);
48 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
)] = 0;
51 InitializeObjectAttributes(&ObjectAttributes
,
53 OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
,
57 Status
= NtCreateFile(&DirectoryHandle
,
58 FILE_LIST_DIRECTORY
| SYNCHRONIZE
,
62 FILE_ATTRIBUTE_DIRECTORY
,
63 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
65 FILE_OPEN_FOR_BACKUP_INTENT
| FILE_DIRECTORY_FILE
,
68 if (NT_SUCCESS(Status
))
70 NtClose(DirectoryHandle
);
73 RtlFreeUnicodeString(&PathName
);
82 PWCHAR PathBuffer
= NULL
;
86 NTSTATUS Status
= STATUS_SUCCESS
;
88 Size
= (wcslen(PathName
) + 1) * sizeof(WCHAR
);
89 PathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, Size
);
90 if (PathBuffer
== NULL
)
91 return STATUS_INSUFFICIENT_RESOURCES
;
93 wcscpy(PathBuffer
, PathName
);
94 EndPtr
= PathBuffer
+ wcslen(PathName
);
98 /* Skip the '\Device\HarddiskX\PartitionY\ part */
100 while (Ptr
< EndPtr
&& BackslashCount
< 4)
114 DPRINT("PathBuffer: %S\n", PathBuffer
);
115 if (!DoesPathExist(NULL
, PathBuffer
))
117 DPRINT("Create: %S\n", PathBuffer
);
118 Status
= SetupCreateSingleDirectory(PathBuffer
);
119 if (!NT_SUCCESS(Status
))
129 if (!DoesPathExist(NULL
, PathBuffer
))
131 DPRINT("Create: %S\n", PathBuffer
);
132 Status
= SetupCreateSingleDirectory(PathBuffer
);
133 if (!NT_SUCCESS(Status
))
139 if (PathBuffer
!= NULL
)
140 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
147 PWCHAR SourceFileName
,
148 PWCHAR DestinationFileName
)
150 OBJECT_ATTRIBUTES ObjectAttributes
;
151 HANDLE FileHandleSource
;
152 HANDLE FileHandleDest
;
153 static IO_STATUS_BLOCK IoStatusBlock
;
154 FILE_STANDARD_INFORMATION FileStandard
;
155 FILE_BASIC_INFORMATION FileBasic
;
157 UNICODE_STRING FileName
;
159 PVOID SourceFileMap
= 0;
160 HANDLE SourceFileSection
;
161 SIZE_T SourceSectionSize
= 0;
162 LARGE_INTEGER ByteOffset
;
164 RtlInitUnicodeString(&FileName
,
167 InitializeObjectAttributes(&ObjectAttributes
,
169 OBJ_CASE_INSENSITIVE
,
173 Status
= NtOpenFile(&FileHandleSource
,
178 FILE_SEQUENTIAL_ONLY
);
179 if (!NT_SUCCESS(Status
))
181 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status
, &FileName
);
185 Status
= NtQueryInformationFile(FileHandleSource
,
188 sizeof(FILE_STANDARD_INFORMATION
),
189 FileStandardInformation
);
190 if (!NT_SUCCESS(Status
))
192 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
196 Status
= NtQueryInformationFile(FileHandleSource
,
197 &IoStatusBlock
,&FileBasic
,
198 sizeof(FILE_BASIC_INFORMATION
),
199 FileBasicInformation
);
200 if (!NT_SUCCESS(Status
))
202 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
206 Status
= NtCreateSection(&SourceFileSection
,
213 if (!NT_SUCCESS(Status
))
215 DPRINT1("NtCreateSection failed: %x, %S\n", Status
, SourceFileName
);
219 Status
= NtMapViewOfSection(SourceFileSection
,
229 if (!NT_SUCCESS(Status
))
231 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status
, SourceFileName
);
235 RtlInitUnicodeString(&FileName
,
236 DestinationFileName
);
238 InitializeObjectAttributes(&ObjectAttributes
,
240 OBJ_CASE_INSENSITIVE
,
244 Status
= NtCreateFile(&FileHandleDest
,
245 GENERIC_WRITE
| SYNCHRONIZE
,
249 FILE_ATTRIBUTE_NORMAL
,
252 FILE_NO_INTERMEDIATE_BUFFERING
|
253 FILE_SEQUENTIAL_ONLY
|
254 FILE_SYNCHRONOUS_IO_NONALERT
,
257 if (!NT_SUCCESS(Status
))
259 /* Open may have failed because the file to overwrite
260 * is in readonly mode
262 if (Status
== STATUS_ACCESS_DENIED
)
264 FILE_BASIC_INFORMATION FileBasicInfo
;
266 /* Reattempt to open it with limited access */
267 Status
= NtCreateFile(&FileHandleDest
,
268 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
272 FILE_ATTRIBUTE_NORMAL
,
275 FILE_NO_INTERMEDIATE_BUFFERING
|
276 FILE_SEQUENTIAL_ONLY
|
277 FILE_SYNCHRONOUS_IO_NONALERT
,
280 /* Fail for real if we cannot open it that way */
281 if (!NT_SUCCESS(Status
))
283 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
287 /* Zero our basic info, just to set attributes */
288 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
289 /* Reset attributes to normal, no read-only */
290 FileBasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
291 /* We basically don't care about whether it succeed:
292 * if it didn't, later open will fail
294 NtSetInformationFile(FileHandleDest
, &IoStatusBlock
, &FileBasicInfo
,
295 sizeof(FileBasicInfo
), FileBasicInformation
);
298 NtClose(FileHandleDest
);
300 /* And re-attempt overwrite */
301 Status
= NtCreateFile(&FileHandleDest
,
302 GENERIC_WRITE
| SYNCHRONIZE
,
306 FILE_ATTRIBUTE_NORMAL
,
309 FILE_NO_INTERMEDIATE_BUFFERING
|
310 FILE_SEQUENTIAL_ONLY
|
311 FILE_SYNCHRONOUS_IO_NONALERT
,
317 if (!NT_SUCCESS(Status
))
319 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
324 RegionSize
= (ULONG
)PAGE_ROUND_UP(FileStandard
.EndOfFile
.u
.LowPart
);
325 IoStatusBlock
.Status
= 0;
326 ByteOffset
.QuadPart
= 0ULL;
327 Status
= NtWriteFile(FileHandleDest
,
336 if (!NT_SUCCESS(Status
))
338 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status
, IoStatusBlock
.Status
, &IoStatusBlock
, SourceFileMap
, RegionSize
);
342 /* Copy file date/time from source file */
343 Status
= NtSetInformationFile(FileHandleDest
,
346 sizeof(FILE_BASIC_INFORMATION
),
347 FileBasicInformation
);
348 if (!NT_SUCCESS(Status
))
350 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
354 /* shorten the file back to it's real size after completing the write */
355 Status
= NtSetInformationFile(FileHandleDest
,
357 &FileStandard
.EndOfFile
,
358 sizeof(FILE_END_OF_FILE_INFORMATION
),
359 FileEndOfFileInformation
);
360 if (!NT_SUCCESS(Status
))
362 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
366 NtClose(FileHandleDest
);
369 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap
);
372 NtClose(SourceFileSection
);
375 NtClose(FileHandleSource
);
384 PWCHAR CabinetFileName
,
385 PWCHAR SourceFileName
,
386 PWCHAR DestinationPathName
)
390 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
391 CabinetFileName
, SourceFileName
, DestinationPathName
);
393 if (HasCurrentCabinet
)
395 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName
);
398 if ((HasCurrentCabinet
) && (wcscmp(CabinetFileName
, CurrentCabinetName
) == 0))
400 DPRINT("Using same cabinet as last time\n");
402 /* Use our last location because the files should be sequential */
403 CabStatus
= CabinetFindNextFileSequential(SourceFileName
, &Search
);
404 if (CabStatus
!= CAB_STATUS_SUCCESS
)
406 DPRINT("Sequential miss on file: %S\n", SourceFileName
);
408 /* Looks like we got unlucky */
409 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
414 DPRINT("Using new cabinet\n");
416 if (HasCurrentCabinet
)
421 wcscpy(CurrentCabinetName
, CabinetFileName
);
424 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
425 CabinetSetCabinetName(CabinetFileName
);
427 CabStatus
= CabinetOpen();
428 if (CabStatus
== CAB_STATUS_SUCCESS
)
430 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
431 HasCurrentCabinet
= TRUE
;
435 DPRINT("Cannot open cabinet (%d)\n", CabStatus
);
436 return STATUS_UNSUCCESSFUL
;
439 /* We have to start at the beginning here */
440 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
443 if (CabStatus
!= CAB_STATUS_SUCCESS
)
445 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName
, CabinetGetCabinetName());
446 return STATUS_UNSUCCESSFUL
;
449 CabinetSetDestinationPath(DestinationPathName
);
450 CabStatus
= CabinetExtractFile(&Search
);
451 if (CabStatus
!= CAB_STATUS_SUCCESS
)
453 DPRINT("Cannot extract file %S (%d)\n", SourceFileName
, CabStatus
);
454 return STATUS_UNSUCCESSFUL
;
457 return STATUS_SUCCESS
;
463 IN PCWSTR InstallDir
)
467 Length
= wcslen(InstallDir
);
469 // TODO: Add check for 8.3 too.
471 /* Path must be at least 2 characters long */
475 /* Path must start with a backslash */
476 // if (InstallDir[0] != L'\\')
479 /* Path must not end with a backslash */
480 if (InstallDir
[Length
- 1] == L
'\\')
483 /* Path must not contain whitespace characters */
484 for (i
= 0; i
< Length
; i
++)
486 if (iswspace(InstallDir
[i
]))
490 /* Path component must not end with a dot */
491 for (i
= 0; i
< Length
; i
++)
493 if (InstallDir
[i
] == L
'\\' && i
> 0)
495 if (InstallDir
[i
- 1] == L
'.')
500 if (InstallDir
[Length
- 1] == L
'.')