From 7764663386cf526b548103d1d4f8d981246080a6 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Mon, 16 Jan 2017 14:54:10 -0800 Subject: [PATCH] dll: FspFileSystemPreflight --- build/VStudio/winfsp_sys.vcxproj.filters | 4 +- inc/winfsp/winfsp.h | 14 ++++++ src/dll/fs.c | 37 ++++++++++++++ src/dll/fuse/fuse.c | 36 ++------------ tst/winfsp-tests/mount-test.c | 63 ++++++++++++++++++++++++ 5 files changed, 120 insertions(+), 34 deletions(-) diff --git a/build/VStudio/winfsp_sys.vcxproj.filters b/build/VStudio/winfsp_sys.vcxproj.filters index 6f0377e2..bef315d5 100644 --- a/build/VStudio/winfsp_sys.vcxproj.filters +++ b/build/VStudio/winfsp_sys.vcxproj.filters @@ -113,8 +113,8 @@ - + Source - + \ No newline at end of file diff --git a/inc/winfsp/winfsp.h b/inc/winfsp/winfsp.h index 9a57732d..b3c11ba2 100644 --- a/inc/winfsp/winfsp.h +++ b/inc/winfsp/winfsp.h @@ -845,6 +845,20 @@ typedef struct _FSP_FILE_SYSTEM_OPERATION_CONTEXT FSP_FSCTL_TRANSACT_REQ *Request; FSP_FSCTL_TRANSACT_RSP *Response; } FSP_FILE_SYSTEM_OPERATION_CONTEXT; +/** + * Check whether creating a file system object is possible. + * + * @param DevicePath + * The name of the control device for this file system. This must be either + * FSP_FSCTL_DISK_DEVICE_NAME or FSP_FSCTL_NET_DEVICE_NAME. + * @param MountPoint + * The mount point for the new file system. A value of NULL means that the file system should + * use the next available drive letter counting downwards from Z: as its mount point. + * @return + * STATUS_SUCCESS or error code. + */ +FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath, + PWSTR MountPoint); /** * Create a file system object. * diff --git a/src/dll/fs.c b/src/dll/fs.c index 74c66adc..9d6d41f7 100644 --- a/src/dll/fs.c +++ b/src/dll/fs.c @@ -72,6 +72,43 @@ VOID FspFileSystemFinalize(BOOLEAN Dynamic) TlsFree(FspFileSystemTlsKey); } +FSP_API NTSTATUS FspFileSystemPreflight(PWSTR DevicePath, + PWSTR MountPoint) +{ + NTSTATUS Result; + WCHAR TargetPath[MAX_PATH]; + HANDLE DirHandle; + + Result = FspFsctlPreflight(DevicePath); + if (!NT_SUCCESS(Result)) + return Result; + + if (0 == MountPoint) + Result = STATUS_SUCCESS; + else + { + if (FspPathIsDrive(MountPoint)) + Result = QueryDosDeviceW(MountPoint, TargetPath, MAX_PATH) ? + STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS; + else + { + DirHandle = CreateFileW(MountPoint, + 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); + Result = INVALID_HANDLE_VALUE != DirHandle || ERROR_FILE_NOT_FOUND != GetLastError() ? + STATUS_OBJECT_NAME_COLLISION : STATUS_SUCCESS; + if (INVALID_HANDLE_VALUE != DirHandle) + CloseHandle(DirHandle); + } + } + + return Result; +} + FSP_API NTSTATUS FspFileSystemCreate(PWSTR DevicePath, const FSP_FSCTL_VOLUME_PARAMS *VolumeParams, const FSP_FILE_SYSTEM_INTERFACE *Interface, diff --git a/src/dll/fuse/fuse.c b/src/dll/fuse/fuse.c index dfdbaa05..183a3638 100644 --- a/src/dll/fuse/fuse.c +++ b/src/dll/fuse/fuse.c @@ -230,36 +230,6 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env, static void fsp_fuse_cleanup(struct fuse *f); -static NTSTATUS fsp_fuse_preflight(struct fuse *f) -{ - NTSTATUS Result; - - Result = FspFsctlPreflight(f->VolumeParams.Prefix[0] ? - L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME); - if (!NT_SUCCESS(Result)) - return Result; - - if (L'\0' != f->MountPoint) - { - if (( - (L'A' <= f->MountPoint[0] && f->MountPoint[0] <= L'Z') || - (L'a' <= f->MountPoint[0] && f->MountPoint[0] <= L'z') - ) && - L':' == f->MountPoint[1] || L'\0' == f->MountPoint[2]) - { - if (GetLogicalDrives() & (1 << ((f->MountPoint[0] & ~0x20) - 'a'))) - return STATUS_OBJECT_NAME_COLLISION; - } - else - if (L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1]) - ; - else - return STATUS_OBJECT_NAME_INVALID; - } - - return STATUS_SUCCESS; -} - static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) { struct fuse *f = Service->UserContext; @@ -380,7 +350,7 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv) FspFileSystemSetOperationGuardStrategy(f->FileSystem, f->OpGuardStrategy); FspFileSystemSetDebugLog(f->FileSystem, f->DebugLog); - if (L'\0' != f->MountPoint) + if (0 != f->MountPoint) { Result = FspFileSystemSetMountPoint(f->FileSystem, L'*' == f->MountPoint[0] && L'\0' == f->MountPoint[1] ? 0 : f->MountPoint); @@ -548,7 +518,9 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env, goto fail; memcpy(f->MountPoint, ch->MountPoint, Size); - Result = fsp_fuse_preflight(f); + Result = FspFileSystemPreflight( + f->VolumeParams.Prefix[0] ? L"" FSP_FSCTL_NET_DEVICE_NAME : L"" FSP_FSCTL_DISK_DEVICE_NAME, + '*' != f->MountPoint[0] || '\0' != f->MountPoint[1] ? f->MountPoint : 0); if (!NT_SUCCESS(Result)) { switch (Result) diff --git a/tst/winfsp-tests/mount-test.c b/tst/winfsp-tests/mount-test.c index b16915f8..3d42747b 100644 --- a/tst/winfsp-tests/mount-test.c +++ b/tst/winfsp-tests/mount-test.c @@ -272,6 +272,68 @@ void mount_volume_transact_test(void) mount_volume_transact_dotest(L"WinFsp.Net", L"\\\\winfsp-tests\\share"); } +void mount_preflight_dotest(PWSTR DeviceName) +{ + NTSTATUS Result; + WCHAR MountPoint[MAX_PATH]; + WCHAR DirBuf[MAX_PATH]; + DWORD Drives; + WCHAR Drive; + BOOL Success; + + MountPoint[0] = L'C'; + MountPoint[1] = L':'; + MountPoint[2] = L'\0'; + + GetTestDirectory(DirBuf); + + Drives = GetLogicalDrives(); + ASSERT(0 != Drives); + + Result = FspFileSystemPreflight(DeviceName, 0); + ASSERT(STATUS_SUCCESS == Result); + + for (Drive = 'Z'; 'A' <= Drive; Drive--) + if (0 == (Drives & (1 << (Drive - 'A')))) + break; + ASSERT('A' <= Drive); + + MountPoint[0] = Drive; + Result = FspFileSystemPreflight(DeviceName, MountPoint); + ASSERT(STATUS_SUCCESS == Result); + + for (Drive = 'Z'; 'A' <= Drive; Drive--) + if (0 != (Drives & (1 << (Drive - 'A')))) + break; + ASSERT('A' <= Drive); + + MountPoint[0] = Drive; + Result = FspFileSystemPreflight(DeviceName, MountPoint); + ASSERT(STATUS_OBJECT_NAME_COLLISION == Result); + + StringCbPrintfW(MountPoint, sizeof MountPoint, L"%s\\dir1", DirBuf); + + Result = FspFileSystemPreflight(DeviceName, MountPoint); + ASSERT(STATUS_SUCCESS == Result); + + Success = CreateDirectoryW(MountPoint, 0); + ASSERT(Success); + + Result = FspFileSystemPreflight(DeviceName, MountPoint); + ASSERT(STATUS_OBJECT_NAME_COLLISION == Result); + + Success = RemoveDirectoryW(MountPoint); + ASSERT(Success); +} + +void mount_preflight_test(void) +{ + if (WinFspDiskTests) + mount_preflight_dotest(L"WinFsp.Disk"); + if (WinFspNetTests) + mount_preflight_dotest(L"WinFsp.Net"); +} + void mount_tests(void) { if (NtfsTests || OptOplock) @@ -282,4 +344,5 @@ void mount_tests(void) TEST_OPT(mount_create_volume_test); TEST_OPT(mount_volume_cancel_test); TEST_OPT(mount_volume_transact_test); + TEST_OPT(mount_preflight_test); }