diff --git a/tst/winfsp-tests/create-test.c b/tst/winfsp-tests/create-test.c index 6033f6a7..28934afb 100644 --- a/tst/winfsp-tests/create-test.c +++ b/tst/winfsp-tests/create-test.c @@ -1370,9 +1370,10 @@ void create_tests(void) TEST(create_fileattr_test); TEST(create_readonlydir_test); TEST(create_related_test); - TEST(create_allocation_test); + if (!OptFuseExternal) + TEST(create_allocation_test); TEST(create_sd_test); - if (!OptNoTraverseToken && !OptShareName) + if (!OptFuseExternal && !OptNoTraverseToken && !OptShareName) TEST(create_notraverse_test); TEST(create_backup_test); TEST(create_restore_test); diff --git a/tst/winfsp-tests/ea-test.c b/tst/winfsp-tests/ea-test.c index 4c3215d3..cee11c9e 100644 --- a/tst/winfsp-tests/ea-test.c +++ b/tst/winfsp-tests/ea-test.c @@ -170,7 +170,11 @@ static NTSTATUS ea_check_ea_enumerate( if (0 == strcmp(SingleEa->EaName, "BNAMETWO")) { - ASSERT(FILE_NEED_EA == SingleEa->Flags); + if (!OptFuseExternal) + { + /* FUSE has no concept of FILE_NEED_EA */ + ASSERT(FILE_NEED_EA == SingleEa->Flags); + } ASSERT(SingleEa->EaNameLength == (UCHAR)strlen("BNAMETWO")); ASSERT(SingleEa->EaValueLength == (UCHAR)strlen("second")); ASSERT(0 == memcmp(SingleEa->EaName + SingleEa->EaNameLength + 1, "second", SingleEa->EaValueLength)); @@ -720,12 +724,17 @@ static void ea_create_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) ASSERT(STATUS_SUCCESS == Result); CloseHandle(FileHandle); - Result = NtCreateFile(&FileHandle, - FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE, &Obja, &Iosb, - &LargeZero, FILE_ATTRIBUTE_NORMAL, 0, - FILE_OPEN, FILE_NO_EA_KNOWLEDGE, - 0, 0); - ASSERT(STATUS_ACCESS_DENIED == Result); + if (!OptFuseExternal) + { + /* FUSE has no concept of FILE_NEED_EA */ + + Result = NtCreateFile(&FileHandle, + FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE, &Obja, &Iosb, + &LargeZero, FILE_ATTRIBUTE_NORMAL, 0, + FILE_OPEN, FILE_NO_EA_KNOWLEDGE, + 0, 0); + ASSERT(STATUS_ACCESS_DENIED == Result); + } Result = NtCreateFile(&FileHandle, FILE_GENERIC_READ | FILE_GENERIC_WRITE | DELETE, &Obja, &Iosb, diff --git a/tst/winfsp-tests/info-test.c b/tst/winfsp-tests/info-test.c index 11a6f3ba..349774b1 100644 --- a/tst/winfsp-tests/info-test.c +++ b/tst/winfsp-tests/info-test.c @@ -2213,10 +2213,11 @@ void query_winfsp_test(void) void info_tests(void) { - if (!OptShareName) + if (!OptFuseExternal && !OptShareName) TEST(getfileattr_test); TEST(getfileinfo_test); - TEST(getfileinfo_name_test); + if (!OptFuseExternal) + TEST(getfileinfo_name_test); TEST(setfileinfo_test); TEST(delete_test); TEST(delete_access_test); diff --git a/tst/winfsp-tests/reparse-test.c b/tst/winfsp-tests/reparse-test.c index 6ccae1a1..2d90b1af 100644 --- a/tst/winfsp-tests/reparse-test.c +++ b/tst/winfsp-tests/reparse-test.c @@ -192,20 +192,25 @@ static void reparse_nfs_dotest(ULONG Flags, PWSTR Prefix, ULONG FileInfoTimeout) 0, OPEN_EXISTING, FILE_FLAG_OPEN_REPARSE_POINT, 0); ASSERT(INVALID_HANDLE_VALUE != Handle); - ReparseDataBuf.D.ReparseDataLength = 0; + if (!OptFuseExternal) + { + /* FUSE cannot delete reparse points */ - Success = DeviceIoControl(Handle, FSCTL_DELETE_REPARSE_POINT, - &ReparseDataBuf, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuf.D.ReparseDataLength, - 0, 0, - &Bytes, 0); - ASSERT(Success); + ReparseDataBuf.D.ReparseDataLength = 0; - Success = DeviceIoControl(Handle, FSCTL_GET_REPARSE_POINT, - 0, 0, - &ReparseDataBuf, sizeof ReparseDataBuf, - &Bytes, 0); - ASSERT(!Success); - ASSERT(ERROR_NOT_A_REPARSE_POINT == GetLastError()); + Success = DeviceIoControl(Handle, FSCTL_DELETE_REPARSE_POINT, + &ReparseDataBuf, REPARSE_DATA_BUFFER_HEADER_SIZE + ReparseDataBuf.D.ReparseDataLength, + 0, 0, + &Bytes, 0); + ASSERT(Success); + + Success = DeviceIoControl(Handle, FSCTL_GET_REPARSE_POINT, + 0, 0, + &ReparseDataBuf, sizeof ReparseDataBuf, + &Bytes, 0); + ASSERT(!Success); + ASSERT(ERROR_NOT_A_REPARSE_POINT == GetLastError()); + } CloseHandle(Handle); @@ -241,7 +246,7 @@ static void reparse_symlink_dotest0(ULONG Flags, PWSTR Prefix, PUINT8 NameInfoBuf[sizeof(FILE_NAME_INFO) + MAX_PATH]; PFILE_NAME_INFO PNameInfo = (PVOID)NameInfoBuf; - Success = CreateSymbolicLinkW(LinkPath, TargetPath, 0); + Success = BestEffortCreateSymbolicLinkW(LinkPath, TargetPath, 0); if (Success) { Handle = CreateFileW(FilePath, @@ -401,7 +406,7 @@ static BOOL my_symlink_fn(ULONG Flags, PWSTR Prefix, void *memfs, PWSTR LinkName StringCbPrintfW(FilePath, sizeof FilePath, L"%s", FileName); - return CreateSymbolicLinkW(LinkPath, + return BestEffortCreateSymbolicLinkW(LinkPath, -1 == Flags && L'\\' == FileName[0] ? FilePath + 6 : FilePath, SymlinkFlags); } @@ -422,7 +427,57 @@ static BOOL my_namecheck_fn(ULONG Flags, PWSTR Prefix, void *memfs, PWSTR FileNa FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, 0); if (INVALID_HANDLE_VALUE == Handle) - return FALSE; + { + /* + * Prior to Windows 11 it used to be the case that NTFS open with FILE_FLAG_BACKUP_SEMANTICS + * did not care about SYMLINK/SYMLINKD difference! + * + * On Windows 11 this no longer appears to be true. In order to keep this test around, we perform + * an alternative name check in this case. + */ + + if (-1 == Flags && (ERROR_ACCESS_DENIED == GetLastError() || ERROR_DIRECTORY == GetLastError())) + ; /* Windows 11: if NTFS and appropriate error then ignore */ + else + return FALSE; + + Handle = CreateFileW(FilePath, FILE_READ_ATTRIBUTES, + FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, + 0, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT, 0); + if (INVALID_HANDLE_VALUE == Handle) + return FALSE; + + union + { + REPARSE_DATA_BUFFER D; + UINT8 B[MAXIMUM_REPARSE_DATA_BUFFER_SIZE]; + } ReparseDataBuf; + DWORD Bytes; + BOOL Success; + + Success = DeviceIoControl(Handle, FSCTL_GET_REPARSE_POINT, + 0, 0, + &ReparseDataBuf, sizeof ReparseDataBuf, + &Bytes, 0); + if (Success) + { + Success = Success && + ReparseDataBuf.D.ReparseTag == IO_REPARSE_TAG_SYMLINK; + Success = Success && + ReparseDataBuf.D.SymbolicLinkReparseBuffer.SubstituteNameLength == + wcslen(ExpectedPath + 6) * sizeof(WCHAR); + Success = Success && + 0 == mywcscmp( + ExpectedPath + 6, + -1, + ReparseDataBuf.D.SymbolicLinkReparseBuffer.PathBuffer + + ReparseDataBuf.D.SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(WCHAR), + ReparseDataBuf.D.SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(WCHAR)); + } + + CloseHandle(Handle); + return Success; + } if (GetFileInformationByHandleEx(Handle, FileNameInfo, PNameInfo, sizeof NameInfoBuf)) { @@ -500,7 +555,11 @@ static void reparse_symlink_relative_dotest(ULONG Flags, PWSTR Prefix, ULONG Fil my_failcheck(L"\\loop"); ASSERT(ERROR_CANT_RESOLVE_FILENAME == GetLastError()); - /* NTFS open with FILE_FLAG_BACKUP_SEMANTICS does not care about SYMLINK/SYMLINKD difference! */ + /* + * NTFS open with FILE_FLAG_BACKUP_SEMANTICS does not care about SYMLINK/SYMLINKD difference! + * + * UPDATE: Appears to no longer be true on Windows 11! + */ my_namecheck(L"\\lf", L"\\1"); my_namecheck(L"\\ld", L"\\1\\1.1\\1.1.1"); @@ -555,7 +614,8 @@ void reparse_symlink_relative_test(void) void reparse_tests(void) { - TEST(reparse_guid_test); + if (!OptFuseExternal) + TEST(reparse_guid_test); TEST(reparse_nfs_test); TEST(reparse_symlink_test); TEST(reparse_symlink_relative_test); diff --git a/tst/winfsp-tests/security-test.c b/tst/winfsp-tests/security-test.c index 613d6a79..0f880262 100644 --- a/tst/winfsp-tests/security-test.c +++ b/tst/winfsp-tests/security-test.c @@ -333,6 +333,7 @@ void security_stress_meta_test(void) void security_tests(void) { TEST(getsecurity_test); - TEST(setsecurity_test); + if (!OptFuseExternal) + TEST(setsecurity_test); TEST_OPT(security_stress_meta_test); } diff --git a/tst/winfsp-tests/stream-tests.c b/tst/winfsp-tests/stream-tests.c index 85b87cf0..9f8a7d22 100644 --- a/tst/winfsp-tests/stream-tests.c +++ b/tst/winfsp-tests/stream-tests.c @@ -2287,6 +2287,9 @@ void stream_dirnotify_test(void) void stream_tests(void) { + if (OptFuseExternal) + return; + TEST(stream_create_test); if (!OptOplock) TEST(stream_create_overwrite_test); diff --git a/tst/winfsp-tests/winfsp-tests.c b/tst/winfsp-tests/winfsp-tests.c index 9fe244f4..1fb31b1f 100644 --- a/tst/winfsp-tests/winfsp-tests.c +++ b/tst/winfsp-tests/winfsp-tests.c @@ -34,6 +34,7 @@ int WinFspDiskTests = 1; int WinFspNetTests = 1; BOOLEAN OptExternal = FALSE; +BOOLEAN OptFuseExternal = FALSE; BOOLEAN OptResilient = FALSE; BOOLEAN OptCaseInsensitiveCmp = FALSE; BOOLEAN OptCaseInsensitive = FALSE; @@ -270,6 +271,15 @@ int main(int argc, char *argv[]) WinFspNetTests = 0; rmarg(argv, argc, argi); } + else if (0 == strcmp("--fuse-external", a)) + { + OptExternal = TRUE; + OptFuseExternal = TRUE; + NtfsTests = 1; + WinFspDiskTests = 0; + WinFspNetTests = 0; + rmarg(argv, argc, argi); + } else if (0 == strcmp("--resilient", a)) { OptResilient = TRUE; diff --git a/tst/winfsp-tests/winfsp-tests.h b/tst/winfsp-tests/winfsp-tests.h index c3d41b89..02bdcdbb 100644 --- a/tst/winfsp-tests/winfsp-tests.h +++ b/tst/winfsp-tests/winfsp-tests.h @@ -132,6 +132,24 @@ BOOL WINAPI ResilientDeleteFileW( BOOL WINAPI ResilientRemoveDirectoryW( LPCWSTR lpPathName); +static inline +BOOLEAN BestEffortCreateSymbolicLinkW( + PWSTR SymlinkFileName, + PWSTR TargetFileName, + DWORD Flags) +{ + BOOLEAN Success = CreateSymbolicLinkW( + SymlinkFileName, + TargetFileName, + Flags | SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE); + if (!Success && ERROR_INVALID_PARAMETER == GetLastError()) + Success = CreateSymbolicLinkW( + SymlinkFileName, + TargetFileName, + Flags & ~SYMBOLIC_LINK_FLAG_ALLOW_UNPRIVILEGED_CREATE); + return Success; +} + typedef struct { BOOLEAN Disposition; @@ -154,6 +172,7 @@ extern int WinFspDiskTests; extern int WinFspNetTests; extern BOOLEAN OptExternal; +extern BOOLEAN OptFuseExternal; extern BOOLEAN OptResilient; extern BOOLEAN OptCaseInsensitiveCmp; extern BOOLEAN OptCaseInsensitive; diff --git a/tst/winfsp-tests/wsl-test.c b/tst/winfsp-tests/wsl-test.c index b0cf1d8e..04dc0bb1 100644 --- a/tst/winfsp-tests/wsl-test.c +++ b/tst/winfsp-tests/wsl-test.c @@ -184,5 +184,8 @@ static void wsl_stat_test(void) void wsl_tests(void) { + if (OptFuseExternal) + return; + TEST_OPT(wsl_stat_test); }