[USETUP] Move Setup[Delete|Copy|Move]File() from usetup code into the setuplib's filesup.c .

Remove the commented-out IsValidPath() in that file, and remove
as well the temporary prototypes in regutil.c .

svn path=/branches/setup_improvements/; revision=75249
This commit is contained in:
Hermès Bélusca-Maïto 2017-06-30 22:28:06 +00:00
parent 60d9ea76d1
commit 2268b3d645
No known key found for this signature in database
GPG key ID: 3B2539C65E7B93D0
5 changed files with 480 additions and 506 deletions

View file

@ -12,8 +12,465 @@
#define NDEBUG
#include <debug.h>
// ACHTUNG! HAXX FIXME!!
#define _SEH2_TRY
#define _SEH2_LEAVE goto __SEH2_FINALLY__label;
#define _SEH2_FINALLY __SEH2_FINALLY__label:
#define _SEH2_END
/* FUNCTIONS ****************************************************************/
// TODO: Move SetupCreateDirectory later...
NTSTATUS
SetupDeleteFile(
IN PCWSTR FileName,
IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files
{
NTSTATUS Status;
UNICODE_STRING NtPathU;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
FILE_DISPOSITION_INFORMATION FileDispInfo;
BOOLEAN RetryOnce = FALSE;
/* Open the directory name that was passed in */
RtlInitUnicodeString(&NtPathU, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&NtPathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Retry: // We go back there once if RetryOnce == TRUE
Status = NtOpenFile(&FileHandle,
DELETE | FILE_READ_ATTRIBUTES |
(RetryOnce ? FILE_WRITE_ATTRIBUTES : 0),
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status);
return Status;
}
if (RetryOnce)
{
FILE_BASIC_INFORMATION FileInformation;
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInformation,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n", Status);
NtClose(FileHandle);
return Status;
}
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileInformation,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n", Status);
return Status;
}
}
/* Ask for the file to be deleted */
FileDispInfo.DeleteFile = TRUE;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileDispInfo,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n", FileName, Status);
// FIXME: Check the precise value of Status!
if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce)
{
/* Retry once */
RetryOnce = TRUE;
goto Retry;
}
/* Return result to the caller */
return Status;
}
NTSTATUS
SetupCopyFile(
IN PCWSTR SourceFileName,
IN PCWSTR DestinationFileName,
IN BOOLEAN FailIfExists)
{
NTSTATUS Status;
UNICODE_STRING FileName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandleSource;
HANDLE FileHandleDest;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION FileStandard;
FILE_BASIC_INFORMATION FileBasic;
ULONG RegionSize;
HANDLE SourceFileSection;
PVOID SourceFileMap = NULL;
SIZE_T SourceSectionSize = 0;
LARGE_INTEGER ByteOffset;
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;
}
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,
FileBasic.FileAttributes, // FILE_ATTRIBUTE_NORMAL,
0,
FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SEQUENTIAL_ONLY |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
/*
* Open may have failed because the file to overwrite
* is in readonly mode.
*/
if (Status == STATUS_ACCESS_DENIED)
{
FILE_BASIC_INFORMATION FileBasicInfo;
/* Reattempt to open it with limited access */
Status = NtCreateFile(&FileHandleDest,
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SEQUENTIAL_ONLY |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
/* Fail for real if we cannot open it that way */
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName);
goto unmapsrcsec;
}
/* Zero our basic info, just to set attributes */
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
/* Reset attributes to normal, no read-only */
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
/*
* We basically don't care about whether it succeed:
* if it didn't, later open will fail.
*/
NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasicInfo,
sizeof(FileBasicInfo), FileBasicInformation);
/* Close file */
NtClose(FileHandleDest);
/* And re-attempt overwrite */
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);
}
/* We failed */
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 its 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;
}
/*
* Synchronized with its kernel32 counterpart, but we don't manage reparse points here.
*/
NTSTATUS
SetupMoveFile(
IN PCWSTR ExistingFileName,
IN PCWSTR NewFileName,
IN ULONG Flags)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PFILE_RENAME_INFORMATION RenameInfo;
UNICODE_STRING NewPathU, ExistingPathU;
HANDLE SourceHandle = NULL;
BOOLEAN ReplaceIfExists;
RtlInitUnicodeString(&ExistingPathU, ExistingFileName);
RtlInitUnicodeString(&NewPathU, NewFileName);
_SEH2_TRY
{
ReplaceIfExists = !!(Flags & MOVEFILE_REPLACE_EXISTING);
/* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
InitializeObjectAttributes(&ObjectAttributes,
&ExistingPathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Attempt to open source file */
Status = NtOpenFile(&SourceHandle,
FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_FOR_BACKUP_INTENT | ((Flags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
if (!NT_SUCCESS(Status))
{
if (Status != STATUS_INVALID_PARAMETER)
{
_SEH2_LEAVE;
}
}
/* At that point, we MUST have a source handle */
ASSERT(SourceHandle);
/* Allocate renaming buffer and fill it */
RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
if (RenameInfo == NULL)
{
Status = STATUS_NO_MEMORY;
_SEH2_LEAVE;
}
RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
RenameInfo->ReplaceIfExists = ReplaceIfExists;
RenameInfo->RootDirectory = NULL;
RenameInfo->FileNameLength = NewPathU.Length;
/* Attempt to rename the file */
Status = NtSetInformationFile(SourceHandle,
&IoStatusBlock,
RenameInfo,
NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
FileRenameInformation);
RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
if (NT_SUCCESS(Status))
{
/* If it succeeded, all fine, quit */
_SEH2_LEAVE;
}
/*
* If we failed for any other reason than not the same device, fail.
* If we failed because of different devices, only allow renaming
* if user allowed copy.
*/
if (Status != STATUS_NOT_SAME_DEVICE || !(Flags & MOVEFILE_COPY_ALLOWED))
{
/* ReactOS hack! To be removed once all FSD have proper renaming support
* Just leave status to error and leave
*/
if (Status == STATUS_NOT_IMPLEMENTED)
{
DPRINT1("Forcing copy, renaming not supported by FSD\n");
}
else
{
_SEH2_LEAVE;
}
}
/* Close the source file */
NtClose(SourceHandle);
SourceHandle = NULL;
/* Perform the file copy */
Status = SetupCopyFile(ExistingFileName,
NewFileName,
!ReplaceIfExists);
/* If it succeeded, delete the source file */
if (NT_SUCCESS(Status))
{
/* Force-delete files even if read-only */
SetupDeleteFile(ExistingFileName, TRUE);
}
}
_SEH2_FINALLY
{
if (SourceHandle)
NtClose(SourceHandle);
}
_SEH2_END;
return Status;
}
NTSTATUS
ConcatPathsV(
IN OUT PWSTR PathBuffer,

View file

@ -7,14 +7,31 @@
#pragma once
#if 0
NTSTATUS
SetupDeleteFile(
IN PCWSTR FileName,
IN BOOLEAN ForceDelete); // ForceDelete can be used to delete read-only files
BOOLEAN
IsValidPath(
IN PCWSTR InstallDir);
NTSTATUS
SetupCopyFile(
IN PCWSTR SourceFileName,
IN PCWSTR DestinationFileName,
IN BOOLEAN FailIfExists);
#ifndef _WINBASE_
#define MOVEFILE_REPLACE_EXISTING 1
#define MOVEFILE_COPY_ALLOWED 2
#define MOVEFILE_WRITE_THROUGH 8
#endif
NTSTATUS
SetupMoveFile(
IN PCWSTR ExistingFileName,
IN PCWSTR NewFileName,
IN ULONG Flags);
NTSTATUS
ConcatPathsV(
IN OUT PWSTR PathBuffer,

View file

@ -19,27 +19,6 @@
#define NDEBUG
#include <debug.h>
// HACK!! These functions should actually be moved in the setup lib!
// For the moment, see usetup/filesup.c (or .h)
#if 1
NTSTATUS
SetupCopyFile(
IN PCWSTR SourceFileName,
IN PCWSTR DestinationFileName,
IN BOOLEAN FailIfExists);
#define MOVEFILE_REPLACE_EXISTING 1
NTSTATUS
SetupMoveFile(
IN PCWSTR ExistingFileName,
IN PCWSTR NewFileName,
IN ULONG Flags);
#endif
/* FUNCTIONS ****************************************************************/
/*

View file

@ -3,7 +3,7 @@
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/filesup.c
* PURPOSE: File support functions
* PROGRAMMER: Casper S. Hornstrup (chorns@users.sourceforge.net)
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
/* INCLUDES *****************************************************************/
@ -142,451 +142,6 @@ done:
return Status;
}
NTSTATUS
SetupDeleteFile(
IN PCWSTR FileName,
IN BOOLEAN ForceDelete) // ForceDelete can be used to delete read-only files
{
NTSTATUS Status;
UNICODE_STRING NtPathU;
OBJECT_ATTRIBUTES ObjectAttributes;
IO_STATUS_BLOCK IoStatusBlock;
HANDLE FileHandle;
FILE_DISPOSITION_INFORMATION FileDispInfo;
BOOLEAN RetryOnce = FALSE;
/* Open the directory name that was passed in */
RtlInitUnicodeString(&NtPathU, FileName);
InitializeObjectAttributes(&ObjectAttributes,
&NtPathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
Retry: // We go back there once if RetryOnce == TRUE
Status = NtOpenFile(&FileHandle,
DELETE | FILE_READ_ATTRIBUTES |
(RetryOnce ? FILE_WRITE_ATTRIBUTES : 0),
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_NON_DIRECTORY_FILE | FILE_OPEN_FOR_BACKUP_INTENT);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtOpenFile failed with Status 0x%08lx\n", Status);
return Status;
}
if (RetryOnce)
{
FILE_BASIC_INFORMATION FileInformation;
Status = NtQueryInformationFile(FileHandle,
&IoStatusBlock,
&FileInformation,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtQueryInformationFile failed with Status 0x%08lx\n", Status);
NtClose(FileHandle);
return Status;
}
FileInformation.FileAttributes = FILE_ATTRIBUTE_NORMAL;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileInformation,
sizeof(FILE_BASIC_INFORMATION),
FileBasicInformation);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
{
DPRINT1("NtSetInformationFile failed with Status 0x%08lx\n", Status);
return Status;
}
}
/* Ask for the file to be deleted */
FileDispInfo.DeleteFile = TRUE;
Status = NtSetInformationFile(FileHandle,
&IoStatusBlock,
&FileDispInfo,
sizeof(FILE_DISPOSITION_INFORMATION),
FileDispositionInformation);
NtClose(FileHandle);
if (!NT_SUCCESS(Status))
DPRINT1("Deletion of file '%S' failed, Status 0x%08lx\n", FileName, Status);
// FIXME: Check the precise value of Status!
if (!NT_SUCCESS(Status) && ForceDelete && !RetryOnce)
{
/* Retry once */
RetryOnce = TRUE;
goto Retry;
}
/* Return result to the caller */
return Status;
}
NTSTATUS
SetupCopyFile(
IN PCWSTR SourceFileName,
IN PCWSTR DestinationFileName,
IN BOOLEAN FailIfExists)
{
NTSTATUS Status;
UNICODE_STRING FileName;
OBJECT_ATTRIBUTES ObjectAttributes;
HANDLE FileHandleSource;
HANDLE FileHandleDest;
IO_STATUS_BLOCK IoStatusBlock;
FILE_STANDARD_INFORMATION FileStandard;
FILE_BASIC_INFORMATION FileBasic;
ULONG RegionSize;
HANDLE SourceFileSection;
PVOID SourceFileMap = NULL;
SIZE_T SourceSectionSize = 0;
LARGE_INTEGER ByteOffset;
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;
}
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,
FileBasic.FileAttributes, // FILE_ATTRIBUTE_NORMAL,
0,
FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SEQUENTIAL_ONLY |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
if (!NT_SUCCESS(Status))
{
/* Open may have failed because the file to overwrite
* is in readonly mode
*/
if (Status == STATUS_ACCESS_DENIED)
{
FILE_BASIC_INFORMATION FileBasicInfo;
/* Reattempt to open it with limited access */
Status = NtCreateFile(&FileHandleDest,
FILE_WRITE_ATTRIBUTES | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
NULL,
FILE_ATTRIBUTE_NORMAL,
0,
FILE_OPEN,
FILE_NO_INTERMEDIATE_BUFFERING |
FILE_SEQUENTIAL_ONLY |
FILE_SYNCHRONOUS_IO_NONALERT,
NULL,
0);
/* Fail for real if we cannot open it that way */
if (!NT_SUCCESS(Status))
{
DPRINT1("NtCreateFile failed: %x, %wZ\n", Status, &FileName);
goto unmapsrcsec;
}
/* Zero our basic info, just to set attributes */
RtlZeroMemory(&FileBasicInfo, sizeof(FileBasicInfo));
/* Reset attributes to normal, no read-only */
FileBasicInfo.FileAttributes = FILE_ATTRIBUTE_NORMAL;
/* We basically don't care about whether it succeed:
* if it didn't, later open will fail
*/
NtSetInformationFile(FileHandleDest, &IoStatusBlock, &FileBasicInfo,
sizeof(FileBasicInfo), FileBasicInformation);
/* Close file */
NtClose(FileHandleDest);
/* And re-attempt overwrite */
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);
}
/* We failed */
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 its 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;
}
/*
* Synchronized with its kernel32 counterpart, but we don't manage reparse points here.
*/
NTSTATUS
SetupMoveFile(
IN PCWSTR ExistingFileName,
IN PCWSTR NewFileName,
IN ULONG Flags)
{
NTSTATUS Status;
IO_STATUS_BLOCK IoStatusBlock;
OBJECT_ATTRIBUTES ObjectAttributes;
PFILE_RENAME_INFORMATION RenameInfo;
UNICODE_STRING NewPathU, ExistingPathU;
HANDLE SourceHandle = NULL;
BOOLEAN ReplaceIfExists;
RtlInitUnicodeString(&ExistingPathU, ExistingFileName);
RtlInitUnicodeString(&NewPathU, NewFileName);
_SEH2_TRY
{
ReplaceIfExists = !!(Flags & MOVEFILE_REPLACE_EXISTING);
/* Unless we manage a proper opening, we'll attempt to reopen without reparse support */
InitializeObjectAttributes(&ObjectAttributes,
&ExistingPathU,
OBJ_CASE_INSENSITIVE,
NULL,
NULL);
/* Attempt to open source file */
Status = NtOpenFile(&SourceHandle,
FILE_READ_ATTRIBUTES | DELETE | SYNCHRONIZE,
&ObjectAttributes,
&IoStatusBlock,
FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE,
FILE_OPEN_FOR_BACKUP_INTENT | ((Flags & MOVEFILE_WRITE_THROUGH) ? FILE_WRITE_THROUGH : 0));
if (!NT_SUCCESS(Status))
{
if (Status != STATUS_INVALID_PARAMETER)
{
_SEH2_LEAVE;
}
}
/* At that point, we MUST have a source handle */
ASSERT(SourceHandle);
/* Allocate renaming buffer and fill it */
RenameInfo = RtlAllocateHeap(RtlGetProcessHeap(), 0, NewPathU.Length + sizeof(FILE_RENAME_INFORMATION));
if (RenameInfo == NULL)
{
Status = STATUS_NO_MEMORY;
_SEH2_LEAVE;
}
RtlCopyMemory(&RenameInfo->FileName, NewPathU.Buffer, NewPathU.Length);
RenameInfo->ReplaceIfExists = ReplaceIfExists;
RenameInfo->RootDirectory = NULL;
RenameInfo->FileNameLength = NewPathU.Length;
/* Attempt to rename the file */
Status = NtSetInformationFile(SourceHandle,
&IoStatusBlock,
RenameInfo,
NewPathU.Length + sizeof(FILE_RENAME_INFORMATION),
FileRenameInformation);
RtlFreeHeap(RtlGetProcessHeap(), 0, RenameInfo);
if (NT_SUCCESS(Status))
{
/* If it succeeded, all fine, quit */
_SEH2_LEAVE;
}
/*
* If we failed for any other reason than not the same device, fail.
* If we failed because of different devices, only allow renaming
* if user allowed copy.
*/
if (Status != STATUS_NOT_SAME_DEVICE || !(Flags & MOVEFILE_COPY_ALLOWED))
{
/* ReactOS hack! To be removed once all FSD have proper renaming support
* Just leave status to error and leave
*/
if (Status == STATUS_NOT_IMPLEMENTED)
{
DPRINT1("Forcing copy, renaming not supported by FSD\n");
}
else
{
_SEH2_LEAVE;
}
}
/* Close the source file */
NtClose(SourceHandle);
SourceHandle = NULL;
/* Perform the file copy */
Status = SetupCopyFile(ExistingFileName,
NewFileName,
!ReplaceIfExists);
/* If it succeeded, delete the source file */
if (NT_SUCCESS(Status))
{
/* Force-delete files even if read-only */
SetupDeleteFile(ExistingFileName, TRUE);
}
}
_SEH2_FINALLY
{
if (SourceHandle)
NtClose(SourceHandle);
}
_SEH2_END;
return Status;
}
NTSTATUS
SetupExtractFile(
PWCHAR CabinetFileName,
@ -665,7 +220,6 @@ SetupExtractFile(
return STATUS_SUCCESS;
}
BOOLEAN
IsValidPath(
IN PCWSTR InstallDir)

View file

@ -3,7 +3,7 @@
* PROJECT: ReactOS text-mode setup
* FILE: base/setup/usetup/filesup.h
* PURPOSE: File support functions
* PROGRAMMER:
* PROGRAMMERS: Casper S. Hornstrup (chorns@users.sourceforge.net)
*/
#pragma once
@ -12,45 +12,12 @@ NTSTATUS
SetupCreateDirectory(
PWCHAR DirectoryName);
NTSTATUS
SetupDeleteFile(
IN PCWSTR FileName,
IN BOOLEAN ForceDelete); // ForceDelete can be used to delete read-only files
NTSTATUS
SetupCopyFile(
IN PCWSTR SourceFileName,
IN PCWSTR DestinationFileName,
IN BOOLEAN FailIfExists);
#ifndef _WINBASE_
#define MOVEFILE_REPLACE_EXISTING 1
#define MOVEFILE_COPY_ALLOWED 2
#define MOVEFILE_WRITE_THROUGH 8
#endif
// ACHTUNG! HAXX FIXME!!
#define _SEH2_TRY
#define _SEH2_LEAVE goto __SEH2_FINALLY__label;
#define _SEH2_FINALLY __SEH2_FINALLY__label:
#define _SEH2_END
NTSTATUS
SetupMoveFile(
IN PCWSTR ExistingFileName,
IN PCWSTR NewFileName,
IN ULONG Flags);
NTSTATUS
SetupExtractFile(
PWCHAR CabinetFileName,
PWCHAR SourceFileName,
PWCHAR DestinationFileName);
BOOLEAN
IsValidPath(
IN PCWSTR InstallDir);