mirror of
https://github.com/winfsp/winfsp.git
synced 2025-04-22 08:23:05 -05:00
dll: fuse: allow multiple FUSE file systems
Refactoring to allow for multiple FUSE file systems within a single process. Running FUSE file systems as Windows services is still supported.
This commit is contained in:
parent
e5c424dba1
commit
ae8e4e61f7
@ -189,6 +189,7 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\exec-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\flush-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-opt-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\hooks.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\info-test.c" />
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\launch-test.c" />
|
||||
|
@ -91,6 +91,9 @@
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\devctl-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="..\..\..\tst\winfsp-tests\fuse-test.c">
|
||||
<Filter>Source</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="..\..\..\ext\tlib\testsuite.h">
|
||||
|
@ -223,17 +223,29 @@ FSP_FUSE_API int fsp_fuse_is_lib_option(struct fsp_fuse_env *env,
|
||||
return fsp_fuse_opt_match(env, fsp_fuse_core_opts, opt);
|
||||
}
|
||||
|
||||
static void fsp_fuse_cleanup(struct fuse *f);
|
||||
static INIT_ONCE fsp_fuse_svconce = INIT_ONCE_STATIC_INIT;
|
||||
static HANDLE fsp_fuse_svcthread;
|
||||
|
||||
static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
static DWORD WINAPI fsp_fuse_svcmain(PVOID Context)
|
||||
{
|
||||
return FspServiceRun(FspDiagIdent(), 0, 0, 0);
|
||||
}
|
||||
|
||||
static BOOL WINAPI fsp_fuse_svcinit(
|
||||
PINIT_ONCE InitOnce, PVOID Parameter, PVOID *Context)
|
||||
{
|
||||
fsp_fuse_svcthread = CreateThread(0, 0, fsp_fuse_svcmain, 0, 0, 0);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static void fsp_fuse_loop_cleanup(struct fuse *f);
|
||||
|
||||
static NTSTATUS fsp_fuse_loop_start(struct fuse *f)
|
||||
{
|
||||
struct fuse *f = Service->UserContext;
|
||||
struct fuse_context *context;
|
||||
struct fuse_conn_info conn;
|
||||
NTSTATUS Result;
|
||||
|
||||
f->Service = Service;
|
||||
|
||||
context = fsp_fuse_get_context(f->env);
|
||||
if (0 == context)
|
||||
{
|
||||
@ -394,23 +406,19 @@ static NTSTATUS fsp_fuse_svcstart(FSP_SERVICE *Service, ULONG argc, PWSTR *argv)
|
||||
return STATUS_SUCCESS;
|
||||
|
||||
fail:
|
||||
fsp_fuse_cleanup(f);
|
||||
fsp_fuse_loop_cleanup(f);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static NTSTATUS fsp_fuse_svcstop(FSP_SERVICE *Service)
|
||||
static void fsp_fuse_loop_stop(struct fuse *f)
|
||||
{
|
||||
struct fuse *f = Service->UserContext;
|
||||
|
||||
FspFileSystemStopDispatcher(f->FileSystem);
|
||||
|
||||
fsp_fuse_cleanup(f);
|
||||
|
||||
return STATUS_SUCCESS;
|
||||
fsp_fuse_loop_cleanup(f);
|
||||
}
|
||||
|
||||
static void fsp_fuse_cleanup(struct fuse *f)
|
||||
static void fsp_fuse_loop_cleanup(struct fuse *f)
|
||||
{
|
||||
if (0 != f->FileSystem)
|
||||
{
|
||||
@ -424,8 +432,40 @@ static void fsp_fuse_cleanup(struct fuse *f)
|
||||
f->ops.destroy(f->data);
|
||||
f->fsinit = FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
f->Service = 0;
|
||||
FSP_FUSE_API NTSTATUS fsp_fuse_loop_internal(struct fuse *f)
|
||||
{
|
||||
HANDLE WaitObjects[2];
|
||||
DWORD WaitResult;
|
||||
NTSTATUS Result;
|
||||
|
||||
Result = fsp_fuse_loop_start(f);
|
||||
if (!NT_SUCCESS(Result))
|
||||
{
|
||||
/* emulate WinFsp-FUSE v1.3 behavior! */
|
||||
FspServiceLog(EVENTLOG_ERROR_TYPE,
|
||||
L"The service %s has failed to start (Status=%lx).", FspDiagIdent(), Result);
|
||||
return Result;
|
||||
}
|
||||
|
||||
InitOnceExecuteOnce(&fsp_fuse_svconce, fsp_fuse_svcinit, 0, 0);
|
||||
if (0 == fsp_fuse_svcthread)
|
||||
{
|
||||
fsp_fuse_loop_stop(f);
|
||||
return STATUS_INSUFFICIENT_RESOURCES;
|
||||
}
|
||||
|
||||
/* if either the service thread dies or our event gets signaled, stop the loop */
|
||||
WaitObjects[0] = fsp_fuse_svcthread;
|
||||
WaitObjects[1] = f->LoopEvent;
|
||||
WaitResult = WaitForMultipleObjects(2, WaitObjects, FALSE, INFINITE);
|
||||
if (WAIT_OBJECT_0 != WaitResult && WAIT_OBJECT_0 + 1 != WaitResult)
|
||||
Result = FspNtStatusFromWin32(GetLastError());
|
||||
|
||||
fsp_fuse_loop_stop(f);
|
||||
|
||||
return Result;
|
||||
}
|
||||
|
||||
static int fsp_fuse_core_opt_proc(void *opt_data0, const char *arg, int key,
|
||||
@ -638,6 +678,10 @@ FSP_FUSE_API struct fuse *fsp_fuse_new(struct fsp_fuse_env *env,
|
||||
goto fail;
|
||||
memcpy(f->MountPoint, ch->MountPoint, Size);
|
||||
|
||||
f->LoopEvent = CreateEventW(0, TRUE, FALSE, 0);
|
||||
if (0 == f->LoopEvent)
|
||||
goto fail;
|
||||
|
||||
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);
|
||||
@ -685,7 +729,10 @@ fail:
|
||||
FSP_FUSE_API void fsp_fuse_destroy(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
fsp_fuse_cleanup(f);
|
||||
fsp_fuse_loop_cleanup(f);
|
||||
|
||||
if (0 != f->LoopEvent)
|
||||
CloseHandle(f->LoopEvent);
|
||||
|
||||
fsp_fuse_obj_free(f->MountPoint);
|
||||
|
||||
@ -696,23 +743,20 @@ FSP_FUSE_API int fsp_fuse_loop(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_COARSE;
|
||||
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
|
||||
0 : -1;
|
||||
return NT_SUCCESS(fsp_fuse_loop_internal(f)) ? 0 : -1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API int fsp_fuse_loop_mt(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
f->OpGuardStrategy = FSP_FILE_SYSTEM_OPERATION_GUARD_STRATEGY_FINE;
|
||||
return 0 == FspServiceRunEx(FspDiagIdent(), fsp_fuse_svcstart, fsp_fuse_svcstop, 0, f) ?
|
||||
0 : -1;
|
||||
return NT_SUCCESS(fsp_fuse_loop_internal(f)) ? 0 : -1;
|
||||
}
|
||||
|
||||
FSP_FUSE_API void fsp_fuse_exit(struct fsp_fuse_env *env,
|
||||
struct fuse *f)
|
||||
{
|
||||
if (0 != f->Service)
|
||||
FspServiceStop(f->Service);
|
||||
SetEvent(f->LoopEvent);
|
||||
f->exited = 1;
|
||||
}
|
||||
|
||||
|
@ -61,8 +61,8 @@ struct fuse
|
||||
UINT16 VolumeLabelLength;
|
||||
WCHAR VolumeLabel[sizeof ((FSP_FSCTL_VOLUME_INFO *)0)->VolumeLabel / sizeof(WCHAR)];
|
||||
PWSTR MountPoint;
|
||||
HANDLE LoopEvent;
|
||||
FSP_FILE_SYSTEM *FileSystem;
|
||||
FSP_SERVICE *Service; /* weak */
|
||||
volatile int exited;
|
||||
struct fuse3 *fuse3;
|
||||
};
|
||||
|
114
tst/winfsp-tests/fuse-test.c
Normal file
114
tst/winfsp-tests/fuse-test.c
Normal file
@ -0,0 +1,114 @@
|
||||
/**
|
||||
* @file fuse-test.c
|
||||
*
|
||||
* @copyright 2015-2018 Bill Zissimopoulos
|
||||
*/
|
||||
/*
|
||||
* This file is part of WinFsp.
|
||||
*
|
||||
* You can redistribute it and/or modify it under the terms of the GNU
|
||||
* General Public License version 3 as published by the Free Software
|
||||
* Foundation.
|
||||
*
|
||||
* Licensees holding a valid commercial license may use this file in
|
||||
* accordance with the commercial license agreement provided with the
|
||||
* software.
|
||||
*/
|
||||
|
||||
#include <fuse/fuse.h>
|
||||
#include <tlib/testsuite.h>
|
||||
#include <process.h>
|
||||
|
||||
#include "winfsp-tests.h"
|
||||
|
||||
static unsigned __stdcall fuse_tests_thread(void *f)
|
||||
{
|
||||
return fuse_loop_mt(f);
|
||||
}
|
||||
|
||||
static void fuse_sequential_test(void)
|
||||
{
|
||||
static struct fuse_operations ops;
|
||||
char *argv[] = { "UNKNOWN" };
|
||||
struct fuse_args args = FUSE_ARGS_INIT(1, argv);
|
||||
struct fuse_chan *ch[10] = { 0 };
|
||||
struct fuse *f[10];
|
||||
HANDLE Thread[10];
|
||||
DWORD ExitCode;
|
||||
|
||||
for (int i = 0; sizeof(f) / sizeof(f[0]) > i; i++)
|
||||
{
|
||||
ch[i] = fuse_mount("*", &args);
|
||||
ASSERT(0 != ch[i]);
|
||||
|
||||
f[i] = fuse_new(ch[i], &args, &ops, sizeof ops, 0);
|
||||
ASSERT(0 != f[i]);
|
||||
|
||||
Thread[i] = (HANDLE)_beginthreadex(0, 0, fuse_tests_thread, f[i], 0, 0);
|
||||
ASSERT(0 != Thread[i]);
|
||||
|
||||
if (0 != i)
|
||||
Sleep(i * 20);
|
||||
|
||||
fuse_exit(f[i]);
|
||||
|
||||
WaitForSingleObject(Thread[i], INFINITE);
|
||||
GetExitCodeThread(Thread[i], &ExitCode);
|
||||
CloseHandle(Thread[i]);
|
||||
|
||||
fuse_destroy(f[i]);
|
||||
|
||||
fuse_unmount("*", ch[i]);
|
||||
|
||||
ASSERT(0 == ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
static void fuse_parallel_test(void)
|
||||
{
|
||||
static struct fuse_operations ops;
|
||||
char *argv[] = { "UNKNOWN" };
|
||||
struct fuse_args args = FUSE_ARGS_INIT(1, argv);
|
||||
struct fuse_chan *ch[10] = { 0 };
|
||||
struct fuse *f[10];
|
||||
HANDLE Thread[10];
|
||||
DWORD ExitCode;
|
||||
|
||||
for (int i = 0; sizeof(f) / sizeof(f[0]) > i; i++)
|
||||
{
|
||||
ch[i] = fuse_mount("*", &args);
|
||||
ASSERT(0 != ch[i]);
|
||||
|
||||
f[i] = fuse_new(ch[i], &args, &ops, sizeof ops, 0);
|
||||
ASSERT(0 != f[i]);
|
||||
|
||||
Thread[i] = (HANDLE)_beginthreadex(0, 0, fuse_tests_thread, f[i], 0, 0);
|
||||
ASSERT(0 != Thread[i]);
|
||||
}
|
||||
|
||||
Sleep(1000);
|
||||
|
||||
for (int i = 0; sizeof(f) / sizeof(f[0]) > i; i++)
|
||||
{
|
||||
fuse_exit(f[i]);
|
||||
|
||||
WaitForSingleObject(Thread[i], INFINITE);
|
||||
GetExitCodeThread(Thread[i], &ExitCode);
|
||||
CloseHandle(Thread[i]);
|
||||
|
||||
fuse_destroy(f[i]);
|
||||
|
||||
fuse_unmount("*", ch[i]);
|
||||
|
||||
ASSERT(0 == ExitCode);
|
||||
}
|
||||
}
|
||||
|
||||
void fuse_tests(void)
|
||||
{
|
||||
if (OptExternal)
|
||||
return;
|
||||
|
||||
TEST_OPT(fuse_sequential_test);
|
||||
TEST_OPT(fuse_parallel_test);
|
||||
}
|
@ -182,6 +182,7 @@ LONG WINAPI UnhandledExceptionHandler(struct _EXCEPTION_POINTERS *ExceptionInfo)
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
TESTSUITE(fuse_opt_tests);
|
||||
TESTSUITE(fuse_tests);
|
||||
TESTSUITE(posix_tests);
|
||||
TESTSUITE(eventlog_tests);
|
||||
TESTSUITE(path_tests);
|
||||
|
Loading…
x
Reference in New Issue
Block a user