3 * Copyright (C) 2002 ReactOS Team
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.
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.
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.
19 /* COPYRIGHT: See COPYING in the top level directory
20 * PROJECT: ReactOS text-mode setup
21 * FILE: base/setup/usetup/filesup.c
22 * PURPOSE: File support functions
23 * PROGRAMMER: Eric Kohl
24 * Casper S. Hornstrup (chorns@users.sourceforge.net)
27 /* INCLUDES *****************************************************************/
34 /* FUNCTIONS ****************************************************************/
36 static BOOLEAN HasCurrentCabinet
= FALSE
;
37 static WCHAR CurrentCabinetName
[MAX_PATH
];
38 static CAB_SEARCH Search
;
42 SetupCreateSingleDirectory(
45 OBJECT_ATTRIBUTES ObjectAttributes
;
46 IO_STATUS_BLOCK IoStatusBlock
;
47 UNICODE_STRING PathName
;
48 HANDLE DirectoryHandle
;
51 if(!RtlCreateUnicodeString(&PathName
, DirectoryName
))
52 return STATUS_NO_MEMORY
;
54 if (PathName
.Length
> sizeof(WCHAR
) &&
55 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 2] == L
'\\' &&
56 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 1] == L
'.')
58 PathName
.Length
-= sizeof(WCHAR
);
59 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
)] = 0;
62 if (PathName
.Length
> sizeof(WCHAR
) &&
63 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
) - 1] == L
'\\')
65 PathName
.Length
-= sizeof(WCHAR
);
66 PathName
.Buffer
[PathName
.Length
/ sizeof(WCHAR
)] = 0;
69 InitializeObjectAttributes(&ObjectAttributes
,
71 OBJ_CASE_INSENSITIVE
| OBJ_INHERIT
,
75 Status
= NtCreateFile(&DirectoryHandle
,
80 FILE_ATTRIBUTE_DIRECTORY
,
81 FILE_SHARE_READ
| FILE_SHARE_WRITE
,
86 if (NT_SUCCESS(Status
))
88 NtClose(DirectoryHandle
);
91 RtlFreeUnicodeString(&PathName
);
102 OBJECT_ATTRIBUTES ObjectAttributes
;
103 IO_STATUS_BLOCK IoStatusBlock
;
108 RtlInitUnicodeString(&Name
,
111 InitializeObjectAttributes(&ObjectAttributes
,
113 OBJ_CASE_INSENSITIVE
,
117 Status
= NtOpenFile(&FileHandle
,
118 GENERIC_READ
| SYNCHRONIZE
,
122 FILE_SYNCHRONOUS_IO_NONALERT
);
123 if (!NT_SUCCESS(Status
))
140 Length
= wcslen(InstallDir
);
142 // TODO: Add check for 8.3 too.
144 /* Path must be at least 2 characters long */
148 /* Path must start with a backslash */
149 // if (InstallDir[0] != L'\\')
152 /* Path must not end with a backslash */
153 if (InstallDir
[Length
- 1] == L
'\\')
156 /* Path must not contain whitespace characters */
157 for (i
= 0; i
< Length
; i
++)
159 if (isspace(InstallDir
[i
]))
163 /* Path component must not end with a dot */
164 for (i
= 0; i
< Length
; i
++)
166 if (InstallDir
[i
] == L
'\\' && i
> 0)
168 if (InstallDir
[i
- 1] == L
'.')
173 if (InstallDir
[Length
- 1] == L
'.')
181 SetupCreateDirectory(
184 PWCHAR PathBuffer
= NULL
;
186 ULONG BackslashCount
;
188 NTSTATUS Status
= STATUS_SUCCESS
;
190 Size
= (wcslen(PathName
) + 1) * sizeof(WCHAR
);
191 PathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, Size
);
192 if (PathBuffer
== NULL
)
193 return STATUS_INSUFFICIENT_RESOURCES
;
195 wcscpy(PathBuffer
, PathName
);
196 EndPtr
= PathBuffer
+ wcslen(PathName
);
200 /* Skip the '\Device\HarddiskX\PartitionY\ part */
202 while (Ptr
< EndPtr
&& BackslashCount
< 4)
216 DPRINT("PathBuffer: %S\n", PathBuffer
);
217 if (!DoesPathExist(PathBuffer
))
219 DPRINT("Create: %S\n", PathBuffer
);
220 Status
= SetupCreateSingleDirectory(PathBuffer
);
221 if (!NT_SUCCESS(Status
))
231 if (!DoesPathExist(PathBuffer
))
233 DPRINT("Create: %S\n", PathBuffer
);
234 Status
= SetupCreateSingleDirectory(PathBuffer
);
235 if (!NT_SUCCESS(Status
))
241 if (PathBuffer
!= NULL
)
242 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
250 PWCHAR SourceFileName
,
251 PWCHAR DestinationFileName
)
253 OBJECT_ATTRIBUTES ObjectAttributes
;
254 HANDLE FileHandleSource
;
255 HANDLE FileHandleDest
;
256 static IO_STATUS_BLOCK IoStatusBlock
;
257 FILE_STANDARD_INFORMATION FileStandard
;
258 FILE_BASIC_INFORMATION FileBasic
;
260 UNICODE_STRING FileName
;
262 PVOID SourceFileMap
= 0;
263 HANDLE SourceFileSection
;
264 SIZE_T SourceSectionSize
= 0;
265 LARGE_INTEGER ByteOffset
;
267 RtlInitUnicodeString(&FileName
,
270 InitializeObjectAttributes(&ObjectAttributes
,
272 OBJ_CASE_INSENSITIVE
,
276 Status
= NtOpenFile(&FileHandleSource
,
281 FILE_SEQUENTIAL_ONLY
);
282 if (!NT_SUCCESS(Status
))
284 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status
, &FileName
);
288 Status
= NtQueryInformationFile(FileHandleSource
,
291 sizeof(FILE_STANDARD_INFORMATION
),
292 FileStandardInformation
);
293 if (!NT_SUCCESS(Status
))
295 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
299 Status
= NtQueryInformationFile(FileHandleSource
,
300 &IoStatusBlock
,&FileBasic
,
301 sizeof(FILE_BASIC_INFORMATION
),
302 FileBasicInformation
);
303 if (!NT_SUCCESS(Status
))
305 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
309 Status
= NtCreateSection(&SourceFileSection
,
316 if (!NT_SUCCESS(Status
))
318 DPRINT1("NtCreateSection failed: %x, %S\n", Status
, SourceFileName
);
322 Status
= NtMapViewOfSection(SourceFileSection
,
332 if (!NT_SUCCESS(Status
))
334 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status
, SourceFileName
);
338 RtlInitUnicodeString(&FileName
,
339 DestinationFileName
);
341 InitializeObjectAttributes(&ObjectAttributes
,
343 OBJ_CASE_INSENSITIVE
,
347 Status
= NtCreateFile(&FileHandleDest
,
348 GENERIC_WRITE
| SYNCHRONIZE
,
352 FILE_ATTRIBUTE_NORMAL
,
355 FILE_NO_INTERMEDIATE_BUFFERING
|
356 FILE_SEQUENTIAL_ONLY
|
357 FILE_SYNCHRONOUS_IO_NONALERT
,
360 if (!NT_SUCCESS(Status
))
362 /* Open may have failed because the file to overwrite
363 * is in readonly mode
365 if (Status
== STATUS_ACCESS_DENIED
)
367 FILE_BASIC_INFORMATION FileBasicInfo
;
369 /* Reattempt to open it with limited access */
370 Status
= NtCreateFile(&FileHandleDest
,
371 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
375 FILE_ATTRIBUTE_NORMAL
,
378 FILE_NO_INTERMEDIATE_BUFFERING
|
379 FILE_SEQUENTIAL_ONLY
|
380 FILE_SYNCHRONOUS_IO_NONALERT
,
383 /* Fail for real if we cannot open it that way */
384 if (!NT_SUCCESS(Status
))
386 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
390 /* Zero our basic info, just to set attributes */
391 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
392 /* Reset attributes to normal, no read-only */
393 FileBasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
394 /* We basically don't care about whether it succeed:
395 * if it didn't, later open will fail
397 NtSetInformationFile(FileHandleDest
, &IoStatusBlock
, &FileBasicInfo
,
398 sizeof(FileBasicInfo
), FileBasicInformation
);
401 NtClose(FileHandleDest
);
403 /* And re-attempt overwrite */
404 Status
= NtCreateFile(&FileHandleDest
,
405 GENERIC_WRITE
| SYNCHRONIZE
,
409 FILE_ATTRIBUTE_NORMAL
,
412 FILE_NO_INTERMEDIATE_BUFFERING
|
413 FILE_SEQUENTIAL_ONLY
|
414 FILE_SYNCHRONOUS_IO_NONALERT
,
420 if (!NT_SUCCESS(Status
))
422 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
427 RegionSize
= (ULONG
)PAGE_ROUND_UP(FileStandard
.EndOfFile
.u
.LowPart
);
428 IoStatusBlock
.Status
= 0;
429 ByteOffset
.QuadPart
= 0ULL;
430 Status
= NtWriteFile(FileHandleDest
,
439 if (!NT_SUCCESS(Status
))
441 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status
, IoStatusBlock
.Status
, &IoStatusBlock
, SourceFileMap
, RegionSize
);
445 /* Copy file date/time from source file */
446 Status
= NtSetInformationFile(FileHandleDest
,
449 sizeof(FILE_BASIC_INFORMATION
),
450 FileBasicInformation
);
451 if (!NT_SUCCESS(Status
))
453 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
457 /* shorten the file back to it's real size after completing the write */
458 Status
= NtSetInformationFile(FileHandleDest
,
460 &FileStandard
.EndOfFile
,
461 sizeof(FILE_END_OF_FILE_INFORMATION
),
462 FileEndOfFileInformation
);
463 if (!NT_SUCCESS(Status
))
465 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
469 NtClose(FileHandleDest
);
472 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap
);
475 NtClose(SourceFileSection
);
478 NtClose(FileHandleSource
);
487 PWCHAR CabinetFileName
,
488 PWCHAR SourceFileName
,
489 PWCHAR DestinationPathName
)
493 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
494 CabinetFileName
, SourceFileName
, DestinationPathName
);
496 if (HasCurrentCabinet
)
498 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName
);
501 if ((HasCurrentCabinet
) && (wcscmp(CabinetFileName
, CurrentCabinetName
) == 0))
503 DPRINT("Using same cabinet as last time\n");
505 /* Use our last location because the files should be sequential */
506 CabStatus
= CabinetFindNextFileSequential(SourceFileName
, &Search
);
507 if (CabStatus
!= CAB_STATUS_SUCCESS
)
509 DPRINT("Sequential miss on file: %S\n", SourceFileName
);
511 /* Looks like we got unlucky */
512 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
517 DPRINT("Using new cabinet\n");
519 if (HasCurrentCabinet
)
524 wcscpy(CurrentCabinetName
, CabinetFileName
);
527 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
528 CabinetSetCabinetName(CabinetFileName
);
530 CabStatus
= CabinetOpen();
531 if (CabStatus
== CAB_STATUS_SUCCESS
)
533 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
534 HasCurrentCabinet
= TRUE
;
538 DPRINT("Cannot open cabinet (%d)\n", CabStatus
);
539 return STATUS_UNSUCCESSFUL
;
542 /* We have to start at the beginning here */
543 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
546 if (CabStatus
!= CAB_STATUS_SUCCESS
)
548 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName
, CabinetGetCabinetName());
549 return STATUS_UNSUCCESSFUL
;
552 CabinetSetDestinationPath(DestinationPathName
);
553 CabStatus
= CabinetExtractFile(&Search
);
554 if (CabStatus
!= CAB_STATUS_SUCCESS
)
556 DPRINT("Cannot extract file %S (%d)\n", SourceFileName
, CabStatus
);
557 return STATUS_UNSUCCESSFUL
;
560 return STATUS_SUCCESS
;
569 OBJECT_ATTRIBUTES ObjectAttributes
;
570 IO_STATUS_BLOCK IoStatusBlock
;
572 WCHAR FullName
[MAX_PATH
];
576 wcscpy(FullName
, PathName
);
577 if (FileName
!= NULL
)
579 if (FileName
[0] != L
'\\')
580 wcscat(FullName
, L
"\\");
581 wcscat(FullName
, FileName
);
584 RtlInitUnicodeString(&Name
,
587 InitializeObjectAttributes(&ObjectAttributes
,
589 OBJ_CASE_INSENSITIVE
,
593 Status
= NtOpenFile(&FileHandle
,
594 GENERIC_READ
| SYNCHRONIZE
,
598 FILE_SYNCHRONOUS_IO_NONALERT
);
599 if (!NT_SUCCESS(Status
))