Compare commits

...

No commits in common. "imports/c8s/glib2-2.56.4-157.el8" and "c8" have entirely different histories.

13 changed files with 7447 additions and 1 deletions

139
SOURCES/1134.patch Normal file
View File

@ -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

654
SOURCES/13.patch Normal file
View File

@ -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

401
SOURCES/1549.patch Normal file
View File

@ -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

83
SOURCES/4155.patch Normal file
View File

@ -0,0 +1,83 @@
From d9fec76b594fccc6eda3ce04a74beae1c8b8c1d2 Mon Sep 17 00:00:00 2001
From: Ondrej Holy <oholy@redhat.com>
Date: Fri, 12 Jul 2024 11:14:10 +0200
Subject: [PATCH] gfile: Add support for x-gvfs-trash mount option
Currently, the trash functionality is disabled for system internal mounts.
That might be a problem in some cases. The `x-gvfs-notrash` mount option
allows disabling the trash functionality for certain mounts. Let's add
support for the `x-gvfs-trash` mount option to allow the opposite.
See: https://issues.redhat.com/browse/RHEL-46828
---
gio/gfile.c | 7 +++++--
gio/glocalfile.c | 22 +++++++++++++---------
2 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/gio/gfile.c b/gio/gfile.c
index 4f9b9c6750..5ac73c03e8 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -4744,10 +4744,13 @@ 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
+ * Trashing is disabled for system mounts by default (see
+ * g_unix_mount_is_system_internal()), so this call can return the
* %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
+ * mount option can be used to disable g_file_trash() support for particular
* mounts, the %G_IO_ERROR_NOT_SUPPORTED error will be returned in that case.
+ * Since 2.82, the `x-gvfs-trash` unix mount option can be used to enable
+ * g_file_trash() support for particular system mounts.
*
* 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 7b70c614c6..ac918d25e3 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -1807,10 +1807,6 @@ 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)
@@ -1819,15 +1815,23 @@ ignore_trash_mount (GUnixMountEntry *mount)
NULL);
if (mount_point != NULL)
mount_options = g_unix_mount_point_get_options (mount_point);
+
+ g_clear_pointer (&mount_point, g_unix_mount_point_free);
}
- if (mount_options == NULL ||
- strstr (mount_options, "x-gvfs-notrash") == NULL)
- retval = FALSE;
+ if (mount_options != NULL)
+ {
+ if (strstr (mount_options, "x-gvfs-trash") != NULL)
+ return FALSE;
+
+ if (strstr (mount_options, "x-gvfs-notrash") != NULL)
+ return TRUE;
+ }
- g_clear_pointer (&mount_point, g_unix_mount_point_free);
+ if (g_unix_mount_is_system_internal (mount))
+ return TRUE;
- return retval;
+ return FALSE;
}
static gboolean
--
GitLab

702
SOURCES/54.patch Normal file
View File

@ -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

