diff options
author | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 11:06:12 +0900 |
---|---|---|
committer | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 11:06:12 +0900 |
commit | ac2d6c432f28bcb3835093099e344bceaba4363e (patch) | |
tree | d70878e0b00ff277442a1532919c70893d3f8447 /gio | |
parent | d5e8c67d8c0767480fe257260d4aeff277a0f30a (diff) | |
download | glib-ac2d6c432f28bcb3835093099e344bceaba4363e.tar.gz glib-ac2d6c432f28bcb3835093099e344bceaba4363e.tar.bz2 glib-ac2d6c432f28bcb3835093099e344bceaba4363e.zip |
Imported Upstream version 2.62.3upstream/2.62.3
Diffstat (limited to 'gio')
-rw-r--r-- | gio/gcredentials.c | 42 | ||||
-rw-r--r-- | gio/gcredentialsprivate.h | 77 | ||||
-rw-r--r-- | gio/gdbusauth.c | 27 | ||||
-rw-r--r-- | gio/gdbusauthmechanismsha1.c | 26 | ||||
-rw-r--r-- | gio/gdbusserver.c | 45 | ||||
-rw-r--r-- | gio/gdesktopappinfo.c | 165 | ||||
-rw-r--r-- | gio/glocalfilemonitor.c | 63 | ||||
-rw-r--r-- | gio/glocalfilemonitor.h | 1 | ||||
-rw-r--r-- | gio/kqueue/gkqueuefilemonitor.c | 2 | ||||
-rw-r--r-- | gio/tests/gdbus-peer.c | 78 | ||||
-rw-r--r-- | gio/tests/meson.build | 6 |
11 files changed, 370 insertions, 162 deletions
diff --git a/gio/gcredentials.c b/gio/gcredentials.c index 57a39f2a2..ff9b7e0b8 100644 --- a/gio/gcredentials.c +++ b/gio/gcredentials.c @@ -265,6 +265,35 @@ g_credentials_to_string (GCredentials *credentials) /* ---------------------------------------------------------------------------------------------------- */ +#if G_CREDENTIALS_USE_LINUX_UCRED +/* + * Check whether @native contains invalid data. If getsockopt SO_PEERCRED + * is used on a TCP socket, it succeeds but yields a credentials structure + * with pid 0, uid -1 and gid -1. Similarly, if SO_PASSCRED is used on a + * receiving Unix socket when the sending socket did not also enable + * SO_PASSCRED, it can succeed but yield a credentials structure with + * pid 0, uid /proc/sys/kernel/overflowuid and gid + * /proc/sys/kernel/overflowgid. + */ +static gboolean +linux_ucred_check_valid (struct ucred *native, + GError **error) +{ + if (native->pid == 0 + || native->uid == -1 + || native->gid == -1) + { + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_INVALID_DATA, + "GCredentials contains invalid data"); + return FALSE; + } + + return TRUE; +} +#endif + /** * g_credentials_is_same_user: * @credentials: A #GCredentials. @@ -294,7 +323,8 @@ g_credentials_is_same_user (GCredentials *credentials, ret = FALSE; #if G_CREDENTIALS_USE_LINUX_UCRED - if (credentials->native.uid == other_credentials->native.uid) + if (linux_ucred_check_valid (&credentials->native, NULL) + && credentials->native.uid == other_credentials->native.uid) ret = TRUE; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED if (credentials->native.cmcred_euid == other_credentials->native.cmcred_euid) @@ -453,7 +483,10 @@ g_credentials_get_unix_user (GCredentials *credentials, g_return_val_if_fail (error == NULL || *error == NULL, -1); #if G_CREDENTIALS_USE_LINUX_UCRED - ret = credentials->native.uid; + if (linux_ucred_check_valid (&credentials->native, error)) + ret = credentials->native.uid; + else + ret = -1; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED ret = credentials->native.cmcred_euid; #elif G_CREDENTIALS_USE_NETBSD_UNPCBID @@ -499,7 +532,10 @@ g_credentials_get_unix_pid (GCredentials *credentials, g_return_val_if_fail (error == NULL || *error == NULL, -1); #if G_CREDENTIALS_USE_LINUX_UCRED - ret = credentials->native.pid; + if (linux_ucred_check_valid (&credentials->native, error)) + ret = credentials->native.pid; + else + ret = -1; #elif G_CREDENTIALS_USE_FREEBSD_CMSGCRED ret = credentials->native.cmcred_pid; #elif G_CREDENTIALS_USE_NETBSD_UNPCBID diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h index 4d1c420a8..e9ec09b9f 100644 --- a/gio/gcredentialsprivate.h +++ b/gio/gcredentialsprivate.h @@ -22,6 +22,77 @@ #include "gio/gcredentials.h" #include "gio/gnetworking.h" +/* + * G_CREDENTIALS_SUPPORTED: + * + * Defined to 1 if GCredentials works. + */ +#undef G_CREDENTIALS_SUPPORTED + +/* + * G_CREDENTIALS_USE_LINUX_UCRED, etc.: + * + * Defined to 1 if GCredentials uses Linux `struct ucred`, etc. + */ +#undef G_CREDENTIALS_USE_LINUX_UCRED +#undef G_CREDENTIALS_USE_FREEBSD_CMSGCRED +#undef G_CREDENTIALS_USE_NETBSD_UNPCBID +#undef G_CREDENTIALS_USE_OPENBSD_SOCKPEERCRED +#undef G_CREDENTIALS_USE_SOLARIS_UCRED + +/* + * G_CREDENTIALS_NATIVE_TYPE: + * + * Defined to one of G_CREDENTIALS_TYPE_LINUX_UCRED, etc. + */ +#undef G_CREDENTIALS_NATIVE_TYPE + +/* + * G_CREDENTIALS_NATIVE_SIZE: + * + * Defined to the size of the %G_CREDENTIALS_NATIVE_TYPE + */ +#undef G_CREDENTIALS_NATIVE_SIZE + +/* + * G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED: + * + * Defined to 1 if we have a message-passing API in which credentials + * are attached to a particular message, such as `SCM_CREDENTIALS` on Linux + * or `SCM_CREDS` on FreeBSD. + */ +#undef G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED + +/* + * G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED: + * + * Defined to 1 if we have a `getsockopt()`-style API in which one end of + * a socket connection can directly query the credentials of the process + * that initiated the other end, such as `getsockopt SO_PEERCRED` on Linux + * or `getpeereid()` on multiple operating systems. + */ +#undef G_CREDENTIALS_SOCKET_GET_CREDENTIALS_SUPPORTED + +/* + * G_CREDENTIALS_SPOOFING_SUPPORTED: + * + * Defined to 1 if privileged processes can spoof their credentials when + * using the message-passing API. + */ +#undef G_CREDENTIALS_SPOOFING_SUPPORTED + +/* + * G_CREDENTIALS_PREFER_MESSAGE_PASSING: + * + * Defined to 1 if the data structure transferred by the message-passing + * API is strictly more informative than the one transferred by the + * `getsockopt()`-style API, and hence should be preferred, even for + * protocols like D-Bus that are defined in terms of the credentials of + * the (process that opened the) socket, as opposed to the credentials + * of an individual message. + */ +#undef G_CREDENTIALS_PREFER_MESSAGE_PASSING + #ifdef __linux__ #define G_CREDENTIALS_SUPPORTED 1 #define G_CREDENTIALS_USE_LINUX_UCRED 1 @@ -41,6 +112,12 @@ #define G_CREDENTIALS_NATIVE_SIZE (sizeof (struct cmsgcred)) #define G_CREDENTIALS_UNIX_CREDENTIALS_MESSAGE_SUPPORTED 1 #define G_CREDENTIALS_SPOOFING_SUPPORTED 1 +/* GLib doesn't implement it yet, but FreeBSD's getsockopt()-style API + * is getpeereid(), which is not as informative as struct cmsgcred - + * it does not tell us the PID. As a result, libdbus prefers to use + * SCM_CREDS, and if we implement getpeereid() in future, we should + * do the same. */ +#define G_CREDENTIALS_PREFER_MESSAGE_PASSING 1 #elif defined(__NetBSD__) #define G_CREDENTIALS_SUPPORTED 1 diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c index 752ec23fc..14cc5d70e 100644 --- a/gio/gdbusauth.c +++ b/gio/gdbusauth.c @@ -31,6 +31,7 @@ #include "gdbusutils.h" #include "gioenumtypes.h" #include "gcredentials.h" +#include "gcredentialsprivate.h" #include "gdbusprivate.h" #include "giostream.h" #include "gdatainputstream.h" @@ -969,9 +970,31 @@ _g_dbus_auth_run_server (GDBusAuth *auth, g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF); - /* first read the NUL-byte */ + /* read the NUL-byte, possibly with credentials attached */ #ifdef G_OS_UNIX - if (G_IS_UNIX_CONNECTION (auth->priv->stream)) +#ifndef G_CREDENTIALS_PREFER_MESSAGE_PASSING + if (G_IS_SOCKET_CONNECTION (auth->priv->stream)) + { + GSocket *sock = g_socket_connection_get_socket (G_SOCKET_CONNECTION (auth->priv->stream)); + + local_error = NULL; + credentials = g_socket_get_credentials (sock, &local_error); + + if (credentials == NULL && !g_error_matches (local_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED)) + { + g_propagate_error (error, local_error); + goto out; + } + else + { + /* Clear the error indicator, so we can retry with + * g_unix_connection_receive_credentials() if necessary */ + g_clear_error (&local_error); + } + } +#endif + + if (credentials == NULL && G_IS_UNIX_CONNECTION (auth->priv->stream)) { local_error = NULL; credentials = g_unix_connection_receive_credentials (G_UNIX_CONNECTION (auth->priv->stream), diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c index 553bcdc32..2754d3c2b 100644 --- a/gio/gdbusauthmechanismsha1.c +++ b/gio/gdbusauthmechanismsha1.c @@ -48,6 +48,7 @@ struct _GDBusAuthMechanismSha1Private gboolean is_client; gboolean is_server; GDBusAuthMechanismState state; + gchar *reject_reason; /* non-NULL iff (state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED) */ /* used on the client side */ gchar *to_send; @@ -101,6 +102,7 @@ _g_dbus_auth_mechanism_sha1_finalize (GObject *object) { GDBusAuthMechanismSha1 *mechanism = G_DBUS_AUTH_MECHANISM_SHA1 (object); + g_free (mechanism->priv->reject_reason); g_free (mechanism->priv->to_send); g_free (mechanism->priv->cookie); @@ -290,7 +292,7 @@ ensure_keyring_directory (GError **error) goto out; } - if (g_mkdir (path, 0700) != 0) + if (g_mkdir_with_parents (path, 0700) != 0) { int errsv = errno; g_set_error (error, @@ -963,7 +965,8 @@ mechanism_server_data_receive (GDBusAuthMechanism *mechanism, tokens = g_strsplit (data, " ", 0); if (g_strv_length (tokens) != 2) { - g_warning ("Malformed data '%s'", data); + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; goto out; } @@ -979,6 +982,8 @@ mechanism_server_data_receive (GDBusAuthMechanism *mechanism, } else { + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("SHA-1 mismatch"); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; } @@ -1014,7 +1019,8 @@ mechanism_server_data_send (GDBusAuthMechanism *mechanism, &m->priv->cookie, &error)) { - g_warning ("Error adding entry to keyring: %s", error->message); + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("Error adding entry to keyring: %s", error->message); g_error_free (error); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; goto out; @@ -1042,10 +1048,7 @@ mechanism_server_get_reject_reason (GDBusAuthMechanism *mechanism) g_return_val_if_fail (m->priv->is_server && !m->priv->is_client, NULL); g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_REJECTED, NULL); - /* can never end up here because we are never in the REJECTED state */ - g_assert_not_reached (); - - return NULL; + return g_strdup (m->priv->reject_reason); } static void @@ -1128,7 +1131,8 @@ mechanism_client_data_receive (GDBusAuthMechanism *mechanism, tokens = g_strsplit (data, " ", 0); if (g_strv_length (tokens) != 3) { - g_warning ("Malformed data '%s'", data); + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("Malformed data '%s'", data); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; goto out; } @@ -1137,7 +1141,8 @@ mechanism_client_data_receive (GDBusAuthMechanism *mechanism, cookie_id = g_ascii_strtoll (tokens[1], &endp, 10); if (*endp != '\0') { - g_warning ("Malformed cookie_id '%s'", tokens[1]); + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("Malformed cookie_id '%s'", tokens[1]); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; goto out; } @@ -1147,7 +1152,8 @@ mechanism_client_data_receive (GDBusAuthMechanism *mechanism, cookie = keyring_lookup_entry (cookie_context, cookie_id, &error); if (cookie == NULL) { - g_warning ("Problems looking up entry in keyring: %s", error->message); + g_free (m->priv->reject_reason); + m->priv->reject_reason = g_strdup_printf ("Problems looking up entry in keyring: %s", error->message); g_error_free (error); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; goto out; diff --git a/gio/gdbusserver.c b/gio/gdbusserver.c index 26f8dadd0..4a8dab0ea 100644 --- a/gio/gdbusserver.c +++ b/gio/gdbusserver.c @@ -179,6 +179,8 @@ g_dbus_server_finalize (GObject *object) { GDBusServer *server = G_DBUS_SERVER (object); + g_assert (!server->active); + if (server->authentication_observer != NULL) g_object_unref (server->authentication_observer); @@ -197,19 +199,8 @@ g_dbus_server_finalize (GObject *object) g_free (server->nonce); } - if (server->unix_socket_path) - { - if (g_unlink (server->unix_socket_path) != 0) - g_warning ("Failed to delete %s: %s", server->unix_socket_path, g_strerror (errno)); - g_free (server->unix_socket_path); - } - - if (server->nonce_file) - { - if (g_unlink (server->nonce_file) != 0) - g_warning ("Failed to delete %s: %s", server->nonce_file, g_strerror (errno)); - g_free (server->nonce_file); - } + g_free (server->unix_socket_path); + g_free (server->nonce_file); g_main_context_unref (server->main_context_at_construction); @@ -622,6 +613,12 @@ g_dbus_server_start (GDBusServer *server) return; /* Right now we don't have any transport not using the listener... */ g_assert (server->is_using_listener); + server->run_signal_handler_id = g_signal_connect_data (G_SOCKET_SERVICE (server->listener), + "run", + G_CALLBACK (on_run), + g_object_ref (server), + (GClosureNotify) g_object_unref, + 0 /* flags */); g_socket_service_start (G_SOCKET_SERVICE (server->listener)); server->active = TRUE; g_object_notify (G_OBJECT (server), "active"); @@ -648,6 +645,18 @@ g_dbus_server_stop (GDBusServer *server) g_socket_service_stop (G_SOCKET_SERVICE (server->listener)); server->active = FALSE; g_object_notify (G_OBJECT (server), "active"); + + if (server->unix_socket_path) + { + if (g_unlink (server->unix_socket_path) != 0) + g_warning ("Failed to delete %s: %s", server->unix_socket_path, g_strerror (errno)); + } + + if (server->nonce_file) + { + if (g_unlink (server->nonce_file) != 0) + g_warning ("Failed to delete %s: %s", server->nonce_file, g_strerror (errno)); + } } /* ---------------------------------------------------------------------------------------------------- */ @@ -1159,15 +1168,7 @@ initable_init (GInitable *initable, if (ret) { - if (last_error != NULL) - g_error_free (last_error); - - /* Right now we don't have any transport not using the listener... */ - g_assert (server->is_using_listener); - server->run_signal_handler_id = g_signal_connect (G_SOCKET_SERVICE (server->listener), - "run", - G_CALLBACK (on_run), - server); + g_clear_error (&last_error); } else { diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index a484c63d4..f1e2fdd65 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -143,6 +143,7 @@ G_DEFINE_TYPE_WITH_CODE (GDesktopAppInfo, g_desktop_app_info, G_TYPE_OBJECT, typedef struct { + gatomicrefcount ref_count; gchar *path; gchar *alternatively_watching; gboolean is_config; @@ -154,17 +155,35 @@ typedef struct GHashTable *memory_implementations; } DesktopFileDir; -static DesktopFileDir *desktop_file_dirs; -static guint n_desktop_file_dirs; +static GPtrArray *desktop_file_dirs = NULL; static const gchar *desktop_file_dirs_config_dir = NULL; -static const guint desktop_file_dir_user_config_index = 0; -static guint desktop_file_dir_user_data_index; +static DesktopFileDir *desktop_file_dir_user_config = NULL; /* (owned) */ +static DesktopFileDir *desktop_file_dir_user_data = NULL; /* (owned) */ static GMutex desktop_file_dir_lock; static const gchar *gio_launch_desktop_path = NULL; /* Monitor 'changed' signal handler {{{2 */ static void desktop_file_dir_reset (DesktopFileDir *dir); +static DesktopFileDir * +desktop_file_dir_ref (DesktopFileDir *dir) +{ + g_atomic_ref_count_inc (&dir->ref_count); + + return dir; +} + +static void +desktop_file_dir_unref (DesktopFileDir *dir) +{ + if (g_atomic_ref_count_dec (&dir->ref_count)) + { + desktop_file_dir_reset (dir); + g_free (dir->path); + g_free (dir); + } +} + /*< internal > * desktop_file_dir_get_alternative_dir: * @dir: a #DesktopFileDir @@ -270,11 +289,15 @@ static gboolean desktop_file_dir_app_name_is_masked (DesktopFileDir *dir, const gchar *app_name) { - while (dir > desktop_file_dirs) + guint i; + + for (i = 0; i < desktop_file_dirs->len; i++) { - dir--; + DesktopFileDir *i_dir = g_ptr_array_index (desktop_file_dirs, i); - if (dir->app_names && g_hash_table_contains (dir->app_names, app_name)) + if (dir == i_dir) + return FALSE; + if (i_dir->app_names && g_hash_table_contains (i_dir->app_names, app_name)) return TRUE; } @@ -1251,44 +1274,41 @@ desktop_file_dir_unindexed_get_implementations (DesktopFileDir *dir, /* DesktopFileDir "API" {{{2 */ /*< internal > - * desktop_file_dir_create: - * @array: the #GArray to add a new item to + * desktop_file_dir_new: * @data_dir: an XDG_DATA_DIR * - * Creates a #DesktopFileDir for the corresponding @data_dir, adding it - * to @array. + * Creates a #DesktopFileDir for the corresponding @data_dir. */ -static void -desktop_file_dir_create (GArray *array, - const gchar *data_dir) +static DesktopFileDir * +desktop_file_dir_new (const gchar *data_dir) { - DesktopFileDir dir = { 0, }; + DesktopFileDir *dir = g_new0 (DesktopFileDir, 1); - dir.path = g_build_filename (data_dir, "applications", NULL); + g_atomic_ref_count_init (&dir->ref_count); + dir->path = g_build_filename (data_dir, "applications", NULL); - g_array_append_val (array, dir); + return g_steal_pointer (&dir); } /*< internal > - * desktop_file_dir_create: - * @array: the #GArray to add a new item to + * desktop_file_dir_new_for_config: * @config_dir: an XDG_CONFIG_DIR * - * Just the same as desktop_file_dir_create() except that it does not + * Just the same as desktop_file_dir_new() except that it does not * add the "applications" directory. It also marks the directory as * config-only, which prevents us from attempting to find desktop files * here. */ -static void -desktop_file_dir_create_for_config (GArray *array, - const gchar *config_dir) +static DesktopFileDir * +desktop_file_dir_new_for_config (const gchar *config_dir) { - DesktopFileDir dir = { 0, }; + DesktopFileDir *dir = g_new0 (DesktopFileDir, 1); - dir.path = g_strdup (config_dir); - dir.is_config = TRUE; + g_atomic_ref_count_init (&dir->ref_count); + dir->path = g_strdup (config_dir); + dir->is_config = TRUE; - g_array_append_val (array, dir); + return g_steal_pointer (&dir); } /*< internal > @@ -1309,6 +1329,7 @@ desktop_file_dir_reset (DesktopFileDir *dir) if (dir->monitor) { g_signal_handlers_disconnect_by_func (dir->monitor, desktop_file_dir_changed, dir); + g_file_monitor_cancel (dir->monitor); g_object_unref (dir->monitor); dir->monitor = NULL; } @@ -1340,6 +1361,14 @@ desktop_file_dir_reset (DesktopFileDir *dir) dir->is_setup = FALSE; } +static void +closure_notify_cb (gpointer data, + GClosure *closure) +{ + DesktopFileDir *dir = data; + desktop_file_dir_unref (dir); +} + /*< internal > * desktop_file_dir_init: * @dir: a #DesktopFileDir @@ -1368,7 +1397,9 @@ desktop_file_dir_init (DesktopFileDir *dir) * we will fall back to polling. */ dir->monitor = g_local_file_monitor_new_in_worker (watch_dir, TRUE, G_FILE_MONITOR_NONE, - desktop_file_dir_changed, dir, NULL); + desktop_file_dir_changed, + desktop_file_dir_ref (dir), + closure_notify_cb, NULL); desktop_file_dir_unindexed_init (dir); @@ -1487,55 +1518,51 @@ desktop_file_dirs_lock (void) /* If the XDG dirs configuration has changed (expected only during tests), * clear and reload the state. */ - if (g_strcmp0 (desktop_file_dirs_config_dir, user_config_dir) != 0) + if (desktop_file_dirs_config_dir != NULL && + g_strcmp0 (desktop_file_dirs_config_dir, user_config_dir) != 0) { g_debug ("%s: Resetting desktop app info dirs from %s to %s", G_STRFUNC, desktop_file_dirs_config_dir, user_config_dir); - for (i = 0; i < n_desktop_file_dirs; i++) - desktop_file_dir_reset (&desktop_file_dirs[i]); - g_clear_pointer (&desktop_file_dirs, g_free); - n_desktop_file_dirs = 0; - desktop_file_dir_user_data_index = 0; + g_ptr_array_set_size (desktop_file_dirs, 0); + g_clear_pointer (&desktop_file_dir_user_config, desktop_file_dir_unref); + g_clear_pointer (&desktop_file_dir_user_data, desktop_file_dir_unref); } - if (desktop_file_dirs == NULL) + if (desktop_file_dirs == NULL || desktop_file_dirs->len == 0) { const char * const *dirs; - GArray *tmp; gint i; - tmp = g_array_new (FALSE, FALSE, sizeof (DesktopFileDir)); + if (desktop_file_dirs == NULL) + desktop_file_dirs = g_ptr_array_new_with_free_func ((GDestroyNotify) desktop_file_dir_unref); /* First, the configs. Highest priority: the user's ~/.config */ - desktop_file_dir_create_for_config (tmp, user_config_dir); + desktop_file_dir_user_config = desktop_file_dir_new_for_config (user_config_dir); + g_ptr_array_add (desktop_file_dirs, desktop_file_dir_ref (desktop_file_dir_user_config)); /* Next, the system configs (/etc/xdg, and so on). */ dirs = g_get_system_config_dirs (); for (i = 0; dirs[i]; i++) - desktop_file_dir_create_for_config (tmp, dirs[i]); + g_ptr_array_add (desktop_file_dirs, desktop_file_dir_new_for_config (dirs[i])); /* Now the data. Highest priority: the user's ~/.local/share/applications */ - desktop_file_dir_user_data_index = tmp->len; - desktop_file_dir_create (tmp, g_get_user_data_dir ()); + desktop_file_dir_user_data = desktop_file_dir_new (g_get_user_data_dir ()); + g_ptr_array_add (desktop_file_dirs, desktop_file_dir_ref (desktop_file_dir_user_data)); /* Following that, XDG_DATA_DIRS/applications, in order */ dirs = g_get_system_data_dirs (); for (i = 0; dirs[i]; i++) - desktop_file_dir_create (tmp, dirs[i]); + g_ptr_array_add (desktop_file_dirs, desktop_file_dir_new (dirs[i])); /* The list of directories will never change after this, unless * g_get_user_config_dir() changes due to %G_TEST_OPTION_ISOLATE_DIRS. */ - desktop_file_dirs = (DesktopFileDir *) tmp->data; - n_desktop_file_dirs = tmp->len; desktop_file_dirs_config_dir = user_config_dir; - - g_array_free (tmp, FALSE); } - for (i = 0; i < n_desktop_file_dirs; i++) - if (!desktop_file_dirs[i].is_setup) - desktop_file_dir_init (&desktop_file_dirs[i]); + for (i = 0; i < desktop_file_dirs->len; i++) + if (!((DesktopFileDir *) g_ptr_array_index (desktop_file_dirs, i))->is_setup) + desktop_file_dir_init (g_ptr_array_index (desktop_file_dirs, i)); } static void @@ -1549,8 +1576,8 @@ desktop_file_dirs_invalidate_user_config (void) { g_mutex_lock (&desktop_file_dir_lock); - if (n_desktop_file_dirs) - desktop_file_dir_reset (&desktop_file_dirs[desktop_file_dir_user_config_index]); + if (desktop_file_dir_user_config != NULL) + desktop_file_dir_reset (desktop_file_dir_user_config); g_mutex_unlock (&desktop_file_dir_lock); } @@ -1560,8 +1587,8 @@ desktop_file_dirs_invalidate_user_data (void) { g_mutex_lock (&desktop_file_dir_lock); - if (n_desktop_file_dirs) - desktop_file_dir_reset (&desktop_file_dirs[desktop_file_dir_user_data_index]); + if (desktop_file_dir_user_data != NULL) + desktop_file_dir_reset (desktop_file_dir_user_data); g_mutex_unlock (&desktop_file_dir_lock); } @@ -1950,9 +1977,9 @@ g_desktop_app_info_new (const char *desktop_id) desktop_file_dirs_lock (); - for (i = 0; i < n_desktop_file_dirs; i++) + for (i = 0; i < desktop_file_dirs->len; i++) { - appinfo = desktop_file_dir_get_app (&desktop_file_dirs[i], desktop_id); + appinfo = desktop_file_dir_get_app (g_ptr_array_index (desktop_file_dirs, i), desktop_id); if (appinfo) break; @@ -4109,8 +4136,8 @@ g_desktop_app_info_get_desktop_ids_for_content_type (const gchar *content_type, desktop_file_dirs_lock (); for (i = 0; types[i]; i++) - for (j = 0; j < n_desktop_file_dirs; j++) - desktop_file_dir_mime_lookup (&desktop_file_dirs[j], types[i], hits, blacklist); + for (j = 0; j < desktop_file_dirs->len; j++) + desktop_file_dir_mime_lookup (g_ptr_array_index (desktop_file_dirs, j), types[i], hits, blacklist); /* We will keep the hits past unlocking, so we must dup them */ for (i = 0; i < hits->len; i++) @@ -4312,21 +4339,21 @@ g_app_info_get_default_for_type (const char *content_type, for (i = 0; types[i]; i++) { /* Collect all the default apps for this type */ - for (j = 0; j < n_desktop_file_dirs; j++) - desktop_file_dir_default_lookup (&desktop_file_dirs[j], types[i], results); + for (j = 0; j < desktop_file_dirs->len; j++) + desktop_file_dir_default_lookup (g_ptr_array_index (desktop_file_dirs, j), types[i], results); /* Consider the associations as well... */ - for (j = 0; j < n_desktop_file_dirs; j++) - desktop_file_dir_mime_lookup (&desktop_file_dirs[j], types[i], results, blacklist); + for (j = 0; j < desktop_file_dirs->len; j++) + desktop_file_dir_mime_lookup (g_ptr_array_index (desktop_file_dirs, j), types[i], results, blacklist); /* (If any), see if one of those apps is installed... */ for (j = 0; j < results->len; j++) { const gchar *desktop_id = g_ptr_array_index (results, j); - for (k = 0; k < n_desktop_file_dirs; k++) + for (k = 0; k < desktop_file_dirs->len; k++) { - info = (GAppInfo *) desktop_file_dir_get_app (&desktop_file_dirs[k], desktop_id); + info = (GAppInfo *) desktop_file_dir_get_app (g_ptr_array_index (desktop_file_dirs, k), desktop_id); if (info) { @@ -4405,8 +4432,8 @@ g_desktop_app_info_get_implementations (const gchar *interface) desktop_file_dirs_lock (); - for (i = 0; i < n_desktop_file_dirs; i++) - desktop_file_dir_get_implementations (&desktop_file_dirs[i], &result, interface); + for (i = 0; i < desktop_file_dirs->len; i++) + desktop_file_dir_get_implementations (g_ptr_array_index (desktop_file_dirs, i), &result, interface); desktop_file_dirs_unlock (); @@ -4464,11 +4491,11 @@ g_desktop_app_info_search (const gchar *search_string) reset_total_search_results (); - for (i = 0; i < n_desktop_file_dirs; i++) + for (i = 0; i < desktop_file_dirs->len; i++) { for (j = 0; search_tokens[j]; j++) { - desktop_file_dir_search (&desktop_file_dirs[i], search_tokens[j]); + desktop_file_dir_search (g_ptr_array_index (desktop_file_dirs, i), search_tokens[j]); merge_token_results (j == 0); } merge_directory_results (); @@ -4543,8 +4570,8 @@ g_app_info_get_all (void) desktop_file_dirs_lock (); - for (i = 0; i < n_desktop_file_dirs; i++) - desktop_file_dir_get_all (&desktop_file_dirs[i], apps); + for (i = 0; i < desktop_file_dirs->len; i++) + desktop_file_dir_get_all (g_ptr_array_index (desktop_file_dirs, i), apps); desktop_file_dirs_unlock (); diff --git a/gio/glocalfilemonitor.c b/gio/glocalfilemonitor.c index 897d5f244..3212beff7 100644 --- a/gio/glocalfilemonitor.c +++ b/gio/glocalfilemonitor.c @@ -46,7 +46,7 @@ struct _GFileMonitorSource { GSource source; GMutex lock; - gpointer instance; + GWeakRef instance_ref; GFileMonitorFlags flags; gchar *dirname; gchar *basename; @@ -348,6 +348,7 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, gint64 event_time) { gboolean interesting = TRUE; + GFileMonitor *instance = NULL; g_assert (!child || is_basename (child)); g_assert (!rename_to || is_basename (rename_to)); @@ -359,7 +360,8 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, g_mutex_lock (&fms->lock); /* monitor is already gone -- don't bother */ - if (!fms->instance) + instance = g_weak_ref_get (&fms->instance_ref); + if (instance == NULL) { g_mutex_unlock (&fms->lock); return TRUE; @@ -450,6 +452,7 @@ g_file_monitor_source_handle_event (GFileMonitorSource *fms, g_file_monitor_source_update_ready_time (fms); g_mutex_unlock (&fms->lock); + g_clear_object (&instance); return interesting; } @@ -500,9 +503,11 @@ g_file_monitor_source_dispatch (GSource *source, QueuedEvent *event; GQueue event_queue; gint64 now; + GFileMonitor *instance = NULL; /* make sure the monitor still exists */ - if (!fms->instance) + instance = g_weak_ref_get (&fms->instance_ref); + if (instance == NULL) return FALSE; now = g_source_get_time (source); @@ -550,15 +555,18 @@ g_file_monitor_source_dispatch (GSource *source, g_file_monitor_source_update_ready_time (fms); + g_clear_object (&instance); g_mutex_unlock (&fms->lock); /* We now have our list of events to deliver */ while ((event = g_queue_pop_head (&event_queue))) { /* an event handler could destroy 'instance', so check each time */ - if (fms->instance) - g_file_monitor_emit_event (fms->instance, event->child, event->other, event->event_type); + instance = g_weak_ref_get (&fms->instance_ref); + if (instance != NULL) + g_file_monitor_emit_event (instance, event->child, event->other, event->event_type); + g_clear_object (&instance); queued_event_free (event); } @@ -568,31 +576,28 @@ g_file_monitor_source_dispatch (GSource *source, static void g_file_monitor_source_dispose (GFileMonitorSource *fms) { + GHashTableIter iter; + gpointer seqiter; + QueuedEvent *event; + g_mutex_lock (&fms->lock); - if (fms->instance) + g_hash_table_iter_init (&iter, fms->pending_changes_table); + while (g_hash_table_iter_next (&iter, NULL, &seqiter)) { - GHashTableIter iter; - gpointer seqiter; - QueuedEvent *event; - - g_hash_table_iter_init (&iter, fms->pending_changes_table); - while (g_hash_table_iter_next (&iter, NULL, &seqiter)) - { - g_hash_table_iter_remove (&iter); - g_sequence_remove (seqiter); - } + g_hash_table_iter_remove (&iter); + g_sequence_remove (seqiter); + } - while ((event = g_queue_pop_head (&fms->event_queue))) - queued_event_free (event); + while ((event = g_queue_pop_head (&fms->event_queue))) + queued_event_free (event); - g_assert (g_sequence_is_empty (fms->pending_changes)); - g_assert (g_hash_table_size (fms->pending_changes_table) == 0); - g_assert (fms->event_queue.length == 0); - fms->instance = NULL; + g_assert (g_sequence_is_empty (fms->pending_changes)); + g_assert (g_hash_table_size (fms->pending_changes_table) == 0); + g_assert (fms->event_queue.length == 0); + g_weak_ref_set (&fms->instance_ref, NULL); - g_file_monitor_source_update_ready_time (fms); - } + g_file_monitor_source_update_ready_time (fms); g_mutex_unlock (&fms->lock); @@ -605,7 +610,9 @@ g_file_monitor_source_finalize (GSource *source) GFileMonitorSource *fms = (GFileMonitorSource *) source; /* should already have been cleared in dispose of the monitor */ - g_assert (fms->instance == NULL); + g_assert (g_weak_ref_get (&fms->instance_ref) == NULL); + g_weak_ref_clear (&fms->instance_ref); + g_assert (g_sequence_is_empty (fms->pending_changes)); g_assert (g_hash_table_size (fms->pending_changes_table) == 0); g_assert (fms->event_queue.length == 0); @@ -653,7 +660,7 @@ g_file_monitor_source_new (gpointer instance, g_source_set_name (source, "GFileMonitorSource"); g_mutex_init (&fms->lock); - fms->instance = instance; + g_weak_ref_init (&fms->instance_ref, instance); fms->pending_changes = g_sequence_new (pending_change_free); fms->pending_changes_table = g_hash_table_new (str_hash0, str_equal0); fms->rate_limit = DEFAULT_RATE_LIMIT; @@ -887,6 +894,7 @@ g_local_file_monitor_new_in_worker (const gchar *pathname, GFileMonitorFlags flags, GFileMonitorCallback callback, gpointer user_data, + GClosureNotify destroy_user_data, GError **error) { GLocalFileMonitor *monitor; @@ -899,7 +907,8 @@ g_local_file_monitor_new_in_worker (const gchar *pathname, if (monitor) { if (callback) - g_signal_connect (monitor, "changed", G_CALLBACK (callback), user_data); + g_signal_connect_data (monitor, "changed", G_CALLBACK (callback), + user_data, destroy_user_data, 0 /* flags */); g_local_file_monitor_start (monitor, pathname, is_directory, flags, GLIB_PRIVATE_CALL(g_get_worker_context) ()); } diff --git a/gio/glocalfilemonitor.h b/gio/glocalfilemonitor.h index 7f3baadbd..3d3cf7528 100644 --- a/gio/glocalfilemonitor.h +++ b/gio/glocalfilemonitor.h @@ -87,6 +87,7 @@ g_local_file_monitor_new_in_worker (const gchar *pathname, GFileMonitorFlags flags, GFileMonitorCallback callback, gpointer user_data, + GClosureNotify destroy_user_data, GError **error); /* for implementations of GLocalFileMonitor */ diff --git a/gio/kqueue/gkqueuefilemonitor.c b/gio/kqueue/gkqueuefilemonitor.c index 3055506a9..fd0db4e29 100644 --- a/gio/kqueue/gkqueuefilemonitor.c +++ b/gio/kqueue/gkqueuefilemonitor.c @@ -107,7 +107,7 @@ G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL static inline unsigned int note_all (void) { - unsigned int notes = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME; + unsigned int notes = NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME | NOTE_REVOKE; #ifdef NOTE_TRUNCATE notes |= NOTE_TRUNCATE; #endif diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c index a3260a6e0..d01bc9a7a 100644 --- a/gio/tests/gdbus-peer.c +++ b/gio/tests/gdbus-peer.c @@ -273,26 +273,21 @@ setup_test_address (void) { if (is_unix) { - g_test_message ("Testing with unix:tmpdir address"); - if (g_unix_socket_address_abstract_names_supported ()) - tmp_address = g_strdup ("unix:tmpdir=/tmp/gdbus-test-"); - else - { - tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL); - tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir); - } + g_test_message ("Testing with unix:dir address"); + tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL); + tmp_address = g_strdup_printf ("unix:dir=%s", tmpdir); } else - tmp_address = g_strdup ("nonce-tcp:"); + tmp_address = g_strdup ("nonce-tcp:host=127.0.0.1"); } #ifdef G_OS_UNIX static void -setup_dir_test_address (void) +setup_tmpdir_test_address (void) { - g_test_message ("Testing with unix:dir address"); + g_test_message ("Testing with unix:tmpdir address"); tmpdir = g_dir_make_tmp ("gdbus-test-XXXXXX", NULL); - tmp_address = g_strdup_printf ("unix:dir=%s", tmpdir); + tmp_address = g_strdup_printf ("unix:tmpdir=%s", tmpdir); } static void @@ -313,7 +308,8 @@ teardown_test_address (void) /* Ensuring the rmdir succeeds also ensures any sockets created on the * filesystem are also deleted. */ - g_assert_cmpint (g_rmdir (tmpdir), ==, 0); + g_assert_cmpstr (g_rmdir (tmpdir) == 0 ? "OK" : g_strerror (errno), + ==, "OK"); g_clear_pointer (&tmpdir, g_free); } } @@ -730,7 +726,7 @@ do_test_peer (void) c = g_dbus_connection_new_for_address_sync (is_unix ? "unix:path=/tmp/gdbus-test-does-not-exist-pid" : /* NOTE: Even if something is listening on port 12345 the connection * will fail because the nonce file doesn't exist */ - "nonce-tcp:host=localhost,port=12345,noncefile=this-does-not-exist-gdbus", + "nonce-tcp:host=127.0.0.1,port=12345,noncefile=this-does-not-exist-gdbus", G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT, NULL, /* GDBusAuthObserver */ NULL, /* cancellable */ @@ -1033,6 +1029,9 @@ do_test_peer (void) static void test_peer (void) { + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + /* Run this test multiple times using different address formats to ensure * they all work. */ @@ -1041,7 +1040,7 @@ test_peer (void) teardown_test_address (); #ifdef G_OS_UNIX - setup_dir_test_address (); + setup_tmpdir_test_address (); do_test_peer (); teardown_test_address (); @@ -1049,6 +1048,9 @@ test_peer (void) do_test_peer (); teardown_test_address (); #endif + + g_main_loop_unref (loop); + g_free (test_guid); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1064,6 +1066,9 @@ test_peer_signals (void) g_test_bug ("https://gitlab.gnome.org/GNOME/glib/issues/1620"); + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + setup_test_address (); memset (&data, '\0', sizeof (PeerData)); data.current_connections = g_ptr_array_new_with_free_func (g_object_unref); @@ -1119,6 +1124,9 @@ test_peer_signals (void) g_thread_join (service_thread); teardown_test_address (); + + g_main_loop_unref (loop); + g_free (test_guid); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1246,6 +1254,7 @@ dmp_thread_func (gpointer user_data) data->loop = g_main_loop_new (data->context, FALSE); g_main_loop_run (data->loop); + g_dbus_server_stop (data->server); g_main_context_pop_thread_default (data->context); g_free (guid); @@ -1260,6 +1269,9 @@ delayed_message_processing (void) GThread *service_thread; guint n; + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + setup_test_address (); data = g_new0 (DmpData, 1); @@ -1307,6 +1319,9 @@ delayed_message_processing (void) g_thread_join (service_thread); dmp_data_free (data); teardown_test_address (); + + g_main_loop_unref (loop); + g_free (test_guid); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1360,7 +1375,7 @@ nonce_tcp_service_thread_func (gpointer user_data) error = NULL; observer = g_dbus_auth_observer_new (); - server = g_dbus_server_new_sync ("nonce-tcp:", + server = g_dbus_server_new_sync ("nonce-tcp:host=127.0.0.1", G_DBUS_SERVER_FLAGS_NONE, test_guid, observer, @@ -1405,6 +1420,9 @@ test_nonce_tcp (void) gboolean res; const gchar *address; + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + memset (&data, '\0', sizeof (PeerData)); data.current_connections = g_ptr_array_new_with_free_func (g_object_unref); @@ -1512,6 +1530,9 @@ test_nonce_tcp (void) g_thread_join (service_thread); g_ptr_array_unref (data.current_connections); + + g_main_loop_unref (loop); + g_free (test_guid); } static void @@ -1563,7 +1584,7 @@ tcp_anonymous_service_thread_func (gpointer user_data) g_main_context_push_thread_default (service_context); error = NULL; - server = g_dbus_server_new_sync ("tcp:", + server = g_dbus_server_new_sync ("tcp:host=127.0.0.1", G_DBUS_SERVER_FLAGS_AUTHENTICATION_ALLOW_ANONYMOUS, test_guid, NULL, /* GDBusObserver* */ @@ -1596,6 +1617,9 @@ test_tcp_anonymous (void) GDBusConnection *connection; GError *error; + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + seen_connection = FALSE; service_thread = g_thread_new ("tcp-anon-service", tcp_anonymous_service_thread_func, @@ -1623,6 +1647,9 @@ test_tcp_anonymous (void) server = NULL; g_thread_join (service_thread); + + g_main_loop_unref (loop); + g_free (test_guid); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1767,6 +1794,9 @@ codegen_test_peer (void) GVariant *value; const gchar *s; + test_guid = g_dbus_generate_guid (); + loop = g_main_loop_new (NULL, FALSE); + setup_test_address (); /* bring up a server - we run the server in a different thread to avoid deadlocks */ @@ -1874,6 +1904,9 @@ codegen_test_peer (void) g_thread_join (service_thread); teardown_test_address (); + + g_main_loop_unref (loop); + g_free (test_guid); } /* ---------------------------------------------------------------------------------------------------- */ @@ -1886,17 +1919,12 @@ main (int argc, gint ret; GDBusNodeInfo *introspection_data = NULL; - g_test_init (&argc, &argv, NULL); + g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL); introspection_data = g_dbus_node_info_new_for_xml (test_interface_introspection_xml, NULL); g_assert (introspection_data != NULL); test_interface_introspection_data = introspection_data->interfaces[0]; - test_guid = g_dbus_generate_guid (); - - /* all the tests rely on a shared main loop */ - loop = g_main_loop_new (NULL, FALSE); - g_test_add_func ("/gdbus/peer-to-peer", test_peer); g_test_add_func ("/gdbus/peer-to-peer/signals", test_peer_signals); g_test_add_func ("/gdbus/delayed-message-processing", delayed_message_processing); @@ -1906,10 +1934,8 @@ main (int argc, g_test_add_func ("/gdbus/credentials", test_credentials); g_test_add_func ("/gdbus/codegen-peer-to-peer", codegen_test_peer); - ret = g_test_run(); + ret = g_test_run (); - g_main_loop_unref (loop); - g_free (test_guid); g_dbus_node_info_unref (introspection_data); return ret; diff --git a/gio/tests/meson.build b/gio/tests/meson.build index b5593a4ec..382dfccad 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -577,7 +577,9 @@ if not meson.is_cross_build() or meson.has_exe_wrapper() # Support for --add-symbol was added to LLVM objcopy in 2019 # (https://reviews.llvm.org/D58234). FIXME: This test could be enabled for # LLVM once that support is in a stable release. - if build_machine.system() == 'linux' and cc.get_id() == 'gcc' + objcopy = find_program('objcopy', required : false) + + if build_machine.system() == 'linux' and cc.get_id() == 'gcc' and objcopy.found() test_gresource_binary = custom_target('test5.gresource', input : 'test5.gresource.xml', output : 'test5.gresource', @@ -616,7 +618,7 @@ if not meson.is_cross_build() or meson.has_exe_wrapper() test_resources_binary2 = custom_target('test_resources2.o', input : test_resources_binary, output : 'test_resources2.o', - command : ['objcopy', + command : [objcopy, '--add-symbol','_g_binary_test1_resource_data=.data:0', '@INPUT@', '@OUTPUT@']) |