From 266e0f4bab8c535514e500f74cc0f1cb8f973c35 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 4 Dec 2017 14:08:44 -0800 Subject: [PATCH] dll: fuse: call chflags from Create and Overwrite tst: winfsp-tests: file attributes test --- src/dll/fuse/fuse_intf.c | 44 ++++++++++--- tools/run-tests.bat | 2 +- tst/winfsp-tests/create-test.c | 117 +++++++++++++++++++++++++++++++++ 3 files changed, 152 insertions(+), 11 deletions(-) diff --git a/src/dll/fuse/fuse_intf.c b/src/dll/fuse/fuse_intf.c index 3fd783b4..3afe4204 100644 --- a/src/dll/fuse/fuse_intf.c +++ b/src/dll/fuse/fuse_intf.c @@ -821,16 +821,24 @@ static NTSTATUS fsp_fuse_intf_Create(FSP_FILE_SYSTEM *FileSystem, Opened = TRUE; - if (Uid != context->uid || Gid != context->gid) - if (0 != f->ops.chown) - { - err = f->ops.chown(contexthdr->PosixPath, Uid, Gid); - if (0 != err) - { - Result = fsp_fuse_ntstatus_from_errno(f->env, err); - goto exit; - } - } + if (0 != FileAttributes && + 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags) + { + err = f->ops.chflags(contexthdr->PosixPath, + fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes | FILE_ATTRIBUTE_ARCHIVE)); + Result = fsp_fuse_ntstatus_from_errno(f->env, err); + if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result) + goto exit; + } + + if ((Uid != context->uid || Gid != context->gid) && + 0 != f->ops.chown) + { + err = f->ops.chown(contexthdr->PosixPath, Uid, Gid); + Result = fsp_fuse_ntstatus_from_errno(f->env, err); + if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result) + goto exit; + } /* * Ignore fuse_file_info::direct_io, fuse_file_info::keep_cache. @@ -1015,6 +1023,22 @@ static NTSTATUS fsp_fuse_intf_Overwrite(FSP_FILE_SYSTEM *FileSystem, if (!NT_SUCCESS(Result)) return Result; + if (0 != FileAttributes && + 0 != (f->conn_want & FSP_FUSE_CAP_STAT_EX) && 0 != f->ops.chflags) + { + /* + * The code below is not strictly correct. File attributes should be + * replaced when ReplaceFileAttributes is TRUE and merged (or'ed) when + * ReplaceFileAttributes is FALSE. I am punting on this detail for now. + */ + + err = f->ops.chflags(filedesc->PosixPath, + fsp_fuse_intf_MapFileAttributesToFlags(FileAttributes | FILE_ATTRIBUTE_ARCHIVE)); + Result = fsp_fuse_ntstatus_from_errno(f->env, err); + if (!NT_SUCCESS(Result) && STATUS_INVALID_DEVICE_REQUEST != Result) + return Result; + } + return fsp_fuse_intf_GetFileInfoEx(FileSystem, filedesc->PosixPath, &fi, &Uid, &Gid, &Mode, FileInfo); } diff --git a/tools/run-tests.bat b/tools/run-tests.bat index d2a82f06..ce94e3af 100755 --- a/tools/run-tests.bat +++ b/tools/run-tests.bat @@ -784,7 +784,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_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_test ^ + -create_fileattr_test -create_allocation_test -create_notraverse_test -create_backup_test -create_restore_test -create_namelen_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 9cbcc555..e3977d9e 100644 --- a/tst/winfsp-tests/create-test.c +++ b/tst/winfsp-tests/create-test.c @@ -232,6 +232,122 @@ void create_test(void) create_dotest(MemfsNet, L"\\\\memfs\\share"); } +static void create_fileattr_dotest(ULONG Flags, PWSTR Prefix) +{ + void *memfs = memfs_start(Flags); + + HANDLE Handle; + BOOLEAN Success; + DWORD FileAttributes; + WCHAR FilePath[MAX_PATH]; + + StringCbPrintfW(FilePath, sizeof FilePath, L"%s%s\\file0", + Prefix ? L"" : L"\\\\?\\GLOBALROOT", Prefix ? Prefix : memfs_volumename(memfs)); + + 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); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes); + Success = DeleteFileW(FilePath); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_READONLY, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + Success = DeleteFileW(FilePath); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_SYSTEM, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + Success = DeleteFileW(FilePath); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_NEW, FILE_ATTRIBUTE_HIDDEN, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + Success = DeleteFileW(FilePath); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT(FILE_ATTRIBUTE_ARCHIVE == FileAttributes); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_READONLY, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_READONLY) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_SYSTEM, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_SYSTEM) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + + Handle = CreateFileW(FilePath, + GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_WRITE, 0, CREATE_ALWAYS, FILE_ATTRIBUTE_HIDDEN, 0); + ASSERT(INVALID_HANDLE_VALUE != Handle); + CloseHandle(Handle); + + FileAttributes = GetFileAttributesW(FilePath); + ASSERT((FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_HIDDEN) == FileAttributes); + Success = SetFileAttributesW(FilePath, FILE_ATTRIBUTE_NORMAL); + ASSERT(Success); + + Success = DeleteFileW(FilePath); + ASSERT(Success); + + memfs_stop(memfs); +} + +static void create_fileattr_test(void) +{ + if (NtfsTests) + { + WCHAR DirBuf[MAX_PATH]; + GetTestDirectory(DirBuf); + create_fileattr_dotest(-1, DirBuf); + } + if (WinFspDiskTests) + create_fileattr_dotest(MemfsDisk, 0); + if (WinFspNetTests) + create_fileattr_dotest(MemfsNet, L"\\\\memfs\\share"); +} + void create_related_dotest(ULONG Flags, PWSTR Prefix) { void *memfs = memfs_start(Flags); @@ -1141,6 +1257,7 @@ void create_pid_test(void) void create_tests(void) { TEST(create_test); + TEST(create_fileattr_test); TEST(create_related_test); TEST(create_allocation_test); TEST(create_sd_test);