Author: hbelusca Date: Sun Jun 11 23:58:43 2017 New Revision: 75008
URL: http://svn.reactos.org/svn/reactos?rev=75008&view=rev Log: [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.
Modified: branches/setup_improvements/base/setup/usetup/filesup.c branches/setup_improvements/base/setup/usetup/filesup.h
Modified: branches/setup_improvements/base/setup/usetup/filesup.c URL: http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/us... ============================================================================== --- branches/setup_improvements/base/setup/usetup/filesup.c [iso-8859-1] (original) +++ branches/setup_improvements/base/setup/usetup/filesup.c [iso-8859-1] Sun Jun 11 23:58:43 2017 @@ -144,26 +144,115 @@ }
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, @@ -195,7 +284,8 @@ }
Status = NtQueryInformationFile(FileHandleSource, - &IoStatusBlock,&FileBasic, + &IoStatusBlock, + &FileBasic, sizeof(FILE_BASIC_INFORMATION), FileBasicInformation); if (!NT_SUCCESS(Status)) @@ -226,15 +316,14 @@ &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, @@ -247,9 +336,9 @@ &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, @@ -275,7 +364,8 @@ 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; }
@@ -291,7 +381,7 @@ 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, @@ -315,6 +405,125 @@ 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; }
Modified: branches/setup_improvements/base/setup/usetup/filesup.h URL: http://svn.reactos.org/svn/reactos/branches/setup_improvements/base/setup/us... ============================================================================== --- branches/setup_improvements/base/setup/usetup/filesup.h [iso-8859-1] (original) +++ branches/setup_improvements/base/setup/usetup/filesup.h [iso-8859-1] Sun Jun 11 23:58:43 2017 @@ -13,9 +13,36 @@ 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(