diff --git a/src/dll/security.c b/src/dll/security.c index f226c738..8be35119 100644 --- a/src/dll/security.c +++ b/src/dll/security.c @@ -341,26 +341,25 @@ FSP_API NTSTATUS FspAccessCheckEx(FSP_FILE_SYSTEM *FileSystem, if (Request->Req.Create.UserMode) { - if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY)) + if (FILE_ATTRIBUTE_READONLY == (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) && + (DesiredAccess & (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD))) { - if (DesiredAccess & - (FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD)) - { - Result = STATUS_ACCESS_DENIED; - goto exit; - } - if (Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE) - { - Result = STATUS_CANNOT_DELETE; - goto exit; - } + Result = STATUS_ACCESS_DENIED; + goto exit; + } + + if (FILE_ATTRIBUTE_READONLY == (FileAttributes & FILE_ATTRIBUTE_READONLY) && + (Request->Req.Create.CreateOptions & FILE_DELETE_ON_CLOSE)) + { + Result = STATUS_CANNOT_DELETE; + goto exit; } if (0 == SecurityDescriptorSize) *PGrantedAccess = (MAXIMUM_ALLOWED & DesiredAccess) ? FspFileGenericMapping.GenericAll : DesiredAccess; - if (0 != (FileAttributes & FILE_ATTRIBUTE_READONLY) && + if (FILE_ATTRIBUTE_READONLY == (FileAttributes & (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_DIRECTORY)) && 0 != (MAXIMUM_ALLOWED & DesiredAccess)) *PGrantedAccess &= ~(FILE_WRITE_DATA | FILE_APPEND_DATA | FILE_ADD_SUBDIRECTORY | FILE_DELETE_CHILD); diff --git a/tools/run-tests.bat b/tools/run-tests.bat index 8f005861..ed2f08bf 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -725,13 +725,13 @@ exit /b 0 :sample-passthrough-fuse3-x64 call :__run_sample_fuse_test passthrough-fuse3 x64 passthrough-fuse3-x64 winfsp-tests-x64 ^ - "-create_fileattr_test -setfileinfo_test" + "-create_fileattr_test -create_readonlydir_test -setfileinfo_test" if !ERRORLEVEL! neq 0 goto fail exit /b 0 :sample-passthrough-fuse3-x86 call :__run_sample_fuse_test passthrough-fuse3 x86 passthrough-fuse3-x86 winfsp-tests-x86 ^ - "-create_fileattr_test -setfileinfo_test" + "-create_fileattr_test -create_readonlydir_test -setfileinfo_test" if !ERRORLEVEL! neq 0 goto fail exit /b 0 @@ -923,7 +923,7 @@ cd L: >nul 2>nul || (echo Unable to find drive L: >&2 & goto fail) L: "%ProjRoot%\build\VStudio\build\%Configuration%\%3.exe" ^ --external --resilient --case-insensitive-cmp --share-prefix="\%1\%TMP::=$%\%1\test" ^ - -create_fileattr_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ + -create_fileattr_test -create_readonlydir_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ -getfileattr_test -getfileinfo_name_test -setfileinfo_test -delete_access_test -delete_mmap_test -rename_flipflop_test -rename_mmap_test -setsecurity_test -querydir_namelen_test -exec_rename_dir_test ^ -reparse* -stream* if !ERRORLEVEL! neq 0 set RunSampleTestExit=1 diff --git a/tst/winfsp-tests/create-test.c b/tst/winfsp-tests/create-test.c index 5392d176..4c05aa21 100644 --- a/tst/winfsp-tests/create-test.c +++ b/tst/winfsp-tests/create-test.c @@ -352,6 +352,68 @@ static void create_fileattr_test(void) create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share"); } +static void create_readonlydir_dotest(ULONG Flags, PWSTR Prefix) +{ + void *memfs = memfs_start(Flags); + + HANDLE Handle; + BOOLEAN Success; + DWORD FileAttributes; + WCHAR DirPath[MAX_PATH], FilePath[MAX_PATH]; + + StringCbPrintfW(DirPath, sizeof DirPath, L"%s%s\\dir0", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\dir0\\file0", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + Success = CreateDirectoryW(DirPath, 0); + ASSERT(Success); + + Success = SetFileAttributesW(DirPath, FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY); + ASSERT(Success); + + FileAttributes = GetFileAttributesW(DirPath); + ASSERT((FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_READONLY) == FileAttributes); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + Success = DeleteFileW(FilePath); + ASSERT(Success); + + Success = RemoveDirectoryW(DirPath); + ASSERT(!Success); + ASSERT(ERROR_ACCESS_DENIED == GetLastError()); + + Success = SetFileAttributesW(DirPath, FILE_ATTRIBUTE_DIRECTORY); + ASSERT(Success); + + FileAttributes = GetFileAttributesW(DirPath); + ASSERT(FILE_ATTRIBUTE_DIRECTORY == FileAttributes); + + Success = RemoveDirectoryW(DirPath); + ASSERT(Success); + + memfs_stop(memfs); +} + +static void create_readonlydir_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + create_readonlydir_dotest(-1, DirBuf); + } + if (WinFspDiskTests) + create_readonlydir_dotest(MemfsDisk, 0); + if (WinFspNetTests) + create_readonlydir_dotest(MemfsNet, L"\\\\memfs\\share"); +} + void create_related_dotest(ULONG Flags, PWSTR Prefix) { void *memfs = memfs_start(Flags); @@ -1265,6 +1327,7 @@ void create_tests(void) { TEST(create_test); TEST(create_fileattr_test); + TEST(create_readonlydir_test); TEST(create_related_test); TEST(create_allocation_test); TEST(create_sd_test);