Compare commits

...

No commits in common. 'c9' and 'i8c-beta' have entirely different histories.
c9 ... i8c-beta

2
.gitignore vendored

@ -1 +1 @@
SOURCES/glib-2.68.4.tar.xz
SOURCES/glib-2.56.4.tar.xz

@ -1 +1 @@
bfebd4a5074715962177e8712cec630219f58786 SOURCES/glib-2.68.4.tar.xz
4064eb1eb5ff626c211e86bc939f8b743ceafaba SOURCES/glib-2.56.4.tar.xz

@ -0,0 +1,658 @@
From 5634fd61f17d28dfc05cd47cfbd2bd2f21e6d2b1 Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:06:03 +0100
Subject: [PATCH 1/4] gsettings: cleanup default value lookup
There are a couple of different ways (and soon one more) to access the
default value of a key. Clean up the various places that access this to
avoid duplication.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/gsettings.c | 20 ++++----------------
1 file changed, 4 insertions(+), 16 deletions(-)
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 10d394d69..5e5816d57 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1204,10 +1204,7 @@ g_settings_get_value (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
g_settings_schema_key_clear (&skey);
@@ -1304,10 +1301,7 @@ g_settings_get_default_value (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, TRUE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
g_settings_schema_key_clear (&skey);
@@ -1360,10 +1354,7 @@ g_settings_get_enum (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
result = g_settings_schema_key_to_enum (&skey, value);
g_settings_schema_key_clear (&skey);
@@ -1473,10 +1464,7 @@ g_settings_get_flags (GSettings *settings,
value = g_settings_read_from_backend (settings, &skey, FALSE, FALSE);
if (value == NULL)
- value = g_settings_schema_key_get_translated_default (&skey);
-
- if (value == NULL)
- value = g_variant_ref (skey.default_value);
+ value = g_settings_schema_key_get_default_value (&skey);
result = g_settings_schema_key_to_flags (&skey, value);
g_settings_schema_key_clear (&skey);
--
2.21.0
From 89c6e8f4a0bcda4b58dbaea713e62be01cfc2087 Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:08:17 +0100
Subject: [PATCH 2/4] gsettingsschema: Allow per-desktop overrides
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Recognise a new 'd' option in schema keys which gives a dictionary of
per-desktop default values. This dictionary is searched for the items
found in XDG_CURRENT_DESKTOP, in the order. If nothing matches (or if
the option is missing) then the default value is used as before.
This feature was requested by Alberts Muktupāvels and this patch is
based on an approach devised by them.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/gsettings.c | 21 +++++++++++++++++
gio/gsettingsschema-internal.h | 2 ++
gio/gsettingsschema.c | 41 ++++++++++++++++++++++++++++++++++
3 files changed, 64 insertions(+)
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 5e5816d57..f1130c095 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -1739,6 +1739,13 @@ g_settings_get_mapped (GSettings *settings,
if (okay) goto okay;
}
+ if ((value = g_settings_schema_key_get_per_desktop_default (&skey)))
+ {
+ okay = mapping (value, &result, user_data);
+ g_variant_unref (value);
+ if (okay) goto okay;
+ }
+
if (mapping (skey.default_value, &result, user_data))
goto okay;
@@ -2647,6 +2654,20 @@ g_settings_binding_key_changed (GSettings *settings,
}
}
+ if (variant == NULL)
+ {
+ variant = g_settings_schema_key_get_per_desktop_default (&binding->key);
+ if (variant &&
+ !binding->get_mapping (&value, variant, binding->user_data))
+ {
+ g_error ("Per-desktop default value for key '%s' in schema '%s' "
+ "was rejected by the binding mapping function.",
+ binding->key.name, g_settings_schema_get_id (binding->key.schema));
+ g_variant_unref (variant);
+ variant = NULL;
+ }
+ }
+
if (variant == NULL)
{
variant = g_variant_ref (binding->key.default_value);
diff --git a/gio/gsettingsschema-internal.h b/gio/gsettingsschema-internal.h
index f54de3b34..5f996b4bc 100644
--- a/gio/gsettingsschema-internal.h
+++ b/gio/gsettingsschema-internal.h
@@ -37,6 +37,7 @@ struct _GSettingsSchemaKey
const GVariantType *type;
GVariant *minimum, *maximum;
GVariant *default_value;
+ GVariant *desktop_overrides;
gint ref_count;
};
@@ -58,6 +59,7 @@ gboolean g_settings_schema_key_type_check (GSettin
GVariant * g_settings_schema_key_range_fixup (GSettingsSchemaKey *key,
GVariant *value);
GVariant * g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key);
+GVariant * g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key);
gint g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
GVariant *value);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index f1274a369..17b7e3b01 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -27,6 +27,7 @@
#include <glibintl.h>
#include <locale.h>
#include <string.h>
+#include <stdlib.h>
/**
* SECTION:gsettingsschema
@@ -1283,6 +1284,11 @@ g_settings_schema_key_init (GSettingsSchemaKey *key,
endian_fixup (&key->maximum);
break;
+ case 'd':
+ g_variant_get (data, "@a{sv}", &key->desktop_overrides);
+ endian_fixup (&key->desktop_overrides);
+ break;
+
default:
g_warning ("unknown schema extension '%c'", code);
break;
@@ -1303,6 +1309,9 @@ g_settings_schema_key_clear (GSettingsSchemaKey *key)
if (key->maximum)
g_variant_unref (key->maximum);
+ if (key->desktop_overrides)
+ g_variant_unref (key->desktop_overrides);
+
g_variant_unref (key->default_value);
g_settings_schema_unref (key->schema);
@@ -1410,6 +1419,35 @@ g_settings_schema_key_get_translated_default (GSettingsSchemaKey *key)
return value;
}
+GVariant *
+g_settings_schema_key_get_per_desktop_default (GSettingsSchemaKey *key)
+{
+ static const gchar * const *current_desktops;
+ GVariant *value = NULL;
+ gint i;
+
+ if (!key->desktop_overrides)
+ return NULL;
+
+ if (g_once_init_enter (&current_desktops))
+ {
+ const gchar *xdg_current_desktop = g_getenv ("XDG_CURRENT_DESKTOP");
+ gchar **tmp;
+
+ if (xdg_current_desktop != NULL && xdg_current_desktop[0] != '\0')
+ tmp = g_strsplit (xdg_current_desktop, G_SEARCHPATH_SEPARATOR_S, -1);
+ else
+ tmp = g_new0 (gchar *, 0 + 1);
+
+ g_once_init_leave (&current_desktops, (const gchar **) tmp);
+ }
+
+ for (i = 0; value == NULL && current_desktops[i] != NULL; i++)
+ value = g_variant_lookup_value (key->desktop_overrides, current_desktops[i], NULL);
+
+ return value;
+}
+
gint
g_settings_schema_key_to_enum (GSettingsSchemaKey *key,
GVariant *value)
@@ -1698,6 +1736,9 @@ g_settings_schema_key_get_default_value (GSettingsSchemaKey *key)
value = g_settings_schema_key_get_translated_default (key);
+ if (!value)
+ value = g_settings_schema_key_get_per_desktop_default (key);
+
if (!value)
value = g_variant_ref (key->default_value);
--
2.21.0
From 3710e830de015829c086c69181a8703645d577ec Mon Sep 17 00:00:00 2001
From: Allison Lortie <desrt@desrt.ca>
Date: Wed, 2 Aug 2017 11:10:18 +0100
Subject: [PATCH 3/4] glib-compile-schemas: Handle per-desktop overrides
Add a new syntax to override files: if the group name has a ':' in it,
it indicates that we want to override the default values of keys for
only one desktop. For example:
[org.gnome.desktop.interface:Unity]
font-name='Ubuntu 12'
Will override the settings, only if "Unity" is found in
XDG_CURRENT_DESKTOP. Multiple per-desktop overrides can be specified
for a given key: the one which comes first in XDG_CURRENT_DESKTOP will
be used.
https://bugzilla.gnome.org/show_bug.cgi?id=746592
---
gio/glib-compile-schemas.c | 83 ++++++++++++++++++++++++++++++++++----
1 file changed, 75 insertions(+), 8 deletions(-)
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index 2dc8c7171..59fb68ee7 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -179,6 +179,8 @@ typedef struct
GString *unparsed_default_value;
GVariant *default_value;
+ GVariantDict *desktop_overrides;
+
GString *strinfo;
gboolean is_enum;
gboolean is_flags;
@@ -731,6 +733,11 @@ key_state_serialise (KeyState *state)
g_variant_builder_add (&builder, "(y(**))", 'r',
state->minimum, state->maximum);
+ /* per-desktop overrides */
+ if (state->desktop_overrides)
+ g_variant_builder_add (&builder, "(y@a{sv})", 'd',
+ g_variant_dict_end (state->desktop_overrides));
+
state->serialised = g_variant_builder_end (&builder);
}
@@ -768,6 +775,9 @@ key_state_free (gpointer data)
if (state->serialised)
g_variant_unref (state->serialised);
+ if (state->desktop_overrides)
+ g_variant_dict_unref (state->desktop_overrides);
+
g_slice_free (KeyState, state);
}
@@ -1878,6 +1888,8 @@ set_overrides (GHashTable *schema_table,
gchar **groups;
gint i;
+ g_debug ("Processing override file '%s'", filename);
+
key_file = g_key_file_new ();
if (!g_key_file_load_from_file (key_file, filename, 0, &error))
{
@@ -1900,18 +1912,31 @@ set_overrides (GHashTable *schema_table,
for (i = 0; groups[i]; i++)
{
const gchar *group = groups[i];
+ const gchar *schema_name;
+ const gchar *desktop_id;
SchemaState *schema;
+ gchar **pieces;
gchar **keys;
gint j;
- schema = g_hash_table_lookup (schema_table, group);
+ pieces = g_strsplit (group, ":", 2);
+ schema_name = pieces[0];
+ desktop_id = pieces[1];
+
+ g_debug ("Processing group '%s' (schema '%s', %s)",
+ group, schema_name, desktop_id ? desktop_id : "all desktops");
+
+ schema = g_hash_table_lookup (schema_table, schema_name);
if (schema == NULL)
- /* Having the schema not be installed is expected to be a
- * common case. Don't even emit an error message about
- * that.
- */
- continue;
+ {
+ /* Having the schema not be installed is expected to be a
+ * common case. Don't even emit an error message about
+ * that.
+ */
+ g_strfreev (pieces);
+ continue;
+ }
keys = g_key_file_get_keys (key_file, group, NULL, NULL);
g_assert (keys != NULL);
@@ -1939,6 +1964,32 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
+ g_strfreev (groups);
+ g_strfreev (keys);
+
+ return FALSE;
+ }
+
+ if (desktop_id != NULL && state->l10n)
+ {
+ /* Let's avoid the n*m case of per-desktop localised
+ * default values, and just forbid it.
+ */
+ fprintf (stderr,
+ _("cannot provide per-desktop overrides for localised "
+ "key '%s' in schema '%s' (override file '%s')"),
+ key, group, filename);
+
+ if (!strict)
+ {
+ fprintf (stderr, _("; ignoring override for this key.\n"));
+ continue;
+ }
+
+ fprintf (stderr, _(" and --strict was specified; exiting.\n"));
+ g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -1969,6 +2020,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _("--strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -1997,6 +2049,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -2025,6 +2078,7 @@ set_overrides (GHashTable *schema_table,
fprintf (stderr, _(" and --strict was specified; exiting.\n"));
g_key_file_free (key_file);
+ g_strfreev (pieces);
g_strfreev (groups);
g_strfreev (keys);
@@ -2032,11 +2086,24 @@ set_overrides (GHashTable *schema_table,
}
}
- g_variant_unref (state->default_value);
- state->default_value = value;
+ if (desktop_id != NULL)
+ {
+ if (state->desktop_overrides == NULL)
+ state->desktop_overrides = g_variant_dict_new (NULL);
+
+ g_variant_dict_insert_value (state->desktop_overrides, desktop_id, value);
+ g_variant_unref (value);
+ }
+ else
+ {
+ g_variant_unref (state->default_value);
+ state->default_value = value;
+ }
+
g_free (string);
}
+ g_strfreev (pieces);
g_strfreev (keys);
}
--
2.21.0
From 2ca9218fb46f32fa02bed43c6e60243c8c5d656f Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Alberts=20Muktup=C4=81vels?= <alberts.muktupavels@gmail.com>
Date: Tue, 19 Jun 2018 23:39:24 +0300
Subject: [PATCH 4/4] Add a test for per-desktop overrides
---
gio/glib-compile-schemas.c | 1 +
gio/tests/Makefile.am | 2 +
gio/tests/gsettings.c | 106 ++++++++++++++++++-
gio/tests/org.gtk.test.gschema.override.orig | 2 +
gio/tests/org.gtk.test.gschema.xml.orig | 6 ++
5 files changed, 116 insertions(+), 1 deletion(-)
create mode 100644 gio/tests/org.gtk.test.gschema.override.orig
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index 59fb68ee7..00dd64146 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -2139,6 +2139,7 @@ main (int argc, char **argv)
/* These options are only for use in the gschema-compile tests */
{ "schema-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &schema_files, NULL, NULL },
+ { "override-file", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME_ARRAY, &override_files, NULL, NULL },
{ NULL }
};
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index 49a19bf4a..b41317ad9 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -367,12 +367,14 @@ test.mo: de.po
EXTRA_DIST += de.po
dist_uninstalled_test_data += \
org.gtk.test.gschema.xml.orig \
+ org.gtk.test.gschema.override.orig \
org.gtk.schemasourcecheck.gschema.xml \
testenum.h \
enums.xml.template
# Generated while running the testcase itself...
CLEANFILES += \
org.gtk.test.gschema.xml \
+ org.gtk.test.gschema.override \
org.gtk.test.enums.xml \
gsettings.store \
gschemas.compiled \
diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c
index 2be4122fe..acdeead4c 100644
--- a/gio/tests/gsettings.c
+++ b/gio/tests/gsettings.c
@@ -2192,6 +2192,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
"org.gtk.test.range.direct",
"org.gtk.test.mapped",
"org.gtk.test.descriptions",
+ "org.gtk.test.per-desktop",
NULL));
}
@@ -2583,6 +2584,100 @@ test_default_value (void)
g_object_unref (settings);
}
+static gboolean
+string_map_func (GVariant *value,
+ gpointer *result,
+ gpointer user_data)
+{
+ const gchar *str;
+
+ str = g_variant_get_string (value, NULL);
+ *result = g_variant_new_string (str);
+
+ return TRUE;
+}
+
+/* Test that per-desktop values from org.gtk.test.gschema.override
+ * does not change default value if current desktop is not listed in
+ * $XDG_CURRENT_DESKTOP.
+ */
+static void
+test_per_desktop (void)
+{
+ GSettings *settings;
+ TestObject *obj;
+ gpointer p;
+ gchar *str;
+
+ settings = g_settings_new ("org.gtk.test.per-desktop");
+ obj = test_object_new ();
+
+ if (!g_test_subprocess ())
+ {
+ g_test_trap_subprocess ("/gsettings/per-desktop/subprocess", 0, 0);
+ g_test_trap_assert_passed ();
+ }
+
+ str = g_settings_get_string (settings, "desktop");
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ p = g_settings_get_mapped (settings, "desktop", string_map_func, NULL);
+
+ str = g_variant_dup_string (p, NULL);
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ g_variant_unref (p);
+
+ g_settings_bind (settings, "desktop", obj, "string", G_SETTINGS_BIND_DEFAULT);
+
+ g_object_get (obj, "string", &str, NULL);
+ g_assert_cmpstr (str, ==, "GNOME");
+ g_free (str);
+
+ g_object_unref (settings);
+ g_object_unref (obj);
+}
+
+/* Test that per-desktop values from org.gtk.test.gschema.override
+ * are successfully loaded based on the value of $XDG_CURRENT_DESKTOP.
+ */
+static void
+test_per_desktop_subprocess (void)
+{
+ GSettings *settings;
+ TestObject *obj;
+ gpointer p;
+ gchar *str;
+
+ g_setenv ("XDG_CURRENT_DESKTOP", "GNOME-Classic:GNOME", TRUE);
+
+ settings = g_settings_new ("org.gtk.test.per-desktop");
+ obj = test_object_new ();
+
+ str = g_settings_get_string (settings, "desktop");
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ p = g_settings_get_mapped (settings, "desktop", string_map_func, NULL);
+
+ str = g_variant_dup_string (p, NULL);
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ g_variant_unref (p);
+
+ g_settings_bind (settings, "desktop", obj, "string", G_SETTINGS_BIND_DEFAULT);
+
+ g_object_get (obj, "string", &str, NULL);
+ g_assert_cmpstr (str, ==, "GNOME Classic");
+ g_free (str);
+
+ g_object_unref (settings);
+ g_object_unref (obj);
+}
+
static void
test_extended_schema (void)
{
@@ -2603,6 +2698,7 @@ int
main (int argc, char *argv[])
{
gchar *schema_text;
+ gchar *override_text;
gchar *enums;
gint result;
@@ -2625,6 +2721,7 @@ main (int argc, char *argv[])
g_setenv ("XDG_DATA_DIRS", ".", TRUE);
g_setenv ("XDG_DATA_HOME", ".", TRUE);
g_setenv ("GSETTINGS_SCHEMA_DIR", ".", TRUE);
+ g_setenv ("XDG_CURRENT_DESKTOP", "", TRUE);
if (!backend_set)
g_setenv ("GSETTINGS_BACKEND", "memory", TRUE);
@@ -2647,6 +2744,10 @@ main (int argc, char *argv[])
g_assert (g_file_set_contents ("org.gtk.test.gschema.xml", schema_text, -1, NULL));
g_free (schema_text);
+ g_assert (g_file_get_contents (SRCDIR "/org.gtk.test.gschema.override.orig", &override_text, NULL, NULL));
+ g_assert (g_file_set_contents ("org.gtk.test.gschema.override", override_text, -1, NULL));
+ g_free (override_text);
+
/* Meson build defines this, autotools build does not */
#ifndef GLIB_COMPILE_SCHEMAS
#define GLIB_COMPILE_SCHEMAS "../glib-compile-schemas"
@@ -2655,7 +2756,8 @@ main (int argc, char *argv[])
g_remove ("gschemas.compiled");
g_assert (g_spawn_command_line_sync (GLIB_COMPILE_SCHEMAS " --targetdir=. "
"--schema-file=org.gtk.test.enums.xml "
- "--schema-file=org.gtk.test.gschema.xml",
+ "--schema-file=org.gtk.test.gschema.xml "
+ "--override-file=org.gtk.test.gschema.override",
NULL, NULL, &result, NULL));
g_assert (result == 0);
@@ -2736,6 +2838,8 @@ main (int argc, char *argv[])
g_test_add_func ("/gsettings/read-descriptions", test_read_descriptions);
g_test_add_func ("/gsettings/test-extended-schema", test_extended_schema);
g_test_add_func ("/gsettings/default-value", test_default_value);
+ g_test_add_func ("/gsettings/per-desktop", test_per_desktop);
+ g_test_add_func ("/gsettings/per-desktop/subprocess", test_per_desktop_subprocess);
result = g_test_run ();
diff --git a/gio/tests/org.gtk.test.gschema.override.orig b/gio/tests/org.gtk.test.gschema.override.orig
new file mode 100644
index 000000000..6694baace
--- /dev/null
+++ b/gio/tests/org.gtk.test.gschema.override.orig
@@ -0,0 +1,2 @@
+[org.gtk.test.per-desktop:GNOME-Classic]
+desktop = "GNOME Classic"
diff --git a/gio/tests/org.gtk.test.gschema.xml.orig b/gio/tests/org.gtk.test.gschema.xml.orig
index c07558335..fbcdce683 100644
--- a/gio/tests/org.gtk.test.gschema.xml.orig
+++ b/gio/tests/org.gtk.test.gschema.xml.orig
@@ -209,4 +209,10 @@
</key>
</schema>
+ <schema id="org.gtk.test.per-desktop" path="/tests/per-desktop/">
+ <key name="desktop" type="s">
+ <default>"GNOME"</default>
+ </key>
+ </schema>
+
</schemalist>
--
2.21.0

@ -0,0 +1,139 @@
From 08f5ab3c3a1877e4a8965a9075bd7675f64eae53 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 27 Sep 2019 14:46:18 +0100
Subject: [PATCH 1/2] gfile: Factor out flags when copying files
This introduces no functional changes; just reduces duplication in the
code a little.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
---
gio/gfile.c | 15 +++++++++------
1 file changed, 9 insertions(+), 6 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 29ebaaa62..a617b4cc8 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3184,6 +3184,7 @@ file_copy_fallback (GFile *source,
const char *target;
char *attrs_to_read;
gboolean do_set_attributes = FALSE;
+ GFileCreateFlags create_flags;
/* need to know the file type */
info = g_file_query_info (source,
@@ -3274,18 +3275,21 @@ file_copy_fallback (GFile *source,
* If a future API like g_file_replace_with_info() is added, switch
* this code to use that.
*/
+ create_flags = G_FILE_CREATE_PRIVATE;
+ if (flags & G_FILE_COPY_OVERWRITE)
+ create_flags |= G_FILE_CREATE_REPLACE_DESTINATION;
+
if (G_IS_LOCAL_FILE (destination))
{
if (flags & G_FILE_COPY_OVERWRITE)
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION |
- G_FILE_CREATE_PRIVATE, info,
+ create_flags, info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, G_FILE_CREATE_PRIVATE, info,
+ FALSE, create_flags, info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
@@ -3293,13 +3297,12 @@ file_copy_fallback (GFile *source,
out = (GOutputStream *)g_file_replace (destination,
NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION |
- G_FILE_CREATE_PRIVATE,
+ create_flags,
cancellable, error);
}
else
{
- out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
+ out = (GOutputStream *)g_file_create (destination, create_flags, cancellable, error);
}
if (!out)
--
2.37.3
From b37d628c01da0bd61348b3ac73b7a436af008d8d Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 27 Sep 2019 15:02:32 +0100
Subject: [PATCH 2/2] =?UTF-8?q?gfile:=20Don=E2=80=99t=20copy=20files=20as?=
=?UTF-8?q?=20private=20if=20using=20default=20permissions?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If a copy operation is started with `G_FILE_COPY_TARGET_DEFAULT_PERMS`,
dont create the destination file as private. Instead, create it with
the process current umask (i.e. default permissions).
This is a partial re-work of commit d8f8f4d637ce43f8699ba94c9b, with
input from Ondrej Holy.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #174
---
gio/gfile.c | 22 +++++++++++++++++++---
1 file changed, 19 insertions(+), 3 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index a617b4cc8..447da3cfb 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3274,8 +3274,22 @@ file_copy_fallback (GFile *source,
*
* If a future API like g_file_replace_with_info() is added, switch
* this code to use that.
+ *
+ * Use %G_FILE_CREATE_PRIVATE unless
+ * - we were told to create the file with default permissions (i.e. the
+ * process umask),
+ * - or if the source file is on a file system which doesnt support
+ * `unix::mode` (in which case it probably also makes sense to create the
+ * destination with default permissions because the source cannot be
+ * private),
+ * - or if the destination file is a `GLocalFile`, in which case we can
+ * directly open() it with the permissions from the source file.
*/
- create_flags = G_FILE_CREATE_PRIVATE;
+ create_flags = G_FILE_CREATE_NONE;
+ if (!(flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) &&
+ g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE) &&
+ !G_IS_LOCAL_FILE (destination))
+ create_flags |= G_FILE_CREATE_PRIVATE;
if (flags & G_FILE_COPY_OVERWRITE)
create_flags |= G_FILE_CREATE_REPLACE_DESTINATION;
@@ -3285,11 +3299,13 @@ file_copy_fallback (GFile *source,
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- create_flags, info,
+ create_flags,
+ (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) ? NULL : info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, create_flags, info,
+ FALSE, create_flags,
+ (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) ? NULL : info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
--
2.37.3

@ -0,0 +1,371 @@
From ef1035d9d86464ea0b5dde60a7a0e190895fdf5b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 14 Oct 2019 08:22:24 +0100
Subject: [PATCH] gcredentialsprivate: Document the various private macros
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gcredentialsprivate.h | 59 +++++++++++++++++++++++++++++++++++++++
1 file changed, 59 insertions(+)
diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h
index 4d1c420a8..06f0aed19 100644
--- a/gio/gcredentialsprivate.h
+++ b/gio/gcredentialsprivate.h
@@ -22,6 +22,65 @@
#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
+
#ifdef __linux__
#define G_CREDENTIALS_SUPPORTED 1
#define G_CREDENTIALS_USE_LINUX_UCRED 1
--
2.23.0
From ee502dbbe89a5976c32eb8863c9a9d274ddb60e1 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 14 Oct 2019 08:47:39 +0100
Subject: [PATCH] GDBus: prefer getsockopt()-style credentials-passing APIs
Conceptually, a D-Bus server is really trying to determine the credentials
of (the process that initiated) a connection, not the credentials that
the process had when it sent a particular message. Ideally, it does
this with a getsockopt()-style API that queries the credentials of the
connection's initiator without requiring any particular cooperation from
that process, avoiding a class of possible failures.
The leading '\0' in the D-Bus protocol is primarily a workaround
for platforms where the message-based credentials-passing API is
strictly better than the getsockopt()-style API (for example, on
FreeBSD, SCM_CREDS includes a process ID but getpeereid() does not),
or where the getsockopt()-style API does not exist at all. As a result
libdbus, the reference implementation of D-Bus, does not implement
Linux SCM_CREDENTIALS at all - it has no reason to do so, because the
SO_PEERCRED socket option is equally informative.
This change makes GDBusServer on Linux more closely match the behaviour
of libdbus.
In particular, GNOME/glib#1831 indicates that when a libdbus client
connects to a GDBus server, recvmsg() sometimes yields a SCM_CREDENTIALS
message with cmsg_data={pid=0, uid=65534, gid=65534}. I think this is
most likely a race condition in the early steps to connect:
client server
connect
accept
send '\0' <- race -> set SO_PASSCRED = 1
receive '\0'
If the server wins the race:
client server
connect
accept
set SO_PASSCRED = 1
send '\0'
receive '\0'
then everything is fine. However, if the client wins the race:
client server
connect
accept
send '\0'
set SO_PASSCRED = 1
receive '\0'
then the kernel does not record credentials for the message containing
'\0' (because SO_PASSCRED was 0 at the time). However, by the time the
server receives the message, the kernel knows that credentials are
desired. I would have expected the kernel to omit the credentials header
in this case, but it seems that instead, it synthesizes a credentials
structure with a dummy process ID 0, a dummy uid derived from
/proc/sys/kernel/overflowuid and a dummy gid derived from
/proc/sys/kernel/overflowgid.
In an unconfigured GDBusServer, hitting this race condition results in
falling back to DBUS_COOKIE_SHA1 authentication, which in practice usually
succeeds in authenticating the peer's uid. However, we encourage AF_UNIX
servers on Unix platforms to allow only EXTERNAL authentication as a
security-hardening measure, because DBUS_COOKIE_SHA1 relies on a series
of assumptions including a cryptographically strong PRNG and a shared
home directory with no write access by others, which are not necessarily
true for all operating systems and users. EXTERNAL authentication will
fail if the server cannot determine the client's credentials.
In particular, this caused a regression when CVE-2019-14822 was fixed
in ibus, which appears to be resolved by this commit. Qt clients
(which use libdbus) intermittently fail to connect to an ibus server
(which uses GDBusServer), because ibus no longer allows DBUS_COOKIE_SHA1
authentication or non-matching uids.
Signed-off-by: Simon McVittie <smcv@collabora.com>
Closes: https://gitlab.gnome.org/GNOME/glib/issues/1831
---
gio/gcredentialsprivate.h | 18 ++++++++++++++++++
gio/gdbusauth.c | 27 +++++++++++++++++++++++++--
2 files changed, 43 insertions(+), 2 deletions(-)
diff --git a/gio/gcredentialsprivate.h b/gio/gcredentialsprivate.h
index 06f0aed19..e9ec09b9f 100644
--- a/gio/gcredentialsprivate.h
+++ b/gio/gcredentialsprivate.h
@@ -81,6 +81,18 @@
*/
#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
@@ -100,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),
--
2.23.0
From 1485a97d8051b0aa047987f7b0c0bfe4ba4ce55b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Fri, 18 Oct 2019 10:55:09 +0100
Subject: [PATCH] credentials: Invalid Linux struct ucred means "no
information"
On Linux, if getsockopt SO_PEERCRED is used on a TCP socket, one
might expect it to fail with an appropriate error like ENOTSUP or
EPROTONOSUPPORT. However, it appears that in fact it succeeds, but
yields a credentials structure with pid 0, uid -1 and gid -1. These
are not real process, user and group IDs that can be allocated to a
real process (pid 0 needs to be reserved to give kill(0) its documented
special semantics, and similarly uid and gid -1 need to be reserved for
setresuid() and setresgid()) so it is not meaningful to signal them to
high-level API users.
An API user with Linux-specific knowledge can still inspect these fields
via g_credentials_get_native() if desired.
Similarly, if SO_PASSCRED is used to receive a SCM_CREDENTIALS message
on a receiving Unix socket, but the sending socket had not enabled
SO_PASSCRED at the time that the message was sent, it is possible
for it to succeed but yield a credentials structure with pid 0, uid
/proc/sys/kernel/overflowuid and gid /proc/sys/kernel/overflowgid. Even
if we were to read those pseudo-files, we cannot distinguish between
the overflow IDs and a real process that legitimately has the same IDs
(typically they are set to 'nobody' and 'nogroup', which can be used
by a real process), so we detect this situation by noticing that
pid == 0, and to save syscalls we do not read the overflow IDs from
/proc at all.
This results in a small API change: g_credentials_is_same_user() now
returns FALSE if we compare two credentials structures that are both
invalid. This seems like reasonable, conservative behaviour: if we cannot
prove that they are the same user, we should assume they are not.
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gcredentials.c | 42 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)
diff --git a/gio/gcredentials.c b/gio/gcredentials.c
index c350e3c88..c4794ded7 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
--
2.23.0

@ -0,0 +1,654 @@
From fe823e3cfe25c96de5e453d1acbdc036892a9c36 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:07:50 +0100
Subject: [PATCH 1/4] codegen: Support Since and name changing annotations on
annotations
Recursive annotations do seem to be supported, so we should support them
properly in the type system representation. This currently introduces no
behavioural changes, but will be used in upcoming commits.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/dbustypes.py | 33 ++++++++++++++++++++++++++++++
1 file changed, 33 insertions(+)
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index 359880ff7..29222f987 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -27,6 +27,25 @@ class Annotation:
self.key = key
self.value = value
self.annotations = []
+ self.since = ''
+
+ def post_process(self, interface_prefix, cns, cns_upper, cns_lower, container):
+ key = self.key
+ overridden_key = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
+ if utils.is_ugly_case(overridden_key):
+ self.key_lower = overridden_key.lower()
+ else:
+ if overridden_key:
+ key = overridden_key
+ self.key_lower = utils.camel_case_to_uscore(key).lower().replace('-', '_').replace('.', '_')
+
+ if len(self.since) == 0:
+ self.since = utils.lookup_since(self.annotations)
+ if len(self.since) == 0:
+ self.since = container.since
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Arg:
def __init__(self, name, signature):
@@ -229,6 +248,8 @@ class Arg:
self.gvalue_get = 'g_value_get_boxed'
self.array_annotation = '(array zero-terminated=1)'
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
class Method:
def __init__(self, name):
@@ -270,6 +291,9 @@ class Method:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Signal:
def __init__(self, name):
self.name = name
@@ -305,6 +329,9 @@ class Signal:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
class Property:
def __init__(self, name, signature, access):
self.name = name
@@ -357,6 +384,9 @@ class Property:
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
# FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and
# http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
# for details
@@ -436,3 +466,6 @@ class Interface:
for p in self.properties:
p.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
+
+ for a in self.annotations:
+ a.post_process(interface_prefix, cns, cns_upper, cns_lower, self)
--
2.35.1
From dcb1c3fbd588dcf5cdcaeb65547fdbe176312e10 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:10:07 +0100
Subject: [PATCH 2/4] codegen: Add --interface-info-[body|header] modes
These generate basic .c and .h files containing the GDBusInterfaceInfo
for a D-Bus introspection XML file, but no other code (no skeletons,
proxies, GObjects, etc.).
This is useful for projects who want to describe their D-Bus interfaces
using introspection XML, but who wish to implement the interfaces
manually (for various reasons, typically because the skeletons generated
by gdbus-codegen are too simplistic and limiting). Previously, these
projects would have had to write the GDBusInterfaceInfo manually, which
is painstaking and error-prone.
The new --interface-info-[body|header] options are very similar to
--[body|header], but mutually exclusive with them.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
docs/reference/gio/gdbus-codegen.xml | 65 +++++-
gio/gdbus-2.0/codegen/codegen.py | 280 ++++++++++++++++++++++++++
gio/gdbus-2.0/codegen/codegen_main.py | 39 ++++
3 files changed, 377 insertions(+), 7 deletions(-)
diff --git a/docs/reference/gio/gdbus-codegen.xml b/docs/reference/gio/gdbus-codegen.xml
index b1145e5ef..3e1a9d668 100644
--- a/docs/reference/gio/gdbus-codegen.xml
+++ b/docs/reference/gio/gdbus-codegen.xml
@@ -39,6 +39,8 @@
<arg><option>--xml-files</option> <replaceable>FILE</replaceable></arg>
<arg><option>--header</option></arg>
<arg><option>--body</option></arg>
+ <arg><option>--interface-info-header</option></arg>
+ <arg><option>--interface-info-body</option></arg>
<arg><option>--output</option> <replaceable>OUTFILE</replaceable></arg>
<group choice="plain" rep="repeat">
<arg>
@@ -69,7 +71,11 @@
arguments on the command line and generates output files.
It currently supports generating C source code (via
<option>--body</option>) or header (via <option>--header</option>)
- and Docbook XML (via <option>--generate-docbook</option>).
+ and Docbook XML (via <option>--generate-docbook</option>). Alternatively,
+ more restricted C source code and headers can be generated, which just
+ contain the interface information (as <type>GDBusInterfaceInfo</type>
+ structures) using <option>--interface-info-body</option> and
+ <option>--interface-info-header</option>.
</para>
</refsect1>
@@ -90,8 +96,11 @@
</para>
<para>
For C code generation either <option>--body</option> that
- generates source code, or <option>--header</option> that
- generates headers, can be used. These options must be used along with
+ generates source code, <option>--header</option> that
+ generates headers, <option>--interface-info-body</option> that generates
+ interface information source code, or
+ <option>--interface-info-header</option> that generates interface information
+ headers, can be used. These options must be used along with
<option>--output</option>, which is used to specify the file to output to.
</para>
<para>
@@ -282,8 +291,10 @@
Directory to output generated source to. Equivalent to changing directory before generation.
</para>
<para>
- This option cannot be used with neither <option>--body</option> nor
- <option>--header</option>, and <option>--output</option> must be used.
+ This option cannot be used with <option>--body</option>,
+ <option>--header</option>, <option>--interface-info-body</option> or
+ <option>--interface-info-header</option>; and
+ <option>--output</option> must be used.
</para>
</listitem>
@@ -321,12 +332,52 @@
</listitem>
</varlistentry>
+ <varlistentry>
+ <term><option>--interface-info-header</option></term>
+ <listitem>
+ <para>
+ If this option is passed, it will generate the header code for the
+ <type>GDBusInterfaceInfo</type> structures only and will write it to
+ the disk by using the path and file name provided by
+ <option>--output</option>.
+ </para>
+ <para>
+ Using <option>--generate-c-code</option>, <option>--generate-docbook</option> or
+ <option>--output-directory</option> are not allowed to be used along with
+ the <option>--interface-info-header</option> and
+ <option>--interface-info-body</option> options, because these options
+ are used to generate only one file.
+ </para>
+ </listitem>
+ </varlistentry>
+
+ <varlistentry>
+ <term><option>--interface-info-body</option></term>
+ <listitem>
+ <para>
+ If this option is passed, it will generate the source code for the
+ <type>GDBusInterfaceInfo</type> structures only and will write it to
+ the disk by using the path and file name provided by
+ <option>--output</option>.
+ </para>
+ <para>
+ Using <option>--generate-c-code</option>, <option>--generate-docbook</option> or
+ <option>--output-directory</option> are not allowed to be used along with
+ the <option>--interface-info-header</option> and
+ <option>--interface-info-body</option> options, because these options
+ are used to generate only one file.
+ </para>
+ </listitem>
+ </varlistentry>
+
<varlistentry>
<term><option>--output</option> <replaceable>OUTFILE</replaceable></term>
<listitem>
<para>
- The full path where the header (<option>--header</option>) or the source code
- (<option>--body</option>) will be written, using the path and filename provided by
+ The full path where the header (<option>--header</option>,
+ <option>--interface-info-header</option>) or the source code
+ (<option>--body</option>, <option>--interface-info-body</option>) will
+ be written, using the path and filename provided by
<option>--output</option>. The full path could be something like
<literal>$($OUTFILE).{c,h}</literal>.
</para>
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index 442bd3f5d..4e258332d 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -610,6 +610,286 @@ class HeaderCodeGenerator:
# ----------------------------------------------------------------------------------------------------
+class InterfaceInfoHeaderCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, use_pragma, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_guard = header_name.upper().replace('.', '_').replace('-', '_').replace('/', '_').replace(':', '_')
+ self.use_pragma = use_pragma
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+
+ if self.use_pragma:
+ self.outfile.write('#pragma once\n')
+ else:
+ self.outfile.write('#ifndef __{!s}__\n'.format(self.header_guard))
+ self.outfile.write('#define __{!s}__\n'.format(self.header_guard))
+
+ self.outfile.write('\n')
+ self.outfile.write('#include <gio/gio.h>\n')
+ self.outfile.write('\n')
+ self.outfile.write('G_BEGIN_DECLS\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def declare_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('extern const GDBusInterfaceInfo %s_interface;\n' % i.name_lower)
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_header_postamble(self):
+ self.outfile.write('\n')
+ self.outfile.write('G_END_DECLS\n')
+
+ if not self.use_pragma:
+ self.outfile.write('\n')
+ self.outfile.write('#endif /* __{!s}__ */\n'.format(self.header_guard))
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_header_preamble()
+ self.declare_infos()
+ self.generate_header_postamble()
+
+# ----------------------------------------------------------------------------------------------------
+
+class InterfaceInfoBodyCodeGenerator:
+ def __init__(self, ifaces, namespace, header_name, outfile):
+ self.ifaces = ifaces
+ self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace)
+ self.header_name = header_name
+ self.outfile = outfile
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_body_preamble(self):
+ self.outfile.write(LICENSE_STR.format(config.VERSION))
+ self.outfile.write('\n')
+ self.outfile.write('#ifdef HAVE_CONFIG_H\n'
+ '# include "config.h"\n'
+ '#endif\n'
+ '\n'
+ '#include "%s"\n'
+ '\n'
+ '#include <string.h>\n'
+ % (self.header_name))
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate_array(self, array_name_lower, element_type, elements):
+ self.outfile.write('const %s * const %s[] =\n' % (element_type, array_name_lower))
+ self.outfile.write('{\n')
+ for (_, name) in sorted(elements, key=utils.version_cmp_key):
+ self.outfile.write(' &%s,\n' % name)
+ self.outfile.write(' NULL,\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ def define_annotations(self, array_name_lower, annotations):
+ if len(annotations) == 0:
+ return
+
+ annotation_pointers = []
+
+ for a in annotations:
+ # Skip internal annotations.
+ if a.key.startswith('org.gtk.GDBus'):
+ continue
+
+ self.define_annotations('%s__%s_annotations' % (array_name_lower, a.key_lower), a.annotations)
+
+ self.outfile.write('const GDBusAnnotationInfo %s__%s_annotation =\n' % (array_name_lower, a.key_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.key)
+ self.outfile.write(' (gchar *) "%s",\n' % a.value)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_annotations,\n' % (array_name_lower, a.key_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_annotation' % (array_name_lower, a.key_lower))
+ annotation_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusAnnotationInfo',
+ annotation_pointers)
+
+ def define_args(self, array_name_lower, args):
+ if len(args) == 0:
+ return
+
+ arg_pointers = []
+
+ for a in args:
+ self.define_annotations('%s__%s_arg_annotations' % (array_name_lower, a.name), a.annotations)
+
+ self.outfile.write('const GDBusArgInfo %s__%s_arg =\n' % (array_name_lower, a.name))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % a.name)
+ self.outfile.write(' (gchar *) "%s",\n' % a.signature)
+ if len(a.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s__%s_arg_annotations,\n' % (array_name_lower, a.name))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (a.since, '%s__%s_arg' % (array_name_lower, a.name))
+ arg_pointers.append(key)
+
+ self.generate_array(array_name_lower, 'GDBusArgInfo', arg_pointers)
+
+ def define_infos(self):
+ for i in self.ifaces:
+ self.outfile.write('/* ------------------------------------------------------------------------ */\n')
+ self.outfile.write('/* Definitions for %s */\n' % i.name)
+ self.outfile.write('\n')
+
+ # GDBusMethodInfos.
+ if len(i.methods) > 0:
+ method_pointers = []
+
+ for m in i.methods:
+ self.define_args('%s_interface__%s_method_in_args' % (i.name_lower, m.name_lower), m.in_args)
+ self.define_args('%s_interface__%s_method_out_args' % (i.name_lower, m.name_lower), m.out_args)
+ self.define_annotations('%s_interface__%s_method_annotations' % (i.name_lower, m.name_lower), m.annotations)
+
+ self.outfile.write('const GDBusMethodInfo %s_interface__%s_method =\n' % (i.name_lower, m.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % m.name)
+ if len(m.in_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_in_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no in args */\n')
+ if len(m.out_args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_method_out_args,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no out args */\n')
+ if len(m.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_method_annotations,\n' % (i.name_lower, m.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_method' % (i.name_lower, m.name_lower))
+ method_pointers.append(key)
+
+ self.generate_array('%s_interface_methods' % i.name_lower,
+ 'GDBusMethodInfo', method_pointers)
+
+ # GDBusSignalInfos.
+ if len(i.signals) > 0:
+ signal_pointers = []
+
+ for s in i.signals:
+ self.define_args('%s_interface__%s_signal_args' % (i.name_lower, s.name_lower), s.args)
+ self.define_annotations('%s_interface__%s_signal_annotations' % (i.name_lower, s.name_lower), s.annotations)
+
+ self.outfile.write('const GDBusSignalInfo %s_interface__%s_signal =\n' % (i.name_lower, s.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % s.name)
+ if len(s.args) > 0:
+ self.outfile.write(' (GDBusArgInfo **) %s_interface__%s_signal_args,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no args */\n')
+ if len(s.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_signal_annotations,\n' % (i.name_lower, s.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_signal' % (i.name_lower, s.name_lower))
+ signal_pointers.append(key)
+
+ self.generate_array('%s_interface_signals' % i.name_lower,
+ 'GDBusSignalInfo', signal_pointers)
+
+ # GDBusPropertyInfos.
+ if len(i.properties) > 0:
+ property_pointers = []
+
+ for p in i.properties:
+ if p.readable and p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ elif p.readable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
+ elif p.writable:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
+ else:
+ flags = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
+
+ self.define_annotations('%s_interface__%s_property_annotations' % (i.name_lower, p.name_lower), p.annotations)
+
+ self.outfile.write('const GDBusPropertyInfo %s_interface__%s_property =\n' % (i.name_lower, p.name_lower))
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % p.name)
+ self.outfile.write(' (gchar *) "%s",\n' % p.signature)
+ self.outfile.write(' %s,\n' % flags)
+ if len(p.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface__%s_property_annotations,\n' % (i.name_lower, p.name_lower))
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ key = (m.since, '%s_interface__%s_property' % (i.name_lower, p.name_lower))
+ property_pointers.append(key)
+
+ self.generate_array('%s_interface_properties' % i.name_lower,
+ 'GDBusPropertyInfo', property_pointers)
+
+ # Finally the GDBusInterfaceInfo.
+ self.define_annotations('%s_interface_annotations' % i.name_lower,
+ i.annotations)
+
+ self.outfile.write('const GDBusInterfaceInfo %s_interface =\n' % i.name_lower)
+ self.outfile.write('{\n')
+ self.outfile.write(' -1, /* ref count */\n')
+ self.outfile.write(' (gchar *) "%s",\n' % i.name)
+ if len(i.methods) > 0:
+ self.outfile.write(' (GDBusMethodInfo **) %s_interface_methods,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no methods */\n')
+ if len(i.signals) > 0:
+ self.outfile.write(' (GDBusSignalInfo **) %s_interface_signals,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no signals */\n')
+ if len(i.properties) > 0:
+ self.outfile.write(' (GDBusPropertyInfo **) %s_interface_properties,\n' % i.name_lower)
+ else:
+ self.outfile.write( 'NULL, /* no properties */\n')
+ if len(i.annotations) > 0:
+ self.outfile.write(' (GDBusAnnotationInfo **) %s_interface_annotations,\n' % i.name_lower)
+ else:
+ self.outfile.write(' NULL, /* no annotations */\n')
+ self.outfile.write('};\n')
+ self.outfile.write('\n')
+
+ # ----------------------------------------------------------------------------------------------------
+
+ def generate(self):
+ self.generate_body_preamble()
+ self.define_infos()
+
+# ----------------------------------------------------------------------------------------------------
+
class CodeGenerator:
def __init__(self, ifaces, namespace, generate_objmanager, header_name,
docbook_gen, outfile):
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index 1cfe7c1bb..37efb3bcf 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -175,6 +175,10 @@ def codegen_main():
help='Generate C headers')
group.add_argument('--body', action='store_true',
help='Generate C code')
+ group.add_argument('--interface-info-header', action='store_true',
+ help='Generate GDBusInterfaceInfo C header')
+ group.add_argument('--interface-info-body', action='store_true',
+ help='Generate GDBusInterfaceInfo C code')
group = arg_parser.add_mutually_exclusive_group()
group.add_argument('--output', metavar='FILE',
@@ -210,6 +214,24 @@ def codegen_main():
c_file = args.output
header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
+ elif args.interface_info_header:
+ if args.output is None:
+ print_error('Using --interface-info-header requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-header')
+
+ h_file = args.output
+ header_name = os.path.basename(h_file)
+ elif args.interface_info_body:
+ if args.output is None:
+ print_error('Using --interface-info-body requires --output')
+ if args.c_generate_object_manager:
+ print_error('--c-generate-object-manager is incompatible with '
+ '--interface-info-body')
+
+ c_file = args.output
+ header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h'
all_ifaces = []
for fname in args.files + args.xml_files:
@@ -250,6 +272,23 @@ def codegen_main():
outfile)
gen.generate()
+ if args.interface_info_header:
+ with open(h_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoHeaderCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ args.pragma_once,
+ outfile)
+ gen.generate()
+
+ if args.interface_info_body:
+ with open(c_file, 'w') as outfile:
+ gen = codegen.InterfaceInfoBodyCodeGenerator(all_ifaces,
+ args.c_namespace,
+ header_name,
+ outfile)
+ gen.generate()
+
sys.exit(0)
if __name__ == "__main__":
--
2.35.1
From 11de9adfe6f57521ea5ed881b6862480c742414c Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:12:18 +0100
Subject: [PATCH 3/4] codegen: Suppress the old --xml-files option in the
--help output
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Since its deprecated in favour of positional arguments, including it in
the help output is confusing.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/codegen_main.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index 37efb3bcf..d3763eb0f 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -152,7 +152,7 @@ def codegen_main():
arg_parser.add_argument('files', metavar='FILE', nargs='*',
help='D-Bus introspection XML file')
arg_parser.add_argument('--xml-files', metavar='FILE', action='append', default=[],
- help='D-Bus introspection XML file')
+ help=argparse.SUPPRESS)
arg_parser.add_argument('--interface-prefix', metavar='PREFIX', default='',
help='String to strip from D-Bus interface names for code and docs')
arg_parser.add_argument('--c-namespace', metavar='NAMESPACE', default='',
--
2.35.1
From b2b72837b0545e297db7ded8773377b4b6473a55 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Tue, 17 Apr 2018 14:13:05 +0100
Subject: [PATCH 4/4] codegen: Fix a minor Python linting warning
This introduces no functional changes.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://bugzilla.gnome.org/show_bug.cgi?id=795304
---
gio/gdbus-2.0/codegen/codegen_main.py | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py
index d3763eb0f..fa9c71373 100755
--- a/gio/gdbus-2.0/codegen/codegen_main.py
+++ b/gio/gdbus-2.0/codegen/codegen_main.py
@@ -240,7 +240,7 @@ def codegen_main():
parsed_ifaces = parser.parse_dbus_xml(xml_data)
all_ifaces.extend(parsed_ifaces)
- if args.annotate != None:
+ if args.annotate is not None:
apply_annotations(all_ifaces, args.annotate)
for i in all_ifaces:
--
2.35.1

@ -0,0 +1,38 @@
From a18f091c6c090b93cd816f8cd5be763b6e238632 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 7 Feb 2020 17:10:23 +0000
Subject: [PATCH] libcharset: Drop a redundant environment variable
It was used for running tests when we built with autotools, but is no
longer used in the Meson build system. If we need something similar in
future, it should be done by adding internal API to override the
directory on a per-call basis, rather than loading a path from a shared
global table every time.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #1919
---
glib/libcharset/localcharset.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/glib/libcharset/localcharset.c b/glib/libcharset/localcharset.c
index 0c4d544be..ab3a2678d 100644
--- a/glib/libcharset/localcharset.c
+++ b/glib/libcharset/localcharset.c
@@ -117,11 +117,7 @@ _g_locale_get_charset_aliases (void)
const char *base = "charset.alias";
char *file_name;
- /* Make it possible to override the charset.alias location. This is
- necessary for running the testsuite before "make install". */
- dir = getenv ("CHARSETALIASDIR");
- if (dir == NULL || dir[0] == '\0')
- dir = relocate (GLIB_CHARSETALIAS_DIR);
+ dir = relocate (GLIB_CHARSETALIAS_DIR);
/* Concatenate dir and base into freshly allocated file_name. */
{
--
2.31.1

@ -0,0 +1,401 @@
From d0821da5244fd08c756a5f84ec0d3063c72d1ac6 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 26 Apr 2018 10:36:36 +0200
Subject: [PATCH] gio: Add g_unix_mount_get_options
GVfsUDisks2VolumeMonitor handles x-gvfs-hide/x-gvfs-show mount options
used to overwrite our heuristics whether the mount should be shown, or
hidden. Unfortunately, it works currently only for mounts with
corresponding fstab entries, because the options are read over
g_unix_mount_point_get_options. Let's introduce g_unix_mount_get_options
to allow reading of the options for all sort of mounts (e.g. created
over pam_mount, or manually mounted).
(Minor fixes to the documentation by Philip Withnall
<withnall@endlessm.com>.)
https://bugzilla.gnome.org/show_bug.cgi?id=668132
---
docs/reference/gio/gio-sections.txt | 1 +
gio/gunixmounts.c | 37 +++++++++++++++++++++++++++++
gio/gunixmounts.h | 2 ++
3 files changed, 40 insertions(+)
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 2eb7efc748..0a35f9541b 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1546,6 +1546,7 @@ g_unix_mount_copy
g_unix_mount_get_mount_path
g_unix_mount_get_device_path
g_unix_mount_get_fs_type
+g_unix_mount_get_options
g_unix_mount_is_readonly
g_unix_mount_is_system_internal
g_unix_mount_guess_icon
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index c74b0cfaf4..f2db27e661 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -126,6 +126,7 @@ struct _GUnixMountEntry {
char *mount_path;
char *device_path;
char *filesystem_type;
+ char *options;
gboolean is_read_only;
gboolean is_system_internal;
};
@@ -412,6 +413,7 @@ static GUnixMountEntry *
create_unix_mount_entry (const char *device_path,
const char *mount_path,
const char *filesystem_type,
+ const char *options,
gboolean is_read_only)
{
GUnixMountEntry *mount_entry = NULL;
@@ -420,6 +422,7 @@ create_unix_mount_entry (const char *device_path,
mount_entry->device_path = g_strdup (device_path);
mount_entry->mount_path = g_strdup (mount_path);
mount_entry->filesystem_type = g_strdup (filesystem_type);
+ mount_entry->options = g_strdup (options);
mount_entry->is_read_only = is_read_only;
mount_entry->is_system_internal =
@@ -498,6 +501,7 @@ _g_get_unix_mounts (void)
mount_entry = create_unix_mount_entry (device_path,
mnt_fs_get_target (fs),
mnt_fs_get_fstype (fs),
+ mnt_fs_get_options (fs),
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
@@ -592,6 +596,7 @@ _g_get_unix_mounts (void)
mount_entry = create_unix_mount_entry (device_path,
mntent->mnt_dir,
mntent->mnt_type,
+ mntent->mnt_opts,
is_read_only);
g_hash_table_insert (mounts_hash,
@@ -705,6 +710,7 @@ _g_get_unix_mounts (void)
mount_entry = create_unix_mount_entry (mntent.mnt_special,
mntent.mnt_mountp,
mntent.mnt_fstype,
+ mntent.mnt_opts,
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
@@ -771,6 +777,7 @@ _g_get_unix_mounts (void)
mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT),
vmt2dataptr (vmount_info, VMT_STUB),
fs_info == NULL ? "unknown" : fs_info->vfsent_name,
+ NULL,
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
@@ -846,6 +853,7 @@ _g_get_unix_mounts (void)
mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname,
mntent[i].f_mntonname,
mntent[i].f_fstypename,
+ NULL,
is_read_only);
return_list = g_list_prepend (return_list, mount_entry);
@@ -1989,6 +1997,7 @@ g_unix_mount_free (GUnixMountEntry *mount_entry)
g_free (mount_entry->mount_path);
g_free (mount_entry->device_path);
g_free (mount_entry->filesystem_type);
+ g_free (mount_entry->options);
g_free (mount_entry);
}
@@ -2013,6 +2022,7 @@ g_unix_mount_copy (GUnixMountEntry *mount_entry)
copy->mount_path = g_strdup (mount_entry->mount_path);
copy->device_path = g_strdup (mount_entry->device_path);
copy->filesystem_type = g_strdup (mount_entry->filesystem_type);
+ copy->options = g_strdup (mount_entry->options);
copy->is_read_only = mount_entry->is_read_only;
copy->is_system_internal = mount_entry->is_system_internal;
@@ -2096,6 +2106,10 @@ g_unix_mount_compare (GUnixMountEntry *mount1,
if (res != 0)
return res;
+ res = g_strcmp0 (mount1->options, mount2->options);
+ if (res != 0)
+ return res;
+
res = mount1->is_read_only - mount2->is_read_only;
if (res != 0)
return res;
@@ -2151,6 +2165,29 @@ g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry)
return mount_entry->filesystem_type;
}
+/**
+ * g_unix_mount_get_options:
+ * @mount_entry: a #GUnixMountEntry.
+ *
+ * Gets a comma-separated list of mount options for the unix mount. For example,
+ * `rw,relatime,seclabel,data=ordered`.
+ *
+ * This is similar to g_unix_mount_point_get_options(), but it takes
+ * a #GUnixMountEntry as an argument.
+ *
+ * Returns: (nullable): a string containing the options, or %NULL if not
+ * available.
+ *
+ * Since: 2.58
+ */
+const gchar *
+g_unix_mount_get_options (GUnixMountEntry *mount_entry)
+{
+ g_return_val_if_fail (mount_entry != NULL, NULL);
+
+ return mount_entry->options;
+}
+
/**
* g_unix_mount_is_readonly:
* @mount_entry: a #GUnixMount.
diff --git a/gio/gunixmounts.h b/gio/gunixmounts.h
index 04d6b0726b..a392d497f1 100644
--- a/gio/gunixmounts.h
+++ b/gio/gunixmounts.h
@@ -81,6 +81,8 @@ GLIB_AVAILABLE_IN_ALL
const char * g_unix_mount_get_device_path (GUnixMountEntry *mount_entry);
GLIB_AVAILABLE_IN_ALL
const char * g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry);
+GLIB_AVAILABLE_IN_2_56
+const char * g_unix_mount_get_options (GUnixMountEntry *mount_entry);
GLIB_AVAILABLE_IN_ALL
gboolean g_unix_mount_is_readonly (GUnixMountEntry *mount_entry);
GLIB_AVAILABLE_IN_ALL
--
GitLab
From 51ec01382137251e08948bbd860a5fbfde41e5ba Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 23 Jun 2020 08:23:16 +0200
Subject: [PATCH 1/2] gunixmounts: Add g_unix_mount_point_at
There is already g_unix_mount_at function which allows to find certain
unix mount for given mount path. It would be useful to have similar
function for mount points, which will allow to replace custom codes in
gvfs. Let's add g_unix_mount_point_at.
---
docs/reference/gio/gio-sections.txt | 1 +
gio/gunixmounts.c | 46 +++++++++++++++++++++++++++++
gio/gunixmounts.h | 3 ++
3 files changed, 50 insertions(+)
diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 2eb7efc74..5c9cbc34c 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -1568,6 +1568,7 @@ g_unix_mount_point_guess_symbolic_icon
g_unix_mount_point_guess_name
g_unix_mount_point_guess_can_eject
g_unix_mount_points_get
+g_unix_mount_point_at
g_unix_mounts_get
g_unix_mount_at
g_unix_mounts_changed_since
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index 4d19217ca..144da4d29 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -1596,6 +1596,52 @@ g_unix_mount_points_get (guint64 *time_read)
return _g_get_unix_mount_points ();
}
+/**
+ * g_unix_mount_point_at:
+ * @mount_path: (type filename): path for a possible unix mount point.
+ * @time_read: (out) (optional): guint64 to contain a timestamp.
+ *
+ * Gets a #GUnixMountPoint for a given mount path. If @time_read is set, it
+ * will be filled with a unix timestamp for checking if the mount points have
+ * changed since with g_unix_mount_points_changed_since().
+ *
+ * If more mount points have the same mount path, the last matching mount point
+ * is returned.
+ *
+ * Returns: (transfer full) (nullable): a #GUnixMountPoint, or %NULL if no match
+ * is found.
+ *
+ * Since: 2.66
+ **/
+GUnixMountPoint *
+g_unix_mount_point_at (const char *mount_path,
+ guint64 *time_read)
+{
+ GList *mount_points, *l;
+ GUnixMountPoint *mount_point, *found;
+
+ mount_points = g_unix_mount_points_get (time_read);
+
+ found = NULL;
+ for (l = mount_points; l != NULL; l = l->next)
+ {
+ mount_point = l->data;
+
+ if (strcmp (mount_path, mount_point->mount_path) == 0)
+ {
+ if (found != NULL)
+ g_unix_mount_point_free (found);
+
+ found = mount_point;
+ }
+ else
+ g_unix_mount_point_free (mount_point);
+ }
+ g_list_free (mount_points);
+
+ return found;
+}
+
/**
* g_unix_mounts_changed_since:
* @time: guint64 to contain a timestamp.
diff --git a/gio/gunixmounts.h b/gio/gunixmounts.h
index 04d6b0726..ab9d3dbb9 100644
--- a/gio/gunixmounts.h
+++ b/gio/gunixmounts.h
@@ -128,6 +128,9 @@ GIcon * g_unix_mount_point_guess_symbolic_icon (GUnixMountPoint *mount
GLIB_AVAILABLE_IN_ALL
GList * g_unix_mount_points_get (guint64 *time_read);
+GLIB_AVAILABLE_IN_2_56
+GUnixMountPoint *g_unix_mount_point_at (const char *mount_path,
+ guint64 *time_read);
GLIB_AVAILABLE_IN_ALL
GList * g_unix_mounts_get (guint64 *time_read);
GLIB_AVAILABLE_IN_ALL
--
2.41.0
From 6daee34fac29df6f182e7e2aa656e0b34bd916a5 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Tue, 23 Jun 2020 08:36:26 +0200
Subject: [PATCH 2/2] gfile: Add support for x-gvfs-notrash option to ignore
mounts
Add support for x-gvfs-notrash mount option, which allows to disable
trash functionality for certain mounts. This might be especially useful
e.g. to prevent trash folder creation on enterprise shares, which are
also accessed from Windows...
https://bugzilla.redhat.com/show_bug.cgi?id=1096200
---
gio/gfile.c | 4 ++-
gio/glocalfile.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 66 insertions(+), 2 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 447da3cfb..43c5c3d74 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -4166,7 +4166,9 @@ g_file_delete_finish (GFile *file,
* Sends @file to the "Trashcan", if possible. This is similar to
* deleting it, but the user can recover it before emptying the trashcan.
* Not all file systems support trashing, so this call can return the
- * %G_IO_ERROR_NOT_SUPPORTED error.
+ * %G_IO_ERROR_NOT_SUPPORTED error. Since GLib 2.66, the `x-gvfs-notrash` unix
+ * mount option can be used to disable g_file_trash() support for certain
+ * mounts, the %G_IO_ERROR_NOT_SUPPORTED error will be returned in that case.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index e7481454e..cb0ecdafb 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -1858,6 +1858,52 @@ try_make_relative (const char *path,
return g_strdup (path);
}
+static gboolean
+ignore_trash_mount (GUnixMountEntry *mount)
+{
+ GUnixMountPoint *mount_point = NULL;
+ const gchar *mount_options;
+ gboolean retval = TRUE;
+
+ if (g_unix_mount_is_system_internal (mount))
+ return TRUE;
+
+ mount_options = g_unix_mount_get_options (mount);
+ if (mount_options == NULL)
+ {
+ mount_point = g_unix_mount_point_at (g_unix_mount_get_mount_path (mount),
+ NULL);
+ if (mount_point != NULL)
+ mount_options = g_unix_mount_point_get_options (mount_point);
+ }
+
+ if (mount_options == NULL ||
+ strstr (mount_options, "x-gvfs-notrash") == NULL)
+ retval = FALSE;
+
+ g_clear_pointer (&mount_point, g_unix_mount_point_free);
+
+ return retval;
+}
+
+static gboolean
+ignore_trash_path (const gchar *topdir)
+{
+ GUnixMountEntry *mount;
+ gboolean retval = TRUE;
+
+ mount = g_unix_mount_at (topdir, NULL);
+ if (mount == NULL)
+ goto out;
+
+ retval = ignore_trash_mount (mount);
+
+ out:
+ g_clear_pointer (&mount, g_unix_mount_free);
+
+ return retval;
+}
+
gboolean
_g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
{
@@ -1886,6 +1932,13 @@ _g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
if (topdir == NULL)
return FALSE;
+ if (ignore_trash_path (topdir))
+ {
+ g_free (topdir);
+
+ return FALSE;
+ }
+
globaldir = g_build_filename (topdir, ".Trash", NULL);
if (g_lstat (globaldir, &global_stat) == 0 &&
S_ISDIR (global_stat.st_mode) &&
@@ -2041,7 +2094,16 @@ g_local_file_trash (GFile *file,
file, G_IO_ERROR_NOT_SUPPORTED);
return FALSE;
}
-
+
+ if (ignore_trash_path (topdir))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Trashing on system internal mounts is not supported"));
+ g_free (topdir);
+
+ return FALSE;
+ }
+
/* Try looking for global trash dir $topdir/.Trash/$uid */
globaldir = g_build_filename (topdir, ".Trash", NULL);
if (g_lstat (globaldir, &global_stat) == 0 &&
--
2.41.0

@ -0,0 +1,204 @@
From 4f0a31d66c2a6588495b8ae682f555584dafdf45 Mon Sep 17 00:00:00 2001
From: Claudio Saavedra <csaavedra@igalia.com>
Date: Wed, 21 Oct 2020 13:19:42 +0300
Subject: [PATCH] gmain: g_main_context_check() can skip updating polled FD
sources
If there is a file descriptor source that has a lower priority
than the one for sources that are going to be dispatched,
all subsequent file descriptor sources (internally sorted by
file descriptor identifier) do not get an update in their GPollRec
and later on wrong sources can be dispatched.
Fix this by first finding the first GPollRec that matches the current
GPollFD, instead of relying on it to be the current one. At
the same time, document the assumptions about the ordering of the
file descriptor records and array and make explicit in the documentation
that the array needs to be passed to g_main_context_check() as it was
received from g_main_context_query().
Added a new test that reproduces the bug by creating two file
descriptor sources and an idle one. Since the first
file descriptor created has a lower identifier and a low priority,
the second one is not dispatched even when it has the same, higher,
priority as the idle source. After fixing this bug, both
higher priority sources are dispatched as expected.
While this patch was written independently, a similar fix for this
bug was first submitted by Eugene M in GNOME/glib!562. Having a
second fix that basically does the same is a reassurance that we
are in the right here.
Fixes #1592
---
glib/gmain.c | 32 ++++++++++++++++++++++--
glib/tests/mainloop.c | 57 +++++++++++++++++++++++++++++++++++++++++++
2 files changed, 87 insertions(+), 2 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 95992253d..a59cd686c 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -3573,7 +3573,10 @@ g_main_context_prepare (GMainContext *context,
* store #GPollFD records that need to be polled.
* @n_fds: (in): length of @fds.
*
- * Determines information necessary to poll this main loop.
+ * Determines information necessary to poll this main loop. You should
+ * be careful to pass the resulting @fds array and its length @n_fds
+ * as is when calling g_main_context_check(), as this function relies
+ * on assumptions made when the array is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@@ -3597,6 +3600,10 @@ g_main_context_query (GMainContext *context,
TRACE (GLIB_MAIN_CONTEXT_BEFORE_QUERY (context, max_priority));
+ /* fds is filled sequentially from poll_records. Since poll_records
+ * are incrementally sorted by file descriptor identifier, fds will
+ * also be incrementally sorted.
+ */
n_poll = 0;
lastpollrec = NULL;
for (pollrec = context->poll_records; pollrec; pollrec = pollrec->next)
@@ -3611,6 +3618,10 @@ g_main_context_query (GMainContext *context,
*/
events = pollrec->fd->events & ~(G_IO_ERR|G_IO_HUP|G_IO_NVAL);
+ /* This optimization --using the same GPollFD to poll for more
+ * than one poll record-- relies on the poll records being
+ * incrementally sorted.
+ */
if (lastpollrec && pollrec->fd->fd == lastpollrec->fd->fd)
{
if (n_poll - 1 < n_fds)
@@ -3656,7 +3667,10 @@ g_main_context_query (GMainContext *context,
* the last call to g_main_context_query()
* @n_fds: return value of g_main_context_query()
*
- * Passes the results of polling back to the main loop.
+ * Passes the results of polling back to the main loop. You should be
+ * careful to pass @fds and its length @n_fds as received from
+ * g_main_context_query(), as this functions relies on assumptions
+ * on how @fds is filled.
*
* You must have successfully acquired the context with
* g_main_context_acquire() before you may call this function.
@@ -3711,10 +3725,22 @@ g_main_context_check (GMainContext *context,
return FALSE;
}
+ /* The linear iteration below relies on the assumption that both
+ * poll records and the fds array are incrementally sorted by file
+ * descriptor identifier.
+ */
pollrec = context->poll_records;
i = 0;
while (pollrec && i < n_fds)
{
+ /* Make sure that fds is sorted by file descriptor identifier. */
+ g_assert (i <= 0 || fds[i - 1].fd < fds[i].fd);
+
+ /* Skip until finding the first GPollRec matching the current GPollFD. */
+ while (pollrec && pollrec->fd->fd != fds[i].fd)
+ pollrec = pollrec->next;
+
+ /* Update all consecutive GPollRecs that match. */
while (pollrec && pollrec->fd->fd == fds[i].fd)
{
if (pollrec->priority <= max_priority)
@@ -3725,6 +3751,7 @@ g_main_context_check (GMainContext *context,
pollrec = pollrec->next;
}
+ /* Iterate to next GPollFD. */
i++;
}
@@ -4320,6 +4347,7 @@ g_main_context_add_poll_unlocked (GMainContext *context,
newrec->fd = fd;
newrec->priority = priority;
+ /* Poll records are incrementally sorted by file descriptor identifier. */
prevrec = NULL;
nextrec = context->poll_records;
while (nextrec)
diff --git a/glib/tests/mainloop.c b/glib/tests/mainloop.c
index f5d672a63..397921f2d 100644
--- a/glib/tests/mainloop.c
+++ b/glib/tests/mainloop.c
@@ -1511,6 +1511,62 @@ test_unix_file_poll (void)
close (fd);
}
+static void
+test_unix_fd_priority (void)
+{
+ gint fd1, fd2;
+ GMainLoop *loop;
+ GSource *source;
+
+ gint s1 = 0;
+ gboolean s2 = FALSE, s3 = FALSE;
+
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/1592");
+
+ loop = g_main_loop_new (NULL, FALSE);
+
+ source = g_idle_source_new ();
+ g_source_set_callback (source, count_calls, &s1, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd1 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd1, >=, 0);
+ source = g_unix_fd_source_new (fd1, G_IO_IN);
+ g_source_set_callback (source, (GSourceFunc) (void (*)(void)) (flag_bool), &s2, NULL);
+ g_source_set_priority (source, 10);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ fd2 = open ("/dev/random", O_RDONLY);
+ g_assert_cmpint (fd2, >=, 0);
+ source = g_unix_fd_source_new (fd2, G_IO_IN);
+ g_source_set_callback (source, (GSourceFunc) (void (*)(void)) (flag_bool), &s3, NULL);
+ g_source_set_priority (source, 0);
+ g_source_attach (source, NULL);
+ g_source_unref (source);
+
+ /* This tests a bug that depends on the source with the lowest FD
+ identifier to have the lowest priority. Make sure that this is
+ the case. */
+ g_assert_cmpint (fd1, <, fd2);
+
+ g_assert_true (g_main_context_iteration (NULL, FALSE));
+
+ /* Idle source should have been dispatched. */
+ g_assert_cmpint (s1, ==, 1);
+ /* Low priority FD source shouldn't have been dispatched. */
+ g_assert_false (s2);
+ /* Default priority FD source should have been dispatched. */
+ g_assert_true (s3);
+
+ g_main_loop_unref (loop);
+
+ close (fd1);
+ close (fd2);
+}
+
#endif
static gboolean
@@ -1751,6 +1807,7 @@ main (int argc, char *argv[])
g_test_add_func ("/mainloop/source-unix-fd-api", test_source_unix_fd_api);
g_test_add_func ("/mainloop/wait", test_mainloop_wait);
g_test_add_func ("/mainloop/unix-file-poll", test_unix_file_poll);
+ g_test_add_func ("/mainloop/unix-fd-priority", test_unix_fd_priority);
#endif
g_test_add_func ("/mainloop/nfds", test_nfds);
--
2.31.1

@ -1,222 +0,0 @@
From 1248b642ad32b0bdf296211c1a0a8817bebf1c66 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 25 Feb 2021 10:35:36 +0000
Subject: [PATCH 1/2] gversionmacros: Add version macros for GLib 2.70
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
docs/reference/gio/gio-docs.xml | 4 +++
docs/reference/glib/glib-docs.xml | 4 +++
docs/reference/glib/glib-sections.txt | 14 ++++++++
docs/reference/gobject/gobject-docs.xml | 4 +++
docs/reference/meson.build | 2 +-
glib/gversionmacros.h | 44 +++++++++++++++++++++++++
6 files changed, 71 insertions(+), 1 deletion(-)
diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index 9cd3d0e39..a09d6d31d 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -389,6 +389,10 @@
<title>Index of new symbols in 2.68</title>
<xi:include href="xml/api-index-2.68.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-2-70" role="2.70">
+ <title>Index of new symbols in 2.70</title>
+ <xi:include href="xml/api-index-2.70.xml"><xi:fallback /></xi:include>
+ </index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml
index e464fb792..2f5de9e31 100644
--- a/docs/reference/glib/glib-docs.xml
+++ b/docs/reference/glib/glib-docs.xml
@@ -288,6 +288,10 @@
<title>Index of new symbols in 2.68</title>
<xi:include href="xml/api-index-2.68.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-2-70" role="2.70">
+ <title>Index of new symbols in 2.70</title>
+ <xi:include href="xml/api-index-2.70.xml"><xi:fallback /></xi:include>
+ </index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 460a299bf..75994e889 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -138,6 +138,7 @@ GLIB_VERSION_2_62
GLIB_VERSION_2_64
GLIB_VERSION_2_66
GLIB_VERSION_2_68
+GLIB_VERSION_2_70
GLIB_VERSION_CUR_STABLE
GLIB_VERSION_PREV_STABLE
GLIB_VERSION_MIN_REQUIRED
@@ -168,6 +169,7 @@ GLIB_AVAILABLE_ENUMERATOR_IN_2_62
GLIB_AVAILABLE_ENUMERATOR_IN_2_64
GLIB_AVAILABLE_ENUMERATOR_IN_2_66
GLIB_AVAILABLE_ENUMERATOR_IN_2_68
+GLIB_AVAILABLE_ENUMERATOR_IN_2_70
GLIB_AVAILABLE_IN_ALL
GLIB_AVAILABLE_IN_2_26
GLIB_AVAILABLE_IN_2_28
@@ -191,6 +193,7 @@ GLIB_AVAILABLE_IN_2_62
GLIB_AVAILABLE_IN_2_64
GLIB_AVAILABLE_IN_2_66
GLIB_AVAILABLE_IN_2_68
+GLIB_AVAILABLE_IN_2_70
GLIB_AVAILABLE_MACRO_IN_2_26
GLIB_AVAILABLE_MACRO_IN_2_28
GLIB_AVAILABLE_MACRO_IN_2_30
@@ -213,12 +216,14 @@ GLIB_AVAILABLE_MACRO_IN_2_62
GLIB_AVAILABLE_MACRO_IN_2_64
GLIB_AVAILABLE_MACRO_IN_2_66
GLIB_AVAILABLE_MACRO_IN_2_68
+GLIB_AVAILABLE_MACRO_IN_2_70
GLIB_AVAILABLE_STATIC_INLINE_IN_2_44
GLIB_AVAILABLE_STATIC_INLINE_IN_2_60
GLIB_AVAILABLE_STATIC_INLINE_IN_2_62
GLIB_AVAILABLE_STATIC_INLINE_IN_2_64
GLIB_AVAILABLE_STATIC_INLINE_IN_2_66
GLIB_AVAILABLE_STATIC_INLINE_IN_2_68
+GLIB_AVAILABLE_STATIC_INLINE_IN_2_70
GLIB_AVAILABLE_TYPE_IN_2_26
GLIB_AVAILABLE_TYPE_IN_2_28
GLIB_AVAILABLE_TYPE_IN_2_30
@@ -241,6 +246,7 @@ GLIB_AVAILABLE_TYPE_IN_2_62
GLIB_AVAILABLE_TYPE_IN_2_64
GLIB_AVAILABLE_TYPE_IN_2_66
GLIB_AVAILABLE_TYPE_IN_2_68
+GLIB_AVAILABLE_TYPE_IN_2_70
GLIB_DEPRECATED_ENUMERATOR
GLIB_DEPRECATED_ENUMERATOR_FOR
GLIB_DEPRECATED_ENUMERATOR_IN_2_26
@@ -287,6 +293,8 @@ GLIB_DEPRECATED_ENUMERATOR_IN_2_66
GLIB_DEPRECATED_ENUMERATOR_IN_2_66_FOR
GLIB_DEPRECATED_ENUMERATOR_IN_2_68
GLIB_DEPRECATED_ENUMERATOR_IN_2_68_FOR
+GLIB_DEPRECATED_ENUMERATOR_IN_2_70
+GLIB_DEPRECATED_ENUMERATOR_IN_2_70_FOR
GLIB_DEPRECATED_IN_2_26
GLIB_DEPRECATED_IN_2_26_FOR
GLIB_DEPRECATED_IN_2_28
@@ -331,6 +339,8 @@ GLIB_DEPRECATED_IN_2_66
GLIB_DEPRECATED_IN_2_66_FOR
GLIB_DEPRECATED_IN_2_68
GLIB_DEPRECATED_IN_2_68_FOR
+GLIB_DEPRECATED_IN_2_70
+GLIB_DEPRECATED_IN_2_70_FOR
GLIB_DEPRECATED_MACRO
GLIB_DEPRECATED_MACRO_FOR
GLIB_DEPRECATED_MACRO_IN_2_26
@@ -377,6 +387,8 @@ GLIB_DEPRECATED_MACRO_IN_2_66
GLIB_DEPRECATED_MACRO_IN_2_66_FOR
GLIB_DEPRECATED_MACRO_IN_2_68
GLIB_DEPRECATED_MACRO_IN_2_68_FOR
+GLIB_DEPRECATED_MACRO_IN_2_70
+GLIB_DEPRECATED_MACRO_IN_2_70_FOR
GLIB_DEPRECATED_TYPE
GLIB_DEPRECATED_TYPE_FOR
GLIB_DEPRECATED_TYPE_IN_2_26
@@ -423,6 +435,8 @@ GLIB_DEPRECATED_TYPE_IN_2_66
GLIB_DEPRECATED_TYPE_IN_2_66_FOR
GLIB_DEPRECATED_TYPE_IN_2_68
GLIB_DEPRECATED_TYPE_IN_2_68_FOR
+GLIB_DEPRECATED_TYPE_IN_2_70
+GLIB_DEPRECATED_TYPE_IN_2_70_FOR
GLIB_VERSION_CUR_STABLE
GLIB_VERSION_PREV_STABLE
</SECTION>
diff --git a/docs/reference/gobject/gobject-docs.xml b/docs/reference/gobject/gobject-docs.xml
index ddbc9f274..e8e7c76d9 100644
--- a/docs/reference/gobject/gobject-docs.xml
+++ b/docs/reference/gobject/gobject-docs.xml
@@ -208,6 +208,10 @@
<title>Index of new symbols in 2.68</title>
<xi:include href="xml/api-index-2.68.xml"><xi:fallback /></xi:include>
</index>
+ <index id="api-index-2-70" role="2.70">
+ <title>Index of new symbols in 2.70</title>
+ <xi:include href="xml/api-index-2.70.xml"><xi:fallback /></xi:include>
+ </index>
<xi:include href="xml/annotation-glossary.xml"><xi:fallback /></xi:include>
diff --git a/docs/reference/meson.build b/docs/reference/meson.build
index 3f09be555..53ca12ff8 100644
--- a/docs/reference/meson.build
+++ b/docs/reference/meson.build
@@ -7,7 +7,7 @@
stable_2_series_versions = [
'26', '28', '30', '32', '34', '36', '38',
'40', '42', '44', '46', '48', '50', '52', '54', '56', '58',
- '60', '62', '64', '66', '68',
+ '60', '62', '64', '66', '68', '70',
]
ignore_decorators = [
diff --git a/glib/gversionmacros.h b/glib/gversionmacros.h
index 77486eafb..d052709cf 100644
--- a/glib/gversionmacros.h
+++ b/glib/gversionmacros.h
@@ -255,6 +255,16 @@
*/
#define GLIB_VERSION_2_68 (G_ENCODE_VERSION (2, 68))
+/**
+ * GLIB_VERSION_2_70:
+ *
+ * A macro that evaluates to the 2.70 version of GLib, in a format
+ * that can be used by the C pre-processor.
+ *
+ * Since: 2.70
+ */
+#define GLIB_VERSION_2_70 (G_ENCODE_VERSION (2, 70))
+
/**
* GLIB_VERSION_CUR_STABLE:
*
@@ -1076,4 +1086,38 @@
# define GLIB_AVAILABLE_TYPE_IN_2_68
#endif
+#if GLIB_VERSION_MIN_REQUIRED >= GLIB_VERSION_2_70
+# define GLIB_DEPRECATED_IN_2_70 GLIB_DEPRECATED
+# define GLIB_DEPRECATED_IN_2_70_FOR(f) GLIB_DEPRECATED_FOR(f)
+# define GLIB_DEPRECATED_MACRO_IN_2_70 GLIB_DEPRECATED_MACRO
+# define GLIB_DEPRECATED_MACRO_IN_2_70_FOR(f) GLIB_DEPRECATED_MACRO_FOR(f)
+# define GLIB_DEPRECATED_ENUMERATOR_IN_2_70 GLIB_DEPRECATED_ENUMERATOR
+# define GLIB_DEPRECATED_ENUMERATOR_IN_2_70_FOR(f) GLIB_DEPRECATED_ENUMERATOR_FOR(f)
+# define GLIB_DEPRECATED_TYPE_IN_2_70 GLIB_DEPRECATED_TYPE
+# define GLIB_DEPRECATED_TYPE_IN_2_70_FOR(f) GLIB_DEPRECATED_TYPE_FOR(f)
+#else
+# define GLIB_DEPRECATED_IN_2_70 _GLIB_EXTERN
+# define GLIB_DEPRECATED_IN_2_70_FOR(f) _GLIB_EXTERN
+# define GLIB_DEPRECATED_MACRO_IN_2_70
+# define GLIB_DEPRECATED_MACRO_IN_2_70_FOR(f)
+# define GLIB_DEPRECATED_ENUMERATOR_IN_2_70
+# define GLIB_DEPRECATED_ENUMERATOR_IN_2_70_FOR(f)
+# define GLIB_DEPRECATED_TYPE_IN_2_70
+# define GLIB_DEPRECATED_TYPE_IN_2_70_FOR(f)
+#endif
+
+#if GLIB_VERSION_MAX_ALLOWED < GLIB_VERSION_2_70
+# define GLIB_AVAILABLE_IN_2_70 GLIB_UNAVAILABLE(2, 70)
+# define GLIB_AVAILABLE_STATIC_INLINE_IN_2_70 GLIB_UNAVAILABLE_STATIC_INLINE(2, 70)
+# define GLIB_AVAILABLE_MACRO_IN_2_70 GLIB_UNAVAILABLE_MACRO(2, 70)
+# define GLIB_AVAILABLE_ENUMERATOR_IN_2_70 GLIB_UNAVAILABLE_ENUMERATOR(2, 70)
+# define GLIB_AVAILABLE_TYPE_IN_2_70 GLIB_UNAVAILABLE_TYPE(2, 70)
+#else
+# define GLIB_AVAILABLE_IN_2_70 _GLIB_EXTERN
+# define GLIB_AVAILABLE_STATIC_INLINE_IN_2_70
+# define GLIB_AVAILABLE_MACRO_IN_2_70
+# define GLIB_AVAILABLE_ENUMERATOR_IN_2_70
+# define GLIB_AVAILABLE_TYPE_IN_2_70
+#endif
+
#endif /* __G_VERSION_MACROS_H__ */
--
GitLab

File diff suppressed because it is too large Load Diff

@ -1,920 +0,0 @@
From 2e500304e304e45042a59855319ff0379b1978b3 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Tue, 27 Jul 2021 17:24:17 +0200
Subject: [PATCH 1/4] tests: Remove unused constant in GMemoryMonitor test
---
gio/tests/memory-monitor-dbus.py.in | 3 ---
1 file changed, 3 deletions(-)
diff --git a/gio/tests/memory-monitor-dbus.py.in b/gio/tests/memory-monitor-dbus.py.in
index cd16cf4e3..7823e7309 100755
--- a/gio/tests/memory-monitor-dbus.py.in
+++ b/gio/tests/memory-monitor-dbus.py.in
@@ -31,9 +31,6 @@ try:
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- # XDG_DESKTOP_PORTAL_PATH = os.path.expanduser("~/.cache/jhbuild/build/xdg-desktop-portal/xdg-desktop-portal")
- XDG_DESKTOP_PORTAL_PATH = "@libexecdir@/xdg-desktop-portal"
-
class TestLowMemoryMonitor(dbusmock.DBusTestCase):
'''Test GMemoryMonitorDBus'''
--
GitLab
From a7000cd989438b01e599b2cfa8b6d5a360bfd102 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 28 Jul 2021 15:10:16 +0200
Subject: [PATCH 2/4] gio: g_clear_signal_handler() can handle NULL args
---
gio/gmemorymonitordbus.c | 6 ++----
1 file changed, 2 insertions(+), 4 deletions(-)
diff --git a/gio/gmemorymonitordbus.c b/gio/gmemorymonitordbus.c
index a34a58d3b..08dc53df1 100644
--- a/gio/gmemorymonitordbus.c
+++ b/gio/gmemorymonitordbus.c
@@ -115,8 +115,7 @@ lmm_vanished_cb (GDBusConnection *connection,
{
GMemoryMonitorDBus *dbus = user_data;
- if (dbus->proxy != NULL)
- g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
+ g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
g_clear_object (&dbus->proxy);
}
@@ -143,8 +142,7 @@ g_memory_monitor_dbus_finalize (GObject *object)
{
GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (object);
- if (dbus->proxy != NULL)
- g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
+ g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
g_clear_object (&dbus->proxy);
g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
--
GitLab
From 92399e7114e590f0371b1a5d71f478f840cb4074 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 28 Jul 2021 15:30:15 +0200
Subject: [PATCH 3/4] gio: Do not block when low-memory-monitor daemon appears
---
gio/gmemorymonitordbus.c | 42 +++++++++++++++++++++++++++-------------
1 file changed, 29 insertions(+), 13 deletions(-)
diff --git a/gio/gmemorymonitordbus.c b/gio/gmemorymonitordbus.c
index 08dc53df1..739b83214 100644
--- a/gio/gmemorymonitordbus.c
+++ b/gio/gmemorymonitordbus.c
@@ -25,6 +25,7 @@
#include "giomodule-priv.h"
#include "glibintl.h"
#include "glib/gstdio.h"
+#include "gcancellable.h"
#include "gdbusproxy.h"
#include "gdbusnamewatching.h"
@@ -38,6 +39,7 @@ struct _GMemoryMonitorDBus
GObject parent_instance;
guint watch_id;
+ GCancellable *cancellable;
GDBusProxy *proxy;
gulong signal_id;
};
@@ -77,24 +79,15 @@ proxy_signal_cb (GDBusProxy *proxy,
}
static void
-lmm_appeared_cb (GDBusConnection *connection,
- const gchar *name,
- const gchar *name_owner,
- gpointer user_data)
+lmm_proxy_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
{
GMemoryMonitorDBus *dbus = user_data;
GDBusProxy *proxy;
GError *error = NULL;
- proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
- G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
- NULL,
- "org.freedesktop.LowMemoryMonitor",
- "/org/freedesktop/LowMemoryMonitor",
- "org.freedesktop.LowMemoryMonitor",
- NULL,
- &error);
-
+ proxy = g_dbus_proxy_new_finish (res, &error);
if (!proxy)
{
g_debug ("Failed to create LowMemoryMonitor D-Bus proxy: %s",
@@ -106,6 +99,26 @@ lmm_appeared_cb (GDBusConnection *connection,
dbus->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
G_CALLBACK (proxy_signal_cb), dbus);
dbus->proxy = proxy;
+
+}
+
+static void
+lmm_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ GMemoryMonitorDBus *dbus = user_data;
+
+ g_dbus_proxy_new (connection,
+ G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
+ NULL,
+ "org.freedesktop.LowMemoryMonitor",
+ "/org/freedesktop/LowMemoryMonitor",
+ "org.freedesktop.LowMemoryMonitor",
+ dbus->cancellable,
+ lmm_proxy_cb,
+ dbus);
}
static void
@@ -126,6 +139,7 @@ g_memory_monitor_dbus_initable_init (GInitable *initable,
{
GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (initable);
+ dbus->cancellable = g_cancellable_new ();
dbus->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
"org.freedesktop.LowMemoryMonitor",
G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
@@ -142,6 +156,8 @@ g_memory_monitor_dbus_finalize (GObject *object)
{
GMemoryMonitorDBus *dbus = G_MEMORY_MONITOR_DBUS (object);
+ g_cancellable_cancel (dbus->cancellable);
+ g_clear_object (&dbus->cancellable);
g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
g_clear_object (&dbus->proxy);
g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
--
GitLab
From 889bdb994fed44344a84ad01aa5633a1b1b62b19 Mon Sep 17 00:00:00 2001
From: Patrick Griffis <pgriffis@igalia.com>
Date: Tue, 20 Jul 2021 16:04:31 -0500
Subject: [PATCH 4/4] Add GPowerProfileMonitor
---
docs/reference/gio/gio-docs.xml | 1 +
docs/reference/gio/gio-sections-common.txt | 18 ++
docs/reference/gio/meson.build | 1 +
gio/gio.h | 1 +
gio/giomodule.c | 7 +
gio/gpowerprofilemonitor.c | 141 ++++++++++++
gio/gpowerprofilemonitor.h | 63 ++++++
gio/gpowerprofilemonitordbus.c | 240 +++++++++++++++++++++
gio/gpowerprofilemonitordbus.h | 32 +++
gio/meson.build | 3 +
gio/tests/meson.build | 1 +
gio/tests/power-profile-monitor.c | 79 +++++++
12 files changed, 587 insertions(+)
create mode 100644 gio/gpowerprofilemonitor.c
create mode 100644 gio/gpowerprofilemonitor.h
create mode 100644 gio/gpowerprofilemonitordbus.c
create mode 100644 gio/gpowerprofilemonitordbus.h
create mode 100644 gio/tests/power-profile-monitor.c
diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml
index a09d6d31d..b01133900 100644
--- a/docs/reference/gio/gio-docs.xml
+++ b/docs/reference/gio/gio-docs.xml
@@ -238,6 +238,7 @@
<xi:include href="xml/gmenuexporter.xml"/>
<xi:include href="xml/gdbusmenumodel.xml"/>
<xi:include href="xml/gnotification.xml"/>
+ <xi:include href="xml/gpowerprofilemonitor.xml"/>
</chapter>
<chapter id="extending">
<title>Extending GIO</title>
diff --git a/docs/reference/gio/gio-sections-common.txt b/docs/reference/gio/gio-sections-common.txt
index 250491a42..a7addedc2 100644
--- a/docs/reference/gio/gio-sections-common.txt
+++ b/docs/reference/gio/gio-sections-common.txt
@@ -4247,6 +4247,24 @@ G_NETWORK_MONITOR_GET_INTERFACE
g_network_connectivity_get_type
</SECTION>
+<SECTION>
+<FILE>gpowerprofilemonitor</FILE>
+<TITLE>GPowerProfileMonitor</TITLE>
+GPowerProfileMonitor
+GPowerProfileMonitorInterface
+G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME
+g_power_profile_monitor_dup_default
+g_power_profile_monitor_get_power_saver_enabled
+<SUBSECTION Standard>
+g_power_profile_monitor_get_type
+G_TYPE_POWER_PROFILE_MONITOR
+G_POWER_PROFILE_MONITOR
+G_IS_POWER_PROFILE_MONITOR
+G_POWER_PROFILE_MONITOR_GET_INTERFACE
+G_TYPE_POWER_PROFILE_LEVEL
+g_power_profile_level_get_type
+</SECTION>
+
<SECTION>
<FILE>gmenuexporter</FILE>
g_dbus_connection_export_menu_model
diff --git a/docs/reference/gio/meson.build b/docs/reference/gio/meson.build
index 4d0364819..fbabd25ca 100644
--- a/docs/reference/gio/meson.build
+++ b/docs/reference/gio/meson.build
@@ -65,6 +65,7 @@ if get_option('gtk_doc')
'gopenuriportal.h',
'gpollfilemonitor.h',
'gportalsupport.h',
+ 'gpowerprofilemonitordbus.h',
'gproxyresolverportal.h',
'gregistrysettingsbackend.h',
'gresourcefile.h',
diff --git a/gio/gio.h b/gio/gio.h
index f5d2dd5a3..e9afab666 100644
--- a/gio/gio.h
+++ b/gio/gio.h
@@ -120,6 +120,7 @@
#include <gio/gpollableinputstream.h>
#include <gio/gpollableoutputstream.h>
#include <gio/gpollableutils.h>
+#include <gio/gpowerprofilemonitor.h>
#include <gio/gpropertyaction.h>
#include <gio/gproxy.h>
#include <gio/gproxyaddress.h>
diff --git a/gio/giomodule.c b/gio/giomodule.c
index c1d451b5c..dfd895717 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -48,6 +48,8 @@
#include "gmemorymonitor.h"
#include "gmemorymonitorportal.h"
#include "gmemorymonitordbus.h"
+#include "gpowerprofilemonitor.h"
+#include "gpowerprofilemonitordbus.h"
#ifdef G_OS_WIN32
#include "gregistrysettingsbackend.h"
#include "giowin32-priv.h"
@@ -1077,6 +1079,7 @@ extern GType _g_network_monitor_nm_get_type (void);
extern GType g_memory_monitor_dbus_get_type (void);
extern GType g_memory_monitor_portal_get_type (void);
+extern GType g_power_profile_monitor_dbus_get_type (void);
#ifdef G_OS_UNIX
extern GType g_fdo_notification_backend_get_type (void);
@@ -1187,6 +1190,9 @@ _g_io_modules_ensure_extension_points_registered (void)
ep = g_io_extension_point_register (G_MEMORY_MONITOR_EXTENSION_POINT_NAME);
g_io_extension_point_set_required_type (ep, G_TYPE_MEMORY_MONITOR);
+
+ ep = g_io_extension_point_register (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME);
+ g_io_extension_point_set_required_type (ep, G_TYPE_POWER_PROFILE_MONITOR);
}
G_UNLOCK (registered_extensions);
@@ -1272,6 +1278,7 @@ _g_io_modules_ensure_loaded (void)
g_type_ensure (g_null_settings_backend_get_type ());
g_type_ensure (g_memory_settings_backend_get_type ());
g_type_ensure (g_keyfile_settings_backend_get_type ());
+ g_type_ensure (g_power_profile_monitor_dbus_get_type ());
#if defined(HAVE_INOTIFY_INIT1)
g_type_ensure (g_inotify_file_monitor_get_type ());
#endif
diff --git a/gio/gpowerprofilemonitor.c b/gio/gpowerprofilemonitor.c
new file mode 100644
index 000000000..f5028b3e8
--- /dev/null
+++ b/gio/gpowerprofilemonitor.c
@@ -0,0 +1,141 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Red Hat, Inc
+ * Copyright 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+#include "glib.h"
+#include "glibintl.h"
+
+#include "gpowerprofilemonitor.h"
+#include "ginetaddress.h"
+#include "ginetsocketaddress.h"
+#include "ginitable.h"
+#include "gioenumtypes.h"
+#include "giomodule-priv.h"
+#include "gtask.h"
+
+/**
+ * SECTION:gpowerprofilemonitor
+ * @title: GPowerProfileMonitor
+ * @short_description: Power profile monitor
+ * @include: gio/gio.h
+ *
+ * #GPowerProfileMonitor makes it possible for applications as well as OS components
+ * to monitor system power profiles and act upon them. It currently only exports
+ * whether the system is in “Power Saver” mode (known as “Low Power” mode on
+ * some systems).
+ *
+ * When in “Low Power” mode, it is recommended that applications:
+ * - disabling automatic downloads
+ * - reduce the rate of refresh from online sources such as calendar or
+ * email synchronisation
+ * - if the application has expensive visual effects, reduce them
+ *
+ * It is also likely that OS components providing services to applications will
+ * lower their own background activity, for the sake of the system.
+ *
+ * There are a variety of tools that exist for power consumption analysis, but those
+ * usually depend on the OS and hardware used. On Linux, one could use `upower` to
+ * monitor the battery discharge rate, `powertop` to check on the background activity
+ * or activity at all), `sysprof` to inspect CPU usage, and `intel_gpu_time` to
+ * profile GPU usage.
+ *
+ * Don't forget to disconnect the #GPowerProfileMonitor::notify::power-saver-enabled
+ * signal, and unref the #GPowerProfileMonitor itself when exiting.
+ *
+ * Since: 2.70
+ */
+
+/**
+ * GPowerProfileMonitor:
+ *
+ * #GPowerProfileMonitor monitors system power profile and notifies on
+ * changes.
+ *
+ * Since: 2.70
+ */
+
+/**
+ * GPowerProfileMonitorInterface:
+ * @g_iface: The parent interface.
+ *
+ * The virtual function table for #GPowerProfileMonitor.
+ *
+ * Since: 2.70
+ */
+
+G_DEFINE_INTERFACE_WITH_CODE (GPowerProfileMonitor, g_power_profile_monitor, G_TYPE_OBJECT,
+ g_type_interface_add_prerequisite (g_define_type_id, G_TYPE_INITABLE))
+
+
+/**
+ * g_power_profile_monitor_dup_default:
+ *
+ * Gets a reference to the default #GPowerProfileMonitor for the system.
+ *
+ * Returns: (not nullable) (transfer full): a new reference to the default #GPowerProfileMonitor
+ *
+ * Since: 2.70
+ */
+GPowerProfileMonitor *
+g_power_profile_monitor_dup_default (void)
+{
+ return g_object_ref (_g_io_module_get_default (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME,
+ "GIO_USE_POWER_PROFILE_MONITOR",
+ NULL));
+}
+
+/**
+ * g_power_profile_monitor_get_power_saver_enabled:
+ * @monitor: a #GPowerProfileMonitor
+ *
+ * Gets whether the system is in “Power Saver” mode.
+ *
+ * You are expected to listen to the
+ * #GPowerProfileMonitor::notify::power-saver-enabled signal to know when the profile has
+ * changed.
+ *
+ * Returns: Whether the system is in “Power Saver” mode.
+ *
+ * Since: 2.70
+ */
+gboolean
+g_power_profile_monitor_get_power_saver_enabled (GPowerProfileMonitor *monitor)
+{
+ gboolean enabled;
+ g_object_get (monitor, "power-saver-enabled", &enabled, NULL);
+ return enabled;
+}
+
+static void
+g_power_profile_monitor_default_init (GPowerProfileMonitorInterface *iface)
+{
+ /**
+ * GPowerProfileMonitor:power-saver-enabled:
+ *
+ * Whether “Power Saver” mode is enabled on the system.
+ *
+ * Since: 2.70
+ */
+ g_object_interface_install_property (iface,
+ g_param_spec_boolean ("power-saver-enabled",
+ "power-saver-enabled",
+ "Power Saver Enabled",
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_STRINGS | G_PARAM_EXPLICIT_NOTIFY));
+}
diff --git a/gio/gpowerprofilemonitor.h b/gio/gpowerprofilemonitor.h
new file mode 100644
index 000000000..0891fc3dc
--- /dev/null
+++ b/gio/gpowerprofilemonitor.h
@@ -0,0 +1,63 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Red Hat, Inc.
+ * Copyright 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_POWER_PROFILE_MONITOR_H__
+#define __G_POWER_PROFILE_MONITOR_H__
+
+#if !defined (__GIO_GIO_H_INSIDE__) && !defined (GIO_COMPILATION)
+#error "Only <gio/gio.h> can be included directly."
+#endif
+
+#include <gio/giotypes.h>
+
+G_BEGIN_DECLS
+
+/**
+ * G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME:
+ *
+ * Extension point for power profile usage monitoring functionality.
+ * See [Extending GIO][extending-gio].
+ *
+ * Since: 2.70
+ */
+#define G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME "gio-power-profile-monitor"
+
+#define G_TYPE_POWER_PROFILE_MONITOR (g_power_profile_monitor_get_type ())
+GLIB_AVAILABLE_IN_2_70
+G_DECLARE_INTERFACE (GPowerProfileMonitor, g_power_profile_monitor, g, power_profile_monitor, GObject)
+
+#define G_POWER_PROFILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_POWER_PROFILE_MONITOR, GPowerProfileMonitor))
+#define G_IS_POWER_PROFILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_POWER_PROFILE_MONITOR))
+#define G_POWER_PROFILE_MONITOR_GET_INTERFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_POWER_PROFILE_MONITOR, GPowerProfileMonitorInterface))
+
+struct _GPowerProfileMonitorInterface
+{
+ /*< private >*/
+ GTypeInterface g_iface;
+};
+
+GLIB_AVAILABLE_IN_2_70
+GPowerProfileMonitor *g_power_profile_monitor_dup_default (void);
+
+GLIB_AVAILABLE_IN_2_70
+gboolean g_power_profile_monitor_get_power_saver_enabled (GPowerProfileMonitor *monitor);
+
+G_END_DECLS
+
+#endif /* __G_POWER_PROFILE_MONITOR_H__ */
diff --git a/gio/gpowerprofilemonitordbus.c b/gio/gpowerprofilemonitordbus.c
new file mode 100644
index 000000000..8bbfe3acc
--- /dev/null
+++ b/gio/gpowerprofilemonitordbus.c
@@ -0,0 +1,240 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Red Hat, Inc.
+ * Copyrgith 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gpowerprofilemonitor.h"
+#include "gpowerprofilemonitordbus.h"
+#include "gioerror.h"
+#include "ginitable.h"
+#include "giomodule-priv.h"
+#include "glibintl.h"
+#include "glib/gstdio.h"
+#include "gcancellable.h"
+#include "gdbusproxy.h"
+#include "gdbusnamewatching.h"
+
+#define G_POWER_PROFILE_MONITOR_DBUS_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
+
+static void g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *iface);
+static void g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface);
+
+struct _GPowerProfileMonitorDBus
+{
+ GObject parent_instance;
+
+ guint watch_id;
+ GCancellable *cancellable;
+ GDBusProxy *proxy;
+ gulong signal_id;
+
+ gboolean power_saver_enabled;
+};
+
+typedef enum
+{
+ PROP_POWER_SAVER_ENABLED = 1,
+} GPowerProfileMonitorDBusProperty;
+
+#define POWERPROFILES_DBUS_NAME "net.hadess.PowerProfiles"
+#define POWERPROFILES_DBUS_IFACE "net.hadess.PowerProfiles"
+#define POWERPROFILES_DBUS_PATH "/net/hadess/PowerProfiles"
+
+G_DEFINE_TYPE_WITH_CODE (GPowerProfileMonitorDBus, g_power_profile_monitor_dbus, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_power_profile_monitor_dbus_initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_POWER_PROFILE_MONITOR,
+ g_power_profile_monitor_dbus_iface_init)
+ _g_io_modules_ensure_extension_points_registered ();
+ g_io_extension_point_implement (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "dbus",
+ 30))
+
+static void
+g_power_profile_monitor_dbus_init (GPowerProfileMonitorDBus *dbus)
+{
+ dbus->power_saver_enabled = FALSE;
+}
+
+static void
+ppd_properties_changed_cb (GDBusProxy *proxy,
+ GVariant *changed_properties,
+ GStrv *invalidated_properties,
+ gpointer user_data)
+{
+ GPowerProfileMonitorDBus *dbus = user_data;
+ const char *active_profile;
+ gboolean enabled;
+
+ if (!g_variant_lookup (changed_properties, "ActiveProfile", "&s", &active_profile))
+ return;
+
+ enabled = g_strcmp0 (active_profile, "power-saver") == 0;
+ if (enabled == dbus->power_saver_enabled)
+ return;
+
+ dbus->power_saver_enabled = enabled;
+ g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
+}
+
+static void
+ppd_proxy_cb (GObject *source_object,
+ GAsyncResult *res,
+ gpointer user_data)
+{
+ GPowerProfileMonitorDBus *dbus = user_data;
+ GVariant *active_profile_variant;
+ GDBusProxy *proxy;
+ GError *error = NULL;
+ const char *active_profile;
+ gboolean power_saver_enabled;
+
+ proxy = g_dbus_proxy_new_finish (res, &error);
+ if (!proxy)
+ {
+ g_debug ("GPowerProfileMonitorDBus: Failed to create PowerProfiles D-Bus proxy: %s",
+ error->message);
+ g_error_free (error);
+ return;
+ }
+
+ active_profile_variant = g_dbus_proxy_get_cached_property (proxy, "ActiveProfile");
+ if (g_variant_is_of_type (active_profile_variant, G_VARIANT_TYPE_STRING))
+ {
+ active_profile = g_variant_get_string (active_profile_variant, NULL);
+ power_saver_enabled = g_strcmp0 (active_profile, "power-saver") == 0;
+ if (power_saver_enabled != dbus->power_saver_enabled)
+ {
+ dbus->power_saver_enabled = power_saver_enabled;
+ g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
+ }
+ }
+
+ dbus->signal_id = g_signal_connect (G_OBJECT (proxy), "g-properties-changed",
+ G_CALLBACK (ppd_properties_changed_cb), dbus);
+ dbus->proxy = g_steal_pointer (&proxy);
+}
+
+static void
+ppd_appeared_cb (GDBusConnection *connection,
+ const gchar *name,
+ const gchar *name_owner,
+ gpointer user_data)
+{
+ GPowerProfileMonitorDBus *dbus = user_data;
+
+ g_dbus_proxy_new (connection,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ POWERPROFILES_DBUS_NAME,
+ POWERPROFILES_DBUS_PATH,
+ POWERPROFILES_DBUS_IFACE,
+ dbus->cancellable,
+ ppd_proxy_cb,
+ dbus);
+}
+
+static void
+ppd_vanished_cb (GDBusConnection *connection,
+ const gchar *name,
+ gpointer user_data)
+{
+ GPowerProfileMonitorDBus *dbus = user_data;
+
+ g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
+ g_clear_object (&dbus->proxy);
+
+ dbus->power_saver_enabled = FALSE;
+ g_object_notify (G_OBJECT (dbus), "power-saver-enabled");
+}
+
+static void
+g_power_profile_monitor_dbus_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (object);
+
+ switch ((GPowerProfileMonitorDBusProperty) prop_id)
+ {
+ case PROP_POWER_SAVER_ENABLED:
+ g_value_set_boolean (value, dbus->power_saver_enabled);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static gboolean
+g_power_profile_monitor_dbus_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (initable);
+
+ dbus->cancellable = g_cancellable_new ();
+ dbus->watch_id = g_bus_watch_name (G_BUS_TYPE_SYSTEM,
+ POWERPROFILES_DBUS_NAME,
+ G_BUS_NAME_WATCHER_FLAGS_AUTO_START,
+ ppd_appeared_cb,
+ ppd_vanished_cb,
+ dbus,
+ NULL);
+
+ return TRUE;
+}
+
+static void
+g_power_profile_monitor_dbus_finalize (GObject *object)
+{
+ GPowerProfileMonitorDBus *dbus = G_POWER_PROFILE_MONITOR_DBUS (object);
+
+ g_cancellable_cancel (dbus->cancellable);
+ g_clear_object (&dbus->cancellable);
+ g_clear_signal_handler (&dbus->signal_id, dbus->proxy);
+ g_clear_object (&dbus->proxy);
+ g_clear_handle_id (&dbus->watch_id, g_bus_unwatch_name);
+
+ G_OBJECT_CLASS (g_power_profile_monitor_dbus_parent_class)->finalize (object);
+}
+
+static void
+g_power_profile_monitor_dbus_class_init (GPowerProfileMonitorDBusClass *nl_class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
+
+ gobject_class->get_property = g_power_profile_monitor_dbus_get_property;
+ gobject_class->finalize = g_power_profile_monitor_dbus_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_POWER_SAVER_ENABLED, "power-saver-enabled");
+}
+
+static void
+g_power_profile_monitor_dbus_iface_init (GPowerProfileMonitorInterface *monitor_iface)
+{
+}
+
+static void
+g_power_profile_monitor_dbus_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_power_profile_monitor_dbus_initable_init;
+}
diff --git a/gio/gpowerprofilemonitordbus.h b/gio/gpowerprofilemonitordbus.h
new file mode 100644
index 000000000..ecf7246d1
--- /dev/null
+++ b/gio/gpowerprofilemonitordbus.h
@@ -0,0 +1,32 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2019 Red Hat, Inc.
+ * Copyright 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_POWER_PROFILE_MONITOR_DBUS_H__
+#define __G_POWER_PROFILE_MONITOR_DBUS_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_POWER_PROFILE_MONITOR_DBUS (g_power_profile_monitor_dbus_get_type ())
+G_DECLARE_FINAL_TYPE (GPowerProfileMonitorDBus, g_power_profile_monitor_dbus, G, POWER_PROFILE_MONITOR_DBUS, GObject)
+
+G_END_DECLS
+
+#endif /* __G_POWER_PROFILE_MONITOR_DBUS_H__ */
diff --git a/gio/meson.build b/gio/meson.build
index 49a37a7bd..d5838ed8a 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -533,6 +533,8 @@ gio_sources = files(
'gpollableoutputstream.c',
'gpollableutils.c',
'gpollfilemonitor.c',
+ 'gpowerprofilemonitor.c',
+ 'gpowerprofilemonitordbus.c',
'gproxy.c',
'gproxyaddress.c',
'gproxyaddressenumerator.c',
@@ -673,6 +675,7 @@ gio_headers = files(
'gpollableinputstream.h',
'gpollableoutputstream.h',
'gpollableutils.h',
+ 'gpowerprofilemonitor.h',
'gproxy.h',
'gproxyaddress.h',
'gproxyaddressenumerator.h',
diff --git a/gio/tests/meson.build b/gio/tests/meson.build
index 98d1401d0..fc2055101 100644
--- a/gio/tests/meson.build
+++ b/gio/tests/meson.build
@@ -75,6 +75,7 @@ gio_tests = {
'network-monitor-race' : {},
'permission' : {},
'pollable' : {'dependencies' : [libdl_dep]},
+ 'power-profile-monitor' : {},
'proxy-test' : {},
'readwrite' : {},
'simple-async-result' : {},
diff --git a/gio/tests/power-profile-monitor.c b/gio/tests/power-profile-monitor.c
new file mode 100644
index 000000000..bb32f181f
--- /dev/null
+++ b/gio/tests/power-profile-monitor.c
@@ -0,0 +1,79 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2021 Igalia S.L.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <gio/gio.h>
+
+static void
+test_dup_default (void)
+{
+ GPowerProfileMonitor *monitor;
+
+ monitor = g_power_profile_monitor_dup_default ();
+ g_assert_nonnull (monitor);
+ g_object_unref (monitor);
+}
+
+static void
+power_saver_enabled_cb (GPowerProfileMonitor *monitor,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ gboolean enabled;
+
+ enabled = g_power_profile_monitor_get_power_saver_enabled (monitor);
+ g_debug ("Power Saver %s (%d)", enabled ? "enabled" : "disabled", enabled);
+}
+
+static void
+do_watch_power_profile (void)
+{
+ GPowerProfileMonitor *monitor;
+ GMainLoop *loop;
+ gulong signal_id;
+
+ monitor = g_power_profile_monitor_dup_default ();
+ signal_id = g_signal_connect (G_OBJECT (monitor), "notify::power-saver-enabled",
+ G_CALLBACK (power_saver_enabled_cb), NULL);
+
+ loop = g_main_loop_new (NULL, TRUE);
+ g_main_loop_run (loop);
+
+ g_signal_handler_disconnect (monitor, signal_id);
+ g_object_unref (monitor);
+ g_main_loop_unref (loop);
+}
+
+int
+main (int argc, char **argv)
+{
+ int ret;
+
+ if (argc == 2 && !strcmp (argv[1], "--watch"))
+ {
+ do_watch_power_profile ();
+ return 0;
+ }
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/power-profile-monitor/default", test_dup_default);
+
+ ret = g_test_run ();
+
+ return ret;
+}
--
GitLab

@ -1,739 +0,0 @@
From 9645cbffa8ba1a08b73fdae50b31125d11aa5684 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 9 Aug 2021 23:19:17 +0200
Subject: [PATCH 1/4] gio: Add portal version of GPowerProfileMonitor
---
docs/reference/gio/meson.build | 1 +
gio/giomodule.c | 2 +
gio/gpowerprofilemonitorportal.c | 182 +++++++++++++++++++++++++++++++
gio/gpowerprofilemonitorportal.h | 31 ++++++
gio/meson.build | 1 +
5 files changed, 217 insertions(+)
create mode 100644 gio/gpowerprofilemonitorportal.c
create mode 100644 gio/gpowerprofilemonitorportal.h
diff --git a/docs/reference/gio/meson.build b/docs/reference/gio/meson.build
index fbabd25ca..9aaafeed5 100644
--- a/docs/reference/gio/meson.build
+++ b/docs/reference/gio/meson.build
@@ -66,6 +66,7 @@ if get_option('gtk_doc')
'gpollfilemonitor.h',
'gportalsupport.h',
'gpowerprofilemonitordbus.h',
+ 'gpowerprofilemonitorportal.h',
'gproxyresolverportal.h',
'gregistrysettingsbackend.h',
'gresourcefile.h',
diff --git a/gio/giomodule.c b/gio/giomodule.c
index dfd895717..d34037a45 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -50,6 +50,7 @@
#include "gmemorymonitordbus.h"
#include "gpowerprofilemonitor.h"
#include "gpowerprofilemonitordbus.h"
+#include "gpowerprofilemonitorportal.h"
#ifdef G_OS_WIN32
#include "gregistrysettingsbackend.h"
#include "giowin32-priv.h"
@@ -1305,6 +1306,7 @@ _g_io_modules_ensure_loaded (void)
g_type_ensure (g_memory_monitor_dbus_get_type ());
g_type_ensure (g_memory_monitor_portal_get_type ());
g_type_ensure (g_network_monitor_portal_get_type ());
+ g_type_ensure (g_power_profile_monitor_portal_get_type ());
g_type_ensure (g_proxy_resolver_portal_get_type ());
#endif
#if MAC_OS_X_VERSION_MIN_REQUIRED >= 1090
diff --git a/gio/gpowerprofilemonitorportal.c b/gio/gpowerprofilemonitorportal.c
new file mode 100644
index 000000000..bb1b4fd15
--- /dev/null
+++ b/gio/gpowerprofilemonitorportal.c
@@ -0,0 +1,182 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include "config.h"
+
+#include "gpowerprofilemonitor.h"
+#include "gpowerprofilemonitorportal.h"
+#include "gdbuserror.h"
+#include "gdbusproxy.h"
+#include "ginitable.h"
+#include "gioerror.h"
+#include "giomodule-priv.h"
+#include "gportalsupport.h"
+
+#define G_POWER_PROFILE_MONITOR_PORTAL_GET_INITABLE_IFACE(o) (G_TYPE_INSTANCE_GET_INTERFACE ((o), G_TYPE_INITABLE, GInitable))
+
+static void g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *iface);
+static void g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface);
+
+typedef enum
+{
+ PROP_POWER_SAVER_ENABLED = 1,
+} GPowerProfileMonitorPortalProperty;
+
+struct _GPowerProfileMonitorPortal
+{
+ GObject parent_instance;
+
+ GDBusProxy *proxy;
+ gulong signal_id;
+ gboolean power_saver_enabled;
+};
+
+G_DEFINE_TYPE_WITH_CODE (GPowerProfileMonitorPortal, g_power_profile_monitor_portal, G_TYPE_OBJECT,
+ G_IMPLEMENT_INTERFACE (G_TYPE_INITABLE,
+ g_power_profile_monitor_portal_initable_iface_init)
+ G_IMPLEMENT_INTERFACE (G_TYPE_POWER_PROFILE_MONITOR,
+ g_power_profile_monitor_portal_iface_init)
+ _g_io_modules_ensure_extension_points_registered ();
+ g_io_extension_point_implement (G_POWER_PROFILE_MONITOR_EXTENSION_POINT_NAME,
+ g_define_type_id,
+ "portal",
+ 40))
+
+static void
+g_power_profile_monitor_portal_init (GPowerProfileMonitorPortal *portal)
+{
+}
+
+static void
+proxy_properties_changed (GDBusProxy *proxy,
+ GVariant *changed_properties,
+ GStrv invalidated_properties,
+ gpointer user_data)
+{
+ GPowerProfileMonitorPortal *ppm = user_data;
+ gboolean power_saver_enabled;
+
+ if (!g_variant_lookup (changed_properties, "power-saver-enabled", "b", &power_saver_enabled))
+ return;
+
+ if (power_saver_enabled == ppm->power_saver_enabled)
+ return;
+
+ ppm->power_saver_enabled = power_saver_enabled;
+ g_object_notify (G_OBJECT (ppm), "power-saver-enabled");
+}
+
+static void
+g_power_profile_monitor_portal_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ GPowerProfileMonitorPortal *ppm = G_POWER_PROFILE_MONITOR_PORTAL (object);
+
+ switch ((GPowerProfileMonitorPortalProperty) prop_id)
+ {
+ case PROP_POWER_SAVER_ENABLED:
+ g_value_set_boolean (value, ppm->power_saver_enabled);
+ break;
+
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ }
+}
+
+static gboolean
+g_power_profile_monitor_portal_initable_init (GInitable *initable,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GPowerProfileMonitorPortal *ppm = G_POWER_PROFILE_MONITOR_PORTAL (initable);
+ GDBusProxy *proxy;
+ gchar *name_owner;
+
+ if (!glib_should_use_portal ())
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, "Not using portals");
+ return FALSE;
+ }
+
+ proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
+ G_DBUS_PROXY_FLAGS_NONE,
+ NULL,
+ "org.freedesktop.portal.Desktop",
+ "/org/freedesktop/portal/desktop",
+ "org.freedesktop.portal.PowerProfileMonitor",
+ cancellable,
+ error);
+ if (!proxy)
+ return FALSE;
+
+ name_owner = g_dbus_proxy_get_name_owner (proxy);
+
+ if (name_owner == NULL)
+ {
+ g_object_unref (proxy);
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Desktop portal not found");
+ return FALSE;
+ }
+
+ g_free (name_owner);
+
+ ppm->signal_id = g_signal_connect (proxy, "g-properties-changed",
+ G_CALLBACK (proxy_properties_changed), ppm);
+
+ ppm->proxy = g_steal_pointer (&proxy);
+
+ return TRUE;
+}
+
+static void
+g_power_profile_monitor_portal_finalize (GObject *object)
+{
+ GPowerProfileMonitorPortal *ppm = G_POWER_PROFILE_MONITOR_PORTAL (object);
+
+ g_clear_signal_handler (&ppm->signal_id, ppm->proxy);
+ g_clear_object (&ppm->proxy);
+
+ G_OBJECT_CLASS (g_power_profile_monitor_portal_parent_class)->finalize (object);
+}
+
+static void
+g_power_profile_monitor_portal_class_init (GPowerProfileMonitorPortalClass *nl_class)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
+
+ gobject_class->get_property = g_power_profile_monitor_portal_get_property;
+ gobject_class->finalize = g_power_profile_monitor_portal_finalize;
+
+ g_object_class_override_property (gobject_class, PROP_POWER_SAVER_ENABLED, "power-saver-enabled");
+}
+
+static void
+g_power_profile_monitor_portal_iface_init (GPowerProfileMonitorInterface *monitor_iface)
+{
+}
+
+static void
+g_power_profile_monitor_portal_initable_iface_init (GInitableIface *iface)
+{
+ iface->init = g_power_profile_monitor_portal_initable_init;
+}
diff --git a/gio/gpowerprofilemonitorportal.h b/gio/gpowerprofilemonitorportal.h
new file mode 100644
index 000000000..b91a14610
--- /dev/null
+++ b/gio/gpowerprofilemonitorportal.h
@@ -0,0 +1,31 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright 2021 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General
+ * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __G_POWER_PROFILE_MONITOR_PORTAL_H__
+#define __G_POWER_PROFILE_MONITOR_PORTAL_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_POWER_PROFILE_MONITOR_PORTAL (g_power_profile_monitor_portal_get_type ())
+G_DECLARE_FINAL_TYPE (GPowerProfileMonitorPortal, g_power_profile_monitor_portal, G, POWER_PROFILE_MONITOR_PORTAL, GObject)
+
+G_END_DECLS
+
+#endif /* __G_POWER_PROFILE_MONITOR_PORTAL_H__ */
diff --git a/gio/meson.build b/gio/meson.build
index d5838ed8a..ac3373f2b 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -383,6 +383,7 @@ if host_system != 'windows'
'gopenuriportal.c',
'gmemorymonitorportal.c',
'gnetworkmonitorportal.c',
+ 'gpowerprofilemonitorportal.c',
'gproxyresolverportal.c',
'gtrashportal.c',
'gportalsupport.c',
--
GitLab
From 18eb29897d80bf662d58bd11a89617ddd7ebfeed Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Tue, 10 Aug 2021 10:58:53 +0200
Subject: [PATCH 2/4] gio: Add GPowerProfileMonitor tests
Tests both the portal and direct D-Bus variants.
---
gio/tests/meson.build | 14 ++-
gio/tests/power-profile-monitor-dbus.py.in | 107 ++++++++++++++++
gio/tests/power-profile-monitor-portal.py.in | 126 +++++++++++++++++++
3 files changed, 241 insertions(+), 6 deletions(-)
create mode 100755 gio/tests/power-profile-monitor-dbus.py.in
create mode 100755 gio/tests/power-profile-monitor-portal.py.in
diff --git a/gio/tests/meson.build b/gio/tests/meson.build
index fc2055101..5dbfb8e60 100644
--- a/gio/tests/meson.build
+++ b/gio/tests/meson.build
@@ -541,27 +541,29 @@ if installed_tests_enabled
install_subdir('static-link', install_dir : installed_tests_execdir)
install_data('static-link.py', install_dir : installed_tests_execdir)
- memory_monitor_tests = [
+ monitor_tests = [
'memory-monitor-dbus',
'memory-monitor-portal',
+ 'power-profile-monitor-dbus',
+ 'power-profile-monitor-portal'
]
- foreach memory_monitor_test : memory_monitor_tests
+ foreach monitor_test : monitor_tests
cdata = configuration_data()
cdata.set('installed_tests_dir', installed_tests_execdir)
- cdata.set('program', memory_monitor_test + '.py')
+ cdata.set('program', monitor_test + '.py')
cdata.set('env', '')
configure_file(
input: installed_tests_template_tap,
- output: memory_monitor_test + '.test',
+ output: monitor_test + '.test',
install_dir: installed_tests_metadir,
configuration: cdata
)
cdata = configuration_data()
cdata.set('libexecdir', join_paths(glib_prefix, get_option('libexecdir')))
configure_file(
- input: memory_monitor_test + '.py.in',
- output: memory_monitor_test + '.py',
+ input: monitor_test + '.py.in',
+ output: monitor_test + '.py',
install_dir : installed_tests_execdir,
configuration: cdata,
)
diff --git a/gio/tests/power-profile-monitor-dbus.py.in b/gio/tests/power-profile-monitor-dbus.py.in
new file mode 100755
index 000000000..06e594f4a
--- /dev/null
+++ b/gio/tests/power-profile-monitor-dbus.py.in
@@ -0,0 +1,107 @@
+#!/usr/bin/python3
+
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option) any
+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
+# of the license.
+
+__author__ = 'Bastien Nocera'
+__email__ = 'hadess@hadess.net'
+__copyright__ = '(c) 2019, 2021 Red Hat Inc.'
+__license__ = 'LGPL 3+'
+
+import unittest
+import sys
+import subprocess
+import fcntl
+import os
+import time
+
+import taptestrunner
+
+try:
+ # Do all non-standard imports here so we can skip the tests if any
+ # needed packages are not available.
+ import dbus
+ import dbus.mainloop.glib
+ import dbusmock
+ from gi.repository import GLib
+ from gi.repository import Gio
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ class TestPowerProfileMonitor(dbusmock.DBusTestCase):
+ '''Test GPowerProfileMonitorDBus'''
+
+ @classmethod
+ def setUpClass(klass):
+ klass.start_system_bus()
+ klass.dbus_con = klass.get_dbus(True)
+
+ def setUp(self):
+ try:
+ Gio.PowerProfileMonitor
+ except AttributeError:
+ raise unittest.SkipTest('Power Profile Monitor not in '
+ 'introspection data. Requires '
+ 'GObject-Introspection ≥ 1.63.2') # FIXME version
+ try:
+ (self.p_mock, self.obj_ppd) = self.spawn_server_template(
+ 'power_profiles_daemon', {}, stdout=subprocess.PIPE)
+ except ModuleNotFoundError:
+ raise unittest.SkipTest("power-profiles-daemon dbusmock template not "
+ "found. Requires dbusmock > 0.23.1.") # FIXME version
+ # set log to nonblocking
+ flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
+ fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+ self.power_saver_enabled = False
+ self.dbus_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE)
+ self.power_profile_monitor = Gio.PowerProfileMonitor.dup_default()
+ self.power_profile_monitor.connect("notify::power-saver-enabled", self.power_saver_enabled_cb)
+ self.mainloop = GLib.MainLoop()
+ self.main_context = self.mainloop.get_context()
+
+ def tearDown(self):
+ self.p_mock.terminate()
+ self.p_mock.wait()
+
+ def assertEventually(self, condition, message=None, timeout=50):
+ '''Assert that condition function eventually returns True.
+
+ Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+ printed on failure.
+ '''
+ while timeout >= 0:
+ context = GLib.MainContext.default()
+ while context.iteration(False):
+ pass
+ if condition():
+ break
+ timeout -= 1
+ time.sleep(0.1)
+ else:
+ self.fail(message or 'timed out waiting for ' + str(condition))
+
+ def power_saver_enabled_cb(self, spec, data):
+ self.power_saver_enabled = self.power_profile_monitor.get_power_saver_enabled()
+ self.main_context.wakeup()
+
+ def test_power_profile_power_saver_enabled(self):
+ '''power-saver-enabled property'''
+
+ self.assertEqual(self.power_profile_monitor.get_power_saver_enabled(), False)
+ self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('power-saver', variant_level=1))
+ self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 10)
+
+ self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('balanced', variant_level=1))
+ self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 10)
+
+except ImportError as e:
+ @unittest.skip("Cannot import %s" % e.name)
+ class TestPowerProfileMonitor(unittest.TestCase):
+ def test_power_profile_power_saver_enabled(self):
+ pass
+
+if __name__ == '__main__':
+ unittest.main(testRunner=taptestrunner.TAPTestRunner())
diff --git a/gio/tests/power-profile-monitor-portal.py.in b/gio/tests/power-profile-monitor-portal.py.in
new file mode 100755
index 000000000..960a62232
--- /dev/null
+++ b/gio/tests/power-profile-monitor-portal.py.in
@@ -0,0 +1,126 @@
+#!/usr/bin/python3
+
+# This program is free software; you can redistribute it and/or modify it under
+# the terms of the GNU Lesser General Public License as published by the Free
+# Software Foundation; either version 3 of the License, or (at your option) any
+# later version. See http://www.gnu.org/copyleft/lgpl.html for the full text
+# of the license.
+
+__author__ = 'Bastien Nocera'
+__email__ = 'hadess@hadess.net'
+__copyright__ = '(c) 2021 Red Hat Inc.'
+__license__ = 'LGPL 3+'
+
+import unittest
+import sys
+import subprocess
+import fcntl
+import os
+import time
+
+import taptestrunner
+
+try:
+ # Do all non-standard imports here so we can skip the tests if any
+ # needed packages are not available.
+ import dbus
+ import dbus.mainloop.glib
+ import dbusmock
+ from gi.repository import GLib
+ from gi.repository import Gio
+
+ dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+ # XDG_DESKTOP_PORTAL_PATH = os.path.expanduser("~/.cache/jhbuild/build/xdg-desktop-portal/xdg-desktop-portal")
+ XDG_DESKTOP_PORTAL_PATH = "@libexecdir@/xdg-desktop-portal"
+
+ class TestPowerProfileMonitorPortal(dbusmock.DBusTestCase):
+ '''Test GPowerProfileMonitorPortal'''
+
+ @classmethod
+ def setUpClass(klass):
+ klass.start_system_bus()
+ klass.dbus_con = klass.get_dbus(True)
+ # Start session bus so that xdg-desktop-portal can run on it
+ klass.start_session_bus()
+
+ def setUp(self):
+ try:
+ Gio.PowerProfileMonitor
+ except AttributeError:
+ raise unittest.SkipTest('Power Profile Monitor not in '
+ 'introspection data. Requires '
+ 'GObject-Introspection > 1.69.0')
+ try:
+ (self.p_mock, self.obj_ppd) = self.spawn_server_template(
+ 'power_profiles_daemon', {}, stdout=subprocess.PIPE)
+ except ModuleNotFoundError:
+ raise unittest.SkipTest("power-profiles-daemon dbusmock template not "
+ "found. Requires dbusmock > 0.23.1.")
+ # set log to nonblocking
+ flags = fcntl.fcntl(self.p_mock.stdout, fcntl.F_GETFL)
+ fcntl.fcntl(self.p_mock.stdout, fcntl.F_SETFL, flags | os.O_NONBLOCK)
+ self.power_saver_enabled = False
+ self.dbus_props = dbus.Interface(self.obj_ppd, dbus.PROPERTIES_IFACE)
+ try:
+ self.xdp = subprocess.Popen([XDG_DESKTOP_PORTAL_PATH])
+ except FileNotFoundError:
+ raise unittest.SkipTest("xdg-desktop-portal not available")
+
+ try:
+ self.wait_for_bus_object('org.freedesktop.portal.Desktop',
+ '/org/freedesktop/portal/desktop')
+ except:
+ raise
+ # subprocess.Popen(['gdbus', 'monitor', '--session', '--dest', 'org.freedesktop.portal.Desktop'])
+
+ os.environ['GTK_USE_PORTAL'] = "1"
+ self.power_profile_monitor = Gio.PowerProfileMonitor.dup_default()
+ assert("GPowerProfileMonitorPortal" in str(self.power_profile_monitor))
+ self.power_profile_monitor.connect("notify::power-saver-enabled", self.power_saver_enabled_cb)
+ self.mainloop = GLib.MainLoop()
+ self.main_context = self.mainloop.get_context()
+
+ def tearDown(self):
+ self.p_mock.terminate()
+ self.p_mock.wait()
+
+ def assertEventually(self, condition, message=None, timeout=50):
+ '''Assert that condition function eventually returns True.
+
+ Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+ printed on failure.
+ '''
+ while timeout >= 0:
+ context = GLib.MainContext.default()
+ while context.iteration(False):
+ pass
+ if condition():
+ break
+ timeout -= 1
+ time.sleep(0.1)
+ else:
+ self.fail(message or 'timed out waiting for ' + str(condition))
+
+ def power_saver_enabled_cb(self, spec, data):
+ self.power_saver_enabled = self.power_profile_monitor.get_power_saver_enabled()
+ self.main_context.wakeup()
+
+ def test_power_profile_power_saver_enabled_portal(self):
+ '''power-saver-enabled property'''
+
+ self.assertEqual(self.power_profile_monitor.get_power_saver_enabled(), False)
+ self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('power-saver', variant_level=1))
+ self.assertEventually(lambda: self.power_saver_enabled == True, "power-saver didn't become enabled", 10)
+
+ self.dbus_props.Set('net.hadess.PowerProfiles', 'ActiveProfile', dbus.String('balanced', variant_level=1))
+ self.assertEventually(lambda: self.power_saver_enabled == False, "power-saver didn't become disabled", 10)
+
+except ImportError as e:
+ @unittest.skip("Cannot import %s" % e.name)
+ class TestPowerProfileMonitorPortal(unittest.TestCase):
+ def test_power_profile_power_saver_enabled_portal(self):
+ pass
+
+if __name__ == '__main__':
+ unittest.main(testRunner=taptestrunner.TAPTestRunner())
--
GitLab
From 66acea8418eb3d8e46bb6f93dc0c3f13a1f7822b Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 11 Aug 2021 15:37:40 +0200
Subject: [PATCH 3/4] gio: Remove left-over debug statement from memory monitor
portal test
---
gio/tests/memory-monitor-portal.py.in | 1 -
1 file changed, 1 deletion(-)
diff --git a/gio/tests/memory-monitor-portal.py.in b/gio/tests/memory-monitor-portal.py.in
index cb4a960eb..f5fd2283f 100755
--- a/gio/tests/memory-monitor-portal.py.in
+++ b/gio/tests/memory-monitor-portal.py.in
@@ -31,7 +31,6 @@ try:
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
- # XDG_DESKTOP_PORTAL_PATH = os.path.expanduser("~/.cache/jhbuild/build/xdg-desktop-portal/xdg-desktop-portal")
XDG_DESKTOP_PORTAL_PATH = "@libexecdir@/xdg-desktop-portal"
class TestLowMemoryMonitorPortal(dbusmock.DBusTestCase):
--
GitLab
From 2e9842cafc73a7fb94cfde7937e125e1a91f35f8 Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Wed, 11 Aug 2021 15:38:12 +0200
Subject: [PATCH 4/4] gio: Simplify memory monitor tests by using
assertEventually() helper
assertEventually is a helper used in a number of projects that use
dbusmock.
See https://github.com/martinpitt/python-dbusmock/issues/82
---
gio/tests/memory-monitor-dbus.py.in | 31 ++++++++++++++++-----------
gio/tests/memory-monitor-portal.py.in | 31 ++++++++++++++++-----------
2 files changed, 38 insertions(+), 24 deletions(-)
diff --git a/gio/tests/memory-monitor-dbus.py.in b/gio/tests/memory-monitor-dbus.py.in
index 7823e7309..e8ac28faf 100755
--- a/gio/tests/memory-monitor-dbus.py.in
+++ b/gio/tests/memory-monitor-dbus.py.in
@@ -66,6 +66,23 @@ try:
self.p_mock.terminate()
self.p_mock.wait()
+ def assertEventually(self, condition, message=None, timeout=50):
+ '''Assert that condition function eventually returns True.
+
+ Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+ printed on failure.
+ '''
+ while timeout >= 0:
+ context = GLib.MainContext.default()
+ while context.iteration(False):
+ pass
+ if condition():
+ break
+ timeout -= 1
+ time.sleep(0.1)
+ else:
+ self.fail(message or 'timed out waiting for ' + str(condition))
+
def memory_warning_cb(self, monitor, level):
self.last_warning = level
self.main_context.wakeup()
@@ -82,21 +99,11 @@ try:
self.dbusmock.EmitWarning(100)
# Wait 2 seconds or until warning
- timeout = 2
- while timeout > 0 and self.last_warning != 100:
- time.sleep(0.5)
- timeout -= 0.5
- self.main_context.iteration(False)
- self.assertEqual(self.last_warning, 100)
+ self.assertEventually(self.last_warning == 100, "'100' low-memory warning not received", 20)
self.dbusmock.EmitWarning(255)
# Wait 2 seconds or until warning
- timeout = 2
- while timeout > 0 and self.last_warning != 255:
- time.sleep(0.5)
- timeout -= 0.5
- self.main_context.iteration(False)
- self.assertEqual(self.last_warning, 255)
+ self.assertEventually(self.last_warning == 255, "'255' low-memory warning not received", 20)
except ImportError as e:
@unittest.skip("Cannot import %s" % e.name)
diff --git a/gio/tests/memory-monitor-portal.py.in b/gio/tests/memory-monitor-portal.py.in
index f5fd2283f..36d5094d3 100755
--- a/gio/tests/memory-monitor-portal.py.in
+++ b/gio/tests/memory-monitor-portal.py.in
@@ -84,6 +84,23 @@ try:
self.p_mock.terminate()
self.p_mock.wait()
+ def assertEventually(self, condition, message=None, timeout=50):
+ '''Assert that condition function eventually returns True.
+
+ Timeout is in deciseconds, defaulting to 50 (5 seconds). message is
+ printed on failure.
+ '''
+ while timeout >= 0:
+ context = GLib.MainContext.default()
+ while context.iteration(False):
+ pass
+ if condition():
+ break
+ timeout -= 1
+ time.sleep(0.1)
+ else:
+ self.fail(message or 'timed out waiting for ' + str(condition))
+
def portal_memory_warning_cb(self, monitor, level):
self.last_warning = level
self.main_context.wakeup()
@@ -100,21 +117,11 @@ try:
self.dbusmock.EmitWarning(100)
# Wait 2 seconds or until warning
- timeout = 2
- while timeout > 0 and self.last_warning != 100:
- time.sleep(0.5)
- timeout -= 0.5
- self.main_context.iteration(False)
- self.assertEqual(self.last_warning, 100)
+ self.assertEventually(self.last_warning == 100, "'100' low-memory warning not received", 20)
self.dbusmock.EmitWarning(255)
# Wait 2 seconds or until warning
- timeout = 2
- while timeout > 0 and self.last_warning != 255:
- time.sleep(0.5)
- timeout -= 0.5
- self.main_context.iteration(False)
- self.assertEqual(self.last_warning, 255)
+ self.assertEventually(self.last_warning == 255, "'255' low-memory warning not received", 20)
except ImportError as e:
@unittest.skip("Cannot import %s" % e.name)
--
GitLab

@ -1,129 +0,0 @@
From f419966808475cb6c0f0ba2f63967876218ffdaf Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 12:01:50 +0200
Subject: [PATCH 1/2] gnetworkmonitornm: Stop using removed PropertiesChanged
signal
Use the org.freedesktop.DBus.Properties interface to listen
to PropertiesChanged signals on /org/freedesktop/NetworkManager.
NetworkManager used to provide its own legacy PropertiesChanged
signal, but that was dropped in
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/853
This requires NetworkManager >= 1.2 (2016)
Fixes: #2505
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1946196
---
gio/gnetworkmonitornm.c | 29 +++++++----------------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 5a36a0ba1..6a6d1d666 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -267,29 +267,14 @@ update_cached_property (GDBusProxy *proxy,
}
static void
-proxy_signal_cb (GDBusProxy *proxy,
- const gchar *sender_name,
- const gchar *signal_name,
- GVariant *parameters,
- GNetworkMonitorNM *nm)
+proxy_properties_changed_cb (GDBusProxy *proxy,
+ GVariant *changed_properties,
+ GStrv invalidated_properties,
+ GNetworkMonitorNM *nm)
{
- GVariant *asv;
GVariantDict *dict;
- if (g_strcmp0 (signal_name, "PropertiesChanged") != 0)
- return;
-
- g_variant_get (parameters, "(@a{sv})", &asv);
- if (!asv)
- return;
-
- dict = g_variant_dict_new (asv);
- g_variant_unref (asv);
- if (!dict)
- {
- g_warning ("Failed to handle PropertiesChanged signal from NetworkManager");
- return;
- }
+ dict = g_variant_dict_new (changed_properties);
update_cached_property (nm->priv->proxy, "Connectivity", dict);
@@ -361,8 +346,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
return FALSE;
}
- nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
- G_CALLBACK (proxy_signal_cb), nm);
+ nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-properties-changed",
+ G_CALLBACK (proxy_properties_changed_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
--
GitLab
From 643fc7ea49e818310f6b3f6e4ebe621c7a4d6bd7 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 17:31:42 +0200
Subject: [PATCH 2/2] gnetworkmonitornm: Do not re-update cached property
GDBusProxy already takes care of updating the cached property
before emitting the signal, so there is no need to do this
a second time ourselves.
---
gio/gnetworkmonitornm.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 6a6d1d666..a8040fb36 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -252,34 +252,12 @@ sync_properties (GNetworkMonitorNM *nm,
}
}
-static void
-update_cached_property (GDBusProxy *proxy,
- const char *property_name,
- GVariantDict *dict)
-{
- GVariant *v;
-
- v = g_variant_dict_lookup_value (dict, property_name, NULL);
- if (!v)
- return;
- g_dbus_proxy_set_cached_property (proxy, property_name, v);
- g_variant_unref (v);
-}
-
static void
proxy_properties_changed_cb (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
GNetworkMonitorNM *nm)
{
- GVariantDict *dict;
-
- dict = g_variant_dict_new (changed_properties);
-
- update_cached_property (nm->priv->proxy, "Connectivity", dict);
-
- g_variant_dict_unref (dict);
-
sync_properties (nm, TRUE);
}
--
GitLab

@ -1,391 +0,0 @@
From 0bbd63bf1945c6f3e1c88232521e1618c21d44f2 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 23 Dec 2021 17:45:51 +0000
Subject: [PATCH 1/4] gmain: Use waitid() on pidfds rather than a global
SIGCHLD handler
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When the system supports it (as all Linux kernels ≥ 5.3 should), its
preferable to use `pidfd_open()` and `waitid()` to be notified of
child processes exiting or being signalled, rather than installing a
default `SIGCHLD` handler.
A default `SIGCHLD` handler is global, and can never interact well with
other code (from the application or other libraries) which also wants to
install a `SIGCHLD` handler.
This use of `pidfd_open()` is racy (the PID may be reused between
`g_child_watch_source_new()` being called and `pidfd_open()` being
called), so it doesnt improve behaviour there. For that, wed need
continuous use of pidfds throughout GLib, from fork/spawn time until
here. See #1866 for that.
The use of `waitid()` to get the process exit status could be expanded
in future to also work for stopped or continued processes (as per #175)
by adding `WSTOPPED | WCONTINUED` into the flags. Thats a behaviour
change which is outside the strict scope of adding pidfd support,
though.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1866
Fixes: #2216
---
glib/gmain.c | 117 ++++++++++++++++++++++++++++++++++++++++++++++++---
meson.build | 14 ++++++
2 files changed, 125 insertions(+), 6 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 15581ee7a..e9965f7f6 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -67,6 +67,12 @@
#include <errno.h>
#include <string.h>
+#ifdef HAVE_PIDFD
+#include <sys/syscall.h>
+#include <sys/wait.h>
+#include <linux/wait.h> /* P_PIDFD */
+#endif /* HAVE_PIDFD */
+
#ifdef G_OS_WIN32
#define STRICT
#include <windows.h>
@@ -329,10 +335,11 @@ struct _GChildWatchSource
GSource source;
GPid pid;
gint child_status;
-#ifdef G_OS_WIN32
+ /* @poll is always used on Windows, and used on Unix iff @using_pidfd is set: */
GPollFD poll;
-#else /* G_OS_WIN32 */
- gboolean child_exited; /* (atomic) */
+#ifndef G_OS_WIN32
+ gboolean child_exited; /* (atomic); not used iff @using_pidfd is set */
+ gboolean using_pidfd;
#endif /* G_OS_WIN32 */
};
@@ -5325,7 +5332,8 @@ dispatch_unix_signals_unlocked (void)
{
GChildWatchSource *source = node->data;
- if (!g_atomic_int_get (&source->child_exited))
+ if (!source->using_pidfd &&
+ !g_atomic_int_get (&source->child_exited))
{
pid_t pid;
do
@@ -5384,6 +5392,38 @@ g_child_watch_prepare (GSource *source,
return g_atomic_int_get (&child_watch_source->child_exited);
}
+#ifdef HAVE_PIDFD
+static int
+siginfo_t_to_wait_status (const siginfo_t *info)
+{
+ /* Each of these returns is essentially the inverse of WIFEXITED(),
+ * WIFSIGNALED(), etc. */
+ switch (info->si_code)
+ {
+ case CLD_EXITED:
+ return W_EXITCODE (info->si_status, 0);
+ case CLD_KILLED:
+ return W_EXITCODE (0, info->si_status);
+ case CLD_DUMPED:
+#ifdef WCOREFLAG
+ return W_EXITCODE (0, info->si_status | WCOREFLAG);
+#else
+ g_assert_not_reached ();
+#endif
+ case CLD_CONTINUED:
+#ifdef __W_CONTINUED
+ return __W_CONTINUED;
+#else
+ g_assert_not_reached ();
+#endif
+ case CLD_STOPPED:
+ case CLD_TRAPPED:
+ default:
+ return W_STOPCODE (info->si_status);
+ }
+}
+#endif /* HAVE_PIDFD */
+
static gboolean
g_child_watch_check (GSource *source)
{
@@ -5391,6 +5431,34 @@ g_child_watch_check (GSource *source)
child_watch_source = (GChildWatchSource *) source;
+#ifdef HAVE_PIDFD
+ if (child_watch_source->using_pidfd)
+ {
+ gboolean child_exited = child_watch_source->poll.revents & G_IO_IN;
+
+ if (child_exited)
+ {
+ siginfo_t child_info = { 0, };
+
+ /* Get the exit status */
+ if (waitid (P_PIDFD, child_watch_source->poll.fd, &child_info, WEXITED | WNOHANG) >= 0 &&
+ child_info.si_pid != 0)
+ {
+ /* waitid() helpfully provides the wait status in a decomposed
+ * form which is quite useful. Unfortunately we have to report it
+ * to the #GChildWatchFunc as a waitpid()-style platform-specific
+ * wait status, so that the user code in #GChildWatchFunc can then
+ * call WIFEXITED() (etc.) on it. That means re-composing the
+ * status information. */
+ child_watch_source->child_status = siginfo_t_to_wait_status (&child_info);
+ child_watch_source->child_exited = TRUE;
+ }
+ }
+
+ return child_exited;
+ }
+#endif /* HAVE_PIDFD */
+
return g_atomic_int_get (&child_watch_source->child_exited);
}
@@ -5575,6 +5643,11 @@ g_unix_signal_watch_finalize (GSource *source)
static void
g_child_watch_finalize (GSource *source)
{
+ GChildWatchSource *child_watch_source = (GChildWatchSource *) source;
+
+ if (child_watch_source->using_pidfd)
+ return;
+
G_LOCK (unix_signal_lock);
unix_child_watches = g_slist_remove (unix_child_watches, source);
unref_unix_signal_handler_unlocked (SIGCHLD);
@@ -5676,6 +5749,9 @@ g_child_watch_source_new (GPid pid)
{
GSource *source;
GChildWatchSource *child_watch_source;
+#ifdef HAVE_PIDFD
+ int errsv;
+#endif
#ifndef G_OS_WIN32
g_return_val_if_fail (pid > 0, NULL);
@@ -5694,14 +5770,43 @@ g_child_watch_source_new (GPid pid)
child_watch_source->poll.events = G_IO_IN;
g_source_add_poll (source, &child_watch_source->poll);
-#else /* G_OS_WIN32 */
+#else /* !G_OS_WIN32 */
+
+#ifdef HAVE_PIDFD
+ /* Use a pidfd, if possible, to avoid having to install a global SIGCHLD
+ * handler and potentially competing with any other library/code which wants
+ * to install one.
+ *
+ * Unfortunately this use of pidfd isnt race-free (the PID could be recycled
+ * between the caller calling g_child_watch_source_new() and here), but its
+ * better than SIGCHLD.
+ */
+ child_watch_source->poll.fd = (int) syscall (SYS_pidfd_open, pid, 0);
+ errsv = errno;
+
+ if (child_watch_source->poll.fd >= 0)
+ {
+ child_watch_source->using_pidfd = TRUE;
+ child_watch_source->poll.events = G_IO_IN;
+ g_source_add_poll (source, &child_watch_source->poll);
+
+ return source;
+ }
+ else
+ {
+ g_debug ("pidfd_open(%" G_PID_FORMAT ") failed with error: %s",
+ pid, g_strerror (errsv));
+ /* Fall through; likely the kernel isnt new enough to support pidfd_open() */
+ }
+#endif /* HAVE_PIDFD */
+
G_LOCK (unix_signal_lock);
ref_unix_signal_handler_unlocked (SIGCHLD);
unix_child_watches = g_slist_prepend (unix_child_watches, child_watch_source);
if (waitpid (pid, &child_watch_source->child_status, WNOHANG) > 0)
child_watch_source->child_exited = TRUE;
G_UNLOCK (unix_signal_lock);
-#endif /* G_OS_WIN32 */
+#endif /* !G_OS_WIN32 */
return source;
}
diff --git a/meson.build b/meson.build
index a0223ce5b..1e1bd602c 100644
--- a/meson.build
+++ b/meson.build
@@ -810,6 +810,20 @@ if cc.links('''#include <sys/eventfd.h>
glib_conf.set('HAVE_EVENTFD', 1)
endif
+# Check for pidfd_open(2)
+if cc.links('''#include <sys/syscall.h>
+ #include <sys/wait.h>
+ #include <linux/wait.h>
+ #include <unistd.h>
+ int main (int argc, char ** argv) {
+ siginfo_t child_info = { 0, };
+ syscall (SYS_pidfd_open, 0, 0);
+ waitid (P_PIDFD, 0, &child_info, WEXITED | WNOHANG);
+ return 0;
+ }''', name : 'pidfd_open(2) system call')
+ glib_conf.set('HAVE_PIDFD', 1)
+endif
+
# Check for __uint128_t (gcc) by checking for 128-bit division
uint128_t_src = '''int main() {
static __uint128_t v1 = 100;
--
2.41.0
From 13c62bc181c6da9f287b737f7a3238e0269b40b3 Mon Sep 17 00:00:00 2001
From: Christian Hergert <chergert@redhat.com>
Date: Tue, 2 Aug 2022 12:35:40 -0700
Subject: [PATCH 2/4] gmain: close pidfd when finalizing GChildWatchSource
A file-descriptor was created with the introduction of pidfd_getfd() but
nothing is closing it when the source finalizes. The GChildWatchSource is
the creator and consumer of this FD and therefore responsible for closing
it on finalization.
The pidfd leak was introduced in !2408.
This fixes issues with Builder where anon_inode:[pidfd] exhaust the
available FD limit for the process.
Fixes #2708
---
glib/gmain.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index e9965f7f6..3ceec61ee 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -5646,7 +5646,11 @@ g_child_watch_finalize (GSource *source)
GChildWatchSource *child_watch_source = (GChildWatchSource *) source;
if (child_watch_source->using_pidfd)
- return;
+ {
+ if (child_watch_source->poll.fd >= 0)
+ close (child_watch_source->poll.fd);
+ return;
+ }
G_LOCK (unix_signal_lock);
unix_child_watches = g_slist_remove (unix_child_watches, source);
--
2.41.0
From 378c72cbe12767b8f6aedc19c7ca46c07aa1ca73 Mon Sep 17 00:00:00 2001
From: Owen Rafferty <owen@owenrafferty.com>
Date: Tue, 12 Jul 2022 20:03:56 -0500
Subject: [PATCH 3/4] gmain: define non-posix symbols
---
glib/gmain.c | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/glib/gmain.c b/glib/gmain.c
index 3ceec61ee..a2d7bb3ba 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -71,6 +71,12 @@
#include <sys/syscall.h>
#include <sys/wait.h>
#include <linux/wait.h> /* P_PIDFD */
+#ifndef W_EXITCODE
+#define W_EXITCODE(ret, sig) ((ret) << 8 | (sig))
+#endif
+#ifndef W_STOPCODE
+#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
+#endif
#endif /* HAVE_PIDFD */
#ifdef G_OS_WIN32
--
2.41.0
From aac37188ce26366bd86626700d49cee0cb121472 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 21 Dec 2022 12:11:46 +0000
Subject: [PATCH 4/4] gmain: Define fallback values for siginfo_t constants for
musl
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
musl doesnt define them itself, presumably because theyre not defined
in POSIX. glibc does define them. Thankfully, the values used in glibc
match the values used internally in other musl macros.
Define the values as a fallback. As a result of this, we can get rid of
the `g_assert_if_reached()` checks in `siginfo_t_to_wait_status()`.
This should fix catching signals from a subprocess when built against
musl.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2852
---
glib/gmain.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index a2d7bb3ba..f0cf700c0 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -77,6 +77,16 @@
#ifndef W_STOPCODE
#define W_STOPCODE(sig) ((sig) << 8 | 0x7f)
#endif
+#ifndef WCOREFLAG
+/* musl doesnt define WCOREFLAG while glibc does. Unfortunately, theres no way
+ * to detect were building against musl, so just define it and hope.
+ * See https://git.musl-libc.org/cgit/musl/tree/include/sys/wait.h#n51 */
+#define WCOREFLAG 0x80
+#endif
+#ifndef __W_CONTINUED
+/* Same as above, for musl */
+#define __W_CONTINUED 0xffff
+#endif
#endif /* HAVE_PIDFD */
#ifdef G_OS_WIN32
@@ -5411,17 +5421,9 @@ siginfo_t_to_wait_status (const siginfo_t *info)
case CLD_KILLED:
return W_EXITCODE (0, info->si_status);
case CLD_DUMPED:
-#ifdef WCOREFLAG
return W_EXITCODE (0, info->si_status | WCOREFLAG);
-#else
- g_assert_not_reached ();
-#endif
case CLD_CONTINUED:
-#ifdef __W_CONTINUED
return __W_CONTINUED;
-#else
- g_assert_not_reached ();
-#endif
case CLD_STOPPED:
case CLD_TRAPPED:
default:
--
2.41.0

@ -1,132 +0,0 @@
From a879d08e912a4421786b44af479f94f7b4503f5a Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Mon, 17 Jan 2022 15:27:24 +0000
Subject: [PATCH] gspawn: Report errors with closing file descriptors between
fork/exec
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
If a seccomp policy is set up incorrectly so that it returns `EPERM` for
`close_range()` rather than `ENOSYS` due to it not being recognised, no
error would previously be reported from GLib, but some file descriptors
wouldnt be closed, and that would cause a hung zombie process. The
zombie process would be waiting for one half of a socket to be closed.
Fix that by correctly propagating errors from `close_range()` back to the
parent process so they can be reported correctly.
Distributions which arent yet carrying the Docker fix to correctly
return `ENOSYS` from unrecognised syscalls may want to temporarily carry
an additional patch to fall back to `safe_fdwalk()` if `close_range()`
fails with `EPERM`. This change will not be accepted upstream as `EPERM`
is not the right error for `close_range()` to be returning.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2580
---
glib/gspawn.c | 35 ++++++++++++++++++++++++++---------
1 file changed, 26 insertions(+), 9 deletions(-)
diff --git a/glib/gspawn.c b/glib/gspawn.c
index c2fe306dc..9c2f7ba7b 100644
--- a/glib/gspawn.c
+++ b/glib/gspawn.c
@@ -1457,8 +1457,10 @@ safe_fdwalk (int (*cb)(void *data, int fd), void *data)
}
/* This function is called between fork() and exec() and hence must be
- * async-signal-safe (see signal-safety(7)). */
-static void
+ * async-signal-safe (see signal-safety(7)).
+ *
+ * On failure, `-1` will be returned and errno will be set. */
+static int
safe_closefrom (int lowfd)
{
#if defined(__FreeBSD__) || defined(__OpenBSD__)
@@ -1472,6 +1474,7 @@ safe_closefrom (int lowfd)
* should be safe to use.
*/
(void) closefrom (lowfd);
+ return 0;
#elif defined(__DragonFly__)
/* It is unclear whether closefrom function included in DragonFlyBSD libc_r
* is safe to use because it calls a lot of library functions. It is also
@@ -1479,12 +1482,13 @@ safe_closefrom (int lowfd)
* direct system call here ourselves to avoid possible issues.
*/
(void) syscall (SYS_closefrom, lowfd);
+ return 0;
#elif defined(F_CLOSEM)
/* NetBSD and AIX have a special fcntl command which does the same thing as
* closefrom. NetBSD also includes closefrom function, which seems to be a
* simple wrapper of the fcntl command.
*/
- (void) fcntl (lowfd, F_CLOSEM);
+ return fcntl (lowfd, F_CLOSEM);
#else
#if defined(HAVE_CLOSE_RANGE)
@@ -1494,9 +1498,11 @@ safe_closefrom (int lowfd)
*
* Handle ENOSYS in case its supported in libc but not the kernel; if so,
* fall back to safe_fdwalk(). */
- if (close_range (lowfd, G_MAXUINT, 0) != 0 && errno == ENOSYS)
+ int ret = close_range (lowfd, G_MAXUINT, 0);
+ if (ret == 0 || errno != ENOSYS)
+ return ret;
#endif /* HAVE_CLOSE_RANGE */
- (void) safe_fdwalk (close_func, GINT_TO_POINTER (lowfd));
+ return safe_fdwalk (close_func, GINT_TO_POINTER (lowfd));
#endif
}
@@ -1534,7 +1540,8 @@ enum
CHILD_EXEC_FAILED,
CHILD_OPEN_FAILED,
CHILD_DUP2_FAILED,
- CHILD_FORK_FAILED
+ CHILD_FORK_FAILED,
+ CHILD_CLOSE_FAILED,
};
/* This function is called between fork() and exec() and hence must be
@@ -1650,12 +1657,14 @@ do_exec (gint child_err_report_fd,
if (safe_dup2 (child_err_report_fd, 3) < 0)
write_err_and_exit (child_err_report_fd, CHILD_DUP2_FAILED);
set_cloexec (GINT_TO_POINTER (0), 3);
- safe_closefrom (4);
+ if (safe_closefrom (4) < 0)
+ write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
child_err_report_fd = 3;
}
else
{
- safe_fdwalk (set_cloexec, GINT_TO_POINTER (3));
+ if (safe_fdwalk (set_cloexec, GINT_TO_POINTER (3)) < 0)
+ write_err_and_exit (child_err_report_fd, CHILD_CLOSE_FAILED);
}
}
else
@@ -2446,7 +2455,15 @@ fork_exec (gboolean intermediate_child,
_("Failed to fork child process (%s)"),
g_strerror (buf[1]));
break;
-
+
+ case CHILD_CLOSE_FAILED:
+ g_set_error (error,
+ G_SPAWN_ERROR,
+ G_SPAWN_ERROR_FAILED,
+ _("Failed to close file descriptor for child process (%s)"),
+ g_strerror (buf[1]));
+ break;
+
default:
g_set_error (error,
G_SPAWN_ERROR,
--
2.34.1

@ -1,278 +0,0 @@
From 764f071909df70622e79ee71323973c18c055c8c Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <giuseppe@scrivano.org>
Date: Mon, 14 Sep 2020 16:28:10 +0200
Subject: [PATCH 1/5] gdbusauth: empty DATA does not need a trailing space
This is an interoperability fix. If the line is exactly "DATA\r\n",
the reference implementation of D-Bus treats this as equivalent to
"DATA \r\n", meaning the data block consists of zero hex-encoded bytes.
In practice, D-Bus clients send empty data blocks as "DATA\r\n", and
in fact sd-bus only accepts that, rejecting "DATA \r\n".
[Originally part of a larger commit; commit message added by smcv]
Signed-off-by: Giuseppe Scrivano <giuseppe@scrivano.org>
Co-authored-by: Simon McVittie <smcv@collabora.com>
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gdbusauth.c | 8 ++++----
1 file changed, 4 insertions(+), 4 deletions(-)
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index ede21c8514..d2ca41a201 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -783,13 +783,13 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
if (line == NULL)
goto out;
debug_print ("CLIENT: WaitingForData, read='%s'", line);
- if (g_str_has_prefix (line, "DATA "))
+ if (g_str_equal (line, "DATA") || g_str_has_prefix (line, "DATA "))
{
gchar *encoded;
gchar *decoded_data;
gsize decoded_data_len = 0;
- encoded = g_strdup (line + 5);
+ encoded = g_strdup (line + 4);
g_free (line);
g_strstrip (encoded);
decoded_data = hexdecode (encoded, &decoded_data_len, error);
@@ -1255,13 +1255,13 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
debug_print ("SERVER: WaitingForData, read '%s'", line);
if (line == NULL)
goto out;
- if (g_str_has_prefix (line, "DATA "))
+ if (g_str_equal (line, "DATA") || g_str_has_prefix (line, "DATA "))
{
gchar *encoded;
gchar *decoded_data;
gsize decoded_data_len = 0;
- encoded = g_strdup (line + 5);
+ encoded = g_strdup (line + 4);
g_free (line);
g_strstrip (encoded);
decoded_data = hexdecode (encoded, &decoded_data_len, error);
--
GitLab
From a7d2e727eefcf883bb463ad559f5632e8e448757 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <giuseppe@scrivano.org>
Date: Mon, 14 Sep 2020 16:28:10 +0200
Subject: [PATCH 2/5] GDBusServer: If no initial response for EXTERNAL, send a
challenge
Sending an "initial response" along with the AUTH command is meant
to be an optional optimization, and clients are allowed to omit it.
We must reply with our initial challenge, which in the case of EXTERNAL
is an empty string: the client responds to that with the authorization
identity.
If we do not reply to the AUTH command, then the client will wait
forever for our reply, while we wait forever for the reply that we
expect the client to send, resulting in deadlock.
D-Bus does not have a way to distinguish between an empty initial
response and the absence of an initial response, so clients that want
to use an empty authorization identity, such as systed's sd-bus,
cannot use the initial-response optimization and will fail to connect
to a GDBusServer that does not have this change.
[Originally part of a larger commit; commit message added by smcv.]
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gdbusauthmechanismexternal.c | 23 ++++++++++++++++++-----
1 file changed, 18 insertions(+), 5 deletions(-)
diff --git a/gio/gdbusauthmechanismexternal.c b/gio/gdbusauthmechanismexternal.c
index 617fe1d0e5..ddd06cbd5e 100644
--- a/gio/gdbusauthmechanismexternal.c
+++ b/gio/gdbusauthmechanismexternal.c
@@ -40,6 +40,7 @@ struct _GDBusAuthMechanismExternalPrivate
gboolean is_client;
gboolean is_server;
GDBusAuthMechanismState state;
+ gboolean empty_data_sent;
};
static gint mechanism_get_priority (void);
@@ -253,7 +254,9 @@ mechanism_server_initiate (GDBusAuthMechanism *mechanism,
}
else
{
- m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
+ /* The initial-response optimization was not used, so we need to
+ * send an empty challenge to prompt the client to respond. */
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND;
}
}
@@ -288,12 +291,22 @@ mechanism_server_data_send (GDBusAuthMechanism *mechanism,
g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_EXTERNAL (mechanism), NULL);
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_HAVE_DATA_TO_SEND, NULL);
- /* can never end up here because we are never in the HAVE_DATA_TO_SEND state */
- g_assert_not_reached ();
+ if (out_data_len)
+ *out_data_len = 0;
- return NULL;
+ if (m->priv->empty_data_sent)
+ {
+ /* We have already sent an empty data response.
+ Reject the connection. */
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED;
+ return NULL;
+ }
+
+ m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA;
+ m->priv->empty_data_sent = TRUE;
+
+ return g_strdup ("");
}
static gchar *
--
GitLab
From b51e3ab09e39c590c65a7be6228ecfa48a6189f6 Mon Sep 17 00:00:00 2001
From: Giuseppe Scrivano <giuseppe@scrivano.org>
Date: Mon, 14 Sep 2020 16:28:10 +0200
Subject: [PATCH 3/5] GDBusServer: Accept empty authorization identity for
EXTERNAL mechanism
RFC 4422 appendix A defines the empty authorization identity to mean
the identity that the server associated with its authentication
credentials. In this case, this means whatever uid is in the
GCredentials object.
In particular, this means that clients in a different Linux user
namespace can authenticate against our server and will be authorized
as the version of their uid that is visible in the server's namespace,
even if the corresponding numeric uid returned by geteuid() in the
client's namespace was different. systemd's sd-bus has relied on this
since commit
https://github.com/systemd/systemd/commit/1ed4723d38cd0d1423c8fe650f90fa86007ddf55.
[Originally part of a larger commit; commit message added by smcv]
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gdbusauthmechanismexternal.c | 16 +++++++++++++---
1 file changed, 13 insertions(+), 3 deletions(-)
diff --git a/gio/gdbusauthmechanismexternal.c b/gio/gdbusauthmechanismexternal.c
index ddd06cbd5e..a465862d12 100644
--- a/gio/gdbusauthmechanismexternal.c
+++ b/gio/gdbusauthmechanismexternal.c
@@ -201,14 +201,24 @@ data_matches_credentials (const gchar *data,
if (credentials == NULL)
goto out;
- if (data == NULL || data_len == 0)
- goto out;
-
#if defined(G_OS_UNIX)
{
gint64 alleged_uid;
gchar *endp;
+ /* If we were unable to find out the uid, then nothing
+ * can possibly match it. */
+ if (g_credentials_get_unix_user (credentials, NULL) == (uid_t) -1)
+ goto out;
+
+ /* An empty authorization identity means we want to be
+ * whatever identity the out-of-band credentials say we have
+ * (RFC 4422 appendix A.1). This effectively matches any uid. */
+ if (data == NULL || data_len == 0)
+ {
+ match = TRUE;
+ goto out;
+ }
/* on UNIX, this is the uid as a string in base 10 */
alleged_uid = g_ascii_strtoll (data, &endp, 10);
if (*endp == '\0')
--
GitLab
From 3f532af65c98e4ba8426c53f26c9ee15d3692f9c Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Mon, 18 Jul 2022 17:14:44 +0100
Subject: [PATCH 4/5] gdbusauth: Represent empty data block as DATA\r\n, with
no space
This is an interoperability fix. The reference implementation of D-Bus
treats "DATA\r\n" as equivalent to "DATA \r\n", but sd-bus does not,
and only accepts the former.
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
gio/gdbusauth.c | 34 ++++++++++++++++++++++++++--------
1 file changed, 26 insertions(+), 8 deletions(-)
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index d2ca41a201..89cbbf67c6 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -807,11 +807,21 @@ _g_dbus_auth_run_client (GDBusAuth *auth,
{
gchar *data;
gsize data_len;
- gchar *encoded_data;
+
data = _g_dbus_auth_mechanism_client_data_send (mech, &data_len);
- encoded_data = _g_dbus_hexencode (data, data_len);
- s = g_strdup_printf ("DATA %s\r\n", encoded_data);
- g_free (encoded_data);
+
+ if (data_len == 0)
+ {
+ s = g_strdup ("DATA\r\n");
+ }
+ else
+ {
+ gchar *encoded_data = _g_dbus_hexencode (data, data_len);
+
+ s = g_strdup_printf ("DATA %s\r\n", encoded_data);
+ g_free (encoded_data);
+ }
+
g_free (data);
debug_print ("CLIENT: writing '%s'", s);
if (!g_data_output_stream_put_string (dos, s, cancellable, error))
@@ -1209,13 +1219,21 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
gsize data_len;
data = _g_dbus_auth_mechanism_server_data_send (mech, &data_len);
+
if (data != NULL)
{
- gchar *encoded_data;
+ if (data_len == 0)
+ {
+ s = g_strdup ("DATA\r\n");
+ }
+ else
+ {
+ gchar *encoded_data = _g_dbus_hexencode (data, data_len);
+
+ s = g_strdup_printf ("DATA %s\r\n", encoded_data);
+ g_free (encoded_data);
+ }
- encoded_data = _g_dbus_hexencode (data, data_len);
- s = g_strdup_printf ("DATA %s\r\n", encoded_data);
- g_free (encoded_data);
g_free (data);
debug_print ("SERVER: writing '%s'", s);
--
GitLab

@ -0,0 +1,100 @@
From 64b76c7ca5cf5b4ede2f4b423114f46141890e1e Mon Sep 17 00:00:00 2001
From: Robert Ancell <robert.ancell@canonical.com>
Date: Fri, 7 Sep 2018 10:19:05 +1200
Subject: [PATCH] codegen: Change pointer casting to remove type-punning
warnings
The existing code was generating code with undefined results that modern compilers warn about:
accounts-generated.c:204:23: warning: dereferencing type-punned pointer will break strict-aliasing rules [-Wstrict-aliasing]
(GDBusArgInfo **) &_accounts_accounts_method_info_list_cached_users_OUT_ARG_pointers,
---
gio/gdbus-2.0/codegen/codegen.py | 22 +++++++++++-----------
1 file changed, 11 insertions(+), 11 deletions(-)
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index e74131cdb..0d95cdcda 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -1129,10 +1129,10 @@ class CodeGenerator:
'\n')
if len(args) > 0:
- self.outfile.write('static const _ExtendedGDBusArgInfo * const %s_pointers[] =\n'
+ self.outfile.write('static const GDBusArgInfo * const %s_pointers[] =\n'
'{\n'%(prefix))
for a in args:
- self.outfile.write(' &%s_%s,\n'%(prefix, a.name))
+ self.outfile.write(' &%s_%s.parent_struct,\n'%(prefix, a.name))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1175,10 +1175,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusMethodInfo * const _%s_method_info_pointers[] =\n'
+ self.outfile.write('static const GDBusMethodInfo * const _%s_method_info_pointers[] =\n'
'{\n'%(i.name_lower))
for m in i.methods:
- self.outfile.write(' &_%s_method_info_%s,\n'%(i.name_lower, m.name_lower))
+ self.outfile.write(' &_%s_method_info_%s.parent_struct,\n'%(i.name_lower, m.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1209,10 +1209,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusSignalInfo * const _%s_signal_info_pointers[] =\n'
+ self.outfile.write('static const GDBusSignalInfo * const _%s_signal_info_pointers[] =\n'
'{\n'%(i.name_lower))
for s in i.signals:
- self.outfile.write(' &_%s_signal_info_%s,\n'%(i.name_lower, s.name_lower))
+ self.outfile.write(' &_%s_signal_info_%s.parent_struct,\n'%(i.name_lower, s.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1251,10 +1251,10 @@ class CodeGenerator:
self.outfile.write('};\n'
'\n')
- self.outfile.write('static const _ExtendedGDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
+ self.outfile.write('static const GDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
'{\n'%(i.name_lower))
for p in i.properties:
- self.outfile.write(' &_%s_property_info_%s,\n'%(i.name_lower, p.name_lower))
+ self.outfile.write(' &_%s_property_info_%s.parent_struct,\n'%(i.name_lower, p.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
@@ -1948,7 +1948,7 @@ class CodeGenerator:
self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
' GVariant *variant;\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
- ' info = _%s_property_info_pointers[prop_id - 1];\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' variant = g_dbus_proxy_get_cached_property (G_DBUS_PROXY (object), info->parent_struct.name);\n'
' if (info->use_gvariant)\n'
' {\n'
@@ -2001,7 +2001,7 @@ class CodeGenerator:
self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
' GVariant *variant;\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
- ' info = _%s_property_info_pointers[prop_id - 1];\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' variant = g_dbus_gvalue_to_gvariant (value, G_VARIANT_TYPE (info->parent_struct.signature));\n'
' g_dbus_proxy_call (G_DBUS_PROXY (object),\n'
' "org.freedesktop.DBus.Properties.Set",\n'
@@ -2887,7 +2887,7 @@ class CodeGenerator:
' if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))\n'
' {\n'
' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
- ' _%s_schedule_emit_changed (skeleton, _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
+ ' _%s_schedule_emit_changed (skeleton, (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
' g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);\n'
' g_object_notify_by_pspec (object, pspec);\n'
' }\n'
--
2.19.1

File diff suppressed because it is too large Load Diff

@ -1,65 +0,0 @@
From ba2137b0d9ea3744155be81a5ba770c6535b46f3 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 15 Dec 2022 12:51:37 +0000
Subject: [PATCH] gvariant-serialiser: Convert endianness of offsets
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The array of offsets is little-endian, even on big-endian architectures
like s390x.
Fixes: ade71fb5 "gvariant: Don’t allow child elements to overlap with each other"
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/2839
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/gvariant-serialiser.c | 19 +++++++++++--------
1 file changed, 11 insertions(+), 8 deletions(-)
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index fadefab659..f443c2eb85 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -714,17 +714,19 @@ gvs_variable_sized_array_n_children (GVariantSerialised value)
/* Find the index of the first out-of-order element in @data, assuming that
* @data is an array of elements of given @type, starting at index @start and
* containing a further @len-@start elements. */
-#define DEFINE_FIND_UNORDERED(type) \
+#define DEFINE_FIND_UNORDERED(type, le_to_native) \
static gsize \
find_unordered_##type (const guint8 *data, gsize start, gsize len) \
{ \
gsize off; \
- type current, previous; \
+ type current_le, previous_le, current, previous; \
\
- memcpy (&previous, data + start * sizeof (current), sizeof (current)); \
+ memcpy (&previous_le, data + start * sizeof (current), sizeof (current)); \
+ previous = le_to_native (previous_le); \
for (off = (start + 1) * sizeof (current); off < len * sizeof (current); off += sizeof (current)) \
{ \
- memcpy (&current, data + off, sizeof (current)); \
+ memcpy (&current_le, data + off, sizeof (current)); \
+ current = le_to_native (current_le); \
if (current < previous) \
break; \
previous = current; \
@@ -732,10 +734,11 @@ gvs_variable_sized_array_n_children (GVariantSerialised value)
return off / sizeof (current) - 1; \
}
-DEFINE_FIND_UNORDERED (guint8);
-DEFINE_FIND_UNORDERED (guint16);
-DEFINE_FIND_UNORDERED (guint32);
-DEFINE_FIND_UNORDERED (guint64);
+#define NO_CONVERSION(x) (x)
+DEFINE_FIND_UNORDERED (guint8, NO_CONVERSION);
+DEFINE_FIND_UNORDERED (guint16, GUINT16_FROM_LE);
+DEFINE_FIND_UNORDERED (guint32, GUINT32_FROM_LE);
+DEFINE_FIND_UNORDERED (guint64, GUINT64_FROM_LE);
static GVariantSerialised
gvs_variable_sized_array_get_child (GVariantSerialised value,
--
GitLab

@ -1,199 +0,0 @@
From 78da5faccb3e065116b75b3ff87ff55381da6c76 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 15 Dec 2022 13:00:39 +0000
Subject: [PATCH 1/2] =?UTF-8?q?gvariant:=20Check=20offset=20table=20doesn?=
=?UTF-8?q?=E2=80=99t=20fall=20outside=20variant=20bounds?=
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When dereferencing the first entry in the offset table for a tuple,
check that it doesn’t fall outside the bounds of the variant first.
This prevents an out-of-bounds read from some non-normal tuples.
This bug was introduced in commit 73d0aa81c2575a5c9ae77d.
Includes a unit test, although the test will likely only catch the
original bug if run with asan enabled.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2840
oss-fuzz#54302
---
glib/gvariant-serialiser.c | 12 ++++++--
glib/tests/gvariant.c | 63 ++++++++++++++++++++++++++++++++++++++
2 files changed, 72 insertions(+), 3 deletions(-)
diff --git a/glib/gvariant-serialiser.c b/glib/gvariant-serialiser.c
index f443c2eb85..4e4a73ad17 100644
--- a/glib/gvariant-serialiser.c
+++ b/glib/gvariant-serialiser.c
@@ -984,7 +984,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value,
member_info = g_variant_type_info_member_info (value.type_info, index_);
- if (member_info->i + 1)
+ if (member_info->i + 1 &&
+ offset_size * (member_info->i + 1) <= value.size)
member_start = gvs_read_unaligned_le (value.data + value.size -
offset_size * (member_info->i + 1),
offset_size);
@@ -995,7 +996,8 @@ gvs_tuple_get_member_bounds (GVariantSerialised value,
member_start &= member_info->b;
member_start |= member_info->c;
- if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST)
+ if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_LAST &&
+ offset_size * (member_info->i + 1) <= value.size)
member_end = value.size - offset_size * (member_info->i + 1);
else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_FIXED)
@@ -1006,11 +1008,15 @@ gvs_tuple_get_member_bounds (GVariantSerialised value,
member_end = member_start + fixed_size;
}
- else /* G_VARIANT_MEMBER_ENDING_OFFSET */
+ else if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET &&
+ offset_size * (member_info->i + 2) <= value.size)
member_end = gvs_read_unaligned_le (value.data + value.size -
offset_size * (member_info->i + 2),
offset_size);
+ else /* invalid */
+ member_end = G_MAXSIZE;
+
if (out_member_start != NULL)
*out_member_start = member_start;
if (out_member_end != NULL)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index b360888e4d..98c51a1d75 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -5576,6 +5576,67 @@ test_normal_checking_tuple_offsets4 (void)
g_variant_unref (variant);
}
+/* This is a regression test that dereferencing the first element in the offset
+ * table doesn’t dereference memory before the start of the GVariant. The first
+ * element in the offset table gives the offset of the final member in the
+ * tuple (the offset table is stored in reverse), and the position of this final
+ * member is needed to check that none of the tuple members overlap with the
+ * offset table
+ *
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2840 */
+static void
+test_normal_checking_tuple_offsets5 (void)
+{
+ /* A tuple of type (sss) in normal form would have an offset table with two
+ * entries:
+ * - The first entry (lowest index in the table) gives the offset of the
+ * third `s` in the tuple, as the offset table is reversed compared to the
+ * tuple members.
+ * - The second entry (highest index in the table) gives the offset of the
+ * second `s` in the tuple.
+ * - The offset of the first `s` in the tuple is always 0.
+ *
+ * See §2.5.4 (Structures) of the GVariant specification for details, noting
+ * that the table is only layed out this way because all three members of the
+ * tuple have non-fixed sizes.
+ *
+ * It’s not clear whether the 0xaa data of this variant is part of the strings
+ * in the tuple, or part of the offset table. It doesn’t really matter. This
+ * is a regression test to check that the code to validate the offset table
+ * doesn’t unconditionally try to access the first entry in the offset table
+ * by subtracting the table size from the end of the GVariant data.
+ *
+ * In this non-normal case, that would result in an address off the start of
+ * the GVariant data, and an out-of-bounds read, because the GVariant is one
+ * byte long, but the offset table is calculated as two bytes long (with 1B
+ * sized entries) from the tuple’s type.
+ */
+ const GVariantType *data_type = G_VARIANT_TYPE ("(sss)");
+ const guint8 data[] = { 0xaa };
+ gsize size = sizeof (data);
+ GVariant *variant = NULL;
+ GVariant *normal_variant = NULL;
+ GVariant *expected = NULL;
+
+ g_test_bug ("https://gitlab.gnome.org/GNOME/glib/-/issues/2840");
+
+ variant = g_variant_new_from_data (data_type, data, size, FALSE, NULL, NULL);
+ g_assert_nonnull (variant);
+
+ g_assert_false (g_variant_is_normal_form (variant));
+
+ normal_variant = g_variant_get_normal_form (variant);
+ g_assert_nonnull (normal_variant);
+
+ expected = g_variant_new_parsed ("('', '', '')");
+ g_assert_cmpvariant (expected, variant);
+ g_assert_cmpvariant (expected, normal_variant);
+
+ g_variant_unref (expected);
+ g_variant_unref (normal_variant);
+ g_variant_unref (variant);
+}
+
/* Test that an otherwise-valid serialised GVariant is considered non-normal if
* its offset table entries are too wide.
*
@@ -5827,6 +5888,8 @@ main (int argc, char **argv)
test_normal_checking_tuple_offsets3);
g_test_add_func ("/gvariant/normal-checking/tuple-offsets4",
test_normal_checking_tuple_offsets4);
+ g_test_add_func ("/gvariant/normal-checking/tuple-offsets5",
+ test_normal_checking_tuple_offsets5);
g_test_add_func ("/gvariant/normal-checking/tuple-offsets/minimal-sized",
test_normal_checking_tuple_offsets_minimal_sized);
g_test_add_func ("/gvariant/normal-checking/empty-object-path",
--
GitLab
From 21a204147b16539b3eda3143b32844c49e29f4d4 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 15 Dec 2022 16:49:28 +0000
Subject: [PATCH 2/2] gvariant: Propagate trust when getting a child of a
serialised variant
If a variant is trusted, that means all its children are trusted, so
ensure that their checked offsets are set as such.
This allows a lot of the offset table checks to be avoided when getting
children from trusted serialised tuples, which speeds things up.
No unit test is included because this is just a performance fix. If
there are other slownesses, or regressions, in serialised `GVariant`
performance, the fuzzing setup will catch them like it did this one.
This change does reduce the time to run the oss-fuzz reproducer from 80s
to about 0.7s on my machine.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2841
oss-fuzz#54314
---
glib/gvariant-core.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/glib/gvariant-core.c b/glib/gvariant-core.c
index f441c4757e..4778022829 100644
--- a/glib/gvariant-core.c
+++ b/glib/gvariant-core.c
@@ -1198,8 +1198,8 @@ g_variant_get_child_value (GVariant *value,
child->contents.serialised.bytes =
g_bytes_ref (value->contents.serialised.bytes);
child->contents.serialised.data = s_child.data;
- child->contents.serialised.ordered_offsets_up_to = s_child.ordered_offsets_up_to;
- child->contents.serialised.checked_offsets_up_to = s_child.checked_offsets_up_to;
+ child->contents.serialised.ordered_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.ordered_offsets_up_to;
+ child->contents.serialised.checked_offsets_up_to = (value->state & STATE_TRUSTED) ? G_MAXSIZE : s_child.checked_offsets_up_to;
return child;
}
--
GitLab

@ -1,141 +0,0 @@
From 059f4f3999f1de506417611318c6f27db57fb689 Mon Sep 17 00:00:00 2001
From: Marius Vollmer <mvollmer@redhat.com>
Date: Mon, 13 Feb 2023 14:12:52 +0200
Subject: [PATCH] gdbus: Never buffer reads during server authentication
Otherwise, the content of the buffer is thrown away when switching
from reading via a GDataInputStream to unbuffered reads when waiting
for the "BEGIN" line.
(The code already tried to protect against over-reading like this by
using unbuffered reads for the last few lines of the auth protocol,
but it might already be too late at that point. The buffer of the
GDataInputStream might already contain the "BEGIN" line for example.)
This matters when connecting a sd-bus client directly to a GDBus
client. A sd-bus client optimistically sends the whole auth
conversation in one go without waiting for intermediate replies. This
is done to improve performance for the many short-lived connections
that are typically made.
---
gio/gdbusauth.c | 50 ++++++++++++++++++++++++++++++-------------------
1 file changed, 31 insertions(+), 19 deletions(-)
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index c430f0cf0..17c7d47b7 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -933,7 +933,6 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
{
gboolean ret;
ServerState state;
- GDataInputStream *dis;
GDataOutputStream *dos;
GError *local_error;
gchar *line;
@@ -949,7 +948,6 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
_g_dbus_auth_add_mechs (auth, observer);
ret = FALSE;
- dis = NULL;
dos = NULL;
mech = NULL;
negotiated_capabilities = 0;
@@ -965,13 +963,18 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
goto out;
}
- dis = G_DATA_INPUT_STREAM (g_data_input_stream_new (g_io_stream_get_input_stream (auth->priv->stream)));
+ /* We use an extremely slow (but reliable) line reader for input
+ * instead of something buffered - this basically does a recvfrom()
+ * system call per character
+ *
+ * (the problem with using GDataInputStream's read_line is that
+ * because of buffering it might start reading into the first D-Bus
+ * message that appears after "BEGIN\r\n"....)
+ */
+
dos = G_DATA_OUTPUT_STREAM (g_data_output_stream_new (g_io_stream_get_output_stream (auth->priv->stream)));
- g_filter_input_stream_set_close_base_stream (G_FILTER_INPUT_STREAM (dis), FALSE);
g_filter_output_stream_set_close_base_stream (G_FILTER_OUTPUT_STREAM (dos), FALSE);
- g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
-
/* read the NUL-byte, possibly with credentials attached */
#ifdef G_OS_UNIX
#ifndef G_CREDENTIALS_PREFER_MESSAGE_PASSING
@@ -1010,11 +1013,22 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
}
else
{
+ gchar c;
+ gssize num_read;
+
local_error = NULL;
- (void)g_data_input_stream_read_byte (dis, cancellable, &local_error);
- if (local_error != NULL)
+ num_read = g_input_stream_read (g_io_stream_get_input_stream (auth->priv->stream),
+ &c, 1,
+ cancellable, &local_error);
+ if (num_read != 1 || local_error != NULL)
{
- g_propagate_error (error, local_error);
+ if (local_error == NULL)
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _ ("Unexpected lack of content trying to read a byte"));
+ else
+ g_propagate_error (error, local_error);
goto out;
}
}
@@ -1050,7 +1064,10 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
{
case SERVER_STATE_WAITING_FOR_AUTH:
debug_print ("SERVER: WaitingForAuth");
- line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+ line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
+ &line_length,
+ cancellable,
+ error);
debug_print ("SERVER: WaitingForAuth, read '%s'", line);
if (line == NULL)
goto out;
@@ -1260,7 +1277,10 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
case SERVER_STATE_WAITING_FOR_DATA:
debug_print ("SERVER: WaitingForData");
- line = _my_g_data_input_stream_read_line (dis, &line_length, cancellable, error);
+ line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
+ &line_length,
+ cancellable,
+ error);
debug_print ("SERVER: WaitingForData, read '%s'", line);
if (line == NULL)
goto out;
@@ -1299,13 +1319,6 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
case SERVER_STATE_WAITING_FOR_BEGIN:
debug_print ("SERVER: WaitingForBegin");
- /* Use extremely slow (but reliable) line reader - this basically
- * does a recvfrom() system call per character
- *
- * (the problem with using GDataInputStream's read_line is that because of
- * buffering it might start reading into the first D-Bus message that
- * appears after "BEGIN\r\n"....)
- */
line = _my_g_input_stream_read_line_safe (g_io_stream_get_input_stream (auth->priv->stream),
&line_length,
cancellable,
@@ -1364,7 +1377,6 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
out:
g_clear_object (&mech);
- g_clear_object (&dis);
g_clear_object (&dos);
g_clear_object (&own_credentials);
--
2.41.0

File diff suppressed because it is too large Load Diff

@ -1,195 +0,0 @@
From 37e323f1d16720d662611866cde567b1d2a01d48 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Mon, 22 Jan 2024 15:29:37 +0100
Subject: [PATCH 1/2] gunixmounts: Use libmnt_monitor API for monitoring
The `GUnixMountMonitor` object implements monitoring on its own currently.
Only the `/proc/mounts` file changes are monitored. It is not aware of the
`/run/mount/utab` file changes. This file contains the userspace mount
options (e.g. `x-gvfs-notrash`, `x-gvfs-hide`) among others. There is a
problem when `/sbin/mount.<type>` (e.g. `mount.nfs`) helper programs are
used. In that case, the `/run/mount/utab` file is updated later than the
`/proc/mounts` file and thus the `GUnixMountMonitor` clients (e.g.
`gvfs-udisks2-volume-monitor`, `gvfsd-trash`) don't see the userspace
options until the next `mount-changed` signal. Let's use the `libmnt_monitor`
API for monitoring instead and emit the `mount-changed` signal also when the
`/run/mount/utab` file is changed.
Related: https://issues.redhat.com/browse/RHEL-14607
Related: https://github.com/util-linux/util-linux/pull/2607
---
gio/gunixmounts.c | 72 ++++++++++++++++++++++++++++++++++++++++++++++-
1 file changed, 71 insertions(+), 1 deletion(-)
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index 32b936259..e11b34a7d 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -202,6 +202,11 @@ static GSource *proc_mounts_watch_source;
#define endmntent(f) fclose(f)
#endif
+#ifdef HAVE_LIBMOUNT
+/* Protected by proc_mounts_source lock */
+static struct libmnt_monitor *proc_mounts_monitor = NULL;
+#endif
+
static gboolean
is_in (const char *value, const char *set[])
{
@@ -1859,7 +1864,36 @@ proc_mounts_changed (GIOChannel *channel,
GIOCondition cond,
gpointer user_data)
{
+ gboolean has_changed = FALSE;
+
+#ifdef HAVE_LIBMOUNT
+ if (cond & G_IO_IN)
+ {
+ G_LOCK (proc_mounts_source);
+ if (proc_mounts_monitor != NULL)
+ {
+ int ret;
+
+ /* The mnt_monitor_next_change function needs to be used to avoid false-positives. */
+ ret = mnt_monitor_next_change (proc_mounts_monitor, NULL, NULL);
+ if (ret == 0)
+ {
+ has_changed = TRUE;
+ ret = mnt_monitor_event_cleanup (proc_mounts_monitor);
+ }
+
+ if (ret < 0)
+ g_debug ("mnt_monitor_next_change failed: %s", g_strerror (-ret));
+ }
+ G_UNLOCK (proc_mounts_source);
+ }
+
+#else
if (cond & G_IO_ERR)
+ has_changed = TRUE;
+#endif
+
+ if (has_changed)
{
G_LOCK (proc_mounts_source);
mount_poller_time = (guint64) g_get_monotonic_time ();
@@ -1924,6 +1958,10 @@ mount_monitor_stop (void)
g_source_destroy (proc_mounts_watch_source);
proc_mounts_watch_source = NULL;
}
+
+#ifdef HAVE_LIBMOUNT
+ g_clear_pointer (&proc_mounts_monitor, mnt_unref_monitor);
+#endif
G_UNLOCK (proc_mounts_source);
if (mtab_monitor)
@@ -1965,9 +2003,37 @@ mount_monitor_start (void)
*/
if (g_str_has_prefix (mtab_path, "/proc/"))
{
- GIOChannel *proc_mounts_channel;
+ GIOChannel *proc_mounts_channel = NULL;
GError *error = NULL;
+#ifdef HAVE_LIBMOUNT
+ int ret;
+
+ G_LOCK (proc_mounts_source);
+
+ proc_mounts_monitor = mnt_new_monitor ();
+ ret = mnt_monitor_enable_kernel (proc_mounts_monitor, TRUE);
+ if (ret < 0)
+ g_warning ("mnt_monitor_enable_kernel failed: %s", g_strerror (-ret));
+
+ ret = mnt_monitor_enable_userspace (proc_mounts_monitor, TRUE, NULL);
+ if (ret < 0)
+ g_warning ("mnt_monitor_enable_userspace failed: %s", g_strerror (-ret));
+
+ ret = mnt_monitor_get_fd (proc_mounts_monitor);
+ if (ret >= 0)
+ {
+ proc_mounts_channel = g_io_channel_unix_new (ret);
+ }
+ else
+ {
+ g_set_error_literal (&error, G_IO_ERROR, g_io_error_from_errno (-ret),
+ g_strerror (-ret));
+ }
+
+ G_UNLOCK (proc_mounts_source);
+#else
proc_mounts_channel = g_io_channel_new_file (mtab_path, "r", &error);
+#endif
if (proc_mounts_channel == NULL)
{
g_warning ("Error creating IO channel for %s: %s (%s, %d)", mtab_path,
@@ -1978,7 +2044,11 @@ mount_monitor_start (void)
{
G_LOCK (proc_mounts_source);
+#ifdef HAVE_LIBMOUNT
+ proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_IN);
+#else
proc_mounts_watch_source = g_io_create_watch (proc_mounts_channel, G_IO_ERR);
+#endif
mount_poller_time = (guint64) g_get_monotonic_time ();
g_source_set_callback (proc_mounts_watch_source,
(GSourceFunc) proc_mounts_changed,
--
2.43.0
From bb7d6b8fcef36af5452071c8758f89955888469a Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Wed, 31 Jan 2024 13:35:39 +0100
Subject: [PATCH 2/2] gunixmounts: Use mnt_monitor_veil_kernel option
The previous commit enabled the `/run/mount/utab` monitoring. The problem
is that the `mount-changed` signal can be emitted twice for one mount. One
for the `/proc/mounts` file change and another one for the `/run/media/utab`
file change. This is still not ideal because e.g. the `GMount` objects for
mounts with the `x-gvfs-hide` option are added and immediately removed.
Let's enable the `mnt_monitor_veil_kernel` option to avoid this.
Related: https://github.com/util-linux/util-linux/pull/2725
---
gio/gunixmounts.c | 6 ++++++
meson.build | 4 ++++
2 files changed, 10 insertions(+)
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index e11b34a7d..6abe87414 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -2019,6 +2019,12 @@ mount_monitor_start (void)
if (ret < 0)
g_warning ("mnt_monitor_enable_userspace failed: %s", g_strerror (-ret));
+#ifdef HAVE_MNT_MONITOR_VEIL_KERNEL
+ ret = mnt_monitor_veil_kernel (proc_mounts_monitor, TRUE);
+ if (ret < 0)
+ g_warning ("mnt_monitor_veil_kernel failed: %s", g_strerror (-ret));
+#endif
+
ret = mnt_monitor_get_fd (proc_mounts_monitor);
if (ret >= 0)
{
diff --git a/meson.build b/meson.build
index a0502fe69..159703557 100644
--- a/meson.build
+++ b/meson.build
@@ -2102,6 +2102,10 @@ libmount_dep = []
if host_system == 'linux'
libmount_dep = dependency('mount', version : '>=2.23', required : get_option('libmount'))
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
+
+ if libmount_dep.found() and cc.has_function('mnt_monitor_veil_kernel', dependencies: libmount_dep)
+ glib_conf.set('HAVE_MNT_MONITOR_VEIL_KERNEL', 1)
+ endif
endif
# gnutls is used optionally by GHmac
--
2.43.0

File diff suppressed because it is too large Load Diff

@ -0,0 +1,56 @@
From d7233ef81e575e84d831414605ba6368394d88b5 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Mon, 15 Oct 2018 21:50:31 +0000
Subject: [PATCH] build-sys: Pass CFLAGS to $(DTRACE)
Fedora is using https://fedoraproject.org/wiki/Changes/Annobin
to try to ensure that all objects are built with hardening flags.
Pass down `CFLAGS` to ensure the SystemTap objects use them.
---
gio/Makefile.am | 2 +-
glib/Makefile.am | 2 +-
gobject/Makefile.am | 2 +-
3 files changed, 3 insertions(+), 3 deletions(-)
diff --git a/gio/Makefile.am b/gio/Makefile.am
index fc0b91855..05b20cdef 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -896,7 +896,7 @@ gio_probes.h: gio_probes.d
< $@.tmp > $@ && rm -f $@.tmp
gio_probes.lo: gio_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += gio_probes.h gio_probes.lo
CLEANFILES += gio_probes.h gio_probes.h.tmp
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 90d33d082..39163aa7f 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -386,7 +386,7 @@ glib_probes.h: glib_probes.d
< $@.tmp > $@ && rm -f $@.tmp
glib_probes.lo: glib_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += glib_probes.h glib_probes.lo
CLEANFILES += glib_probes.h glib_probes.h.tmp
diff --git a/gobject/Makefile.am b/gobject/Makefile.am
index 4c28acdff..78748e96c 100644
--- a/gobject/Makefile.am
+++ b/gobject/Makefile.am
@@ -119,7 +119,7 @@ gobject_probes.h: gobject_probes.d
< $@.tmp > $@ && rm -f $@.tmp
gobject_probes.lo: gobject_probes.d
- $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC $(DTRACE) -G -s $< -o $@
+ $(AM_V_GEN) $(LIBTOOL) --mode=compile $(AM_V_lt) --tag=CC env CFLAGS="$(CFLAGS)" $(DTRACE) -G -s $< -o $@
BUILT_SOURCES += gobject_probes.h gobject_probes.lo
CLEANFILES += gobject_probes.h
--
2.21.0

@ -0,0 +1,27 @@
From fe803a6da0c7d73cd689d905258847384e11d1fd Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 17 Dec 2018 14:36:07 -0500
Subject: [PATCH] gdbus unix addresses test: don't g_debug when also testing
stdout
At the moment the gdbus-unix-addresses test will fail if
G_MESSAGES_DEBUG is set, since the test checks stdout, and the
test has a g_debug call.
This commit drops the g_debug call, which isn't that useful anyway.
---
gio/tests/gdbus-unix-addresses.c | 1 -
1 file changed, 1 deletion(-)
diff --git a/gio/tests/gdbus-unix-addresses.c b/gio/tests/gdbus-unix-addresses.c
index e08328711..d020edd06 100644
--- a/gio/tests/gdbus-unix-addresses.c
+++ b/gio/tests/gdbus-unix-addresses.c
@@ -106,7 +106,6 @@ set_up_mock_dbus_launch (void)
{
path = g_strconcat (g_test_get_dir (G_TEST_BUILT), ":",
g_getenv ("PATH"), NULL);
- g_debug ("PATH=%s", path);
g_setenv ("PATH", path, TRUE);
/* libdbus won't even try X11 autolaunch if DISPLAY is unset; GDBus

@ -0,0 +1,613 @@
From aea538fe703652fd0a39b2ac9185133849cfdcc4 Mon Sep 17 00:00:00 2001
From: Thomas Jost <schnouki@schnouki.net>
Date: Thu, 13 Dec 2018 03:06:02 -0800
Subject: [PATCH] gdbus-codegen: honor "Property.EmitsChangedSignal"
annotations
Co-Authored-by: Andy Holmes <andrew.g.r.holmes@gmail.com>
---
gio/gdbus-2.0/codegen/codegen.py | 18 ++++++++++-----
gio/gdbus-2.0/codegen/dbustypes.py | 7 ++++++
gio/tests/gdbus-test-codegen.c | 36 +++++++++++++++++++++++++-----
gio/tests/test-codegen.xml | 6 +++++
4 files changed, 56 insertions(+), 11 deletions(-)
diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py
index f6892af95..442bd3f5d 100644
--- a/gio/gdbus-2.0/codegen/codegen.py
+++ b/gio/gdbus-2.0/codegen/codegen.py
@@ -638,61 +638,62 @@ class CodeGenerator:
'# include <gio/gunixfdlist.h>\n'
'#endif\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusArgInfo parent_struct;\n'
' gboolean use_gvariant;\n'
'} _ExtendedGDBusArgInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusMethodInfo parent_struct;\n'
' const gchar *signal_name;\n'
' gboolean pass_fdlist;\n'
'} _ExtendedGDBusMethodInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusSignalInfo parent_struct;\n'
' const gchar *signal_name;\n'
'} _ExtendedGDBusSignalInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusPropertyInfo parent_struct;\n'
' const gchar *hyphen_name;\n'
- ' gboolean use_gvariant;\n'
+ ' guint use_gvariant : 1;\n'
+ ' guint emits_changed_signal : 1;\n'
'} _ExtendedGDBusPropertyInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' GDBusInterfaceInfo parent_struct;\n'
' const gchar *hyphen_name;\n'
'} _ExtendedGDBusInterfaceInfo;\n'
'\n')
self.outfile.write('typedef struct\n'
'{\n'
' const _ExtendedGDBusPropertyInfo *info;\n'
' guint prop_id;\n'
' GValue orig_value; /* the value before the change */\n'
'} ChangedProperty;\n'
'\n'
'static void\n'
'_changed_property_free (ChangedProperty *data)\n'
'{\n'
' g_value_unset (&data->orig_value);\n'
' g_free (data);\n'
'}\n'
'\n')
self.outfile.write('static gboolean\n'
'_g_strv_equal0 (gchar **a, gchar **b)\n'
'{\n'
' gboolean ret = FALSE;\n'
' guint n;\n'
@@ -933,63 +934,67 @@ class CodeGenerator:
'\n')
# ---
if len(i.properties) > 0:
for p in i.properties:
if p.readable and p.writable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE | G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
elif p.readable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_READABLE'
elif p.writable:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_WRITABLE'
else:
access = 'G_DBUS_PROPERTY_INFO_FLAGS_NONE'
num_anno = self.generate_annotations('_%s_property_%s_annotation_info'%(i.name_lower, p.name_lower), p.annotations)
self.outfile.write('static const _ExtendedGDBusPropertyInfo _%s_property_info_%s =\n'
'{\n'
' {\n'
' -1,\n'
' (gchar *) "%s",\n'
' (gchar *) "%s",\n'
' %s,\n'%(i.name_lower, p.name_lower, p.name, p.arg.signature, access))
if num_anno == 0:
self.outfile.write(' NULL\n')
else:
self.outfile.write(' (GDBusAnnotationInfo **) &_%s_property_%s_annotation_info_pointers\n'%(i.name_lower, p.name_lower))
self.outfile.write(' },\n'
' "%s",\n'
%(p.name_hyphen))
if not utils.lookup_annotation(p.annotations, 'org.gtk.GDBus.C.ForceGVariant'):
- self.outfile.write(' FALSE\n')
+ self.outfile.write(' FALSE,\n')
else:
+ self.outfile.write(' TRUE,\n')
+ if p.emits_changed_signal:
self.outfile.write(' TRUE\n')
+ else:
+ self.outfile.write(' FALSE\n')
self.outfile.write('};\n'
'\n')
self.outfile.write('static const GDBusPropertyInfo * const _%s_property_info_pointers[] =\n'
'{\n'%(i.name_lower))
for p in i.properties:
self.outfile.write(' &_%s_property_info_%s.parent_struct,\n'%(i.name_lower, p.name_lower))
self.outfile.write(' NULL\n'
'};\n'
'\n')
num_anno = self.generate_annotations('_%s_annotation_info'%(i.name_lower), i.annotations)
self.outfile.write('static const _ExtendedGDBusInterfaceInfo _%s_interface_info =\n'
'{\n'
' {\n'
' -1,\n'
' (gchar *) "%s",\n'%(i.name_lower, i.name))
if len(i.methods) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusMethodInfo **) &_%s_method_info_pointers,\n'%(i.name_lower))
if len(i.signals) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusSignalInfo **) &_%s_signal_info_pointers,\n'%(i.name_lower))
if len(i.properties) == 0:
self.outfile.write(' NULL,\n')
else:
self.outfile.write(' (GDBusPropertyInfo **) &_%s_property_info_pointers,\n'%(i.name_lower))
if num_anno == 0:
@@ -2568,68 +2573,71 @@ class CodeGenerator:
# this allows use of g_object_freeze_notify()/g_object_thaw_notify() ...
# This is useful when updating several properties from another thread than
# where the idle will be emitted from
self.outfile.write('static void\n'
'%s_skeleton_notify (GObject *object,\n'
' GParamSpec *pspec G_GNUC_UNUSED)\n'
'{\n'
' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
' g_mutex_lock (&skeleton->priv->lock);\n'
' if (skeleton->priv->changed_properties != NULL &&\n'
' skeleton->priv->changed_properties_idle_source == NULL)\n'
' {\n'
' skeleton->priv->changed_properties_idle_source = g_idle_source_new ();\n'
' g_source_set_priority (skeleton->priv->changed_properties_idle_source, G_PRIORITY_DEFAULT);\n'
' g_source_set_callback (skeleton->priv->changed_properties_idle_source, _%s_emit_changed, g_object_ref (skeleton), (GDestroyNotify) g_object_unref);\n'
' g_source_set_name (skeleton->priv->changed_properties_idle_source, "[generated] _%s_emit_changed");\n'
' g_source_attach (skeleton->priv->changed_properties_idle_source, skeleton->priv->context);\n'
' g_source_unref (skeleton->priv->changed_properties_idle_source);\n'
' }\n'
' g_mutex_unlock (&skeleton->priv->lock);\n'
'}\n'
'\n'
%(i.name_lower, i.camel_name, i.ns_upper, i.name_upper, i.name_lower, i.name_lower))
self.outfile.write('static void\n'
'%s_skeleton_set_property (GObject *object,\n'
' guint prop_id,\n'
' const GValue *value,\n'
' GParamSpec *pspec)\n'
'{\n'%(i.name_lower))
- self.outfile.write(' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
+ self.outfile.write(' const _ExtendedGDBusPropertyInfo *info;\n'
+ ' %sSkeleton *skeleton = %s%s_SKELETON (object);\n'
' g_assert (prop_id != 0 && prop_id - 1 < %d);\n'
+ ' info = (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1];\n'
' g_mutex_lock (&skeleton->priv->lock);\n'
' g_object_freeze_notify (object);\n'
' if (!_g_value_equal (value, &skeleton->priv->properties[prop_id - 1]))\n'
' {\n'
- ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL)\n'
- ' _%s_schedule_emit_changed (skeleton, (const _ExtendedGDBusPropertyInfo *) _%s_property_info_pointers[prop_id - 1], prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
+ ' if (g_dbus_interface_skeleton_get_connection (G_DBUS_INTERFACE_SKELETON (skeleton)) != NULL &&\n'
+ ' info->emits_changed_signal)\n'
+ ' _%s_schedule_emit_changed (skeleton, info, prop_id, &skeleton->priv->properties[prop_id - 1]);\n'
' g_value_copy (value, &skeleton->priv->properties[prop_id - 1]);\n'
' g_object_notify_by_pspec (object, pspec);\n'
' }\n'
' g_mutex_unlock (&skeleton->priv->lock);\n'
' g_object_thaw_notify (object);\n'
%(i.camel_name, i.ns_upper, i.name_upper, len(i.properties), i.name_lower, i.name_lower))
self.outfile.write('}\n'
'\n')
self.outfile.write('static void\n'
'%s_skeleton_init (%sSkeleton *skeleton)\n'
'{\n'
'#if GLIB_VERSION_MAX_ALLOWED >= GLIB_VERSION_2_38\n'
' skeleton->priv = %s_skeleton_get_instance_private (skeleton);\n'
'#else\n'
' skeleton->priv = G_TYPE_INSTANCE_GET_PRIVATE (skeleton, %sTYPE_%s_SKELETON, %sSkeletonPrivate);\n'
'#endif\n\n'
%(i.name_lower, i.camel_name,
i.name_lower,
i.ns_upper, i.name_upper, i.camel_name))
self.outfile.write(' g_mutex_init (&skeleton->priv->lock);\n')
self.outfile.write(' skeleton->priv->context = g_main_context_ref_thread_default ();\n')
if len(i.properties) > 0:
self.outfile.write(' skeleton->priv->properties = g_new0 (GValue, %d);\n'%(len(i.properties)))
n = 0
for p in i.properties:
self.outfile.write(' g_value_init (&skeleton->priv->properties[%d], %s);\n'%(n, p.arg.gtype))
n += 1
self.outfile.write('}\n'
'\n')
diff --git a/gio/gdbus-2.0/codegen/dbustypes.py b/gio/gdbus-2.0/codegen/dbustypes.py
index bfc69f596..359880ff7 100644
--- a/gio/gdbus-2.0/codegen/dbustypes.py
+++ b/gio/gdbus-2.0/codegen/dbustypes.py
@@ -300,89 +300,96 @@ class Signal:
arg_count = 0
for a in self.args:
a.post_process(interface_prefix, cns, cns_upper, cns_lower, arg_count)
arg_count += 1
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
class Property:
def __init__(self, name, signature, access):
self.name = name
self.signature = signature
self.access = access
self.annotations = []
self.arg = Arg('value', self.signature)
self.arg.annotations = self.annotations
self.readable = False
self.writable = False
if self.access == 'readwrite':
self.readable = True
self.writable = True
elif self.access == 'read':
self.readable = True
elif self.access == 'write':
self.writable = True
else:
print_error('Invalid access type "{}"'.format(self.access))
self.doc_string = ''
self.since = ''
self.deprecated = False
+ self.emits_changed_signal = True
def post_process(self, interface_prefix, cns, cns_upper, cns_lower, containing_iface):
if len(self.doc_string) == 0:
self.doc_string = utils.lookup_docs(self.annotations)
if len(self.since) == 0:
self.since = utils.lookup_since(self.annotations)
if len(self.since) == 0:
self.since = containing_iface.since
name = self.name
overridden_name = utils.lookup_annotation(self.annotations, 'org.gtk.GDBus.C.Name')
if utils.is_ugly_case(overridden_name):
self.name_lower = overridden_name.lower()
else:
if overridden_name:
name = overridden_name
self.name_lower = utils.camel_case_to_uscore(name).lower().replace('-', '_')
self.name_hyphen = self.name_lower.replace('_', '-')
# don't clash with the GType getter, e.g.: GType foo_bar_get_type (void); G_GNUC_CONST
if self.name_lower == 'type':
self.name_lower = 'type_'
# recalculate arg
self.arg.annotations = self.annotations
self.arg.post_process(interface_prefix, cns, cns_upper, cns_lower, 0)
if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Deprecated') == 'true':
self.deprecated = True
+ # FIXME: for now we only support 'false' and 'const' on the signal itself, see #674913 and
+ # http://dbus.freedesktop.org/doc/dbus-specification.html#introspection-format
+ # for details
+ if utils.lookup_annotation(self.annotations, 'org.freedesktop.DBus.Property.EmitsChangedSignal') in ('false', 'const'):
+ self.emits_changed_signal = False
+
class Interface:
def __init__(self, name):
self.name = name
self.methods = []
self.signals = []
self.properties = []
self.annotations = []
self.doc_string = ''
self.doc_string_brief = ''
self.since = ''
self.deprecated = False
def post_process(self, interface_prefix, c_namespace):
if len(self.doc_string) == 0:
self.doc_string = utils.lookup_docs(self.annotations)
if len(self.doc_string_brief) == 0:
self.doc_string_brief = utils.lookup_brief_docs(self.annotations)
if len(self.since) == 0:
self.since = utils.lookup_since(self.annotations)
if len(c_namespace) > 0:
if utils.is_ugly_case(c_namespace):
cns = c_namespace.replace('_', '')
cns_upper = c_namespace.upper() + '_'
cns_lower = c_namespace.lower() + '_'
else:
cns = c_namespace
cns_upper = utils.camel_case_to_uscore(c_namespace).upper() + '_'
cns_lower = utils.camel_case_to_uscore(c_namespace).lower() + '_'
else:
diff --git a/gio/tests/gdbus-test-codegen.c b/gio/tests/gdbus-test-codegen.c
index 1c4e83c4c..c906d05ae 100644
--- a/gio/tests/gdbus-test-codegen.c
+++ b/gio/tests/gdbus-test-codegen.c
@@ -1740,103 +1740,127 @@ on_object_proxy_added (GDBusObjectManagerClient *manager,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_added_signals += 1;
g_signal_connect (object_proxy,
"interface-added",
G_CALLBACK (on_interface_added),
om_data);
g_signal_connect (object_proxy,
"interface-removed",
G_CALLBACK (on_interface_removed),
om_data);
}
static void
on_object_proxy_removed (GDBusObjectManagerClient *manager,
GDBusObjectProxy *object_proxy,
gpointer user_data)
{
OMData *om_data = user_data;
om_data->num_object_proxy_removed_signals += 1;
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_added),
om_data), ==, 1);
g_assert_cmpint (g_signal_handlers_disconnect_by_func (object_proxy,
G_CALLBACK (on_interface_removed),
om_data), ==, 1);
}
static void
-property_d_changed (GObject *object,
- GParamSpec *pspec,
- gpointer user_data)
+property_changed (GObject *object,
+ GParamSpec *pspec,
+ gpointer user_data)
{
gboolean *changed = user_data;
*changed = TRUE;
}
static void
om_check_property_and_signal_emission (GMainLoop *loop,
FooiGenBar *skeleton,
FooiGenBar *proxy)
{
gboolean d_changed = FALSE;
+ gboolean quiet_changed = FALSE;
+ gboolean quiet_too_changed = FALSE;
guint handler;
/* First PropertiesChanged */
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 0);
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 0);
foo_igen_bar_set_i (skeleton, 1);
_g_assert_property_notify (proxy, "i");
g_assert_cmpint (foo_igen_bar_get_i (skeleton), ==, 1);
g_assert_cmpint (foo_igen_bar_get_i (proxy), ==, 1);
/* Double-check the gdouble case */
g_assert_cmpfloat (foo_igen_bar_get_d (skeleton), ==, 0.0);
g_assert_cmpfloat (foo_igen_bar_get_d (proxy), ==, 0.0);
foo_igen_bar_set_d (skeleton, 1.0);
_g_assert_property_notify (proxy, "d");
/* Verify that re-setting it to the same value doesn't cause a
* notify on the proxy, by taking advantage of the fact that
* notifications are serialized.
*/
handler = g_signal_connect (proxy, "notify::d",
- G_CALLBACK (property_d_changed), &d_changed);
+ G_CALLBACK (property_changed), &d_changed);
foo_igen_bar_set_d (skeleton, 1.0);
foo_igen_bar_set_i (skeleton, 2);
_g_assert_property_notify (proxy, "i");
g_assert (d_changed == FALSE);
g_signal_handler_disconnect (proxy, handler);
+ /* Verify that re-setting a property with the "EmitsChangedSignal"
+ * set to false doesn't emit a signal. */
+ handler = g_signal_connect (proxy, "notify::quiet",
+ G_CALLBACK (property_changed), &quiet_changed);
+ foo_igen_bar_set_quiet (skeleton, "hush!");
+ foo_igen_bar_set_i (skeleton, 3);
+ _g_assert_property_notify (proxy, "i");
+ g_assert (quiet_changed == FALSE);
+ g_assert_cmpstr (foo_igen_bar_get_quiet (skeleton), ==, "hush!");
+ g_signal_handler_disconnect (proxy, handler);
+
+ /* Also verify that re-setting a property with the "EmitsChangedSignal"
+ * set to 'const' doesn't emit a signal. */
+ handler = g_signal_connect (proxy, "notify::quiet-too",
+ G_CALLBACK (property_changed), &quiet_changed);
+ foo_igen_bar_set_quiet_too (skeleton, "hush too!");
+ foo_igen_bar_set_i (skeleton, 4);
+ _g_assert_property_notify (proxy, "i");
+ g_assert (quiet_too_changed == FALSE);
+ g_assert_cmpstr (foo_igen_bar_get_quiet_too (skeleton), ==, "hush too!");
+ g_signal_handler_disconnect (proxy, handler);
+
/* Then just a regular signal */
foo_igen_bar_emit_another_signal (skeleton, "word");
_g_assert_signal_received (proxy, "another-signal");
}
static void
check_object_manager (void)
{
FooiGenObjectSkeleton *o = NULL;
FooiGenObjectSkeleton *o2 = NULL;
FooiGenObjectSkeleton *o3 = NULL;
GDBusInterfaceSkeleton *i;
GDBusConnection *c;
GDBusObjectManagerServer *manager = NULL;
GDBusNodeInfo *info;
GError *error;
GMainLoop *loop;
OMData *om_data = NULL;
guint om_signal_id = -1;
GDBusObjectManager *pm = NULL;
GList *object_proxies;
GList *proxies;
GDBusObject *op;
GDBusProxy *p;
FooiGenBar *bar_skeleton;
GDBusInterface *iface;
gchar *path, *name, *name_owner;
GDBusConnection *c2;
GDBusObjectManagerClientFlags flags;
@@ -2124,73 +2148,73 @@ check_object_manager (void)
"({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}},)");
/* -------------------------------------------------- */
/* create a new object with two interfaces */
o2 = foo_igen_object_skeleton_new ("/managed/second");
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bar_skeleton_new ());
bar_skeleton = FOO_IGEN_BAR (i); /* save for later test */
foo_igen_object_skeleton_set_bar (o2, FOO_IGEN_BAR (i));
g_clear_object (&i);
i = G_DBUS_INTERFACE_SKELETON (foo_igen_bat_skeleton_new ());
foo_igen_object_skeleton_set_bat (o2, FOO_IGEN_BAT (i));
g_clear_object (&i);
/* ... add it */
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (o2));
/* ... check we get the InterfacesAdded with _two_ interfaces */
om_data->state = 101;
g_main_loop_run (om_data->loop);
g_assert_cmpint (om_data->state, ==, 102);
g_assert_cmpint (om_data->num_object_proxy_added_signals, ==, 5);
g_assert_cmpint (om_data->num_object_proxy_removed_signals, ==, 3);
g_assert_cmpint (om_data->num_interface_added_signals, ==, 1);
g_assert_cmpint (om_data->num_interface_removed_signals, ==, 1);
/* -------------------------------------------------- */
/* Now that we have a couple of objects with interfaces, check
* that ObjectManager.GetManagedObjects() works
*/
om_check_get_all (c, loop,
- "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Set connection to NULL, causing everything to be unexported.. verify this.. and
* then set the connection back.. and then check things still work
*/
g_dbus_object_manager_server_set_connection (manager, NULL);
info = introspect (c, g_dbus_connection_get_unique_name (c), "/managed", loop);
g_assert_cmpint (count_interfaces (info), ==, 0); /* nothing */
g_dbus_node_info_unref (info);
g_dbus_object_manager_server_set_connection (manager, c);
om_check_get_all (c, loop,
- "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
+ "({objectpath '/managed/first': {'com.acme.Coyote': {'Mood': <''>}}, '/managed/second': {'org.project.Bar': {'y': <byte 0x00>, 'b': <false>, 'n': <int16 0>, 'q': <uint16 0>, 'i': <0>, 'u': <uint32 0>, 'x': <int64 0>, 't': <uint64 0>, 'd': <0.0>, 's': <''>, 'o': <objectpath '/'>, 'g': <signature ''>, 'ay': <b''>, 'as': <@as []>, 'aay': <@aay []>, 'ao': <@ao []>, 'ag': <@ag []>, 'FinallyNormalName': <''>, 'ReadonlyProperty': <''>, 'quiet': <''>, 'quiet_too': <''>, 'unset_i': <0>, 'unset_d': <0.0>, 'unset_s': <''>, 'unset_o': <objectpath '/'>, 'unset_g': <signature ''>, 'unset_ay': <b''>, 'unset_as': <@as []>, 'unset_ao': <@ao []>, 'unset_ag': <@ag []>, 'unset_struct': <(0, 0.0, '', objectpath '/', signature '', @ay [], @as [], @ao [], @ag [])>}, 'org.project.Bat': {'force_i': <0>, 'force_s': <''>, 'force_ay': <@ay []>, 'force_struct': <(0,)>}}},)");
/* Also check that the ObjectManagerClient returns these objects - and
* that they are of the right GType cf. what was requested via
* the generated ::get-proxy-type signal handler
*/
object_proxies = g_dbus_object_manager_get_objects (pm);
g_assert (g_list_length (object_proxies) == 2);
g_list_free_full (object_proxies, g_object_unref);
op = g_dbus_object_manager_get_object (pm, "/managed/first");
g_assert (op != NULL);
g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/first");
proxies = g_dbus_object_get_interfaces (op);
g_assert (g_list_length (proxies) == 1);
g_list_free_full (proxies, g_object_unref);
p = G_DBUS_PROXY (foo_igen_object_get_com_acme_coyote (FOO_IGEN_OBJECT (op)));
g_assert (p != NULL);
g_assert_cmpint (G_TYPE_FROM_INSTANCE (p), ==, FOO_IGEN_TYPE_COM_ACME_COYOTE_PROXY);
g_assert (g_type_is_a (G_TYPE_FROM_INSTANCE (p), FOO_IGEN_TYPE_COM_ACME_COYOTE));
g_clear_object (&p);
p = (GDBusProxy *) g_dbus_object_get_interface (op, "org.project.NonExisting");
g_assert (p == NULL);
g_clear_object (&op);
/* -- */
op = g_dbus_object_manager_get_object (pm, "/managed/second");
g_assert (op != NULL);
g_assert (FOO_IGEN_IS_OBJECT_PROXY (op));
g_assert_cmpstr (g_dbus_object_get_object_path (op), ==, "/managed/second");
proxies = g_dbus_object_get_interfaces (op);
diff --git a/gio/tests/test-codegen.xml b/gio/tests/test-codegen.xml
index 885a21f77..39d8769c7 100644
--- a/gio/tests/test-codegen.xml
+++ b/gio/tests/test-codegen.xml
@@ -79,60 +79,66 @@
<arg type="aay" name="array_of_bytestrings" />
<arg type="a{s(ii)}" name="dict_s_to_pairs" />
</signal>
<signal name="AnotherSignal">
<arg type="s" name="word" />
</signal>
<property name="y" type="y" access="readwrite">
<annotation name="org.gtk.GDBus.DocString" value="&lt;para&gt;Property docs, yah...&lt;/para&gt;&lt;para&gt;Second paragraph.&lt;/para&gt;"/>
</property>
<property name="b" type="b" access="readwrite"/>
<property name="n" type="n" access="readwrite"/>
<property name="q" type="q" access="readwrite"/>
<property name="i" type="i" access="readwrite"/>
<property name="u" type="u" access="readwrite"/>
<property name="x" type="x" access="readwrite"/>
<property name="t" type="t" access="readwrite"/>
<property name="d" type="d" access="readwrite"/>
<property name="s" type="s" access="readwrite"/>
<property name="o" type="o" access="readwrite"/>
<property name="g" type="g" access="readwrite"/>
<property name="ay" type="ay" access="readwrite"/>
<property name="as" type="as" access="readwrite"/>
<property name="aay" type="aay" access="readwrite"/>
<property name="ao" type="ao" access="readwrite"/>
<property name="ag" type="ag" access="readwrite"/>
<property name="FinallyNormalName" type="s" access="readwrite"/>
<property name="ReadonlyProperty" type="s" access="read"/>
<property name="WriteonlyProperty" type="s" access="write"/>
+ <property name="quiet" type="s" access="readwrite">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="false"/>
+ </property>
+ <property name="quiet_too" type="s" access="readwrite">
+ <annotation name="org.freedesktop.DBus.Property.EmitsChangedSignal" value="const"/>
+ </property>
<!-- unset properties -->
<property name="unset_i" type="i" access="readwrite"/>
<property name="unset_d" type="d" access="readwrite"/>
<property name="unset_s" type="s" access="readwrite"/>
<property name="unset_o" type="o" access="readwrite"/>
<property name="unset_g" type="g" access="readwrite"/>
<property name="unset_ay" type="ay" access="readwrite"/>
<property name="unset_as" type="as" access="readwrite"/>
<property name="unset_ao" type="ao" access="readwrite"/>
<property name="unset_ag" type="ag" access="readwrite"/>
<property name="unset_struct" type="(idsogayasaoag)" access="readwrite"/>
</interface> <!-- End org.project.Bar -->
<!-- Namespaced -->
<interface name="org.project.Bar.Frobnicator">
<method name="RandomMethod"/>
</interface>
<!-- Empty -->
<interface name="org.project.Baz">
</interface>
<!-- Outside D-Bus prefix -->
<interface name="com.acme.Coyote">
<method name="Run"/>
<method name="Sleep"/>
<method name="Attack"/>
<signal name="Surprised"/>
<property name="Mood" type="s" access="read"/>
--
2.21.0

@ -0,0 +1,702 @@
From 9e5a53d576765819d1c7c233515b9f6e5d77eb61 Mon Sep 17 00:00:00 2001
From: Emmanuele Bassi <ebassi@gnome.org>
Date: Wed, 17 Jan 2018 16:38:45 +0000
Subject: [PATCH] Add reference counting types
We have a common pattern for reference counting in GLib, but we always
implement it with ad hoc code. This is a good chance at trying to
standardise the implementation and make it public, so that other code
using GLib can take advantage of shared behaviour and semantics.
Instead of simply taking an integer variable, we should create type
aliases, to immediately distinguish the reference counting semantics of
the code; we can handle mixing atomic reference counting with a
non-atomic type (and vice versa) by using differently signed values for
the atomic and non-atomic cases.
The gatomicrefcount type is modelled on the Linux kernel refcount_t
type; the grefcount type is added to let single-threaded code bases to
avoid paying the price of atomic memory barriers on reference counting
operations.
---
docs/reference/glib/glib-docs.xml | 1 +
docs/reference/glib/glib-sections.txt | 15 ++
glib/Makefile.am | 2 +
glib/glib.h | 1 +
glib/grefcount.c | 285 ++++++++++++++++++++++++++
glib/grefcount.h | 52 +++++
glib/gtypes.h | 3 +
glib/meson.build | 2 +
8 files changed, 361 insertions(+)
create mode 100644 glib/grefcount.c
create mode 100644 glib/grefcount.h
diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml
index a0716c1727..26cdafb67b 100644
--- a/docs/reference/glib/glib-docs.xml
+++ b/docs/reference/glib/glib-docs.xml
@@ -119,6 +119,7 @@
<xi:include href="xml/gvariant.xml"/>
<xi:include href="gvariant-varargs.xml"/>
<xi:include href="gvariant-text.xml"/>
+ <xi:include href="xml/refcount.xml"/>
</chapter>
<chapter id="deprecated">
diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt
index 0183b0898a..331d92c75f 100644
--- a/docs/reference/glib/glib-sections.txt
+++ b/docs/reference/glib/glib-sections.txt
@@ -3449,3 +3449,18 @@ g_hostname_is_ip_address
g_uuid_string_is_valid
g_uuid_string_random
</SECTION>
+
+<SECTION>
+<FILE>refcount</FILE>
+grefcount
+g_ref_count_init
+g_ref_count_inc
+g_ref_count_dec
+g_ref_count_compare
+<SUBSECTION>
+gatomicrefcount
+g_atomic_ref_count_init
+g_atomic_ref_count_inc
+g_atomic_ref_count_dec
+g_atomic_ref_count_compare
+</SECTION>
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 0497061265..4d04e09daa 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -149,6 +149,7 @@ libglib_2_0_la_SOURCES = \
gquark.c \
gqueue.c \
grand.c \
+ grefcount.c \
gregex.c \
gscanner.c \
gscripttable.h \
@@ -284,6 +285,7 @@ glibsubinclude_HEADERS = \
gquark.h \
gqueue.h \
grand.h \
+ grefcount.h \
gregex.h \
gscanner.h \
gsequence.h \
diff --git a/glib/glib.h b/glib/glib.h
index 4f5a7f702f..84299c4f90 100644
--- a/glib/glib.h
+++ b/glib/glib.h
@@ -69,6 +69,7 @@
#include <glib/gquark.h>
#include <glib/gqueue.h>
#include <glib/grand.h>
+#include <glib/grefcount.h>
#include <glib/gregex.h>
#include <glib/gscanner.h>
#include <glib/gsequence.h>
diff --git a/glib/grefcount.c b/glib/grefcount.c
new file mode 100644
index 0000000000..10e35a217d
--- /dev/null
+++ b/glib/grefcount.c
@@ -0,0 +1,285 @@
+/* grefcount.c: Reference counting
+ *
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+/**
+ * SECTION:refcount
+ * @Title: Reference counting
+ * @Short_description: Reference counting types and functions
+ *
+ * Reference counting is a garbage collection mechanism that is based on
+ * assigning a counter to a data type, or any memory area; the counter is
+ * increased whenever a new reference to that data type is acquired, and
+ * decreased whenever the reference is released. Once the last reference
+ * is released, the resources associated to that data type are freed.
+ *
+ * GLib uses reference counting in many of its data types, and provides
+ * the #grefcount and #gatomicrefcount types to implement safe and atomic
+ * reference counting semantics in new data types.
+ *
+ * It is important to note that #grefcount and #gatomicrefcount should be
+ * considered completely opaque types; you should always use the provided
+ * API to increase and decrease the counters, and you should never check
+ * their content directly, or compare their content with other values.
+ *
+ * Since: 2.58
+ */
+
+#include "config.h"
+
+#include "grefcount.h"
+
+#include "gatomic.h"
+#include "gmessages.h"
+
+/**
+ * grefcount:
+ *
+ * A type for implementing non-atomic reference count semantics.
+ *
+ * Use g_ref_count_init() to initialize it; g_ref_count_inc() to
+ * increase the counter, and g_ref_count_dec() to decrease it.
+ *
+ * It is safe to use #grefcount only if you're expecting to operate
+ * on the reference counter from a single thread. It is entirely up
+ * to you to ensure that all reference count changes happen in the
+ * same thread.
+ *
+ * See also: #gatomicrefcount
+ *
+ * Since: 2.58
+ */
+
+/**
+ * gatomicrefcount:
+ *
+ * A type for implementing atomic reference count semantics.
+ *
+ * Use g_atomic_ref_count_init() to initialize it; g_atomic_ref_count_inc()
+ * to increase the counter, and g_atomic_ref_count_dec() to decrease it.
+ *
+ * It is safe to use #gatomicrefcount if you're expecting to operate on the
+ * reference counter from multiple threads.
+ *
+ * See also: #grefcount
+ *
+ * Since: 2.58
+ */
+
+/**
+ * g_ref_count_init:
+ * @rc: the address of a reference count variable
+ *
+ * Initializes a reference count variable.
+ *
+ * Since: 2.58
+ */
+void
+g_ref_count_init (grefcount *rc)
+{
+ g_return_if_fail (rc != NULL);
+
+ /* Non-atomic refcounting is implemented using the negative range
+ * of signed integers:
+ *
+ * G_MININT Z¯< 0 > Z⁺ G_MAXINT
+ * |----------------------------|----------------------------|
+ *
+ * Acquiring a reference moves us towards MININT, and releasing a
+ * reference moves us towards 0.
+ */
+ *rc = -1;
+}
+
+/**
+ * g_ref_count_inc:
+ * @rc: the address of a reference count variable
+ *
+ * Increases the reference count.
+ *
+ * Since: 2.58
+ */
+void
+g_ref_count_inc (grefcount *rc)
+{
+ grefcount rrc;
+
+ g_return_if_fail (rc != NULL);
+
+ rrc = *rc;
+
+ g_return_if_fail (rrc < 0);
+
+ /* Check for saturation */
+ if (rrc == G_MININT)
+ {
+ g_critical ("Reference count %p has reached saturation", rc);
+ return;
+ }
+
+ rrc -= 1;
+
+ *rc = rrc;
+}
+
+/**
+ * g_ref_count_dec:
+ * @rc: the address of a reference count variable
+ *
+ * Decreases the reference count.
+ *
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
+ *
+ * Since: 2.58
+ */
+gboolean
+g_ref_count_dec (grefcount *rc)
+{
+ grefcount rrc;
+
+ g_return_val_if_fail (rc != NULL, FALSE);
+
+ rrc = *rc;
+
+ g_return_val_if_fail (rrc < 0, FALSE);
+
+ rrc += 1;
+ if (rrc == 0)
+ return TRUE;
+
+ *rc = rrc;
+
+ return FALSE;
+}
+
+/**
+ * g_ref_count_compare:
+ * @rc: the address of a reference count variable
+ * @val: the value to compare
+ *
+ * Compares the current value of @rc with @val.
+ *
+ * Returns: %TRUE if the reference count is the same
+ * as the given value
+ *
+ * Since: 2.58
+ */
+gboolean
+g_ref_count_compare (grefcount *rc,
+ gint val)
+{
+ grefcount rrc;
+
+ g_return_val_if_fail (rc != NULL, FALSE);
+ g_return_val_if_fail (val >= 0, FALSE);
+
+ rrc = *rc;
+
+ if (val == G_MAXINT)
+ return rrc == G_MININT;
+
+ return rrc == -val;
+}
+
+/**
+ * g_atomic_ref_count_init:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically initializes a reference count variable.
+ *
+ * Since: 2.58
+ */
+void
+g_atomic_ref_count_init (gatomicrefcount *arc)
+{
+ g_return_if_fail (arc != NULL);
+
+ /* Atomic refcounting is implemented using the positive range
+ * of signed integers:
+ *
+ * G_MININT Z¯< 0 > Z⁺ G_MAXINT
+ * |----------------------------|----------------------------|
+ *
+ * Acquiring a reference moves us towards MAXINT, and releasing a
+ * reference moves us towards 0.
+ */
+ g_atomic_int_set (arc, 1);
+}
+
+/**
+ * g_atomic_ref_count_inc:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically increases the reference count.
+ *
+ * Since: 2.58
+ */
+void
+g_atomic_ref_count_inc (gatomicrefcount *arc)
+{
+ g_return_if_fail (arc != NULL);
+ g_return_if_fail (g_atomic_int_get (arc) > 0);
+
+ if (g_atomic_int_get (arc) == G_MAXINT)
+ {
+ g_critical ("Reference count has reached saturation");
+ return;
+ }
+
+ g_atomic_int_inc (arc);
+}
+
+/**
+ * g_atomic_ref_count_dec:
+ * @arc: the address of an atomic reference count variable
+ *
+ * Atomically decreases the reference count.
+ *
+ * Returns: %TRUE if the reference count reached 0, and %FALSE otherwise
+ *
+ * Since: 2.58
+ */
+gboolean
+g_atomic_ref_count_dec (gatomicrefcount *arc)
+{
+ g_return_val_if_fail (arc != NULL, FALSE);
+ g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
+
+ return g_atomic_int_dec_and_test (arc);
+}
+
+/**
+ * g_atomic_ref_count_compare:
+ * @arc: the address of an atomic reference count variable
+ * @val: the value to compare
+ *
+ * Atomically compares the current value of @arc with @val.
+ *
+ * Returns: %TRUE if the reference count is the same
+ * as the given value
+ *
+ * Since: 2.58
+ */
+gboolean
+g_atomic_ref_count_compare (gatomicrefcount *arc,
+ gint val)
+{
+ g_return_val_if_fail (arc != NULL, FALSE);
+ g_return_val_if_fail (val >= 0, FALSE);
+
+ return g_atomic_int_get (arc) == val;
+}
diff --git a/glib/grefcount.h b/glib/grefcount.h
new file mode 100644
index 0000000000..b24c71e8cb
--- /dev/null
+++ b/glib/grefcount.h
@@ -0,0 +1,52 @@
+/* grefcount.h: Reference counting
+ *
+ * Copyright 2018 Emmanuele Bassi
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __GREFCOUNT_H__
+#define __GREFCOUNT_H__
+
+#if !defined (__GLIB_H_INSIDE__) && !defined (GLIB_COMPILATION)
+#error "Only <glib.h> can be included directly."
+#endif
+
+#include <glib/gtypes.h>
+
+G_BEGIN_DECLS
+
+GLIB_AVAILABLE_IN_2_56
+void g_ref_count_init (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+void g_ref_count_inc (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_ref_count_dec (grefcount *rc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_ref_count_compare (grefcount *rc,
+ gint val);
+
+GLIB_AVAILABLE_IN_2_56
+void g_atomic_ref_count_init (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+void g_atomic_ref_count_inc (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_atomic_ref_count_dec (gatomicrefcount *arc);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
+ gint val);
+
+G_END_DECLS
+
+#endif /* __GREFCOUNT_H__ */
diff --git a/glib/gtypes.h b/glib/gtypes.h
index 09d9bd1456..67adb7f1f8 100644
--- a/glib/gtypes.h
+++ b/glib/gtypes.h
@@ -510,6 +510,9 @@ struct _GTimeVal
glong tv_usec;
};
+typedef gint grefcount;
+typedef volatile gint gatomicrefcount;
+
G_END_DECLS
/* We prefix variable declarations so they can
diff --git a/glib/meson.build b/glib/meson.build
index 036d1f4d60..76d354c2a7 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -76,6 +76,7 @@ glib_sub_headers = files(
'gquark.h',
'gqueue.h',
'grand.h',
+ 'grefcount.h',
'gregex.h',
'gscanner.h',
'gsequence.h',
@@ -159,6 +160,7 @@ glib_sources = files(
'gquark.c',
'gqueue.c',
'grand.c',
+ 'grefcount.c',
'gregex.c',
'gscanner.c',
'gsequence.c',
--
GitLab
From 827c208cbf9cc0ef17b8c4531a40aafe1edc3f01 Mon Sep 17 00:00:00 2001
From: Emmanuele Bassi <ebassi@gnome.org>
Date: Mon, 4 Jun 2018 11:38:40 +0100
Subject: [PATCH] Use macros for refcount types API
If we're using GCC we can use __extension__ to inline the grefcount and
gatomicrefcount API, and avoid the function call.
These macros are only enabled if G_DISABLE_CHECKS is defined, as they
remove critical warnings when the reference counters achieve saturation.
---
glib/grefcount.c | 20 +++++++-------
glib/grefcount.h | 70 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 80 insertions(+), 10 deletions(-)
diff --git a/glib/grefcount.c b/glib/grefcount.c
index 10e35a217d..37085316b9 100644
--- a/glib/grefcount.c
+++ b/glib/grefcount.c
@@ -89,7 +89,7 @@
* Since: 2.58
*/
void
-g_ref_count_init (grefcount *rc)
+(g_ref_count_init) (grefcount *rc)
{
g_return_if_fail (rc != NULL);
@@ -114,7 +114,7 @@ g_ref_count_init (grefcount *rc)
* Since: 2.58
*/
void
-g_ref_count_inc (grefcount *rc)
+(g_ref_count_inc) (grefcount *rc)
{
grefcount rrc;
@@ -147,7 +147,7 @@ g_ref_count_inc (grefcount *rc)
* Since: 2.58
*/
gboolean
-g_ref_count_dec (grefcount *rc)
+(g_ref_count_dec) (grefcount *rc)
{
grefcount rrc;
@@ -179,8 +179,8 @@ g_ref_count_dec (grefcount *rc)
* Since: 2.58
*/
gboolean
-g_ref_count_compare (grefcount *rc,
- gint val)
+(g_ref_count_compare) (grefcount *rc,
+ gint val)
{
grefcount rrc;
@@ -204,7 +204,7 @@ g_ref_count_compare (grefcount *rc,
* Since: 2.58
*/
void
-g_atomic_ref_count_init (gatomicrefcount *arc)
+(g_atomic_ref_count_init) (gatomicrefcount *arc)
{
g_return_if_fail (arc != NULL);
@@ -229,7 +229,7 @@ g_atomic_ref_count_init (gatomicrefcount *arc)
* Since: 2.58
*/
void
-g_atomic_ref_count_inc (gatomicrefcount *arc)
+(g_atomic_ref_count_inc) (gatomicrefcount *arc)
{
g_return_if_fail (arc != NULL);
g_return_if_fail (g_atomic_int_get (arc) > 0);
@@ -254,7 +254,7 @@ g_atomic_ref_count_inc (gatomicrefcount *arc)
* Since: 2.58
*/
gboolean
-g_atomic_ref_count_dec (gatomicrefcount *arc)
+(g_atomic_ref_count_dec) (gatomicrefcount *arc)
{
g_return_val_if_fail (arc != NULL, FALSE);
g_return_val_if_fail (g_atomic_int_get (arc) > 0, FALSE);
@@ -275,8 +275,8 @@ g_atomic_ref_count_dec (gatomicrefcount *arc)
* Since: 2.58
*/
gboolean
-g_atomic_ref_count_compare (gatomicrefcount *arc,
- gint val)
+(g_atomic_ref_count_compare) (gatomicrefcount *arc,
+ gint val)
{
g_return_val_if_fail (arc != NULL, FALSE);
g_return_val_if_fail (val >= 0, FALSE);
diff --git a/glib/grefcount.h b/glib/grefcount.h
index b24c71e8cb..dec9a5ffb8 100644
--- a/glib/grefcount.h
+++ b/glib/grefcount.h
@@ -47,6 +47,76 @@ GLIB_AVAILABLE_IN_2_58
gboolean g_atomic_ref_count_compare (gatomicrefcount *arc,
gint val);
+/* On GCC we can use __extension__ to inline the API without using
+ * ancillary functions; we only do this when disabling checks, as
+ * it disables warnings when saturating the reference counters
+ */
+#if defined(__GNUC__) && defined(G_DISABLE_CHECKS)
+
+# define g_ref_count_init(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ *(rc) = -1; \
+ }))
+
+# define g_ref_count_inc(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ if (*(rc) == G_MININT) ; else { \
+ *(rc) -= 1; \
+ } \
+ }))
+
+# define g_ref_count_dec(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ grefcount __rc = *(rc); \
+ __rc += 1; \
+ if (__rc == 0) ; else { \
+ *(rc) = __rc; \
+ } \
+ (gboolean) (__rc == 0); \
+ }))
+
+# define g_ref_count_compare(rc,val) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (grefcount)); \
+ (void) (0 ? *(rc) ^ (val) : 1); \
+ (gboolean) (*(rc) == -(val)); \
+ }))
+
+# define g_atomic_ref_count_init(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ g_atomic_int_set ((rc), 1); \
+ }))
+
+# define g_atomic_ref_count_inc(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ (void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
+ }))
+
+# define g_atomic_ref_count_dec(rc) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ *(rc) : 1); \
+ g_atomic_int_dec_and_test ((rc)); \
+ }))
+
+# define g_atomic_ref_count_compare(rc,val) \
+ (G_GNUC_EXTENSION ({ \
+ G_STATIC_ASSERT (sizeof *(rc) == sizeof (gatomicrefcount)); \
+ (void) (0 ? *(rc) ^ (val) : 1); \
+ (gboolean) (g_atomic_int_get (rc) == (val)); \
+ }))
+
+#endif /* __GNUC__ && G_DISABLE_CHECKS */
+
G_END_DECLS
#endif /* __GREFCOUNT_H__ */
--
GitLab
From 09c149453ac969dedb1cb2d15d489d1dd81412bf Mon Sep 17 00:00:00 2001
From: Fabrice Fontaine <fontaine.fabrice@gmail.com>
Date: Sat, 13 Oct 2018 23:10:33 +0200
Subject: [PATCH] grefcount: add missing gatomic.h
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Without gatomic.h, build fails on:
In file included from garcbox.c:24:0:
garcbox.c: In function ‘g_atomic_rc_box_acquire’:
grefcount.h:101:13: error: implicit declaration of function ‘g_atomic_int_get’; did you mean ‘__atomic_store’? [-Werror=implicit-function-declaration]
(void) (g_atomic_int_get (rc) == G_MAXINT ? 0 : g_atomic_int_inc ((rc))); \
^
garcbox.c:292:3: note: in expansion of macro ‘g_atomic_ref_count_inc’
g_atomic_ref_count_inc (&real_box->ref_count);
Signed-off-by: Fabrice Fontaine <fontaine.fabrice@gmail.com>
---
glib/grefcount.h | 1 +
1 file changed, 1 insertion(+)
diff --git a/glib/grefcount.h b/glib/grefcount.h
index dec9a5ffb8..b6eced1b7d 100644
--- a/glib/grefcount.h
+++ b/glib/grefcount.h
@@ -23,6 +23,7 @@
#error "Only <glib.h> can be included directly."
#endif
+#include <glib/gatomic.h>
#include <glib/gtypes.h>
G_BEGIN_DECLS
--
GitLab

@ -0,0 +1,21 @@
From 521f9605e0ab019ec9a493153ca0c8fe4267d665 Mon Sep 17 00:00:00 2001
From: Ray Strode <rstrode@redhat.com>
Date: Mon, 17 Dec 2018 15:46:10 -0500
Subject: [PATCH] spawn: add shebang line to script
downstream tools get confused when the script is missing a shebang
line, and having a shebang line doesn't hurt, so add one.
---
glib/tests/echo-script | 1 +
1 file changed, 1 insertion(+)
diff --git a/glib/tests/echo-script b/glib/tests/echo-script
index c732ed910..b609f2d39 100755
--- a/glib/tests/echo-script
+++ b/glib/tests/echo-script
@@ -1 +1,2 @@
+#!/bin/sh
echo "echo"
--
2.20.0

@ -0,0 +1,53 @@
From d8f8f4d637ce43f8699ba94c9b7648beda0ca174 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Thu, 23 May 2019 10:41:53 +0200
Subject: [PATCH] gfile: Limit access to files when copying
file_copy_fallback creates new files with default permissions and
set the correct permissions after the operation is finished. This
might cause that the files can be accessible by more users during
the operation than expected. Use G_FILE_CREATE_PRIVATE for the new
files to limit access to those files.
---
gio/gfile.c | 11 ++++++-----
1 file changed, 6 insertions(+), 5 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 24b136d80..74b58047c 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3284,12 +3284,12 @@ file_copy_fallback (GFile *source,
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION,
- info,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE, info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, 0, info,
+ FALSE, G_FILE_CREATE_PRIVATE, info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
@@ -3297,12 +3297,13 @@ file_copy_fallback (GFile *source,
out = (GOutputStream *)g_file_replace (destination,
NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE,
cancellable, error);
}
else
{
- out = (GOutputStream *)g_file_create (destination, 0, cancellable, error);
+ out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
}
if (!out)
--
2.21.0

@ -0,0 +1,38 @@
From 32ed752130bcbccc008819a7f1ea27651c601ee2 Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Tue, 22 Jan 2019 13:26:31 -0500
Subject: [PATCH 9/9] keyfile settings: Use tighter permissions
When creating directories, create them with 700 permissions,
instead of 777.
Closes: #1658
---
gio/gkeyfilesettingsbackend.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)
diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
index f5358818e..3d793f5a8 100644
--- a/gio/gkeyfilesettingsbackend.c
+++ b/gio/gkeyfilesettingsbackend.c
@@ -113,7 +113,8 @@ g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kfsb)
contents = g_key_file_to_data (kfsb->keyfile, &length, NULL);
g_file_replace_contents (kfsb->file, contents, length, NULL, FALSE,
- G_FILE_CREATE_REPLACE_DESTINATION,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE,
NULL, NULL, NULL);
compute_checksum (kfsb->digest, contents, length);
@@ -708,7 +709,7 @@ g_keyfile_settings_backend_constructed (GObject *object)
kfsb->permission = g_simple_permission_new (TRUE);
kfsb->dir = g_file_get_parent (kfsb->file);
- g_file_make_directory_with_parents (kfsb->dir, NULL, NULL);
+ g_mkdir_with_parents (g_file_peek_path (kfsb->dir), 0700);
kfsb->file_monitor = g_file_monitor (kfsb->file, G_FILE_MONITOR_NONE, NULL, NULL);
kfsb->dir_monitor = g_file_monitor (kfsb->dir, G_FILE_MONITOR_NONE, NULL, NULL);
--
2.28.0

@ -0,0 +1,129 @@
From 89b522ed31837cb2ac107a8961fbb0f2c7fc7ccb Mon Sep 17 00:00:00 2001
From: Krzesimir Nowak <qdlacz@gmail.com>
Date: Wed, 10 Feb 2021 23:51:07 +0100
Subject: [PATCH] gbytearray: Do not accept too large byte arrays
GByteArray uses guint for storing the length of the byte array, but it
also has a constructor (g_byte_array_new_take) that takes length as a
gsize. gsize may be larger than guint (64 bits for gsize vs 32 bits
for guint). It is possible to call the function with a value greater
than G_MAXUINT, which will result in silent length truncation. This
may happen as a result of unreffing GBytes into GByteArray, so rather
be loud about it.
(Test case tweaked by Philip Withnall.)
---
glib/garray.c | 6 ++++++
glib/gbytes.c | 4 ++++
glib/tests/bytes.c | 37 +++++++++++++++++++++++++++++++++++--
3 files changed, 45 insertions(+), 2 deletions(-)
diff --git a/glib/garray.c b/glib/garray.c
index aa3c04707..271d85ad8 100644
--- a/glib/garray.c
+++ b/glib/garray.c
@@ -1666,6 +1666,10 @@ g_byte_array_new (void)
* Create byte array containing the data. The data will be owned by the array
* and will be freed with g_free(), i.e. it could be allocated using g_strdup().
*
+ * Do not use it if @len is greater than %G_MAXUINT. #GByteArray
+ * stores the length of its data in #guint, which may be shorter than
+ * #gsize.
+ *
* Since: 2.32
*
* Returns: (transfer full): a new #GByteArray
@@ -1677,6 +1681,8 @@ g_byte_array_new_take (guint8 *data,
GByteArray *array;
GRealArray *real;
+ g_return_val_if_fail (len <= G_MAXUINT, NULL);
+
array = g_byte_array_new ();
real = (GRealArray *)array;
g_assert (real->data == NULL);
diff --git a/glib/gbytes.c b/glib/gbytes.c
index 5141170d7..635b79535 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -512,6 +512,10 @@ g_bytes_unref_to_data (GBytes *bytes,
* g_bytes_new(), g_bytes_new_take() or g_byte_array_free_to_bytes(). In all
* other cases the data is copied.
*
+ * Do not use it if @bytes contains more than %G_MAXUINT
+ * bytes. #GByteArray stores the length of its data in #guint, which
+ * may be shorter than #gsize, that @bytes is using.
+ *
* Returns: (transfer full): a new mutable #GByteArray containing the same byte data
*
* Since: 2.32
diff --git a/glib/tests/bytes.c b/glib/tests/bytes.c
index 5ea5c2b35..42281307b 100644
--- a/glib/tests/bytes.c
+++ b/glib/tests/bytes.c
@@ -10,12 +10,12 @@
*/
#undef G_DISABLE_ASSERT
-#undef G_LOG_DOMAIN
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "glib.h"
+#include "glib/gstrfuncsprivate.h"
/* Keep in sync with glib/gbytes.c */
struct _GBytes
@@ -333,6 +333,38 @@ test_to_array_transferred (void)
g_byte_array_unref (array);
}
+static void
+test_to_array_transferred_oversize (void)
+{
+ g_test_message ("g_bytes_unref_to_array() can only take GBytes up to "
+ "G_MAXUINT in length; test that longer ones are rejected");
+
+ if (sizeof (guint) >= sizeof (gsize))
+ {
+ g_test_skip ("Skipping test as guint is not smaller than gsize");
+ }
+ else if (g_test_undefined ())
+ {
+ GByteArray *array = NULL;
+ GBytes *bytes = NULL;
+ gpointer data = g_memdup2 (NYAN, N_NYAN);
+ gsize len = ((gsize) G_MAXUINT) + 1;
+
+ bytes = g_bytes_new_take (data, len);
+ g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL,
+ "g_byte_array_new_take: assertion 'len <= G_MAXUINT' failed");
+ array = g_bytes_unref_to_array (g_steal_pointer (&bytes));
+ g_test_assert_expected_messages ();
+ g_assert_null (array);
+
+ g_free (data);
+ }
+ else
+ {
+ g_test_skip ("Skipping test as testing undefined behaviour is disabled");
+ }
+}
+
static void
test_to_array_two_refs (void)
{
@@ -407,7 +439,8 @@ main (int argc, char *argv[])
g_test_add_func ("/bytes/to-data/transfered", test_to_data_transferred);
g_test_add_func ("/bytes/to-data/two-refs", test_to_data_two_refs);
g_test_add_func ("/bytes/to-data/non-malloc", test_to_data_non_malloc);
- g_test_add_func ("/bytes/to-array/transfered", test_to_array_transferred);
+ g_test_add_func ("/bytes/to-array/transferred", test_to_array_transferred);
+ g_test_add_func ("/bytes/to-array/transferred-oversize", test_to_array_transferred_oversize);
g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
g_test_add_func ("/bytes/null", test_null);
--
2.31.1

@ -0,0 +1,849 @@
From 7b46597384de916b4027ebaff662d06ff3ea2bc8 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:30:52 +0000
Subject: [PATCH 1/6] gstrfuncs: Add internal g_memdup2() function
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
This will replace the existing `g_memdup()` function for use within
GLib. It has an unavoidable security flaw of taking its `byte_size`
argument as a `guint` rather than as a `gsize`. Most callers will
expect it to be a `gsize`, and may pass in large values which could
silently be truncated, resulting in an undersize allocation compared
to what the caller expects.
This could lead to a classic buffer overflow vulnerability for many
callers of `g_memdup()`.
`g_memdup2()`, in comparison, takes its `byte_size` as a `gsize`.
Spotted by Kevin Backhouse of GHSL.
In GLib 2.68, `g_memdup2()` will be a new public API. In this version
for backport to older stable releases, its a new `static inline` API
in a private header, so that use of `g_memdup()` within GLib can be
fixed without adding a new API in a stable release series.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: CVE-2021-27219
Helps: GHSL-2021-045
Helps: #2319
(cherry picked from commit 5e5f75a77e399c638be66d74e5daa8caeb433e00)
---
docs/reference/glib/meson.build | 1 +
glib/gstrfuncsprivate.h | 55 +++++++++++++++++++++++++++++++++
glib/meson.build | 1 +
glib/tests/strfuncs.c | 23 ++++++++++++++
4 files changed, 80 insertions(+)
create mode 100644 glib/gstrfuncsprivate.h
diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build
index f0f915e96..1a3680941 100644
--- a/docs/reference/glib/meson.build
+++ b/docs/reference/glib/meson.build
@@ -20,6 +20,7 @@ if get_option('gtk_doc')
'gprintfint.h',
'gmirroringtable.h',
'gscripttable.h',
+ 'gstrfuncsprivate.h',
'glib-mirroring-tab',
'gnulib',
'pcre',
diff --git a/glib/gstrfuncsprivate.h b/glib/gstrfuncsprivate.h
new file mode 100644
index 000000000..85c88328a
--- /dev/null
+++ b/glib/gstrfuncsprivate.h
@@ -0,0 +1,55 @@
+/* GLIB - Library of useful routines for C programming
+ * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <glib.h>
+#include <string.h>
+
+/*
+ * g_memdup2:
+ * @mem: (nullable): the memory to copy.
+ * @byte_size: the number of bytes to copy.
+ *
+ * Allocates @byte_size bytes of memory, and copies @byte_size bytes into it
+ * from @mem. If @mem is %NULL it returns %NULL.
+ *
+ * This replaces g_memdup(), which was prone to integer overflows when
+ * converting the argument from a #gsize to a #guint.
+ *
+ * This static inline version is a backport of the new public API from
+ * GLib 2.68, kept internal to GLib for backport to older stable releases.
+ * See https://gitlab.gnome.org/GNOME/glib/-/issues/2319.
+ *
+ * Returns: (nullable): a pointer to the newly-allocated copy of the memory,
+ * or %NULL if @mem is %NULL.
+ * Since: 2.68
+ */
+static inline gpointer
+g_memdup2 (gconstpointer mem,
+ gsize byte_size)
+{
+ gpointer new_mem;
+
+ if (mem && byte_size != 0)
+ {
+ new_mem = g_malloc (byte_size);
+ memcpy (new_mem, mem, byte_size);
+ }
+ else
+ new_mem = NULL;
+
+ return new_mem;
+}
diff --git a/glib/meson.build b/glib/meson.build
index a2f9da81c..481fd06ff 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -167,6 +167,7 @@ glib_sources = files(
'gslist.c',
'gstdio.c',
'gstrfuncs.c',
+ 'gstrfuncsprivate.h',
'gstring.c',
'gstringchunk.c',
'gtestutils.c',
diff --git a/glib/tests/strfuncs.c b/glib/tests/strfuncs.c
index 7e031bdb1..2aa252946 100644
--- a/glib/tests/strfuncs.c
+++ b/glib/tests/strfuncs.c
@@ -32,6 +32,8 @@
#include <string.h>
#include "glib.h"
+#include "gstrfuncsprivate.h"
+
#if defined (_MSC_VER) && (_MSC_VER <= 1800)
#define isnan(x) _isnan(x)
@@ -199,6 +201,26 @@ test_is_to_digit (void)
#undef TEST_DIGIT
}
+/* Testing g_memdup2() function with various positive and negative cases */
+static void
+test_memdup2 (void)
+{
+ gchar *str_dup = NULL;
+ const gchar *str = "The quick brown fox jumps over the lazy dog";
+
+ /* Testing negative cases */
+ g_assert_null (g_memdup2 (NULL, 1024));
+ g_assert_null (g_memdup2 (str, 0));
+ g_assert_null (g_memdup2 (NULL, 0));
+
+ /* Testing normal usage cases */
+ str_dup = g_memdup2 (str, strlen (str) + 1);
+ g_assert_nonnull (str_dup);
+ g_assert_cmpstr (str, ==, str_dup);
+
+ g_free (str_dup);
+}
+
static void
test_strdup (void)
{
@@ -1726,6 +1748,7 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/strfuncs/test-is-to-digit", test_is_to_digit);
+ g_test_add_func ("/strfuncs/memdup2", test_memdup2);
g_test_add_func ("/strfuncs/strdup", test_strdup);
g_test_add_func ("/strfuncs/strndup", test_strndup);
g_test_add_func ("/strfuncs/strdup-printf", test_strdup_printf);
--
2.31.1
From d6aab169954d9e6e77753dee68e1b3f5932f6dee Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:41:21 +0000
Subject: [PATCH 2/6] glib: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()` or an existing `gsize`
variable), so that they use `g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it
In particular, this fixes an overflow within `g_bytes_new()`, identified
as GHSL-2021-045 (aka CVE-2021-27219) by GHSL team member Kevin Backhouse.
Adapted for GLib 2.58 by Simon McVittie.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: CVE-2021-27219
Fixes: GHSL-2021-045
Helps: #2319
(cherry picked from commit 0736b7c1e7cf4232c5d7eb2b0fbfe9be81bd3baa)
[Backport to 2.58: Omit changes to ghash.c, will be a separate commit]
[Backport to 2.58: Omit changes to giochannel.c, not needed in this branch]
[Backport to 2.58: Omit changes to uri test, not needed in this branch]
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/gbytes.c | 6 ++++--
glib/gdir.c | 3 ++-
glib/gslice.c | 3 ++-
glib/gtestutils.c | 3 ++-
glib/gvariant.c | 7 ++++---
glib/gvarianttype.c | 3 ++-
glib/tests/array-test.c | 2 +-
glib/tests/option-context.c | 6 ++++--
8 files changed, 21 insertions(+), 12 deletions(-)
diff --git a/glib/gbytes.c b/glib/gbytes.c
index 3b14a51cd..5141170d7 100644
--- a/glib/gbytes.c
+++ b/glib/gbytes.c
@@ -33,6 +33,8 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
+
/**
* GBytes:
*
@@ -94,7 +96,7 @@ g_bytes_new (gconstpointer data,
{
g_return_val_if_fail (data != NULL || size == 0, NULL);
- return g_bytes_new_take (g_memdup (data, size), size);
+ return g_bytes_new_take (g_memdup2 (data, size), size);
}
/**
@@ -490,7 +492,7 @@ g_bytes_unref_to_data (GBytes *bytes,
* Copy: Non g_malloc (or compatible) allocator, or static memory,
* so we have to copy, and then unref.
*/
- result = g_memdup (bytes->data, bytes->size);
+ result = g_memdup2 (bytes->data, bytes->size);
*size = bytes->size;
g_bytes_unref (bytes);
}
diff --git a/glib/gdir.c b/glib/gdir.c
index cb4ad0b2f..9d955d57f 100644
--- a/glib/gdir.c
+++ b/glib/gdir.c
@@ -37,6 +37,7 @@
#include "gconvert.h"
#include "gfileutils.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gtestutils.h"
#include "glibintl.h"
@@ -113,7 +114,7 @@ g_dir_open_with_errno (const gchar *path,
return NULL;
#endif
- return g_memdup (&dir, sizeof dir);
+ return g_memdup2 (&dir, sizeof dir);
}
/**
diff --git a/glib/gslice.c b/glib/gslice.c
index 454c8a602..8e2359515 100644
--- a/glib/gslice.c
+++ b/glib/gslice.c
@@ -45,6 +45,7 @@
#include "gmain.h"
#include "gmem.h" /* gslice.h */
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gutils.h"
#include "gtrashstack.h"
#include "gtestutils.h"
@@ -352,7 +353,7 @@ g_slice_get_config_state (GSliceConfig ckey,
array[i++] = allocator->contention_counters[address];
array[i++] = allocator_get_magazine_threshold (allocator, address);
*n_values = i;
- return g_memdup (array, sizeof (array[0]) * *n_values);
+ return g_memdup2 (array, sizeof (array[0]) * *n_values);
default:
return NULL;
}
diff --git a/glib/gtestutils.c b/glib/gtestutils.c
index 0447dcda5..14e071fce 100644
--- a/glib/gtestutils.c
+++ b/glib/gtestutils.c
@@ -49,6 +49,7 @@
#include "gpattern.h"
#include "grand.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gtimer.h"
#include "gslice.h"
#include "gspawn.h"
@@ -3397,7 +3398,7 @@ g_test_log_extract (GTestLogBuffer *tbuffer)
if (p <= tbuffer->data->str + mlength)
{
g_string_erase (tbuffer->data, 0, mlength);
- tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup (&msg, sizeof (msg)));
+ tbuffer->msgs = g_slist_prepend (tbuffer->msgs, g_memdup2 (&msg, sizeof (msg)));
return TRUE;
}
diff --git a/glib/gvariant.c b/glib/gvariant.c
index 8be9ce798..45a1a73dc 100644
--- a/glib/gvariant.c
+++ b/glib/gvariant.c
@@ -33,6 +33,7 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
/**
* SECTION:gvariant
@@ -720,7 +721,7 @@ g_variant_new_variant (GVariant *value)
g_variant_ref_sink (value);
return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
- g_memdup (&value, sizeof value),
+ g_memdup2 (&value, sizeof value),
1, g_variant_is_trusted (value));
}
@@ -1224,7 +1225,7 @@ g_variant_new_fixed_array (const GVariantType *element_type,
return NULL;
}
- data = g_memdup (elements, n_elements * element_size);
+ data = g_memdup2 (elements, n_elements * element_size);
value = g_variant_new_from_data (array_type, data,
n_elements * element_size,
FALSE, g_free, data);
@@ -1901,7 +1902,7 @@ g_variant_dup_bytestring (GVariant *value,
if (length)
*length = size;
- return g_memdup (original, size + 1);
+ return g_memdup2 (original, size + 1);
}
/**
diff --git a/glib/gvarianttype.c b/glib/gvarianttype.c
index c8433e65a..dbbf7d2d1 100644
--- a/glib/gvarianttype.c
+++ b/glib/gvarianttype.c
@@ -28,6 +28,7 @@
#include <string.h>
+#include "gstrfuncsprivate.h"
/**
* SECTION:gvarianttype
@@ -1174,7 +1175,7 @@ g_variant_type_new_tuple (const GVariantType * const *items,
g_assert (offset < sizeof buffer);
buffer[offset++] = ')';
- return (GVariantType *) g_memdup (buffer, offset);
+ return (GVariantType *) g_memdup2 (buffer, offset);
}
/**
--
2.31.1
From 7e2c2a07508a97b9d75e402afe4749b02a34dd8b Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 18 Mar 2021 10:31:00 +0000
Subject: [PATCH 3/6] ghash: Use g_memdup2() instead of g_memdup()
Backport of part of commit 0736b7c1e7cf4232c5d7eb2b0fbfe9be81bd3baa
to the simpler structure of the GHashTable code in glib-2-58.
Helps: #2319
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/ghash.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/glib/ghash.c b/glib/ghash.c
index 6bb04a50d..608d136f4 100644
--- a/glib/ghash.c
+++ b/glib/ghash.c
@@ -34,6 +34,7 @@
#include "glib-private.h"
#include "gstrfuncs.h"
+#include "gstrfuncsprivate.h"
#include "gatomic.h"
#include "gtestutils.h"
#include "gslice.h"
@@ -967,7 +968,7 @@ g_hash_table_insert_node (GHashTable *hash_table,
* split the table.
*/
if (G_UNLIKELY (hash_table->keys == hash_table->values && hash_table->keys[node_index] != new_value))
- hash_table->values = g_memdup (hash_table->keys, sizeof (gpointer) * hash_table->size);
+ hash_table->values = g_memdup2 (hash_table->keys, sizeof (gpointer) * hash_table->size);
/* Step 3: Actually do the write */
hash_table->values[node_index] = new_value;
--
2.31.1
From 9e0c87610dccd1b0eaca28a3baa521ea6a24f46b Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:39:25 +0000
Subject: [PATCH 4/6] gobject: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
(cherry picked from commit 6110caea45b235420b98cd41d845cc92238f6781)
---
gobject/gsignal.c | 3 ++-
gobject/gtype.c | 9 +++++----
gobject/gtypemodule.c | 3 ++-
gobject/tests/param.c | 4 +++-
4 files changed, 12 insertions(+), 7 deletions(-)
diff --git a/gobject/gsignal.c b/gobject/gsignal.c
index b22dfcca8..92555eb60 100644
--- a/gobject/gsignal.c
+++ b/gobject/gsignal.c
@@ -28,6 +28,7 @@
#include <signal.h>
#include "gsignal.h"
+#include "gstrfuncsprivate.h"
#include "gtype-private.h"
#include "gbsearcharray.h"
#include "gvaluecollector.h"
@@ -1724,7 +1725,7 @@ g_signal_newv (const gchar *signal_name,
node->single_va_closure_is_valid = FALSE;
node->flags = signal_flags & G_SIGNAL_FLAGS_MASK;
node->n_params = n_params;
- node->param_types = g_memdup (param_types, sizeof (GType) * n_params);
+ node->param_types = g_memdup2 (param_types, sizeof (GType) * n_params);
node->return_type = return_type;
node->class_closure_bsa = NULL;
if (accumulator)
diff --git a/gobject/gtype.c b/gobject/gtype.c
index 275a8b60b..9e663ce52 100644
--- a/gobject/gtype.c
+++ b/gobject/gtype.c
@@ -33,6 +33,7 @@
#include "glib-private.h"
#include "gconstructor.h"
+#include "gstrfuncsprivate.h"
#ifdef G_OS_WIN32
#include <windows.h>
@@ -1471,7 +1472,7 @@ type_add_interface_Wm (TypeNode *node,
iholder->next = iface_node_get_holders_L (iface);
iface_node_set_holders_W (iface, iholder);
iholder->instance_type = NODE_TYPE (node);
- iholder->info = info ? g_memdup (info, sizeof (*info)) : NULL;
+ iholder->info = info ? g_memdup2 (info, sizeof (*info)) : NULL;
iholder->plugin = plugin;
/* create an iface entry for this type */
@@ -1732,7 +1733,7 @@ type_iface_retrieve_holder_info_Wm (TypeNode *iface,
INVALID_RECURSION ("g_type_plugin_*", iholder->plugin, NODE_NAME (iface));
check_interface_info_I (iface, instance_type, &tmp_info);
- iholder->info = g_memdup (&tmp_info, sizeof (tmp_info));
+ iholder->info = g_memdup2 (&tmp_info, sizeof (tmp_info));
}
return iholder; /* we don't modify write lock upon returning NULL */
@@ -2013,10 +2014,10 @@ type_iface_vtable_base_init_Wm (TypeNode *iface,
IFaceEntry *pentry = type_lookup_iface_entry_L (pnode, iface);
if (pentry)
- vtable = g_memdup (pentry->vtable, iface->data->iface.vtable_size);
+ vtable = g_memdup2 (pentry->vtable, iface->data->iface.vtable_size);
}
if (!vtable)
- vtable = g_memdup (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
+ vtable = g_memdup2 (iface->data->iface.dflt_vtable, iface->data->iface.vtable_size);
entry->vtable = vtable;
vtable->g_type = NODE_TYPE (iface);
vtable->g_instance_type = NODE_TYPE (node);
diff --git a/gobject/gtypemodule.c b/gobject/gtypemodule.c
index c67f789b1..cf877bc0b 100644
--- a/gobject/gtypemodule.c
+++ b/gobject/gtypemodule.c
@@ -19,6 +19,7 @@
#include <stdlib.h>
+#include "gstrfuncsprivate.h"
#include "gtypeplugin.h"
#include "gtypemodule.h"
@@ -436,7 +437,7 @@ g_type_module_register_type (GTypeModule *module,
module_type_info->loaded = TRUE;
module_type_info->info = *type_info;
if (type_info->value_table)
- module_type_info->info.value_table = g_memdup (type_info->value_table,
+ module_type_info->info.value_table = g_memdup2 (type_info->value_table,
sizeof (GTypeValueTable));
return module_type_info->type;
diff --git a/gobject/tests/param.c b/gobject/tests/param.c
index 758289bf8..971cff162 100644
--- a/gobject/tests/param.c
+++ b/gobject/tests/param.c
@@ -2,6 +2,8 @@
#include <glib-object.h>
#include <stdlib.h>
+#include "gstrfuncsprivate.h"
+
static void
test_param_value (void)
{
@@ -851,7 +853,7 @@ main (int argc, char *argv[])
test_path = g_strdup_printf ("/param/implement/subprocess/%d-%d-%d-%d",
data.change_this_flag, data.change_this_type,
data.use_this_flag, data.use_this_type);
- test_data = g_memdup (&data, sizeof (TestParamImplementData));
+ test_data = g_memdup2 (&data, sizeof (TestParamImplementData));
g_test_add_data_func_full (test_path, test_data, test_param_implement_child, g_free);
g_free (test_path);
}
--
2.31.1
From d3f7a79540fc1e85eb82c2987e9f7e2dbd93ff74 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Thu, 4 Feb 2021 13:37:56 +0000
Subject: [PATCH 5/6] gio: Use g_memdup2() instead of g_memdup() in obvious
places
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Convert all the call sites which use `g_memdup()`s length argument
trivially (for example, by passing a `sizeof()`), so that they use
`g_memdup2()` instead.
In almost all of these cases the use of `g_memdup()` would not have
caused problems, but it will soon be deprecated, so best port away from
it.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #2319
(cherry picked from commit be8834340a2d928ece82025463ae23dee2c333d0)
---
gio/gdbusconnection.c | 5 +++--
gio/gdbusinterfaceskeleton.c | 3 ++-
gio/gfile.c | 7 ++++---
gio/gsettingsschema.c | 5 +++--
gio/gwin32registrykey.c | 8 +++++---
gio/tests/async-close-output-stream.c | 6 ++++--
gio/tests/gdbus-export.c | 5 +++--
gio/win32/gwinhttpfile.c | 9 +++++----
8 files changed, 29 insertions(+), 19 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 6f7e5fefc..117c8df35 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -119,6 +119,7 @@
#include "gasyncinitable.h"
#include "giostream.h"
#include "gasyncresult.h"
+#include "gstrfuncsprivate.h"
#include "gtask.h"
#ifdef G_OS_UNIX
@@ -3970,7 +3971,7 @@ _g_dbus_interface_vtable_copy (const GDBusInterfaceVTable *vtable)
/* Don't waste memory by copying padding - remember to update this
* when changing struct _GDBusInterfaceVTable in gdbusconnection.h
*/
- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
}
static void
@@ -3987,7 +3988,7 @@ _g_dbus_subtree_vtable_copy (const GDBusSubtreeVTable *vtable)
/* Don't waste memory by copying padding - remember to update this
* when changing struct _GDBusSubtreeVTable in gdbusconnection.h
*/
- return g_memdup ((gconstpointer) vtable, 3 * sizeof (gpointer));
+ return g_memdup2 ((gconstpointer) vtable, 3 * sizeof (gpointer));
}
static void
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 96bd520aa..672604c49 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -27,6 +27,7 @@
#include "gdbusprivate.h"
#include "gdbusmethodinvocation.h"
#include "gdbusconnection.h"
+#include "gstrfuncsprivate.h"
#include "gtask.h"
#include "gioerror.h"
@@ -697,7 +698,7 @@ add_connection_locked (GDBusInterfaceSkeleton *interface_,
* properly before building the hooked_vtable, so we create it
* once at the last minute.
*/
- interface_->priv->hooked_vtable = g_memdup (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
+ interface_->priv->hooked_vtable = g_memdup2 (g_dbus_interface_skeleton_get_vtable (interface_), sizeof (GDBusInterfaceVTable));
interface_->priv->hooked_vtable->method_call = skeleton_intercept_handle_method_call;
}
diff --git a/gio/gfile.c b/gio/gfile.c
index ff313ebf8..29ebaaa62 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -60,6 +60,7 @@
#include "gasyncresult.h"
#include "gioerror.h"
#include "glibintl.h"
+#include "gstrfuncsprivate.h"
/**
@@ -7734,7 +7735,7 @@ measure_disk_usage_progress (gboolean reporting,
g_main_context_invoke_full (g_task_get_context (task),
g_task_get_priority (task),
measure_disk_usage_invoke_progress,
- g_memdup (&progress, sizeof progress),
+ g_memdup2 (&progress, sizeof progress),
g_free);
}
@@ -7752,7 +7753,7 @@ measure_disk_usage_thread (GTask *task,
data->progress_callback ? measure_disk_usage_progress : NULL, task,
&result.disk_usage, &result.num_dirs, &result.num_files,
&error))
- g_task_return_pointer (task, g_memdup (&result, sizeof result), g_free);
+ g_task_return_pointer (task, g_memdup2 (&result, sizeof result), g_free);
else
g_task_return_error (task, error);
}
@@ -7776,7 +7777,7 @@ g_file_real_measure_disk_usage_async (GFile *file,
task = g_task_new (file, cancellable, callback, user_data);
g_task_set_source_tag (task, g_file_real_measure_disk_usage_async);
- g_task_set_task_data (task, g_memdup (&data, sizeof data), g_free);
+ g_task_set_task_data (task, g_memdup2 (&data, sizeof data), g_free);
g_task_set_priority (task, io_priority);
g_task_run_in_thread (task, measure_disk_usage_thread);
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index 17b7e3b01..499944395 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -20,6 +20,7 @@
#include "gsettingsschema-internal.h"
#include "gsettings.h"
+#include "gstrfuncsprivate.h"
#include "gvdb/gvdb-reader.h"
#include "strinfo.c"
@@ -1054,9 +1055,9 @@ g_settings_schema_list_children (GSettingsSchema *schema)
if (g_str_has_suffix (key, "/"))
{
- gint length = strlen (key);
+ gsize length = strlen (key);
- strv[j] = g_memdup (key, length);
+ strv[j] = g_memdup2 (key, length);
strv[j][length - 1] = '\0';
j++;
}
diff --git a/gio/gwin32registrykey.c b/gio/gwin32registrykey.c
index c19fede4e..619fd48af 100644
--- a/gio/gwin32registrykey.c
+++ b/gio/gwin32registrykey.c
@@ -28,6 +28,8 @@
#include <ntstatus.h>
#include <winternl.h>
+#include "gstrfuncsprivate.h"
+
#ifndef _WDMDDK_
typedef enum _KEY_INFORMATION_CLASS {
KeyBasicInformation,
@@ -247,7 +249,7 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
new_iter->value_name_size = iter->value_name_size;
if (iter->value_data != NULL)
- new_iter->value_data = g_memdup (iter->value_data, iter->value_data_size);
+ new_iter->value_data = g_memdup2 (iter->value_data, iter->value_data_size);
new_iter->value_data_size = iter->value_data_size;
@@ -268,8 +270,8 @@ g_win32_registry_value_iter_copy (const GWin32RegistryValueIter *iter)
new_iter->value_data_expanded_charsize = iter->value_data_expanded_charsize;
if (iter->value_data_expanded_u8 != NULL)
- new_iter->value_data_expanded_u8 = g_memdup (iter->value_data_expanded_u8,
- iter->value_data_expanded_charsize);
+ new_iter->value_data_expanded_u8 = g_memdup2 (iter->value_data_expanded_u8,
+ iter->value_data_expanded_charsize);
new_iter->value_data_expanded_u8_size = iter->value_data_expanded_charsize;
diff --git a/gio/tests/async-close-output-stream.c b/gio/tests/async-close-output-stream.c
index 5f6620275..d3f97a119 100644
--- a/gio/tests/async-close-output-stream.c
+++ b/gio/tests/async-close-output-stream.c
@@ -24,6 +24,8 @@
#include <stdlib.h>
#include <string.h>
+#include "gstrfuncsprivate.h"
+
#define DATA_TO_WRITE "Hello world\n"
typedef struct
@@ -147,9 +149,9 @@ prepare_data (SetupData *data,
data->expected_size = g_memory_output_stream_get_data_size (G_MEMORY_OUTPUT_STREAM (data->data_stream));
- g_assert_cmpint (data->expected_size, >, 0);
+ g_assert_cmpuint (data->expected_size, >, 0);
- data->expected_output = g_memdup (written, (guint)data->expected_size);
+ data->expected_output = g_memdup2 (written, data->expected_size);
/* then recreate the streams and prepare them for the asynchronous close */
destroy_streams (data);
diff --git a/gio/tests/gdbus-export.c b/gio/tests/gdbus-export.c
index ef0dddeee..a3c842360 100644
--- a/gio/tests/gdbus-export.c
+++ b/gio/tests/gdbus-export.c
@@ -23,6 +23,7 @@
#include <string.h>
#include "gdbus-tests.h"
+#include "gstrfuncsprivate.h"
/* all tests rely on a shared mainloop */
static GMainLoop *loop = NULL;
@@ -652,7 +653,7 @@ subtree_introspect (GDBusConnection *connection,
g_assert_not_reached ();
}
- return g_memdup (interfaces, 2 * sizeof (void *));
+ return g_memdup2 (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
@@ -708,7 +709,7 @@ dynamic_subtree_introspect (GDBusConnection *connection,
{
const GDBusInterfaceInfo *interfaces[2] = { &dyna_interface_info, NULL };
- return g_memdup (interfaces, 2 * sizeof (void *));
+ return g_memdup2 (interfaces, 2 * sizeof (void *));
}
static const GDBusInterfaceVTable *
diff --git a/gio/win32/gwinhttpfile.c b/gio/win32/gwinhttpfile.c
index d5df16d91..f424d21cc 100644
--- a/gio/win32/gwinhttpfile.c
+++ b/gio/win32/gwinhttpfile.c
@@ -29,6 +29,7 @@
#include "gio/gfile.h"
#include "gio/gfileattribute.h"
#include "gio/gfileinfo.h"
+#include "gstrfuncsprivate.h"
#include "gwinhttpfile.h"
#include "gwinhttpfileinputstream.h"
#include "gwinhttpfileoutputstream.h"
@@ -393,10 +394,10 @@ g_winhttp_file_resolve_relative_path (GFile *file,
child = g_object_new (G_TYPE_WINHTTP_FILE, NULL);
child->vfs = winhttp_file->vfs;
child->url = winhttp_file->url;
- child->url.lpszScheme = g_memdup (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
- child->url.lpszHostName = g_memdup (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
- child->url.lpszUserName = g_memdup (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
- child->url.lpszPassword = g_memdup (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
+ child->url.lpszScheme = g_memdup2 (winhttp_file->url.lpszScheme, (winhttp_file->url.dwSchemeLength+1)*2);
+ child->url.lpszHostName = g_memdup2 (winhttp_file->url.lpszHostName, (winhttp_file->url.dwHostNameLength+1)*2);
+ child->url.lpszUserName = g_memdup2 (winhttp_file->url.lpszUserName, (winhttp_file->url.dwUserNameLength+1)*2);
+ child->url.lpszPassword = g_memdup2 (winhttp_file->url.lpszPassword, (winhttp_file->url.dwPasswordLength+1)*2);
child->url.lpszUrlPath = wnew_path;
child->url.dwUrlPathLength = wcslen (wnew_path);
child->url.lpszExtraInfo = NULL;
--
2.31.1
From 661f5edc901219a1a99bb51f171be13063878bd6 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 20 May 2021 15:58:53 -0500
Subject: [PATCH 6/6] gdatainputstream: replace easy use of g_memdup()
This code is passing a gsize, so might as well switch this to g_memdup2().
This is the only use of g_memdup() in GLib 2.56 that is not part of GLib
2.58. All other uses analyzed in glib!2000.
---
gio/gdatainputstream.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gio/gdatainputstream.c b/gio/gdatainputstream.c
index 9f207b158..ebef7c797 100644
--- a/gio/gdatainputstream.c
+++ b/gio/gdatainputstream.c
@@ -27,6 +27,7 @@
#include "gioenumtypes.h"
#include "gioerror.h"
#include "glibintl.h"
+#include "gstrfuncsprivate.h"
#include <string.h>
@@ -1082,7 +1083,7 @@ g_data_input_stream_read_async (GDataInputStream *stream,
data = g_slice_new0 (GDataInputStreamReadData);
if (stop_chars_len == -1)
stop_chars_len = strlen (stop_chars);
- data->stop_chars = g_memdup (stop_chars, stop_chars_len);
+ data->stop_chars = g_memdup2 (stop_chars, stop_chars_len);
data->stop_chars_len = stop_chars_len;
data->last_saw_cr = FALSE;
--
2.31.1

@ -0,0 +1,388 @@
From 8fef6abe1131da0c8a7211c740a12ebe11cbcc51 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 10 Mar 2021 16:05:55 +0000
Subject: [PATCH 1/3] glocalfileoutputstream: Factor out a flag check
This clarifies the code a little. It introduces no functional changes.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
---
gio/glocalfileoutputstream.c | 9 +++++----
1 file changed, 5 insertions(+), 4 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 57d2d5dfe..6a70b2a04 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -751,6 +751,7 @@ handle_overwrite_open (const char *filename,
int res;
int mode;
int errsv;
+ gboolean replace_destination_set = (flags & G_FILE_CREATE_REPLACE_DESTINATION);
mode = mode_from_flags_or_info (flags, reference_info);
@@ -857,8 +858,8 @@ handle_overwrite_open (const char *filename,
* The second strategy consist simply in copying the old file
* to a backup file and rewrite the contents of the file.
*/
-
- if ((flags & G_FILE_CREATE_REPLACE_DESTINATION) ||
+
+ if (replace_destination_set ||
(!(original_stat.st_nlink > 1) && !is_symlink))
{
char *dirname, *tmp_filename;
@@ -877,7 +878,7 @@ handle_overwrite_open (const char *filename,
/* try to keep permissions (unless replacing) */
- if ( ! (flags & G_FILE_CREATE_REPLACE_DESTINATION) &&
+ if (!replace_destination_set &&
(
#ifdef HAVE_FCHOWN
fchown (tmpfd, original_stat.st_uid, original_stat.st_gid) == -1 ||
@@ -1016,7 +1017,7 @@ handle_overwrite_open (const char *filename,
}
}
- if (flags & G_FILE_CREATE_REPLACE_DESTINATION)
+ if (replace_destination_set)
{
g_close (fd, NULL);
--
2.31.1
From 6c10e8ce6905e8fcc3466eb8af707b5d0d3bdb85 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 24 Feb 2021 17:36:07 +0000
Subject: [PATCH 2/3] glocalfileoutputstream: Fix CREATE_REPLACE_DESTINATION
with symlinks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
The `G_FILE_CREATE_REPLACE_DESTINATION` flag is equivalent to unlinking
the destination file and re-creating it from scratch. That did
previously work, but in the process the code would call `open(O_CREAT)`
on the file. If the file was a dangling symlink, this would create the
destination file (empty). Thats not an intended side-effect, and has
security implications if the symlink is controlled by a lower-privileged
process.
Fix that by not opening the destination file if its a symlink, and
adjusting the rest of the code to cope with
- the fact that `fd == -1` is not an error iff `is_symlink` is true,
- and that `original_stat` will contain the `lstat()` results for the
symlink now, rather than the `stat()` results for its target (again,
iff `is_symlink` is true).
This means that the target of the dangling symlink is no longer created,
which was the bug. The symlink itself continues to be replaced (as
before) with the new file — this is the intended behaviour of
`g_file_replace()`.
The behaviour for non-symlink cases, or cases where the symlink was not
dangling, should be unchanged.
Includes a unit test.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Fixes: #2325
---
gio/glocalfileoutputstream.c | 63 ++++++++++++++-------
gio/tests/file.c | 107 ++++++++++++++++++++++++++++++++++-
2 files changed, 149 insertions(+), 21 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 6a70b2a04..4a7766f68 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -779,16 +779,22 @@ handle_overwrite_open (const char *filename,
/* Could be a symlink, or it could be a regular ELOOP error,
* but then the next open will fail too. */
is_symlink = TRUE;
- fd = g_open (filename, open_flags, mode);
+ if (!replace_destination_set)
+ fd = g_open (filename, open_flags, mode);
}
-#else
- fd = g_open (filename, open_flags, mode);
- errsv = errno;
+#else /* if !O_NOFOLLOW */
/* This is racy, but we do it as soon as possible to minimize the race */
is_symlink = g_file_test (filename, G_FILE_TEST_IS_SYMLINK);
+
+ if (!is_symlink || !replace_destination_set)
+ {
+ fd = g_open (filename, open_flags, mode);
+ errsv = errno;
+ }
#endif
- if (fd == -1)
+ if (fd == -1 &&
+ (!is_symlink || !replace_destination_set))
{
char *display_name = g_filename_display_name (filename);
g_set_error (error, G_IO_ERROR,
@@ -800,10 +806,17 @@ handle_overwrite_open (const char *filename,
}
#ifdef G_OS_WIN32
- res = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &original_stat);
-#else
- res = fstat (fd, &original_stat);
+#error This patch has not been ported to Windows, sorry
#endif
+
+ if (!is_symlink)
+ {
+ res = fstat (fd, &original_stat);
+ }
+ else
+ {
+ res = lstat (filename, &original_stat);
+ }
errsv = errno;
if (res != 0)
@@ -821,16 +834,27 @@ handle_overwrite_open (const char *filename,
if (!S_ISREG (original_stat.st_mode))
{
if (S_ISDIR (original_stat.st_mode))
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_IS_DIRECTORY,
- _("Target file is a directory"));
- else
- g_set_error_literal (error,
- G_IO_ERROR,
- G_IO_ERROR_NOT_REGULAR_FILE,
- _("Target file is not a regular file"));
- goto err_out;
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_IS_DIRECTORY,
+ _("Target file is a directory"));
+ goto err_out;
+ }
+ else if (!is_symlink ||
+#ifdef S_ISLNK
+ !S_ISLNK (original_stat.st_mode)
+#else
+ FALSE
+#endif
+ )
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_NOT_REGULAR_FILE,
+ _("Target file is not a regular file"));
+ goto err_out;
+ }
}
if (etag != NULL)
@@ -911,7 +935,8 @@ handle_overwrite_open (const char *filename,
}
}
- g_close (fd, NULL);
+ if (fd >= 0)
+ g_close (fd, NULL);
*temp_filename = tmp_filename;
return tmpfd;
}
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 98eeb85d4..44db6e295 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -671,8 +671,6 @@ test_replace_cancel (void)
guint count;
GError *error = NULL;
- g_test_bug ("629301");
-
path = g_dir_make_tmp ("g_file_replace_cancel_XXXXXX", &error);
g_assert_no_error (error);
tmpdir = g_file_new_for_path (path);
@@ -779,6 +777,110 @@ test_replace_cancel (void)
g_object_unref (tmpdir);
}
+static void
+test_replace_symlink (void)
+{
+#ifdef G_OS_UNIX
+ gchar *tmpdir_path = NULL;
+ GFile *tmpdir = NULL, *source_file = NULL, *target_file = NULL;
+ GFileOutputStream *stream = NULL;
+ const gchar *new_contents = "this is a test message which should be written to source and not target";
+ gsize n_written;
+ GFileEnumerator *enumerator = NULL;
+ GFileInfo *info = NULL;
+ gchar *contents = NULL;
+ gsize length = 0;
+ GError *local_error = NULL;
+
+ /* Create a fresh, empty working directory. */
+ tmpdir_path = g_dir_make_tmp ("g_file_replace_symlink_XXXXXX", &local_error);
+ g_assert_no_error (local_error);
+ tmpdir = g_file_new_for_path (tmpdir_path);
+
+ g_test_message ("Using temporary directory %s", tmpdir_path);
+ g_free (tmpdir_path);
+
+ /* Create symlink `source` which points to `target`. */
+ source_file = g_file_get_child (tmpdir, "source");
+ target_file = g_file_get_child (tmpdir, "target");
+ g_file_make_symbolic_link (source_file, "target", NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ /* Ensure that `target` doesnt exist */
+ g_assert_false (g_file_query_exists (target_file, NULL));
+
+ /* Replace the `source` symlink with a regular file using
+ * %G_FILE_CREATE_REPLACE_DESTINATION, which should replace it *without*
+ * following the symlink */
+ stream = g_file_replace (source_file, NULL, FALSE /* no backup */,
+ G_FILE_CREATE_REPLACE_DESTINATION, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_output_stream_write_all (G_OUTPUT_STREAM (stream), new_contents, strlen (new_contents),
+ &n_written, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_cmpint (n_written, ==, strlen (new_contents));
+
+ g_output_stream_close (G_OUTPUT_STREAM (stream), NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_clear_object (&stream);
+
+ /* At this point, there should still only be one file: `source`. It should
+ * now be a regular file. `target` should not exist. */
+ enumerator = g_file_enumerate_children (tmpdir,
+ G_FILE_ATTRIBUTE_STANDARD_NAME ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_nonnull (info);
+
+ g_assert_cmpstr (g_file_info_get_name (info), ==, "source");
+ g_assert_cmpint (g_file_info_get_file_type (info), ==, G_FILE_TYPE_REGULAR);
+
+ g_clear_object (&info);
+
+ info = g_file_enumerator_next_file (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_assert_null (info);
+
+ g_file_enumerator_close (enumerator, NULL, &local_error);
+ g_assert_no_error (local_error);
+ g_clear_object (&enumerator);
+
+ /* Double-check that `target` doesnt exist */
+ g_assert_false (g_file_query_exists (target_file, NULL));
+
+ /* Check the content of `source`. */
+ g_file_load_contents (source_file,
+ NULL,
+ &contents,
+ &length,
+ NULL,
+ &local_error);
+ g_assert_no_error (local_error);
+ g_assert_cmpstr (contents, ==, new_contents);
+ g_assert_cmpuint (length, ==, strlen (new_contents));
+ g_free (contents);
+
+ /* Tidy up. */
+ g_file_delete (source_file, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_file_delete (tmpdir, NULL, &local_error);
+ g_assert_no_error (local_error);
+
+ g_clear_object (&target_file);
+ g_clear_object (&source_file);
+ g_clear_object (&tmpdir);
+#else /* if !G_OS_UNIX */
+ g_test_skip ("Symlink replacement tests can only be run on Unix")
+#endif
+}
+
static void
on_file_deleted (GObject *object,
GAsyncResult *result,
@@ -1170,6 +1272,7 @@ main (int argc, char *argv[])
g_test_add_data_func ("/file/async-create-delete/4096", GINT_TO_POINTER (4096), test_create_delete);
g_test_add_func ("/file/replace-load", test_replace_load);
g_test_add_func ("/file/replace-cancel", test_replace_cancel);
+ g_test_add_func ("/file/replace-symlink", test_replace_symlink);
g_test_add_func ("/file/async-delete", test_async_delete);
#ifdef G_OS_UNIX
g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
--
2.31.1
From 7f0b0d7fd744ad2f51236444005db49c80a0293d Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 24 Feb 2021 17:42:24 +0000
Subject: [PATCH 3/3] glocalfileoutputstream: Add a missing O_CLOEXEC flag to
replace()
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
---
gio/glocalfileoutputstream.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 4a7766f68..275770fa4 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -56,6 +56,12 @@
#define O_BINARY 0
#endif
+#ifndef O_CLOEXEC
+#define O_CLOEXEC 0
+#else
+#define HAVE_O_CLOEXEC 1
+#endif
+
struct _GLocalFileOutputStreamPrivate {
char *tmp_filename;
char *original_filename;
@@ -1127,7 +1133,7 @@ _g_local_file_output_stream_replace (const char *filename,
sync_on_close = FALSE;
/* If the file doesn't exist, create it */
- open_flags = O_CREAT | O_EXCL | O_BINARY;
+ open_flags = O_CREAT | O_EXCL | O_BINARY | O_CLOEXEC;
if (readable)
open_flags |= O_RDWR;
else
@@ -1157,8 +1163,11 @@ _g_local_file_output_stream_replace (const char *filename,
set_error_from_open_errno (filename, error);
return NULL;
}
-
-
+#if !defined(HAVE_O_CLOEXEC) && defined(F_SETFD)
+ else
+ fcntl (fd, F_SETFD, FD_CLOEXEC);
+#endif
+
stream = g_object_new (G_TYPE_LOCAL_FILE_OUTPUT_STREAM, NULL);
stream->priv->fd = fd;
stream->priv->sync_on_close = sync_on_close;
--
2.31.1

@ -1,17 +1,30 @@
From ff90bb8474b1e724727f4014b446e7c851e609bd Mon Sep 17 00:00:00 2001
From c5cc0bb6f2d6e468c7402915a0a4e6799f0febdf Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 18:44:43 +0000
Subject: [PATCH 1/4] ghmac: Split off wrapper functions into ghmac-utils.c
Subject: [PATCH 1/3] ghmac: Split off wrapper functions into ghmac-utils.c
Prep for adding a GnuTLS HMAC implementation; these are just
utility functions that call the "core" API.
---
glib/Makefile.am | 1 +
glib/ghmac-utils.c | 145 +++++++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 112 ----------------------------------
glib/meson.build | 1 +
3 files changed, 146 insertions(+), 112 deletions(-)
4 files changed, 147 insertions(+), 112 deletions(-)
create mode 100644 glib/ghmac-utils.c
diff --git a/glib/Makefile.am b/glib/Makefile.am
index c0c3b92f0..43fa17051 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -126,6 +126,7 @@ libglib_2_0_la_SOURCES = \
ggettext.c \
ghash.c \
ghmac.c \
+ ghmac-utils.c \
ghook.c \
ghostutils.c \
giochannel.c \
diff --git a/glib/ghmac-utils.c b/glib/ghmac-utils.c
new file mode 100644
index 000000000..a17359ff1
@ -164,7 +177,7 @@ index 000000000..a17359ff1
+ (const guchar *) str, length);
+}
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 49fd272f0..4f181f21f 100644
index 9b58fd81c..7db38e34a 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -329,115 +329,3 @@ g_hmac_get_digest (GHmac *hmac,
@ -284,10 +297,10 @@ index 49fd272f0..4f181f21f 100644
- (const guchar *) str, length);
-}
diff --git a/glib/meson.build b/glib/meson.build
index 8c18e6de4..329b8d197 100644
index c81e99f9c..306a67f13 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -253,6 +253,7 @@ glib_sources = files(
@@ -138,6 +138,7 @@ glib_sources = files(
'ggettext.c',
'ghash.c',
'ghmac.c',
@ -298,10 +311,10 @@ index 8c18e6de4..329b8d197 100644
--
2.31.1
From 5395d36e6685e0b7377794c59c5820970bb472ef Mon Sep 17 00:00:00 2001
From 3befcf1eb31e0fa7a988b22a9c24240218cd4744 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Fri, 7 Jun 2019 19:36:54 +0000
Subject: [PATCH 2/4] Add a gnutls backend for GHmac
Subject: [PATCH 2/3] Add a gnutls backend for GHmac
For RHEL we want apps to use FIPS-certified crypto libraries,
and HMAC apparently counts as "keyed" and hence needs to
@ -348,19 +361,50 @@ don't think this error should actually be hit in practice.
https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
---
glib/Makefile.am | 8 +-
glib/gchecksum.c | 9 +-
glib/gchecksumprivate.h | 32 +++++++
glib/ghmac-gnutls.c | 187 ++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 15 ++++
glib/ghmac-gnutls.c | 182 ++++++++++++++++++++++++++++++++++++++++
glib/ghmac.c | 13 +++
glib/meson.build | 10 ++-
meson.build | 7 ++
meson_options.txt | 7 +-
7 files changed, 260 insertions(+), 7 deletions(-)
meson_options.txt | 5 ++
8 files changed, 258 insertions(+), 8 deletions(-)
create mode 100644 glib/gchecksumprivate.h
create mode 100644 glib/ghmac-gnutls.c
diff --git a/glib/Makefile.am b/glib/Makefile.am
index 43fa17051..1175bbe40 100644
--- a/glib/Makefile.am
+++ b/glib/Makefile.am
@@ -125,7 +125,7 @@ libglib_2_0_la_SOURCES = \
gfileutils.c \
ggettext.c \
ghash.c \
- ghmac.c \
+ ghmac-gnutls.c \
ghmac-utils.c \
ghook.c \
ghostutils.c \
@@ -352,11 +352,15 @@ pcre_lib = pcre/libpcre.la
pcre_inc =
endif
-libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS)
+gnutls_libs = $(shell pkg-config --libs gnutls)
+gnutls_cflags = $(shell pkg-config --cflags gnutls)
+
+libglib_2_0_la_CFLAGS = $(AM_CFLAGS) $(GLIB_HIDDEN_VISIBILITY_CFLAGS) $(LIBSYSTEMD_CFLAGS) $(gnutls_cflags)
libglib_2_0_la_LIBADD = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ @ICONV_LIBS@ @G_LIBS_EXTRA@ $(pcre_lib) $(G_THREAD_LIBS_EXTRA) $(G_THREAD_LIBS_FOR_GTHREAD) $(LIBSYSTEMD_LIBS)
libglib_2_0_la_DEPENDENCIES = libcharset/libcharset.la $(printf_la) @GIO@ @GSPAWN@ @PLATFORMDEP@ $(glib_win32_res) $(glib_def)
libglib_2_0_la_LDFLAGS = $(GLIB_LINK_FLAGS) \
+ $(gnutls_libs) \
$(glib_win32_res_ldflag) \
-version-info $(LT_CURRENT):$(LT_REVISION):$(LT_AGE) \
-export-dynamic $(no_undefined)
diff --git a/glib/gchecksum.c b/glib/gchecksum.c
index 29b479bc6..929958c3a 100644
index 40b1d50e2..2f59d4a66 100644
--- a/glib/gchecksum.c
+++ b/glib/gchecksum.c
@@ -20,7 +20,7 @@
@ -383,9 +427,9 @@ index 29b479bc6..929958c3a 100644
+gchecksum_digest_to_string (guint8 *digest,
+ gsize digest_len)
{
gsize i, len = digest_len * 2;
gchar *retval;
@@ -194,6 +194,7 @@ digest_to_string (guint8 *digest,
gint len = digest_len * 2;
gint i;
@@ -195,6 +195,7 @@ digest_to_string (guint8 *digest,
return retval;
}
@ -434,10 +478,10 @@ index 000000000..86c7a3b61
\ No newline at end of file
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
new file mode 100644
index 000000000..9fb775f89
index 000000000..522b9b302
--- /dev/null
+++ b/glib/ghmac-gnutls.c
@@ -0,0 +1,187 @@
@@ -0,0 +1,182 @@
+/* ghmac.h - data hashing functions
+ *
+ * Copyright (C) 2011 Collabora Ltd.
@ -474,10 +518,6 @@ index 000000000..9fb775f89
+#include "gtypes.h"
+#include "glibintl.h"
+
+#ifndef HAVE_GNUTLS
+#error "build configuration error"
+#endif
+
+struct _GHmac
+{
+ int ref_count;
@ -516,7 +556,6 @@ index 000000000..9fb775f89
+ algo = GNUTLS_MAC_SHA512;
+ break;
+ default:
+ g_free (hmac);
+ g_return_val_if_reached (NULL);
+ }
+
@ -526,7 +565,7 @@ index 000000000..9fb775f89
+ /* There is no way to report an error here, but one possible cause of
+ * failure is that the requested digest may be disabled by FIPS mode.
+ */
+ g_free (hmac);
+ g_free (hmac->hmac);
+ return NULL;
+ }
+
@ -626,20 +665,18 @@ index 000000000..9fb775f89
+ *digest_len = g_checksum_type_get_length (hmac->digest_type);
+}
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 4f181f21f..0e39ea40a 100644
index 7db38e34a..b03a5aea7 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,6 +33,9 @@
@@ -33,6 +33,7 @@
#include "gtypes.h"
#include "glibintl.h"
+#ifdef HAVE_GNUTLS
+#error "build configuration error"
+#endif
/**
* SECTION:hmac
@@ -84,6 +87,18 @@ struct _GHmac
@@ -84,6 +85,18 @@ struct _GHmac
* Support for digests of type %G_CHECKSUM_SHA512 has been added in GLib 2.42.
* Support for %G_CHECKSUM_SHA384 was added in GLib 2.52.
*
@ -659,10 +696,18 @@ index 4f181f21f..0e39ea40a 100644
* Use g_hmac_unref() to free the memory allocated by it.
*
diff --git a/glib/meson.build b/glib/meson.build
index 329b8d197..2417de53d 100644
index 306a67f13..07d41456d 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -252,7 +252,6 @@ glib_sources = files(
@@ -127,6 +127,7 @@ glib_sources = files(
'gbytes.c',
'gcharset.c',
'gchecksum.c',
+ 'gchecksumprivate.h',
'gconvert.c',
'gdataset.c',
'gdate.c',
@@ -137,7 +138,6 @@ glib_sources = files(
'gfileutils.c',
'ggettext.c',
'ghash.c',
@ -670,15 +715,7 @@ index 329b8d197..2417de53d 100644
'ghmac-utils.c',
'ghook.c',
'ghostutils.c',
@@ -308,6 +307,7 @@ glib_sources = files(
'guriprivate.h',
'gutils.c',
'gutilsprivate.h',
+ 'gchecksumprivate.h',
'guuid.c',
'gvariant.c',
'gvariant-core.c',
@@ -352,6 +352,12 @@ else
@@ -223,6 +223,12 @@ else
glib_dtrace_hdr = []
endif
@ -691,21 +728,21 @@ index 329b8d197..2417de53d 100644
pcre_static_args = []
if use_pcre_static_flag
@@ -378,7 +384,7 @@ libglib = library('glib-2.0',
# intl.lib is not compatible with SAFESEH
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
@@ -239,7 +245,7 @@ libglib = library('glib-2.0',
link_args : platform_ldflags + noseh_link_args,
include_directories : configinc,
- dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
+ dependencies : pcre_deps + [thread_dep, librt] + libgnutls_dep + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
c_args : glib_c_args,
objc_args : glib_c_args,
link_with : [charset_lib, gnulib_lib],
- dependencies : [pcre, thread_dep, libintl, librt] + libiconv + platform_deps,
+ dependencies : [pcre, thread_dep, libintl, librt] + libgnutls_dep + libiconv + platform_deps,
c_args : ['-DG_LOG_DOMAIN="GLib"', '-DGLIB_COMPILATION'] + pcre_static_args + glib_hidden_visibility_args
)
diff --git a/meson.build b/meson.build
index e2eba1871..cca15f653 100644
index 0cefee51d..eaf8d3900 100644
--- a/meson.build
+++ b/meson.build
@@ -2090,6 +2090,13 @@ if host_system == 'linux'
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
@@ -1596,6 +1596,13 @@ if host_system == 'linux' and get_option('libmount')
libmount_dep = [dependency('mount', version : '>=2.23', required : true)]
endif
+# gnutls is used optionally by ghmac
@ -719,243 +756,28 @@ index e2eba1871..cca15f653 100644
winsock2 = cc.find_library('ws2_32')
endif
diff --git a/meson_options.txt b/meson_options.txt
index 072765361..c8f26ac02 100644
index 4504c6858..d18c42a36 100644
--- a/meson_options.txt
+++ b/meson_options.txt
@@ -39,6 +39,11 @@ option('internal_pcre',
value : false,
description : 'whether to use internal PCRE')
@@ -34,6 +34,11 @@ option('libmount',
value : true,
description : 'build with libmount support')
+option('gnutls',
+ type : 'boolean',
+ value : false,
+ description : 'build with gnutls support')
+
option('man',
option('internal_pcre',
type : 'boolean',
value : false,
--
2.31.1
From 61c175277acb8d1e080305acd444201c5ad1fb81 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 16 Jun 2021 20:35:00 -0500
Subject: [PATCH 3/4] dlopen GnuTLS instead of linking directly
I'd like to enable our GnuTLS GHmac patchset in Fedora in order to
ensure it is receiving sufficient real-world testing, since we've
discovered several bugs thus far. Problem is Fedora has one requirement
that RHEL does not: it needs to build glib as a static lib. This is
needed by QEMU in Fedora for complicated technical reasons that I don't
understand. However, nothing in RHEL needs it. This means we failed to
notice that glib2-static is broken in RHEL, because there is no
gnutls-static! We could fix this by adding a gnutls-static package, but
that seems like overkill, and adding more static libraries where they're
not truly necessary is not the direction we want to move in anyway. So
instead, let's just dlopen GnuTLS to sidestep this problem entirely.
This would not be a good solution for upstream, but upstream has made
clear that this patchset is already non-upstreamable, so it will be fine
for our purposes.
---
glib/ghmac-gnutls.c | 101 ++++++++++++++++++++++++++++++++++++++++++--
glib/ghmac.c | 2 +-
glib/meson.build | 2 +-
meson.build | 6 +--
4 files changed, 102 insertions(+), 9 deletions(-)
diff --git a/glib/ghmac-gnutls.c b/glib/ghmac-gnutls.c
index 9fb775f89..1800fc2e0 100644
--- a/glib/ghmac-gnutls.c
+++ b/glib/ghmac-gnutls.c
@@ -19,8 +19,8 @@
#include "config.h"
+#include <dlfcn.h>
#include <string.h>
-#include <gnutls/crypto.h>
#include "ghmac.h"
@@ -31,13 +31,16 @@
#include "gstrfuncs.h"
#include "gchecksumprivate.h"
#include "gtestutils.h"
+#include "gthread.h"
#include "gtypes.h"
#include "glibintl.h"
-#ifndef HAVE_GNUTLS
+#ifndef USE_GNUTLS
#error "build configuration error"
#endif
+typedef gpointer gnutls_hmac_hd_t;
+
struct _GHmac
{
int ref_count;
@@ -46,15 +49,107 @@ struct _GHmac
gchar *digest_str;
};
+typedef enum
+{
+ GNUTLS_MAC_MD5 = 2,
+ GNUTLS_MAC_SHA1 = 3,
+ GNUTLS_MAC_SHA256 = 6,
+ GNUTLS_MAC_SHA384 = 7,
+ GNUTLS_MAC_SHA512 = 8,
+} gnutls_mac_algorithm_t;
+
+/* Why are we dlopening GnuTLS instead of linking to it directly? Because we
+ * want to be able to build GLib as a static library without depending on a
+ * static build of GnuTLS. QEMU depends on static linking with GLib, but Fedora
+ * does not ship a static build of GnuTLS, and this allows us to avoid changing
+ * that.
+ */
+static int (*gnutls_hmac_init) (gnutls_hmac_hd_t *dig, gnutls_mac_algorithm_t algorithm, const void *key, size_t keylen);
+static gnutls_hmac_hd_t (*gnutls_hmac_copy) (gnutls_hmac_hd_t handle);
+static void (*gnutls_hmac_deinit) (gnutls_hmac_hd_t handle, void *digest);
+static int (*gnutls_hmac) (gnutls_hmac_hd_t handle, const void *ptext, size_t ptext_len);
+static void (*gnutls_hmac_output) (gnutls_hmac_hd_t handle, void *digest);
+static const char * (*gnutls_strerror) (int error);
+
+static gsize gnutls_initialize_attempted = 0;
+static gboolean gnutls_initialize_successful = FALSE;
+
+static void
+initialize_gnutls (void)
+{
+ gpointer libgnutls;
+
+ libgnutls = dlopen ("libgnutls.so.30", RTLD_LAZY | RTLD_GLOBAL);
+ if (!libgnutls)
+ {
+ g_warning ("Cannot use GHmac: failed to load libgnutls.so.30: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_init = dlsym (libgnutls, "gnutls_hmac_init");
+ if (!gnutls_hmac_init)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_init: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_copy = dlsym (libgnutls, "gnutls_hmac_copy");
+ if (!gnutls_hmac_copy)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_copy: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_deinit = dlsym (libgnutls, "gnutls_hmac_deinit");
+ if (!gnutls_hmac_deinit)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_deinit: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac = dlsym (libgnutls, "gnutls_hmac");
+ if (!gnutls_hmac)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac: %s", dlerror ());
+ return;
+ }
+
+ gnutls_hmac_output = dlsym (libgnutls, "gnutls_hmac_output");
+ if (!gnutls_hmac_output)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_hmac_output: %s", dlerror ());
+ return;
+ }
+
+ gnutls_strerror = dlsym (libgnutls, "gnutls_strerror");
+ if (!gnutls_strerror)
+ {
+ g_warning ("Cannot use GHmac: failed to load gnutls_strerror: %s", dlerror ());
+ return;
+ }
+
+ gnutls_initialize_successful = TRUE;
+}
+
GHmac *
g_hmac_new (GChecksumType digest_type,
const guchar *key,
gsize key_len)
{
gnutls_mac_algorithm_t algo;
- GHmac *hmac = g_new0 (GHmac, 1);
+ GHmac *hmac;
int ret;
+ if (g_once_init_enter (&gnutls_initialize_attempted))
+ {
+ initialize_gnutls ();
+ g_once_init_leave (&gnutls_initialize_attempted, 1);
+ }
+
+ if (!gnutls_initialize_successful)
+ return NULL;
+
+ hmac = g_new0 (GHmac, 1);
hmac->ref_count = 1;
hmac->digest_type = digest_type;
diff --git a/glib/ghmac.c b/glib/ghmac.c
index 0e39ea40a..2d9be91b8 100644
--- a/glib/ghmac.c
+++ b/glib/ghmac.c
@@ -33,7 +33,7 @@
#include "gtypes.h"
#include "glibintl.h"
-#ifdef HAVE_GNUTLS
+#ifdef USE_GNUTLS
#error "build configuration error"
#endif
diff --git a/glib/meson.build b/glib/meson.build
index 2417de53d..ba42951aa 100644
--- a/glib/meson.build
+++ b/glib/meson.build
@@ -384,7 +384,7 @@ libglib = library('glib-2.0',
# intl.lib is not compatible with SAFESEH
link_args : [noseh_link_args, glib_link_flags, win32_ldflags],
include_directories : configinc,
- dependencies : pcre_deps + [thread_dep, librt] + libgnutls_dep + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep],
+ dependencies : pcre_deps + [thread_dep, librt] + libintl_deps + libiconv + platform_deps + [gnulib_libm_dependency, libm] + [libsysprof_capture_dep] + [libdl_dep],
c_args : glib_c_args,
objc_args : glib_c_args,
)
diff --git a/meson.build b/meson.build
index cca15f653..404ef1790 100644
--- a/meson.build
+++ b/meson.build
@@ -2090,11 +2090,9 @@ if host_system == 'linux'
glib_conf.set('HAVE_LIBMOUNT', libmount_dep.found())
endif
-# gnutls is used optionally by ghmac
-libgnutls_dep = []
+# gnutls is used optionally by GHmac
if get_option('gnutls')
- libgnutls_dep = [dependency('gnutls', version : '>=3.6.9', required : true)]
- glib_conf.set('HAVE_GNUTLS', 1)
+ glib_conf.set('USE_GNUTLS', 1)
endif
if host_system == 'windows'
--
2.31.1
From 7d1d96311b6ecd4f90ebbdd6fc58d28e06a86887 Mon Sep 17 00:00:00 2001
From 87280b23902290dcf843a42d06cedeef571a673f Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Wed, 16 Jun 2021 20:46:24 -0500
Subject: [PATCH 4/4] Add test for GHmac in FIPS mode
Date: Thu, 1 Jul 2021 15:51:26 -0500
Subject: [PATCH 3/3] Add more tests for GHmac
This will test a few problems that we hit recently:
@ -964,73 +786,29 @@ g_hmac_copy() is broken, https://bugzilla.redhat.com/show_bug.cgi?id=1786538
Crash in g_hmac_update() in FIPS mode, https://bugzilla.redhat.com/show_bug.cgi?id=1971533
Crash when passing -1 length to g_hmac_update() (discovered in #1971533)
We'll also test to ensure MD5 fails, and stop compiling the other MD5
tests.
---
glib/tests/hmac.c | 46 ++++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 46 insertions(+)
glib/tests/hmac.c | 22 ++++++++++++++++++++++
1 file changed, 22 insertions(+)
diff --git a/glib/tests/hmac.c b/glib/tests/hmac.c
index 3ac3206df..2fa447984 100644
index 3ac3206df..16b2fac9c 100644
--- a/glib/tests/hmac.c
+++ b/glib/tests/hmac.c
@@ -1,7 +1,10 @@
+#include "config.h"
+
#include <glib.h>
#include <string.h>
#include <stdlib.h>
+#ifndef USE_GNUTLS
/* HMAC-MD5 test vectors as per RFC 2202 */
/* Test 1 */
@@ -81,6 +84,7 @@ guint8 key_md5_test7[] = {
guint8 result_md5_test7[] = {
0x6f, 0x63, 0x0f, 0xad, 0x67, 0xcd, 0xa0, 0xee, 0x1f, 0xb1,
0xf5, 0x62, 0xdb, 0x3a, 0xa5, 0x3e };
+#endif
/* HMAC-SHA1, HMAC-SHA256, HMAC-SHA384 and HMAC-SHA512 test vectors
* as per RFCs 2202 and 4868.
@@ -299,6 +303,7 @@ typedef struct {
gconstpointer result;
} HmacCase;
+#ifndef USE_GNUTLS
HmacCase hmac_md5_tests[] = {
{ G_CHECKSUM_MD5, key_md5_test1, 16, "Hi There", 8, result_md5_test1 },
{ G_CHECKSUM_MD5, "Jefe", 4, "what do ya want for nothing?", 28,
@@ -317,6 +322,7 @@ HmacCase hmac_md5_tests[] = {
73, result_md5_test7 },
{ -1, NULL, 0, NULL, 0, NULL },
};
+#endif
HmacCase hmac_sha1_tests[] = {
{ G_CHECKSUM_SHA1, key_sha_test1, 20, "Hi There", 8, result_sha1_test1 },
@@ -493,11 +499,45 @@ test_hmac_for_bytes (void)
@@ -493,6 +493,27 @@ test_hmac_for_bytes (void)
g_bytes_unref (data);
}
+#ifdef USE_GNUTLS
+static void
+test_gnutls_fips_mode (void)
+test_ghmac_gnutls_regressions (void)
+{
+ GHmac *hmac;
+ GHmac *copy;
+
+ /* No MD5 in FIPS mode. */
+ hmac = g_hmac_new (G_CHECKSUM_MD5, "abc123", sizeof ("abc123"));
+ g_assert_null (hmac);
+
+ /* SHA-256 should be good. */
+ hmac = g_hmac_new (G_CHECKSUM_SHA256, "abc123", sizeof ("abc123"));
+ hmac = g_hmac_new (G_CHECKSUM_SHA256, (const guchar *)"abc123", sizeof ("abc123"));
+ g_assert_nonnull (hmac);
+
+ /* Ensure g_hmac_update() does not crash when called with -1. */
+ g_hmac_update (hmac, "You win again, gravity!", -1);
+ g_hmac_update (hmac, (const guchar *)"You win again, gravity!", -1);
+
+ /* Ensure g_hmac_copy() does not crash. */
+ copy = g_hmac_copy (hmac);
@ -1040,46 +818,16 @@ index 3ac3206df..2fa447984 100644
+ g_assert_cmpstr (g_hmac_get_string (copy), ==, "795ba6900bcb22e8ce65c2ec02db4e85697da921deb960ee3143bf88a4a60f83");
+ g_hmac_unref (copy);
+}
+#endif
+
int
main (int argc,
char **argv)
{
int i;
+
+#ifdef USE_GNUTLS
+ /* This has to happen before GnuTLS is dlopened. */
+ g_setenv ("GNUTLS_FORCE_FIPS_MODE", "1", FALSE);
+#endif
+
g_test_init (&argc, &argv, NULL);
for (i = 0 ; hmac_sha1_tests[i].key_len > 0 ; i++)
@@ -532,6 +572,7 @@ main (int argc,
g_free (name);
}
+#ifndef USE_GNUTLS
for (i = 0 ; hmac_md5_tests[i].key_len > 0 ; i++)
{
gchar *name = g_strdup_printf ("/hmac/md5-%d", i + 1);
@@ -539,6 +580,7 @@ main (int argc,
(void (*)(const void *)) test_hmac);
g_free (name);
}
+#endif
g_test_add_func ("/hmac/ref-unref", test_hmac_ref_unref);
g_test_add_func ("/hmac/copy", test_hmac_copy);
@@ -546,5 +588,9 @@ main (int argc,
@@ -545,6 +566,7 @@ main (int argc,
g_test_add_func ("/hmac/for-data", test_hmac_for_data);
g_test_add_func ("/hmac/for-string", test_hmac_for_string);
g_test_add_func ("/hmac/for-bytes", test_hmac_for_bytes);
+ g_test_add_func ("/hmac/ghmac-gnutls-regressions", test_ghmac_gnutls_regressions);
+#ifdef USE_GNUTLS
+ g_test_add_func ("/hmac/gnutls-fips-mode", test_gnutls_fips_mode);
+#endif
+
return g_test_run ();
}
--

@ -0,0 +1,386 @@
From 2bad3cb3bf8f0cc3f45057061f9a538ecf7742b6 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Thu, 14 Feb 2019 17:46:33 +0200
Subject: [PATCH 1/5] Use atomic reference counting for GSource
If attached to a context already it would use a mutex instead but at
least before that the reference counting is not thread-safe currently.
---
glib/gmain.c | 50 +++++++++++++++-----------------------------------
1 file changed, 15 insertions(+), 35 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 26e68823d..5b91c3117 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -374,15 +374,6 @@ typedef struct _GSourceIter
#define SOURCE_DESTROYED(source) (((source)->flags & G_HOOK_FLAG_ACTIVE) == 0)
#define SOURCE_BLOCKED(source) (((source)->flags & G_SOURCE_BLOCKED) != 0)
-#define SOURCE_UNREF(source, context) \
- G_STMT_START { \
- if ((source)->ref_count > 1) \
- (source)->ref_count--; \
- else \
- g_source_unref_internal ((source), (context), TRUE); \
- } G_STMT_END
-
-
/* Forward declarations */
static void g_source_unref_internal (GSource *source,
@@ -977,10 +968,10 @@ g_source_iter_next (GSourceIter *iter, GSource **source)
*/
if (iter->source && iter->may_modify)
- SOURCE_UNREF (iter->source, iter->context);
+ g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = next_source;
if (iter->source && iter->may_modify)
- iter->source->ref_count++;
+ g_source_ref (iter->source);
*source = iter->source;
return *source != NULL;
@@ -994,7 +985,7 @@ g_source_iter_clear (GSourceIter *iter)
{
if (iter->source && iter->may_modify)
{
- SOURCE_UNREF (iter->source, iter->context);
+ g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = NULL;
}
}
@@ -1135,7 +1126,7 @@ g_source_attach_unlocked (GSource *source,
source->context = context;
source->source_id = id;
- source->ref_count++;
+ g_source_ref (source);
g_hash_table_insert (context->sources, GUINT_TO_POINTER (id), source);
@@ -1675,7 +1666,7 @@ g_source_set_funcs (GSource *source,
{
g_return_if_fail (source != NULL);
g_return_if_fail (source->context == NULL);
- g_return_if_fail (source->ref_count > 0);
+ g_return_if_fail (g_atomic_int_get (&source->ref_count) > 0);
g_return_if_fail (funcs != NULL);
source->source_funcs = funcs;
@@ -2050,19 +2041,9 @@ g_source_set_name_by_id (guint tag,
GSource *
g_source_ref (GSource *source)
{
- GMainContext *context;
-
g_return_val_if_fail (source != NULL, NULL);
- context = source->context;
-
- if (context)
- LOCK_CONTEXT (context);
-
- source->ref_count++;
-
- if (context)
- UNLOCK_CONTEXT (context);
+ g_atomic_int_inc (&source->ref_count);
return source;
}
@@ -2078,12 +2059,11 @@ g_source_unref_internal (GSource *source,
GSourceCallbackFuncs *old_cb_funcs = NULL;
g_return_if_fail (source != NULL);
-
+
if (!have_lock && context)
LOCK_CONTEXT (context);
- source->ref_count--;
- if (source->ref_count == 0)
+ if (g_atomic_int_dec_and_test (&source->ref_count))
{
TRACE (GLIB_SOURCE_BEFORE_FREE (source, context,
source->source_funcs->finalize));
@@ -2107,20 +2087,20 @@ g_source_unref_internal (GSource *source,
{
/* Temporarily increase the ref count again so that GSource methods
* can be called from finalize(). */
- source->ref_count++;
+ g_atomic_int_inc (&source->ref_count);
if (context)
UNLOCK_CONTEXT (context);
source->source_funcs->finalize (source);
if (context)
LOCK_CONTEXT (context);
- source->ref_count--;
+ g_atomic_int_add (&source->ref_count, -1);
}
if (old_cb_funcs)
{
/* Temporarily increase the ref count again so that GSource methods
* can be called from callback_funcs.unref(). */
- source->ref_count++;
+ g_atomic_int_inc (&source->ref_count);
if (context)
UNLOCK_CONTEXT (context);
@@ -2128,7 +2108,7 @@ g_source_unref_internal (GSource *source,
if (context)
LOCK_CONTEXT (context);
- source->ref_count--;
+ g_atomic_int_add (&source->ref_count, -1);
}
g_free (source->name);
@@ -3201,7 +3181,7 @@ g_main_dispatch (GMainContext *context)
}
}
- SOURCE_UNREF (source, context);
+ g_source_unref_internal (source, context, TRUE);
}
g_ptr_array_set_size (context->pending_dispatches, 0);
@@ -3440,7 +3420,7 @@ g_main_context_prepare (GMainContext *context,
for (i = 0; i < context->pending_dispatches->len; i++)
{
if (context->pending_dispatches->pdata[i])
- SOURCE_UNREF ((GSource *)context->pending_dispatches->pdata[i], context);
+ g_source_unref_internal ((GSource *)context->pending_dispatches->pdata[i], context, TRUE);
}
g_ptr_array_set_size (context->pending_dispatches, 0);
@@ -3788,7 +3768,7 @@ g_main_context_check (GMainContext *context,
if (source->flags & G_SOURCE_READY)
{
- source->ref_count++;
+ g_source_ref (source);
g_ptr_array_add (context->pending_dispatches, source);
n_ready++;
--
2.31.1
From 323d0c7658a9a44efc327840c0667044a4b98f89 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Mon, 3 Feb 2020 15:38:28 +0200
Subject: [PATCH 2/5] GMainContext - Fix GSource iterator if iteration can
modify the list
We first have to ref the next source and then unref the previous one.
This might be the last reference to the previous source, and freeing the
previous source might unref and free the next one which would then leave
use with a dangling pointer here.
Fixes https://gitlab.gnome.org/GNOME/glib/issues/2031
---
glib/gmain.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 5b91c3117..a3ea1d36c 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -965,13 +965,17 @@ g_source_iter_next (GSourceIter *iter, GSource **source)
* GSourceList to be removed from source_lists (if iter->source is
* the only source in its list, and it is destroyed), so we have to
* keep it reffed until after we advance iter->current_list, above.
+ *
+ * Also we first have to ref the next source before unreffing the
+ * previous one as unreffing the previous source can potentially
+ * free the next one.
*/
+ if (next_source && iter->may_modify)
+ g_source_ref (next_source);
if (iter->source && iter->may_modify)
g_source_unref_internal (iter->source, iter->context, TRUE);
iter->source = next_source;
- if (iter->source && iter->may_modify)
- g_source_ref (iter->source);
*source = iter->source;
return *source != NULL;
--
2.31.1
From fc051ec83d8894dd754bf364562ba9be9ff999fc Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Mon, 3 Feb 2020 15:35:51 +0200
Subject: [PATCH 3/5] GMainContext - Fix memory leaks and memory corruption
when freeing sources while freeing a context
Instead of destroying sources directly while freeing the context, and
potentially freeing them if this was the last reference to them, collect
new references of all sources in a separate list before and at the same
time invalidate their context so that they can't access it anymore. Only
once all sources have their context invalidated, destroy them while
still keeping a reference to them. Once all sources are destroyed we get
rid of the additional references and free them if nothing else keeps a
reference to them anymore.
This fixes a regression introduced by 26056558be in 2012.
The previous code that invalidated the context of each source and then
destroyed it before going to the next source without keeping an
additional reference caused memory leaks or memory corruption depending
on the order of the sources in the sources lists.
If a source was destroyed it might happen that this was the last
reference to this source, and it would then be freed. This would cause
the finalize function to be called, which might destroy and unref
another source and potentially free it. This other source would then
either
- go through the normal free logic and change the intern linked list
between the sources, while other sources that are unreffed as part of
the main context freeing would not. As such the list would be in an
inconsistent state and we might dereference freed memory.
- go through the normal destroy and free logic but because the context
pointer was already invalidated it would simply mark the source as
destroyed without actually removing it from the context. This would
then cause a memory leak because the reference owned by the context is
not freed.
Fixes https://github.com/gtk-rs/glib/issues/583 while still keeping
https://bugzilla.gnome.org/show_bug.cgi?id=661767 fixes.
---
glib/gmain.c | 35 ++++++++++++++++++++++++++++++++++-
1 file changed, 34 insertions(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index a3ea1d36c..1c249ad02 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -534,6 +534,7 @@ g_main_context_unref (GMainContext *context)
GSourceIter iter;
GSource *source;
GList *sl_iter;
+ GSList *s_iter, *remaining_sources = NULL;
GSourceList *list;
guint i;
@@ -553,10 +554,30 @@ g_main_context_unref (GMainContext *context)
/* g_source_iter_next() assumes the context is locked. */
LOCK_CONTEXT (context);
- g_source_iter_init (&iter, context, TRUE);
+
+ /* First collect all remaining sources from the sources lists and store a
+ * new reference in a separate list. Also set the context of the sources
+ * to NULL so that they can't access a partially destroyed context anymore.
+ *
+ * We have to do this first so that we have a strong reference to all
+ * sources and destroying them below does not also free them, and so that
+ * none of the sources can access the context from their finalize/dispose
+ * functions. */
+ g_source_iter_init (&iter, context, FALSE);
while (g_source_iter_next (&iter, &source))
{
source->context = NULL;
+ remaining_sources = g_slist_prepend (remaining_sources, g_source_ref (source));
+ }
+ g_source_iter_clear (&iter);
+
+ /* Next destroy all sources. As we still hold a reference to all of them,
+ * this won't cause any of them to be freed yet and especially prevents any
+ * source that unrefs another source from its finalize function to be freed.
+ */
+ for (s_iter = remaining_sources; s_iter; s_iter = s_iter->next)
+ {
+ source = s_iter->data;
g_source_destroy_internal (source, context, TRUE);
}
UNLOCK_CONTEXT (context);
@@ -581,6 +602,18 @@ g_main_context_unref (GMainContext *context)
g_cond_clear (&context->cond);
g_free (context);
+
+ /* And now finally get rid of our references to the sources. This will cause
+ * them to be freed unless something else still has a reference to them. Due
+ * to setting the context pointers in the sources to NULL above, this won't
+ * ever access the context or the internal linked list inside the GSource.
+ * We already removed the sources completely from the context above. */
+ for (s_iter = remaining_sources; s_iter; s_iter = s_iter->next)
+ {
+ source = s_iter->data;
+ g_source_unref_internal (source, NULL, FALSE);
+ }
+ g_slist_free (remaining_sources);
}
/* Helper function used by mainloop/overflow test.
--
2.31.1
From 1d16e92028f235ed9cd786070832d5bd71017661 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Sebastian=20Dr=C3=B6ge?= <sebastian@centricular.com>
Date: Tue, 11 Feb 2020 09:34:38 +0200
Subject: [PATCH 4/5] GMainContext - Move mutex unlocking in destructor right
before freeing the mutex
This does not have any behaviour changes but is cleaner. The mutex is
only unlocked now after all operations on the context are done and right
before freeing the mutex and the context itself.
---
glib/gmain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 1c249ad02..44e6ed0c3 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -580,7 +580,6 @@ g_main_context_unref (GMainContext *context)
source = s_iter->data;
g_source_destroy_internal (source, context, TRUE);
}
- UNLOCK_CONTEXT (context);
for (sl_iter = context->source_lists; sl_iter; sl_iter = sl_iter->next)
{
@@ -591,6 +590,7 @@ g_main_context_unref (GMainContext *context)
g_hash_table_destroy (context->sources);
+ UNLOCK_CONTEXT (context);
g_mutex_clear (&context->mutex);
g_ptr_array_free (context->pending_dispatches, TRUE);
--
2.31.1
From 02ad7294ad5895178df73a6cd8546c6e67097493 Mon Sep 17 00:00:00 2001
From: Benjamin Berg <bberg@redhat.com>
Date: Tue, 13 Oct 2020 15:09:43 +0200
Subject: [PATCH 5/5] gmain: Fix possible locking issue in source unref
When unref'ing child sources, the lock is already held. But instead of
passing TRUE to g_source_unref_internal it currently passes whether the
lock was already held outside of the current invocation. Just pass TRUE
to fix this possible issue.
---
glib/gmain.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/glib/gmain.c b/glib/gmain.c
index 44e6ed0c3..95992253d 100644
--- a/glib/gmain.c
+++ b/glib/gmain.c
@@ -2164,7 +2164,7 @@ g_source_unref_internal (GSource *source,
g_slist_remove (source->priv->child_sources, child_source);
child_source->priv->parent_source = NULL;
- g_source_unref_internal (child_source, context, have_lock);
+ g_source_unref_internal (child_source, context, TRUE);
}
g_slice_free (GSourcePrivate, source->priv);
--
2.31.1

@ -0,0 +1,431 @@
From c48c984d39afeae84b0cad515f08f83c711fd9c4 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Thu, 13 Sep 2018 10:25:05 +0100
Subject: [PATCH 1/9] gnetworkmonitornm: Set a GError properly on an error
handling path
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
All the other initialisation failure paths set a GError, but this one
didnt. Set a GError to avoid breaking the invariant that returning
FALSE should always have a GError set.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
https://gitlab.gnome.org/GNOME/glib/issues/1523
---
gio/gnetworkmonitornm.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 20a86571f..5bc8c925a 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -309,6 +309,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
if (!name_owner)
{
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
+ _("NetworkManager not running"));
g_object_unref (proxy);
return FALSE;
}
--
2.33.1
From d139986b1f213a7e1c1e3968ad2d8270f820bd57 Mon Sep 17 00:00:00 2001
From: Antonio Larrosa <alarrosa@suse.com>
Date: Tue, 12 Mar 2019 18:35:10 +0100
Subject: [PATCH 2/9] Handle an UNKNOWN NetworkManager connectivity as NONE
nm_conn_to_g_conn already handles UNKNOWN like NONE (returning
G_NETWORK_CONNECTIVITY_LOCAL in both cases). So in sync_properties
we should also set new_connectivity to G_NETWORK_CONNECTIVITY_LOCAL
for both NM_CONNECTIVITY_UNKNOWN and NM_CONNECTIVITY_NONE.
This has the added benefit that when NetworkManager returns the network
connectivity is UNKNOWN, we set network_available to FALSE as it should
be. Previously, there were cases in a laptop with no network access,
that g_network_monitor_get_network_available returned true, which was
wrong and is also fixed with this commit.
---
gio/gnetworkmonitornm.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 5bc8c925a..4e2a35e8a 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -167,7 +167,8 @@ sync_properties (GNetworkMonitorNM *nm,
nm_connectivity = g_variant_get_uint32 (v);
g_variant_unref (v);
- if (nm_connectivity == NM_CONNECTIVITY_NONE)
+ if (nm_connectivity == NM_CONNECTIVITY_UNKNOWN ||
+ nm_connectivity == NM_CONNECTIVITY_NONE)
{
new_network_available = FALSE;
new_network_metered = FALSE;
--
2.33.1
From 5b4e6f9813cf90c690d8974635b0aeff8f5d2c5d Mon Sep 17 00:00:00 2001
From: Fabrice Bellet <fabrice@bellet.info>
Date: Mon, 29 Apr 2019 12:05:54 +0000
Subject: [PATCH 3/9] gnetworkmonitornm: Fix network available detection
The network-available property can be asserted by querying the NMState
describing the current overval network state, instead of the
NMConnectivityState. The advantage of the NMState is that is reflects
immediately the network state modification, while the connectivity
state is tested at a fixed frequency.
---
gio/gnetworkmonitornm.c | 39 ++++++++++++++++++++++++++++++++++++---
1 file changed, 36 insertions(+), 3 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 4e2a35e8a..7bb480f54 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -52,6 +52,19 @@ typedef enum {
NM_CONNECTIVITY_FULL
} NMConnectivityState;
+/* Copied from https://developer.gnome.org/libnm-util/stable/libnm-util-NetworkManager.html#NMState;
+ * used inline to avoid a NetworkManager dependency from GLib. */
+typedef enum {
+ NM_STATE_UNKNOWN = 0,
+ NM_STATE_ASLEEP = 10,
+ NM_STATE_DISCONNECTED = 20,
+ NM_STATE_DISCONNECTING = 30,
+ NM_STATE_CONNECTING = 40,
+ NM_STATE_CONNECTED_LOCAL = 50,
+ NM_STATE_CONNECTED_SITE = 60,
+ NM_STATE_CONNECTED_GLOBAL = 70,
+} NMState;
+
struct _GNetworkMonitorNMPrivate
{
GDBusProxy *proxy;
@@ -155,11 +168,19 @@ sync_properties (GNetworkMonitorNM *nm,
gboolean emit_signals)
{
GVariant *v;
+ NMState nm_state;
NMConnectivityState nm_connectivity;
gboolean new_network_available;
gboolean new_network_metered;
GNetworkConnectivity new_connectivity;
+ v = g_dbus_proxy_get_cached_property (nm->priv->proxy, "State");
+ if (!v)
+ return;
+
+ nm_state = g_variant_get_uint32 (v);
+ g_variant_unref (v);
+
v = g_dbus_proxy_get_cached_property (nm->priv->proxy, "Connectivity");
if (!v)
return;
@@ -167,14 +188,26 @@ sync_properties (GNetworkMonitorNM *nm,
nm_connectivity = g_variant_get_uint32 (v);
g_variant_unref (v);
- if (nm_connectivity == NM_CONNECTIVITY_UNKNOWN ||
- nm_connectivity == NM_CONNECTIVITY_NONE)
+ if (nm_state <= NM_STATE_CONNECTED_LOCAL)
{
new_network_available = FALSE;
new_network_metered = FALSE;
new_connectivity = G_NETWORK_CONNECTIVITY_LOCAL;
}
- else
+ else if (nm_state <= NM_STATE_CONNECTED_SITE)
+ {
+ new_network_available = FALSE;
+ new_network_metered = FALSE;
+ if (nm_connectivity == NM_CONNECTIVITY_PORTAL)
+ {
+ new_connectivity = G_NETWORK_CONNECTIVITY_PORTAL;
+ }
+ else
+ {
+ new_connectivity = G_NETWORK_CONNECTIVITY_LIMITED;
+ }
+ }
+ else /* nm_state == NM_STATE_CONNECTED_FULL */
{
/* this is only available post NM 1.0 */
--
2.33.1
From 96fba295771d600e4f0f522400b2fb9b1ff42cee Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 31 May 2019 11:19:07 +0100
Subject: [PATCH 4/9] gnetworkmonitornm: Consider NM_STATE_CONNECTED_SITE to be
available
`NM_STATE_CONNECTED_SITE` is documented to mean that a default route is
available, but that the internet connectivity check failed. A default
route being available is compatible with the documentation for
GNetworkMonitor:network-available, which should be true if the system
has a default route for at least one of IPv4 and IPv6.
https://developer.gnome.org/NetworkManager/stable/nm-dbus-types.html
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1788
---
gio/gnetworkmonitornm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 7bb480f54..9013fd49c 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -196,7 +196,7 @@ sync_properties (GNetworkMonitorNM *nm,
}
else if (nm_state <= NM_STATE_CONNECTED_SITE)
{
- new_network_available = FALSE;
+ new_network_available = TRUE;
new_network_metered = FALSE;
if (nm_connectivity == NM_CONNECTIVITY_PORTAL)
{
--
2.33.1
From 74e5f472c838115f0ba19ac501805cb5b2ca837f Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:25:21 +0200
Subject: [PATCH 5/9] gnetworkmonitornm: Disconnect g-signal from proxy
So that we're sure never to receive a signal if something is keeping the
proxy alive.
---
gio/gnetworkmonitornm.c | 12 ++++++++++--
1 file changed, 10 insertions(+), 2 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 9013fd49c..52073fac9 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -68,6 +68,7 @@ typedef enum {
struct _GNetworkMonitorNMPrivate
{
GDBusProxy *proxy;
+ guint signal_id;
GNetworkConnectivity connectivity;
gboolean network_available;
@@ -360,8 +361,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
return FALSE;
}
- g_signal_connect (G_OBJECT (proxy), "g-signal",
- G_CALLBACK (proxy_signal_cb), nm);
+ nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
+ G_CALLBACK (proxy_signal_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
@@ -373,6 +374,13 @@ g_network_monitor_nm_finalize (GObject *object)
{
GNetworkMonitorNM *nm = G_NETWORK_MONITOR_NM (object);
+ if (nm->priv->proxy != NULL &&
+ nm->priv->signal_id != 0)
+ {
+ g_signal_handler_disconnect (nm->priv->proxy,
+ nm->priv->signal_id);
+ nm->priv->signal_id = 0;
+ }
g_clear_object (&nm->priv->proxy);
G_OBJECT_CLASS (g_network_monitor_nm_parent_class)->finalize (object);
--
2.33.1
From eeaf1de6e695afd971d67137caa8e39e1c1267df Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:26:20 +0200
Subject: [PATCH 6/9] gnetworkmonitornm: Arguments to g-signal's callback are
const
---
gio/gnetworkmonitornm.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 52073fac9..479653a51 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -268,8 +268,8 @@ update_cached_property (GDBusProxy *proxy,
static void
proxy_signal_cb (GDBusProxy *proxy,
- gchar *sender_name,
- gchar *signal_name,
+ const gchar *sender_name,
+ const gchar *signal_name,
GVariant *parameters,
GNetworkMonitorNM *nm)
{
--
2.33.1
From 46d70700c85e4419942c8a3d08bd0bf842702c4a Mon Sep 17 00:00:00 2001
From: Bastien Nocera <hadess@hadess.net>
Date: Mon, 29 Jul 2019 17:26:47 +0200
Subject: [PATCH 7/9] gnetworkmonitornm: Remove double-space
---
gio/gnetworkmonitornm.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 479653a51..5a36a0ba1 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -391,7 +391,7 @@ g_network_monitor_nm_class_init (GNetworkMonitorNMClass *nl_class)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (nl_class);
- gobject_class->finalize = g_network_monitor_nm_finalize;
+ gobject_class->finalize = g_network_monitor_nm_finalize;
gobject_class->get_property = g_network_monitor_nm_get_property;
g_object_class_override_property (gobject_class, PROP_NETWORK_AVAILABLE, "network-available");
--
2.33.1
From 72291aac3dac7a8ed4c85eb41608f3f5f9ad7681 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 12:01:50 +0200
Subject: [PATCH 8/9] gnetworkmonitornm: Stop using removed PropertiesChanged
signal
Use the org.freedesktop.DBus.Properties interface to listen
to PropertiesChanged signals on /org/freedesktop/NetworkManager.
NetworkManager used to provide its own legacy PropertiesChanged
signal, but that was dropped in
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/853
This requires NetworkManager >= 1.2 (2016)
Fixes: #2505
Bug-Ubuntu: https://bugs.launchpad.net/bugs/1946196
---
gio/gnetworkmonitornm.c | 29 +++++++----------------------
1 file changed, 7 insertions(+), 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 5a36a0ba1..6a6d1d666 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -267,29 +267,14 @@ update_cached_property (GDBusProxy *proxy,
}
static void
-proxy_signal_cb (GDBusProxy *proxy,
- const gchar *sender_name,
- const gchar *signal_name,
- GVariant *parameters,
- GNetworkMonitorNM *nm)
+proxy_properties_changed_cb (GDBusProxy *proxy,
+ GVariant *changed_properties,
+ GStrv invalidated_properties,
+ GNetworkMonitorNM *nm)
{
- GVariant *asv;
GVariantDict *dict;
- if (g_strcmp0 (signal_name, "PropertiesChanged") != 0)
- return;
-
- g_variant_get (parameters, "(@a{sv})", &asv);
- if (!asv)
- return;
-
- dict = g_variant_dict_new (asv);
- g_variant_unref (asv);
- if (!dict)
- {
- g_warning ("Failed to handle PropertiesChanged signal from NetworkManager");
- return;
- }
+ dict = g_variant_dict_new (changed_properties);
update_cached_property (nm->priv->proxy, "Connectivity", dict);
@@ -361,8 +346,8 @@ g_network_monitor_nm_initable_init (GInitable *initable,
return FALSE;
}
- nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-signal",
- G_CALLBACK (proxy_signal_cb), nm);
+ nm->priv->signal_id = g_signal_connect (G_OBJECT (proxy), "g-properties-changed",
+ G_CALLBACK (proxy_properties_changed_cb), nm);
nm->priv->proxy = proxy;
sync_properties (nm, FALSE);
--
2.33.1
From 3bafff71d7588285763f603b23c830722a2169d1 Mon Sep 17 00:00:00 2001
From: Julian Andres Klode <julian.klode@canonical.com>
Date: Tue, 12 Oct 2021 17:31:42 +0200
Subject: [PATCH 9/9] gnetworkmonitornm: Do not re-update cached property
GDBusProxy already takes care of updating the cached property
before emitting the signal, so there is no need to do this
a second time ourselves.
---
gio/gnetworkmonitornm.c | 22 ----------------------
1 file changed, 22 deletions(-)
diff --git a/gio/gnetworkmonitornm.c b/gio/gnetworkmonitornm.c
index 6a6d1d666..a8040fb36 100644
--- a/gio/gnetworkmonitornm.c
+++ b/gio/gnetworkmonitornm.c
@@ -252,34 +252,12 @@ sync_properties (GNetworkMonitorNM *nm,
}
}
-static void
-update_cached_property (GDBusProxy *proxy,
- const char *property_name,
- GVariantDict *dict)
-{
- GVariant *v;
-
- v = g_variant_dict_lookup_value (dict, property_name, NULL);
- if (!v)
- return;
- g_dbus_proxy_set_cached_property (proxy, property_name, v);
- g_variant_unref (v);
-}
-
static void
proxy_properties_changed_cb (GDBusProxy *proxy,
GVariant *changed_properties,
GStrv invalidated_properties,
GNetworkMonitorNM *nm)
{
- GVariantDict *dict;
-
- dict = g_variant_dict_new (changed_properties);
-
- update_cached_property (nm->priv->proxy, "Connectivity", dict);
-
- g_variant_dict_unref (dict);
-
sync_properties (nm, TRUE);
}
--
2.33.1

@ -0,0 +1,142 @@
From 85c4031696add9797e2334ced20678edcd96c869 Mon Sep 17 00:00:00 2001
From: Mart Raudsepp <leio@gentoo.org>
Date: Wed, 19 Dec 2018 16:22:21 +0200
Subject: [PATCH 1/2] tests: Allocate gvariant data from the heap to guarantee
alignment
On glib-2-58 branch we don't have !455, thus we need aligned data
for the gvariant tests to not fail on i686.
Fixes #1626
---
glib/tests/gvariant.c | 15 ++++++++++++---
1 file changed, 12 insertions(+), 3 deletions(-)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index 6e417f6c1..a7b19826d 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4664,6 +4664,7 @@ test_stack_dict_init (void)
static void
test_normal_checking_tuples (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00,
'a', '(', 'a', 'o', 'a', 'o', 'a', 'a', 'o', 'a', 'a', 'o', ')'
@@ -4672,13 +4673,15 @@ test_normal_checking_tuples (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
@@ -4790,6 +4793,7 @@ test_recursion_limits_array_in_variant (void)
static void
test_normal_checking_array_offsets (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x07, 0xe5, 0x00, 0x07, 0x00, 0x07, 0x00, 0x00,
'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'a', 'g',
@@ -4798,13 +4802,15 @@ test_normal_checking_array_offsets (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
@@ -4838,6 +4844,7 @@ test_normal_checking_tuple_offsets (void)
static void
test_normal_checking_empty_object_path (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x20, 0x20, 0x00, 0x00, 0x00, 0x00,
'(', 'h', '(', 'a', 'i', 'a', 'b', 'i', 'o', ')', ')',
@@ -4846,13 +4853,15 @@ test_normal_checking_empty_object_path (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data, size,
FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
--
2.19.1
From 4ef58e5661849317a1110c9b93957f2c608677dd Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@collabora.com>
Date: Thu, 3 Jan 2019 08:21:40 +0000
Subject: [PATCH 2/2] gvariant test: Also force alignment for tuple test data
glib!552 (commit 9eed22b3) fixed this for the tests that failed on i686,
but this additional test failed on Debian's s390x port
(IBM z/Architecture, 64-bit big-endian).
Signed-off-by: Simon McVittie <smcv@collabora.com>
---
glib/tests/gvariant.c | 7 +++++--
1 file changed, 5 insertions(+), 2 deletions(-)
diff --git a/glib/tests/gvariant.c b/glib/tests/gvariant.c
index a7b19826d..c4a996c1f 100644
--- a/glib/tests/gvariant.c
+++ b/glib/tests/gvariant.c
@@ -4820,6 +4820,7 @@ test_normal_checking_array_offsets (void)
static void
test_normal_checking_tuple_offsets (void)
{
+ gpointer aligned_data;
const guint8 data[] = {
0x07, 0xe5, 0x00, 0x07, 0x00, 0x07,
'(', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', 'a', 's', ')',
@@ -4828,13 +4829,15 @@ test_normal_checking_tuple_offsets (void)
GVariant *variant = NULL;
GVariant *normal_variant = NULL;
- variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, data, size,
- FALSE, NULL, NULL);
+ aligned_data = g_memdup (data, size); /* guarantee alignment */
+ variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, aligned_data,
+ size, FALSE, NULL, NULL);
g_assert_nonnull (variant);
normal_variant = g_variant_get_normal_form (variant);
g_assert_nonnull (normal_variant);
+ g_free (aligned_data);
g_variant_unref (normal_variant);
g_variant_unref (variant);
}
--
2.19.1

File diff suppressed because it is too large Load Diff

@ -1,105 +1,129 @@
%global _changelog_trimtime %(date +%s -d "1 year ago")
# See https://fedoraproject.org/wiki/Packaging:Python_Appendix#Manual_byte_compilation
%global __python %{__python3}
Name: glib2
Version: 2.68.4
Release: 14%{?dist}.1
Version: 2.56.4
Release: 162%{?dist}
Summary: A library of handy utility functions
License: LGPLv2+
URL: http://www.gtk.org
Source0: http://download.gnome.org/sources/glib/2.68/glib-%{version}.tar.xz
Source0: http://download.gnome.org/sources/glib/2.56/glib-%{version}.tar.xz
# Required for RHEL core crypto components policy. Good for Fedora too.
# https://bugzilla.redhat.com/show_bug.cgi?id=1630260
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/903
Patch: gnutls-hmac.patch
# Add GPowerProfileMonitor
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1965
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2194
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2222
Patch: 1965.patch
Patch: 2194.patch
Patch: 2222.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2244
Patch: 2244.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2291
Patch: 2291.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1968
Patch: 1968.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2435
Patch: 2435.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3126
Patch: 3126.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3136
Patch: 3136.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3163
Patch: 3163.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2826
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3272
Patch: 2826.patch
Patch: 3272.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2408
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2816
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2847
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3158
Patch: 2408.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3353
Patch: 3353.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3845
Patch: 3845.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3720
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4038
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4053
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4057
Patch: 4038.patch
# For ghmac-gnutls.patch
BuildRequires: pkgconfig(gnutls)
BuildRequires: chrpath
BuildRequires: gcc
BuildRequires: gcc-c++
BuildRequires: gettext
BuildRequires: gtk-doc
BuildRequires: perl-interpreter
# for sys/inotify.h
BuildRequires: glibc-devel
BuildRequires: libattr-devel
BuildRequires: libselinux-devel
BuildRequires: meson
# for sys/sdt.h
BuildRequires: systemtap-sdt-devel
BuildRequires: pkgconfig(libelf)
BuildRequires: pkgconfig(libffi)
BuildRequires: pkgconfig(libpcre)
BuildRequires: pkgconfig(mount)
BuildRequires: pkgconfig(sysprof-capture-4)
BuildRequires: pkgconfig(zlib)
# Bootstrap build requirements
BuildRequires: automake autoconf libtool
BuildRequires: gtk-doc
BuildRequires: python3-devel
# For gnutls-hmac.patch. We now dlopen libgnutls.so.30 so that we can build a
# static glib2 without depending on a static build of GnuTLS as well. This will
# ensure we notice if the GnuTLS soname bumps, so that we can update our patch.
%if 0%{?__isa_bits} == 64
Requires: libgnutls.so.30()(64bit)
%else
Requires: libgnutls.so.30
%endif
# for GIO content-type support
Recommends: shared-mime-info
# Implement RHEL 8 core crypto components policy
# https://bugzilla.redhat.com/show_bug.cgi?id=1630260
# https://gitlab.gnome.org/GNOME/glib/merge_requests/903
Patch0: ghmac-gnutls.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/50
Patch1: 50.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/309
Patch2: 309.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/403
Patch3: 409.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/546
Patch4: 546.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/876
Patch5: CVE-2019-12450.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/552
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/569
Patch6: gvariant-tests.patch
# Remove gamin dependency
Obsoletes: glib2-fam < 2.67.1-3
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/105
Patch7: 105.patch
# glib 2.59.0 hash table changes broke older gcr versions / password prompts in gnome-shell
Conflicts: gcr < 3.28.1
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/532
Patch8: 532.patch
Provides: bundled(gnulib)
Provides: bundled(gvdb)
Provides: bundled(libcharset)
Provides: bundled(xdgmime)
# https://bugzilla.redhat.com/show_bug.cgi?id=1777213
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1176
Patch9: 1176.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/450
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/603
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/974
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/984
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/985
Patch10: keyfile-backend.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/604
Patch11: CVE-2019-13012.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1942
Patch12: CVE-2021-27218.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1927
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2000
Patch13: CVE-2021-27219.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1981
Patch14: CVE-2021-28153.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1938284
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1369
Patch15: 1369.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=1948988
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/873
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1353
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1691
Patch16: gmain-corruption.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1713
Patch17: 1713.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2244
Patch18: 2244.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2014652
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/2291
Patch19: gnetworkmonitornm.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/13
Patch20: 13.patch
# https://bugzilla.redhat.com/show_bug.cgi?id=2125184
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1134
Patch21: 1134.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/54
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/400
Patch22: 54.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1549
# Also: https://gitlab.gnome.org/GNOME/glib/-/commit/d0821da5244fd08c756a5f84ec0d3063c72d1ac6
Patch23: 1549.patch
%description
GLib is the low-level core library that forms the basis for projects
@ -107,6 +131,7 @@ such as GTK+ and GNOME. It provides data structure handling for C,
portability wrappers, and interfaces for such runtime functionality
as an event loop, threads, dynamic loading, and an object system.
%package devel
Summary: A library of handy utility functions
Requires: %{name}%{?_isa} = %{version}-%{release}
@ -122,6 +147,14 @@ BuildArch: noarch
%description doc
The glib2-doc package includes documentation for the GLib library.
%package fam
Summary: FAM monitoring module for GIO
Requires: %{name}%{?_isa} = %{version}-%{release}
BuildRequires: gamin-devel
%description fam
The glib2-fam package contains the FAM (File Alteration Monitor) module for GIO.
%package static
Summary: glib static
Requires: %{name}-devel = %{version}-%{release}
@ -140,45 +173,57 @@ the functionality of the installed glib2 package.
%prep
%autosetup -n glib-%{version} -p1
# restore timestamps after patching to appease multilib for .pyc files
tar vtf %{SOURCE0} | while read mode user size date time name; do touch -d "$date $time" ../$name; done
%build
autoreconf -f -i
# Bug 1324770: Also explicitly remove PCRE sources since we use --with-pcre=system
rm glib/pcre/*.[ch]
%meson \
-Dman=true \
-Ddtrace=true \
-Dsystemtap=true \
-Dsysprof=enabled \
-Dglib_debug=disabled \
-Dgtk_doc=true \
-Dinstalled_tests=true \
-Dgnutls=true \
--default-library=both \
%{nil}
%meson_build
# Support builds of both git snapshots and tarballs packed with autogoo
(if ! test -x configure; then NOCONFIGURE=1 ./autogen.sh; CONFIGFLAGS=--enable-gtk-doc; fi;
%configure $CONFIGFLAGS \
--with-python=%{__python3} \
--with-pcre=system \
--enable-systemtap \
--enable-static \
--enable-installed-tests
)
%make_build
%install
%meson_install
# Since this is a generated .py file, set it to a known timestamp for
# better reproducibility.
# Also copy the timestamp for other .py files, because meson doesn't
# do this, see https://github.com/mesonbuild/meson/issues/5027.
touch -r gio/gdbus-2.0/codegen/config.py.in %{buildroot}%{_datadir}/glib-2.0/codegen/*.py
chrpath --delete %{buildroot}%{_libdir}/*.so
# Perform byte compilation manually to avoid issues with
# irreproducibility of the default invalidation mode, see
# https://www.python.org/dev/peps/pep-0552/ and
# https://bugzilla.redhat.com/show_bug.cgi?id=1686078
export PYTHONHASHSEED=0
%py_byte_compile %{__python3} %{buildroot}%{_datadir}
mv %{buildroot}%{_bindir}/gio-querymodules %{buildroot}%{_bindir}/gio-querymodules-%{__isa_bits}
sed -i -e "/^gio_querymodules=/s/gio-querymodules/gio-querymodules-%{__isa_bits}/" %{buildroot}%{_libdir}/pkgconfig/gio-2.0.pc
mkdir -p %{buildroot}%{_libdir}/gio/modules
touch %{buildroot}%{_libdir}/gio/modules/giomodule.cache
# Use -p to preserve timestamps on .py files to ensure
# they're not recompiled with different timestamps
# to help multilib: https://bugzilla.redhat.com/show_bug.cgi?id=718404
%make_install INSTALL="install -p"
# Also since this is a generated .py file, set it to a known timestamp,
# otherwise it will vary by build time, and thus break multilib -devel
# installs.
touch -r gio/gdbus-2.0/codegen/config.py.in $RPM_BUILD_ROOT/%{_datadir}/glib-2.0/codegen/config.py
# patch0 changes the timestamp of codegen.py; reset it to a known value to not
# break multilib
touch -r gio/gdbus-2.0/codegen/config.py.in $RPM_BUILD_ROOT/%{_datadir}/glib-2.0/codegen/codegen.py
chrpath --delete $RPM_BUILD_ROOT%{_libdir}/*.so
rm -f $RPM_BUILD_ROOT%{_libdir}/*.la
rm -f $RPM_BUILD_ROOT%{_libdir}/gio/modules/*.{a,la}
rm -f $RPM_BUILD_ROOT%{_libexecdir}/installed-tests/glib/*.{a,la}
rm -f $RPM_BUILD_ROOT%{_libexecdir}/installed-tests/glib/modules/*.{a,la}
# Remove python files bytecompiled by the build system. rpmbuild regenerates
# them again later in a brp script using the timestamps set above.
rm -f $RPM_BUILD_ROOT%{_datadir}/glib-2.0/gdb/*.{pyc,pyo}
rm -rf $RPM_BUILD_ROOT%{_datadir}/glib-2.0/gdb/__pycache__/
rm -f $RPM_BUILD_ROOT%{_datadir}/glib-2.0/codegen/*.{pyc,pyo}
rm -rf $RPM_BUILD_ROOT%{_datadir}/glib-2.0/codegen/__pycache__/
mv $RPM_BUILD_ROOT%{_bindir}/gio-querymodules $RPM_BUILD_ROOT%{_bindir}/gio-querymodules-%{__isa_bits}
touch $RPM_BUILD_ROOT%{_libdir}/gio/modules/giomodule.cache
# bash-completion scripts need not be executable
chmod 644 $RPM_BUILD_ROOT%{_datadir}/bash-completion/completions/*
%find_lang glib20
@ -204,10 +249,9 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_libdir}/libgio-2.0.so.*
%dir %{_datadir}/bash-completion
%dir %{_datadir}/bash-completion/completions
%{_datadir}/bash-completion/completions/gapplication
%{_datadir}/bash-completion/completions/gdbus
%{_datadir}/bash-completion/completions/gio
%{_datadir}/bash-completion/completions/gsettings
%{_datadir}/bash-completion/completions/gapplication
%dir %{_datadir}/glib-2.0
%dir %{_datadir}/glib-2.0/schemas
%dir %{_libdir}/gio
@ -261,7 +305,10 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_datadir}/systemtap/
%files doc
%{_datadir}/gtk-doc/
%doc %{_datadir}/gtk-doc/html/*
%files fam
%{_libdir}/gio/modules/libgiofam.so
%files static
%{_libdir}/libgio-2.0.a
@ -275,372 +322,124 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_datadir}/installed-tests
%changelog
* Mon May 13 2024 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-14.1
- Fix CVE-2024-34397, signal subscription vulnerabilities
- Resolves: RHEL-56979
* Wed Feb 21 2024 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-14
- Rebuild against newer util-linux for libmnt changes
- Resolves: RHEL-23637
* Thu Feb 01 2024 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-13
- Backport GUnixMountMonitor port to libmnt_monitor
- Resolves: RHEL-23637
* Fri Nov 03 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-12
- Fix race with waitpid() and child watcher sources
- Resolves: RHEL-14761
* Wed Jul 19 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-11
- Really fix authentication failures when sd-bus clients connect to GDBus servers
- Resolves: #2217771
* Thu Jul 06 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-10
- Fix authentication failures when sd-bus clients connect to GDBus servers
- Resolves: #2217771
* Thu May 25 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-9
- Resolve s390x crashes introduced by fixes for CVE-2023-24593/CVE-2023-25180
- Related: #2181196
- Related: #2181200
* Wed May 17 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-8
- Resolve use after free introduced by fixes for CVE-2023-24593/CVE-2023-25180
- Related: #2181196
- Related: #2181200
* Fri Mar 24 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-7
- Fix CVE-2023-24593 and CVE-2023-25180
- Resolves: #2181196
- Resolves: #2181200
* Fri Dec 02 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-6
- Drop gdesktopappinfo patchset
- Resolves: #2150307
* Fri Jan 21 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-5
- Add one more upstream patch to gspawn patchset
- Related: #1910092
* Fri Jan 21 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-4
- Add gspawn patchset
- Resolves: #1910092
* Wed Dec 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-3
- Fix GNetworkMonitor after NetworkManager D-Bus API changes
- Resolves: #2014624
* Wed Sep 15 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.4-2
- Fix g_get_user_database_entry() crash when used with nss-systemd
- Resolves: #2004711
* Sat Aug 21 2021 Kalev Lember <klember@redhat.com> - 2.68.4-1
- Update to 2.68.4
* Wed Aug 18 2021 DJ Delorie <dj@redhat.com> - 2.68.3-6
- Rebuilt for libffi 3.4.2 SONAME transition.
Related: rhbz#1891914
* Tue Aug 17 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.3-5
- Backport GPowerProfileMonitor
- Resolves: #1994466
* Mon Aug 09 2021 Mohan Boddu <mboddu@redhat.com> - 2.68.3-4
- Rebuilt for IMA sigs, glibc 2.34, aarch64 flags
Related: rhbz#1991688
* Tue Jul 27 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.3-3
- Fix build with glibc 2.34
- Resolves: #1984626
* Thu Jul 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.3-2
- Refresh gnutls-hmac patchset to fix leaks in error path
- Related: #1971823
* Mon Jun 28 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.3-1
- Update to 2.68.3
- Resolves: #1976713
- Remove Recommends: shared-mime-info
- Resolves: #1947897
* Wed Jun 23 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.2-2
- Update GHmac patchset and reenable glib2-static
- Resolves: #1971823
* Wed May 19 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.2-1
- Update to 2.68.2
- Resolves: #1961039
* Tue May 11 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.1-4
- No changes, bump revision to retry gating
- Related: #1951126
* Fri May 07 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.1-3
- Add missing bundled provides
- Add rpminspect gating configuration
- Consolidate GDesktopAppInfo patchset
- Resolves: #1951126
* Wed Apr 28 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.68.1-2
- Refresh GDesktopAppInfo patchset
- Related: #1951126
* Thu Apr 22 2021 Kalev Lember <klember@redhat.com> - 2.68.1-1
- Update to 2.68.1
* Thu Apr 15 2021 Mohan Boddu <mboddu@redhat.com> - 2.68.0-3
- Rebuilt for RHEL 9 BETA on Apr 15th 2021. Related: rhbz#1947937
* Fri Mar 26 2021 Kalev Lember <klember@redhat.com> - 2.68.0-2
- Rebuild to fix sysprof-capture symbols leaking into libraries consuming it
* Thu Mar 18 2021 Kalev Lember <klember@redhat.com> - 2.68.0-1
- Update to 2.68.0
* Thu Mar 18 2021 Petr Pisar <ppisar@redhat.com> - 2.67.6-2
- Disable debugging glib (bug #1936339)
* Thu Mar 11 2021 Kalev Lember <klember@redhat.com> - 2.67.6-1
- Update to 2.67.6
* Tue Mar 02 2021 Kalev Lember <klember@redhat.com> - 2.67.5-1
- Update to 2.67.5
* Wed Feb 24 2021 Kalev Lember <klember@redhat.com> - 2.67.4-3
- Enable sysprof capture support
* Fri Feb 19 2021 Kalev Lember <klember@redhat.com> - 2.67.4-2
- Backport a fix for gsubprocesslauncher regression
* Tue Feb 16 2021 Kalev Lember <klember@redhat.com> - 2.67.4-1
- Update to 2.67.4
* Fri Mar 29 2024 MSVSphere Packaging Team <packager@msvsphere-os.ru> - 2.56.4-162
- Rebuilt for MSVSphere 8.10 beta
* Tue Feb 09 2021 Benjamin Berg <bberg@redhat.com> - 2.67.3-2
- Add patches to move applications into systemd scopes
* Thu Sep 21 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-162
- Add support to ignore trash for certain mounts
- Resolves: RHEL-2836
* Thu Feb 04 2021 Kalev Lember <klember@redhat.com> - 2.67.3-1
- Update to 2.67.3
- Fix gtk-doc directory ownership
* Tue Jan 03 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-161
- Backport grefcount API
- Resolves: #2153205
* Tue Jan 26 2021 Fedora Release Engineering <releng@fedoraproject.org> - 2.67.1-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_34_Mass_Rebuild
* Wed Nov 16 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-160
- Fix G_FILE_COPY_TARGET_DEFAULT_PERMS, should not create private files
- Resolves: #2125184
* Fri Jan 22 2021 Peter Robinson <pbrobinson@fedoraproject.org> - 2.67.1-3
- Drop dependency on gamin
* Fri Apr 22 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-159
- Add --interface-info-[body|header] modes to gdbus-codegen
- Related: #2061994
* Sat Dec 19 2020 Kevin Fenzi <kevin@scrye.com> - 2.67.1-2
- Add already upstream patch to fix gdm crasher.
* Sat Dec 19 2020 Kalev Lember <klember@redhat.com> - 2.67.1-1
- Update to 2.67.1
* Fri Dec 04 2020 Ondrej Holy <oholy@redhat.com> - 2.67.0-7
- Explicitly create modules dir to fix ELN build
* Tue Dec 01 2020 Ondrej Holy and Michael Catanzaro <mcatanzaro@redhat.com> - 2.67.0-6
- Disable glib2-fam in RHEL
* Tue Nov 24 2020 Kalev Lember <klember@redhat.com> - 2.67.0-5
- Backport upstream patches to fix invalid use of volatile objects
(gcc 11 support)
* Wed Nov 11 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.67.0-4
- Make GnuTLS patch RHEL-specific, and make glib2-static subpackage Fedora-specific
* Tue Nov 10 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.67.0-3
- Use GnuTLS to implement GHmac (thanks to Colin Walters)
* Wed Nov 04 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.67.0-2
- Backport fix for GSocketClient crash
* Thu Oct 29 2020 Kalev Lember <klember@redhat.com> - 2.67.0-1
- Update to 2.67.0
* Mon Oct 19 2020 Kalev Lember <klember@redhat.com> - 2.66.2-1
- Update to 2.66.2
- Drop gtk-doc patch as we finally have a new enough gtk-doc
* Wed Oct 14 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.66.1-3
- Fix yet another timezone bug
* Wed Oct 14 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.66.1-2
- Fix timezone-related bugs in many applications caused by new glib timezone cache
* Thu Oct 1 2020 Kalev Lember <klember@redhat.com> - 2.66.1-1
- Update to 2.66.1
* Thu Sep 10 2020 Kalev Lember <klember@redhat.com> - 2.66.0-1
- Update to 2.66.0
* Wed Sep 02 2020 Kalev Lember <klember@redhat.com> - 2.65.3-1
- Update to 2.65.3
* Tue Aug 25 2020 Adam Williamson <awilliam@redhat.com> - 2.65.2-3
- Backport fix for GGO #2189 (error accessing some filesystems)
* Thu Aug 20 2020 Jeff Law <law@redhat.com> - 2.65.2-2
- Re-enable LTO
* Tue Aug 18 2020 Kalev Lember <klember@redhat.com> - 2.65.2-1
- Update to 2.65.2
* Mon Aug 17 2020 Kalev Lember <klember@redhat.com> - 2.65.1-1
- Update to 2.65.1
* Sat Aug 01 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.65.0-5
- Second attempt - Rebuilt for
https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Mon Jul 27 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.65.0-4
- Rebuilt for https://fedoraproject.org/wiki/Fedora_33_Mass_Rebuild
* Tue Jun 30 2020 Jeff Law <aw@redhat.com> - 2.65.0-3
Disable LTO
* Mon Jun 22 2020 Kalev Lember <klember@redhat.com> - 2.65.0-2
- Update gio-2.0.pc with correct gio-querymodules name when renaming it
(#1849441)
* Mon Jun 22 2020 Kalev Lember <klember@redhat.com> - 2.65.0-1
- Update to 2.65.0
* Wed May 20 2020 Kalev Lember <klember@redhat.com> - 2.64.3-1
- Update to 2.64.3
* Tue Apr 28 2020 Tomas Popela <tpopela@redhat.com> - 2.64.2-2
- Backport fix for a race condition in GCancellable (rhbz#1825230)
* Fri Apr 10 2020 Kalev Lember <klember@redhat.com> - 2.64.2-1
- Update to 2.64.2
* Wed Mar 11 2020 Kalev Lember <klember@redhat.com> - 2.64.1-1
- Update to 2.64.1
* Mon Mar 02 2020 Kalev Lember <klember@redhat.com> - 2.64.0-1
- Update to 2.64.0
* Mon Feb 24 2020 Kalev Lember <klember@redhat.com> - 2.63.6-1
- Update to 2.63.6
* Wed Feb 12 2020 Kalev Lember <klember@redhat.com> - 2.63.5-3
- Backport a patch to work around SELinux policies not allowing
SYS_sched_setattr (#1795524)
* Fri Feb 07 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.63.5-2
- Add patch for CVE-2020-6750 and related issues.
* Mon Feb 03 2020 Kalev Lember <klember@redhat.com> - 2.63.5-1
- Update to 2.63.5
* Wed Jan 29 2020 Stephen Gallagher <sgallagh@redhat.com> - 2.63.4-3
- Fix GThreadPool initialization that is breaking createrepo_c (BZ #1795052)
* Tue Jan 28 2020 Fedora Release Engineering <releng@fedoraproject.org> - 2.63.4-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_32_Mass_Rebuild
* Fri Jan 24 2020 Kalev Lember <klember@redhat.com> - 2.63.4-1
- Update to 2.63.4
* Mon Dec 16 2019 Kalev Lember <klember@redhat.com> - 2.63.3-1
- Update to 2.63.3
* Mon Dec 02 2019 Kalev Lember <klember@redhat.com> - 2.63.2-1
- Update to 2.63.2
* Fri Oct 04 2019 Kalev Lember <klember@redhat.com> - 2.63.0-1
- Update to 2.63.0
* Fri Oct 04 2019 Kalev Lember <klember@redhat.com> - 2.62.1-1
- Update to 2.62.1
* Fri Sep 06 2019 Kalev Lember <klember@redhat.com> - 2.62.0-1
- Update to 2.62.0
* Tue Sep 03 2019 Kalev Lember <klember@redhat.com> - 2.61.3-1
- Update to 2.61.3
* Mon Aug 12 2019 Kalev Lember <klember@redhat.com> - 2.61.2-1
- Update to 2.61.2
* Thu Jul 25 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.61.1-3
- Rebuilt for https://fedoraproject.org/wiki/Fedora_31_Mass_Rebuild
* Tue Jun 11 2019 David King <amigadave@amigadave.com> - 2.61.1-2
- Fix CVE-2019-12450 (#1719142)
- Consistently use buildroot macro
* Fri May 24 2019 Kalev Lember <klember@redhat.com> - 2.61.1-1
- Update to 2.61.1
* Tue Apr 16 2019 Adam Williamson <awilliam@redhat.com> - 2.61.0-2
- Rebuild with Meson fix for #1699099
* Mon Apr 15 2019 Kalev Lember <klember@redhat.com> - 2.61.0-1
- Update to 2.61.0
* Mon Apr 15 2019 Kalev Lember <klember@redhat.com> - 2.60.1-1
- Update to 2.60.1
* Wed Mar 13 2019 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.60.0-3
- Switch back to timestamp-based pyc invalidation mode
* Wed Mar 6 2019 Zbigniew Jędrzejewski-Szmek <zbyszek@in.waw.pl> - 2.60.0-2
- Make sure all .py files have fixed timestamps (fixes issue with
parallel installability of i686 and amd64 -devel packages)
- Switch to explicit byte compilation to override invalidation mode
* Mon Mar 04 2019 Kalev Lember <klember@redhat.com> - 2.60.0-1
- Update to 2.60.0
* Mon Feb 18 2019 Kalev Lember <klember@redhat.com> - 2.59.3-1
- Update to 2.59.3
* Mon Feb 04 2019 Kalev Lember <klember@redhat.com> - 2.59.2-1
- Update to 2.59.2
* Thu Jan 31 2019 Fedora Release Engineering <releng@fedoraproject.org> - 2.59.1-2
- Rebuilt for https://fedoraproject.org/wiki/Fedora_30_Mass_Rebuild
* Sat Jan 26 2019 Kalev Lember <klember@redhat.com> - 2.59.1-1
- Update to 2.59.1
* Thu Jan 03 2019 Kalev Lember <klember@redhat.com> - 2.59.0-1
- Update to 2.59.0
- Switch to the meson build system
* Tue Dec 18 2018 Kalev Lember <klember@redhat.com> - 2.58.2-1
- Update to 2.58.2
* Fri Oct 05 2018 Kalev Lember <klember@redhat.com> - 2.58.1-2
- Fix multilib -devel installs (#1634778)
* Fri Sep 21 2018 Kalev Lember <klember@redhat.com> - 2.58.1-1
- Update to 2.58.1
* Wed Sep 05 2018 Kalev Lember <klember@redhat.com> - 2.58.0-1
- Update to 2.58.0
* Thu Aug 2 2018 Ondrej Holy <oholy@redhat.com> - 2.57.2-1
- Update to 2.57.2
* Fri Jul 20 2018 Ondrej Holy <oholy@redhat.com> - 2.57.1-1
- Update to 2.57.1
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org> - 2.56.1-6
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
* Tue Jun 19 2018 Miro Hrončok <mhroncok@redhat.com> - 2.56.1-5
- Rebuilt for Python 3.7
* Thu Jun 14 2018 Debarshi Ray <rishi@fedoraproject.org> - 2.56.1-4
- Backport patch to fix possible invalid pointer in dbus callback in the FD.o
notification backend (RH #1584916)
* Sun May 27 2018 Kalev Lember <klember@redhat.com> - 2.56.1-3
- Fix multilib -devel installs (#1581067)
* Wed Dec 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-158
- Fix GNetworkMonitor after NetworkManager D-Bus API changes
- Resolves: #2014652
* Sun May 13 2018 Fabio Valentini <decathorpe@gmail.com> - 2.56.1-2
- Include upstream patch to fix gdbus-codegen with meson 0.46.
* Wed Sep 15 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-157
- Fix g_get_user_database_entry() crash when used with nss-systemd
- Resolves: #2002126
* Thu Jul 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-156
- Fix test failure introduced in previous update
- Related: #1971533
* Wed Jun 23 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-14
- Refresh GHmac patchset
- Resolves: #1971533
* Thu May 20 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-13
- Rename and consolidate existing patches for better maintainability
- Refresh CVE-2021-27219 patcheset, using better-targeted fixes
Resolves: #1939108
* Wed May 05 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-12
- Fix various problems in GMainContext
Resolves: #1948988
* Tue May 04 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-11
- Remove CHARSETALIASDIR environment variable
Resolves: #1938284
* Wed Mar 31 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-10
- Fix CVE-2021-27218
Resolves: #1939072
- Fix CVE-2021-27219
Resolves: #1939108
- Fix CVE-2021-28153
Resolves: #1939118
* Tue Nov 10 2020 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-9
- Update GHmac patch to implement g_hmac_copy()
Resolves: #1786538
- Update keyfile settings backend
Resolves: #1728896
- Fix CVE-2019-13012
Resolves: #1728632
* Mon Dec 02 2019 Colin Walters <walters@verbum.org> - 2.56.4-8
- Backport patches for GDBus auth
Resolves: #1777213
* Sat Jul 13 2019 Colin Walters <walters@redhat.com> - 2.56.4-7
- Backport patch for CVE-2019-12450
Resolves: #1722101
* Mon Jun 17 2019 Ray Strode <rstrode@redhat.com> - 2.56.4-5
- Backport glib2 change needed for accountsservice dbus
codegen fix
Resolves: #1713081
* Mon Jun 10 2019 Colin Walters <walters@redhat.com> - 2.56.4-4
- Back GHmac with GnuTLS for FIPS
- Resolves: #1630260
* Fri May 31 2019 Florian Müllner <fmuellner@redhat.com> - 2.56.4-3
- Backport per-desktop overrides
- Resolves: #1715951
* Tue Apr 02 2019 Colin Walters <walters@redhat.com> - 2.56.4-2
- Add system LDFLAGS
- Resolves: #1630566
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.4-1
- Update to 2.56.4
- Resolves: #1660859
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-7
- Remove .la files from -tests subpackage
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-6
- Fix multilib -devel installs
- Related: #1639428
* Mon Jan 14 2019 Kalev Lember <klember@redhat.com> - 2.56.1-5
- Fix gdbus codegen generated proxies breaking strict aliasing rules
- Resolves: #1639428
* Mon Dec 17 2018 Ray Strode <rstrode@redhat.com> - 2.56.1-4
- Ensure shared-mime-info is installed during testing
- Ensure test suite runs as unprivileged user
- Ensure test suite works when debugging is enabled
- Ensure echo-script from spawn test is marked executable
Related: #1625683
* Fri Dec 14 2018 Ray Strode <rstrode@redhat.com> - 2.56.1-3
- rebuild
Related: #1625683
* Mon Dec 10 2018 Josh Boyer <jwboyer@redhat.com> - 2.56.1-2
- Rebuild for CET note fixes
Resolves: #1657311
* Sun Apr 08 2018 Kalev Lember <klember@redhat.com> - 2.56.1-1
- Update to 2.56.1

Loading…
Cancel
Save