diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 041fab7a8..0b8630ab2 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -23,27 +23,28 @@ #include #include -#include "giotypes.h" -#include "gioenumtypes.h" -#include "gsocket.h" #include "gdbusauthobserver.h" -#include "gdbusprivate.h" -#include "gdbusmessage.h" #include "gdbusconnection.h" -#include "gdbusproxy.h" +#include "gdbusdaemon.h" #include "gdbuserror.h" #include "gdbusintrospection.h" -#include "gdbusdaemon.h" -#include "giomodule-priv.h" -#include "gtask.h" +#include "gdbusmessage.h" +#include "gdbusprivate.h" +#include "gdbusproxy.h" #include "ginputstream.h" -#include "gmemoryinputstream.h" +#include "gioenumtypes.h" +#include "giomodule-priv.h" #include "giostream.h" +#include "giotypes.h" +#include "glib-private.h" #include "glib/gstdio.h" +#include "gmemoryinputstream.h" +#include "gsocket.h" #include "gsocketaddress.h" -#include "gsocketcontrolmessage.h" #include "gsocketconnection.h" +#include "gsocketcontrolmessage.h" #include "gsocketoutputstream.h" +#include "gtask.h" #ifdef G_OS_UNIX #include "gunixfdmessage.h" @@ -2275,6 +2276,26 @@ g_win32_run_session_bus (void* hwnd, void* hinst, const char* cmdline, int cmdsh static gboolean autolaunch_binary_absent = FALSE; +static wchar_t * +find_dbus_process_path (void) +{ + wchar_t *dbus_path; + gchar *exe_path = GLIB_PRIVATE_CALL (g_win32_find_helper_executable_path) ("gdbus.exe", _g_io_win32_get_module ()); + dbus_path = g_utf8_to_utf16 (exe_path, -1, NULL, NULL, NULL); + g_free (exe_path); + + if (dbus_path == NULL) + return NULL; + + if (GetFileAttributesW (dbus_path) == INVALID_FILE_ATTRIBUTES) + { + g_free (dbus_path); + return NULL; + } + + return dbus_path; +} + gchar * _g_dbus_win32_get_session_address_dbus_launch (GError **error) { @@ -2292,61 +2313,53 @@ _g_dbus_win32_get_session_address_dbus_launch (GError **error) if (address == NULL && !autolaunch_binary_absent) { - wchar_t gio_path[MAX_PATH + 2] = { 0 }; - int gio_path_len = GetModuleFileNameW (_g_io_win32_get_module (), gio_path, MAX_PATH + 1); + wchar_t *dbus_path = find_dbus_process_path (); + if (dbus_path == NULL) + { + /* warning won't be raised another time + * since autolaunch_binary_absent would be already set. + */ + autolaunch_binary_absent = TRUE; + g_warning ("win32 session dbus binary not found"); + } + else + { + PROCESS_INFORMATION pi = { 0 }; + STARTUPINFOW si = { 0 }; + BOOL res = FALSE; + wchar_t args[MAX_PATH * 2 + 100] = { 0 }; + wchar_t working_dir[MAX_PATH + 2] = { 0 }; + wchar_t *p; - /* The <= MAX_PATH check prevents truncated path usage */ - if (gio_path_len > 0 && gio_path_len <= MAX_PATH) - { - PROCESS_INFORMATION pi = { 0 }; - STARTUPINFOW si = { 0 }; - BOOL res = FALSE; - wchar_t exe_path[MAX_PATH + 100] = { 0 }; - /* calculate index of first char of dll file name inside full path */ - int gio_name_index = gio_path_len; - for (; gio_name_index > 0; --gio_name_index) - { - wchar_t prev_char = gio_path[gio_name_index - 1]; - if (prev_char == L'\\' || prev_char == L'/') - break; - } - gio_path[gio_name_index] = L'\0'; - wcscpy (exe_path, gio_path); - wcscat (exe_path, L"\\gdbus.exe"); + wcscpy (working_dir, dbus_path); + p = wcsrchr (working_dir, L'\\'); + if (p != NULL) + *p = L'\0'; - if (GetFileAttributesW (exe_path) == INVALID_FILE_ATTRIBUTES) - { - /* warning won't be raised another time - * since autolaunch_binary_absent would be already set. - */ - autolaunch_binary_absent = TRUE; - g_warning ("win32 session dbus binary not found: %S", exe_path ); - } - else - { - wchar_t args[MAX_PATH*2 + 100] = { 0 }; - wcscpy (args, L"\""); - wcscat (args, exe_path); - wcscat (args, L"\" "); + wcscpy (args, L"\""); + wcscat (args, dbus_path); + wcscat (args, L"\" "); #define _L_PREFIX_FOR_EXPANDED(arg) L##arg #define _L_PREFIX(arg) _L_PREFIX_FOR_EXPANDED (arg) - wcscat (args, _L_PREFIX (_GDBUS_ARG_WIN32_RUN_SESSION_BUS)); + wcscat (args, _L_PREFIX (_GDBUS_ARG_WIN32_RUN_SESSION_BUS)); #undef _L_PREFIX #undef _L_PREFIX_FOR_EXPANDED - res = CreateProcessW (exe_path, args, - 0, 0, FALSE, - NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS, - 0, gio_path, - &si, &pi); - } - if (res) - { - address = read_shm (DBUS_DAEMON_ADDRESS_INFO); - if (address == NULL) - g_warning ("%S dbus binary failed to launch bus, maybe incompatible version", exe_path ); - } - } + res = CreateProcessW (dbus_path, args, + 0, 0, FALSE, + NORMAL_PRIORITY_CLASS | CREATE_NO_WINDOW | DETACHED_PROCESS, + 0, working_dir, + &si, &pi); + + if (res) + { + address = read_shm (DBUS_DAEMON_ADDRESS_INFO); + if (address == NULL) + g_warning ("%S dbus binary failed to launch bus, maybe incompatible version", dbus_path); + } + + g_free (dbus_path); + } } release_mutex (autolaunch_mutex); diff --git a/glib/glib-init.h b/glib/glib-init.h index 4c812d9d6..b77164c73 100644 --- a/glib/glib-init.h +++ b/glib/glib-init.h @@ -40,7 +40,9 @@ void g_clock_win32_init (void); void g_crash_handler_win32_init (void); void g_crash_handler_win32_deinit (void); gboolean _g_win32_call_rtl_version (OSVERSIONINFOEXW *info); + extern HMODULE glib_dll; +gchar *g_win32_find_helper_executable_path (const gchar *process_name, void *dll_handle); #endif #endif /* __GLIB_INIT_H__ */ diff --git a/glib/glib-private.c b/glib/glib-private.c index 1c0da1947..0a59c6f16 100644 --- a/glib/glib-private.c +++ b/glib/glib-private.c @@ -54,6 +54,7 @@ glib__private__ (void) g_win32_lstat_utf8, g_win32_readlink_utf8, g_win32_fstat, + g_win32_find_helper_executable_path, #endif }; diff --git a/glib/glib-private.h b/glib/glib-private.h index 85987e272..943252f1b 100644 --- a/glib/glib-private.h +++ b/glib/glib-private.h @@ -120,7 +120,6 @@ gboolean g_check_setuid (void); GMainContext * g_main_context_new_with_next_id (guint next_id); #ifdef G_OS_WIN32 -gchar *_glib_get_dll_directory (void); GLIB_AVAILABLE_IN_ALL gchar *_glib_get_locale_dir (void); #endif @@ -168,6 +167,10 @@ typedef struct { int (* g_win32_fstat) (int fd, GWin32PrivateStat *buf); + + /* See gwin32.c */ + gchar *(*g_win32_find_helper_executable_path) (const gchar *process_name, + void *dll_handle); #endif diff --git a/glib/gspawn-win32.c b/glib/gspawn-win32.c index 182928cb4..b43778156 100644 --- a/glib/gspawn-win32.c +++ b/glib/gspawn-win32.c @@ -42,10 +42,11 @@ #include "config.h" -#include "glib.h" +#include "glib-init.h" #include "glib-private.h" -#include "gprintfint.h" +#include "glib.h" #include "glibintl.h" +#include "gprintfint.h" #include "gspawn-private.h" #include "gthread.h" @@ -586,7 +587,6 @@ fork_exec (gint *exit_status, gint conv_error_index; gchar *helper_process; wchar_t *whelper, **wargv, **wenvp; - gchar *glib_dll_directory; int stdin_pipe[2] = { -1, -1 }; int stdout_pipe[2] = { -1, -1 }; int stderr_pipe[2] = { -1, -1 }; @@ -651,16 +651,8 @@ fork_exec (gint *exit_status, helper_process = HELPER_PROCESS "-console.exe"; else helper_process = HELPER_PROCESS ".exe"; - - glib_dll_directory = _glib_get_dll_directory (); - if (glib_dll_directory != NULL) - { - helper_process = g_build_filename (glib_dll_directory, helper_process, NULL); - g_free (glib_dll_directory); - } - else - helper_process = g_strdup (helper_process); + helper_process = g_win32_find_helper_executable_path (helper_process, glib_dll); new_argv[0] = protect_argv_string (helper_process); _g_sprintf (args[ARG_CHILD_ERR_REPORT], "%d", child_err_report_pipe[1]); diff --git a/glib/gutils.c b/glib/gutils.c index 6cc450607..c6aec9e6f 100644 --- a/glib/gutils.c +++ b/glib/gutils.c @@ -104,47 +104,6 @@ #include #endif -#ifdef G_PLATFORM_WIN32 - -gchar * -_glib_get_dll_directory (void) -{ - gchar *retval; - gchar *p; - wchar_t wc_fn[MAX_PATH]; - -#ifdef DLL_EXPORT - if (glib_dll == NULL) - return NULL; -#endif - - /* This code is different from that in - * g_win32_get_package_installation_directory_of_module() in that - * here we return the actual folder where the GLib DLL is. We don't - * do the check for it being in a "bin" or "lib" subfolder and then - * returning the parent of that. - * - * In a statically built GLib, glib_dll will be NULL and we will - * thus look up the application's .exe file's location. - */ - if (!GetModuleFileNameW (glib_dll, wc_fn, MAX_PATH)) - return NULL; - - retval = g_utf16_to_utf8 (wc_fn, -1, NULL, NULL, NULL); - - p = strrchr (retval, G_DIR_SEPARATOR); - if (p == NULL) - { - /* Wtf? */ - return NULL; - } - *p = '\0'; - - return retval; -} - -#endif - /** * g_memmove: * @dest: the destination address to copy the bytes to. diff --git a/glib/gwin32.c b/glib/gwin32.c index e2f73e135..b2b5ff69d 100644 --- a/glib/gwin32.c +++ b/glib/gwin32.c @@ -1336,4 +1336,123 @@ g_crash_handler_win32_deinit (void) WinVEH_handle = NULL; } +/** + * g_win32_find_helper_executable_path: + * @executable_name: (transfer none): name of the helper executable to find + * (something like gspawn-win64-helper.exe or gdbus.exe for example). + * @dll_handle: handle of the DLL to use as searching base path. Pass NULL + * to take current process executable as searching base path. + * + * Find an external executable path and name starting in the same folder + * as a specified DLL or current process executable path. Helper executables + * (like gspawn-win64-helper.exe, gspawn-win64-helper-console.exe or + * gdbus.exe for example) are generally installed in the same folder as the + * corresponding DLL file. + * + * So, if package has been correctly installed, with a dynamic build of GLib, + * the helper executable should be in the same directory as the corresponding + * DLL file and searching should be straightforward. + * + * But if built statically, DLL handle is not available and we have to start + * searching from the directory holding current executable. It may be very + * different from the directory containing the helper program. In order to + * find the right helper program automatically in all common situations, we + * use this pattern: + * + * current directory + * |-- ??? + * |-- bin + * | |-- ??? + * |-- lib + * | |-- ??? + * |-- glib + * | |-- ??? + * |-- gio + * |-- ??? + * + * starting at base searching path (DLL or current executable directory) and + * getting up until the root path. If we cannot still find the helper program, + * we'll rely on PATH as the last resort. + * + * Returns: (transfer full) (type filename) (nullable): the helper executable + * path and name in the GLib filename encoding or NULL in case of error. It + * should be deallocated with g_free(). + */ +gchar * +g_win32_find_helper_executable_path (const gchar *executable_name, void *dll_handle) +{ + static const gchar *const subdirs[] = { "", "bin", "lib", "glib", "gio" }; + static const gsize nb_subdirs = G_N_ELEMENTS (subdirs); + + DWORD module_path_len; + wchar_t module_path[MAX_PATH + 2] = { 0 }; + gchar *base_searching_path; + gchar *p; + gchar *executable_path; + gsize i; + + g_return_val_if_fail (executable_name && *executable_name, NULL); + + module_path_len = GetModuleFileNameW (dll_handle, module_path, MAX_PATH + 1); + /* The > MAX_PATH check prevents truncated module path usage */ + if (module_path_len == 0 || module_path_len > MAX_PATH) + return NULL; + + base_searching_path = g_utf16_to_utf8 (module_path, -1, NULL, NULL, NULL); + if (base_searching_path == NULL) + return NULL; + + p = strrchr (base_searching_path, G_DIR_SEPARATOR); + if (p == NULL) + { + g_free (base_searching_path); + return NULL; + } + *p = '\0'; + + for (;;) + { + /* Search in subdirectories */ + for (i = 0; i < nb_subdirs; ++i) + { + /* As this function is exclusively used on Windows, the + * executable_path is always an absolute path. At worse, when + * reaching the root of the filesystem, base_searching_path may + * equal something like "[Drive letter]:" but never "/" like on + * Linux or Mac. + * For the peace of mind we still assert this, just in case that + * one day someone tries to use this function on Linux or Mac. + */ + executable_path = g_build_filename (base_searching_path, subdirs[i], executable_name, NULL); + g_assert (g_path_is_absolute (executable_path)); + if (g_file_test (executable_path, G_FILE_TEST_IS_REGULAR)) + break; + + g_free (executable_path); + executable_path = NULL; + } + + if (executable_path != NULL) + break; + + /* Let's get one directory level up */ + p = strrchr (base_searching_path, G_DIR_SEPARATOR); + if (p == NULL) + break; + + *p = '\0'; + } + g_free (base_searching_path); + + if (executable_path == NULL) + { + /* Search in system PATH */ + executable_path = g_find_program_in_path (executable_name); + if (executable_path == NULL) + executable_path = g_strdup (executable_name); + } + + return executable_path; +} + #endif diff --git a/glib/tests/completion.c b/glib/tests/completion.c index 223b3df52..4f790373b 100644 --- a/glib/tests/completion.c +++ b/glib/tests/completion.c @@ -34,6 +34,11 @@ static void test_completion (void) { + static const char *const a1 = "a\302\243"; + static const char *const a2 = "a\302\244"; + static const char *const bb = "bb"; + static const char *const bc = "bc"; + GCompletion *cmp; GList *items; gchar *prefix; @@ -42,10 +47,10 @@ test_completion (void) g_completion_set_compare (cmp, strncmp); items = NULL; - items = g_list_append (items, "a\302\243"); - items = g_list_append (items, "a\302\244"); - items = g_list_append (items, "bb"); - items = g_list_append (items, "bc"); + items = g_list_append (items, (gpointer) a1); + items = g_list_append (items, (gpointer) a2); + items = g_list_append (items, (gpointer) bb); + items = g_list_append (items, (gpointer) bc); g_completion_add_items (cmp, items); g_list_free (items); @@ -75,7 +80,7 @@ test_completion (void) items = g_completion_complete_utf8 (cmp, "a", NULL); g_assert_cmpint (g_list_length (items), ==, 2); - items = g_list_append (NULL, "bb"); + items = g_list_append (NULL, (gpointer) bb); g_completion_remove_items (cmp, items); g_list_free (items); diff --git a/subprojects/proxy-libintl.wrap b/subprojects/proxy-libintl.wrap index 3523a5041..0e6c8529c 100644 --- a/subprojects/proxy-libintl.wrap +++ b/subprojects/proxy-libintl.wrap @@ -1,5 +1,5 @@ [wrap-git] directory=proxy-libintl url=https://github.com/frida/proxy-libintl.git -revision=0.2 +revision=c03e1a74b17fa7ec467e110130775409e4828a4c depth=1