From d72fe2ee331e003551ea7ed70e0ca689118744d6 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Fri, 19 Nov 2021 17:16:36 +0000 Subject: [PATCH] sys: FspFsvolSetDispositionInformation: ignore FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK flag --- src/sys/fileinfo.c | 26 ++++++++++++++++++-------- tst/winfsp-tests/exec-test.c | 21 +++++++++++++++++++++ tst/winfsp-tests/winfsp-tests.h | 4 ++++ 3 files changed, 43 insertions(+), 8 deletions(-) diff --git a/src/sys/fileinfo.c b/src/sys/fileinfo.c index 3072cd17..34512f9d 100644 --- a/src/sys/fileinfo.c +++ b/src/sys/fileinfo.c @@ -1513,15 +1513,25 @@ retry: if (!NT_SUCCESS(Result)) goto unlock_exit; - if (FlagOn(DispositionFlags, FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK)) + /* + * Make sure no process is mapping the file as an image. + * + * NOTE: + * Turns out that NTFS always does this test, even when + * FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK has been specified. + * If MmFlushImageSection fails (e.g. an actively running EXE) then + * it only allows the deletion to go through when a secondary hard + * link is being deleted. + * + * Since WinFsp does not support hard links, we will go ahead and + * ignore the FILE_DISPOSITION_FORCE_IMAGE_SECTION_CHECK flag and + * always respect the result of MmFlushImageSection. + */ + Success = MmFlushImageSection(FileObject->SectionObjectPointer, MmFlushForDelete); + if (!Success) { - /* make sure no process is mapping the file as an image */ - Success = MmFlushImageSection(FileObject->SectionObjectPointer, MmFlushForDelete); - if (!Success) - { - Result = STATUS_CANNOT_DELETE; - goto unlock_exit; - } + Result = STATUS_CANNOT_DELETE; + goto unlock_exit; } if (FlagOn(DispositionFlags, FILE_DISPOSITION_IGNORE_READONLY_ATTRIBUTE)) diff --git a/tst/winfsp-tests/exec-test.c b/tst/winfsp-tests/exec-test.c index c336bae2..b19bd1d1 100644 --- a/tst/winfsp-tests/exec-test.c +++ b/tst/winfsp-tests/exec-test.c @@ -200,6 +200,27 @@ static void exec_delete_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) ASSERT(!DeleteFileW(FilePath)); ASSERT(ERROR_ACCESS_DENIED == GetLastError()); + { + MY_FILE_DISPOSITION_INFO_EX DispositionInfo; + HANDLE Handle; + BOOLEAN Success; + Handle = CreateFileW(FilePath, + DELETE, FILE_SHARE_DELETE, 0, + OPEN_EXISTING, 0, 0); + if (INVALID_HANDLE_VALUE != Handle) + { + DispositionInfo.Disposition = FILE_DISPOSITION_DELETE | FILE_DISPOSITION_POSIX_SEMANTICS; + Success = SetFileInformationByHandle(Handle, + 21/*FileDispositionInfoEx*/, &DispositionInfo, sizeof DispositionInfo); + ASSERT(!Success); + ASSERT( + ERROR_INVALID_PARAMETER == GetLastError() || + ERROR_ACCESS_DENIED == GetLastError()); + Success = CloseHandle(Handle); + ASSERT(Success); + } + } + WaitHelper(Process, 1000); ASSERT(DeleteFileW(FilePath)); diff --git a/tst/winfsp-tests/winfsp-tests.h b/tst/winfsp-tests/winfsp-tests.h index 63b603d0..a87fc463 100644 --- a/tst/winfsp-tests/winfsp-tests.h +++ b/tst/winfsp-tests/winfsp-tests.h @@ -154,6 +154,10 @@ typedef struct { BOOLEAN Disposition; } MY_FILE_DISPOSITION_INFO; +typedef struct +{ + UINT32 Disposition; +} MY_FILE_DISPOSITION_INFO_EX; void *memfs_start_ex(ULONG Flags, ULONG FileInfoTimeout); void *memfs_start(ULONG Flags);