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
))
141 // TODO: Add check for 8.3 too.
143 /* Check for whitespaces */
144 for (i
= 0; i
< Length
; i
++)
146 if (isspace(InstallDir
[i
]))
155 SetupCreateDirectory(
158 PWCHAR PathBuffer
= NULL
;
160 ULONG BackslashCount
;
162 NTSTATUS Status
= STATUS_SUCCESS
;
164 Size
= (wcslen(PathName
) + 1) * sizeof(WCHAR
);
165 PathBuffer
= RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY
, Size
);
166 if (PathBuffer
== NULL
)
167 return STATUS_INSUFFICIENT_RESOURCES
;
169 wcscpy(PathBuffer
, PathName
);
170 EndPtr
= PathBuffer
+ wcslen(PathName
);
174 /* Skip the '\Device\HarddiskX\PartitionY\ part */
176 while (Ptr
< EndPtr
&& BackslashCount
< 4)
190 DPRINT("PathBuffer: %S\n", PathBuffer
);
191 if (!DoesPathExist(PathBuffer
))
193 DPRINT("Create: %S\n", PathBuffer
);
194 Status
= SetupCreateSingleDirectory(PathBuffer
);
195 if (!NT_SUCCESS(Status
))
205 if (!DoesPathExist(PathBuffer
))
207 DPRINT("Create: %S\n", PathBuffer
);
208 Status
= SetupCreateSingleDirectory(PathBuffer
);
209 if (!NT_SUCCESS(Status
))
215 if (PathBuffer
!= NULL
)
216 RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer
);
224 PWCHAR SourceFileName
,
225 PWCHAR DestinationFileName
)
227 OBJECT_ATTRIBUTES ObjectAttributes
;
228 HANDLE FileHandleSource
;
229 HANDLE FileHandleDest
;
230 static IO_STATUS_BLOCK IoStatusBlock
;
231 FILE_STANDARD_INFORMATION FileStandard
;
232 FILE_BASIC_INFORMATION FileBasic
;
234 UNICODE_STRING FileName
;
236 PVOID SourceFileMap
= 0;
237 HANDLE SourceFileSection
;
238 SIZE_T SourceSectionSize
= 0;
239 LARGE_INTEGER ByteOffset
;
242 RtlInitUnicodeString(&FileName
,
245 InitializeObjectAttributes(&ObjectAttributes
,
247 OBJ_CASE_INSENSITIVE
,
251 Status
= NtOpenFile(&FileHandleSource
,
256 FILE_SEQUENTIAL_ONLY
);
257 if (!NT_SUCCESS(Status
))
259 DPRINT1("NtOpenFile failed: %x, %wZ\n", Status
, &FileName
);
263 FileHandleSource
= CreateFileW(SourceFileName
,
270 if (FileHandleSource
== INVALID_HANDLE_VALUE
)
272 Status
= STATUS_UNSUCCESSFUL
;
277 Status
= NtQueryInformationFile(FileHandleSource
,
280 sizeof(FILE_STANDARD_INFORMATION
),
281 FileStandardInformation
);
282 if (!NT_SUCCESS(Status
))
284 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
288 Status
= NtQueryInformationFile(FileHandleSource
,
289 &IoStatusBlock
,&FileBasic
,
290 sizeof(FILE_BASIC_INFORMATION
),
291 FileBasicInformation
);
292 if (!NT_SUCCESS(Status
))
294 DPRINT1("NtQueryInformationFile failed: %x\n", Status
);
298 Status
= NtCreateSection(&SourceFileSection
,
305 if (!NT_SUCCESS(Status
))
307 DPRINT1("NtCreateSection failed: %x, %S\n", Status
, SourceFileName
);
311 Status
= NtMapViewOfSection(SourceFileSection
,
321 if (!NT_SUCCESS(Status
))
323 DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status
, SourceFileName
);
327 RtlInitUnicodeString(&FileName
,
328 DestinationFileName
);
330 InitializeObjectAttributes(&ObjectAttributes
,
332 OBJ_CASE_INSENSITIVE
,
336 Status
= NtCreateFile(&FileHandleDest
,
337 GENERIC_WRITE
| SYNCHRONIZE
,
341 FILE_ATTRIBUTE_NORMAL
,
344 FILE_NO_INTERMEDIATE_BUFFERING
|
345 FILE_SEQUENTIAL_ONLY
|
346 FILE_SYNCHRONOUS_IO_NONALERT
,
349 if (!NT_SUCCESS(Status
))
351 /* Open may have failed because the file to overwrite
352 * is in readonly mode
354 if (Status
== STATUS_ACCESS_DENIED
)
356 FILE_BASIC_INFORMATION FileBasicInfo
;
358 /* Reattempt to open it with limited access */
359 Status
= NtCreateFile(&FileHandleDest
,
360 FILE_WRITE_ATTRIBUTES
| SYNCHRONIZE
,
364 FILE_ATTRIBUTE_NORMAL
,
367 FILE_NO_INTERMEDIATE_BUFFERING
|
368 FILE_SEQUENTIAL_ONLY
|
369 FILE_SYNCHRONOUS_IO_NONALERT
,
372 /* Fail for real if we cannot open it that way */
373 if (!NT_SUCCESS(Status
))
375 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
379 /* Zero our basic info, just to set attributes */
380 RtlZeroMemory(&FileBasicInfo
, sizeof(FileBasicInfo
));
381 /* Reset attributes to normal, no read-only */
382 FileBasicInfo
.FileAttributes
= FILE_ATTRIBUTE_NORMAL
;
383 /* We basically don't care about whether it succeed:
384 * if it didn't, later open will fail
386 NtSetInformationFile(FileHandleDest
, &IoStatusBlock
, &FileBasicInfo
,
387 sizeof(FileBasicInfo
), FileBasicInformation
);
390 NtClose(FileHandleDest
);
392 /* And re-attempt overwrite */
393 Status
= NtCreateFile(&FileHandleDest
,
394 GENERIC_WRITE
| SYNCHRONIZE
,
398 FILE_ATTRIBUTE_NORMAL
,
401 FILE_NO_INTERMEDIATE_BUFFERING
|
402 FILE_SEQUENTIAL_ONLY
|
403 FILE_SYNCHRONOUS_IO_NONALERT
,
409 if (!NT_SUCCESS(Status
))
411 DPRINT1("NtCreateFile failed: %x, %wZ\n", Status
, &FileName
);
416 RegionSize
= (ULONG
)PAGE_ROUND_UP(FileStandard
.EndOfFile
.u
.LowPart
);
417 IoStatusBlock
.Status
= 0;
418 ByteOffset
.QuadPart
= 0ULL;
419 Status
= NtWriteFile(FileHandleDest
,
428 if (!NT_SUCCESS(Status
))
430 DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status
, IoStatusBlock
.Status
, &IoStatusBlock
, SourceFileMap
, RegionSize
);
434 /* Copy file date/time from source file */
435 Status
= NtSetInformationFile(FileHandleDest
,
438 sizeof(FILE_BASIC_INFORMATION
),
439 FileBasicInformation
);
440 if (!NT_SUCCESS(Status
))
442 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
446 /* shorten the file back to it's real size after completing the write */
447 Status
= NtSetInformationFile(FileHandleDest
,
449 &FileStandard
.EndOfFile
,
450 sizeof(FILE_END_OF_FILE_INFORMATION
),
451 FileEndOfFileInformation
);
452 if (!NT_SUCCESS(Status
))
454 DPRINT1("NtSetInformationFile failed: %x\n", Status
);
458 NtClose(FileHandleDest
);
461 NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap
);
464 NtClose(SourceFileSection
);
467 NtClose(FileHandleSource
);
476 PWCHAR CabinetFileName
,
477 PWCHAR SourceFileName
,
478 PWCHAR DestinationPathName
)
482 DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n",
483 CabinetFileName
, SourceFileName
, DestinationPathName
);
485 if (HasCurrentCabinet
)
487 DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName
);
490 if ((HasCurrentCabinet
) && (wcscmp(CabinetFileName
, CurrentCabinetName
) == 0))
492 DPRINT("Using same cabinet as last time\n");
494 /* Use our last location because the files should be sequential */
495 CabStatus
= CabinetFindNextFileSequential(SourceFileName
, &Search
);
496 if (CabStatus
!= CAB_STATUS_SUCCESS
)
498 DPRINT("Sequential miss on file: %S\n", SourceFileName
);
500 /* Looks like we got unlucky */
501 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
506 DPRINT("Using new cabinet\n");
508 if (HasCurrentCabinet
)
513 wcscpy(CurrentCabinetName
, CabinetFileName
);
516 CabinetSetEventHandlers(NULL
, NULL
, NULL
);
517 CabinetSetCabinetName(CabinetFileName
);
519 CabStatus
= CabinetOpen();
520 if (CabStatus
== CAB_STATUS_SUCCESS
)
522 DPRINT("Opened cabinet %S\n", CabinetGetCabinetName());
523 HasCurrentCabinet
= TRUE
;
527 DPRINT("Cannot open cabinet (%d)\n", CabStatus
);
528 return STATUS_UNSUCCESSFUL
;
531 /* We have to start at the beginning here */
532 CabStatus
= CabinetFindFirst(SourceFileName
, &Search
);
535 if (CabStatus
!= CAB_STATUS_SUCCESS
)
537 DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName
, CabinetGetCabinetName());
538 return STATUS_UNSUCCESSFUL
;
541 CabinetSetDestinationPath(DestinationPathName
);
542 CabStatus
= CabinetExtractFile(&Search
);
543 if (CabStatus
!= CAB_STATUS_SUCCESS
)
545 DPRINT("Cannot extract file %S (%d)\n", SourceFileName
, CabStatus
);
546 return STATUS_UNSUCCESSFUL
;
549 return STATUS_SUCCESS
;
558 OBJECT_ATTRIBUTES ObjectAttributes
;
559 IO_STATUS_BLOCK IoStatusBlock
;
561 WCHAR FullName
[MAX_PATH
];
565 wcscpy(FullName
, PathName
);
566 if (FileName
!= NULL
)
568 if (FileName
[0] != L
'\\')
569 wcscat(FullName
, L
"\\");
570 wcscat(FullName
, FileName
);
573 RtlInitUnicodeString(&Name
,
576 InitializeObjectAttributes(&ObjectAttributes
,
578 OBJ_CASE_INSENSITIVE
,
582 Status
= NtOpenFile(&FileHandle
,
583 GENERIC_READ
| SYNCHRONIZE
,
587 FILE_SYNCHRONOUS_IO_NONALERT
);
588 if (!NT_SUCCESS(Status
))