From f2a0eb544e95808441437a34a078224260321102 Mon Sep 17 00:00:00 2001 From: Bill Zissimopoulos Date: Wed, 22 Jun 2016 11:12:33 -0700 Subject: [PATCH] opt: cygfuse: rename cygfuse.cpp to cygfuse.c and fix fork problem --- opt/cygfuse/Makefile | 4 +- opt/cygfuse/cygfuse.c | 146 ++++++++++++++++++++++++++++++++++++++++ opt/cygfuse/cygfuse.cpp | 122 --------------------------------- 3 files changed, 148 insertions(+), 124 deletions(-) create mode 100644 opt/cygfuse/cygfuse.c delete mode 100644 opt/cygfuse/cygfuse.cpp diff --git a/opt/cygfuse/Makefile b/opt/cygfuse/Makefile index afa3deec..9b3dc213 100644 --- a/opt/cygfuse/Makefile +++ b/opt/cygfuse/Makefile @@ -1,8 +1,8 @@ Version = $(shell sed -n '/^VERSION=/s/VERSION=\(.*\)/\1/p' fuse.cygport) #Debug = -g -cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.cpp fuse.pc.in - g++ $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.cpp +cygfuse-$(Version).dll libfuse-$(Version).dll.a fuse.pc: cygfuse.c fuse.pc.in + gcc $(Debug) -shared -o cygfuse-$(Version).dll -Wl,--out-implib=libfuse-$(Version).dll.a -I../../inc/fuse cygfuse.c [ -n "$(Debug)" ] || strip cygfuse-$(Version).dll sed "s/@Version@/$(Version)/g" fuse.pc.in > fuse.pc diff --git a/opt/cygfuse/cygfuse.c b/opt/cygfuse/cygfuse.c new file mode 100644 index 00000000..b2e38565 --- /dev/null +++ b/opt/cygfuse/cygfuse.c @@ -0,0 +1,146 @@ +/** + * @file cygfuse/cygfuse.c + * + * @copyright 2015-2016 Bill Zissimopoulos + */ +/* + * This file is part of WinFsp. + * + * You can redistribute it and/or modify it under the terms of the + * GNU Affero 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 +#include +#include +#include +#include + +static void *cygfuse_init_winfsp(); +static void *cygfuse_init_fail(); + +static pthread_mutex_t cygfuse_mutex = PTHREAD_MUTEX_INITIALIZER; +static void *cygfuse_handle = 0; + +static inline void cygfuse_init(int force) +{ + pthread_mutex_lock(&cygfuse_mutex); + if (force || 0 == cygfuse_handle) + cygfuse_handle = cygfuse_init_winfsp(); + pthread_mutex_unlock(&cygfuse_mutex); +} + +/* + * Unfortunately Cygwin fork is very fragile and cannot even correctly + * handle dlopen'ed DLL's if they are native (rather than Cygwin ones). + * + * So we have this very nasty hack where we reset the dlopen'ed handle + * immediately after daemonization. This will force cygfuse_init() to + * reload the WinFsp DLL and reset all API pointers in the daemonized + * process. + */ +static inline int cygfuse_daemon(int nochdir, int noclose) +{ + if (-1 == daemon(nochdir, noclose)) + return -1; + + /* force reload of WinFsp DLL to workaround fork() problems */ + cygfuse_init(1); + + return 0; +} +#define daemon cygfuse_daemon + +#define FSP_FUSE_API static +#define FSP_FUSE_API_NAME(api) (* pfn_ ## api) +#define FSP_FUSE_API_CALL(api) (cygfuse_init(0), pfn_ ## api) +#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ } +#include +#include +#include + +#if defined(__LP64__) +#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll" +#else +#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll" +#endif +#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME +#define CYGFUSE_GET_API(h, n) \ + if (0 == (*(void **)&(pfn_ ## n) = dlsym(h, #n)))\ + return cygfuse_init_fail(); + +static void *cygfuse_init_winfsp() +{ + void *h; + + h = dlopen(CYGFUSE_WINFSP_NAME, RTLD_NOW); + if (0 == h) + { + char winpath[260], *psxpath; + int regfd, bytes; + + regfd = open("/proc/registry32/HKEY_LOCAL_MACHINE/Software/WinFsp/InstallDir", O_RDONLY); + if (-1 == regfd) + return cygfuse_init_fail(); + + bytes = read(regfd, winpath, sizeof winpath - sizeof CYGFUSE_WINFSP_PATH); + close(regfd); + if (-1 == bytes || 0 == bytes) + return cygfuse_init_fail(); + + if ('\0' == winpath[bytes - 1]) + bytes--; + memcpy(winpath + bytes, CYGFUSE_WINFSP_PATH, sizeof CYGFUSE_WINFSP_PATH); + + psxpath = (char *)cygwin_create_path(CCP_WIN_A_TO_POSIX | CCP_PROC_CYGDRIVE, winpath); + if (0 == psxpath) + return cygfuse_init_fail(); + + h = dlopen(psxpath, RTLD_NOW); + free(psxpath); + if (0 == h) + return cygfuse_init_fail(); + } + + /* winfsp_fuse.h */ + CYGFUSE_GET_API(h, fsp_fuse_signal_handler); + + /* fuse_common.h */ + CYGFUSE_GET_API(h, fsp_fuse_version); + CYGFUSE_GET_API(h, fsp_fuse_mount); + CYGFUSE_GET_API(h, fsp_fuse_unmount); + CYGFUSE_GET_API(h, fsp_fuse_parse_cmdline); + CYGFUSE_GET_API(h, fsp_fuse_ntstatus_from_errno); + + /* fuse.h */ + CYGFUSE_GET_API(h, fsp_fuse_main_real); + CYGFUSE_GET_API(h, fsp_fuse_is_lib_option); + CYGFUSE_GET_API(h, fsp_fuse_new); + CYGFUSE_GET_API(h, fsp_fuse_destroy); + CYGFUSE_GET_API(h, fsp_fuse_loop); + CYGFUSE_GET_API(h, fsp_fuse_loop_mt); + CYGFUSE_GET_API(h, fsp_fuse_exit); + CYGFUSE_GET_API(h, fsp_fuse_get_context); + + /* fuse_opt.h */ + CYGFUSE_GET_API(h, fsp_fuse_opt_parse); + CYGFUSE_GET_API(h, fsp_fuse_opt_add_arg); + CYGFUSE_GET_API(h, fsp_fuse_opt_insert_arg); + CYGFUSE_GET_API(h, fsp_fuse_opt_free_args); + CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt); + CYGFUSE_GET_API(h, fsp_fuse_opt_add_opt_escaped); + CYGFUSE_GET_API(h, fsp_fuse_opt_match); + + return h; +} + +static void *cygfuse_init_fail() +{ + abort(); + return 0; +} diff --git a/opt/cygfuse/cygfuse.cpp b/opt/cygfuse/cygfuse.cpp deleted file mode 100644 index b42d8785..00000000 --- a/opt/cygfuse/cygfuse.cpp +++ /dev/null @@ -1,122 +0,0 @@ -/** - * @file cygfuse/cygfuse.cpp - * - * @copyright 2015-2016 Bill Zissimopoulos - */ -/* - * This file is part of WinFsp. - * - * You can redistribute it and/or modify it under the terms of the - * GNU Affero 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 -#undef _WIN32 -#undef _WIN64 - -static HANDLE cygfuse_init_winfsp(); -static HANDLE cygfuse_init_fail(int err); -static inline void cygfuse_init() -{ - static HANDLE Handle = cygfuse_init_winfsp(); -} - -#define FSP_FUSE_API static -#define FSP_FUSE_API_NAME(api) (* pfn_ ## api) -#define FSP_FUSE_API_CALL(api) (cygfuse_init(), pfn_ ## api) -#define FSP_FUSE_SYM(proto, ...) __attribute__ ((visibility("default"))) proto { __VA_ARGS__ } -#include -#include -#include - -#if defined(__LP64__) -#define CYGFUSE_WINFSP_NAME "winfsp-x64.dll" -#else -#define CYGFUSE_WINFSP_NAME "winfsp-x86.dll" -#endif -#define CYGFUSE_WINFSP_PATH "bin\\" CYGFUSE_WINFSP_NAME -#define CYGFUSE_API_GET(h, n) \ - if (0 == (*(FARPROC *)&(pfn_ ## n) = GetProcAddress((HMODULE)h, #n)))\ - return cygfuse_init_fail(ERROR_PROC_NOT_FOUND); - -static HANDLE cygfuse_init_fail(int err) -{ - //RaiseException(ERROR_SEVERITY_ERROR | (109/*FACILITY_VISUALCPP*/ << 16) | err, 0, 0, 0); - abort(); - return 0; -} - -static HANDLE cygfuse_init_winfsp() -{ - HANDLE Handle; - - Handle = LoadLibraryW(L"" CYGFUSE_WINFSP_NAME); - if (0 == Handle) - { - HKEY RegKey; - DWORD RegResult, RegType; - WCHAR Path[MAX_PATH]; - DWORD Size; - - Size = sizeof(Path); - if (ERROR_SUCCESS == (RegResult = RegOpenKeyExW(HKEY_LOCAL_MACHINE, - L"Software\\WinFsp", 0, KEY_QUERY_VALUE | KEY_WOW64_32KEY, &RegKey))) - { - RegResult = RegQueryValueExW(RegKey, L"InstallDir", 0, &RegType, (PBYTE)Path, &Size); - RegCloseKey(RegKey); - } - if (ERROR_SUCCESS != RegResult) - return cygfuse_init_fail(ERROR_MOD_NOT_FOUND); - - Size /= sizeof(WCHAR); - if (Size >= MAX_PATH) - Size = MAX_PATH - 1; - Path[Size] = L'\0'; - - Size = lstrlenW(Path); - if (Size * sizeof(WCHAR) + sizeof L"" CYGFUSE_WINFSP_PATH > MAX_PATH * sizeof(WCHAR)) - return cygfuse_init_fail(ERROR_MOD_NOT_FOUND); - - memcpy(Path + Size, L"" CYGFUSE_WINFSP_PATH, sizeof L"" CYGFUSE_WINFSP_PATH); - - Handle = LoadLibraryW(Path); - if (0 == Handle) - return cygfuse_init_fail(ERROR_MOD_NOT_FOUND); - } - - /* winfsp_fuse.h */ - CYGFUSE_API_GET(Handle, fsp_fuse_signal_handler); - - /* fuse_common.h */ - CYGFUSE_API_GET(Handle, fsp_fuse_version); - CYGFUSE_API_GET(Handle, fsp_fuse_mount); - CYGFUSE_API_GET(Handle, fsp_fuse_unmount); - CYGFUSE_API_GET(Handle, fsp_fuse_parse_cmdline); - CYGFUSE_API_GET(Handle, fsp_fuse_ntstatus_from_errno); - - /* fuse.h */ - CYGFUSE_API_GET(Handle, fsp_fuse_main_real); - CYGFUSE_API_GET(Handle, fsp_fuse_is_lib_option); - CYGFUSE_API_GET(Handle, fsp_fuse_new); - CYGFUSE_API_GET(Handle, fsp_fuse_destroy); - CYGFUSE_API_GET(Handle, fsp_fuse_loop); - CYGFUSE_API_GET(Handle, fsp_fuse_loop_mt); - CYGFUSE_API_GET(Handle, fsp_fuse_exit); - CYGFUSE_API_GET(Handle, fsp_fuse_get_context); - - /* fuse_opt.h */ - CYGFUSE_API_GET(Handle, fsp_fuse_opt_parse); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_add_arg); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_insert_arg); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_free_args); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_add_opt); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_add_opt_escaped); - CYGFUSE_API_GET(Handle, fsp_fuse_opt_match); - - return Handle; -}