diff --git a/base/setup/lib/filesup.c b/base/setup/lib/filesup.c index c6314c222e2..03d1ad80031 100644 --- a/base/setup/lib/filesup.c +++ b/base/setup/lib/filesup.c @@ -12,8 +12,465 @@ #define NDEBUG #include + +// 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, diff --git a/base/setup/lib/filesup.h b/base/setup/lib/filesup.h index abc1b1c58de..0b820691857 100644 --- a/base/setup/lib/filesup.h +++ b/base/setup/lib/filesup.h @@ -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, diff --git a/base/setup/lib/regutil.c b/base/setup/lib/regutil.c index eebbac0febe..2ede2241649 100644 --- a/base/setup/lib/regutil.c +++ b/base/setup/lib/regutil.c @@ -19,27 +19,6 @@ #define NDEBUG #include - -// 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 ****************************************************************/ /* diff --git a/base/setup/usetup/filesup.c b/base/setup/usetup/filesup.c index 06d9d86344c..261bfd9fa85 100644 --- a/base/setup/usetup/filesup.c +++ b/base/setup/usetup/filesup.c @@ -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) diff --git a/base/setup/usetup/filesup.h b/base/setup/usetup/filesup.h index a8cc7940a7d..884d384efae 100644 --- a/base/setup/usetup/filesup.h +++ b/base/setup/usetup/filesup.h @@ -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);