https://git.reactos.org/?p=reactos.git;a=commitdiff;h=55d8a8490c5cb795fa1308c291485d31f8b53608

commit 55d8a8490c5cb795fa1308c291485d31f8b53608
Author:     Hermès Bélusca-Maïto <[email protected]>
AuthorDate: Sun Jun 11 23:58:43 2017 +0000
Commit:     Hermès Bélusca-Maïto <[email protected]>
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(

Reply via email to