/* * ReactOS kernel * Copyright (C) 2002 ReactOS Team * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ /* COPYRIGHT: See COPYING in the top level directory * PROJECT: ReactOS text-mode setup * FILE: base/setup/usetup/filesup.c * PURPOSE: File support functions * PROGRAMMER: Eric Kohl * Casper S. Hornstrup (chorns@users.sourceforge.net) */ /* INCLUDES *****************************************************************/ #include "usetup.h" #define NDEBUG #include /* FUNCTIONS ****************************************************************/ static BOOLEAN HasCurrentCabinet = FALSE; static WCHAR CurrentCabinetName[MAX_PATH]; static CAB_SEARCH Search; static NTSTATUS SetupCreateSingleDirectory( PWCHAR DirectoryName) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING PathName; HANDLE DirectoryHandle; NTSTATUS Status; if(!RtlCreateUnicodeString(&PathName, DirectoryName)) return STATUS_NO_MEMORY; if (PathName.Length > sizeof(WCHAR) && PathName.Buffer[PathName.Length / sizeof(WCHAR) - 2] == L'\\' && PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'.') { PathName.Length -= sizeof(WCHAR); PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0; } if (PathName.Length > sizeof(WCHAR) && PathName.Buffer[PathName.Length / sizeof(WCHAR) - 1] == L'\\') { PathName.Length -= sizeof(WCHAR); PathName.Buffer[PathName.Length / sizeof(WCHAR)] = 0; } InitializeObjectAttributes(&ObjectAttributes, &PathName, OBJ_CASE_INSENSITIVE | OBJ_INHERIT, NULL, NULL); Status = NtCreateFile(&DirectoryHandle, DIRECTORY_ALL_ACCESS, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_DIRECTORY, FILE_SHARE_READ | FILE_SHARE_WRITE, FILE_OPEN_IF, FILE_DIRECTORY_FILE, NULL, 0); if (NT_SUCCESS(Status)) { NtClose(DirectoryHandle); } RtlFreeUnicodeString(&PathName); return Status; } static BOOLEAN DoesPathExist( PWSTR PathName) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; HANDLE FileHandle; NTSTATUS Status; RtlInitUnicodeString(&Name, PathName); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(Status)) { return FALSE; } NtClose(FileHandle); return TRUE; } BOOLEAN IsValidPath( PWCHAR InstallDir, ULONG Length) { UINT i; // TODO: Add check for 8.3 too. /* Check for whitespaces */ for (i = 0; i < Length; i++) { if (isspace(InstallDir[i])) return FALSE; } return TRUE; } NTSTATUS SetupCreateDirectory( PWCHAR PathName) { PWCHAR PathBuffer = NULL; PWCHAR Ptr, EndPtr; ULONG BackslashCount; ULONG Size; NTSTATUS Status = STATUS_SUCCESS; Size = (wcslen(PathName) + 1) * sizeof(WCHAR); PathBuffer = RtlAllocateHeap(RtlGetProcessHeap(), HEAP_ZERO_MEMORY, Size); if (PathBuffer == NULL) return STATUS_INSUFFICIENT_RESOURCES; wcscpy(PathBuffer, PathName); EndPtr = PathBuffer + wcslen(PathName); Ptr = PathBuffer; /* Skip the '\Device\HarddiskX\PartitionY\ part */ BackslashCount = 0; while (Ptr < EndPtr && BackslashCount < 4) { if (*Ptr == L'\\') BackslashCount++; Ptr++; } while (Ptr < EndPtr) { if (*Ptr == L'\\') { *Ptr = 0; DPRINT("PathBuffer: %S\n", PathBuffer); if (!DoesPathExist(PathBuffer)) { DPRINT("Create: %S\n", PathBuffer); Status = SetupCreateSingleDirectory(PathBuffer); if (!NT_SUCCESS(Status)) goto done; } *Ptr = L'\\'; } Ptr++; } if (!DoesPathExist(PathBuffer)) { DPRINT("Create: %S\n", PathBuffer); Status = SetupCreateSingleDirectory(PathBuffer); if (!NT_SUCCESS(Status)) goto done; } done: DPRINT("Done.\n"); if (PathBuffer != NULL) RtlFreeHeap(RtlGetProcessHeap(), 0, PathBuffer); return Status; } NTSTATUS SetupCopyFile( PWCHAR SourceFileName, PWCHAR DestinationFileName) { OBJECT_ATTRIBUTES ObjectAttributes; HANDLE FileHandleSource; HANDLE FileHandleDest; static IO_STATUS_BLOCK IoStatusBlock; FILE_STANDARD_INFORMATION FileStandard; FILE_BASIC_INFORMATION FileBasic; ULONG RegionSize; UNICODE_STRING FileName; NTSTATUS Status; PVOID SourceFileMap = 0; HANDLE SourceFileSection; SIZE_T SourceSectionSize = 0; LARGE_INTEGER ByteOffset; #ifdef __REACTOS__ RtlInitUnicodeString(&FileName, SourceFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandleSource, GENERIC_READ, &ObjectAttributes, &IoStatusBlock, FILE_SHARE_READ, FILE_SEQUENTIAL_ONLY); if (!NT_SUCCESS(Status)) { DPRINT1("NtOpenFile failed: %x, %wZ\n", Status, &FileName); goto done; } #else FileHandleSource = CreateFileW(SourceFileName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL); if (FileHandleSource == INVALID_HANDLE_VALUE) { Status = STATUS_UNSUCCESSFUL; goto done; } #endif Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock, &FileStandard, sizeof(FILE_STANDARD_INFORMATION), FileStandardInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtQueryInformationFile(FileHandleSource, &IoStatusBlock,&FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtQueryInformationFile failed: %x\n", Status); goto closesrc; } Status = NtCreateSection(&SourceFileSection, SECTION_MAP_READ, NULL, NULL, PAGE_READONLY, SEC_COMMIT, FileHandleSource); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateSection failed: %x, %S\n", Status, SourceFileName); goto closesrc; } Status = NtMapViewOfSection(SourceFileSection, NtCurrentProcess(), &SourceFileMap, 0, 0, NULL, &SourceSectionSize, ViewUnmap, 0, PAGE_READONLY ); if (!NT_SUCCESS(Status)) { DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName); goto closesrcsec; } RtlInitUnicodeString(&FileName, DestinationFileName); InitializeObjectAttributes(&ObjectAttributes, &FileName, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtCreateFile(&FileHandleDest, GENERIC_WRITE | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, NULL, FILE_ATTRIBUTE_NORMAL, 0, FILE_OVERWRITE_IF, FILE_NO_INTERMEDIATE_BUFFERING | FILE_SEQUENTIAL_ONLY | FILE_SYNCHRONOUS_IO_NONALERT, NULL, 0); if (!NT_SUCCESS(Status)) { DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName); goto unmapsrcsec; } RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart); IoStatusBlock.Status = 0; ByteOffset.QuadPart = 0ULL; Status = NtWriteFile(FileHandleDest, NULL, NULL, NULL, &IoStatusBlock, SourceFileMap, RegionSize, &ByteOffset, NULL); if (!NT_SUCCESS(Status)) { DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize); goto closedest; } /* Copy file date/time from source file */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); goto closedest; } /* shorten the file back to it's real size after completing the write */ Status = NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileStandard.EndOfFile, sizeof(FILE_END_OF_FILE_INFORMATION), FileEndOfFileInformation); if (!NT_SUCCESS(Status)) { DPRINT1("NtSetInformationFile failed: %x\n", Status); } closedest: NtClose(FileHandleDest); unmapsrcsec: NtUnmapViewOfSection(NtCurrentProcess(), SourceFileMap); closesrcsec: NtClose(SourceFileSection); closesrc: NtClose(FileHandleSource); done: return Status; } #ifdef __REACTOS__ NTSTATUS SetupExtractFile( PWCHAR CabinetFileName, PWCHAR SourceFileName, PWCHAR DestinationPathName) { ULONG CabStatus; DPRINT("SetupExtractFile(CabinetFileName %S, SourceFileName %S, DestinationPathName %S)\n", CabinetFileName, SourceFileName, DestinationPathName); if (HasCurrentCabinet) { DPRINT("CurrentCabinetName: %S\n", CurrentCabinetName); } if ((HasCurrentCabinet) && (wcscmp(CabinetFileName, CurrentCabinetName) == 0)) { DPRINT("Using same cabinet as last time\n"); /* Use our last location because the files should be sequential */ CabStatus = CabinetFindNextFileSequential(SourceFileName, &Search); if (CabStatus != CAB_STATUS_SUCCESS) { DPRINT("Sequential miss on file: %S\n", SourceFileName); /* Looks like we got unlucky */ CabStatus = CabinetFindFirst(SourceFileName, &Search); } } else { DPRINT("Using new cabinet\n"); if (HasCurrentCabinet) { CabinetCleanup(); } wcscpy(CurrentCabinetName, CabinetFileName); CabinetInitialize(); CabinetSetEventHandlers(NULL, NULL, NULL); CabinetSetCabinetName(CabinetFileName); CabStatus = CabinetOpen(); if (CabStatus == CAB_STATUS_SUCCESS) { DPRINT("Opened cabinet %S\n", CabinetGetCabinetName()); HasCurrentCabinet = TRUE; } else { DPRINT("Cannot open cabinet (%d)\n", CabStatus); return STATUS_UNSUCCESSFUL; } /* We have to start at the beginning here */ CabStatus = CabinetFindFirst(SourceFileName, &Search); } if (CabStatus != CAB_STATUS_SUCCESS) { DPRINT1("Unable to find '%S' in cabinet '%S'\n", SourceFileName, CabinetGetCabinetName()); return STATUS_UNSUCCESSFUL; } CabinetSetDestinationPath(DestinationPathName); CabStatus = CabinetExtractFile(&Search); if (CabStatus != CAB_STATUS_SUCCESS) { DPRINT("Cannot extract file %S (%d)\n", SourceFileName, CabStatus); return STATUS_UNSUCCESSFUL; } return STATUS_SUCCESS; } #endif BOOLEAN DoesFileExist( PWSTR PathName, PWSTR FileName) { OBJECT_ATTRIBUTES ObjectAttributes; IO_STATUS_BLOCK IoStatusBlock; UNICODE_STRING Name; WCHAR FullName[MAX_PATH]; HANDLE FileHandle; NTSTATUS Status; wcscpy(FullName, PathName); if (FileName != NULL) { if (FileName[0] != L'\\') wcscat(FullName, L"\\"); wcscat(FullName, FileName); } RtlInitUnicodeString(&Name, FullName); InitializeObjectAttributes(&ObjectAttributes, &Name, OBJ_CASE_INSENSITIVE, NULL, NULL); Status = NtOpenFile(&FileHandle, GENERIC_READ | SYNCHRONIZE, &ObjectAttributes, &IoStatusBlock, 0, FILE_SYNCHRONOUS_IO_NONALERT); if (!NT_SUCCESS(Status)) { return FALSE; } NtClose(FileHandle); return TRUE; } /* EOF */