https://git.reactos.org/?p=reactos.git;a=commitdiff;h=55d8a8490c5cb795fa130…
commit 55d8a8490c5cb795fa1308c291485d31f8b53608
Author: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
AuthorDate: Sun Jun 11 23:58:43 2017 +0000
Commit: Hermès Bélusca-Maïto <hermes.belusca-maito(a)reactos.org>
CommitDate: Thu Oct 25 00:58:22 2018 +0200
[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
---
base/setup/usetup/bootsup.c | 6 +-
base/setup/usetup/filequeue.c | 2 +-
base/setup/usetup/filesup.c | 240 +++++++++++++++++++++++++++++++++++++++---
base/setup/usetup/filesup.h | 31 +++++-
4 files changed, 257 insertions(+), 22 deletions(-)
diff --git a/base/setup/usetup/bootsup.c b/base/setup/usetup/bootsup.c
index 7fd723c33a..b6d4220dc0 100644
--- a/base/setup/usetup/bootsup.c
+++ b/base/setup/usetup/bootsup.c
@@ -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);
diff --git a/base/setup/usetup/filequeue.c b/base/setup/usetup/filequeue.c
index f672e2b23e..6067fca07e 100644
--- a/base/setup/usetup/filequeue.c
+++ b/base/setup/usetup/filequeue.c
@@ -427,7 +427,7 @@ SetupCommitFileQueueW(
else
{
/* Copy the file */
- Status = SetupCopyFile(FileSrcPath, FileDstPath);
+ Status = SetupCopyFile(FileSrcPath, FileDstPath, FALSE);
}
if (!NT_SUCCESS(Status))
diff --git a/base/setup/usetup/filesup.c b/base/setup/usetup/filesup.c
index e0bd0b110e..06d9d86344 100644
--- a/base/setup/usetup/filesup.c
+++ b/base/setup/usetup/filesup.c
@@ -142,27 +142,116 @@ 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(
- PWCHAR SourceFileName,
- PWCHAR DestinationFileName)
+ 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(
diff --git a/base/setup/usetup/filesup.h b/base/setup/usetup/filesup.h
index 5c2c296ecf..a8cc7940a7 100644
--- a/base/setup/usetup/filesup.h
+++ b/base/setup/usetup/filesup.h
@@ -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(