summaryrefslogtreecommitdiff
path: root/gio
diff options
context:
space:
mode:
authorDongHun Kwak <dh0128.kwak@samsung.com>2021-10-29 10:26:38 +0900
committerDongHun Kwak <dh0128.kwak@samsung.com>2021-10-29 10:26:38 +0900
commit585b698fad12e1c8676aba6a5d8e249355554d2b (patch)
tree1b41cbd2a120ba4786c9f3aba24413f3fa9578d3 /gio
parent4de08fc06a7555c3642c170bfdc66fddd9787fdb (diff)
downloadglib-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.c5
-rw-r--r--gio/glocalfileinfo.c79
-rw-r--r--gio/tests/gdbus-peer.c199
-rw-r--r--gio/tests/gsocketclient-slow.c39
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);