mirror of
https://github.com/reactos/reactos.git
synced 2026-06-02 17:31:23 +08:00
[USETUP] Introduce SetupDeleteFile() and SetupMoveFile() (in addition to the already-existing SetupCopyFile()) in order to implement moving / renaming existing files.
Will be used soon to make backups of system files, like the registry hive files just freshly created. - Make the SetupCopyFile() function closer to its win32 counterpart. - Adjust the code that calls SetupCopyFile(). svn path=/branches/setup_improvements/; revision=75008 svn path=/branches/setup_improvements/; revision=75009
This commit is contained in:
@@ -1788,7 +1788,7 @@ InstallFatBootcodeToPartition(
|
||||
CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
|
||||
|
||||
DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath, FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
|
||||
@@ -2101,7 +2101,7 @@ InstallBtrfsBootcodeToPartition(
|
||||
CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, SystemRootPath->Buffer, L"freeldr.sys");
|
||||
|
||||
DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath, FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
|
||||
@@ -2266,7 +2266,7 @@ InstallFatBootcodeToFloppy(
|
||||
CombinePaths(DstPath, ARRAYSIZE(DstPath), 2, FloppyDevice.Buffer, L"freeldr.sys");
|
||||
|
||||
DPRINT("Copy: %S ==> %S\n", SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath);
|
||||
Status = SetupCopyFile(SrcPath, DstPath, FALSE);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("SetupCopyFile() failed (Status %lx)\n", Status);
|
||||
|
||||
@@ -427,7 +427,7 @@ SetupCommitFileQueueW(
|
||||
else
|
||||
{
|
||||
/* Copy the file */
|
||||
Status = SetupCopyFile(FileSrcPath, FileDstPath);
|
||||
Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
|
||||
}
|
||||
|
||||
if (!NT_SUCCESS(Status))
|
||||
|
||||
@@ -143,26 +143,115 @@ done:
|
||||
}
|
||||
|
||||
NTSTATUS
|
||||
SetupCopyFile(
|
||||
PWCHAR SourceFileName,
|
||||
PWCHAR DestinationFileName)
|
||||
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;
|
||||
static IO_STATUS_BLOCK IoStatusBlock;
|
||||
IO_STATUS_BLOCK IoStatusBlock;
|
||||
FILE_STANDARD_INFORMATION FileStandard;
|
||||
FILE_BASIC_INFORMATION FileBasic;
|
||||
ULONG RegionSize;
|
||||
UNICODE_STRING FileName;
|
||||
NTSTATUS Status;
|
||||
PVOID SourceFileMap = 0;
|
||||
HANDLE SourceFileSection;
|
||||
PVOID SourceFileMap = NULL;
|
||||
SIZE_T SourceSectionSize = 0;
|
||||
LARGE_INTEGER ByteOffset;
|
||||
|
||||
RtlInitUnicodeString(&FileName,
|
||||
SourceFileName);
|
||||
RtlInitUnicodeString(&FileName, SourceFileName);
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&FileName,
|
||||
@@ -194,7 +283,8 @@ SetupCopyFile(
|
||||
}
|
||||
|
||||
Status = NtQueryInformationFile(FileHandleSource,
|
||||
&IoStatusBlock,&FileBasic,
|
||||
&IoStatusBlock,
|
||||
&FileBasic,
|
||||
sizeof(FILE_BASIC_INFORMATION),
|
||||
FileBasicInformation);
|
||||
if (!NT_SUCCESS(Status))
|
||||
@@ -225,15 +315,14 @@ SetupCopyFile(
|
||||
&SourceSectionSize,
|
||||
ViewUnmap,
|
||||
0,
|
||||
PAGE_READONLY );
|
||||
PAGE_READONLY);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtMapViewOfSection failed: %x, %S\n", Status, SourceFileName);
|
||||
goto closesrcsec;
|
||||
}
|
||||
|
||||
RtlInitUnicodeString(&FileName,
|
||||
DestinationFileName);
|
||||
RtlInitUnicodeString(&FileName, DestinationFileName);
|
||||
|
||||
InitializeObjectAttributes(&ObjectAttributes,
|
||||
&FileName,
|
||||
@@ -246,9 +335,9 @@ SetupCopyFile(
|
||||
&ObjectAttributes,
|
||||
&IoStatusBlock,
|
||||
NULL,
|
||||
FILE_ATTRIBUTE_NORMAL,
|
||||
FileBasic.FileAttributes, // FILE_ATTRIBUTE_NORMAL,
|
||||
0,
|
||||
FILE_OVERWRITE_IF,
|
||||
FailIfExists ? FILE_CREATE : FILE_OVERWRITE_IF,
|
||||
FILE_NO_INTERMEDIATE_BUFFERING |
|
||||
FILE_SEQUENTIAL_ONLY |
|
||||
FILE_SYNCHRONOUS_IO_NONALERT,
|
||||
@@ -335,7 +424,8 @@ SetupCopyFile(
|
||||
NULL);
|
||||
if (!NT_SUCCESS(Status))
|
||||
{
|
||||
DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n", Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
|
||||
DPRINT1("NtWriteFile failed: %x:%x, iosb: %p src: %p, size: %x\n",
|
||||
Status, IoStatusBlock.Status, &IoStatusBlock, SourceFileMap, RegionSize);
|
||||
goto closedest;
|
||||
}
|
||||
|
||||
@@ -351,7 +441,7 @@ SetupCopyFile(
|
||||
goto closedest;
|
||||
}
|
||||
|
||||
/* shorten the file back to it's real size after completing the write */
|
||||
/* Shorten the file back to its real size after completing the write */
|
||||
Status = NtSetInformationFile(FileHandleDest,
|
||||
&IoStatusBlock,
|
||||
&FileStandard.EndOfFile,
|
||||
@@ -378,6 +468,124 @@ 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(
|
||||
|
||||
@@ -12,10 +12,37 @@ NTSTATUS
|
||||
SetupCreateDirectory(
|
||||
PWCHAR DirectoryName);
|
||||
|
||||
NTSTATUS
|
||||
SetupDeleteFile(
|
||||
IN PCWSTR FileName,
|
||||
IN BOOLEAN ForceDelete); // ForceDelete can be used to delete read-only files
|
||||
|
||||
NTSTATUS
|
||||
SetupCopyFile(
|
||||
PWCHAR SourceFileName,
|
||||
PWCHAR DestinationFileName);
|
||||
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(
|
||||
|
||||
Reference in New Issue
Block a user