3170
SOURCES/CVE-2024-34397.patch Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,45 @@
From 25833cefda24c60af913d6f2d532b5afd608b821 Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 19 Sep 2024 18:35:53 +0100
Subject: [PATCH] gsocks4aproxy: Fix a single byte buffer overflow in connect
messages
`SOCKS4_CONN_MSG_LEN` failed to account for the length of the final nul
byte in the connect message, which is an addition in SOCKSv4a vs
SOCKSv4.
This means that the buffer for building and transmitting the connect
message could be overflowed if the username and hostname are both
`SOCKS4_MAX_LEN` (255) bytes long.
Proxy configurations are normally statically configured, so the username
is very unlikely to be near its maximum length, and hence this overflow
is unlikely to be triggered in practice.
(Commit message by Philip Withnall, diagnosis and fix by Michael
Catanzaro.)
Fixes: #3461
---
gio/gsocks4aproxy.c | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/gio/gsocks4aproxy.c b/gio/gsocks4aproxy.c
index 3dad118eb7..b3146d08fd 100644
--- a/gio/gsocks4aproxy.c
+++ b/gio/gsocks4aproxy.c
@@ -79,9 +79,9 @@ g_socks4a_proxy_init (GSocks4aProxy *proxy)
* +----+----+----+----+----+----+----+----+----+----+....+----+------+....+------+
* | VN | CD | DSTPORT | DSTIP | USERID |NULL| HOST | | NULL |
* +----+----+----+----+----+----+----+----+----+----+....+----+------+....+------+
- * 1 1 2 4 variable 1 variable
+ * 1 1 2 4 variable 1 variable 1
*/
-#define SOCKS4_CONN_MSG_LEN (9 + SOCKS4_MAX_LEN * 2)
+#define SOCKS4_CONN_MSG_LEN (10 + SOCKS4_MAX_LEN * 2)
static gint
set_connect_msg (guint8 *msg,
const gchar *hostname,
--
GitLab

433
SOURCES/CVE-2025-4373.patch Normal file
View File

@ -0,0 +1,433 @@
From 6c2178a3bc216a6cc765fc6ba3b0e6d22ce5af7e Mon Sep 17 00:00:00 2001
From: Emmanuel Fleury <emmanuel.fleury@u-bordeaux.fr>
Date: Mon, 4 Feb 2019 13:31:28 +0100
Subject: [PATCH 1/3] Fixing various warnings in glib/gstring.c
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function g_string_insert_len:
glib/gstring.c:441:31: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro G_LIKELY
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:441:5: note: in expansion of macro g_return_val_if_fail
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:458:15: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (pos < string->len)
^
glib/gstring.c:462:18: error: comparison of integer expressions of different signedness: gsize {aka long unsigned int} and gssize {aka long int} [-Werror=sign-compare]
if (offset < pos)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gmacros.h:351:26: error: comparison of integer expressions of different signedness: gssize {aka long int} and long unsigned int [-Werror=sign-compare]
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
^
glib/gstring.c:464:22: note: in expansion of macro MIN
precount = MIN (len, pos - offset);
^~~
glib/gmacros.h:351:35: error: operand of ?: changes signedness from gssize {aka long int} to long unsigned int due to unsignedness of other operand [-Werror=sign-compare]
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
^~~
glib/gstring.c:464:22: note: in expansion of macro MIN
precount = MIN (len, pos - offset);
^~~
glib/gstring.c:469:15: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (len > precount)
^
glib/gstring.c:481:15: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function g_string_insert_c:
glib/gstring.c:782:31: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro G_LIKELY
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:782:5: note: in expansion of macro g_return_val_if_fail
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:785:11: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function g_string_insert_unichar:
glib/gstring.c:857:31: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro G_LIKELY
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:857:5: note: in expansion of macro g_return_val_if_fail
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:860:11: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (pos < string->len)
^
In file included from glib/glibconfig.h:9,
from glib/gtypes.h:32,
from glib/gstring.h:32,
from glib/gstring.c:37:
glib/gstring.c: In function g_string_erase:
glib/gstring.c:969:29: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
g_return_val_if_fail (pos <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro G_LIKELY
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:969:3: note: in expansion of macro g_return_val_if_fail
g_return_val_if_fail (pos <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:975:39: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
g_return_val_if_fail (pos + len <= string->len, string);
^~
glib/gmacros.h:455:25: note: in definition of macro G_LIKELY
#define G_LIKELY(expr) (expr)
^~~~
glib/gstring.c:975:7: note: in expansion of macro g_return_val_if_fail
g_return_val_if_fail (pos + len <= string->len, string);
^~~~~~~~~~~~~~~~~~~~
glib/gstring.c:977:21: error: comparison of integer expressions of different signedness: gssize {aka long int} and gsize {aka long unsigned int} [-Werror=sign-compare]
if (pos + len < string->len)
^
---
glib/gstring.c | 82 +++++++++++++++++++++++++++++++-------------------
1 file changed, 51 insertions(+), 31 deletions(-)
diff --git a/glib/gstring.c b/glib/gstring.c
index 966502019..f5bfeb0ed 100644
--- a/glib/gstring.c
+++ b/glib/gstring.c
@@ -426,6 +426,8 @@ g_string_insert_len (GString *string,
const gchar *val,
gssize len)
{
+ gsize len_unsigned, pos_unsigned;
+
g_return_val_if_fail (string != NULL, NULL);
g_return_val_if_fail (len == 0 || val != NULL, string);
@@ -434,11 +436,15 @@ g_string_insert_len (GString *string,
if (len < 0)
len = strlen (val);
+ len_unsigned = len;
if (pos < 0)
- pos = string->len;
+ pos_unsigned = string->len;
else
- g_return_val_if_fail (pos <= string->len, string);
+ {
+ pos_unsigned = pos;
+ g_return_val_if_fail (pos_unsigned <= string->len, string);
+ }
/* Check whether val represents a substring of string.
* This test probably violates chapter and verse of the C standards,
@@ -450,45 +456,48 @@ g_string_insert_len (GString *string,
gsize offset = val - string->str;
gsize precount = 0;
- g_string_maybe_expand (string, len);
+ g_string_maybe_expand (string, len_unsigned);
val = string->str + offset;
/* At this point, val is valid again. */
/* Open up space where we are going to insert. */
- if (pos < string->len)
- memmove (string->str + pos + len, string->str + pos, string->len - pos);
+ if (pos_unsigned < string->len)
+ memmove (string->str + pos_unsigned + len_unsigned,
+ string->str + pos_unsigned, string->len - pos_unsigned);
/* Move the source part before the gap, if any. */
- if (offset < pos)
+ if (offset < pos_unsigned)
{
- precount = MIN (len, pos - offset);
- memcpy (string->str + pos, val, precount);
+ precount = MIN (len_unsigned, pos_unsigned - offset);
+ memcpy (string->str + pos_unsigned, val, precount);
}
/* Move the source part after the gap, if any. */
- if (len > precount)
- memcpy (string->str + pos + precount,
- val + /* Already moved: */ precount + /* Space opened up: */ len,
- len - precount);
+ if (len_unsigned > precount)
+ memcpy (string->str + pos_unsigned + precount,
+ val + /* Already moved: */ precount +
+ /* Space opened up: */ len_unsigned,
+ len_unsigned - precount);
}
else
{
- g_string_maybe_expand (string, len);
+ g_string_maybe_expand (string, len_unsigned);
/* If we aren't appending at the end, move a hunk
* of the old string to the end, opening up space
*/
- if (pos < string->len)
- memmove (string->str + pos + len, string->str + pos, string->len - pos);
+ if (pos_unsigned < string->len)
+ memmove (string->str + pos_unsigned + len_unsigned,
+ string->str + pos_unsigned, string->len - pos_unsigned);
/* insert the new string */
- if (len == 1)
- string->str[pos] = *val;
+ if (len_unsigned == 1)
+ string->str[pos_unsigned] = *val;
else
- memcpy (string->str + pos, val, len);
+ memcpy (string->str + pos_unsigned, val, len_unsigned);
}
- string->len += len;
+ string->len += len_unsigned;
string->str[string->len] = 0;
@@ -772,6 +781,8 @@ g_string_insert_c (GString *string,
gssize pos,
gchar c)
{
+ gsize pos_unsigned;
+
g_return_val_if_fail (string != NULL, NULL);
g_string_maybe_expand (string, 1);
@@ -779,13 +790,15 @@ g_string_insert_c (GString *string,
if (pos < 0)
pos = string->len;
else
- g_return_val_if_fail (pos <= string->len, string);
+ g_return_val_if_fail ((gsize) pos <= string->len, string);
+ pos_unsigned = pos;
/* If not just an append, move the old stuff */
- if (pos < string->len)
- memmove (string->str + pos + 1, string->str + pos, string->len - pos);
+ if (pos_unsigned < string->len)
+ memmove (string->str + pos_unsigned + 1,
+ string->str + pos_unsigned, string->len - pos_unsigned);
- string->str[pos] = c;
+ string->str[pos_unsigned] = c;
string->len += 1;
@@ -854,10 +867,10 @@ g_string_insert_unichar (GString *string,
if (pos < 0)
pos = string->len;
else
- g_return_val_if_fail (pos <= string->len, string);
+ g_return_val_if_fail ((gsize) pos <= string->len, string);
/* If not just an append, move the old stuff */
- if (pos < string->len)
+ if ((gsize) pos < string->len)
memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
dest = string->str + pos;
@@ -964,21 +977,28 @@ g_string_erase (GString *string,
gssize pos,
gssize len)
{
+ gsize len_unsigned, pos_unsigned;
+
g_return_val_if_fail (string != NULL, NULL);
g_return_val_if_fail (pos >= 0, string);
- g_return_val_if_fail (pos <= string->len, string);
+ pos_unsigned = pos;
+
+ g_return_val_if_fail (pos_unsigned <= string->len, string);
if (len < 0)
- len = string->len - pos;
+ len_unsigned = string->len - pos_unsigned;
else
{
- g_return_val_if_fail (pos + len <= string->len, string);
+ len_unsigned = len;
+ g_return_val_if_fail (pos_unsigned + len_unsigned <= string->len, string);
- if (pos + len < string->len)
- memmove (string->str + pos, string->str + pos + len, string->len - (pos + len));
+ if (pos_unsigned + len_unsigned < string->len)
+ memmove (string->str + pos_unsigned,
+ string->str + pos_unsigned + len_unsigned,
+ string->len - (pos_unsigned + len_unsigned));
}
- string->len -= len;
+ string->len -= len_unsigned;
string->str[string->len] = 0;
--
2.50.0
From 101afb01778659cb7051b3cb33d55dc965c8dc7e Mon Sep 17 00:00:00 2001
From: Michael Catanzaro <mcatanzaro@redhat.com>
Date: Thu, 10 Apr 2025 10:57:20 -0500
Subject: [PATCH 2/3] gstring: carefully handle gssize parameters
Wherever we use gssize to allow passing -1, we need to ensure we don't
overflow the value by assigning a gsize to it without checking if the
size exceeds the maximum gssize. The safest way to do this is to just
use normal gsize everywhere instead and use gssize only for the
parameter.
Our computers don't have enough RAM to write tests for this. I tried
forcing string->len to high values for test purposes, but this isn't
valid and will just cause out of bounds reads/writes due to
string->allocated_len being unexpectedly small, so I don't think we can
test this easily.
---
glib/gstring.c | 36 +++++++++++++++++++++++-------------
1 file changed, 23 insertions(+), 13 deletions(-)
diff --git a/glib/gstring.c b/glib/gstring.c
index f5bfeb0ed..84a98da25 100644
--- a/glib/gstring.c
+++ b/glib/gstring.c
@@ -435,8 +435,9 @@ g_string_insert_len (GString *string,
return string;
if (len < 0)
- len = strlen (val);
- len_unsigned = len;
+ len_unsigned = strlen (val);
+ else
+ len_unsigned = len;
if (pos < 0)
pos_unsigned = string->len;
@@ -788,10 +789,12 @@ g_string_insert_c (GString *string,
g_string_maybe_expand (string, 1);
if (pos < 0)
- pos = string->len;
+ pos_unsigned = string->len;
else
- g_return_val_if_fail ((gsize) pos <= string->len, string);
- pos_unsigned = pos;
+ {
+ pos_unsigned = pos;
+ g_return_val_if_fail (pos_unsigned <= string->len, string);
+ }
/* If not just an append, move the old stuff */
if (pos_unsigned < string->len)
@@ -824,6 +827,7 @@ g_string_insert_unichar (GString *string,
gssize pos,
gunichar wc)
{
+ gsize pos_unsigned;
gint charlen, first, i;
gchar *dest;
@@ -865,15 +869,18 @@ g_string_insert_unichar (GString *string,
g_string_maybe_expand (string, charlen);
if (pos < 0)
- pos = string->len;
+ pos_unsigned = string->len;
else
- g_return_val_if_fail ((gsize) pos <= string->len, string);
+ {
+ pos_unsigned = pos;
+ g_return_val_if_fail (pos_unsigned <= string->len, string);
+ }
/* If not just an append, move the old stuff */
- if ((gsize) pos < string->len)
- memmove (string->str + pos + charlen, string->str + pos, string->len - pos);
+ if (pos_unsigned < string->len)
+ memmove (string->str + pos_unsigned + charlen, string->str + pos_unsigned, string->len - pos_unsigned);
- dest = string->str + pos;
+ dest = string->str + pos_unsigned;
/* Code copied from g_unichar_to_utf() */
for (i = charlen - 1; i > 0; --i)
{
@@ -931,6 +938,7 @@ g_string_overwrite_len (GString *string,
const gchar *val,
gssize len)
{
+ gssize len_unsigned;
gsize end;
g_return_val_if_fail (string != NULL, NULL);
@@ -942,14 +950,16 @@ g_string_overwrite_len (GString *string,
g_return_val_if_fail (pos <= string->len, string);
if (len < 0)
- len = strlen (val);
+ len_unsigned = strlen (val);
+ else
+ len_unsigned = len;
- end = pos + len;
+ end = pos + len_unsigned;
if (end > string->len)
g_string_maybe_expand (string, end - string->len);
- memcpy (string->str + pos, val, len);
+ memcpy (string->str + pos, val, len_unsigned);
if (end > string->len)
{
--
2.50.0
From 789c240db9738cae37ee77f7e135e5dbc39ab3ca Mon Sep 17 00:00:00 2001
From: Peter Bloomfield <peterbloomfield@bellsouth.net>
Date: Fri, 11 Apr 2025 05:52:33 +0000
Subject: [PATCH 3/3] gstring: Make len_unsigned unsigned
---
glib/gstring.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/glib/gstring.c b/glib/gstring.c
index 84a98da25..7379517f5 100644
--- a/glib/gstring.c
+++ b/glib/gstring.c
@@ -938,7 +938,7 @@ g_string_overwrite_len (GString *string,
const gchar *val,
gssize len)
{
- gssize len_unsigned;
+ gsize len_unsigned;
gsize end;
g_return_val_if_fail (string != NULL, NULL);
--
2.50.0

View File

@ -0,0 +1,126 @@
From a07f759373d888c837a780cb93f14542b029e19c Mon Sep 17 00:00:00 2001
From: "Rebecca N. Palmer" <rebecca_palmer@zoho.com>
Date: Fri, 11 Oct 2024 09:38:52 +0100
Subject: [PATCH 1/2] gdatetime test: Do not assume PST8PDT was always exactly
-8/-7
In newer tzdata, it is an alias for America/Los_Angeles, which has a
slightly different meaning: DST did not exist there before 1883. As a
result, we can no longer hard-code the knowledge that interval 0 is
standard time and interval 1 is summer time, and instead we need to look
up the correct intervals from known timestamps.
Resolves: https://gitlab.gnome.org/GNOME/glib/-/issues/3502
Bug-Debian: https://bugs.debian.org/1084190
[smcv: expand commit message, fix whitespace]
Signed-off-by: Simon McVittie <smcv@debian.org>
---
glib/tests/gdatetime.c | 23 +++++++++++++++++------
1 file changed, 17 insertions(+), 6 deletions(-)
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index 5a2190d5f..80098bab3 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -2096,6 +2096,7 @@ test_posix_parse (void)
{
GTimeZone *tz;
GDateTime *gdt1, *gdt2;
+ gint i1, i2;
tz = g_time_zone_new ("PST");
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "UTC");
@@ -2111,14 +2112,24 @@ test_posix_parse (void)
/* This fails rules_from_identifier on Unix (though not on Windows)
* but passes anyway because PST8PDT is a zone name.
+ *
+ * Intervals i1 and i2 (rather than 0 and 1) are needed because in
+ * recent tzdata, PST8PDT may be an alias for America/Los_Angeles,
+ * and hence be aware that DST has not always existed.
+ * https://bugs.debian.org/1084190
*/
tz = g_time_zone_new ("PST8PDT");
- g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 0), ==, "PST");
- g_assert_cmpint (g_time_zone_get_offset (tz, 0), ==, - 8 * 3600);
- g_assert (!g_time_zone_is_dst (tz, 0));
- g_assert_cmpstr (g_time_zone_get_abbreviation (tz, 1), ==, "PDT");
- g_assert_cmpint (g_time_zone_get_offset (tz, 1), ==,- 7 * 3600);
- g_assert (g_time_zone_is_dst (tz, 1));
+ g_assert_nonnull (tz);
+ /* a date in winter = non-DST */
+ i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, 0);
+ /* approximately 6 months in seconds, i.e. a date in summer = DST */
+ i2 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, 15000000);
+ g_assert_cmpstr (g_time_zone_get_abbreviation (tz, i1), ==, "PST");
+ g_assert_cmpint (g_time_zone_get_offset (tz, i1), ==, - 8 * 3600);
+ g_assert (!g_time_zone_is_dst (tz, i1));
+ g_assert_cmpstr (g_time_zone_get_abbreviation (tz, i2), ==, "PDT");
+ g_assert_cmpint (g_time_zone_get_offset (tz, i2), ==,- 7 * 3600);
+ g_assert (g_time_zone_is_dst (tz, i2));
g_time_zone_unref (tz);
tz = g_time_zone_new ("PST8PDT6:32:15");
--
2.50.0
From d1e564d6d4f478c9e0b163763ed2b199dfafd500 Mon Sep 17 00:00:00 2001
From: Simon McVittie <smcv@debian.org>
Date: Fri, 18 Oct 2024 11:03:19 +0100
Subject: [PATCH 2/2] gdatetime test: Try to make PST8PDT test more obviously
correct
Instead of using timestamp 0 as a magic number (in this case interpreted
as 1970-01-01T00:00:00-08:00), calculate a timestamp from a recent
year/month/day in winter, in this case 2024-01-01T00:00:00-08:00.
Similarly, instead of using a timestamp 15 million seconds later
(1970-06-23T15:40:00-07:00), calculate a timestamp from a recent
year/month/day in summer, in this case 2024-07-01T00:00:00-07:00.
Signed-off-by: Simon McVittie <smcv@debian.org>
---
glib/tests/gdatetime.c | 15 +++++++--------
1 file changed, 7 insertions(+), 8 deletions(-)
diff --git a/glib/tests/gdatetime.c b/glib/tests/gdatetime.c
index 80098bab3..d0755e722 100644
--- a/glib/tests/gdatetime.c
+++ b/glib/tests/gdatetime.c
@@ -2112,18 +2112,15 @@ test_posix_parse (void)
/* This fails rules_from_identifier on Unix (though not on Windows)
* but passes anyway because PST8PDT is a zone name.
- *
- * Intervals i1 and i2 (rather than 0 and 1) are needed because in
- * recent tzdata, PST8PDT may be an alias for America/Los_Angeles,
- * and hence be aware that DST has not always existed.
- * https://bugs.debian.org/1084190
*/
tz = g_time_zone_new ("PST8PDT");
g_assert_nonnull (tz);
/* a date in winter = non-DST */
- i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, 0);
- /* approximately 6 months in seconds, i.e. a date in summer = DST */
- i2 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, 15000000);
+ gdt1 = g_date_time_new (tz, 2024, 1, 1, 0, 0, 0);
+ i1 = g_time_zone_find_interval (tz, G_TIME_TYPE_STANDARD, g_date_time_to_unix (gdt1));
+ /* a date in summer = DST */
+ gdt2 = g_date_time_new (tz, 2024, 7, 1, 0, 0, 0);
+ i2 = g_time_zone_find_interval (tz, G_TIME_TYPE_DAYLIGHT, g_date_time_to_unix (gdt2));
g_assert_cmpstr (g_time_zone_get_abbreviation (tz, i1), ==, "PST");
g_assert_cmpint (g_time_zone_get_offset (tz, i1), ==, - 8 * 3600);
g_assert (!g_time_zone_is_dst (tz, i1));
@@ -2131,6 +2128,8 @@ test_posix_parse (void)
g_assert_cmpint (g_time_zone_get_offset (tz, i2), ==,- 7 * 3600);
g_assert (g_time_zone_is_dst (tz, i2));
g_time_zone_unref (tz);
+ g_date_time_unref (gdt1);
+ g_date_time_unref (gdt2);
tz = g_time_zone_new ("PST8PDT6:32:15");
#ifdef G_OS_WIN32
--
2.50.0

View File

@ -0,0 +1,401 @@
From b43d2e06834a9779801f9a68904ae73a26578f01 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Sat, 21 Sep 2019 10:45:36 +0200
Subject: [PATCH 1/2] gatomic: Add various casts to use of g_atomic_*()s to fix
warnings
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
When compiling GLib with `-Wsign-conversion`, we get various warnings
about the atomic calls. A lot of these were fixed by
3ad375a629c91a27d0165a31f0ed298fd553de0a, but some remain. Fix them by
adding appropriate casts at the call sites.
Note that `g_atomic_int_{and,or,xor}()` actually all operate on `guint`s
rather than `gint`s (which is what the rest of the `g_atomic_int_*()`
functions operate on). I cant find any written reasoning for this, but
assume that its because signedness is irrelevant when youre using an
integer as a bit field. Its unfortunate that theyre named a
`g_atomic_int_*()` rather than `g_atomic_uint_*()` functions.
Tested by compiling GLib as:
```
CFLAGS=-Wsign-conversion jhbuild make -ac |& grep atomic
```
Im not going to add `-Wsign-conversion` to the set of default warnings
for building GLib, because it mostly produces false positives throughout
the rest of GLib.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #1565
---
gio/gdbusconnection.c | 8 ++++----
gio/gdbusnamewatching.c | 4 ++--
gio/tests/gdbus-threading.c | 2 +-
glib/gbitlock.c | 2 +-
glib/gquark.c | 2 +-
glib/gthread-posix.c | 2 +-
glib/gthreadpool.c | 10 +++++-----
glib/tests/atomic.c | 20 ++++++++++----------
8 files changed, 25 insertions(+), 25 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 117c8df35..1c1f0cf3d 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -3127,7 +3127,7 @@ g_dbus_connection_add_filter (GDBusConnection *connection,
CONNECTION_LOCK (connection);
data = g_new0 (FilterData, 1);
- data->id = g_atomic_int_add (&_global_filter_id, 1); /* TODO: overflow etc. */
+ data->id = (guint) g_atomic_int_add (&_global_filter_id, 1); /* TODO: overflow etc. */
data->ref_count = 1;
data->filter_function = filter_function;
data->user_data = user_data;
@@ -3482,7 +3482,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
subscriber.callback = callback;
subscriber.user_data = user_data;
subscriber.user_data_free_func = user_data_free_func;
- subscriber.id = g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
+ subscriber.id = (guint) g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
subscriber.context = g_main_context_ref_thread_default ();
/* see if we've already have this rule */
@@ -5172,7 +5172,7 @@ g_dbus_connection_register_object (GDBusConnection *connection,
}
ei = g_new0 (ExportedInterface, 1);
- ei->id = g_atomic_int_add (&_global_registration_id, 1); /* TODO: overflow etc. */
+ ei->id = (guint) g_atomic_int_add (&_global_registration_id, 1); /* TODO: overflow etc. */
ei->eo = eo;
ei->user_data = user_data;
ei->user_data_free_func = user_data_free_func;
@@ -6832,7 +6832,7 @@ g_dbus_connection_register_subtree (GDBusConnection *connection,
es->vtable = _g_dbus_subtree_vtable_copy (vtable);
es->flags = flags;
- es->id = g_atomic_int_add (&_global_subtree_registration_id, 1); /* TODO: overflow etc. */
+ es->id = (guint) g_atomic_int_add (&_global_subtree_registration_id, 1); /* TODO: overflow etc. */
es->user_data = user_data;
es->user_data_free_func = user_data_free_func;
es->context = g_main_context_ref_thread_default ();
diff --git a/gio/gdbusnamewatching.c b/gio/gdbusnamewatching.c
index dad8e75ec..01ee6e762 100644
--- a/gio/gdbusnamewatching.c
+++ b/gio/gdbusnamewatching.c
@@ -603,7 +603,7 @@ g_bus_watch_name (GBusType bus_type,
client = g_new0 (Client, 1);
client->ref_count = 1;
- client->id = g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
+ client->id = (guint) g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
client->name = g_strdup (name);
client->flags = flags;
client->name_appeared_handler = name_appeared_handler;
@@ -665,7 +665,7 @@ guint g_bus_watch_name_on_connection (GDBusConnection *connection,
client = g_new0 (Client, 1);
client->ref_count = 1;
- client->id = g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
+ client->id = (guint) g_atomic_int_add (&next_global_id, 1); /* TODO: uh oh, handle overflow */
client->name = g_strdup (name);
client->flags = flags;
client->name_appeared_handler = name_appeared_handler;
diff --git a/gio/tests/gdbus-threading.c b/gio/tests/gdbus-threading.c
index 3e4dc92e5..13ff15bab 100644
--- a/gio/tests/gdbus-threading.c
+++ b/gio/tests/gdbus-threading.c
@@ -514,7 +514,7 @@ test_threaded_singleton (void)
/* We want to be the last ref, so let it finish setting up */
for (j = 0; j < 100; j++)
{
- guint r = g_atomic_int_get (&G_OBJECT (c)->ref_count);
+ guint r = (guint) g_atomic_int_get (&G_OBJECT (c)->ref_count);
if (r == 1)
break;
diff --git a/glib/gbitlock.c b/glib/gbitlock.c
index 46e5f7d06..23024d08c 100644
--- a/glib/gbitlock.c
+++ b/glib/gbitlock.c
@@ -224,7 +224,7 @@ g_bit_lock (volatile gint *address,
guint mask = 1u << lock_bit;
guint v;
- v = g_atomic_int_get (address);
+ v = (guint) g_atomic_int_get (address);
if (v & mask)
{
guint class = ((gsize) address) % G_N_ELEMENTS (g_bit_lock_contended);
diff --git a/glib/gquark.c b/glib/gquark.c
index c4d12b870..df12ff69a 100644
--- a/glib/gquark.c
+++ b/glib/gquark.c
@@ -262,7 +262,7 @@ g_quark_to_string (GQuark quark)
gchar **strings;
gint seq_id;
- seq_id = g_atomic_int_get (&quark_seq_id);
+ seq_id = (guint) g_atomic_int_get (&quark_seq_id);
strings = g_atomic_pointer_get (&quarks);
if (quark < seq_id)
diff --git a/glib/gthread-posix.c b/glib/gthread-posix.c
index 5fff51477..aca9208cc 100644
--- a/glib/gthread-posix.c
+++ b/glib/gthread-posix.c
@@ -1396,7 +1396,7 @@ void
g_cond_wait (GCond *cond,
GMutex *mutex)
{
- guint sampled = g_atomic_int_get (&cond->i[0]);
+ guint sampled = (guint) g_atomic_int_get (&cond->i[0]);
g_mutex_unlock (mutex);
syscall (__NR_futex, &cond->i[0], (gsize) FUTEX_WAIT_PRIVATE, (gsize) sampled, NULL);
diff --git a/glib/gthreadpool.c b/glib/gthreadpool.c
index dd7289370..7d75245b0 100644
--- a/glib/gthreadpool.c
+++ b/glib/gthreadpool.c
@@ -145,7 +145,7 @@ g_thread_pool_wait_for_new_pool (void)
gint last_wakeup_thread_serial;
gboolean have_relayed_thread_marker = FALSE;
- local_max_unused_threads = g_atomic_int_get (&max_unused_threads);
+ local_max_unused_threads = (guint) g_atomic_int_get (&max_unused_threads);
local_max_idle_time = g_atomic_int_get (&max_idle_time);
last_wakeup_thread_serial = g_atomic_int_get (&wakeup_thread_serial);
@@ -209,7 +209,7 @@ g_thread_pool_wait_for_new_pool (void)
DEBUG_MSG (("thread %p updating to new limits.",
g_thread_self ()));
- local_max_unused_threads = g_atomic_int_get (&max_unused_threads);
+ local_max_unused_threads = (guint) g_atomic_int_get (&max_unused_threads);
local_max_idle_time = g_atomic_int_get (&max_idle_time);
last_wakeup_thread_serial = local_wakeup_thread_serial;
@@ -893,7 +893,7 @@ g_thread_pool_get_max_unused_threads (void)
guint
g_thread_pool_get_num_unused_threads (void)
{
- return g_atomic_int_get (&unused_threads);
+ return (guint) g_atomic_int_get (&unused_threads);
}
/**
@@ -1016,7 +1016,7 @@ g_thread_pool_set_max_idle_time (guint interval)
g_atomic_int_set (&max_idle_time, interval);
- i = g_atomic_int_get (&unused_threads);
+ i = (guint) g_atomic_int_get (&unused_threads);
if (i > 0)
{
g_atomic_int_inc (&wakeup_thread_serial);
@@ -1052,5 +1052,5 @@ g_thread_pool_set_max_idle_time (guint interval)
guint
g_thread_pool_get_max_idle_time (void)
{
- return g_atomic_int_get (&max_idle_time);
+ return (guint) g_atomic_int_get (&max_idle_time);
}
diff --git a/glib/tests/atomic.c b/glib/tests/atomic.c
index 35fa705a4..856df12d2 100644
--- a/glib/tests/atomic.c
+++ b/glib/tests/atomic.c
@@ -27,7 +27,7 @@ test_types (void)
cspp = &csp;
g_atomic_int_set (&u, 5);
- u2 = g_atomic_int_get (&u);
+ u2 = (guint) g_atomic_int_get (&u);
g_assert_cmpint (u2, ==, 5);
res = g_atomic_int_compare_and_exchange (&u, 6, 7);
g_assert (!res);
@@ -62,13 +62,13 @@ test_types (void)
res = g_atomic_int_dec_and_test (&s);
g_assert (!res);
g_assert_cmpint (s, ==, 6);
- s2 = g_atomic_int_and (&s, 5);
+ s2 = (gint) g_atomic_int_and (&s, 5);
g_assert_cmpint (s2, ==, 6);
g_assert_cmpint (s, ==, 4);
- s2 = g_atomic_int_or (&s, 8);
+ s2 = (gint) g_atomic_int_or (&s, 8);
g_assert_cmpint (s2, ==, 4);
g_assert_cmpint (s, ==, 12);
- s2 = g_atomic_int_xor (&s, 4);
+ s2 = (gint) g_atomic_int_xor (&s, 4);
g_assert_cmpint (s2, ==, 12);
g_assert_cmpint (s, ==, 8);
@@ -92,7 +92,7 @@ test_types (void)
res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0);
g_assert (res);
g_assert (gs == 0);
- gs2 = g_atomic_pointer_add (&gs, 5);
+ gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
g_assert (gs2 == 0);
g_assert (gs == 5);
gs2 = g_atomic_pointer_and (&gs, 6);
@@ -127,7 +127,7 @@ test_types (void)
#undef g_atomic_pointer_xor
g_atomic_int_set ((gint*)&u, 5);
- u2 = g_atomic_int_get ((gint*)&u);
+ u2 = (guint) g_atomic_int_get ((gint*)&u);
g_assert_cmpint (u2, ==, 5);
res = g_atomic_int_compare_and_exchange ((gint*)&u, 6, 7);
g_assert (!res);
@@ -161,13 +161,13 @@ test_types (void)
res = g_atomic_int_dec_and_test (&s);
g_assert (!res);
g_assert_cmpint (s, ==, 6);
- s2 = g_atomic_int_and ((guint*)&s, 5);
+ s2 = (gint) g_atomic_int_and ((guint*)&s, 5);
g_assert_cmpint (s2, ==, 6);
g_assert_cmpint (s, ==, 4);
- s2 = g_atomic_int_or ((guint*)&s, 8);
+ s2 = (gint) g_atomic_int_or ((guint*)&s, 8);
g_assert_cmpint (s2, ==, 4);
g_assert_cmpint (s, ==, 12);
- s2 = g_atomic_int_xor ((guint*)&s, 4);
+ s2 = (gint) g_atomic_int_xor ((guint*)&s, 4);
g_assert_cmpint (s2, ==, 12);
g_assert_cmpint (s, ==, 8);
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
@@ -196,7 +196,7 @@ G_GNUC_END_IGNORE_DEPRECATIONS
res = g_atomic_pointer_compare_and_exchange (&gs, 0, 0);
g_assert (res);
g_assert (gs == 0);
- gs2 = g_atomic_pointer_add (&gs, 5);
+ gs2 = (gsize) g_atomic_pointer_add (&gs, 5);
g_assert (gs2 == 0);
g_assert (gs == 5);
gs2 = g_atomic_pointer_and (&gs, 6);
--
2.50.0
From 5d6ced6a7fc6dbbc891992a7d16cd465f2ff1290 Mon Sep 17 00:00:00 2001
From: Philip Withnall <pwithnall@endlessos.org>
Date: Wed, 22 Feb 2023 12:19:16 +0000
Subject: [PATCH 2/2] gdbusconnection: Rearrange refcount handling of
map_method_serial_to_task
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
It already implicitly held a strong ref on its `GTask` values, but
didnt have a free function set so that they would be automatically
unreffed on removal from the map.
This meant that the functions handling removals from the map,
`on_worker_closed()` (via `cancel_method_on_close()`) and
`send_message_with_reply_cleanup()` had to call unref once more than
they would otherwise.
In `send_message_with_reply_cleanup()`, this behaviour depended on
whether it was called with `remove == TRUE`. If not, it was `(transfer
none)` not `(transfer full)`. This led to bugs in its callers.
For example, this led to a direct leak in `cancel_method_on_close()`, as
it needed to remove tasks from `map_method_serial_to_task`, but called
`send_message_with_reply_cleanup(remove = FALSE)` and erroneously didnt
call unref an additional time.
Try and simplify it all by setting a `GDestroyNotify` on
`map_method_serial_to_task`s values, and making the refcount handling
of `send_message_with_reply_cleanup()` not be conditional on its
arguments.
Signed-off-by: Philip Withnall <pwithnall@endlessos.org>
Helps: #1264
---
gio/gdbusconnection.c | 18 ++++++++++--------
1 file changed, 10 insertions(+), 8 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 1c1f0cf3d..63f37ca4b 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -433,7 +433,7 @@ struct _GDBusConnection
GDBusConnectionFlags flags;
/* Map used for managing method replies, protected by @lock */
- GHashTable *map_method_serial_to_task; /* guint32 -> GTask* */
+ GHashTable *map_method_serial_to_task; /* guint32 -> owned GTask* */
/* Maps used for managing signal subscription, protected by @lock */
GHashTable *map_rule_to_signal_data; /* match rule (gchar*) -> SignalData */
@@ -1067,7 +1067,7 @@ g_dbus_connection_init (GDBusConnection *connection)
g_mutex_init (&connection->lock);
g_mutex_init (&connection->init_lock);
- connection->map_method_serial_to_task = g_hash_table_new (g_direct_hash, g_direct_equal);
+ connection->map_method_serial_to_task = g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_object_unref);
connection->map_rule_to_signal_data = g_hash_table_new (g_str_hash,
g_str_equal);
@@ -1759,7 +1759,7 @@ send_message_data_free (SendMessageData *data)
/* ---------------------------------------------------------------------------------------------------- */
-/* can be called from any thread with lock held; @task is (transfer full) */
+/* can be called from any thread with lock held; @task is (transfer none) */
static void
send_message_with_reply_cleanup (GTask *task, gboolean remove)
{
@@ -1789,13 +1789,11 @@ send_message_with_reply_cleanup (GTask *task, gboolean remove)
GUINT_TO_POINTER (data->serial));
g_warn_if_fail (removed);
}
-
- g_object_unref (task);
}
/* ---------------------------------------------------------------------------------------------------- */
-/* Called from GDBus worker thread with lock held; @task is (transfer full). */
+/* Called from GDBus worker thread with lock held; @task is (transfer none). */
static void
send_message_data_deliver_reply_unlocked (GTask *task,
GDBusMessage *reply)
@@ -1813,7 +1811,7 @@ send_message_data_deliver_reply_unlocked (GTask *task,
;
}
-/* Called from a user thread, lock is not held */
+/* Called from a user thread, lock is not held; @task is (transfer none) */
static void
send_message_data_deliver_error (GTask *task,
GQuark domain,
@@ -1830,7 +1828,10 @@ send_message_data_deliver_error (GTask *task,
return;
}
+ /* Hold a ref on @task as send_message_with_reply_cleanup() will remove it
+ * from the task map and could end up dropping the last reference */
g_object_ref (task);
+
send_message_with_reply_cleanup (task, TRUE);
CONNECTION_UNLOCK (connection);
@@ -2363,7 +2364,8 @@ on_worker_message_about_to_be_sent (GDBusWorker *worker,
return message;
}
-/* called with connection lock held, in GDBusWorker thread */
+/* called with connection lock held, in GDBusWorker thread
+ * @key, @value and @user_data are (transfer none) */
static gboolean
cancel_method_on_close (gpointer key, gpointer value, gpointer user_data)
{
--
2.50.0

View File

@ -0,0 +1,780 @@
From c53784092c2d69c4a1d916bb22235ffb8f0b5bad Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 17 Jan 2020 16:11:06 +0000
Subject: [PATCH 1/5] gdbusconnection: Allocate SignalSubscriber structs
individually
The `SignalSubscriber` structs contain the callback and `user_data` of each
subscriber to a signal, along with the `guint id` token held by that
subscriber to identify their subscription. There are one or more
`SignalSubscriber` structs for a given signal match rule, which is
represented as a `SignalData` struct.
Previously, the `SignalSubscriber` structs were stored in a `GArray` in
the `SignalData` struct, to reduce the number of allocations needed
when subscribing to a signal.
However, this means that a `SignalSubscriber` struct cannot have a
lifetime which exceeds the `SignalData` which contains it. In order to
fix the race in #978, one thread needs to be able to unsubscribe from a
signal (destroying the `SignalData` struct) while zero or more other
threads are in the process of calling the callbacks from a previous
emission of that signal (using the callback and `user_data` from zero or
more `SignalSubscriber` structs). Multiple threads could be calling
callbacks because callbacks are invoked in the `GMainContext` which
originally made a subscription, and GDBus supports subscribing to a
signal from multiple threads. In that case, the callbacks are dispatched
to multiple threads.
In order to allow the `SignalSubscriber` structs to outlive the
`SignalData` which contained their old match rule, store them in a
`GPtrArray` in the `SignalData` struct, and refcount them individually.
This commit in itself should make no functional changes to how GDBus
works, but will allow following commits to do so.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
---
gio/gdbusconnection.c | 105 +++++++++++++++++++++++++-----------------
1 file changed, 63 insertions(+), 42 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 63f37ca4b..170057682 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -3229,18 +3229,9 @@ typedef struct
gchar *object_path;
gchar *arg0;
GDBusSignalFlags flags;
- GArray *subscribers;
+ GPtrArray *subscribers; /* (owned) (element-type SignalSubscriber) */
} SignalData;
-typedef struct
-{
- GDBusSignalCallback callback;
- gpointer user_data;
- GDestroyNotify user_data_free_func;
- guint id;
- GMainContext *context;
-} SignalSubscriber;
-
static void
signal_data_free (SignalData *signal_data)
{
@@ -3251,10 +3242,37 @@ signal_data_free (SignalData *signal_data)
g_free (signal_data->member);
g_free (signal_data->object_path);
g_free (signal_data->arg0);
- g_array_free (signal_data->subscribers, TRUE);
+ g_ptr_array_unref (signal_data->subscribers);
g_free (signal_data);
}
+typedef struct
+{
+ gatomicrefcount ref_count;
+ GDBusSignalCallback callback;
+ gpointer user_data;
+ GDestroyNotify user_data_free_func;
+ guint id;
+ GMainContext *context;
+} SignalSubscriber;
+
+static SignalSubscriber *
+signal_subscriber_ref (SignalSubscriber *subscriber)
+{
+ g_atomic_ref_count_inc (&subscriber->ref_count);
+ return subscriber;
+}
+
+static void
+signal_subscriber_unref (SignalSubscriber *subscriber)
+{
+ if (g_atomic_ref_count_dec (&subscriber->ref_count))
+ {
+ g_main_context_unref (subscriber->context);
+ g_free (subscriber);
+ }
+}
+
static gchar *
args_to_rule (const gchar *sender,
const gchar *interface_name,
@@ -3440,7 +3458,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
{
gchar *rule;
SignalData *signal_data;
- SignalSubscriber subscriber;
+ SignalSubscriber *subscriber;
GPtrArray *signal_data_array;
const gchar *sender_unique_name;
@@ -3481,17 +3499,19 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
else
sender_unique_name = "";
- subscriber.callback = callback;
- subscriber.user_data = user_data;
- subscriber.user_data_free_func = user_data_free_func;
- subscriber.id = (guint) g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
- subscriber.context = g_main_context_ref_thread_default ();
+ subscriber = g_new0 (SignalSubscriber, 1);
+ subscriber->ref_count = 1;
+ subscriber->callback = callback;
+ subscriber->user_data = user_data;
+ subscriber->user_data_free_func = user_data_free_func;
+ subscriber->id = (guint) g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
+ subscriber->context = g_main_context_ref_thread_default ();
/* see if we've already have this rule */
signal_data = g_hash_table_lookup (connection->map_rule_to_signal_data, rule);
if (signal_data != NULL)
{
- g_array_append_val (signal_data->subscribers, subscriber);
+ g_ptr_array_add (signal_data->subscribers, subscriber);
g_free (rule);
goto out;
}
@@ -3505,8 +3525,8 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
signal_data->object_path = g_strdup (object_path);
signal_data->arg0 = g_strdup (arg0);
signal_data->flags = flags;
- signal_data->subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
- g_array_append_val (signal_data->subscribers, subscriber);
+ signal_data->subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
+ g_ptr_array_add (signal_data->subscribers, subscriber);
g_hash_table_insert (connection->map_rule_to_signal_data,
signal_data->rule,
@@ -3536,12 +3556,12 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
out:
g_hash_table_insert (connection->map_id_to_signal_data,
- GUINT_TO_POINTER (subscriber.id),
+ GUINT_TO_POINTER (subscriber->id),
signal_data);
CONNECTION_UNLOCK (connection);
- return subscriber.id;
+ return subscriber->id;
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -3551,7 +3571,7 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
static void
unsubscribe_id_internal (GDBusConnection *connection,
guint subscription_id,
- GArray *out_removed_subscribers)
+ GPtrArray *out_removed_subscribers)
{
SignalData *signal_data;
GPtrArray *signal_data_array;
@@ -3567,16 +3587,19 @@ unsubscribe_id_internal (GDBusConnection *connection,
for (n = 0; n < signal_data->subscribers->len; n++)
{
- SignalSubscriber *subscriber;
+ SignalSubscriber *subscriber = signal_data->subscribers->pdata[n];
- subscriber = &(g_array_index (signal_data->subscribers, SignalSubscriber, n));
if (subscriber->id != subscription_id)
continue;
+ /* Its OK to rearrange the array order using the fast #GPtrArray
+ * removal functions, since were going to exit the loop below anyway — we
+ * never move on to the next element. Secondly, subscription IDs are
+ * guaranteed to be unique. */
g_warn_if_fail (g_hash_table_remove (connection->map_id_to_signal_data,
GUINT_TO_POINTER (subscription_id)));
- g_array_append_val (out_removed_subscribers, *subscriber);
- g_array_remove_index (signal_data->subscribers, n);
+ g_ptr_array_add (out_removed_subscribers, signal_subscriber_ref (subscriber));
+ g_ptr_array_remove_index_fast (signal_data->subscribers, n);
if (signal_data->subscribers->len == 0)
{
@@ -3634,13 +3657,13 @@ void
g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
guint subscription_id)
{
- GArray *subscribers;
+ GPtrArray *subscribers;
guint n;
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (check_initialized (connection));
- subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+ subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
CONNECTION_LOCK (connection);
unsubscribe_id_internal (connection,
@@ -3654,15 +3677,15 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
/* call GDestroyNotify without lock held */
for (n = 0; n < subscribers->len; n++)
{
- SignalSubscriber *subscriber;
- subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
+ SignalSubscriber *subscriber = subscribers->pdata[n];
call_destroy_notify (subscriber->context,
subscriber->user_data_free_func,
subscriber->user_data);
- g_main_context_unref (subscriber->context);
+ subscriber->user_data_free_func = NULL;
+ subscriber->user_data = NULL;
}
- g_array_free (subscribers, TRUE);
+ g_ptr_array_unref (subscribers);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -3852,12 +3875,10 @@ schedule_callbacks (GDBusConnection *connection,
for (m = 0; m < signal_data->subscribers->len; m++)
{
- SignalSubscriber *subscriber;
+ SignalSubscriber *subscriber = signal_data->subscribers->pdata[m];
GSource *idle_source;
SignalInstance *signal_instance;
- subscriber = &(g_array_index (signal_data->subscribers, SignalSubscriber, m));
-
signal_instance = g_new0 (SignalInstance, 1);
signal_instance->subscription_id = subscriber->id;
signal_instance->callback = subscriber->callback;
@@ -3930,7 +3951,7 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
GHashTableIter iter;
gpointer key;
GArray *ids;
- GArray *subscribers;
+ GPtrArray *subscribers;
guint n;
ids = g_array_new (FALSE, FALSE, sizeof (guint));
@@ -3941,7 +3962,7 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
g_array_append_val (ids, subscription_id);
}
- subscribers = g_array_new (FALSE, FALSE, sizeof (SignalSubscriber));
+ subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
for (n = 0; n < ids->len; n++)
{
guint subscription_id = g_array_index (ids, guint, n);
@@ -3954,15 +3975,15 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
/* call GDestroyNotify without lock held */
for (n = 0; n < subscribers->len; n++)
{
- SignalSubscriber *subscriber;
- subscriber = &(g_array_index (subscribers, SignalSubscriber, n));
+ SignalSubscriber *subscriber = subscribers->pdata[n];
call_destroy_notify (subscriber->context,
subscriber->user_data_free_func,
subscriber->user_data);
- g_main_context_unref (subscriber->context);
+ subscriber->user_data_free_func = NULL;
+ subscriber->user_data = NULL;
}
- g_array_free (subscribers, TRUE);
+ g_ptr_array_unref (subscribers);
}
/* ---------------------------------------------------------------------------------------------------- */
--
2.50.0
From d21d9fb02496f21864e4175d08b5f55416e832e6 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 17 Jan 2020 19:52:46 +0000
Subject: [PATCH 2/5] gdbusconnection: Tidy up destroy notification for signal
subscriptions
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Tie the destruction of the `user_data` to the destruction of the
`SignalSubscriber` struct. This is tidier, and ensures that the fields
in `SignalSubscriber` are all immutable after being set, so the
structure can safely be used across threads without locking.
It doesnt matter which thread we call `call_destroy_notify()` in, since
it always defers calling `user_data_free_func` to the user-provided
`GMainContext`.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
---
gio/gdbusconnection.c | 32 +++++++++-----------------------
1 file changed, 9 insertions(+), 23 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 170057682..2dba09fcc 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -3248,6 +3248,7 @@ signal_data_free (SignalData *signal_data)
typedef struct
{
+ /* All fields are immutable after construction. */
gatomicrefcount ref_count;
GDBusSignalCallback callback;
gpointer user_data;
@@ -3268,6 +3269,14 @@ signal_subscriber_unref (SignalSubscriber *subscriber)
{
if (g_atomic_ref_count_dec (&subscriber->ref_count))
{
+ /* Destroy the user data. It doesnt matter which thread
+ * signal_subscriber_unref() is called in (or whether its called with a
+ * lock held), as call_destroy_notify() always defers to the next
+ * #GMainContext iteration. */
+ call_destroy_notify (subscriber->context,
+ subscriber->user_data_free_func,
+ subscriber->user_data);
+
g_main_context_unref (subscriber->context);
g_free (subscriber);
}
@@ -3658,7 +3667,6 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
guint subscription_id)
{
GPtrArray *subscribers;
- guint n;
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (check_initialized (connection));
@@ -3674,17 +3682,6 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
/* invariant */
g_assert (subscribers->len == 0 || subscribers->len == 1);
- /* call GDestroyNotify without lock held */
- for (n = 0; n < subscribers->len; n++)
- {
- SignalSubscriber *subscriber = subscribers->pdata[n];
- call_destroy_notify (subscriber->context,
- subscriber->user_data_free_func,
- subscriber->user_data);
- subscriber->user_data_free_func = NULL;
- subscriber->user_data = NULL;
- }
-
g_ptr_array_unref (subscribers);
}
@@ -3972,17 +3969,6 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
}
g_array_free (ids, TRUE);
- /* call GDestroyNotify without lock held */
- for (n = 0; n < subscribers->len; n++)
- {
- SignalSubscriber *subscriber = subscribers->pdata[n];
- call_destroy_notify (subscriber->context,
- subscriber->user_data_free_func,
- subscriber->user_data);
- subscriber->user_data_free_func = NULL;
- subscriber->user_data = NULL;
- }
-
g_ptr_array_unref (subscribers);
}
--
2.50.0
From 5b7c9398a67ad274cb8faef8bf45461540a7198e Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 17 Jan 2020 19:38:55 +0000
Subject: [PATCH 3/5] gdbusconnection: Fix race when emitting D-Bus signal
callbacks
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
Instead of storing a copy of the `callback` and `user_data` from a
`SignalSubscriber` in a `SignalInstance` struct (which is the closure
for signal callback data as its sent from the D-Bus worker thread to
the thread which originally subscribed to a signal), store a strong
reference to the `SignalSubscriber` struct itself.
This keeps the `SignalSubscriber` alive until the emission is
complete, which ensures that the `user_data` is not freed prematurely.
It also slightly reduces the allocation size of `SignalInstance` (not
that it matters).
This is threadsafe because the fields in `SignalSubscriber` are all
immutable after construction.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
---
gio/gdbusconnection.c | 27 ++++++++++++---------------
1 file changed, 12 insertions(+), 15 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 2dba09fcc..4cae53b29 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -3689,9 +3689,7 @@ g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
typedef struct
{
- guint subscription_id;
- GDBusSignalCallback callback;
- gpointer user_data;
+ SignalSubscriber *subscriber; /* (owned) */
GDBusMessage *message;
GDBusConnection *connection;
const gchar *sender;
@@ -3723,7 +3721,7 @@ emit_signal_instance_in_idle_cb (gpointer data)
#if 0
g_print ("in emit_signal_instance_in_idle_cb (id=%d sender=%s path=%s interface=%s member=%s params=%s)\n",
- signal_instance->subscription_id,
+ signal_instance->subscriber->id,
signal_instance->sender,
signal_instance->path,
signal_instance->interface,
@@ -3735,18 +3733,18 @@ emit_signal_instance_in_idle_cb (gpointer data)
CONNECTION_LOCK (signal_instance->connection);
has_subscription = FALSE;
if (g_hash_table_lookup (signal_instance->connection->map_id_to_signal_data,
- GUINT_TO_POINTER (signal_instance->subscription_id)) != NULL)
+ GUINT_TO_POINTER (signal_instance->subscriber->id)) != NULL)
has_subscription = TRUE;
CONNECTION_UNLOCK (signal_instance->connection);
if (has_subscription)
- signal_instance->callback (signal_instance->connection,
- signal_instance->sender,
- signal_instance->path,
- signal_instance->interface,
- signal_instance->member,
- parameters,
- signal_instance->user_data);
+ signal_instance->subscriber->callback (signal_instance->connection,
+ signal_instance->sender,
+ signal_instance->path,
+ signal_instance->interface,
+ signal_instance->member,
+ parameters,
+ signal_instance->subscriber->user_data);
g_variant_unref (parameters);
@@ -3758,6 +3756,7 @@ signal_instance_free (SignalInstance *signal_instance)
{
g_object_unref (signal_instance->message);
g_object_unref (signal_instance->connection);
+ signal_subscriber_unref (signal_instance->subscriber);
g_free (signal_instance);
}
@@ -3877,9 +3876,7 @@ schedule_callbacks (GDBusConnection *connection,
SignalInstance *signal_instance;
signal_instance = g_new0 (SignalInstance, 1);
- signal_instance->subscription_id = subscriber->id;
- signal_instance->callback = subscriber->callback;
- signal_instance->user_data = subscriber->user_data;
+ signal_instance->subscriber = signal_subscriber_ref (subscriber);
signal_instance->message = g_object_ref (message);
signal_instance->connection = g_object_ref (connection);
signal_instance->sender = sender;
--
2.50.0
From a13bbdc1dc0cd4ec16c3e75d0cc1c07eb791b3bc Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 17 Jan 2020 19:56:58 +0000
Subject: [PATCH 4/5] gdbusconnection: Tidy up unsubscription code
This just removes a now-redundant intermediate array. This means that
the `SignalSubscriber` instances are now potentially freed a little
sooner, inside the locked segment, but they are already careful to only
call their `user_data_free_func` in the right thread. So that should not
deadlock.
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Helps: #978
---
gio/gdbusconnection.c | 33 +++++++++++----------------------
1 file changed, 11 insertions(+), 22 deletions(-)
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index 4cae53b29..4d99f8570 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -3576,15 +3576,16 @@ g_dbus_connection_signal_subscribe (GDBusConnection *connection,
/* ---------------------------------------------------------------------------------------------------- */
/* called in any thread */
-/* must hold lock when calling this (except if connection->finalizing is TRUE) */
-static void
+/* must hold lock when calling this (except if connection->finalizing is TRUE)
+ * returns the number of removed subscribers */
+static guint
unsubscribe_id_internal (GDBusConnection *connection,
- guint subscription_id,
- GPtrArray *out_removed_subscribers)
+ guint subscription_id)
{
SignalData *signal_data;
GPtrArray *signal_data_array;
guint n;
+ guint n_removed = 0;
signal_data = g_hash_table_lookup (connection->map_id_to_signal_data,
GUINT_TO_POINTER (subscription_id));
@@ -3607,7 +3608,7 @@ unsubscribe_id_internal (GDBusConnection *connection,
* guaranteed to be unique. */
g_warn_if_fail (g_hash_table_remove (connection->map_id_to_signal_data,
GUINT_TO_POINTER (subscription_id)));
- g_ptr_array_add (out_removed_subscribers, signal_subscriber_ref (subscriber));
+ n_removed++;
g_ptr_array_remove_index_fast (signal_data->subscribers, n);
if (signal_data->subscribers->len == 0)
@@ -3649,7 +3650,7 @@ unsubscribe_id_internal (GDBusConnection *connection,
g_assert_not_reached ();
out:
- ;
+ return n_removed;
}
/**
@@ -3666,23 +3667,17 @@ void
g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
guint subscription_id)
{
- GPtrArray *subscribers;
+ guint n_subscribers_removed G_GNUC_UNUSED /* when compiling with G_DISABLE_ASSERT */;
g_return_if_fail (G_IS_DBUS_CONNECTION (connection));
g_return_if_fail (check_initialized (connection));
- subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
-
CONNECTION_LOCK (connection);
- unsubscribe_id_internal (connection,
- subscription_id,
- subscribers);
+ n_subscribers_removed = unsubscribe_id_internal (connection, subscription_id);
CONNECTION_UNLOCK (connection);
/* invariant */
- g_assert (subscribers->len == 0 || subscribers->len == 1);
-
- g_ptr_array_unref (subscribers);
+ g_assert (n_subscribers_removed == 0 || n_subscribers_removed == 1);
}
/* ---------------------------------------------------------------------------------------------------- */
@@ -3945,7 +3940,6 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
GHashTableIter iter;
gpointer key;
GArray *ids;
- GPtrArray *subscribers;
guint n;
ids = g_array_new (FALSE, FALSE, sizeof (guint));
@@ -3956,17 +3950,12 @@ purge_all_signal_subscriptions (GDBusConnection *connection)
g_array_append_val (ids, subscription_id);
}
- subscribers = g_ptr_array_new_with_free_func ((GDestroyNotify) signal_subscriber_unref);
for (n = 0; n < ids->len; n++)
{
guint subscription_id = g_array_index (ids, guint, n);
- unsubscribe_id_internal (connection,
- subscription_id,
- subscribers);
+ unsubscribe_id_internal (connection, subscription_id);
}
g_array_free (ids, TRUE);
-
- g_ptr_array_unref (subscribers);
}
/* ---------------------------------------------------------------------------------------------------- */
--
2.50.0
From 0ec439aab1da5df011bed6a1a317439efacb6c25 Mon Sep 17 00:00:00 2001
From: Philip Withnall <withnall@endlessm.com>
Date: Fri, 17 Jan 2020 20:00:22 +0000
Subject: [PATCH 5/5] gdbusnameowning: Fix race between connection shutdown and
NameLost
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
As with all D-Bus signal subscriptions, its possible for a signal
callback to be invoked in one thread (T1) while another thread (T2) is
unsubscribing from that signal. In this case, T1 is the main thread, and
T2 is the D-Bus connection worker thread which is unsubscribing all
signals as its in the process of closing.
Due to this possibility, all `user_data` for signal callbacks needs to
be referenced outside the lifecycle of the code which
subscribes/unsubscribes the signal. In other words, its not safe to
subscribe to a signal, store the subscription ID in a struct,
unsubscribe from the signal when freeing the struct, and dereference the
struct in the signal callback. The data passed to the signal callback
has to have its own strong reference.
Instead, its safe to subscribe to a signal and add a strong reference
to the struct, store the subscription ID in that struct, and unsubscribe
from the signal when the last external reference to your struct is
dropped. That unsubscription should break the refcount cycle between the
signal connection and the struct, and allow the struct to be completely
freed. Only with that approach is it safe to dereference the struct in
the signal callback, if theres any possibility that the signal might be
unsubscribed from a separate thread.
The tests need specific additional main loop cycles to completely emit
the NameLost signal callback. Ideally they need refactoring, but this
will do (1000 test cycles passed).
Signed-off-by: Philip Withnall <withnall@endlessm.com>
Fixes: #978
---
gio/gdbusnameowning.c | 15 ++++++++++-----
gio/tests/gdbus-names.c | 11 ++++++++++-
2 files changed, 20 insertions(+), 6 deletions(-)
diff --git a/gio/gdbusnameowning.c b/gio/gdbusnameowning.c
index 2c2714db2..00554c16a 100644
--- a/gio/gdbusnameowning.c
+++ b/gio/gdbusnameowning.c
@@ -366,7 +366,12 @@ request_name_cb (GObject *source_object,
connection = g_object_ref (client->connection);
G_UNLOCK (lock);
- /* start listening to NameLost and NameAcquired messages */
+ /* Start listening to NameLost and NameAcquired messages. We hold
+ * references to the Client in the signal closures, since its possible
+ * for a signal to be in-flight after unsubscribing the signal handler.
+ * This creates a reference count cycle, but thats explicitly broken by
+ * disconnecting the signal handlers before calling client_unref() in
+ * g_bus_unown_name(). */
if (connection != NULL)
{
client->name_lost_subscription_id =
@@ -378,8 +383,8 @@ request_name_cb (GObject *source_object,
client->name,
G_DBUS_SIGNAL_FLAGS_NONE,
on_name_lost_or_acquired,
- client,
- NULL);
+ client_ref (client),
+ (GDestroyNotify) client_unref);
client->name_acquired_subscription_id =
g_dbus_connection_signal_subscribe (connection,
"org.freedesktop.DBus",
@@ -389,8 +394,8 @@ request_name_cb (GObject *source_object,
client->name,
G_DBUS_SIGNAL_FLAGS_NONE,
on_name_lost_or_acquired,
- client,
- NULL);
+ client_ref (client),
+ (GDestroyNotify) client_unref);
g_object_unref (connection);
}
}
diff --git a/gio/tests/gdbus-names.c b/gio/tests/gdbus-names.c
index 648b54774..b42ba2141 100644
--- a/gio/tests/gdbus-names.c
+++ b/gio/tests/gdbus-names.c
@@ -189,6 +189,7 @@ test_bus_own_name (void)
* Stop owning the name - this should invoke our free func
*/
g_bus_unown_name (id);
+ g_main_loop_run (loop);
g_assert_cmpint (data.num_free_func, ==, 2);
/*
@@ -330,6 +331,7 @@ test_bus_own_name (void)
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
g_bus_unown_name (id2);
+ g_main_loop_run (loop);
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
@@ -355,6 +357,7 @@ test_bus_own_name (void)
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
g_bus_unown_name (id2);
+ g_main_loop_run (loop);
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
@@ -365,6 +368,7 @@ test_bus_own_name (void)
*/
data.expect_null_connection = FALSE;
g_bus_unown_name (id);
+ g_main_loop_run (loop);
g_assert_cmpint (data.num_bus_acquired, ==, 1);
g_assert_cmpint (data.num_acquired, ==, 1);
g_assert_cmpint (data.num_free_func, ==, 4);
@@ -418,6 +422,7 @@ test_bus_own_name (void)
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
g_bus_unown_name (id2);
+ g_main_loop_run (loop);
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
g_assert_cmpint (data2.num_acquired, ==, 0);
g_assert_cmpint (data2.num_lost, ==, 1);
@@ -450,8 +455,9 @@ test_bus_own_name (void)
g_assert_cmpint (data2.num_bus_acquired, ==, 0);
/* ok, make owner2 release the name - then wait for owner to automagically reacquire it */
g_bus_unown_name (id2);
- g_assert_cmpint (data2.num_free_func, ==, 1);
g_main_loop_run (loop);
+ g_main_loop_run (loop);
+ g_assert_cmpint (data2.num_free_func, ==, 1);
g_assert_cmpint (data.num_acquired, ==, 2);
g_assert_cmpint (data.num_lost, ==, 1);
@@ -466,6 +472,7 @@ test_bus_own_name (void)
g_assert_cmpint (data.num_acquired, ==, 2);
g_assert_cmpint (data.num_lost, ==, 2);
g_bus_unown_name (id);
+ g_main_loop_run (loop);
g_assert_cmpint (data.num_free_func, ==, 5);
g_object_unref (c);
@@ -648,6 +655,7 @@ test_bus_watch_name (void)
/* unown the name */
g_bus_unown_name (owner_id);
+ g_main_loop_run (loop);
g_assert_cmpint (data.num_acquired, ==, 1);
g_assert_cmpint (data.num_free_func, ==, 2);
@@ -707,6 +715,7 @@ test_bus_watch_name (void)
g_assert_cmpint (data.num_free_func, ==, 1);
g_bus_unown_name (owner_id);
+ g_main_loop_run (loop);
g_assert_cmpint (data.num_free_func, ==, 2);
session_bus_down ();
--
2.50.0

View File

@ -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

View File

@ -5,7 +5,7 @@
Name: glib2
Version: 2.56.4
Release: 157%{?dist}
Release: 166%{?dist}
Summary: A library of handy utility functions
License: LGPLv2+
@ -106,6 +106,47 @@ 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
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4155
Patch24: 4155.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4281
Patch25: CVE-2024-52533.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4588
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4592
Patch26: CVE-2025-4373.patch
# Contains commits from:
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1121
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3291
Patch27: gdbus-conflict-reduction.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/1332
Patch28: gdbus-signal-race.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4038
Patch29: CVE-2024-34397.patch
# https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4356
Patch30: gdatetime-test.patch
%description
GLib is the low-level core library that forms the basis for projects
such as GTK+ and GNOME. It provides data structure handling for C,
@ -303,6 +344,46 @@ glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
%{_datadir}/installed-tests
%changelog
* Fri Jul 11 2025 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-166
- Add patches for CVE-2024-34397, CVE-2024-52533, CVE-2025-4373
- Update GDateTime test for new tzdata
- Resolves: RHEL-67084
- Resolves: RHEL-94286
- Resolves: RHEL-94848
* Thu Sep 26 2024 Ondrej Holy <oholy@redhat.com> - 2.56.4-165
- Add support for x-gvfs-trash mount option
- Resolves: RHEL-46828
* Tue Feb 13 2024 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-164
- Revert GUnixMountMonitor changes (it depends on functionality not in RHEL 8)
- Resolves: RHEL-23636
* Thu Feb 01 2024 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-163
- Backport GUnixMountMonitor port to libmnt_monitor
- Make GUnixMountMonitor thread-safe
- Resolves: RHEL-23636
* Thu Sep 21 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-162
- Add support to ignore trash for certain mounts
- Resolves: RHEL-2836
* Tue Jan 03 2023 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-161
- Backport grefcount API
- Resolves: #2153205
* 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 Apr 22 2022 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-159
- Add --interface-info-[body|header] modes to gdbus-codegen
- Related: #2061994
* Wed Dec 01 2021 Michael Catanzaro <mcatanzaro@redhat.com> - 2.56.4-158
- Fix GNetworkMonitor after NetworkManager D-Bus API changes
- Resolves: #2014652
* 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