diff options
author | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-29 10:26:38 +0900 |
---|---|---|
committer | DongHun Kwak <dh0128.kwak@samsung.com> | 2021-10-29 10:26:38 +0900 |
commit | 585b698fad12e1c8676aba6a5d8e249355554d2b (patch) | |
tree | 1b41cbd2a120ba4786c9f3aba24413f3fa9578d3 /gio | |
parent | 4de08fc06a7555c3642c170bfdc66fddd9787fdb (diff) | |
download | glib-585b698fad12e1c8676aba6a5d8e249355554d2b.tar.gz glib-585b698fad12e1c8676aba6a5d8e249355554d2b.tar.bz2 glib-585b698fad12e1c8676aba6a5d8e249355554d2b.zip |
Imported Upstream version 2.66.3upstream/2.66.3
Diffstat (limited to 'gio')
-rw-r--r-- | gio/gdbusprivate.c | 5 | ||||
-rw-r--r-- | gio/glocalfileinfo.c | 79 | ||||
-rw-r--r-- | gio/tests/gdbus-peer.c | 199 | ||||
-rw-r--r-- | gio/tests/gsocketclient-slow.c | 39 |
4 files changed, 220 insertions, 102 deletions
diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 5c980b40b..2551e4791 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -1085,8 +1085,11 @@ write_message_continue_writing (MessageToWriteData *data) else { #ifdef G_OS_UNIX - if (fd_list != NULL) + if (data->total_written == 0 && fd_list != NULL) { + /* We were trying to write byte 0 of the message, which needs + * the fd list to be attached to it, but this connection doesn't + * support doing that. */ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 90fcb3336..a4abef089 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -1547,15 +1547,45 @@ win32_get_file_user_info (const gchar *filename, /* support for '.hidden' files */ G_LOCK_DEFINE_STATIC (hidden_cache); static GHashTable *hidden_cache; +static GSource *hidden_cache_source = NULL; /* Under the hidden_cache lock */ +static guint hidden_cache_ttl_secs = 5; +static guint hidden_cache_ttl_jitter_secs = 2; + +typedef struct +{ + GHashTable *hidden_files; + gint64 timestamp_secs; +} HiddenCacheData; static gboolean remove_from_hidden_cache (gpointer user_data) { + HiddenCacheData *data; + GHashTableIter iter; + gboolean retval; + gint64 timestamp_secs; + G_LOCK (hidden_cache); - g_hash_table_remove (hidden_cache, user_data); + timestamp_secs = g_source_get_time (hidden_cache_source) / G_USEC_PER_SEC; + + g_hash_table_iter_init (&iter, hidden_cache); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &data)) + { + if (timestamp_secs > data->timestamp_secs + hidden_cache_ttl_secs) + g_hash_table_iter_remove (&iter); + } + + if (g_hash_table_size (hidden_cache) == 0) + { + g_clear_pointer (&hidden_cache_source, g_source_unref); + retval = G_SOURCE_REMOVE; + } + else + retval = G_SOURCE_CONTINUE; + G_UNLOCK (hidden_cache); - return FALSE; + return retval; } static GHashTable * @@ -1593,16 +1623,19 @@ read_hidden_file (const gchar *dirname) } static void -maybe_unref_hash_table (gpointer data) +free_hidden_file_data (gpointer user_data) { - if (data != NULL) - g_hash_table_unref (data); + HiddenCacheData *data = user_data; + + g_clear_pointer (&data->hidden_files, g_hash_table_unref); + g_free (data); } static gboolean file_is_hidden (const gchar *path, const gchar *basename) { + HiddenCacheData *data; gboolean result; gchar *dirname; gpointer table; @@ -1613,28 +1646,38 @@ file_is_hidden (const gchar *path, if G_UNLIKELY (hidden_cache == NULL) hidden_cache = g_hash_table_new_full (g_str_hash, g_str_equal, - g_free, maybe_unref_hash_table); + g_free, free_hidden_file_data); if (!g_hash_table_lookup_extended (hidden_cache, dirname, - NULL, &table)) + NULL, (gpointer *) &data)) { gchar *mydirname; - GSource *remove_from_cache_source; + + data = g_new0 (HiddenCacheData, 1); + data->hidden_files = table = read_hidden_file (dirname); + data->timestamp_secs = g_get_monotonic_time () / G_USEC_PER_SEC; g_hash_table_insert (hidden_cache, mydirname = g_strdup (dirname), - table = read_hidden_file (dirname)); + data); - remove_from_cache_source = g_timeout_source_new_seconds (5); - g_source_set_priority (remove_from_cache_source, G_PRIORITY_DEFAULT); - g_source_set_callback (remove_from_cache_source, - remove_from_hidden_cache, - mydirname, - NULL); - g_source_attach (remove_from_cache_source, - GLIB_PRIVATE_CALL (g_get_worker_context) ()); - g_source_unref (remove_from_cache_source); + if (!hidden_cache_source) + { + hidden_cache_source = + g_timeout_source_new_seconds (hidden_cache_ttl_secs + + hidden_cache_ttl_jitter_secs); + g_source_set_priority (hidden_cache_source, G_PRIORITY_DEFAULT); + g_source_set_name (hidden_cache_source, + "[gio] remove_from_hidden_cache"); + g_source_set_callback (hidden_cache_source, + remove_from_hidden_cache, + NULL, NULL); + g_source_attach (hidden_cache_source, + GLIB_PRIVATE_CALL (g_get_worker_context) ()); + } } + else + table = data->hidden_files; result = table != NULL && g_hash_table_contains (table, basename); diff --git a/gio/tests/gdbus-peer.c b/gio/tests/gdbus-peer.c index 617d7561a..8450a3be7 100644 --- a/gio/tests/gdbus-peer.c +++ b/gio/tests/gdbus-peer.c @@ -76,6 +76,12 @@ typedef struct gboolean signal_received; } PeerData; +/* This needs to be enough to usually take more than one write(), + * to reproduce + * <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>. + * 1 MiB ought to be enough. */ +#define BIG_MESSAGE_ARRAY_SIZE (1024 * 1024) + static const gchar *test_interface_introspection_xml = "<node>" " <interface name='org.gtk.GDBus.PeerTestInterface'>" @@ -88,6 +94,11 @@ static const gchar *test_interface_introspection_xml = " <method name='OpenFile'>" " <arg type='s' name='path' direction='in'/>" " </method>" + " <method name='OpenFileWithBigMessage'>" + " <arg type='s' name='path' direction='in'/>" + " <arg type='h' name='handle' direction='out'/>" + " <arg type='ay' name='junk' direction='out'/>" + " </method>" " <signal name='PeerSignal'>" " <arg type='s' name='a_string'/>" " </signal>" @@ -164,7 +175,8 @@ test_interface_method_call (GDBusConnection *connection, g_dbus_method_invocation_return_value (invocation, NULL); } - else if (g_strcmp0 (method_name, "OpenFile") == 0) + else if (g_strcmp0 (method_name, "OpenFile") == 0 || + g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0) { #ifdef G_OS_UNIX const gchar *path; @@ -190,6 +202,21 @@ test_interface_method_call (GDBusConnection *connection, g_object_unref (fd_list); g_object_unref (invocation); + if (g_strcmp0 (method_name, "OpenFileWithBigMessage") == 0) + { + char *junk; + + junk = g_new0 (char, BIG_MESSAGE_ARRAY_SIZE); + g_dbus_message_set_body (reply, + g_variant_new ("(h@ay)", + 0, + g_variant_new_fixed_array (G_VARIANT_TYPE_BYTE, + junk, + BIG_MESSAGE_ARRAY_SIZE, + 1))); + g_free (junk); + } + error = NULL; g_dbus_connection_send_message (connection, reply, @@ -723,6 +750,7 @@ do_test_peer (void) const gchar *s; GThread *service_thread; gulong signal_handler_id; + gsize i; memset (&data, '\0', sizeof (PeerData)); data.current_connections = g_ptr_array_new_with_free_func (g_object_unref); @@ -843,73 +871,116 @@ do_test_peer (void) g_assert_cmpint (data.num_method_calls, ==, 3); g_signal_handler_disconnect (proxy, signal_handler_id); - /* check for UNIX fd passing */ + /* + * Check for UNIX fd passing. + * + * The first time through, we use a very simple method call. Note that + * because this does not have a G_VARIANT_TYPE_HANDLE in the message body + * to refer to the fd, it is a GDBus-specific idiom that would not + * interoperate with libdbus or sd-bus + * (see <https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1726>). + * + * The second time, we call a method that returns a fd attached to a + * large message, to reproduce + * <https://gitlab.gnome.org/GNOME/glib/-/issues/2074>. It also happens + * to follow the more usual pattern for D-Bus messages containing a + * G_VARIANT_TYPE_HANDLE to refer to attached fds. + */ + for (i = 0; i < 2; i++) + { #ifdef G_OS_UNIX - { - GDBusMessage *method_call_message; - GDBusMessage *method_reply_message; - GUnixFDList *fd_list; - gint fd; - gchar *buf; - gsize len; - gchar *buf2; - gsize len2; - const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL); - - method_call_message = g_dbus_message_new_method_call (NULL, /* name */ - "/org/gtk/GDBus/PeerTestObject", - "org.gtk.GDBus.PeerTestInterface", - "OpenFile"); - g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile)); - error = NULL; - method_reply_message = g_dbus_connection_send_message_with_reply_sync (c, - method_call_message, - G_DBUS_SEND_MESSAGE_FLAGS_NONE, - -1, - NULL, /* out_serial */ - NULL, /* cancellable */ - &error); - g_assert_no_error (error); - g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN); - fd_list = g_dbus_message_get_unix_fd_list (method_reply_message); - g_assert (fd_list != NULL); - g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1); - error = NULL; - fd = g_unix_fd_list_get (fd_list, 0, &error); - g_assert_no_error (error); - g_object_unref (method_call_message); - g_object_unref (method_reply_message); + GDBusMessage *method_call_message; + GDBusMessage *method_reply_message; + GUnixFDList *fd_list; + gint fd; + gchar *buf; + gsize len; + gchar *buf2; + gsize len2; + const char *testfile = g_test_get_filename (G_TEST_DIST, "file.c", NULL); + const char *method = "OpenFile"; + GVariant *body; + + if (i == 1) + method = "OpenFileWithBigMessage"; + + method_call_message = g_dbus_message_new_method_call (NULL, /* name */ + "/org/gtk/GDBus/PeerTestObject", + "org.gtk.GDBus.PeerTestInterface", + method); + g_dbus_message_set_body (method_call_message, g_variant_new ("(s)", testfile)); + error = NULL; + method_reply_message = g_dbus_connection_send_message_with_reply_sync (c, + method_call_message, + G_DBUS_SEND_MESSAGE_FLAGS_NONE, + -1, + NULL, /* out_serial */ + NULL, /* cancellable */ + &error); + g_assert_no_error (error); + g_assert (g_dbus_message_get_message_type (method_reply_message) == G_DBUS_MESSAGE_TYPE_METHOD_RETURN); - error = NULL; - len = 0; - buf = read_all_from_fd (fd, &len, &error); - g_assert_no_error (error); - g_assert (buf != NULL); - close (fd); + body = g_dbus_message_get_body (method_reply_message); - error = NULL; - g_file_get_contents (testfile, - &buf2, - &len2, - &error); - g_assert_no_error (error); - g_assert_cmpmem (buf, len, buf2, len2); - g_free (buf2); - g_free (buf); - } + if (i == 1) + { + gint32 handle = -1; + GVariant *junk = NULL; + + g_assert_cmpstr (g_variant_get_type_string (body), ==, "(hay)"); + g_variant_get (body, "(h@ay)", &handle, &junk); + g_assert_cmpint (handle, ==, 0); + g_assert_cmpuint (g_variant_n_children (junk), ==, BIG_MESSAGE_ARRAY_SIZE); + g_variant_unref (junk); + } + else + { + g_assert_null (body); + } + + fd_list = g_dbus_message_get_unix_fd_list (method_reply_message); + g_assert (fd_list != NULL); + g_assert_cmpint (g_unix_fd_list_get_length (fd_list), ==, 1); + error = NULL; + fd = g_unix_fd_list_get (fd_list, 0, &error); + g_assert_no_error (error); + g_object_unref (method_call_message); + g_object_unref (method_reply_message); + + error = NULL; + len = 0; + buf = read_all_from_fd (fd, &len, &error); + g_assert_no_error (error); + g_assert (buf != NULL); + close (fd); + + error = NULL; + g_file_get_contents (testfile, + &buf2, + &len2, + &error); + g_assert_no_error (error); + g_assert_cmpmem (buf, len, buf2, len2); + g_free (buf2); + g_free (buf); #else - error = NULL; - result = g_dbus_proxy_call_sync (proxy, - "OpenFile", - g_variant_new ("(s)", "boo"), - G_DBUS_CALL_FLAGS_NONE, - -1, - NULL, /* GCancellable */ - &error); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR); - g_assert (result == NULL); - g_error_free (error); + /* We do the same number of iterations on non-Unix, so that + * the method call count will match. In this case we use + * OpenFile both times, because the difference between this + * and OpenFileWithBigMessage is only relevant on Unix. */ + error = NULL; + result = g_dbus_proxy_call_sync (proxy, + "OpenFile", + g_variant_new ("(s)", "boo"), + G_DBUS_CALL_FLAGS_NONE, + -1, + NULL, /* GCancellable */ + &error); + g_assert_error (error, G_IO_ERROR, G_IO_ERROR_DBUS_ERROR); + g_assert (result == NULL); + g_error_free (error); #endif /* G_OS_UNIX */ + } /* Check that g_socket_get_credentials() work - (though this really * should be in socket.c) @@ -1017,7 +1088,7 @@ do_test_peer (void) g_variant_get (result, "(&s)", &s); g_assert_cmpstr (s, ==, "You greeted me with 'Hey Again Peer!'."); g_variant_unref (result); - g_assert_cmpint (data.num_method_calls, ==, 5); + g_assert_cmpint (data.num_method_calls, ==, 6); #if 0 /* TODO: THIS TEST DOESN'T WORK YET */ diff --git a/gio/tests/gsocketclient-slow.c b/gio/tests/gsocketclient-slow.c index 34410f4cf..803ed9082 100644 --- a/gio/tests/gsocketclient-slow.c +++ b/gio/tests/gsocketclient-slow.c @@ -79,23 +79,26 @@ on_connected_cancelled (GObject *source_object, g_main_loop_quit (user_data); } -static int -on_timer (GCancellable *cancel) +typedef struct { - g_cancellable_cancel (cancel); - return G_SOURCE_REMOVE; -} + GCancellable *cancellable; + gboolean completed; +} EventCallbackData; static void on_event (GSocketClient *client, GSocketClientEvent event, GSocketConnectable *connectable, GIOStream *connection, - gboolean *got_completed_event) + EventCallbackData *data) { - if (event == G_SOCKET_CLIENT_COMPLETE) + if (data->cancellable && event == G_SOCKET_CLIENT_CONNECTED) + { + g_cancellable_cancel (data->cancellable); + } + else if (event == G_SOCKET_CLIENT_COMPLETE) { - *got_completed_event = TRUE; + data->completed = TRUE; g_assert_null (connection); } } @@ -108,8 +111,7 @@ test_happy_eyeballs_cancel_delayed (void) GError *error = NULL; guint16 port; GMainLoop *loop; - GCancellable *cancel; - gboolean got_completed_event = FALSE; + EventCallbackData data = { NULL, FALSE }; /* This just tests that cancellation works as expected, still emits the completed signal, * and never returns a connection */ @@ -122,17 +124,16 @@ test_happy_eyeballs_cancel_delayed (void) g_socket_service_start (service); client = g_socket_client_new (); - cancel = g_cancellable_new (); - g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop); - g_timeout_add (1, (GSourceFunc) on_timer, cancel); - g_signal_connect (client, "event", G_CALLBACK (on_event), &got_completed_event); + data.cancellable = g_cancellable_new (); + g_socket_client_connect_to_host_async (client, "localhost", port, data.cancellable, on_connected_cancelled, loop); + g_signal_connect (client, "event", G_CALLBACK (on_event), &data); g_main_loop_run (loop); - g_assert_true (got_completed_event); + g_assert_true (data.completed); g_main_loop_unref (loop); g_object_unref (service); g_object_unref (client); - g_object_unref (cancel); + g_object_unref (data.cancellable); } static void @@ -144,7 +145,7 @@ test_happy_eyeballs_cancel_instant (void) guint16 port; GMainLoop *loop; GCancellable *cancel; - gboolean got_completed_event = FALSE; + EventCallbackData data = { NULL, FALSE }; /* This tests the same things as above, test_happy_eyeballs_cancel_delayed(), but * with different timing since it sends an already cancelled cancellable */ @@ -160,10 +161,10 @@ test_happy_eyeballs_cancel_instant (void) cancel = g_cancellable_new (); g_cancellable_cancel (cancel); g_socket_client_connect_to_host_async (client, "localhost", port, cancel, on_connected_cancelled, loop); - g_signal_connect (client, "event", G_CALLBACK (on_event), &got_completed_event); + g_signal_connect (client, "event", G_CALLBACK (on_event), &data); g_main_loop_run (loop); - g_assert_true (got_completed_event); + g_assert_true (data.completed); g_main_loop_unref (loop); g_object_unref (service); g_object_unref (client); |