mirror of
https://github.com/reactos/reactos.git
synced 2024-11-20 06:15:26 +00:00
9ed2e0b5bc
svn path=/branches/condrv_restructure/; revision=63744
516 lines
15 KiB
C
516 lines
15 KiB
C
/*
|
|
* 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: subsys/system/usetup/filesup.c
|
|
* PURPOSE: File support functions
|
|
* PROGRAMMER: Eric Kohl
|
|
* Casper S. Hornstrup (chorns@users.sourceforge.net)
|
|
*/
|
|
|
|
/* INCLUDES *****************************************************************/
|
|
|
|
#include "usetup.h"
|
|
|
|
#define NDEBUG
|
|
#include <debug.h>
|
|
|
|
/* 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;
|
|
|
|
RtlCreateUnicodeString(&PathName,
|
|
DirectoryName);
|
|
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;
|
|
}
|
|
|
|
|
|
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\n", Status);
|
|
goto unmapsrcsec;
|
|
}
|
|
|
|
RegionSize = (ULONG)PAGE_ROUND_UP(FileStandard.EndOfFile.u.LowPart);
|
|
IoStatusBlock.Status = 0;
|
|
ByteOffset.QuadPart = 0;
|
|
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 */
|