Russian
Turkish
+Overview of changes in GLib 2.44.1
+==================================
+
+* Don't redefine typedefs to avoid build problems on OpenBSD
+
+* Improve the default application algorithm
+
+* Bump the number of children a GType can have
+
+* Various testsuite improvements
+
+* Translation updates:
+ Czech
+ Icelandic
+ Russian
+
+
+Overview of changes in GLib 2.44.0
+===================================
+
+With the exception of translation and documentation, there have been no
+changes since the prerelease.
+
+Bugs fixed:
+ 730188 gsocket: Document FD ownership with g_socket_new_from_fd()
+
+Translations updated:
+ Basque language
+ Brazilian Portuguese
+ Chinese (Taiwan)
+ Danish
+ Galician s
+ Hebrew
+ Indonesian
+ Norwegian bokmål
+ Turkish
+
Overview of changes in GLib 2.43.92
===================================
# regenerated from their corresponding *.in files by ./configure anyway.
touch README INSTALL
-autoreconf --force --install --verbose || exit $?
+test -n "$NOAUTORECONF" || autoreconf --force --install --verbose || exit $?
cd "$olddir"
test -n "$NOCONFIGURE" || "$srcdir/configure" "$@"
[AS_HELP_STRING([--disable-rebuilds],
[disable all source autogeneration rules])],,
[enable_rebuilds=yes])
+AC_ARG_ENABLE(libdbuspolicy,
+ [AS_HELP_STRING([--enable-libdbuspolicy],
+ [enable libdbuspolicy for kdbus transport [default=no]])],,
+ [enable_libdbuspolicy=no])
GLIB_TESTS
AC_MSG_RESULT([yes])
])
+AC_MSG_CHECKING([whether to enable libdbuspolicy for kdbus transport])
+AM_CONDITIONAL(LIBDBUSPOLICY, [test "x$enable_libdbuspolicy" = "xyes"])
+AS_IF([test "x$enable_libdbuspolicy" = "xyes"], [
+ PKG_CHECK_MODULES(LIBDBUSPOLICY1, libdbuspolicy1 >= 1)
+ AC_SUBST(LIBDBUSPOLICY1_CFLAGS)
+ AC_SUBST(LIBDBUSPOLICY1_LIBS)
+ AC_DEFINE(LIBDBUSPOLICY, 1, [Whether to enable libdbuspolicy for kdbus transport])
+ AC_MSG_RESULT([yes])
+], [ AC_MSG_RESULT([no]) ])
+
dnl location to install runtime libraries, e.g. ../../lib to install
dnl to /lib if libdir is /usr/lib
AC_ARG_WITH(runtime-libdir,
AC_CHECK_HEADERS([sys/select.h stdint.h inttypes.h sched.h malloc.h])
AC_CHECK_HEADERS([sys/vfs.h sys/vmount.h sys/statfs.h sys/statvfs.h sys/filio.h])
AC_CHECK_HEADERS([mntent.h sys/mnttab.h sys/vfstab.h sys/mntctl.h fstab.h])
-AC_CHECK_HEADERS([linux/magic.h])
+AC_CHECK_HEADERS([linux/magic.h linux/memfd.h sys/prctl.h])
AC_CHECK_HEADERS([termios.h])
# Some versions of MSC lack these
LDFLAGS="$LDFLAGS -lgcov"
])
+dnl ************************************
+dnl *** Enable gcov (without lcov) coverage reports ***
+dnl ************************************
+
+AC_ARG_ENABLE(gcov-coverage,
+ AS_HELP_STRING([--enable-gcov-coverage],
+ [enable coverage testing with gcov, without lcov]),
+ [use_only_gcov=$enableval], [use_only_gcov=no])
+
+AS_IF([ test "x$use_only_gcov" = "xyes"], [
+ dnl we need gcc:
+ if test "$GCC" != "yes"; then
+ AC_MSG_ERROR([GCC is required for --enable-gcov-coverage])
+ fi
+
+ dnl Check if ccache is being used
+ AC_CHECK_PROG(SHTOOL, shtool, shtool)
+ case `$SHTOOL path $CC` in
+ *ccache*[)] gcc_ccache=yes;;
+ *[)] gcc_ccache=no;;
+ esac
+
+ if test "$gcc_ccache" = "yes" && (test -z "$CCACHE_DISABLE" || test "$CCACHE_DISABLE" != "1"); then
+ AC_MSG_ERROR([ccache must be disabled when --enable-coverage option is used. You can disable ccache by setting environment variable CCACHE_DISABLE=1.])
+ fi
+
+ dnl Remove all optimization flags from CFLAGS
+ changequote({,})
+ CFLAGS=`echo "$CFLAGS" | $SED -e 's/-Wl,-O[0-9]*//g'`
+ CFLAGS=`echo "$CFLAGS" | $SED -e 's/-O[0-9]*//g'`
+ changequote([,])
+
+ dnl Add the special gcc flags
+ CFLAGS="$CFLAGS -O0 -fprofile-arcs -ftest-coverage"
+ LDFLAGS="$LDFLAGS -lgcov"
+])
+
dnl ******************************
dnl *** output the whole stuff ***
dnl ******************************
AM_CONDITIONAL(HAVE_DBUS1, [test "x$have_dbus1" = "xyes"])
AC_CHECK_PROGS([DBUS_DAEMON], [dbus-daemon])
-AM_CONDITIONAL([HAVE_DBUS_DAEMON], [test x$DBUS_DAEMON = xdbus-daemon ])
+AM_CONDITIONAL([HAVE_DBUS_DAEMON], [test x$DBUS_DAEMON = xdbus-daemon || test x$FORCE_DBUS_TESTS = x1 ])
# Check whether MSVC toolset is explicitly set
AM_CONDITIONAL(MSVC_BASE_NO_TOOLSET_SET, [test x$MSVC_BASE_TOOLSET = x])
<SUBSECTION>
g_return_if_fail
g_return_val_if_fail
+g_return_if_fail_se
+g_return_val_if_fail_se
g_return_if_reached
g_return_val_if_reached
g_warn_if_fail
g_unix_fd_add
g_unix_fd_add_full
g_unix_fd_source_new
+g_unix_fd_ensure_zero_copy_safe
<SUBSECTION Private>
g_unix_error_quark
GBytes
g_bytes_new
g_bytes_new_take
+g_bytes_new_take_zero_copy_fd
g_bytes_new_static
g_bytes_new_with_free_func
g_bytes_new_from_bytes
g_bytes_get_data
g_bytes_get_size
+g_bytes_get_zero_copy_fd
g_bytes_hash
g_bytes_equal
g_bytes_compare
g_test_rand_double_range
g_assert
+g_assert_se
g_assert_not_reached
g_assert_cmpstr
<literal>handle</literal>,
<literal>int64</literal>,
<literal>uint64</literal>,
+ <literal>float</literal>,
<literal>double</literal>,
<literal>string</literal>,
<literal>objectpath</literal>,
Type keywords can be seen as more verbose (and more legible) versions of a common subset of the type codes.
The type keywords <literal>boolean</literal>, <literal>byte</literal>, <literal>int16</literal>,
<literal>uint16</literal>, <literal>int32</literal>, <literal>uint32</literal>, <literal>handle</literal>,
- <literal>int64</literal>, <literal>uint64</literal>, <literal>double</literal>, <literal>string</literal>,
- <literal>objectpath</literal> and literal <literal>signature</literal> are each exactly equivalent to their
- corresponding type code.
+ <literal>int64</literal>, <literal>uint64</literal>, <literal>float</literal>, <literal>double</literal>,
+ <literal>string</literal>, <literal>objectpath</literal> and literal <literal>signature</literal> are each
+ exactly equivalent to their corresponding type code.
</para>
<para>
Type codes are an <literal>@</literal> ("at" sign) followed by a definite GVariant type string. Some
$(gmodule_INCLUDES) \
$(GLIB_DEBUG_FLAGS) \
-DGIO_COMPILATION \
- -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\"
+ -DGIO_MODULE_DIR=\"$(GIO_MODULE_DIR)\"
AM_CFLAGS = $(GLIB_WARN_CFLAGS)
appinfo_headers =
contenttype_sources =
+if LIBDBUSPOLICY
+platform_libadd += $(LIBDBUSPOLICY1_LIBS)
+endif
+
if HAVE_INOTIFY
SUBDIRS += inotify
platform_libadd += inotify/libinotify.la
unix_sources = \
gfiledescriptorbased.c \
+ gkdbus.c \
+ gkdbus.h \
+ gkdbusfakedaemon.c \
+ gkdbusfakedaemon.h \
gunixconnection.c \
gunixcredentialsmessage.c \
gunixfdlist.c \
libgio_2_0_la_LIBADD += $(LIBMOUNT_LIBS)
endif
+if LIBDBUSPOLICY
+libgio_2_0_la_CPPFLAGS += $(LIBDBUSPOLICY1_CFLAGS)
+endif
+
libgio_2_0_la_DEPENDENCIES = $(gio_win32_res) $(gio_def) $(platform_deps)
gio-win32-res.o: gio.rc
gzlibdecompressor.h \
glistmodel.h \
gliststore.h \
+ tizen_header_glib.h \
$(application_headers) \
$(settings_headers) \
$(gdbus_headers) \
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+glib_compile_resources_LDFLAGS = -pie
glib_compile_resources_SOURCES = \
gvdb/gvdb-format.h \
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gio_querymodules_LDFLAGS = -pie
gconstructor_as_data.h: $(top_srcdir)/glib/gconstructor.h data-to-c.pl
$(AM_V_GEN) $(srcdir)/data-to-c.pl $(top_srcdir)/glib/gconstructor.h gconstructor_code > $@.tmp && mv $@.tmp $@
glib_compile_schemas_LDADD = $(top_builddir)/glib/libglib-2.0.la
+glib_compile_schemas_LDFLAGS = -pie
glib_compile_schemas_SOURCES = \
gconstructor_as_data.h \
gvdb/gvdb-format.h \
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gsettings_LDFLAGS = -pie
gsettings_SOURCES = gsettings-tool.c
schemadir = $(datadir)/glib-2.0/schemas
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gdbus_LDFLAGS = -pie
if OS_UNIX
if !OS_COCOA
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gapplication_LDFLAGS = -pie
endif
endif
$(top_builddir)/gmodule/libgmodule-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(LIBELF_LIBS)
+gresource_LDFLAGS = -pie
# ------------------------------------------------------------------------
# gio tool
$(top_builddir)/gobject/libgobject-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
+gio_LDFLAGS = -pie
# ------------------------------------------------------------------------
# ------ MSVC Project File Generation ------
NULL /* set_property */
};
GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
- GVariant *reply;
- guint32 rval;
+ GBusRequestNameReplyFlags rval;
if (org_gtk_Application == NULL)
{
* in the case that we can't do that.
*/
/* DBUS_NAME_FLAG_DO_NOT_QUEUE: 0x4 */
- reply = g_dbus_connection_call_sync (impl->session_bus, "org.freedesktop.DBus", "/org/freedesktop/DBus",
- "org.freedesktop.DBus", "RequestName",
- g_variant_new ("(su)", impl->bus_name, 0x4), G_VARIANT_TYPE ("(u)"),
- 0, -1, cancellable, error);
+ rval = g_dbus_request_name (impl->session_bus, impl->bus_name, G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE, error);
- if (reply == NULL)
+ if (rval == G_BUS_REQUEST_NAME_FLAGS_ERROR)
return FALSE;
- g_variant_get (reply, "(u)", &rval);
- g_variant_unref (reply);
-
/* DBUS_REQUEST_NAME_REPLY_EXISTS: 3 */
- impl->primary = (rval != 3);
+ impl->primary = (rval != G_BUS_REQUEST_NAME_FLAGS_EXISTS);
return TRUE;
}
if (impl->primary && impl->bus_name)
{
- g_dbus_connection_call (impl->session_bus, "org.freedesktop.DBus",
- "/org/freedesktop/DBus", "org.freedesktop.DBus",
- "ReleaseName", g_variant_new ("(s)", impl->bus_name),
- NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, NULL, NULL);
+ g_dbus_release_name (impl->session_bus, impl->bus_name, NULL);
impl->primary = FALSE;
}
}
if (fd_list && g_unix_fd_list_get_length (fd_list))
{
- gint *fds, n_fds, i;
+ const gint *fds;
- fds = g_unix_fd_list_steal_fds (fd_list, &n_fds);
- result = g_unix_input_stream_new (fds[0], TRUE);
- for (i = 1; i < n_fds; i++)
- (void) g_close (fds[i], NULL);
- g_free (fds);
+ fds = g_unix_fd_list_peek_fds (fd_list, NULL);
+ result = g_unix_input_stream_new (fds[0], FALSE);
+ g_object_weak_ref (G_OBJECT (result),
+ (GWeakNotify) g_object_unref,
+ g_object_ref (fd_list));
}
return result;
%(i.name_lower, i.camel_name), False))
self.write_gtkdoc_deprecated_and_since_and_close(i, self.c, 0)
self.c.write('guint\n'
- '%s_override_properties (GObjectClass *klass, guint property_id_begin)\n'
+ '%s_override_properties (GObjectClass *klass G_GNUC_UNUSED, guint property_id_begin)\n'
'{\n'%(i.name_lower))
for p in i.properties:
self.c.write (' g_object_class_override_property (klass, property_id_begin++, "%s");\n'%(p.name_hyphen))
self.write_gtkdoc_deprecated_and_since_and_close(m, self.c, 0)
self.c.write('void\n'
'%s_complete_%s (\n'
- ' %s *object,\n'
+ ' %s *object G_GNUC_UNUSED,\n'
' GDBusMethodInvocation *invocation'%(i.name_lower, m.name_lower, i.camel_name))
if unix_fd:
self.c.write(',\n GUnixFDList *fd_list')
# laid out in the same order as introspection data pointers
#
self.c.write('static void\n'
- '%s_proxy_get_property (GObject *object,\n'
- ' guint prop_id,\n'
- ' GValue *value,\n'
+ '%s_proxy_get_property (GObject *object G_GNUC_UNUSED,\n'
+ ' guint prop_id G_GNUC_UNUSED,\n'
+ ' GValue *value G_GNUC_UNUSED,\n'
' GParamSpec *pspec G_GNUC_UNUSED)\n'
'{\n'%(i.name_lower))
if len(i.properties) > 0:
self.c.write('}\n'
'\n')
self.c.write('static void\n'
- '%s_proxy_set_property (GObject *object,\n'
- ' guint prop_id,\n'
- ' const GValue *value,\n'
+ '%s_proxy_set_property (GObject *object G_GNUC_UNUSED,\n'
+ ' guint prop_id G_GNUC_UNUSED,\n'
+ ' const GValue *value G_GNUC_UNUSED,\n'
' GParamSpec *pspec G_GNUC_UNUSED)\n'
'{\n'%(i.name_lower))
if len(i.properties) > 0:
'\n')
self.c.write('static void\n'
- '%s_proxy_iface_init (%sIface *iface)\n'
+ '%s_proxy_iface_init (%sIface *iface G_GNUC_UNUSED)\n'
'{\n'%(i.name_lower, i.camel_name))
for p in i.properties:
self.c.write(' iface->get_%s = %s_proxy_get_%s;\n'%(p.name_lower, i.name_lower, p.name_lower))
%(i.name_lower))
self.c.write('static void\n'
- '%s_skeleton_dbus_interface_flush (GDBusInterfaceSkeleton *_skeleton)\n'
+ '%s_skeleton_dbus_interface_flush (GDBusInterfaceSkeleton *_skeleton G_GNUC_UNUSED)\n'
'{\n'
%(i.name_lower))
if len(i.properties) > 0:
'\n')
self.c.write('static void\n'
- '%s_skeleton_iface_init (%sIface *iface)\n'
+ '%s_skeleton_iface_init (%sIface *iface G_GNUC_UNUSED)\n'
'{\n'
%(i.name_lower, i.camel_name))
for s in i.signals:
#endif
#include "giotypes.h"
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
G_TYPE_DBUS_ACTION_GROUP, GDBusActionGroupClass))
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_action_group_get_type (void) G_GNUC_CONST;
+GType g_dbus_action_group_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_32
GDBusActionGroup * g_dbus_action_group_get (GDBusConnection *connection,
const gchar *bus_name,
- const gchar *object_path);
+ const gchar *object_path) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#include "gstdio.h"
#ifdef G_OS_UNIX
+#include "gkdbus.h"
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
/* ---------------------------------------------------------------------------------------------------- */
-static GIOStream *
+static GObject *
g_dbus_address_try_connect_one (const gchar *address_entry,
+ gboolean kdbus_okay,
gchar **out_guid,
GCancellable *cancellable,
GError **error);
* point. That way we can implement a D-Bus transport over X11 without
* making libgio link to libX11...
*/
-static GIOStream *
+static GObject *
g_dbus_address_connect (const gchar *address_entry,
const gchar *transport_name,
+ gboolean kdbus_okay,
GHashTable *key_value_pairs,
GCancellable *cancellable,
GError **error)
{
- GIOStream *ret;
+ GObject *ret;
GSocketConnectable *connectable;
const gchar *nonce_file;
{
}
#ifdef G_OS_UNIX
+ else if (kdbus_okay && g_str_equal (transport_name, "kernel"))
+ {
+ GKDBusWorker *worker;
+ const gchar *path;
+
+ path = g_hash_table_lookup (key_value_pairs, "path");
+
+ if (path == NULL)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
+ _("Error in address '%s' - the kernel transport requires a path"),
+ address_entry);
+ }
+ else
+ {
+ worker = _g_kdbus_worker_new (path, error);
+
+ if (worker == NULL)
+ return NULL;
+
+ return G_OBJECT (worker);
+ }
+ }
else if (g_strcmp0 (transport_name, "unix") == 0)
{
const gchar *path;
autolaunch_address = get_session_address_dbus_launch (error);
if (autolaunch_address != NULL)
{
- ret = g_dbus_address_try_connect_one (autolaunch_address, NULL, cancellable, error);
+ ret = g_dbus_address_try_connect_one (autolaunch_address, kdbus_okay, NULL, cancellable, error);
g_free (autolaunch_address);
goto out;
}
if (connection == NULL)
goto out;
- ret = G_IO_STREAM (connection);
+ ret = G_OBJECT (connection);
if (nonce_file != NULL)
{
}
fclose (f);
- if (!g_output_stream_write_all (g_io_stream_get_output_stream (ret),
+ if (!g_output_stream_write_all (g_io_stream_get_output_stream (G_IO_STREAM (connection)),
nonce_contents,
16,
NULL,
return ret;
}
-static GIOStream *
+static GObject *
g_dbus_address_try_connect_one (const gchar *address_entry,
+ gboolean kdbus_okay,
gchar **out_guid,
GCancellable *cancellable,
GError **error)
{
- GIOStream *ret;
+ GObject *ret;
GHashTable *key_value_pairs;
gchar *transport_name;
const gchar *guid;
ret = g_dbus_address_connect (address_entry,
transport_name,
+ kdbus_okay,
key_value_pairs,
cancellable,
error);
GCancellable *cancellable,
GError **error)
{
- GIOStream *ret;
+ GObject *result;
+
+ result = g_dbus_address_get_stream_internal (address, FALSE, out_guid, cancellable, error);
+ g_assert (result == NULL || G_IS_IO_STREAM (result));
+
+ if (result)
+ return G_IO_STREAM (result);
+
+ return NULL;
+}
+
+GObject *
+g_dbus_address_get_stream_internal (const gchar *address,
+ gboolean kdbus_okay,
+ gchar **out_guid,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GObject *ret;
gchar **addr_array;
guint n;
GError *last_error;
this_error = NULL;
ret = g_dbus_address_try_connect_one (addr,
+ kdbus_okay,
out_guid,
cancellable,
&this_error);
#endif
}
+static gchar *
+get_session_address_kdbus (void)
+{
+#ifdef G_OS_UNIX
+ gchar *ret = NULL;
+ gchar *bus;
+ GStatBuf buf;
+
+ bus = g_strdup_printf ("/sys/fs/kdbus/%d-user/bus", getuid());
+
+ /* if ENOENT, EPERM, etc., quietly don't use it */
+ if (g_stat (bus, &buf) < 0)
+ goto out;
+
+ ret = g_strconcat ("kernel:path=", bus, NULL);
+
+out:
+ g_free (bus);
+ return ret;
+#else
+ return NULL;
+#endif
+}
+
/* ---------------------------------------------------------------------------------------------------- */
#ifdef G_OS_UNIX
if (G_UNLIKELY (_g_dbus_debug_address ()))
{
guint n;
+ gchar *s;
_g_dbus_debug_print_lock ();
s = _g_dbus_enum_to_string (G_TYPE_BUS_TYPE, bus_type);
g_print ("GDBus-debug:Address: In g_dbus_address_get_for_bus_sync() for bus type '%s'\n",
ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
if (ret == NULL)
{
- ret = g_strdup ("unix:path=/var/run/dbus/system_bus_socket");
+ ret = g_strdup ("kernel:path=/sys/fs/kdbus/0-system/bus;unix:path=/var/run/dbus/system_bus_socket");
}
break;
ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
if (ret == NULL)
{
- ret = get_session_address_platform_specific (&local_error);
+ ret = get_session_address_kdbus ();
+ if (ret == NULL)
+ ret = get_session_address_platform_specific (&local_error);
+ if (ret == NULL)
+ goto out;
}
break;
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_2_36
-gchar *g_dbus_address_escape_value (const gchar *string);
+gchar *g_dbus_address_escape_value (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_address (const gchar *string);
+gboolean g_dbus_is_address (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_is_supported_address (const gchar *string,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_address_get_stream (const gchar *address,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GIOStream *g_dbus_address_get_stream_finish (GAsyncResult *res,
gchar **out_guid,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GIOStream *g_dbus_address_get_stream_sync (const gchar *address,
gchar **out_guid,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gchar *g_dbus_address_get_for_bus_sync (GBusType bus_type,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
&line_length,
cancellable,
error);
- debug_print ("SERVER: WaitingForBegin, read '%s'", line);
if (line == NULL)
goto out;
+ debug_print ("SERVER: WaitingForBegin, read '%s'", line);
if (g_strcmp0 (line, "BEGIN") == 0)
{
/* YAY, done! */
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
#define G_IS_DBUS_AUTH_OBSERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_AUTH_OBSERVER))
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_auth_observer_get_type (void) G_GNUC_CONST;
+GType g_dbus_auth_observer_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusAuthObserver *g_dbus_auth_observer_new (void);
+GDBusAuthObserver *g_dbus_auth_observer_new (void) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_auth_observer_authorize_authenticated_peer (GDBusAuthObserver *observer,
GIOStream *stream,
- GCredentials *credentials);
+ GCredentials *credentials) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_34
gboolean g_dbus_auth_observer_allow_mechanism (GDBusAuthObserver *observer,
- const gchar *mechanism);
+ const gchar *mechanism) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#include "gtask.h"
#ifdef G_OS_UNIX
+#include "gkdbus.h"
#include "gunixconnection.h"
#include "gunixfdmessage.h"
#endif
*/
GDBusWorker *worker;
+#ifdef G_OS_UNIX
+ GKDBusWorker *kdbus_worker;
+#endif
+
/* If connected to a message bus, this contains the unique name assigned to
* us by the bus (e.g. ":1.42").
* Read-only after initable_init(), so it may be read if you either
G_LOCK (message_bus_lock);
CONNECTION_LOCK (connection);
+
if (connection->worker != NULL)
{
_g_dbus_worker_stop (connection->worker);
if (alive_connections != NULL)
g_warn_if_fail (g_hash_table_remove (alive_connections, connection));
}
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker != NULL)
+ {
+ _g_kdbus_worker_stop (connection->kdbus_worker);
+ connection->kdbus_worker = NULL;
+ if (alive_connections != NULL)
+ g_warn_if_fail (g_hash_table_remove (alive_connections, connection));
+ }
+#endif
else
{
if (alive_connections != NULL)
connection->filters = g_ptr_array_new ();
}
+#ifdef G_OS_UNIX
+gboolean
+_g_dbus_connection_is_kdbus (GDBusConnection *connection)
+{
+ if (connection->kdbus_worker)
+ return TRUE;
+ else
+ return FALSE;
+}
+#endif
+
/**
* g_dbus_connection_get_stream:
* @connection: a #GDBusConnection
if (!check_initialized (connection))
return;
- g_assert (connection->worker != NULL);
- _g_dbus_worker_unfreeze (connection->worker);
+ if (connection->worker)
+ _g_dbus_worker_unfreeze (connection->worker);
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ _g_kdbus_worker_unfreeze (connection->kdbus_worker);
+#endif
+ else
+ g_assert_not_reached ();
}
/**
if (!check_unclosed (connection, 0, error))
goto out;
- g_assert (connection->worker != NULL);
-
- ret = _g_dbus_worker_flush_sync (connection->worker,
- cancellable,
- error);
+ if (connection->worker != NULL)
+ {
+ ret = _g_dbus_worker_flush_sync (connection->worker,
+ cancellable,
+ error);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker != NULL)
+ {
+ ret = _g_kdbus_worker_flush_sync (connection->kdbus_worker);
+ }
+#endif
+ else
+ g_assert_not_reached();
out:
return ret;
* of the thread that @connection was constructed in.
*
* This is an asynchronous method. When the operation is finished,
- * @callback will be invoked in the
+ * @callback will be invoked in the
* [thread-default main context][g-main-context-push-thread-default]
* of the thread you are calling this method from. You can
* then call g_dbus_connection_close_finish() to get the result of the
if (!check_initialized (connection))
return;
- g_assert (connection->worker != NULL);
-
task = g_task_new (connection, cancellable, callback, user_data);
g_task_set_source_tag (task, g_dbus_connection_close);
- _g_dbus_worker_close (connection->worker, task);
+ if (connection->worker)
+ {
+ _g_dbus_worker_close (connection->worker, task);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ _g_kdbus_worker_close (connection->kdbus_worker, task);
+ }
+#endif
+ else
+ g_assert_not_reached();
g_object_unref (task);
}
/* ---------------------------------------------------------------------------------------------------- */
/**
+ * g_dbus_request_name:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name (name to request)
+ * @flags: a set of flags from the GBusNameOwnerFlags enumeration
+ * @error: return location for error or %NULL
+ *
+ * Synchronously acquires name on the bus and returns status code
+ * from the #GBusRequestNameReplyFlags enumeration.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: status code or %G_BUS_REQUEST_NAME_FLAGS_ERROR
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+GBusRequestNameReplyFlags
+g_dbus_request_name (GDBusConnection *connection,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GError **error)
+{
+ GVariant *result;
+ guint32 request_name_reply;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+ g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+ g_return_val_if_fail (error == NULL || *error == NULL, G_BUS_RELEASE_NAME_FLAGS_ERROR);
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_RequestName (connection->kdbus_worker, name, flags, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+ "org.freedesktop.DBus", "RequestName",
+ g_variant_new ("(su)", name, flags), G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(u)", &request_name_reply);
+ g_variant_unref (result);
+ }
+ else
+ request_name_reply = G_BUS_REQUEST_NAME_FLAGS_ERROR;
+
+ return (GBusRequestNameReplyFlags) request_name_reply;
+}
+
+/**
+ * g_dbus_release_name:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name (name to release)
+ * @error: return location for error or %NULL
+ *
+ * Synchronously releases name on the bus and returns status code
+ * from the #GBusReleaseNameReplyFlags enumeration.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: status code or %G_BUS_RELEASE_NAME_FLAGS_ERROR
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+GBusReleaseNameReplyFlags
+g_dbus_release_name (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ GVariant *result;
+ guint32 release_name_reply;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+ g_return_val_if_fail (g_dbus_is_name (name) && !g_dbus_is_unique_name (name), G_BUS_RELEASE_NAME_FLAGS_ERROR);
+ g_return_val_if_fail (error == NULL || *error == NULL, G_BUS_RELEASE_NAME_FLAGS_ERROR);
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_ReleaseName (connection->kdbus_worker, name, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+ "org.freedesktop.DBus", "ReleaseName",
+ g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(u)", &release_name_reply);
+ g_variant_unref (result);
+ }
+ else
+ release_name_reply = G_BUS_RELEASE_NAME_FLAGS_ERROR;
+
+ return (GBusReleaseNameReplyFlags) release_name_reply;
+}
+
+/**
+ * g_dbus_add_match:
+ * @connection: a #GDBusConnection
+ * @match_rule: match rule to add to the @connection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously adds a match rule to match messages.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: %TRUE if the operation succeeded, %FALSE
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+gboolean
+g_dbus_add_match (GDBusConnection *connection,
+ const gchar *match_rule,
+ GError **error)
+{
+ GVariant *result;
+ gboolean ret;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ result = NULL;
+ ret = FALSE;
+
+ if (match_rule[0] == '-')
+ return ret;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_AddMatch (connection->kdbus_worker, match_rule, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+ "org.freedesktop.DBus", "AddMatch",
+ g_variant_new ("(s)", match_rule), NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ ret = TRUE;
+ g_variant_unref (result);
+ }
+
+ return ret;
+}
+
+/**
+ * g_dbus_remove_match:
+ * @connection: a #GDBusConnection
+ * @match_rule: match rule to remove from the @connection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously removes the first rule that matches.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: %TRUE if the operation succeeded, %FALSE
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+gboolean
+g_dbus_remove_match (GDBusConnection *connection,
+ const gchar *match_rule,
+ GError **error)
+{
+ GVariant *result;
+ gboolean ret;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ result = NULL;
+ ret = FALSE;
+
+ if (match_rule[0] == '-')
+ return ret;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_RemoveMatch (connection->kdbus_worker, match_rule, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/org/freedesktop/DBus",
+ "org.freedesktop.DBus", "RemoveMatch",
+ g_variant_new ("(s)", match_rule), NULL,
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ ret = TRUE;
+ g_variant_unref (result);
+ }
+
+ return ret;
+}
+
+/**
+ * g_dbus_get_bus_id:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique ID of the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique ID of the bus or %NULL if @error is set.
+ * Free with g_free().
+ *
+ * Since: 2.44
+ */
+gchar *
+g_dbus_get_bus_id (GDBusConnection *connection,
+ GError **error)
+{
+ GVariant *result;
+ gchar *bus_id;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ result = NULL;
+ bus_id = NULL;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetBusId (connection->kdbus_worker, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "GetId",
+ NULL, G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(s)", &bus_id);
+ g_variant_unref (result);
+ }
+
+ return bus_id;
+}
+
+typedef enum
+{
+ LIST_NAMES,
+ LIST_ACTIVATABLE_NAMES,
+ LIST_QUEUED_OWNERS
+} GDBusListNameType;
+
+static gchar **
+_g_dbus_get_list_internal (GDBusConnection *connection,
+ const gchar *name,
+ GDBusListNameType list_name_type,
+ GError **error)
+{
+ gchar **strv;
+ GVariant *result;
+ GVariantIter *iter;
+ gchar *str;
+ gsize n, i;
+
+ result = NULL;
+ strv = NULL;
+
+ if (list_name_type == LIST_QUEUED_OWNERS)
+ {
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetListQueuedOwners (connection->kdbus_worker, name, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "ListQueuedOwners",
+ g_variant_new ("(s)", name), G_VARIANT_TYPE ("(as)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ }
+ else
+ {
+ gchar *method_name;
+
+ if (list_name_type == LIST_NAMES)
+ method_name = "ListNames";
+ else
+ method_name = "ListActivatableNames";
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetListNames (connection->kdbus_worker, list_name_type, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", method_name,
+ NULL, G_VARIANT_TYPE ("(as)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ }
+
+ if (result != NULL)
+ {
+ g_variant_get (result, "(as)", &iter);
+ n = g_variant_iter_n_children (iter);
+ strv = g_new (gchar *, n + 1);
+
+ i = 0;
+ while (g_variant_iter_loop (iter, "s", &str))
+ {
+ strv[i] = g_strdup (str);
+ i++;
+ }
+ strv[i] = NULL;
+
+ g_variant_iter_free (iter);
+ g_variant_unref (result);
+ }
+
+ return strv;
+}
+
+/**
+ * g_dbus_get_list_names:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns a list of all currently-owned names on the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: a list of all currently-owned names on the bus or %NULL if
+ * @error is set. Free with g_strfreev().
+ *
+ * Since: 2.44
+ */
+gchar **
+g_dbus_get_list_names (GDBusConnection *connection,
+ GError **error)
+{
+ gchar **strv;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ strv = _g_dbus_get_list_internal (connection, NULL, LIST_NAMES, error);
+
+ return strv;
+}
+
+/**
+ * g_dbus_get_list_activatable_names:
+ * @connection: a #GDBusConnection
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns a list of all names that can be activated on the bus.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: a list of all names that can be activated on the bus or %NULL if
+ * @error is set. Free with g_strfreev().
+ *
+ * Since: 2.44
+ */
+gchar **
+g_dbus_get_list_activatable_names (GDBusConnection *connection,
+ GError **error)
+{
+ gchar **strv;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ strv = _g_dbus_get_list_internal (connection, NULL, LIST_ACTIVATABLE_NAMES, error);
+
+ return strv;
+}
+
+/**
+ * g_dbus_get_list_queued_names:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique bus names of connections currently queued
+ * for the @name.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns %NULL and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique bus names of connections currently queued for the @name
+ * or %NULL if @error is set. Free with g_strfreev().
+ *
+ * Since: 2.44
+ */
+gchar **
+g_dbus_get_list_queued_owners (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ gchar **strv;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ strv = _g_dbus_get_list_internal (connection, name, LIST_QUEUED_OWNERS, error);
+
+ return strv;
+}
+
+/**
+ * g_dbus_get_name_owner:
+ * @connection: a #GDBusConnection
+ * @name: well-known bus name to get the owner of
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the unique connection name of the primary owner of
+ * the name given. If the requested name doesn't have an owner, an @error is
+ * returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns %NULL and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the unique connection name of the primary owner of the
+ * name given. If the requested name doesn't have an owner, function
+ * returns %NULL and @error is set. Free with g_free().
+ *
+ * Since: 2.44
+ */
+gchar *
+g_dbus_get_name_owner (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ GVariant *result;
+ gchar *name_owner;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), NULL);
+ g_return_val_if_fail (name == NULL || g_dbus_is_name (name), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ name_owner = NULL;
+ result = NULL;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetNameOwner (connection->kdbus_worker, name, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "GetNameOwner",
+ g_variant_new ("(s)", name), G_VARIANT_TYPE ("(s)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(s)", &name_owner);
+ g_variant_unref (result);
+ }
+ else
+ name_owner = NULL;
+
+ return name_owner;
+}
+
+/**
+ * g_dbus_get_connection_pid:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name of the connection to query
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the Unix process ID of the process connected to the
+ * bus. If unable to determine it, an @error is returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns -1 and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the Unix process ID of the process connected to the bus or -1
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+pid_t
+g_dbus_get_connection_pid (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ GVariant *result;
+ pid_t pid;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), -1);
+ g_return_val_if_fail (name == NULL || g_dbus_is_name (name), -1);
+ g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+ result = NULL;
+ pid = -1;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetConnectionUnixProcessID (connection->kdbus_worker, name, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "GetConnectionUnixProcessID",
+ g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(u)", &pid);
+ g_variant_unref (result);
+ }
+
+ return pid;
+}
+
+/**
+ * g_dbus_get_connection_uid:
+ * @connection: a #GDBusConnection
+ * @name: a unique or well-known bus name of the connection to query
+ * @error: return location for error or %NULL
+ *
+ * Synchronously returns the Unix user ID of the process connected to the
+ * bus. If unable to determine it, an @error is returned.
+ *
+ * If @name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns -1 and @error is set.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: the Unix user ID of the process connected to the bus or -1
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+uid_t
+g_dbus_get_connection_uid (GDBusConnection *connection,
+ const gchar *name,
+ GError **error)
+{
+ GVariant *result;
+ uid_t uid;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), -1);
+ g_return_val_if_fail (name == NULL || g_dbus_is_name (name), -1);
+ g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+ result = NULL;
+ uid = -1;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_GetConnectionUnixUser (connection->kdbus_worker, name, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "GetConnectionUnixUser",
+ g_variant_new ("(s)", name), G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(u)", &uid);
+ g_variant_unref (result);
+ }
+
+ return uid;
+}
+
+/**
+ * g_dbus_start_service_by_name:
+ * @connection: a #GDBusConnection
+ * @name: name of the service to start
+ * @flags: (currently not used)
+ * @error: return location for error or %NULL
+ *
+ * Synchronously tries to launch the executable associated
+ * with a @name.
+ *
+ * The calling thread is blocked until a reply is received.
+ *
+ * Returns: status code or %G_BUS_START_SERVICE_REPLY_ERROR
+ * if @error is set.
+ *
+ * Since: 2.44
+ */
+GBusStartServiceReplyFlags
+g_dbus_start_service_by_name (GDBusConnection *connection,
+ const gchar *name,
+ guint32 flags,
+ GError **error)
+{
+ GVariant *result;
+ guint32 ret;
+
+ g_return_val_if_fail (G_IS_DBUS_CONNECTION (connection), -1);
+ g_return_val_if_fail (name == NULL || g_dbus_is_name (name), -1);
+ g_return_val_if_fail (error == NULL || *error == NULL, -1);
+
+ result = NULL;
+ ret = G_BUS_START_SERVICE_REPLY_ERROR;
+
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker)
+ return _g_kdbus_StartServiceByName (connection->kdbus_worker, name, flags, NULL, error);
+#endif
+
+ result = g_dbus_connection_call_sync (connection, "org.freedesktop.DBus", "/",
+ "org.freedesktop.DBus", "StartServiceByName",
+ g_variant_new ("(su)", name, flags), G_VARIANT_TYPE ("(u)"),
+ G_DBUS_CALL_FLAGS_NONE, -1, NULL, error);
+ if (result != NULL)
+ {
+ g_variant_get (result, "(u)", &ret);
+ g_variant_unref (result);
+ }
+
+ return (GBusStartServiceReplyFlags) ret;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/**
* g_dbus_connection_get_last_serial:
* @connection: a #GDBusConnection
*
GDBusMessage *message,
GDBusSendMessageFlags flags,
volatile guint32 *out_serial,
- GError **error)
+ GError **error,
+ gint timeout_msec)
{
guchar *blob;
gsize blob_size;
error))
goto out;
- blob = g_dbus_message_to_blob (message,
- &blob_size,
- connection->capabilities,
- error);
- if (blob == NULL)
- goto out;
+ if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
+ g_dbus_message_set_serial (message, ++connection->last_serial);
- if (flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL)
- serial_to_use = g_dbus_message_get_serial (message);
- else
- serial_to_use = ++connection->last_serial; /* TODO: handle overflow */
+ serial_to_use = g_dbus_message_get_serial (message);
- switch (blob[0])
+ /*
+ * serializes message to a blob
+ */
+ if (connection->worker)
{
- case 'l':
- ((guint32 *) blob)[2] = GUINT32_TO_LE (serial_to_use);
- break;
- case 'B':
- ((guint32 *) blob)[2] = GUINT32_TO_BE (serial_to_use);
- break;
- default:
- g_assert_not_reached ();
- break;
+ blob = g_dbus_message_to_blob (message,
+ &blob_size,
+ connection->capabilities,
+ error);
+ if (blob == NULL)
+ goto out;
+
+ switch (blob[0])
+ {
+ case 'l':
+ ((guint32 *) blob)[2] = GUINT32_TO_LE (serial_to_use);
+ break;
+ case 'B':
+ ((guint32 *) blob)[2] = GUINT32_TO_BE (serial_to_use);
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
}
+ g_dbus_message_lock (message);
+
#if 0
g_printerr ("Writing message of %" G_GSIZE_FORMAT " bytes (serial %d) on %p:\n",
blob_size, serial_to_use, connection);
g_thread_self (),
GUINT_TO_POINTER (serial_to_use));
- if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
- g_dbus_message_set_serial (message, serial_to_use);
+ ret = TRUE;
- g_dbus_message_lock (message);
- _g_dbus_worker_send_message (connection->worker,
- message,
- (gchar*) blob,
- blob_size);
- blob = NULL; /* since _g_dbus_worker_send_message() steals the blob */
+ if (connection->worker)
+ {
+ _g_dbus_worker_send_message (connection->worker,
+ message,
+ (gchar*) blob,
+ blob_size);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ ret = _g_kdbus_worker_send_message (connection->kdbus_worker, message, timeout_msec, error);
+ }
+#endif
+ else
+ g_assert_not_reached ();
- ret = TRUE;
+ blob = NULL; /* since _g_dbus_worker_send_message() steals the blob */
out:
g_free (blob);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
CONNECTION_LOCK (connection);
- ret = g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, error);
+ ret = g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, error, -1);
CONNECTION_UNLOCK (connection);
return ret;
}
if (out_serial == NULL)
out_serial = &serial;
- if (timeout_msec == -1)
- timeout_msec = 25 * 1000;
-
data = g_slice_new0 (SendMessageData);
task = g_task_new (connection, cancellable, callback, user_data);
g_task_set_source_tag (task,
return;
}
- if (!g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, &error))
+ if (!g_dbus_connection_send_message_unlocked (connection, message, flags, out_serial, &error, timeout_msec))
{
g_task_return_error (task, error);
g_object_unref (task);
g_object_unref);
}
- if (timeout_msec != G_MAXINT)
+ if (timeout_msec != G_MAXINT
+#ifdef G_OS_UNIX
+ /* Userspace timeouts unnecessary on unix/kdbus - kdbus handles timeouts. */
+ && !connection->kdbus_worker
+#endif
+ )
{
- data->timeout_source = g_timeout_source_new (timeout_msec);
+ data->timeout_source = g_timeout_source_new (timeout_msec == -1 ? DBUS_DEFAULT_TIMEOUT_MSEC : timeout_msec);
g_task_attach_source (task, data->timeout_source,
(GSourceFunc) send_message_with_reply_timeout_cb);
g_source_unref (data->timeout_source);
* the operation fails with %G_IO_ERROR_INVALID_ARGUMENT.
*
* This is an asynchronous method. When the operation is finished, @callback
- * will be invoked in the
+ * will be invoked in the
* [thread-default main context][g-main-context-push-thread-default]
* of the thread you are calling this method from. You can then call
* g_dbus_connection_send_message_with_reply_finish() to get the result of the operation.
g_return_val_if_fail (timeout_msec >= 0 || timeout_msec == -1, NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
- data.res = NULL;
- data.context = g_main_context_new ();
- data.loop = g_main_loop_new (data.context, FALSE);
+ if (connection->worker)
+ {
+ data.res = NULL;
+ data.context = g_main_context_new ();
+ data.loop = g_main_loop_new (data.context, FALSE);
- g_main_context_push_thread_default (data.context);
+ g_main_context_push_thread_default (data.context);
- g_dbus_connection_send_message_with_reply (connection,
- message,
- flags,
- timeout_msec,
- out_serial,
- cancellable,
- (GAsyncReadyCallback) send_message_with_reply_sync_cb,
- &data);
- g_main_loop_run (data.loop);
- reply = g_dbus_connection_send_message_with_reply_finish (connection,
- data.res,
- error);
+ g_dbus_connection_send_message_with_reply (connection,
+ message,
+ flags,
+ timeout_msec,
+ out_serial,
+ cancellable,
+ (GAsyncReadyCallback) send_message_with_reply_sync_cb,
+ &data);
+ g_main_loop_run (data.loop);
+ reply = g_dbus_connection_send_message_with_reply_finish (connection,
+ data.res,
+ error);
+
+ g_main_context_pop_thread_default (data.context);
+
+ g_main_context_unref (data.context);
+ g_main_loop_unref (data.loop);
+ if (data.res)
+ g_object_unref (data.res);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ /* kdbus supports blocking synchronous calls, so let's use them instead of mainloops */
+
+ volatile guint32 serial;
+ guint32 serial_to_use;
+
+ reply = NULL;
+
+ CONNECTION_LOCK (connection);
+
+ if (out_serial == NULL)
+ out_serial = &serial;
+ else
+ *out_serial = 0;
+
+ /*
+ * Check that we never actually send a message if the GCancellable
+ * is already cancelled
+ */
+ if (g_cancellable_is_cancelled (cancellable))
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ CONNECTION_UNLOCK (connection);
+ goto out;
+ }
+
+ if (!check_unclosed (connection,
+ (flags & SEND_MESSAGE_FLAGS_INITIALIZING) ? MAY_BE_UNINITIALIZED : 0,
+ error))
+ {
+ CONNECTION_UNLOCK (connection);
+ goto out;
+ }
+
+ if (!(flags & G_DBUS_SEND_MESSAGE_FLAGS_PRESERVE_SERIAL))
+ g_dbus_message_set_serial (message, ++connection->last_serial);
+
+ serial_to_use = g_dbus_message_get_serial (message);
+
+ g_dbus_message_lock (message);
- g_main_context_pop_thread_default (data.context);
+ if (out_serial != NULL)
+ *out_serial = serial_to_use;
- g_main_context_unref (data.context);
- g_main_loop_unref (data.loop);
- if (data.res)
- g_object_unref (data.res);
+ CONNECTION_UNLOCK (connection);
+
+ /* Reference is still kept for the connection, so there is no worry
+ * that it will be freed. Same for connection->kdbus_worker - by reference
+ * from the connection. Inside _g_kdbus_worker_send_message_sync only
+ * initialized-once, read-only fields from kdbus_worker are used, except
+ * 'matches', which now has got its own mutex.
+ */
+ _g_kdbus_worker_send_message_sync (connection->kdbus_worker, message,
+ &reply, timeout_msec, cancellable, error);
+
+ }
+#endif /* G_OS_UNIX */
+ else
+ g_assert_not_reached ();
+out:
return reply;
}
/* Called in GDBusWorker's thread - we must not block - with no lock held */
static void
-on_worker_message_received (GDBusWorker *worker,
- GDBusMessage *message,
+on_worker_message_received (GDBusMessage *message,
gpointer user_data)
{
GDBusConnection *connection;
g_object_ref (connection);
G_UNLOCK (message_bus_lock);
- //g_debug ("in on_worker_message_received");
+#ifdef G_OS_UNIX
+ if (_g_dbus_connection_is_kdbus (connection))
+ {
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " <<<< RECEIVED D-Bus message\n");
+ s = g_dbus_message_print (message, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
+ }
+#endif
g_object_ref (message);
g_dbus_message_lock (message);
/* Called in GDBusWorker's thread, lock is not held */
static GDBusMessage *
-on_worker_message_about_to_be_sent (GDBusWorker *worker,
- GDBusMessage *message,
+on_worker_message_about_to_be_sent (GDBusMessage *message,
gpointer user_data)
{
GDBusConnection *connection;
/* Called in GDBusWorker's thread - we must not block - without lock held */
static void
-on_worker_closed (GDBusWorker *worker,
- gboolean remote_peer_vanished,
- GError *error,
- gpointer user_data)
+on_worker_closed (gboolean remote_peer_vanished,
+ GError *error,
+ gpointer user_data)
{
GDBusConnection *connection;
gboolean alive;
GError **error)
{
GDBusConnection *connection = G_DBUS_CONNECTION (initable);
+ gboolean initially_frozen;
gboolean ret;
/* This method needs to be idempotent to work with the singleton
*/
if (connection->address != NULL)
{
+ GObject *ret;
+
g_assert (connection->stream == NULL);
if ((connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER) ||
goto out;
}
- connection->stream = g_dbus_address_get_stream_sync (connection->address,
- NULL, /* TODO: out_guid */
- cancellable,
- &connection->initialization_error);
- if (connection->stream == NULL)
+ ret = g_dbus_address_get_stream_internal (connection->address, TRUE,
+ NULL, /* TODO: out_guid */
+ cancellable, &connection->initialization_error);
+ if (ret == NULL)
goto out;
+
+ if (G_IS_IO_STREAM (ret))
+ connection->stream = G_IO_STREAM (ret);
+#ifdef G_OS_UNIX
+ else if (G_IS_KDBUS_WORKER (ret))
+ connection->kdbus_worker = G_KDBUS_WORKER (ret);
+#endif
+ else
+ g_assert_not_reached ();
}
else if (connection->stream != NULL)
{
g_assert_not_reached ();
}
+#ifdef G_OS_UNIX
+ /* Skip authentication process for kdbus transport */
+ if (connection->kdbus_worker)
+ {
+ if (!_g_kdbus_can_connect (connection->kdbus_worker,
+ &connection->initialization_error))
+ goto out;
+
+ /* kdbus connection always supports exchanging UNIX file descriptors with the remote peer */
+ connection->capabilities |= G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING;
+ goto authenticated;
+ }
+#endif
+
/* Authenticate the connection */
if (connection->flags & G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_SERVER)
{
connection->authentication_observer = NULL;
}
+authenticated:
+
//g_output_stream_flush (G_SOCKET_CONNECTION (connection->stream)
//g_debug ("haz unix fd passing powers: %d", connection->capabilities & G_DBUS_CAPABILITY_FLAGS_UNIX_FD_PASSING);
g_hash_table_insert (alive_connections, connection, connection);
G_UNLOCK (message_bus_lock);
- connection->worker = _g_dbus_worker_new (connection->stream,
- connection->capabilities,
- ((connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) != 0),
- on_worker_message_received,
- on_worker_message_about_to_be_sent,
- on_worker_closed,
- connection);
+ initially_frozen = (connection->flags & G_DBUS_CONNECTION_FLAGS_DELAY_MESSAGE_PROCESSING) != 0;
+
+ if (0)
+ {
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ _g_kdbus_worker_associate (connection->kdbus_worker,
+ connection->capabilities,
+ on_worker_message_received,
+ on_worker_message_about_to_be_sent,
+ on_worker_closed,
+ connection);
+ }
+#endif
+ else
+ {
+ connection->worker = _g_dbus_worker_new (connection->stream,
+ connection->capabilities,
+ initially_frozen,
+ on_worker_message_received,
+ on_worker_message_about_to_be_sent,
+ on_worker_closed,
+ connection);
+ }
/* if a bus connection, call org.freedesktop.DBus.Hello - this is how we're getting a name */
if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
goto out;
}
- hello_result = g_dbus_connection_call_sync (connection,
- "org.freedesktop.DBus", /* name */
- "/org/freedesktop/DBus", /* path */
- "org.freedesktop.DBus", /* interface */
- "Hello",
- NULL, /* parameters */
- G_VARIANT_TYPE ("(s)"),
- CALL_FLAGS_INITIALIZING,
- -1,
- NULL, /* TODO: cancellable */
- &connection->initialization_error);
- if (hello_result == NULL)
- goto out;
+ if (connection->worker)
+ {
+ hello_result = g_dbus_connection_call_sync (connection,
+ "org.freedesktop.DBus", /* name */
+ "/org/freedesktop/DBus", /* path */
+ "org.freedesktop.DBus", /* interface */
+ "Hello",
+ NULL, /* parameters */
+ G_VARIANT_TYPE ("(s)"),
+ CALL_FLAGS_INITIALIZING,
+ -1,
+ NULL, /* TODO: cancellable */
+ &connection->initialization_error);
+ if (hello_result == NULL)
+ goto out;
+
+ g_variant_get (hello_result, "(s)", &connection->bus_unique_name);
+ g_variant_unref (hello_result);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ const gchar *unique_name;
+
+ unique_name = _g_kdbus_Hello (connection->kdbus_worker, &connection->initialization_error);
+ if (unique_name == NULL)
+ goto out;
- g_variant_get (hello_result, "(s)", &connection->bus_unique_name);
- g_variant_unref (hello_result);
- //g_debug ("unique name is '%s'", connection->bus_unique_name);
+ connection->bus_unique_name = g_strdup (unique_name);
+ }
+#endif
+ else
+ g_assert_not_reached ();
}
+#ifdef G_OS_UNIX
+ if (connection->kdbus_worker && !initially_frozen)
+ _g_kdbus_worker_unfreeze (connection->kdbus_worker);
+#endif
+
ret = TRUE;
out:
if (!ret)
{
GDBusSignalCallback callback;
gpointer user_data;
+ GFunc user_data_ref_func;
+ GFunc user_data_unref_func;
GDestroyNotify user_data_free_func;
guint id;
GMainContext *context;
message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
NULL,
- &error))
+ &error,
+ -1))
{
g_critical ("Error while sending AddMatch() message: %s", error->message);
g_error_free (error);
message,
G_DBUS_SEND_MESSAGE_FLAGS_NONE,
NULL,
- &error))
+ &error,
+ -1))
{
/* If we could get G_IO_ERROR_CLOSED here, it wouldn't be reasonable to
* critical; but we're holding the lock, and our caller checked whether
* subscription is removed or %NULL
*
* Subscribes to signals on @connection and invokes @callback with a whenever
- * the signal is received. Note that @callback will be invoked in the
+ * the signal is received. Note that @callback will be invoked in the
* [thread-default main context][g-main-context-push-thread-default]
* of the thread you are calling this method from.
*
gpointer user_data,
GDestroyNotify user_data_free_func)
{
+ return g_dbus_connection_signal_subscribe_with_ref (connection,
+ sender,
+ interface_name,
+ member,
+ object_path,
+ arg0,
+ flags,
+ callback,
+ user_data,
+ NULL,
+ NULL,
+ user_data_free_func);
+}
+
+guint
+g_dbus_connection_signal_subscribe_with_ref (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *interface_name,
+ const gchar *member,
+ const gchar *object_path,
+ const gchar *arg0,
+ GDBusSignalFlags flags,
+ GDBusSignalCallback callback,
+ gpointer user_data,
+ GFunc user_data_ref_func,
+ GFunc user_data_unref_func,
+ GDestroyNotify user_data_free_func)
+{
gchar *rule;
SignalData *signal_data;
SignalSubscriber subscriber;
subscriber.user_data_free_func = user_data_free_func;
subscriber.id = g_atomic_int_add (&_global_subscriber_id, 1); /* TODO: overflow etc. */
subscriber.context = g_main_context_ref_thread_default ();
+ subscriber.user_data_ref_func = user_data_ref_func;
+ subscriber.user_data_unref_func = user_data_unref_func;
/* see if we've already have this rule */
signal_data = g_hash_table_lookup (connection->map_rule_to_signal_data, rule);
*/
if (connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION)
{
- if (!is_signal_data_for_name_lost_or_acquired (signal_data))
- add_match_rule (connection, signal_data->rule);
+ if (connection->worker)
+ {
+ if (!is_signal_data_for_name_lost_or_acquired (signal_data))
+ add_match_rule (connection, signal_data->rule);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ gboolean special_rule = FALSE;
+ /* rule for special message */
+ if (!signal_data->sender_unique_name[0] || g_strcmp0 (signal_data->sender_unique_name, "org.freedesktop.DBus") == 0)
+ {
+ if (signal_data->sender_unique_name[0]) /* So, this is org.freedesktop.DBus */
+ special_rule = TRUE;
+ if (!signal_data->object_path || g_strcmp0 (signal_data->object_path, "/org/freedesktop/DBus") == 0)
+ {
+ if (!signal_data->interface_name || g_strcmp0 (signal_data->interface_name, "org.freedesktop.DBus") == 0)
+ {
+ /* By https://dbus.freedesktop.org/doc/dbus-specification.html, org.freedesktop.DBus
+ * has three signal types: NameAcquired, NameLost, NameOwnerChanged (all covered below).
+ *
+ * 1. if sender is NULL and other parameters are matched with special rule, add BOTH special and standard,
+ * - (NULL, NULL or DBUS, NULL or DBUS, NULL or Special Name)
+ *
+ * if other parameters are NOT matched with special rule, add standard rule
+ * - (NULL, X, X, "NotSpecial")
+ *
+ * 2. if sender is 'org.freedesktop.DBus' and other parameters are matched with special rule, add special rule
+ * - (org.freedesktop.DBus, NULL or DBUS, NULL or DBUS, NULL or Special Name)
+ *
+ * if other parameters are NOT matched with special rule, then ignore
+ * - (org.freedesktop.DBus, X, X, "NotSpecial")
+ *
+ * for every other cases, add standard rule,
+ */
+
+ if (g_strcmp0 (signal_data->member, "NameAcquired") == 0)
+ _g_kdbus_subscribe_name_acquired (connection->kdbus_worker, signal_data->rule, arg0, NULL);
+ else if (g_strcmp0 (signal_data->member, "NameLost") == 0)
+ _g_kdbus_subscribe_name_lost (connection->kdbus_worker, signal_data->rule, arg0, NULL);
+ else if (!signal_data->member || g_strcmp0 (signal_data->member, "NameOwnerChanged") == 0)
+ _g_kdbus_subscribe_name_owner_changed (connection->kdbus_worker, signal_data->rule, arg0, NULL);
+ }
+ }
+ }
+ /* standard rule */
+ if (!special_rule)
+ _g_kdbus_AddMatch (connection->kdbus_worker, signal_data->rule, NULL);
+ }
+#endif
+ else
+ g_assert_not_reached ();
}
signal_data_array = g_hash_table_lookup (connection->map_sender_unique_name_to_signal_data_array,
/* remove the match rule from the bus unless NameLost or NameAcquired (see subscribe()) */
if ((connection->flags & G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION) &&
- !is_signal_data_for_name_lost_or_acquired (signal_data) &&
!g_dbus_connection_is_closed (connection) &&
!connection->finalizing)
{
* so on_worker_closed() can't happen between the check we just
* did, and releasing the lock later.
*/
- remove_match_rule (connection, signal_data->rule);
+ if (connection->worker)
+ {
+ if (!is_signal_data_for_name_lost_or_acquired (signal_data))
+ remove_match_rule (connection, signal_data->rule);
+ }
+#ifdef G_OS_UNIX
+ else if (connection->kdbus_worker)
+ {
+ _g_kdbus_RemoveMatch (connection->kdbus_worker, signal_data->rule, NULL);
+ }
+#endif
+ else
+ g_assert_not_reached ();
}
signal_data_free (signal_data);
guint subscription_id;
GDBusSignalCallback callback;
gpointer user_data;
+ GFunc user_data_ref_func;
+ GFunc user_data_unref_func;
GDBusMessage *message;
GDBusConnection *connection;
const gchar *sender;
}
else
{
- g_variant_ref_sink (parameters);
+ g_variant_ref (parameters);
}
#if 0
has_subscription = FALSE;
if (g_hash_table_lookup (signal_instance->connection->map_id_to_signal_data,
GUINT_TO_POINTER (signal_instance->subscription_id)) != NULL)
- has_subscription = TRUE;
+ {
+ if (signal_instance->user_data_ref_func)
+ signal_instance->user_data_ref_func (signal_instance->user_data, 0);
+ 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->callback (signal_instance->connection,
+ signal_instance->sender,
+ signal_instance->path,
+ signal_instance->interface,
+ signal_instance->member,
+ parameters,
+ signal_instance->user_data);
+ if (signal_instance->user_data_unref_func)
+ signal_instance->user_data_unref_func (signal_instance->user_data, 0);
+ }
g_variant_unref (parameters);
signal_instance->subscription_id = subscriber->id;
signal_instance->callback = subscriber->callback;
signal_instance->user_data = subscriber->user_data;
+ signal_instance->user_data_ref_func = subscriber->user_data_ref_func;
+ signal_instance->user_data_unref_func = subscriber->user_data_unref_func;
signal_instance->message = g_object_ref (message);
signal_instance->connection = g_object_ref (connection);
signal_instance->sender = sender;
"org.freedesktop.DBus.Error.InvalidArgs",
_("No such property '%s'"),
property_name);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
"org.freedesktop.DBus.Error.InvalidArgs",
_("Property '%s' is not readable"),
property_name);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
"org.freedesktop.DBus.Error.InvalidArgs",
_("Property '%s' is not writable"),
property_name);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
_("Error setting property '%s': Expected type '%s' but got '%s'"),
property_name, property_info->signature,
g_variant_get_type_string (value));
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_variant_unref (value);
g_object_unref (reply);
handled = TRUE;
"org.freedesktop.DBus.Error.InvalidArgs",
_("No such interface '%s'"),
interface_name);
- g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
"org.freedesktop.DBus.Error.InvalidArgs",
_("No such interface '%s'"),
interface_name);
- g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (eo->connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
reply = g_dbus_message_new_method_reply (message);
g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
g_string_free (s, TRUE);
"org.freedesktop.DBus.Error.UnknownMethod",
_("No such method '%s'"),
g_dbus_message_get_member (message));
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
handled = TRUE;
goto out;
_("Type of message, '%s', does not match expected type '%s'"),
g_variant_get_type_string (parameters),
type_string);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_variant_type_free (in_type);
g_variant_unref (parameters);
g_object_unref (reply);
* D-Bus interface that is described in @interface_info.
*
* Calls to functions in @vtable (and @user_data_free_func) will happen
- * in the
+ * in the
* [thread-default main context][g-main-context-push-thread-default]
* of the thread you are calling this method from.
*
case G_DBUS_MESSAGE_TYPE_ERROR:
g_dbus_message_to_gerror (reply, error);
+ if (error == NULL || *error == NULL)
+ break;
+ if ((*error)->code == G_DBUS_ERROR_NO_REPLY)
+ {
+ g_clear_error(error);
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_TIMED_OUT,
+ _("Timeout was reached"));
+ }
break;
default:
{
GDBusMessage *reply;
reply = g_dbus_message_new_method_reply (message);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
}
reply = g_dbus_message_new_method_reply (message);
g_dbus_message_set_body (reply, g_variant_new ("(s)", connection->machine_id));
}
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
}
reply = g_dbus_message_new_method_reply (message);
g_dbus_message_set_body (reply, g_variant_new ("(s)", s->str));
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
g_string_free (s, TRUE);
}
_("No such interface '%s' on object at path %s"),
interface_name,
object_path);
- g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL);
+ g_dbus_connection_send_message_unlocked (connection, reply, G_DBUS_SEND_MESSAGE_FLAGS_NONE, NULL, NULL, -1);
g_object_unref (reply);
out:
}
/* ---------------------------------------------------------------------------------------------------- */
+#ifdef _TIZEN_DBUS_TOUCH
+static void __attribute__((constructor)) glib_type_dbus_connection_gc( void )
+{
+ GObject* temp = g_type_class_ref(G_TYPE_DBUS_CONNECTION);
+ g_type_class_unref(temp);
+}
+#endif
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
+#define DBUS_DEFAULT_TIMEOUT_MSEC 25000U
+
#define G_TYPE_DBUS_CONNECTION (g_dbus_connection_get_type ())
#define G_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_CONNECTION, GDBusConnection))
#define G_IS_DBUS_CONNECTION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_CONNECTION))
void g_bus_get (GBusType bus_type,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_bus_get_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_bus_get_sync (GBusType bus_type,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
GDBusAuthObserver *observer,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_dbus_connection_new_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_dbus_connection_new_sync (GIOStream *stream,
const gchar *guid,
GDBusConnectionFlags flags,
GDBusAuthObserver *observer,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_new_for_address (const gchar *address,
GDBusAuthObserver *observer,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_dbus_connection_new_for_address_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusConnection *g_dbus_connection_new_for_address_sync (const gchar *address,
GDBusConnectionFlags flags,
GDBusAuthObserver *observer,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean _g_dbus_connection_is_kdbus (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
+
+/* GLIB_AVAILABLE_IN_2_44 */
+GBusRequestNameReplyFlags g_dbus_request_name (GDBusConnection *connection,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+GBusReleaseNameReplyFlags g_dbus_release_name (GDBusConnection *connection,
+ const gchar *name,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gboolean g_dbus_add_match (GDBusConnection *connection,
+ const gchar *match_rule,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gboolean g_dbus_remove_match (GDBusConnection *connection,
+ const gchar *match_rule,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gchar *g_dbus_get_bus_id (GDBusConnection *connection,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gchar **g_dbus_get_list_names (GDBusConnection *connection,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gchar **g_dbus_get_list_activatable_names (GDBusConnection *connection,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gchar **g_dbus_get_list_queued_owners (GDBusConnection *connection,
+ const gchar *name,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+gchar *g_dbus_get_name_owner (GDBusConnection *connection,
+ const gchar *name,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+pid_t g_dbus_get_connection_pid (GDBusConnection *connection,
+ const gchar *name,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+uid_t g_dbus_get_connection_uid (GDBusConnection *connection,
+ const gchar *name,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
+/* GLIB_AVAILABLE_IN_2_44 */
+GBusStartServiceReplyFlags g_dbus_start_service_by_name (GDBusConnection *connection,
+ const gchar *name,
+ guint32 flags,
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
GLIB_AVAILABLE_IN_ALL
-void g_dbus_connection_start_message_processing (GDBusConnection *connection);
+void g_dbus_connection_start_message_processing (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_connection_is_closed (GDBusConnection *connection);
+gboolean g_dbus_connection_is_closed (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GIOStream *g_dbus_connection_get_stream (GDBusConnection *connection);
+GIOStream *g_dbus_connection_get_stream (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_connection_get_guid (GDBusConnection *connection);
+const gchar *g_dbus_connection_get_guid (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection);
+const gchar *g_dbus_connection_get_unique_name (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GCredentials *g_dbus_connection_get_peer_credentials (GDBusConnection *connection);
+GCredentials *g_dbus_connection_get_peer_credentials (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_34
-guint32 g_dbus_connection_get_last_serial (GDBusConnection *connection);
+guint32 g_dbus_connection_get_last_serial (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection);
+gboolean g_dbus_connection_get_exit_on_close (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_set_exit_on_close (GDBusConnection *connection,
- gboolean exit_on_close);
+ gboolean exit_on_close) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusCapabilityFlags g_dbus_connection_get_capabilities (GDBusConnection *connection);
+GDBusCapabilityFlags g_dbus_connection_get_capabilities (GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
void g_dbus_connection_close (GDBusConnection *connection,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_close_finish (GDBusConnection *connection,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_close_sync (GDBusConnection *connection,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
void g_dbus_connection_flush (GDBusConnection *connection,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_flush_finish (GDBusConnection *connection,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_flush_sync (GDBusConnection *connection,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
GDBusMessage *message,
GDBusSendMessageFlags flags,
volatile guint32 *out_serial,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_send_message_with_reply (GDBusConnection *connection,
GDBusMessage *message,
volatile guint32 *out_serial,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_connection_send_message_with_reply_finish (GDBusConnection *connection,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_connection_send_message_with_reply_sync (GDBusConnection *connection,
GDBusMessage *message,
gint timeout_msec,
volatile guint32 *out_serial,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
const gchar *interface_name,
const gchar *signal_name,
GVariant *parameters,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_call (GDBusConnection *connection,
const gchar *bus_name,
gint timeout_msec,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_connection_call_finish (GDBusConnection *connection,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_connection_call_sync (GDBusConnection *connection,
const gchar *bus_name,
GDBusCallFlags flags,
gint timeout_msec,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_30
void g_dbus_connection_call_with_unix_fd_list (GDBusConnection *connection,
const gchar *bus_name,
GUnixFDList *fd_list,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_30
GVariant *g_dbus_connection_call_with_unix_fd_list_finish (GDBusConnection *connection,
GUnixFDList **out_fd_list,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_30
GVariant *g_dbus_connection_call_with_unix_fd_list_sync (GDBusConnection *connection,
const gchar *bus_name,
GUnixFDList *fd_list,
GUnixFDList **out_fd_list,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
const GDBusInterfaceVTable *vtable,
gpointer user_data,
GDestroyNotify user_data_free_func,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_46
guint g_dbus_connection_register_object_with_closures (GDBusConnection *connection,
const gchar *object_path,
GClosure *method_call_closure,
GClosure *get_property_closure,
GClosure *set_property_closure,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_unregister_object (GDBusConnection *connection,
- guint registration_id);
+ guint registration_id) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
GDBusSubtreeFlags flags,
gpointer user_data,
GDestroyNotify user_data_free_func,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_connection_unregister_subtree (GDBusConnection *connection,
- guint registration_id);
+ guint registration_id) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
GDBusSignalFlags flags,
GDBusSignalCallback callback,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
+GLIB_AVAILABLE_IN_ALL
+guint g_dbus_connection_signal_subscribe_with_ref (GDBusConnection *connection,
+ const gchar *sender,
+ const gchar *interface_name,
+ const gchar *member,
+ const gchar *object_path,
+ const gchar *arg0,
+ GDBusSignalFlags flags,
+ GDBusSignalCallback callback,
+ gpointer user_data,
+ GFunc user_data_ref_func,
+ GFunc user_data_unref_func,
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_signal_unsubscribe (GDBusConnection *connection,
- guint subscription_id);
+ guint subscription_id) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
guint g_dbus_connection_add_filter (GDBusConnection *connection,
GDBusMessageFilterFunction filter_function,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_connection_remove_filter (GDBusConnection *connection,
- guint filter_id);
+ guint filter_id) TIZEN_PUBLIC_DEPRECATED_API;
/* ---------------------------------------------------------------------------------------------------- */
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
#define G_DBUS_ERROR g_dbus_error_quark()
GLIB_AVAILABLE_IN_ALL
-GQuark g_dbus_error_quark (void);
+GQuark g_dbus_error_quark (void) TIZEN_PUBLIC_DEPRECATED_API;
/* Used by applications to check, get and strip the D-Bus error name */
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_error_is_remote_error (const GError *error);
+gboolean g_dbus_error_is_remote_error (const GError *error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar *g_dbus_error_get_remote_error (const GError *error);
+gchar *g_dbus_error_get_remote_error (const GError *error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_error_strip_remote_error (GError *error);
+gboolean g_dbus_error_strip_remote_error (GError *error) TIZEN_PUBLIC_DEPRECATED_API;
/**
* GDBusErrorEntry:
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_error_register_error (GQuark error_domain,
gint error_code,
- const gchar *dbus_error_name);
+ const gchar *dbus_error_name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_error_unregister_error (GQuark error_domain,
gint error_code,
- const gchar *dbus_error_name);
+ const gchar *dbus_error_name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_error_register_error_domain (const gchar *error_domain_quark_name,
volatile gsize *quark_volatile,
const GDBusErrorEntry *entries,
- guint num_entries);
+ guint num_entries) TIZEN_PUBLIC_DEPRECATED_API;
/* Only used by object mappings to map back and forth to GError */
GLIB_AVAILABLE_IN_ALL
GError *g_dbus_error_new_for_dbus_error (const gchar *dbus_error_name,
- const gchar *dbus_error_message);
+ const gchar *dbus_error_message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_error_set_dbus_error (GError **error,
const gchar *dbus_error_name,
const gchar *dbus_error_message,
const gchar *format,
- ...) G_GNUC_PRINTF(4, 5);
+ ...) G_GNUC_PRINTF(4, 5) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_error_set_dbus_error_valist (GError **error,
const gchar *dbus_error_name,
const gchar *dbus_error_message,
const gchar *format,
- va_list var_args) G_GNUC_PRINTF(4, 0);
+ va_list var_args) G_GNUC_PRINTF(4, 0) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar *g_dbus_error_encode_gerror (const GError *error);
+gchar *g_dbus_error_encode_gerror (const GError *error) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_INTERFACE_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_interface_get_type (void) G_GNUC_CONST;
+GType g_dbus_interface_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceInfo *g_dbus_interface_get_info (GDBusInterface *interface_);
+GDBusInterfaceInfo *g_dbus_interface_get_info (GDBusInterface *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusObject *g_dbus_interface_get_object (GDBusInterface *interface_);
+GDBusObject *g_dbus_interface_get_object (GDBusInterface *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_interface_set_object (GDBusInterface *interface_,
- GDBusObject *object);
+ GDBusObject *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_32
-GDBusObject *g_dbus_interface_dup_object (GDBusInterface *interface_);
+GDBusObject *g_dbus_interface_dup_object (GDBusInterface *interface_) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_INTERFACE_SKELETON_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_interface_skeleton_get_type (void) G_GNUC_CONST;
+GType g_dbus_interface_skeleton_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceSkeletonFlags g_dbus_interface_skeleton_get_flags (GDBusInterfaceSkeleton *interface_);
+GDBusInterfaceSkeletonFlags g_dbus_interface_skeleton_get_flags (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_interface_skeleton_set_flags (GDBusInterfaceSkeleton *interface_,
- GDBusInterfaceSkeletonFlags flags);
+ GDBusInterfaceSkeletonFlags flags) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceInfo *g_dbus_interface_skeleton_get_info (GDBusInterfaceSkeleton *interface_);
+GDBusInterfaceInfo *g_dbus_interface_skeleton_get_info (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceVTable *g_dbus_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *interface_);
+GDBusInterfaceVTable *g_dbus_interface_skeleton_get_vtable (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GVariant *g_dbus_interface_skeleton_get_properties (GDBusInterfaceSkeleton *interface_);
+GVariant *g_dbus_interface_skeleton_get_properties (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_interface_skeleton_flush (GDBusInterfaceSkeleton *interface_);
+void g_dbus_interface_skeleton_flush (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_interface_skeleton_export (GDBusInterfaceSkeleton *interface_,
GDBusConnection *connection,
const gchar *object_path,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_);
+void g_dbus_interface_skeleton_unexport (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_interface_skeleton_unexport_from_connection (GDBusInterfaceSkeleton *interface_,
- GDBusConnection *connection);
+ GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusConnection *g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_);
+GDBusConnection *g_dbus_interface_skeleton_get_connection (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GList *g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_);
+GList *g_dbus_interface_skeleton_get_connections (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_interface_skeleton_has_connection (GDBusInterfaceSkeleton *interface_,
- GDBusConnection *connection);
+ GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_);
+const gchar *g_dbus_interface_skeleton_get_object_path (GDBusInterfaceSkeleton *interface_) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
const gchar *g_dbus_annotation_info_lookup (GDBusAnnotationInfo **annotations,
- const gchar *name);
+ const gchar *name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMethodInfo *g_dbus_interface_info_lookup_method (GDBusInterfaceInfo *info,
- const gchar *name);
+ const gchar *name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusSignalInfo *g_dbus_interface_info_lookup_signal (GDBusInterfaceInfo *info,
- const gchar *name);
+ const gchar *name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusPropertyInfo *g_dbus_interface_info_lookup_property (GDBusInterfaceInfo *info,
- const gchar *name);
+ const gchar *name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info);
+void g_dbus_interface_info_cache_build (GDBusInterfaceInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info);
+void g_dbus_interface_info_cache_release (GDBusInterfaceInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_interface_info_generate_xml (GDBusInterfaceInfo *info,
guint indent,
- GString *string_builder);
+ GString *string_builder) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusNodeInfo *g_dbus_node_info_new_for_xml (const gchar *xml_data,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusInterfaceInfo *g_dbus_node_info_lookup_interface (GDBusNodeInfo *info,
- const gchar *name);
+ const gchar *name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_node_info_generate_xml (GDBusNodeInfo *info,
guint indent,
- GString *string_builder);
+ GString *string_builder) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusNodeInfo *g_dbus_node_info_ref (GDBusNodeInfo *info);
+GDBusNodeInfo *g_dbus_node_info_ref (GDBusNodeInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceInfo *g_dbus_interface_info_ref (GDBusInterfaceInfo *info);
+GDBusInterfaceInfo *g_dbus_interface_info_ref (GDBusInterfaceInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMethodInfo *g_dbus_method_info_ref (GDBusMethodInfo *info);
+GDBusMethodInfo *g_dbus_method_info_ref (GDBusMethodInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusSignalInfo *g_dbus_signal_info_ref (GDBusSignalInfo *info);
+GDBusSignalInfo *g_dbus_signal_info_ref (GDBusSignalInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusPropertyInfo *g_dbus_property_info_ref (GDBusPropertyInfo *info);
+GDBusPropertyInfo *g_dbus_property_info_ref (GDBusPropertyInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusArgInfo *g_dbus_arg_info_ref (GDBusArgInfo *info);
+GDBusArgInfo *g_dbus_arg_info_ref (GDBusArgInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusAnnotationInfo *g_dbus_annotation_info_ref (GDBusAnnotationInfo *info);
+GDBusAnnotationInfo *g_dbus_annotation_info_ref (GDBusAnnotationInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_node_info_unref (GDBusNodeInfo *info);
+void g_dbus_node_info_unref (GDBusNodeInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_interface_info_unref (GDBusInterfaceInfo *info);
+void g_dbus_interface_info_unref (GDBusInterfaceInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_method_info_unref (GDBusMethodInfo *info);
+void g_dbus_method_info_unref (GDBusMethodInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_signal_info_unref (GDBusSignalInfo *info);
+void g_dbus_signal_info_unref (GDBusSignalInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_property_info_unref (GDBusPropertyInfo *info);
+void g_dbus_property_info_unref (GDBusPropertyInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_arg_info_unref (GDBusArgInfo *info);
+void g_dbus_arg_info_unref (GDBusArgInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_annotation_info_unref (GDBusAnnotationInfo *info);
+void g_dbus_annotation_info_unref (GDBusAnnotationInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
/**
* G_TYPE_DBUS_NODE_INFO:
#define G_TYPE_DBUS_ANNOTATION_INFO (g_dbus_annotation_info_get_type ())
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_node_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_node_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_interface_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_interface_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_method_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_method_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_signal_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_signal_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_property_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_property_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_arg_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_arg_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_annotation_info_get_type (void) G_GNUC_CONST;
+GType g_dbus_annotation_info_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_MENU_MODEL_H__
#include <gio/gdbusconnection.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
typedef struct _GDBusMenuModel GDBusMenuModel;
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_menu_model_get_type (void) G_GNUC_CONST;
+GType g_dbus_menu_model_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMenuModel * g_dbus_menu_model_get (GDBusConnection *connection,
const gchar *bus_name,
- const gchar *object_path);
+ const gchar *object_path) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
if (message->body != NULL)
{
gchar *tupled_signature_str;
- tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
if (signature == NULL)
{
g_set_error (error,
G_IO_ERROR_INVALID_ARGUMENT,
_("Message body has signature “%s” but there is no signature header"),
signature_str);
- g_free (tupled_signature_str);
goto out;
}
- else if (g_strcmp0 (tupled_signature_str, g_variant_get_type_string (message->body)) != 0)
+ tupled_signature_str = g_strdup_printf ("(%s)", signature_str);
+ if (g_strcmp0 (tupled_signature_str, g_variant_get_type_string (message->body)) != 0)
{
g_set_error (error,
G_IO_ERROR,
#endif
return ret;
}
+
+void
+g_dbus_message_init_header_iter (GDBusMessage *message,
+ GHashTableIter *iter)
+{
+ g_hash_table_iter_init (iter, message->headers);
+}
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
#define G_IS_DBUS_MESSAGE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_MESSAGE))
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_message_get_type (void) G_GNUC_CONST;
+GType g_dbus_message_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessage *g_dbus_message_new (void);
+GDBusMessage *g_dbus_message_new (void) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_signal (const gchar *path,
const gchar *interface_,
- const gchar *signal);
+ const gchar *signal) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_method_call (const gchar *name,
const gchar *path,
const gchar *interface_,
- const gchar *method);
+ const gchar *method) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessage *g_dbus_message_new_method_reply (GDBusMessage *method_call_message);
+GDBusMessage *g_dbus_message_new_method_reply (GDBusMessage *method_call_message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_method_error (GDBusMessage *method_call_message,
const gchar *error_name,
const gchar *error_message_format,
- ...) G_GNUC_PRINTF(3, 4);
+ ...) G_GNUC_PRINTF(3, 4) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_method_error_valist (GDBusMessage *method_call_message,
const gchar *error_name,
const gchar *error_message_format,
- va_list var_args);
+ va_list var_args) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_method_error_literal (GDBusMessage *method_call_message,
const gchar *error_name,
- const gchar *error_message);
+ const gchar *error_message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gchar *g_dbus_message_print (GDBusMessage *message,
- guint indent);
+ guint indent) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_message_get_locked (GDBusMessage *message);
+gboolean g_dbus_message_get_locked (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_message_lock (GDBusMessage *message);
+void g_dbus_message_lock (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_copy (GDBusMessage *message,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessageByteOrder g_dbus_message_get_byte_order (GDBusMessage *message);
+GDBusMessageByteOrder g_dbus_message_get_byte_order (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_byte_order (GDBusMessage *message,
- GDBusMessageByteOrder byte_order);
+ GDBusMessageByteOrder byte_order) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessageType g_dbus_message_get_message_type (GDBusMessage *message);
+GDBusMessageType g_dbus_message_get_message_type (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_message_type (GDBusMessage *message,
- GDBusMessageType type);
+ GDBusMessageType type) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessageFlags g_dbus_message_get_flags (GDBusMessage *message);
+GDBusMessageFlags g_dbus_message_get_flags (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_flags (GDBusMessage *message,
- GDBusMessageFlags flags);
+ GDBusMessageFlags flags) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-guint32 g_dbus_message_get_serial (GDBusMessage *message);
+guint32 g_dbus_message_get_serial (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_serial (GDBusMessage *message,
- guint32 serial);
+ guint32 serial) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_message_get_header (GDBusMessage *message,
- GDBusMessageHeaderField header_field);
+ GDBusMessageHeaderField header_field) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_header (GDBusMessage *message,
GDBusMessageHeaderField header_field,
- GVariant *value);
+ GVariant *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-guchar *g_dbus_message_get_header_fields (GDBusMessage *message);
+guchar *g_dbus_message_get_header_fields (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GVariant *g_dbus_message_get_body (GDBusMessage *message);
+GVariant *g_dbus_message_get_body (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_body (GDBusMessage *message,
- GVariant *body);
+ GVariant *body) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GUnixFDList *g_dbus_message_get_unix_fd_list (GDBusMessage *message);
+GUnixFDList *g_dbus_message_get_unix_fd_list (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_unix_fd_list (GDBusMessage *message,
- GUnixFDList *fd_list);
+ GUnixFDList *fd_list) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-guint32 g_dbus_message_get_reply_serial (GDBusMessage *message);
+guint32 g_dbus_message_get_reply_serial (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_reply_serial (GDBusMessage *message,
- guint32 value);
+ guint32 value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_interface (GDBusMessage *message);
+const gchar *g_dbus_message_get_interface (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_interface (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_member (GDBusMessage *message);
+const gchar *g_dbus_message_get_member (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_member (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_path (GDBusMessage *message);
+const gchar *g_dbus_message_get_path (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_path (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_sender (GDBusMessage *message);
+const gchar *g_dbus_message_get_sender (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_sender (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_destination (GDBusMessage *message);
+const gchar *g_dbus_message_get_destination (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_destination (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_error_name (GDBusMessage *message);
+const gchar *g_dbus_message_get_error_name (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_error_name (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_signature (GDBusMessage *message);
+const gchar *g_dbus_message_get_signature (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_signature (GDBusMessage *message,
- const gchar *value);
+ const gchar *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-guint32 g_dbus_message_get_num_unix_fds (GDBusMessage *message);
+guint32 g_dbus_message_get_num_unix_fds (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_message_set_num_unix_fds (GDBusMessage *message,
- guint32 value);
+ guint32 value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_message_get_arg0 (GDBusMessage *message);
+const gchar *g_dbus_message_get_arg0 (GDBusMessage *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusMessage *g_dbus_message_new_from_blob (guchar *blob,
gsize blob_len,
GDBusCapabilityFlags capabilities,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gssize g_dbus_message_bytes_needed (guchar *blob,
gsize blob_len,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guchar *g_dbus_message_to_blob (GDBusMessage *message,
gsize *out_size,
GDBusCapabilityFlags capabilities,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_message_to_gerror (GDBusMessage *message,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
}
/**
+ * g_dbus_method_invocation_peek_unix_fd:
+ * @invocation: A #GDBusMethodInvocation.
+ * @index_: the index
+ *
+ * Gets the fd associated with @index in the method invocation.
+ *
+ * If there is no file descriptor at the given index, -1 is returned.
+ *
+ * The returned file descriptor is owned by the message and must not be
+ * closed by the caller. Use dup() if you want your own copy.
+ *
+ * Returns: the file descriptor, or -1
+ */
+#ifdef G_OS_UNIX
+gint
+g_dbus_method_invocation_peek_unix_fd (GDBusMethodInvocation *invocation,
+ guint index_)
+{
+ GUnixFDList *fd_list;
+
+ fd_list = g_dbus_message_get_unix_fd_list (invocation->message);
+
+ if (fd_list)
+ {
+ const gint *fds;
+ gint n_fds;
+
+ fds = g_unix_fd_list_peek_fds (fd_list, &n_fds);
+
+ if (index_ < (guint) n_fds)
+ return fds[index_];
+ }
+
+ return -1;
+}
+#endif
+
+/**
* g_dbus_method_invocation_get_user_data: (skip)
* @invocation: A #GDBusMethodInvocation.
*
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
#define G_IS_DBUS_METHOD_INVOCATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_METHOD_INVOCATION))
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_method_invocation_get_type (void) G_GNUC_CONST;
+GType g_dbus_method_invocation_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_method_invocation_get_sender (GDBusMethodInvocation *invocation);
+const gchar *g_dbus_method_invocation_get_sender (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_method_invocation_get_object_path (GDBusMethodInvocation *invocation);
+const gchar *g_dbus_method_invocation_get_object_path (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_method_invocation_get_interface_name (GDBusMethodInvocation *invocation);
+const gchar *g_dbus_method_invocation_get_interface_name (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_method_invocation_get_method_name (GDBusMethodInvocation *invocation);
+const gchar *g_dbus_method_invocation_get_method_name (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const GDBusMethodInfo *g_dbus_method_invocation_get_method_info (GDBusMethodInvocation *invocation);
+const GDBusMethodInfo *g_dbus_method_invocation_get_method_info (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_2_38
-const GDBusPropertyInfo *g_dbus_method_invocation_get_property_info (GDBusMethodInvocation *invocation);
+const GDBusPropertyInfo *g_dbus_method_invocation_get_property_info (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusConnection *g_dbus_method_invocation_get_connection (GDBusMethodInvocation *invocation);
+GDBusConnection *g_dbus_method_invocation_get_connection (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusMessage *g_dbus_method_invocation_get_message (GDBusMethodInvocation *invocation);
+GDBusMessage *g_dbus_method_invocation_get_message (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GVariant *g_dbus_method_invocation_get_parameters (GDBusMethodInvocation *invocation);
+GVariant *g_dbus_method_invocation_get_parameters (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
+#ifdef G_OS_UNIX
+GLIB_AVAILABLE_IN_2_44
+gint g_dbus_method_invocation_peek_unix_fd (GDBusMethodInvocation *invocation,
+ guint index_) TIZEN_PUBLIC_DEPRECATED_API;
+#endif
GLIB_AVAILABLE_IN_ALL
-gpointer g_dbus_method_invocation_get_user_data (GDBusMethodInvocation *invocation);
+gpointer g_dbus_method_invocation_get_user_data (GDBusMethodInvocation *invocation) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_value (GDBusMethodInvocation *invocation,
- GVariant *parameters);
+ GVariant *parameters) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_value_with_unix_fd_list (GDBusMethodInvocation *invocation,
GVariant *parameters,
- GUnixFDList *fd_list);
+ GUnixFDList *fd_list) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_error (GDBusMethodInvocation *invocation,
GQuark domain,
gint code,
const gchar *format,
- ...) G_GNUC_PRINTF(4, 5);
+ ...) G_GNUC_PRINTF(4, 5) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_error_valist (GDBusMethodInvocation *invocation,
GQuark domain,
gint code,
const gchar *format,
va_list var_args)
- G_GNUC_PRINTF(4, 0);
+ G_GNUC_PRINTF(4, 0) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_error_literal (GDBusMethodInvocation *invocation,
GQuark domain,
gint code,
- const gchar *message);
+ const gchar *message) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_gerror (GDBusMethodInvocation *invocation,
- const GError *error);
+ const GError *error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_take_error (GDBusMethodInvocation *invocation,
- GError *error);
+ GError *error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_method_invocation_return_dbus_error (GDBusMethodInvocation *invocation,
const gchar *error_name,
- const gchar *error_message);
+ const gchar *error_message) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
GBusNameAcquiredCallback name_acquired_handler,
GBusNameLostCallback name_lost_handler,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_own_name_on_connection (GDBusConnection *connection,
GBusNameAcquiredCallback name_acquired_handler,
GBusNameLostCallback name_lost_handler,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_own_name_with_closures (GBusType bus_type,
GBusNameOwnerFlags flags,
GClosure *bus_acquired_closure,
GClosure *name_acquired_closure,
- GClosure *name_lost_closure);
+ GClosure *name_lost_closure) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_own_name_on_connection_with_closures (
const gchar *name,
GBusNameOwnerFlags flags,
GClosure *name_acquired_closure,
- GClosure *name_lost_closure);
+ GClosure *name_lost_closure) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_bus_unown_name (guint owner_id);
+void g_bus_unown_name (guint owner_id) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
}
}
+static void
+client_ref_func (gpointer user_data, gpointer unused)
+{
+ if (user_data)
+ client_ref ((Client*)user_data);
+}
+
+static void
+client_unref_func (gpointer user_data, gpointer unused)
+{
+ if (user_data)
+ client_unref ((Client*)user_data);
+}
+
/* ---------------------------------------------------------------------------------------------------- */
typedef enum
const gchar *old_owner;
const gchar *new_owner;
- if (!client->initialized)
- goto out;
-
if (g_strcmp0 (object_path, "/org/freedesktop/DBus") != 0 ||
g_strcmp0 (interface_name, "org.freedesktop.DBus") != 0 ||
g_strcmp0 (sender_name, "org.freedesktop.DBus") != 0)
if (g_strcmp0 (name, client->name) != 0)
goto out;
- if ((old_owner != NULL && strlen (old_owner) > 0) && client->name_owner != NULL)
+ if (old_owner != NULL && strlen (old_owner) > 0)
{
g_free (client->name_owner);
client->name_owner = NULL;
if (new_owner != NULL && strlen (new_owner) > 0)
{
- g_warn_if_fail (client->name_owner == NULL);
g_free (client->name_owner);
client->name_owner = g_strdup (new_owner);
call_appeared_handler (client);
}
+ /* initialized set to TRUE means that signal was delivered and processed.
+ * Now, if we receive a reply to GetNameOwner call, we may just ignore it as it carries the same
+ * information as the current signal, or if something changed in the meantime we will
+ * get next signal very soon.
+ */
+ client->initialized = TRUE;
+
out:
;
}
result = g_dbus_connection_call_finish (client->connection,
res,
NULL);
+ /* In case we already received NameOwnerChanged signal, we don't need to
+ * process GetNameOwner answer, because all the information we needed was already
+ * delivered with the signal and processed by the signal handler.
+ */
+ if (client->initialized)
+ goto out;
+
if (result != NULL)
{
g_variant_get (result, "(&s)", &name_owner);
call_vanished_handler (client, FALSE);
}
- client->initialized = TRUE;
-
+ out:
if (result != NULL)
g_variant_unref (result);
+
client_unref (client);
}
{
g_warning ("Unexpected reply %d from StartServiceByName() method", start_service_result);
call_vanished_handler (client, FALSE);
- client->initialized = TRUE;
}
}
else
client);
/* start listening to NameOwnerChanged messages immediately */
- client->name_owner_changed_subscription_id = g_dbus_connection_signal_subscribe (client->connection,
- "org.freedesktop.DBus", /* name */
- "org.freedesktop.DBus", /* if */
- "NameOwnerChanged", /* signal */
- "/org/freedesktop/DBus", /* path */
- client->name,
- G_DBUS_SIGNAL_FLAGS_NONE,
- on_name_owner_changed,
- client,
- NULL);
+ client->name_owner_changed_subscription_id
+ = g_dbus_connection_signal_subscribe_with_ref (client->connection,
+ "org.freedesktop.DBus", /* name */
+ "org.freedesktop.DBus", /* if */
+ "NameOwnerChanged", /* signal */
+ "/org/freedesktop/DBus", /* path */
+ client->name,
+ G_DBUS_SIGNAL_FLAGS_NONE,
+ on_name_owner_changed,
+ client,
+ client_ref_func,
+ client_unref_func,
+ NULL);
if (client->flags & G_BUS_NAME_WATCHER_FLAGS_AUTO_START)
{
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
GBusNameAppearedCallback name_appeared_handler,
GBusNameVanishedCallback name_vanished_handler,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_watch_name_on_connection (GDBusConnection *connection,
const gchar *name,
GBusNameAppearedCallback name_appeared_handler,
GBusNameVanishedCallback name_vanished_handler,
gpointer user_data,
- GDestroyNotify user_data_free_func);
+ GDestroyNotify user_data_free_func) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_watch_name_with_closures (GBusType bus_type,
const gchar *name,
GBusNameWatcherFlags flags,
GClosure *name_appeared_closure,
- GClosure *name_vanished_closure);
+ GClosure *name_vanished_closure) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
guint g_bus_watch_name_on_connection_with_closures (
GDBusConnection *connection,
const gchar *name,
GBusNameWatcherFlags flags,
GClosure *name_appeared_closure,
- GClosure *name_vanished_closure);
+ GClosure *name_vanished_closure) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_bus_unwatch_name (guint watcher_id);
+void g_bus_unwatch_name (guint watcher_id) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_OBJECT_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_object_get_type (void) G_GNUC_CONST;
+GType g_dbus_object_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_object_get_object_path (GDBusObject *object);
+const gchar *g_dbus_object_get_object_path (GDBusObject *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GList *g_dbus_object_get_interfaces (GDBusObject *object);
+GList *g_dbus_object_get_interfaces (GDBusObject *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusInterface *g_dbus_object_get_interface (GDBusObject *object,
- const gchar *interface_name);
+ const gchar *interface_name) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_OBJECT_MANAGER_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_object_manager_get_type (void) G_GNUC_CONST;
+GType g_dbus_object_manager_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_object_manager_get_object_path (GDBusObjectManager *manager);
+const gchar *g_dbus_object_manager_get_object_path (GDBusObjectManager *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GList *g_dbus_object_manager_get_objects (GDBusObjectManager *manager);
+GList *g_dbus_object_manager_get_objects (GDBusObjectManager *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusObject *g_dbus_object_manager_get_object (GDBusObjectManager *manager,
- const gchar *object_path);
+ const gchar *object_path) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusInterface *g_dbus_object_manager_get_interface (GDBusObjectManager *manager,
const gchar *object_path,
- const gchar *interface_name);
+ const gchar *interface_name) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
const gchar *name_owner)
{
GError *error = NULL;
- GVariant *ret;
g_return_if_fail (G_IS_DBUS_OBJECT_MANAGER_CLIENT (manager));
g_return_if_fail (manager->priv->signal_subscription_id == 0);
/* The bus daemon may not implement path_namespace so gracefully
* handle this by using a fallback triggered if @error is set. */
- ret = g_dbus_connection_call_sync (manager->priv->connection,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "AddMatch",
- g_variant_new ("(s)",
- manager->priv->match_rule),
- NULL, /* reply_type */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* default timeout */
- NULL, /* TODO: Cancellable */
- &error);
-
- /* yay, bus daemon supports path_namespace */
- if (ret != NULL)
- g_variant_unref (ret);
+ g_dbus_add_match (manager->priv->connection, manager->priv->match_rule, &error);
}
if (error == NULL)
/* Since the AddMatch call succeeded this is guaranteed to not
* fail - therefore, don't bother checking the return value
*/
- g_dbus_connection_call (manager->priv->connection,
- "org.freedesktop.DBus",
- "/org/freedesktop/DBus",
- "org.freedesktop.DBus",
- "RemoveMatch",
- g_variant_new ("(s)",
- manager->priv->match_rule),
- NULL, /* reply_type */
- G_DBUS_CALL_FLAGS_NONE,
- -1, /* default timeout */
- NULL, /* GCancellable */
- NULL, /* GAsyncReadyCallback */
- NULL); /* user data */
+ g_dbus_remove_match (manager->priv->connection,
+ manager->priv->match_rule,
+ NULL);
g_free (manager->priv->match_rule);
manager->priv->match_rule = NULL;
}
g_variant_unref (properties);
}
+ if (added)
+ {
+ g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
+ g_strdup (object_path),
+ op);
+ }
+
g_mutex_unlock (&manager->priv->lock);
/* now that we don't hold the lock any more, emit signals */
g_list_free (interface_added_signals);
if (added)
- {
- g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
- g_strdup (object_path),
- op);
- g_signal_emit_by_name (manager, "object-added", op);
- }
+ g_signal_emit_by_name (manager, "object-added", op);
+
g_object_unref (manager);
g_object_unref (op);
}
#define __G_DBUS_OBJECT_MANAGER_CLIENT_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_object_manager_client_get_type (void) G_GNUC_CONST;
+GType g_dbus_object_manager_client_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_object_manager_client_new (GDBusConnection *connection,
GDBusObjectManagerClientFlags flags,
GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusObjectManager *g_dbus_object_manager_client_new_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusObjectManager *g_dbus_object_manager_client_new_sync (GDBusConnection *connection,
GDBusObjectManagerClientFlags flags,
gpointer get_proxy_type_user_data,
GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_object_manager_client_new_for_bus (GBusType bus_type,
GDBusObjectManagerClientFlags flags,
GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusObjectManager *g_dbus_object_manager_client_new_for_bus_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusObjectManager *g_dbus_object_manager_client_new_for_bus_sync (GBusType bus_type,
GDBusObjectManagerClientFlags flags,
gpointer get_proxy_type_user_data,
GDestroyNotify get_proxy_type_destroy_notify,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusConnection *g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager);
+GDBusConnection *g_dbus_object_manager_client_get_connection (GDBusObjectManagerClient *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusObjectManagerClientFlags g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager);
+GDBusObjectManagerClientFlags g_dbus_object_manager_client_get_flags (GDBusObjectManagerClient *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager);
+const gchar *g_dbus_object_manager_client_get_name (GDBusObjectManagerClient *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar *g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager);
+gchar *g_dbus_object_manager_client_get_name_owner (GDBusObjectManagerClient *manager) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#define __G_DBUS_OBJECT_MANAGER_SERVER_H__
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_object_manager_server_get_type (void) G_GNUC_CONST;
+GType g_dbus_object_manager_server_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusObjectManagerServer *g_dbus_object_manager_server_new (const gchar *object_path);
+GDBusObjectManagerServer *g_dbus_object_manager_server_new (const gchar *object_path) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusConnection *g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager);
+GDBusConnection *g_dbus_object_manager_server_get_connection (GDBusObjectManagerServer *manager) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_object_manager_server_set_connection (GDBusObjectManagerServer *manager,
- GDBusConnection *connection);
+ GDBusConnection *connection) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_object_manager_server_export (GDBusObjectManagerServer *manager,
- GDBusObjectSkeleton *object);
+ GDBusObjectSkeleton *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_object_manager_server_export_uniquely (GDBusObjectManagerServer *manager,
- GDBusObjectSkeleton *object);
+ GDBusObjectSkeleton *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_object_manager_server_is_exported (GDBusObjectManagerServer *manager,
- GDBusObjectSkeleton *object);
+ GDBusObjectSkeleton *object) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
gboolean g_dbus_object_manager_server_unexport (GDBusObjectManagerServer *manager,
- const gchar *object_path);
+ const gchar *object_path) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
GError *error)
{
if (!g_atomic_int_get (&worker->stopped))
- worker->disconnected_callback (worker, remote_peer_vanished, error, worker->user_data);
+ worker->disconnected_callback (remote_peer_vanished, error, worker->user_data);
}
static void
GDBusMessage *message)
{
if (!g_atomic_int_get (&worker->stopped))
- worker->message_received_callback (worker, message, worker->user_data);
+ worker->message_received_callback (message, worker->user_data);
}
static GDBusMessage *
{
GDBusMessage *ret;
if (!g_atomic_int_get (&worker->stopped))
- ret = worker->message_about_to_be_sent_callback (worker, message, worker->user_data);
+ ret = worker->message_about_to_be_sent_callback (message, worker->user_data);
else
ret = message;
return ret;
typedef struct GDBusWorker GDBusWorker;
-typedef void (*GDBusWorkerMessageReceivedCallback) (GDBusWorker *worker,
- GDBusMessage *message,
+typedef void (*GDBusWorkerMessageReceivedCallback) (GDBusMessage *message,
gpointer user_data);
-typedef GDBusMessage *(*GDBusWorkerMessageAboutToBeSentCallback) (GDBusWorker *worker,
- GDBusMessage *message,
+typedef GDBusMessage *(*GDBusWorkerMessageAboutToBeSentCallback) (GDBusMessage *message,
gpointer user_data);
-typedef void (*GDBusWorkerDisconnectedCallback) (GDBusWorker *worker,
- gboolean remote_peer_vanished,
+typedef void (*GDBusWorkerDisconnectedCallback) (gboolean remote_peer_vanished,
GError *error,
gpointer user_data);
/* Implemented in gdbusconnection.c */
GDBusConnection *_g_bus_get_singleton_if_exists (GBusType bus_type);
+void g_dbus_message_init_header_iter (GDBusMessage *message,
+ GHashTableIter *iter);
+
+GObject *
+g_dbus_address_get_stream_internal (const gchar *address,
+ gboolean kdbus_okay,
+ gchar **out_uuid,
+ GCancellable *cancellable,
+ GError **error);
+
+
G_END_DECLS
#endif /* __G_DBUS_PRIVATE_H__ */
static const gchar *
get_destination_for_call (GDBusProxy *proxy)
{
- const gchar *ret;
-
- ret = NULL;
-
- /* If proxy->priv->name is a unique name, then proxy->priv->name_owner
- * is never NULL and always the same as proxy->priv->name. We use this
- * knowledge to avoid checking if proxy->priv->name is a unique or
- * well-known name.
- */
- ret = proxy->priv->name_owner;
- if (ret != NULL)
- goto out;
-
if (proxy->priv->flags & G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START)
- goto out;
-
- ret = proxy->priv->name;
+ return proxy->priv->name_owner;
- out:
- return ret;
+ return proxy->priv->name;
}
/* ---------------------------------------------------------------------------------------------------- */
#include <gio/giotypes.h>
#include <gio/gdbusintrospection.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
};
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_proxy_get_type (void) G_GNUC_CONST;
+GType g_dbus_proxy_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_new (GDBusConnection *connection,
GDBusProxyFlags flags,
const gchar *interface_name,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusProxy *g_dbus_proxy_new_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusProxy *g_dbus_proxy_new_sync (GDBusConnection *connection,
GDBusProxyFlags flags,
const gchar *object_path,
const gchar *interface_name,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_new_for_bus (GBusType bus_type,
GDBusProxyFlags flags,
const gchar *interface_name,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusProxy *g_dbus_proxy_new_for_bus_finish (GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusProxy *g_dbus_proxy_new_for_bus_sync (GBusType bus_type,
GDBusProxyFlags flags,
const gchar *object_path,
const gchar *interface_name,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusConnection *g_dbus_proxy_get_connection (GDBusProxy *proxy);
+GDBusConnection *g_dbus_proxy_get_connection (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusProxyFlags g_dbus_proxy_get_flags (GDBusProxy *proxy);
+GDBusProxyFlags g_dbus_proxy_get_flags (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_proxy_get_name (GDBusProxy *proxy);
+const gchar *g_dbus_proxy_get_name (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar *g_dbus_proxy_get_name_owner (GDBusProxy *proxy);
+gchar *g_dbus_proxy_get_name_owner (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_proxy_get_object_path (GDBusProxy *proxy);
+const gchar *g_dbus_proxy_get_object_path (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_proxy_get_interface_name (GDBusProxy *proxy);
+const gchar *g_dbus_proxy_get_interface_name (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gint g_dbus_proxy_get_default_timeout (GDBusProxy *proxy);
+gint g_dbus_proxy_get_default_timeout (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_set_default_timeout (GDBusProxy *proxy,
- gint timeout_msec);
+ gint timeout_msec) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusInterfaceInfo *g_dbus_proxy_get_interface_info (GDBusProxy *proxy);
+GDBusInterfaceInfo *g_dbus_proxy_get_interface_info (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_set_interface_info (GDBusProxy *proxy,
- GDBusInterfaceInfo *info);
+ GDBusInterfaceInfo *info) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_proxy_get_cached_property (GDBusProxy *proxy,
- const gchar *property_name);
+ const gchar *property_name) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_set_cached_property (GDBusProxy *proxy,
const gchar *property_name,
- GVariant *value);
+ GVariant *value) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar **g_dbus_proxy_get_cached_property_names (GDBusProxy *proxy);
+gchar **g_dbus_proxy_get_cached_property_names (GDBusProxy *proxy) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_call (GDBusProxy *proxy,
const gchar *method_name,
gint timeout_msec,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_proxy_call_finish (GDBusProxy *proxy,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_proxy_call_sync (GDBusProxy *proxy,
const gchar *method_name,
GDBusCallFlags flags,
gint timeout_msec,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_proxy_call_with_unix_fd_list (GDBusProxy *proxy,
GUnixFDList *fd_list,
GCancellable *cancellable,
GAsyncReadyCallback callback,
- gpointer user_data);
+ gpointer user_data) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_proxy_call_with_unix_fd_list_finish (GDBusProxy *proxy,
GUnixFDList **out_fd_list,
GAsyncResult *res,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_proxy_call_with_unix_fd_list_sync (GDBusProxy *proxy,
const gchar *method_name,
GUnixFDList *fd_list,
GUnixFDList **out_fd_list,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
#define G_IS_DBUS_SERVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_SERVER))
GLIB_AVAILABLE_IN_ALL
-GType g_dbus_server_get_type (void) G_GNUC_CONST;
+GType g_dbus_server_get_type (void) G_GNUC_CONST TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GDBusServer *g_dbus_server_new_sync (const gchar *address,
GDBusServerFlags flags,
const gchar *guid,
GDBusAuthObserver *observer,
GCancellable *cancellable,
- GError **error);
+ GError **error) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_server_get_client_address (GDBusServer *server);
+const gchar *g_dbus_server_get_client_address (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-const gchar *g_dbus_server_get_guid (GDBusServer *server);
+const gchar *g_dbus_server_get_guid (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-GDBusServerFlags g_dbus_server_get_flags (GDBusServer *server);
+GDBusServerFlags g_dbus_server_get_flags (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_server_start (GDBusServer *server);
+void g_dbus_server_start (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-void g_dbus_server_stop (GDBusServer *server);
+void g_dbus_server_stop (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_server_is_active (GDBusServer *server);
+gboolean g_dbus_server_is_active (GDBusServer *server) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
g_value_set_uint64 (out_gvalue, g_variant_get_uint64 (value));
break;
+ case G_VARIANT_CLASS_FLOAT:
+ g_value_init (out_gvalue, G_TYPE_FLOAT);
+ g_value_set_float (out_gvalue, g_variant_get_float (value));
+ break;
+
case G_VARIANT_CLASS_DOUBLE:
g_value_init (out_gvalue, G_TYPE_DOUBLE);
g_value_set_double (out_gvalue, g_variant_get_double (value));
ret = g_variant_ref_sink (g_variant_new_uint64 (g_value_get_uint64 (gvalue)));
break;
+ case G_VARIANT_CLASS_FLOAT:
+ ret = g_variant_ref_sink (g_variant_new_float (g_value_get_float (gvalue)));
+ break;
+
case G_VARIANT_CLASS_DOUBLE:
ret = g_variant_ref_sink (g_variant_new_double (g_value_get_double (gvalue)));
break;
#endif
#include <gio/giotypes.h>
+#include <gio/tizen_header_glib.h> /* for TIZEN_PUBLIC_DEPRECATED_API */
G_BEGIN_DECLS
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_guid (const gchar *string);
+gboolean g_dbus_is_guid (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gchar *g_dbus_generate_guid (void);
+gchar *g_dbus_generate_guid (void) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_name (const gchar *string);
+gboolean g_dbus_is_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_unique_name (const gchar *string);
+gboolean g_dbus_is_unique_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_member_name (const gchar *string);
+gboolean g_dbus_is_member_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
-gboolean g_dbus_is_interface_name (const gchar *string);
+gboolean g_dbus_is_interface_name (const gchar *string) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
void g_dbus_gvariant_to_gvalue (GVariant *value,
- GValue *out_gvalue);
+ GValue *out_gvalue) TIZEN_PUBLIC_DEPRECATED_API;
GLIB_AVAILABLE_IN_ALL
GVariant *g_dbus_gvalue_to_gvariant (const GValue *gvalue,
- const GVariantType *type);
+ const GVariantType *type) TIZEN_PUBLIC_DEPRECATED_API;
G_END_DECLS
out = (GOutputStream*)_g_local_file_output_stream_replace (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
FALSE, NULL,
flags & G_FILE_COPY_BACKUP,
- G_FILE_CREATE_REPLACE_DESTINATION,
- info,
+ G_FILE_CREATE_REPLACE_DESTINATION |
+ G_FILE_CREATE_PRIVATE, info,
cancellable, error);
else
out = (GOutputStream*)_g_local_file_output_stream_create (_g_local_file_get_filename (G_LOCAL_FILE (destination)),
- FALSE, 0, info,
+ FALSE, G_FILE_CREATE_PRIVATE, info,
cancellable, error);
}
else if (flags & G_FILE_COPY_OVERWRITE)
}
else
{
- out = (GOutputStream *)g_file_create (destination, 0, cancellable, error);
+ out = (GOutputStream *)g_file_create (destination, G_FILE_CREATE_PRIVATE, cancellable, error);
}
if (!out)
* @G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT: Allow another message bus connection to claim the name.
* @G_BUS_NAME_OWNER_FLAGS_REPLACE: If another message bus connection owns the name and have
* specified #G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT, then take the name from the other connection.
+ * @G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE: Do not place message bus connection in a queue to own the name.
*
* Flags used in g_bus_own_name().
*
{
G_BUS_NAME_OWNER_FLAGS_NONE = 0, /*< nick=none >*/
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT = (1<<0), /*< nick=allow-replacement >*/
- G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1) /*< nick=replace >*/
+ G_BUS_NAME_OWNER_FLAGS_REPLACE = (1<<1), /*< nick=replace >*/
+ G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE = (1<<2) /*< nick=do-not-queue >*/
} GBusNameOwnerFlags;
/**
+ * GBusRequestNameReplyFlags:
+ * @G_BUS_REQUEST_NAME_FLAGS_ERROR: Error flag.
+ * @G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER: Caller is now the primary owner of the name, replacing
+ * any previous owner.
+ * @G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE: The name already had an owner, the application will be
+ * placed in a queue.
+ * @G_BUS_REQUEST_NAME_FLAGS_EXISTS: The name already has an owner.
+ * @G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER: The application trying to request ownership of a name
+ * is already the owner of it.
+ *
+ * Flags used in g_dbus_request_name().
+ *
+ * Since: 2.44
+ */
+typedef enum
+{
+ G_BUS_REQUEST_NAME_FLAGS_ERROR = 0,
+ G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER = 1,
+ G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE = 2,
+ G_BUS_REQUEST_NAME_FLAGS_EXISTS = 3,
+ G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER = 4
+} GBusRequestNameReplyFlags;
+
+/**
+ * GBusReleaseNameReplyFlags:
+ * @G_BUS_RELEASE_NAME_FLAGS_ERROR: Error flag.
+ * @G_BUS_RELEASE_NAME_FLAGS_RELEASED: The caller has released his claim on the given name.
+ * @G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT: The given name does not exist on this bus.
+ * @G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER: The caller not waiting in the queue to own this name.
+ *
+ * Flags used in g_dbus_release_name().
+ *
+ * Since: 2.44
+ */
+typedef enum
+{
+ G_BUS_RELEASE_NAME_FLAGS_ERROR = 0,
+ G_BUS_RELEASE_NAME_FLAGS_RELEASED = 1,
+ G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT = 2,
+ G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER = 3
+} GBusReleaseNameReplyFlags;
+
+/**
+ * GBusStartServiceReplyFlags:
+ * @G_BUS_START_SERVICE_REPLY_ERROR: Error flag.
+ * @G_BUS_START_SERVICE_REPLY_SUCCESS: The service was successfully started.
+ * @G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING: A connection already owns the given name.
+ *
+ * Flags used in g_dbus_start_service_by_name().
+ *
+ * Since: 2.44
+ */
+typedef enum
+{
+ G_BUS_START_SERVICE_REPLY_ERROR = 0,
+ G_BUS_START_SERVICE_REPLY_SUCCESS = 1,
+ G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING = 2
+} GBusStartServiceReplyFlags;
+
+/**
* GBusNameWatcherFlags:
* @G_BUS_NAME_WATCHER_FLAGS_NONE: No flags set.
* @G_BUS_NAME_WATCHER_FLAGS_AUTO_START: If no-one owns the name when
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Lukasz Skalski <l.skalski@samsung.com>
+ * Author: Adrian Szyndela <adrian.s@samsung.com>
+ * Author: Michal Eljasiewicz <m.eljasiewic@samsung.com>
+ */
+
+#include "config.h"
+#include "gdbusconnection.h" /* DBUS_DEFAULT_TIMEOUT_MSEC */
+#include "gkdbus.h"
+#include "glib-unix.h"
+#include "glib-linux.h"
+#include "glibintl.h"
+#include <linux/kdbus.h>
+
+#include <gio/gio.h>
+#include <errno.h>
+#include <string.h>
+#include <sys/mman.h>
+#include <sys/ioctl.h>
+#include <stdio.h>
+#include <stdint.h>
+
+#ifdef HAVE_SYS_FILIO_H
+#include <sys/filio.h>
+#endif
+
+#ifdef HAVE_SYS_UIO_H
+#include <sys/uio.h>
+#endif
+
+#ifdef LIBDBUSPOLICY
+#include <dbuspolicy/libdbuspolicy1.h>
+#endif
+
+#define DBUS_DAEMON_EMULATION
+#ifdef DBUS_DAEMON_EMULATION
+#include "gkdbusfakedaemon.h"
+#endif
+
+#include <glib/gstdio.h>
+#include <glib/glib-private.h>
+#include <gio/gio.h>
+#include <gio/gunixfdlist.h>
+
+#include "glibintl.h"
+#include "gunixfdmessage.h"
+
+#define KDBUS_MSG_MAX_SIZE 8192
+#define KDBUS_INFINITE_TIMEOUT_NS 0x3fffffffffffffffLLU
+
+#define RECEIVE_POOL_SIZE_DEFAULT_SIZE (16 * 1024LU * 1024LU)
+#define RECEIVE_POOL_SIZE_ENV_VAR_NAME "KDBUS_MEMORY_POOL_SIZE"
+#define RECEIVE_POOL_SIZE_MAX_MBYTES 64
+#define RECEIVE_POOL_SIZE_MIN_KBYTES 16
+
+#define KDBUS_MEMFD_THRESHOLD (512 * 1024LU)
+#define KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE 0x00200000 /* maximum size of message header and items */
+
+#define KDBUS_ALIGN8(l) (((l) + 7) & ~7)
+#define KDBUS_ALIGN8_PTR(p) ((void*) (uintptr_t)(p))
+
+#define KDBUS_ITEM_HEADER_SIZE G_STRUCT_OFFSET(struct kdbus_item, data)
+#define KDBUS_ITEM_SIZE(s) KDBUS_ALIGN8((s) + KDBUS_ITEM_HEADER_SIZE)
+
+#define KDBUS_ITEM_NEXT(item) \
+ (typeof(item))(((guint8 *)item) + KDBUS_ALIGN8((item)->size))
+#define KDBUS_ITEM_FOREACH(item, head, first) \
+ for (item = (head)->first; \
+ (guint8 *)(item) < (guint8 *)(head) + (head)->size; \
+ item = KDBUS_ITEM_NEXT(item))
+#define KDBUS_FOREACH(iter, first, _size) \
+ for (iter = (first); \
+ ((guint8 *)(iter) < (guint8 *)(first) + (_size)) && \
+ ((guint8 *)(iter) >= (guint8 *)(first)); \
+ iter = (void*)(((guint8 *)iter) + KDBUS_ALIGN8((iter)->size)))
+
+#define g_alloca0(x) memset(g_alloca(x), '\0', (x))
+
+struct dbus_fixed_header {
+ guint8 endian;
+ guint8 type;
+ guint8 flags;
+ guint8 version;
+ guint32 reserved;
+ guint64 serial;
+};
+
+#define DBUS_FIXED_HEADER_TYPE ((const GVariantType *) "(yyyyut)")
+#define DBUS_EXTENDED_HEADER_TYPE ((const GVariantType *) "a{tv}")
+#define DBUS_MESSAGE_TYPE ((const GVariantType *) "((yyyyut)a{tv}v)")
+
+/*
+ * Macros for SipHash algorithm
+ */
+
+#define ROTL(x,b) (guint64)( ((x) << (b)) | ( (x) >> (64 - (b))) )
+
+#define U32TO8_LE(p, v) \
+ (p)[0] = (guint8)((v) ); (p)[1] = (guint8)((v) >> 8); \
+ (p)[2] = (guint8)((v) >> 16); (p)[3] = (guint8)((v) >> 24);
+
+#define U64TO8_LE(p, v) \
+ U32TO8_LE((p), (guint32)((v) )); \
+ U32TO8_LE((p) + 4, (guint32)((v) >> 32));
+
+#define U8TO64_LE(p) \
+ (((guint64)((p)[0]) ) | \
+ ((guint64)((p)[1]) << 8) | \
+ ((guint64)((p)[2]) << 16) | \
+ ((guint64)((p)[3]) << 24) | \
+ ((guint64)((p)[4]) << 32) | \
+ ((guint64)((p)[5]) << 40) | \
+ ((guint64)((p)[6]) << 48) | \
+ ((guint64)((p)[7]) << 56))
+
+#define SIPROUND \
+ do { \
+ v0 += v1; v1=ROTL(v1,13); v1 ^= v0; v0=ROTL(v0,32); \
+ v2 += v3; v3=ROTL(v3,16); v3 ^= v2; \
+ v0 += v3; v3=ROTL(v3,21); v3 ^= v0; \
+ v2 += v1; v1=ROTL(v1,17); v1 ^= v2; v2=ROTL(v2,32); \
+ } while(0)
+
+typedef GObjectClass GKDBusWorkerClass;
+
+struct _GKDBusWorker
+{
+ GObject parent_instance;
+
+ const gchar *address;
+ gint fd;
+
+ GMainContext *context;
+ GMainLoop *loop;
+ GThread *thread;
+ GSource *source;
+
+ gchar *kdbus_buffer;
+ guint64 receive_pool_size;
+ gchar *unique_name;
+ guint64 unique_id;
+
+ guint64 flags;
+ guint64 attach_flags_send;
+ guint64 attach_flags_recv;
+
+ gsize bloom_size;
+ guint bloom_n_hash;
+
+ guint closed : 1;
+ guint inited : 1;
+ guint timeout;
+ guint timed_out : 1;
+
+ guchar bus_id[16];
+
+ GMutex matches_mutex;
+ GList *matches;
+
+#ifdef LIBDBUSPOLICY
+ void *dbuspolicy;
+#endif
+
+ GDBusCapabilityFlags capabilities;
+ GDBusWorkerMessageReceivedCallback message_received_callback;
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback;
+ GDBusWorkerDisconnectedCallback disconnected_callback;
+ gpointer user_data;
+};
+
+static gboolean _g_kdbus_send (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GDBusMessage **reply,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error);
+
+static void _g_kdbus_receive (GKDBusWorker *worker,
+ GError **error);
+
+G_DEFINE_TYPE (GKDBusWorker, g_kdbus_worker, G_TYPE_OBJECT)
+
+/* Hash keys for bloom filters*/
+const guint8 hash_keys[8][16] =
+{
+ {0xb9,0x66,0x0b,0xf0,0x46,0x70,0x47,0xc1,0x88,0x75,0xc4,0x9c,0x54,0xb9,0xbd,0x15},
+ {0xaa,0xa1,0x54,0xa2,0xe0,0x71,0x4b,0x39,0xbf,0xe1,0xdd,0x2e,0x9f,0xc5,0x4a,0x3b},
+ {0x63,0xfd,0xae,0xbe,0xcd,0x82,0x48,0x12,0xa1,0x6e,0x41,0x26,0xcb,0xfa,0xa0,0xc8},
+ {0x23,0xbe,0x45,0x29,0x32,0xd2,0x46,0x2d,0x82,0x03,0x52,0x28,0xfe,0x37,0x17,0xf5},
+ {0x56,0x3b,0xbf,0xee,0x5a,0x4f,0x43,0x39,0xaf,0xaa,0x94,0x08,0xdf,0xf0,0xfc,0x10},
+ {0x31,0x80,0xc8,0x73,0xc7,0xea,0x46,0xd3,0xaa,0x25,0x75,0x0f,0x9e,0x4c,0x09,0x29},
+ {0x7d,0xf7,0x18,0x4b,0x7b,0xa4,0x44,0xd5,0x85,0x3c,0x06,0xe0,0x65,0x53,0x96,0x6d},
+ {0xf2,0x77,0xe9,0x6f,0x93,0xb5,0x4e,0x71,0x9a,0x0c,0x34,0x88,0x39,0x25,0xbf,0x35}
+};
+
+enum {
+ MATCH_ELEMENT_TYPE,
+ MATCH_ELEMENT_SENDER,
+ MATCH_ELEMENT_INTERFACE,
+ MATCH_ELEMENT_MEMBER,
+ MATCH_ELEMENT_PATH,
+ MATCH_ELEMENT_PATH_NAMESPACE,
+ MATCH_ELEMENT_DESTINATION,
+ MATCH_ELEMENT_ARG0NAMESPACE,
+ MATCH_ELEMENT_EAVESDROP,
+ MATCH_ELEMENT_ARGN,
+ MATCH_ELEMENT_ARGNPATH,
+};
+
+static guint64 _global_match_cookie = 1;
+
+/* MatchElement struct */
+typedef struct {
+ guint16 type;
+ guint16 arg;
+ char *value;
+} MatchElement;
+
+/* Match struct */
+typedef struct {
+ int n_elements;
+ MatchElement *elements;
+ guint64 cookie;
+} Match;
+
+
+/*
+ * SipHash algorithm
+ */
+static void
+_g_siphash24 (guint8 out[8],
+ const void *_in,
+ gsize inlen,
+ const guint8 k[16])
+{
+ /* "somepseudorandomlygeneratedbytes" */
+ guint64 v0 = 0x736f6d6570736575ULL;
+ guint64 v1 = 0x646f72616e646f6dULL;
+ guint64 v2 = 0x6c7967656e657261ULL;
+ guint64 v3 = 0x7465646279746573ULL;
+ guint64 b;
+ guint64 k0 = U8TO64_LE (k);
+ guint64 k1 = U8TO64_LE (k + 8);
+ guint64 m;
+ const guint8 *in = _in;
+ const guint8 *end = in + inlen - (inlen % sizeof(guint64));
+ const int left = inlen & 7;
+ b = ((guint64) inlen) << 56;
+ v3 ^= k1;
+ v2 ^= k0;
+ v1 ^= k1;
+ v0 ^= k0;
+
+ for (; in != end; in += 8)
+ {
+ m = U8TO64_LE (in);
+ v3 ^= m;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= m;
+ }
+
+ switch (left)
+ {
+ case 7: b |= ((guint64) in[6]) << 48;
+ case 6: b |= ((guint64) in[5]) << 40;
+ case 5: b |= ((guint64) in[4]) << 32;
+ case 4: b |= ((guint64) in[3]) << 24;
+ case 3: b |= ((guint64) in[2]) << 16;
+ case 2: b |= ((guint64) in[1]) << 8;
+ case 1: b |= ((guint64) in[0]); break;
+ case 0: break;
+ }
+
+ v3 ^= b;
+ SIPROUND;
+ SIPROUND;
+ v0 ^= b;
+
+ v2 ^= 0xff;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ SIPROUND;
+ b = v0 ^ v1 ^ v2 ^ v3;
+ U64TO8_LE (out, b);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static gboolean
+is_key (const char *key_start, const char *key_end, char *value)
+{
+ gsize len = strlen (value);
+
+ if (len != key_end - key_start)
+ return FALSE;
+
+ return strncmp (key_start, value, len) == 0;
+}
+
+static gboolean
+parse_key (MatchElement *element, const char *key_start, const char *key_end)
+{
+ gboolean res = TRUE;
+
+ if (is_key (key_start, key_end, "type"))
+ {
+ element->type = MATCH_ELEMENT_TYPE;
+ }
+ else if (is_key (key_start, key_end, "sender"))
+ {
+ element->type = MATCH_ELEMENT_SENDER;
+ }
+ else if (is_key (key_start, key_end, "interface"))
+ {
+ element->type = MATCH_ELEMENT_INTERFACE;
+ }
+ else if (is_key (key_start, key_end, "member"))
+ {
+ element->type = MATCH_ELEMENT_MEMBER;
+ }
+ else if (is_key (key_start, key_end, "path"))
+ {
+ element->type = MATCH_ELEMENT_PATH;
+ }
+ else if (is_key (key_start, key_end, "path_namespace"))
+ {
+ element->type = MATCH_ELEMENT_PATH_NAMESPACE;
+ }
+ else if (is_key (key_start, key_end, "destination"))
+ {
+ element->type = MATCH_ELEMENT_DESTINATION;
+ }
+ else if (is_key (key_start, key_end, "arg0namespace"))
+ {
+ element->type = MATCH_ELEMENT_ARG0NAMESPACE;
+ }
+ else if (is_key (key_start, key_end, "eavesdrop"))
+ {
+ element->type = MATCH_ELEMENT_EAVESDROP;
+ }
+ else if (key_end - key_start > 3 && is_key (key_start, key_start + 3, "arg"))
+ {
+ const char *digits = key_start + 3;
+ const char *end_digits = digits;
+
+ while (end_digits < key_end && g_ascii_isdigit (*end_digits))
+ end_digits++;
+
+ if (end_digits == key_end) /* argN */
+ {
+ element->type = MATCH_ELEMENT_ARGN;
+ element->arg = atoi (digits);
+ }
+ else if (is_key (end_digits, key_end, "path")) /* argNpath */
+ {
+ element->type = MATCH_ELEMENT_ARGNPATH;
+ element->arg = atoi (digits);
+ }
+ else
+ res = FALSE;
+ }
+ else
+ res = FALSE;
+
+ return res;
+}
+
+static const char *
+parse_value (MatchElement *element, const char *s)
+{
+ char quote_char;
+ GString *value;
+
+ value = g_string_new ("");
+
+ quote_char = 0;
+
+ for (;*s; s++)
+ {
+ if (quote_char == 0)
+ {
+ switch (*s)
+ {
+ case '\'':
+ quote_char = '\'';
+ break;
+
+ case ',':
+ s++;
+ goto out;
+
+ case '\\':
+ quote_char = '\\';
+ break;
+
+ default:
+ g_string_append_c (value, *s);
+ break;
+ }
+ }
+ else if (quote_char == '\\')
+ {
+ /* \ only counts as an escape if escaping a quote mark */
+ if (*s != '\'')
+ g_string_append_c (value, '\\');
+
+ g_string_append_c (value, *s);
+ quote_char = 0;
+ }
+ else /* quote_char == ' */
+ {
+ if (*s == '\'')
+ quote_char = 0;
+ else
+ g_string_append_c (value, *s);
+ }
+ }
+
+ out:
+ if (quote_char == '\\')
+ g_string_append_c (value, '\\');
+ else if (quote_char == '\'')
+ {
+ g_string_free (value, TRUE);
+ return NULL;
+ }
+
+ element->value = g_string_free (value, FALSE);
+ return s;
+}
+
+static Match *
+match_new (const char *str)
+{
+ Match *match;
+ GArray *elements;
+ const char *p;
+ const char *key_start;
+ const char *key_end;
+ MatchElement element;
+ int i;
+
+ elements = g_array_new (TRUE, TRUE, sizeof (MatchElement));
+
+ p = str;
+
+ while (*p != 0)
+ {
+ memset (&element, 0, sizeof (element));
+
+ /* Skip initial whitespace */
+ while (*p && g_ascii_isspace (*p))
+ p++;
+
+ key_start = p;
+
+ /* Read non-whitespace non-equals chars */
+ while (*p && *p != '=' && !g_ascii_isspace (*p))
+ p++;
+
+ key_end = p;
+
+ /* Skip any whitespace after key */
+ while (*p && g_ascii_isspace (*p))
+ p++;
+
+ if (key_start == key_end)
+ continue; /* Allow trailing whitespace */
+ if (*p != '=')
+ goto error;
+
+ ++p;
+
+ if (!parse_key (&element, key_start, key_end))
+ goto error;
+
+ p = parse_value (&element, p);
+ if (p == NULL)
+ goto error;
+
+ g_array_append_val (elements, element);
+ }
+
+ match = g_new0 (Match, 1);
+ match->n_elements = elements->len;
+ match->elements = (MatchElement *)g_array_free (elements, FALSE);
+ match->cookie = _global_match_cookie++;
+
+ return match;
+
+ error:
+ for (i = 0; i < elements->len; i++)
+ g_free (g_array_index (elements, MatchElement, i).value);
+ g_array_free (elements, TRUE);
+ return NULL;
+}
+
+static gboolean
+match_equal (Match *a, Match *b)
+{
+ int i;
+
+ if (a->n_elements != b->n_elements)
+ return FALSE;
+
+ for (i = 0; i < a->n_elements; i++)
+ {
+ if (a->elements[i].type != b->elements[i].type ||
+ a->elements[i].arg != b->elements[i].arg ||
+ strcmp (a->elements[i].value, b->elements[i].value) != 0)
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+static void
+match_free (Match *match)
+{
+ int i;
+
+ for (i = 0; i < match->n_elements; i++)
+ g_free (match->elements[i].value);
+
+ g_free (match->elements);
+ g_free (match);
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/*
+ * _g_kdbus_open
+ */
+gboolean
+_g_kdbus_open (GKDBusWorker *worker,
+ const gchar *address,
+ GError **error)
+{
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ worker->fd = g_open(address, O_RDWR|O_NOCTTY|O_CLOEXEC, 0);
+ if (worker->fd<0)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot open kdbus endpoint"));
+ return FALSE;
+ }
+
+ worker->address = g_strdup(address);
+ worker->closed = FALSE;
+ return TRUE;
+}
+
+static gboolean
+_g_kdbus_quit_loop (gpointer loop)
+{
+ g_main_loop_quit ((GMainLoop*)loop);
+ return FALSE;
+}
+
+gboolean
+_g_kdbus_can_connect (GKDBusWorker *worker,
+ GError **error)
+{
+#ifdef LIBDBUSPOLICY
+ worker->dbuspolicy = dbuspolicy1_init_shared (worker->address, worker->fd);
+ if (worker->dbuspolicy == NULL)
+ {
+ g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Cannot load dbus policy for kdbus transport or access to bus denied by security policy"));
+ return FALSE;
+ }
+#endif
+ return TRUE;
+}
+
+/*
+ * _g_kdbus_close
+ */
+gboolean
+_g_kdbus_close (GKDBusWorker *worker)
+{
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+
+ if (worker->closed)
+ return TRUE;
+
+ g_main_context_invoke (worker->context, _g_kdbus_quit_loop, worker->loop);
+
+ g_main_context_unref (worker->context);
+ worker->context = NULL;
+
+ g_main_loop_unref (worker->loop);
+
+ g_thread_unref(worker->thread);
+
+ worker->thread = NULL;
+
+ g_free ((char*)worker->address);
+
+ close (worker->fd);
+ worker->fd = -1;
+
+ worker->closed = TRUE;
+ return TRUE;
+}
+
+/*
+ * _g_kdbus_is_closed
+ */
+gboolean
+_g_kdbus_is_closed (GKDBusWorker *worker)
+{
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+
+ return worker->closed;
+}
+
+static void
+g_kdbus_free_data (GKDBusWorker *worker,
+ guint64 offset)
+{
+ struct kdbus_cmd_free cmd = {
+ .size = sizeof(cmd),
+ .offset = offset,
+ .flags = 0
+ };
+
+ if (ioctl (worker->fd, KDBUS_CMD_FREE, &cmd) < 0)
+ {
+ g_error ("kdbus: invalid KDBUS_CMD_FREE ioctl : %" G_GUINT64_FORMAT " offset\n", offset);
+ }
+}
+
+static void
+g_kdbus_close_msg (GKDBusWorker *worker,
+ struct kdbus_msg *msg)
+{
+ guint64 offset;
+
+ offset = (guint8 *)msg - (guint8 *)worker->kdbus_buffer;
+ g_kdbus_free_data (worker, offset);
+}
+
+
+/*
+ * g_kdbus_translate_nameowner_flags
+ */
+static void
+g_kdbus_translate_nameowner_flags (GBusNameOwnerFlags flags,
+ guint64 *kdbus_flags)
+{
+ guint64 new_flags;
+
+ new_flags = 0;
+
+ if (flags & G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT)
+ new_flags |= KDBUS_NAME_ALLOW_REPLACEMENT;
+
+ if (flags & G_BUS_NAME_OWNER_FLAGS_REPLACE)
+ new_flags |= KDBUS_NAME_REPLACE_EXISTING;
+
+ if (!(flags & G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE))
+ new_flags |= KDBUS_NAME_QUEUE;
+
+ *kdbus_flags = new_flags;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+/* < internal >
+ *
+ * _g_kdbus_Hello:
+ *
+ * Gets the unique name.
+ *
+ * Returns: the unique name or NULL. Do not free this string,
+ * it is owned by GKDBusWorker.
+ */
+const gchar *
+_g_kdbus_Hello (GKDBusWorker *worker,
+ GError **error)
+{
+ struct kdbus_cmd_hello *cmd;
+ struct kdbus_bloom_parameter *bloom;
+ struct kdbus_item *item, *items;
+
+ gchar *conn_name;
+ size_t size, conn_name_size;
+
+ const gchar *env_pool;
+ guint64 receive_pool_size = RECEIVE_POOL_SIZE_DEFAULT_SIZE;
+
+ conn_name = "gdbus-kdbus";
+ conn_name_size = strlen (conn_name);
+
+ size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_hello, items)) +
+ KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1);
+
+ cmd = g_alloca0 (size);
+ cmd->flags = worker->flags;
+ cmd->attach_flags_send = worker->attach_flags_send;
+ cmd->attach_flags_recv = worker->attach_flags_recv;
+ cmd->size = size;
+
+ env_pool = getenv (RECEIVE_POOL_SIZE_ENV_VAR_NAME);
+ if(env_pool)
+ {
+ guint64 size;
+ guint32 multiply = 1;
+ gint64 page_size;
+
+ page_size = sysconf(_SC_PAGESIZE);
+ if(page_size == -1)
+ {
+ size = 0;
+ goto finish;
+ }
+
+ errno = 0;
+ size = strtoul(env_pool, (char**)&env_pool, 10);
+ if(errno == EINVAL || size == 0)
+ {
+ size = 0;
+ goto finish;
+ }
+
+ if(*env_pool == 'k')
+ {
+ multiply = 1024;
+ env_pool++;
+ }
+ else if (*env_pool == 'M')
+ {
+ multiply = 1024 * 1024;
+ env_pool++;
+ }
+
+ if(*env_pool != '\0')
+ {
+ size = 0;
+ goto finish;
+ }
+
+ receive_pool_size = size * multiply;
+
+ if((receive_pool_size > RECEIVE_POOL_SIZE_MAX_MBYTES * 1024 * 1024) ||
+ (receive_pool_size < RECEIVE_POOL_SIZE_MIN_KBYTES * 1024) ||
+ ((receive_pool_size & (page_size - 1)) != 0))
+ size = 0;
+
+ finish:
+ if(size == 0)
+ {
+ g_warning ("%s value is invalid, default value %luB will be used.", RECEIVE_POOL_SIZE_ENV_VAR_NAME,
+ RECEIVE_POOL_SIZE_DEFAULT_SIZE);
+ g_warning ("Correct value must be between %ukB and %uMB and must be aligned to page size: %" G_GINT64_FORMAT "B.",
+ RECEIVE_POOL_SIZE_MIN_KBYTES, RECEIVE_POOL_SIZE_MAX_MBYTES, page_size);
+
+ receive_pool_size = RECEIVE_POOL_SIZE_DEFAULT_SIZE;
+ }
+ }
+
+ g_debug ("[KDBUS] receive pool size set to %" G_GUINT64_FORMAT "\n", receive_pool_size);
+ worker->receive_pool_size = receive_pool_size;
+ cmd->pool_size = worker->receive_pool_size;
+
+ item = cmd->items;
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, str) + conn_name_size + 1;
+ item->type = KDBUS_ITEM_CONN_DESCRIPTION;
+ memcpy (item->str, conn_name, conn_name_size+1);
+ item = KDBUS_ITEM_NEXT (item);
+
+ if (worker->unique_id != -1)
+ {
+ g_set_error (error, G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Already handled an Hello message");
+ return NULL;
+ }
+
+ if (ioctl(worker->fd, KDBUS_CMD_HELLO, cmd))
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Failed to send HELLO: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
+
+ worker->kdbus_buffer = mmap(NULL, worker->receive_pool_size, PROT_READ, MAP_SHARED, worker->fd, 0);
+ if (worker->kdbus_buffer == MAP_FAILED)
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("mmap error: %s"),
+ g_strerror (errno));
+ return NULL;
+ }
+
+ if (cmd->bus_flags > 0xFFFFFFFFULL)
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Incompatible HELLO flags"));
+ return NULL;
+ }
+
+ memcpy (worker->bus_id, cmd->id128, 16);
+
+ worker->unique_id = cmd->id;
+ if (asprintf (&worker->unique_name, ":1.%llu", (unsigned long long) cmd->id) < 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_UNKNOWN,
+ "asprintf error: %s",
+ g_strerror(errno));
+ return NULL;
+ }
+
+ /* read bloom filters parameters */
+ bloom = NULL;
+ items = (void*)(worker->kdbus_buffer + cmd->offset);
+ KDBUS_FOREACH(item, items, cmd->items_size)
+ {
+ switch (item->type)
+ {
+ case KDBUS_ITEM_BLOOM_PARAMETER:
+ bloom = &item->bloom_parameter;
+ break;
+ }
+ }
+
+ if (bloom != NULL)
+ {
+ worker->bloom_size = (gsize) bloom->size;
+ worker->bloom_n_hash = (guint) bloom->n_hash;
+ }
+ else
+ {
+ g_set_error_literal (error,
+ G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Can't read bloom filter parameters"));
+ return NULL;
+ }
+
+ g_kdbus_free_data (worker, cmd->offset);
+
+#ifdef LIBDBUSPOLICY
+ dbuspolicy1_init_set_pool (worker->dbuspolicy, worker->kdbus_buffer);
+#endif
+
+ return worker->unique_name;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_RequestName:
+ *
+ * Synchronously acquires name on the bus and returns status code
+ * from the GBusRequestNameReplyFlags enumeration.
+ *
+ * Returns: status code or G_BUS_REQUEST_NAME_FLAGS_ERROR
+ * if error is set.
+ */
+GBusRequestNameReplyFlags
+_g_kdbus_RequestName (GKDBusWorker *worker,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GError **error)
+{
+ GBusRequestNameReplyFlags status;
+ struct kdbus_cmd *cmd;
+ guint64 kdbus_flags;
+ gsize len, size;
+ gint ret;
+
+ status = G_BUS_REQUEST_NAME_FLAGS_PRIMARY_OWNER;
+
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+ }
+
+ if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot acquire a service named '%s', because that is reserved", name);
+ return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+ }
+
+ if (*name == ':')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot acquire a service starting with ':' such as \"%s\"", name);
+ return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+ }
+
+#ifdef LIBDBUSPOLICY
+ if (worker->dbuspolicy != NULL)
+ {
+ if (dbuspolicy1_can_own (worker->dbuspolicy, name) != 1)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_ACCESS_DENIED,
+ "Connection \"%s\" is not allowed to own the "
+ "service \"%s\" due to security policies", worker->unique_name, name);
+ return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+ }
+ }
+#endif
+
+ g_kdbus_translate_nameowner_flags (flags, &kdbus_flags);
+
+ len = strlen(name) + 1;
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ cmd->flags = kdbus_flags;
+ memcpy (cmd->items[0].str, name, len);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_NAME_ACQUIRE, cmd);
+ if (ret < 0)
+ {
+ if (errno == EEXIST)
+ status = G_BUS_REQUEST_NAME_FLAGS_EXISTS;
+ else if (errno == EALREADY)
+ status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
+ else
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error while acquiring name: %s"),
+ g_strerror (errno));
+ return G_BUS_REQUEST_NAME_FLAGS_ERROR;
+ }
+ }
+ else if ((cmd->return_flags & KDBUS_NAME_PRIMARY)
+ && !(cmd->return_flags & KDBUS_NAME_ACQUIRED))
+ status = G_BUS_REQUEST_NAME_FLAGS_ALREADY_OWNER;
+
+ if (cmd->return_flags & KDBUS_NAME_IN_QUEUE)
+ status = G_BUS_REQUEST_NAME_FLAGS_IN_QUEUE;
+
+ return status;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_ReleaseName:
+ *
+ * Synchronously releases name on the bus and returns status code
+ * from the GBusReleaseNameReplyFlags enumeration.
+ *
+ * Returns: status code or G_BUS_RELEASE_NAME_FLAGS_ERROR
+ * if error is set.
+ */
+GBusReleaseNameReplyFlags
+_g_kdbus_ReleaseName (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GBusReleaseNameReplyFlags status;
+ struct kdbus_cmd *cmd;
+ gsize len, size;
+ gint ret;
+
+ status = G_BUS_RELEASE_NAME_FLAGS_RELEASED;
+
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return G_BUS_RELEASE_NAME_FLAGS_ERROR;
+ }
+
+ if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot release a service named '%s', because that is owned by the bus", name);
+ return G_BUS_RELEASE_NAME_FLAGS_ERROR;
+ }
+
+ if (*name == ':')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Cannot release a service starting with ':' such as \"%s\"", name);
+ return G_BUS_RELEASE_NAME_FLAGS_ERROR;
+ }
+
+ len = strlen(name) + 1;
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_NAME_RELEASE, cmd);
+ if (ret < 0)
+ {
+ if (errno == ESRCH)
+ status = G_BUS_RELEASE_NAME_FLAGS_NON_EXISTENT;
+ else if (errno == EADDRINUSE)
+ status = G_BUS_RELEASE_NAME_FLAGS_NOT_OWNER;
+ else
+ {
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errno),
+ _("Error while releasing name: %s"),
+ g_strerror (errno));
+ return G_BUS_RELEASE_NAME_FLAGS_ERROR;
+ }
+ }
+
+ return status;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetBusId:
+ *
+ * Synchronously returns the unique ID of the bus.
+ *
+ * Returns: the unique ID of the bus or NULL if error is set.
+ * Free with g_free().
+ */
+gchar *
+_g_kdbus_GetBusId (GKDBusWorker *worker,
+ GError **error)
+{
+ GString *result;
+ guint cnt;
+
+ result = g_string_new (NULL);
+
+ for (cnt=0; cnt<16; cnt++)
+ g_string_append_printf (result, "%02x", worker->bus_id[cnt]);
+
+ return g_string_free (result, FALSE);
+}
+
+
+static void
+expand_strv (gchar ***strv_ptr,
+ gchar *value)
+{
+ gchar **strv;
+ guint strv_len;
+
+ if (!value)
+ return;
+
+ strv = *strv_ptr;
+ strv_len = g_strv_length (strv);
+
+ strv = g_renew (gchar *, strv, strv_len + 2);
+ strv[strv_len] = value;
+ strv[strv_len + 1] = NULL;
+
+ *strv_ptr = strv;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetListNames:
+ *
+ * Synchronously returns a list of:
+ * - all currently-owned names on the bus (activatable = FALSE),
+ * - all names that can be activated on the bus (activatable = TRUE),
+ *
+ * or NULL if error is set. Free with g_strfreev().
+ */
+gchar **
+_g_kdbus_GetListNames (GKDBusWorker *worker,
+ gboolean activatable,
+ GError **error)
+{
+ struct kdbus_info *name_list, *name;
+ struct kdbus_cmd_list cmd = {
+ .size = sizeof(cmd)
+ };
+
+ gchar **listnames;
+ guint64 prev_id;
+ gint ret;
+
+ prev_id = 0;
+
+ if (activatable)
+ cmd.flags = KDBUS_LIST_ACTIVATORS; /* ListActivatableNames */
+ else
+ cmd.flags = KDBUS_LIST_UNIQUE | KDBUS_LIST_NAMES; /* ListNames */
+
+ ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Error listing names"));
+ return NULL;
+ }
+
+ listnames = g_new0 (gchar *, 1);
+ name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
+
+ KDBUS_FOREACH (name, name_list, cmd.list_size)
+ {
+ struct kdbus_item *item;
+
+ if ((cmd.flags & KDBUS_LIST_UNIQUE) && name->id != prev_id)
+ {
+ gchar *unique_name;
+
+ if (asprintf (&unique_name, ":1.%llu", name->id) < 0)
+ {
+ g_set_error (error,
+ G_IO_ERROR,
+ G_IO_ERROR_UNKNOWN,
+ "asprintf error: %s",
+ g_strerror(errno));
+ goto error;
+ }
+
+ expand_strv (&listnames, unique_name);
+ prev_id = name->id;
+ }
+
+ KDBUS_ITEM_FOREACH (item, name, items)
+ {
+ if (item->type == KDBUS_ITEM_OWNED_NAME)
+ {
+ if (g_dbus_is_name (item->name.name))
+ expand_strv (&listnames, g_strdup (item->name.name));
+ }
+ }
+ }
+
+ /* org.freedesktop.DBus.ListNames */
+ if (!activatable)
+ expand_strv (&listnames, g_strdup ("org.freedesktop.DBus"));
+
+ g_kdbus_free_data (worker, cmd.offset);
+
+ return listnames;
+
+error:
+ g_strfreev(listnames);
+ return NULL;
+}
+
+
+static gboolean
+g_kdbus_NameHasOwner_internal (GKDBusWorker *worker,
+ const gchar *name)
+{
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_info *conn_info;
+ gsize size, len;
+ gint ret;
+
+ if (g_dbus_is_unique_name(name))
+ {
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
+ cmd = g_alloca0 (size);
+ cmd->id = g_ascii_strtoull (name+3, NULL, 10);
+ }
+ else
+ {
+ len = strlen(name) + 1;
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
+ }
+ cmd->size = size;
+
+ ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
+ if (ret < 0)
+ return FALSE;
+
+ conn_info = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd->offset);
+
+ if (conn_info->flags & KDBUS_HELLO_ACTIVATOR)
+ ret = -1;
+
+ g_kdbus_free_data (worker, cmd->offset);
+
+ if (ret < 0)
+ return FALSE;
+ else
+ return TRUE;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetListQueuedOwners:
+ *
+ * Synchronously returns the unique bus names of connections currently
+ * queued for the name.
+ *
+ * Returns: the unique bus names of connections currently queued for the
+ * 'name' or NULL if error is set. Free with g_strfreev().
+ */
+gchar **
+_g_kdbus_GetListQueuedOwners (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ struct kdbus_info *name_list, *kname;
+ struct kdbus_cmd_list cmd = {
+ .size = sizeof(cmd),
+ .flags = KDBUS_LIST_QUEUED
+ };
+
+ gchar **queued_owners;
+ gint ret;
+
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return NULL;
+ }
+
+ if (!g_kdbus_NameHasOwner_internal (worker, name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Could not get owner of name '%s': no such name", name);
+ return NULL;
+ }
+
+ ret = ioctl(worker->fd, KDBUS_CMD_LIST, &cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Error listing names"));
+ return NULL;
+ }
+
+ queued_owners = g_new0 (gchar *, 1);
+ name_list = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd.offset);
+
+ KDBUS_FOREACH(kname, name_list, cmd.list_size)
+ {
+ struct kdbus_item *item;
+
+ KDBUS_ITEM_FOREACH(item, kname, items)
+ {
+ if (item->type == KDBUS_ITEM_OWNED_NAME)
+ {
+ gchar *unique_name;
+
+ if (strcmp(item->name.name, name))
+ continue;
+
+ if (asprintf (&unique_name, ":1.%llu", kname->id) != -1)
+ expand_strv (&queued_owners, unique_name);
+ }
+ }
+ }
+
+ g_kdbus_free_data (worker, cmd.offset);
+
+ return queued_owners;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_NameHasOwner:
+ *
+ * Checks if the specified name exists (currently has an owner).
+ *
+ * Returns: TRUE if the name exists and FALSE when name doesn't exists
+ * or error is set.
+ */
+gboolean
+_g_kdbus_NameHasOwner (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return FALSE;
+ }
+
+ if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
+ return TRUE;
+
+ if (!g_kdbus_NameHasOwner_internal (worker, name))
+ return FALSE; /* Don't make g_set_error, otherwise NameHasOwner will fail. */
+ else
+ return TRUE;
+}
+
+
+GDBusCredentials *
+_g_kdbus_GetConnInfo (GKDBusWorker *worker,
+ const gchar *name,
+ guint flags,
+ GError **error)
+{
+ GDBusCredentials *creds;
+ struct kdbus_cmd_info *cmd;
+ struct kdbus_info *conn_info;
+ struct kdbus_item *item;
+ gsize size, len;
+ gint ret;
+
+ creds = g_new0 (GDBusCredentials, 1);
+
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ goto error;
+ }
+
+ if (!g_kdbus_NameHasOwner_internal (worker, name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Could not get owner of name '%s': no such name", name);
+ goto error;
+ }
+
+ if (g_dbus_is_unique_name(name))
+ {
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd_info, items);
+ cmd = g_alloca0 (size);
+ cmd->id = g_ascii_strtoull (name+3, NULL, 10);
+ }
+ else
+ {
+ len = strlen(name) + 1;
+ size = (gulong) G_STRUCT_OFFSET (struct kdbus_cmd_info, items) + KDBUS_ITEM_SIZE(len);
+ cmd = g_alloca0 (size);
+ cmd->items[0].size = KDBUS_ITEM_HEADER_SIZE + len;
+ cmd->items[0].type = KDBUS_ITEM_NAME;
+ memcpy (cmd->items[0].str, name, len);
+ }
+
+ cmd->attach_flags = _KDBUS_ATTACH_ALL;
+ cmd->size = size;
+
+ ret = ioctl(worker->fd, KDBUS_CMD_CONN_INFO, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Could not get connection info"));
+ goto error;
+ }
+
+ conn_info = (struct kdbus_info *) ((guint8 *) worker->kdbus_buffer + cmd->offset);
+
+ if (flags & G_DBUS_CREDS_UNIQUE_NAME)
+ {
+ if (asprintf (&creds->unique_name, ":1.%llu", (unsigned long long) conn_info->id) < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "asprintf error: %s",
+ g_strerror(errno));
+ goto error;
+ }
+ }
+
+ KDBUS_ITEM_FOREACH(item, conn_info, items)
+ {
+ switch (item->type)
+ {
+ case KDBUS_ITEM_PIDS:
+ if (flags & G_DBUS_CREDS_PID)
+ creds->pid = item->pids.pid;
+ break;
+
+ case KDBUS_ITEM_CREDS:
+ if (flags & G_DBUS_CREDS_UID)
+ creds->uid = item->creds.uid;
+ break;
+
+ case KDBUS_ITEM_SECLABEL:
+ if (flags & G_DBUS_CREDS_SEC_LABEL)
+ creds->sec_label = g_strdup (item->str);
+ break;
+
+ case KDBUS_ITEM_PID_COMM:
+ case KDBUS_ITEM_TID_COMM:
+ case KDBUS_ITEM_EXE:
+ case KDBUS_ITEM_CMDLINE:
+ case KDBUS_ITEM_CGROUP:
+ case KDBUS_ITEM_CAPS:
+ case KDBUS_ITEM_AUDIT:
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ case KDBUS_ITEM_AUXGROUPS:
+ case KDBUS_ITEM_OWNED_NAME:
+ break;
+ }
+ }
+
+ g_kdbus_free_data (worker, cmd->offset);
+ return creds;
+
+error:
+ g_free (creds->unique_name);
+ g_free (creds->sec_label);
+ g_free (creds);
+ return NULL;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetNameOwner:
+ *
+ * Synchronously returns the unique connection name of the primary owner of
+ * the name given. If the requested name doesn't have an owner, an error is
+ * returned.
+ *
+ * Returns: the unique connection name of the primary owner of the
+ * name given. If the requested name doesn't have an owner, function
+ * returns NULL and error is set. Free with g_free().
+ */
+gchar *
+_g_kdbus_GetNameOwner (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GDBusCredentials *creds;
+ gchar *unique_name;
+ guint flags;
+
+ creds = NULL;
+ unique_name = NULL;
+
+ if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
+ return g_strdup (name);
+
+ flags = G_DBUS_CREDS_UNIQUE_NAME;
+ creds = _g_kdbus_GetConnInfo (worker,
+ name,
+ flags,
+ error);
+ if (creds != NULL)
+ {
+ unique_name = creds->unique_name;
+ g_free (creds);
+ }
+
+ return unique_name;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetConnectionUnixProcessID:
+ *
+ * Synchronously returns the Unix process ID of the process connected to the
+ * bus. If unable to determine it, an error is returned.
+ *
+ * If name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns -1 and error is set.
+ *
+ * Returns: the Unix process ID of the process connected to the bus or -1
+ * if error is set.
+ */
+pid_t
+_g_kdbus_GetConnectionUnixProcessID (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GDBusCredentials *creds;
+ guint flags;
+ pid_t pid;
+
+ creds = NULL;
+ pid = -1;
+
+ flags = G_DBUS_CREDS_PID;
+ creds = _g_kdbus_GetConnInfo (worker,
+ name,
+ flags,
+ error);
+ if (creds != NULL)
+ {
+ pid = creds->pid;
+ g_free (creds);
+ }
+
+ return pid;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetConnectionUnixUser:
+ *
+ * Synchronously returns the Unix user ID of the process connected to the
+ * bus. If unable to determine it, an error is returned.
+ *
+ * If name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns -1 and error is set.
+ *
+ * Returns: the Unix user ID of the process connected to the bus or -1
+ * if error is set.
+ */
+uid_t
+_g_kdbus_GetConnectionUnixUser (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GDBusCredentials *creds;
+ guint flags;
+ uid_t uid;
+
+ creds = NULL;
+ uid = -1;
+
+ flags = G_DBUS_CREDS_UID;
+ creds = _g_kdbus_GetConnInfo (worker,
+ name,
+ flags,
+ error);
+ if (creds != NULL)
+ {
+ uid = creds->uid;
+ g_free (creds);
+ }
+
+ return uid;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_GetConnectionSecurityLabel:
+ *
+ * Synchronously returns security label of the process connected to the bus.
+ *
+ * If name contains a value not compatible with the D-Bus syntax and naming
+ * conventions for bus names, the operation returns -1 and error is set.
+ *
+ * Returns: security label of the process connected to the bus or -1
+ */
+gchar *
+_g_kdbus_GetConnectionSecurityLabel (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GDBusCredentials *creds;
+ gchar *sec_label;
+ guint flags;
+
+ creds = NULL;
+ sec_label = NULL;
+
+ flags = G_DBUS_CREDS_SEC_LABEL;
+ creds = _g_kdbus_GetConnInfo (worker,
+ name,
+ flags,
+ error);
+ if (creds != NULL)
+ {
+ sec_label = creds->sec_label;
+ g_free (creds);
+ }
+
+ return sec_label;
+}
+
+typedef struct
+{
+ GKDBusWorker *worker;
+ GDBusMessage *message;
+} SyntheticReplyData;
+
+static gboolean
+deliver_synthetic_reply (gpointer user_data)
+{
+ SyntheticReplyData *data;
+ GKDBusWorker *worker;
+ GDBusMessage *message;
+
+ data = user_data;
+ worker = data->worker;
+ message = data->message;
+
+ (* worker->message_received_callback) (message, worker->user_data);
+
+ g_object_unref (message);
+ g_free (data);
+
+ return FALSE;
+}
+
+static void
+send_synthetic_message (GKDBusWorker *worker,
+ GDBusMessage *message)
+{
+ SyntheticReplyData *reply_data;
+ reply_data = g_new0 (SyntheticReplyData, 1);
+ reply_data->worker = worker;
+ reply_data->message = message;
+ g_main_context_invoke (worker->context, deliver_synthetic_reply, reply_data);
+}
+
+static GBusStartServiceReplyFlags
+_g_kdbus_send_Ping (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error)
+{
+ GDBusMessage *ping_message;
+ GDBusMessage *reply = NULL;
+ gboolean ret;
+
+ ping_message = g_dbus_message_new_method_call (name, "/", "org.freedesktop.DBus.Peer", "Ping");
+ g_dbus_message_set_serial (ping_message, -1);
+
+ ret = _g_kdbus_send (worker, ping_message, &reply, 25000, NULL, NULL);
+ g_object_unref (ping_message);
+ if (reply)
+ g_object_unref (reply);
+
+ if (!ret)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_SERVICE_UNKNOWN,
+ "The name %s was not provided by any .service files", name);
+ return G_BUS_START_SERVICE_REPLY_ERROR;
+ }
+ return G_BUS_START_SERVICE_REPLY_SUCCESS;
+}
+
+static void
+_g_kdbus_send_Ping_thread (GTask *task,
+ gpointer source_object,
+ gpointer task_data,
+ GCancellable *cancellable)
+{
+ GKDBusWorker *worker = source_object;
+ GDBusMessage *message = task_data;
+ const gchar *name = NULL;
+ GError *error = NULL;
+
+ GBusStartServiceReplyFlags status;
+
+ g_variant_get (g_dbus_message_get_body (message), "(su)", &name, NULL);
+
+ status = _g_kdbus_send_Ping (worker, name, &error);
+ g_free ((gchar*) name);
+
+ if (status == G_BUS_START_SERVICE_REPLY_SUCCESS)
+ g_task_return_int (task, G_BUS_START_SERVICE_REPLY_SUCCESS);
+ else
+ g_task_return_error (task, error);
+
+}
+
+static void
+_g_kdbus_send_Ping_finish (GKDBusWorker *worker,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GDBusMessage *message = user_data;
+ GDBusMessage *synthetic_reply = NULL;
+ GError *error = NULL;
+ gssize status = g_task_propagate_int (G_TASK (result), &error);
+ if (status != -1)
+ {
+ synthetic_reply = g_dbus_message_new_method_reply (message);
+ g_dbus_message_set_body (synthetic_reply, g_variant_new ("(u)", status));
+ }
+ else
+ {
+ gchar *dbus_error_name = g_dbus_error_encode_gerror (error);
+ synthetic_reply = g_dbus_message_new_method_error (message, dbus_error_name, "%s", error->message);
+ g_free (dbus_error_name);
+ g_error_free (error);
+ }
+ g_object_unref (message);
+ g_dbus_message_set_serial (synthetic_reply, -1);
+ send_synthetic_message (worker, synthetic_reply);
+}
+
+/* < internal >
+ *
+ * _g_kdbus_StartServiceByName:
+ *
+ * Synchronously tries to launch the executable associated
+ * with a name.
+ *
+ * Returns: status code or G_BUS_START_SERVICE_REPLY_ERROR
+ if error is set.
+ */
+GBusStartServiceReplyFlags
+_g_kdbus_StartServiceByName (GKDBusWorker *worker,
+ const gchar *name,
+ guint32 flags,
+ GDBusMessage *message,
+ GError **error)
+{
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_INVALID_ARGS,
+ "Given bus name \"%s\" is not valid", name);
+ return G_BUS_START_SERVICE_REPLY_ERROR;
+ }
+
+ if (g_strcmp0 (name, "org.freedesktop.DBus") == 0)
+ return G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING;
+
+ if (!g_kdbus_NameHasOwner_internal (worker, name))
+ {
+ if (!message)
+ {
+ return _g_kdbus_send_Ping(worker, name, error);
+ }
+ else
+ {
+ GTask *task;
+ task = g_task_new (worker,
+ NULL,
+ (GAsyncReadyCallback) _g_kdbus_send_Ping_finish,
+ g_object_ref(message));
+ g_task_set_task_data (task, message, NULL);
+ g_task_run_in_thread (task, _g_kdbus_send_Ping_thread);
+ g_object_unref (task);
+ return G_BUS_START_SERVICE_REPLY_SUCCESS;
+ }
+ }
+ else
+ {
+ return G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING;
+ }
+}
+
+
+/*
+ * g_kdbus_bloom_add_data:
+ * Based on bus-bloom.c from systemd
+ * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
+ */
+static void
+g_kdbus_bloom_add_data (GKDBusWorker *worker,
+ guint64 bloom_data[],
+ const void *data,
+ gsize n)
+{
+ guint8 hash[8];
+ guint64 bit_num;
+ guint bytes_num = 0;
+ guint cnt_1, cnt_2;
+ guint hash_index = 0;
+
+ guint c = 0;
+
+ bit_num = (guint64)worker->bloom_size * 8;
+
+ if (bit_num > 1)
+ bytes_num = ((__builtin_clzll(bit_num) ^ 63U) + 7) / 8;
+
+ for (cnt_1 = 0, hash_index = 0; cnt_1 < (worker->bloom_n_hash); cnt_1++)
+ {
+ guint64 p = 0;
+ for (cnt_2 = 0; cnt_2 < bytes_num; cnt_2++)
+ {
+ if (c <= 0)
+ {
+ _g_siphash24(hash, data, n, hash_keys[hash_index++]);
+ c += 8;
+ }
+
+ p = (p << 8ULL) | (guint64) hash[8 - c];
+ c--;
+ }
+
+ p &= bit_num - 1;
+ bloom_data[p >> 6] |= 1ULL << (p & 63);
+ }
+}
+
+static void
+g_kdbus_bloom_add_pair (GKDBusWorker *worker,
+ guint64 bloom_data[],
+ const gchar *parameter,
+ const gchar *value)
+{
+ gchar buf[1024];
+ gsize size;
+
+ size = strlen(parameter) + strlen(value) + 1;
+ if (size >= 1024)
+ return;
+
+ strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
+ g_kdbus_bloom_add_data(worker, bloom_data, buf, size);
+}
+
+static void
+g_kdbus_bloom_add_prefixes (GKDBusWorker *worker,
+ guint64 bloom_data[],
+ const gchar *parameter,
+ const gchar *value,
+ gchar separator)
+{
+ gchar buf[1024];
+ gsize size;
+
+ size = strlen(parameter) + strlen(value) + 1;
+ if (size >= 1024)
+ return;
+
+ strcpy(stpcpy(stpcpy(buf, parameter), ":"), value);
+
+ for (;;)
+ {
+ gchar *last_sep;
+ last_sep = strrchr(buf, separator);
+ if (!last_sep || last_sep == buf)
+ break;
+
+ *last_sep = 0;
+ g_kdbus_bloom_add_data(worker, bloom_data, buf, last_sep-buf);
+ }
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_AddMatch:
+ *
+ * Synchronously adds a match rule to match messages.
+ *
+ * Returns: TRUE if the operation succeeded, FALSE
+ * if error is set.
+ *
+ */
+gboolean
+_g_kdbus_AddMatch (GKDBusWorker *worker,
+ const gchar *match_rule,
+ GError **error)
+{
+ Match *match;
+ MatchElement *element;
+ const gchar *sender_name;
+ gsize sender_len, size;
+ struct kdbus_cmd_match *cmd;
+ struct kdbus_item *item;
+ guint64 *bloom;
+ guint64 src_id;
+ gchar *type;
+ gint cnt, ret;
+
+ if (match_rule[0] == '-')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ sender_name = NULL;
+ src_id = KDBUS_MATCH_ID_ANY;
+
+ bloom = g_alloca0 (worker->bloom_size);
+ size = KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_cmd_match, items));
+
+ for (cnt = 0; cnt < match->n_elements; cnt++)
+ {
+ element = &match->elements[cnt];
+ switch (element->type)
+ {
+ case MATCH_ELEMENT_SENDER:
+ if (g_dbus_is_unique_name(element->value))
+ {
+ src_id = g_ascii_strtoull ((element->value)+3, NULL, 10);
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id));
+ }
+ else if (g_dbus_is_name (element->value))
+ {
+ sender_name = element->value;
+ sender_len = strlen(element->value) + 1;
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len);
+ }
+ else
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ match_free (match);
+ return FALSE;
+ }
+ break;
+
+ case MATCH_ELEMENT_TYPE:
+ g_kdbus_bloom_add_pair (worker, bloom, "message-type", element->value);
+ break;
+
+ case MATCH_ELEMENT_INTERFACE:
+ g_kdbus_bloom_add_pair (worker, bloom, "interface", element->value);
+ break;
+
+ case MATCH_ELEMENT_MEMBER:
+ g_kdbus_bloom_add_pair (worker, bloom, "member", element->value);
+ break;
+
+ case MATCH_ELEMENT_PATH:
+ g_kdbus_bloom_add_pair (worker, bloom, "path", element->value);
+ break;
+
+ case MATCH_ELEMENT_PATH_NAMESPACE:
+ if (g_strcmp0 (element->value, "/"))
+ g_kdbus_bloom_add_pair (worker, bloom, "path-slash-prefix", element->value);
+ break;
+
+ case MATCH_ELEMENT_ARGN:
+ if (asprintf (&type, "arg%u", element->arg) < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "asprintf failed: %s", g_strerror(errno));
+ match_free (match);
+ return FALSE;
+ }
+ else
+ {
+ g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
+ free (type);
+ }
+ break;
+
+ case MATCH_ELEMENT_ARGNPATH:
+ if (asprintf (&type, "arg%u-slash-prefix", element->arg) < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "asprintf failed: %s", g_strerror(errno));
+ match_free (match);
+ return FALSE;
+ }
+ else
+ {
+ g_kdbus_bloom_add_pair (worker, bloom, type, element->value);
+ free (type);
+ }
+ break;
+
+ case MATCH_ELEMENT_ARG0NAMESPACE:
+ g_kdbus_bloom_add_pair (worker, bloom, "arg0-dot-prefix", element->value);
+ break;
+
+ case MATCH_ELEMENT_DESTINATION:
+ case MATCH_ELEMENT_EAVESDROP:
+ break;
+ }
+ }
+
+ size += KDBUS_ALIGN8 (G_STRUCT_OFFSET (struct kdbus_item, data64) + worker->bloom_size);
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = match->cookie;
+
+ item = cmd->items;
+ item->size = (guint64) G_STRUCT_OFFSET(struct kdbus_item, data64) + worker->bloom_size;
+ item->type = KDBUS_ITEM_BLOOM_MASK;
+ memcpy(item->data64, bloom, worker->bloom_size);
+ item = KDBUS_ITEM_NEXT(item);
+
+ if (src_id != KDBUS_MATCH_ID_ANY)
+ {
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, id) + sizeof(src_id);
+ item->type = KDBUS_ITEM_ID;
+ item->id = src_id;
+ item = KDBUS_ITEM_NEXT(item);
+ }
+
+ if (sender_name)
+ {
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, str) + sender_len;
+ item->type = KDBUS_ITEM_NAME;
+ memcpy (item->str, sender_name, sender_len);
+ }
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ g_mutex_lock (&worker->matches_mutex);
+ worker->matches = g_list_prepend (worker->matches, match);
+ g_mutex_unlock (&worker->matches_mutex);
+ return TRUE;
+}
+
+
+/* < internal >
+ *
+ * _g_kdbus_RemoveMatch:
+ *
+ * Synchronously removes the first rule that matches.
+ *
+ * Returns: TRUE if the operation succeeded, FALSE
+ * if error is set.
+ */
+gboolean
+_g_kdbus_RemoveMatch (GKDBusWorker *worker,
+ const gchar *match_rule,
+ GError **error)
+{
+ Match *match, *other_match;
+ GList *matches;
+ guint64 cookie;
+
+ if (match_rule[0] == '-')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ g_mutex_lock (&worker->matches_mutex);
+ for (matches = worker->matches; matches != NULL; matches = matches->next)
+ {
+ other_match = matches->data;
+ if (match_equal (match, other_match))
+ {
+ cookie = other_match->cookie;
+ match_free (other_match);
+ worker->matches = g_list_delete_link (worker->matches, matches);
+ break;
+ }
+ }
+ g_mutex_unlock (&worker->matches_mutex);
+
+ if (matches == NULL)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
+ "The given match rule wasn't found and can't be removed");
+ match_free (match);
+ return FALSE;
+ }
+ else
+ {
+ struct kdbus_cmd_match cmd = {
+ .size = sizeof(cmd),
+ .cookie = cookie
+ };
+ gint ret;
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_REMOVE, &cmd);
+ if (ret < 0)
+ {
+ if (errno == EBADSLT)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_MATCH_RULE_NOT_FOUND,
+ "A match entry with the given cookie could not be found");
+ }
+ else
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "Error while removing a match");
+ }
+ match_free (match);
+ return FALSE;
+ }
+ }
+
+ match_free (match);
+ return TRUE;
+}
+
+
+/*
+ * _g_kdbus_subscribe_name_owner_changed_internal
+ */
+static gboolean
+_g_kdbus_subscribe_name_owner_changed_internal (GKDBusWorker *worker,
+ const gchar *name,
+ const gchar *old_name,
+ const gchar *new_name,
+ guint64 cookie,
+ GError **error)
+{
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd;
+ gsize size, len;
+ gint ret;
+ guint64 old_id = 0;
+ guint64 new_id = KDBUS_MATCH_ID_ANY;
+
+ if (name)
+ len = strlen(name) + 1;
+ else
+ len = 0;
+
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->items;
+
+ if (old_name == NULL)
+ {
+ old_id = KDBUS_MATCH_ID_ANY;
+ }
+ else
+ {
+ if (g_dbus_is_unique_name(old_name))
+ old_id = strtoull (old_name + 3, NULL, 10);
+ else
+ return TRUE;
+ }
+
+ if (new_name == NULL)
+ {
+ new_id = KDBUS_MATCH_ID_ANY;
+ }
+ else
+ {
+ if (g_dbus_is_unique_name(new_name))
+ new_id = strtoull (new_name + 3, NULL, 10);
+ else
+ return TRUE;
+ }
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = cookie;
+ item = cmd->items;
+
+ item->type = KDBUS_ITEM_NAME_CHANGE;
+ item->name_change.old_id.id = old_id;
+ item->name_change.new_id.id = new_id;
+
+ if (name)
+ memcpy(item->name_change.name, name, len);
+
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ (guint64) G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+
+/*
+ * _g_kdbus_subscribe_name_acquired
+ */
+gboolean
+_g_kdbus_subscribe_name_acquired (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error)
+{
+ Match *match;
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd;
+ gsize size, len;
+ gint ret;
+
+ if (match_rule[0] == '-')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ if (name != NULL)
+ {
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+ }
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ if (name)
+ len = strlen(name) + 1;
+ else
+ len = 0;
+
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = match->cookie;
+ item = cmd->items;
+
+ item->type = KDBUS_ITEM_NAME_ADD;
+ item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+ item->name_change.new_id.id = worker->unique_id;
+
+ if (name)
+ memcpy(item->name_change.name, name, len);
+
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ (guint64) G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ if (!_g_kdbus_subscribe_name_owner_changed_internal (worker, name, NULL, worker->unique_name, match->cookie, error))
+ {
+ match_free (match);
+ return FALSE;
+ }
+
+ g_mutex_lock (&worker->matches_mutex);
+ worker->matches = g_list_prepend (worker->matches, match);
+ g_mutex_unlock (&worker->matches_mutex);
+ return TRUE;
+}
+
+
+/*
+ * _g_kdbus_subscribe_name_lost
+ */
+gboolean
+_g_kdbus_subscribe_name_lost (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error)
+{
+ Match *match;
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd;
+ gsize size, len;
+ gint ret;
+
+ if (match_rule[0] == '-')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ if (name != NULL)
+ {
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+ }
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ if (name)
+ len = strlen(name) + 1;
+ else
+ len = 0;
+
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = match->cookie;
+ item = cmd->items;
+
+ item->type = KDBUS_ITEM_NAME_REMOVE;
+ item->name_change.old_id.id = worker->unique_id;
+ item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
+
+ if (name)
+ memcpy(item->name_change.name, name, len);
+
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ (guint64) G_STRUCT_OFFSET(struct kdbus_notify_name_change, name) + len;
+ item = KDBUS_ITEM_NEXT(item);
+
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ if (!_g_kdbus_subscribe_name_owner_changed_internal (worker, name, worker->unique_name, NULL, match->cookie, error))
+ {
+ match_free (match);
+ return FALSE;
+ }
+
+ g_mutex_lock (&worker->matches_mutex);
+ worker->matches = g_list_prepend (worker->matches, match);
+ g_mutex_unlock (&worker->matches_mutex);
+ return TRUE;
+}
+
+
+/*
+ * _g_kdbus_subscribe_name_owner_changed
+ */
+gboolean
+_g_kdbus_subscribe_name_owner_changed (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error)
+{
+ Match *match;
+ struct kdbus_item *item;
+ struct kdbus_cmd_match *cmd;
+ gsize size, len;
+ gint ret;
+
+ if (match_rule[0] == '-')
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ match = match_new (match_rule);
+ if (!match)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+
+ if (name != NULL)
+ {
+ if (!g_dbus_is_name (name))
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_MATCH_RULE_INVALID,
+ "Invalid rule: %s", match_rule);
+ return FALSE;
+ }
+ }
+
+ /* 'name' argument is missing or is a unique name */
+ if (name == NULL || g_dbus_is_unique_name (name))
+ {
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, id_change) +
+ sizeof (struct kdbus_notify_id_change));
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = match->cookie;
+ item = cmd->items;
+
+ if (name)
+ item->id_change.id = strtoull (name + 3, NULL, 10);
+ else
+ item->id_change.id = KDBUS_MATCH_ID_ANY;
+
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, id_change) +
+ sizeof (struct kdbus_notify_id_change);
+
+ item->type = KDBUS_ITEM_ID_ADD;
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ item->type = KDBUS_ITEM_ID_REMOVE;
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+ }
+
+ /* 'name' argument is missing or is a well-known name */
+ if (name == NULL || !g_dbus_is_unique_name (name))
+ {
+ if (name)
+ len = strlen(name) + 1;
+ else
+ len = 0;
+
+ size = KDBUS_ALIGN8(G_STRUCT_OFFSET (struct kdbus_cmd_match, items) +
+ G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len);
+
+ cmd = g_alloca0 (size);
+ cmd->size = size;
+ cmd->cookie = match->cookie;
+ item = cmd->items;
+
+ item->name_change.old_id.id = KDBUS_MATCH_ID_ANY;
+ item->name_change.new_id.id = KDBUS_MATCH_ID_ANY;
+ item->size = (guint64) G_STRUCT_OFFSET (struct kdbus_item, name_change) +
+ (guint64) G_STRUCT_OFFSET (struct kdbus_notify_name_change, name) + len;
+
+ if (name)
+ memcpy(item->name_change.name, name, len);
+
+ item->type = KDBUS_ITEM_NAME_ADD;
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ item->type = KDBUS_ITEM_NAME_REMOVE;
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+
+ item->type = KDBUS_ITEM_NAME_CHANGE;
+ ret = ioctl(worker->fd, KDBUS_CMD_MATCH_ADD, cmd);
+ if (ret < 0)
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ "Error while adding a match");
+ match_free (match);
+ return FALSE;
+ }
+ }
+
+ g_mutex_lock (&worker->matches_mutex);
+ worker->matches = g_list_prepend (worker->matches, match);
+ g_mutex_unlock (&worker->matches_mutex);
+ return TRUE;
+}
+
+
+/*
+ * g_kdbus_setup_bloom:
+ * Based on bus-bloom.c from systemd
+ * http://cgit.freedesktop.org/systemd/systemd/tree/src/libsystemd/sd-bus/bus-bloom.c
+ */
+static void
+g_kdbus_setup_bloom (GKDBusWorker *worker,
+ GDBusMessage *dbus_msg,
+ struct kdbus_bloom_filter *bloom_filter)
+{
+ GVariant *body;
+ gchar *message_type;
+ const gchar *interface;
+ const gchar *member;
+ const gchar *path;
+ void *bloom_data;
+
+ body = g_dbus_message_get_body (dbus_msg);
+ message_type = _g_dbus_enum_to_string (G_TYPE_DBUS_MESSAGE_TYPE, g_dbus_message_get_message_type (dbus_msg));
+ interface = g_dbus_message_get_interface (dbus_msg);
+ member = g_dbus_message_get_member (dbus_msg);
+ path = g_dbus_message_get_path (dbus_msg);
+
+ bloom_data = bloom_filter->data;
+ memset (bloom_data, 0, worker->bloom_size);
+ bloom_filter->generation = 0;
+
+ g_kdbus_bloom_add_pair(worker, bloom_data, "message-type", message_type);
+
+ if (interface)
+ g_kdbus_bloom_add_pair(worker, bloom_data, "interface", interface);
+
+ if (member)
+ g_kdbus_bloom_add_pair(worker, bloom_data, "member", member);
+
+ if (path)
+ {
+ g_kdbus_bloom_add_pair(worker, bloom_data, "path", path);
+ g_kdbus_bloom_add_pair(worker, bloom_data, "path-slash-prefix", path);
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, "path-slash-prefix", path, '/');
+ }
+
+ if (body != NULL)
+ {
+ const GVariantType *body_type;
+ const GVariantType *arg_type;
+ guint cnt;
+
+ body_type = g_variant_get_type (body);
+
+ for (arg_type = g_variant_type_first (body_type), cnt = 0;
+ arg_type;
+ arg_type = g_variant_type_next (arg_type), cnt++)
+ {
+ gchar type_char = g_variant_type_peek_string (arg_type)[0];
+ gchar buf[sizeof("arg")-1 + 2 + sizeof("-slash-prefix")];
+ const gchar *str;
+ GVariant *child;
+ gchar *e;
+
+ if (type_char != 's' && type_char != 'o')
+ /* XXX: kdbus docs say "stop after first non-string" but I
+ * think they're wrong (vs. dbus-1 compat)...
+ */
+ continue;
+
+ child = g_variant_get_child_value (body, cnt);
+ str = g_variant_get_string (child, NULL);
+
+ e = stpcpy(buf, "arg");
+ if (cnt < 10)
+ *(e++) = '0' + (char) cnt;
+ else
+ {
+ *(e++) = '0' + (char) (cnt / 10);
+ *(e++) = '0' + (char) (cnt % 10);
+ }
+
+ /* We add this one for both strings and object paths */
+ strcpy(e, "-slash-prefix");
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '/');
+
+ /* But the others are only for strings */
+ if (type_char == 's')
+ {
+ strcpy(e, "-dot-prefix");
+ g_kdbus_bloom_add_prefixes(worker, bloom_data, buf, str, '.');
+
+ *e = 0;
+ g_kdbus_bloom_add_pair(worker, bloom_data, buf, str);
+ }
+
+ g_variant_unref (child);
+ }
+ }
+ g_free (message_type);
+}
+
+
+/*
+ * g_kdbus_translate_id_change
+ */
+static void
+g_kdbus_translate_id_change (GKDBusWorker *worker,
+ struct kdbus_item *item)
+{
+ GDBusMessage *signal_message;
+ gchar *name;
+
+ signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged");
+
+ name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->id_change.id);
+
+ g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+ g_dbus_message_set_body (signal_message,
+ g_variant_new ("(sss)",
+ name,
+ item->type == KDBUS_ITEM_ID_ADD ? "" : name,
+ item->type == KDBUS_ITEM_ID_ADD ? name : ""));
+
+ (* worker->message_received_callback) (signal_message, worker->user_data);
+
+ g_free (name);
+ g_object_unref (signal_message);
+}
+
+
+/*
+ * g_kdbus_translate_name_change
+ */
+static void
+g_kdbus_translate_name_change (GKDBusWorker *worker,
+ struct kdbus_item *item)
+{
+ GDBusMessage *signal_message;
+
+ signal_message = NULL;
+
+ /* NameAcquired */
+ if ((item->type == KDBUS_ITEM_NAME_ADD) ||
+ (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.new_id.id == worker->unique_id)))
+ {
+ signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameAcquired");
+
+ g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+ g_dbus_message_set_body (signal_message,
+ g_variant_new ("(s)", item->name_change.name));
+
+ (* worker->message_received_callback) (signal_message, worker->user_data);
+ g_object_unref (signal_message);
+ }
+
+ /* NameLost */
+ if ((item->type == KDBUS_ITEM_NAME_REMOVE) ||
+ (item->type == KDBUS_ITEM_NAME_CHANGE && ((guint64)item->name_change.old_id.id == worker->unique_id)))
+ {
+ signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameLost");
+
+ g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+ g_dbus_message_set_body (signal_message,
+ g_variant_new ("(s)", item->name_change.name));
+
+ (* worker->message_received_callback) (signal_message, worker->user_data);
+ g_object_unref (signal_message);
+ }
+
+ /* NameOwnerChanged */
+ if (1)
+ {
+ gchar *old_name;
+ gchar *new_name;
+
+ old_name = NULL;
+ new_name = NULL;
+
+ /* old_name */
+ if (!(item->type == KDBUS_ITEM_NAME_ADD || (item->name_change.old_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
+ old_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.old_id.id);
+
+ /* new_name */
+ if (!(item->type == KDBUS_ITEM_NAME_REMOVE || (item->name_change.new_id.flags & (KDBUS_NAME_IN_QUEUE|KDBUS_NAME_ACTIVATOR))))
+ new_name = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) item->name_change.new_id.id);
+ else
+ if (old_name == NULL)
+ return;
+
+ /* send signal */
+ signal_message = g_dbus_message_new_signal ("/org/freedesktop/DBus",
+ "org.freedesktop.DBus",
+ "NameOwnerChanged");
+ g_dbus_message_set_sender (signal_message, "org.freedesktop.DBus");
+ g_dbus_message_set_body (signal_message,
+ g_variant_new ("(sss)",
+ item->name_change.name,
+ old_name ? old_name : "",
+ new_name ? new_name : ""));
+
+ (* worker->message_received_callback) (signal_message, worker->user_data);
+
+ g_free (old_name);
+ g_free (new_name);
+ g_object_unref (signal_message);
+ }
+}
+
+
+/*
+ * g_kdbus_translate_kernel_reply
+ */
+static void
+g_kdbus_translate_kernel_reply (GKDBusWorker *worker,
+ struct kdbus_msg *msg,
+ struct kdbus_item *item)
+{
+ GDBusMessage *message;
+
+ message = g_dbus_message_new ();
+
+ g_dbus_message_set_message_type (message, G_DBUS_MESSAGE_TYPE_ERROR);
+ g_dbus_message_set_flags (message, G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED);
+ g_dbus_message_set_reply_serial (message, (guint32) msg->cookie_reply);
+
+ g_dbus_message_set_sender (message, "org.freedesktop.DBus");
+ g_dbus_message_set_destination (message, worker->unique_name);
+
+ g_dbus_message_set_error_name (message, "org.freedesktop.DBus.Error.NoReply");
+
+ if (item->type == KDBUS_ITEM_REPLY_TIMEOUT)
+ g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call timed out"));
+ else
+ g_dbus_message_set_body (message, g_variant_new ("(s)", "Method call peer died"));
+
+ (* worker->message_received_callback) (message, worker->user_data);
+
+ g_object_unref (message);
+}
+
+
+/*
+ * g_kdbus_decode_kernel_msg
+ */
+static void
+g_kdbus_decode_kernel_msg (GKDBusWorker *worker,
+ struct kdbus_msg *msg)
+{
+ struct kdbus_item *item = NULL;
+
+ KDBUS_ITEM_FOREACH(item, msg, items)
+ {
+ switch (item->type)
+ {
+ case KDBUS_ITEM_ID_ADD:
+ case KDBUS_ITEM_ID_REMOVE:
+ g_kdbus_translate_id_change (worker, item);
+ break;
+
+ case KDBUS_ITEM_NAME_ADD:
+ case KDBUS_ITEM_NAME_REMOVE:
+ case KDBUS_ITEM_NAME_CHANGE:
+ g_kdbus_translate_name_change (worker, item);
+ break;
+
+ case KDBUS_ITEM_REPLY_TIMEOUT:
+ case KDBUS_ITEM_REPLY_DEAD:
+ g_kdbus_translate_kernel_reply (worker, msg, item);
+ break;
+
+ case KDBUS_ITEM_TIMESTAMP:
+ break;
+
+ default:
+ g_warning ("kdbus: unknown field in kernel message - %lld", item->type);
+ }
+ }
+}
+
+
+/*
+ * g_kdbus_decode_dbus_msg
+ */
+static GKDBusMessage *
+g_kdbus_decode_dbus_msg (GKDBusWorker *worker,
+ struct kdbus_msg *msg)
+{
+ GKDBusMessage *kmsg;
+ struct kdbus_item *item;
+ gssize data_size = 0;
+ GArray *body_vectors;
+ gsize body_size;
+ GVariant *body, *value;
+ gchar *sender;
+ guint i;
+ GVariant *parts[2];
+ GVariantIter *fields_iter;
+ GString *owned_name;
+ guint8 endianness, type, flags, version;
+ guint64 key, serial;
+
+ kmsg = g_new0 (GKDBusMessage, 1);
+ kmsg->message = g_dbus_message_new();
+ kmsg->sender_euid = (uid_t) -1;
+ kmsg->sender_egid = (gid_t) -1;
+ kmsg->sender_seclabel = NULL;
+ kmsg->sender_names = NULL;
+
+ body_vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
+
+ item = msg->items;
+ body_size = 0;
+ owned_name = NULL;
+
+ KDBUS_ITEM_FOREACH(item, msg, items)
+ {
+ if (item->size < KDBUS_ITEM_HEADER_SIZE)
+ g_error("kdbus: %llu bytes - invalid data record", item->size);
+
+ data_size = item->size - KDBUS_ITEM_HEADER_SIZE;
+
+ switch (item->type)
+ {
+ case KDBUS_ITEM_DST_NAME:
+ /* Classic D-Bus doesn't make this known to the receiver, so
+ * we don't do it here either (for compatibility with the
+ * fallback case).
+ */
+ break;
+
+ case KDBUS_ITEM_PAYLOAD_OFF:
+ {
+ GVariantVector vector;
+ gsize flavour;
+
+ /* We want to make sure the bytes are aligned the same as
+ * they would be if they appeared in a contiguously
+ * allocated chunk of aligned memory.
+ *
+ * We decide what the alignment 'should' be by consulting
+ * body_size, which has been tracking the total size of the
+ * message up to this point.
+ *
+ * We then play around with the pointer by removing as many
+ * bytes as required to get it to the proper alignment (and
+ * copy extra bytes accordingly). This means that we will
+ * grab some extra data in the 'bytes', but it won't be
+ * shared with GVariant (which means there is no chance of
+ * it being accidentally retransmitted).
+ *
+ * The kernel does the same thing, so make sure we get the
+ * expected result. Because of the kernel doing the same,
+ * the result is that we will always be rounding-down to a
+ * multiple of 8 for the pointer, which means that the
+ * pointer will always be valid, assuming the original
+ * address was.
+ *
+ * We could fix this with a new GBytes constructor that took
+ * 'flavour' as a parameter, but it's not worth it...
+ */
+ flavour = body_size & 7;
+ g_assert ((item->vec.offset & 7) == flavour);
+
+ vector.gbytes = g_bytes_new (((guchar *) msg) + item->vec.offset - flavour, item->vec.size + flavour);
+ vector.data.pointer = g_bytes_get_data (vector.gbytes, NULL);
+ vector.data.pointer += flavour;
+ vector.size = item->vec.size;
+
+ g_array_append_val (body_vectors, vector);
+ body_size += vector.size;
+ }
+ break;
+
+ case KDBUS_ITEM_PAYLOAD_MEMFD:
+ {
+ GVariantVector vector;
+ const guchar *data;
+ gsize size;
+
+ vector.gbytes = g_bytes_new_take_zero_copy_fd_size (item->memfd.fd, item->memfd.size);
+ data = g_bytes_get_data (vector.gbytes, &size);
+
+ g_assert (item->memfd.size == size);
+
+ vector.data.pointer = data + item->memfd.start;
+ vector.size = item->memfd.size;
+
+ g_array_append_val (body_vectors, vector);
+ body_size += vector.size;
+ }
+ break;
+
+ case KDBUS_ITEM_FDS:
+ {
+ GUnixFDList *fd_list;
+
+ fd_list = g_unix_fd_list_new_from_array (item->fds, data_size / sizeof (int));
+ g_dbus_message_set_unix_fd_list (kmsg->message, fd_list);
+ g_object_unref (fd_list);
+ }
+ break;
+
+ /* [libdbuspolicy] read euid and egid values */
+ case KDBUS_ITEM_CREDS:
+
+ if ((uid_t) item->creds.euid != (uid_t) -1)
+ kmsg->sender_euid = (uid_t) item->creds.euid;
+
+ if ((gid_t) item->creds.egid != (gid_t) -1)
+ kmsg->sender_egid = (gid_t) item->creds.egid;
+
+ break;
+
+ /* [libdbuspolicy] read security label value */
+ case KDBUS_ITEM_SECLABEL:
+
+ /*if (item->str != NULL)*/
+ kmsg->sender_seclabel = g_strdup (item->str);
+
+ break;
+
+ /* [libdbuspolicy] read all owned well-known names */
+ case KDBUS_ITEM_OWNED_NAME:
+
+ if (g_dbus_is_name (item->name.name))
+ {
+ if (owned_name == NULL)
+ owned_name = g_string_new (item->name.name);
+ else
+ g_string_append_printf (owned_name, " %s", item->name.name);
+ }
+
+ break;
+
+ case KDBUS_ITEM_TIMESTAMP:
+ case KDBUS_ITEM_PIDS:
+ case KDBUS_ITEM_PID_COMM:
+ case KDBUS_ITEM_TID_COMM:
+ case KDBUS_ITEM_EXE:
+ case KDBUS_ITEM_CMDLINE:
+ case KDBUS_ITEM_CGROUP:
+ case KDBUS_ITEM_AUDIT:
+ case KDBUS_ITEM_CAPS:
+ case KDBUS_ITEM_CONN_DESCRIPTION:
+ case KDBUS_ITEM_AUXGROUPS:
+ case KDBUS_ITEM_NAME:
+ case KDBUS_ITEM_DST_ID:
+ case KDBUS_ITEM_BLOOM_FILTER:
+ break;
+
+ default:
+ g_warning ("kdbus: unknown filed - %lld", item->type);
+ break;
+ }
+ }
+
+ body = GLIB_PRIVATE_CALL(g_variant_from_vectors) (G_VARIANT_TYPE ("((yyyyuta{tv})v)"),
+ (GVariantVector *) body_vectors->data,
+ body_vectors->len, body_size, FALSE);
+ g_assert (body);
+
+ for (i = 0; i < body_vectors->len; i++)
+ g_bytes_unref (g_array_index (body_vectors, GVariantVector, i).gbytes);
+
+ g_array_free (body_vectors, TRUE);
+
+ parts[0] = g_variant_get_child_value (body, 0);
+ parts[1] = g_variant_get_child_value (body, 1);
+ g_variant_unref (body);
+
+ g_variant_get (parts[0], "(yyyyuta{tv})", &endianness, &type, &flags, &version, NULL, &serial, &fields_iter);
+ g_variant_unref (parts[0]);
+
+ while (g_variant_iter_loop (fields_iter, "{tv}", &key, &value))
+ {
+ switch (key)
+ {
+ case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
+ g_dbus_message_set_reply_serial (kmsg->message, (guint32) g_variant_get_uint64 (value));
+ continue;
+
+ default:
+ g_dbus_message_set_header (kmsg->message, key, value);
+ continue;
+ }
+ }
+
+ g_variant_iter_free (fields_iter);
+
+ g_dbus_message_set_flags (kmsg->message, flags);
+ g_dbus_message_set_serial (kmsg->message, serial);
+ g_dbus_message_set_message_type (kmsg->message, type);
+
+ body = g_variant_get_variant (parts[1]);
+ if (!g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ g_dbus_message_set_body (kmsg->message, body);
+ else
+ g_dbus_message_set_body (kmsg->message, NULL);
+
+ g_variant_unref (body);
+ g_variant_unref (parts[1]);
+
+ /* set 'sender' field */
+ sender = g_strdup_printf (":1.%"G_GUINT64_FORMAT, (guint64) msg->src_id);
+ g_dbus_message_set_sender (kmsg->message, sender);
+ g_free (sender);
+
+ /* owned name */
+ if (owned_name != NULL)
+ kmsg->sender_names = g_string_free (owned_name, FALSE);
+
+ return kmsg;
+}
+
+
+/*
+ * _g_kdbus_receive
+ */
+static void
+_g_kdbus_receive (GKDBusWorker *worker,
+ GError **error)
+{
+ struct kdbus_cmd_recv recv;
+ struct kdbus_msg *msg;
+ gboolean can_receive;
+ gint ret = 0;
+
+ can_receive = TRUE;
+ memset (&recv, 0, sizeof recv);
+ recv.size = sizeof (recv);
+
+again:
+ ret = ioctl (worker->fd, KDBUS_CMD_RECV, &recv);
+ if (ret < 0)
+ ret = errno;
+
+ if (recv.return_flags & KDBUS_RECV_RETURN_DROPPED_MSGS)
+ g_warning ("kdbus: %lld dropped broadcast messages", recv.dropped_msgs);
+
+ if (ret != 0)
+ {
+ if (ret == EINTR)
+ goto again;
+
+ if (ret == EAGAIN)
+ return;
+
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (ret),
+ _("Error while receiving message: %s"),
+ g_strerror (ret));
+ return;
+ }
+
+ msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + recv.msg.offset);
+
+ if (msg->payload_type == KDBUS_PAYLOAD_DBUS)
+ {
+ GKDBusMessage *kmsg;
+
+ kmsg = g_kdbus_decode_dbus_msg (worker, msg);
+
+#ifdef LIBDBUSPOLICY
+ if (worker->dbuspolicy != NULL)
+ {
+ if (g_dbus_message_get_message_type (kmsg->message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL ||
+ g_dbus_message_get_message_type (kmsg->message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ if ((kmsg->sender_euid != (uid_t) -1) && (kmsg->sender_egid != (gid_t) -1) &&
+ (kmsg->sender_seclabel != NULL))
+ {
+ gint check;
+ const gchar *destination = g_dbus_message_get_destination (kmsg->message);
+ if (!destination)
+ destination = worker->unique_name;
+
+ check = dbuspolicy1_check_in (worker->dbuspolicy,
+ destination,
+ kmsg->sender_names,
+ kmsg->sender_seclabel,
+ kmsg->sender_euid,
+ kmsg->sender_egid,
+ g_dbus_message_get_path (kmsg->message),
+ g_dbus_message_get_interface (kmsg->message),
+ g_dbus_message_get_member (kmsg->message),
+ g_dbus_message_get_message_type (kmsg->message),
+ NULL, 0, 0);
+ if (check != 1)
+ {
+ can_receive = FALSE;
+ }
+ }
+ else
+ {
+ can_receive = FALSE;
+ }
+ }
+ }
+#endif
+
+ if (can_receive)
+ (* worker->message_received_callback) (kmsg->message, worker->user_data);
+
+ if (kmsg->sender_seclabel != NULL)
+ g_free (kmsg->sender_seclabel);
+
+ if (kmsg->sender_names != NULL)
+ g_free (kmsg->sender_names);
+
+ g_object_unref (kmsg->message);
+ g_free (kmsg);
+ }
+ else if (msg->payload_type == KDBUS_PAYLOAD_KERNEL)
+ g_kdbus_decode_kernel_msg (worker, msg);
+ else
+ {
+ g_set_error (error,
+ G_DBUS_ERROR,
+ G_DBUS_ERROR_FAILED,
+ _("Received unknown payload type"));
+ }
+
+ g_kdbus_close_msg (worker, msg);
+ return;
+}
+
+static gboolean
+g_kdbus_msg_append_item (struct kdbus_msg *msg,
+ gsize type,
+ gconstpointer data,
+ gsize size)
+{
+ struct kdbus_item *item;
+ gsize item_size;
+
+ item_size = size + G_STRUCT_OFFSET(struct kdbus_item, data);
+
+ msg->size += (-msg->size) & 7;
+ item = (struct kdbus_item *) ((guchar *) msg + msg->size);
+ item->type = type;
+ item->size = item_size;
+ memcpy (item->data, data, size);
+
+ msg->size += item_size;
+
+ return TRUE;
+}
+
+static gboolean
+g_kdbus_msg_append_payload_vec (struct kdbus_msg *msg,
+ gconstpointer data,
+ gsize size)
+{
+ gboolean ok = TRUE;
+ do {
+ struct kdbus_vec vec = {
+ .size = size <= KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE ? size : KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE,
+ .address = (gsize) data
+ };
+ ok = g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_VEC, &vec, sizeof vec);
+ data = (char*)data + vec.size;
+ size -= vec.size;
+ } while (size > 0 && ok);
+ return ok;
+}
+
+static gboolean
+g_kdbus_msg_append_payload_memfd (struct kdbus_msg *msg,
+ gint fd,
+ gsize offset,
+ gsize size)
+{
+ struct kdbus_memfd mfd = {
+ .start = offset,
+ .size = size,
+ .fd = fd,
+ };
+
+ return g_kdbus_msg_append_item (msg, KDBUS_ITEM_PAYLOAD_MEMFD, &mfd, sizeof mfd);
+}
+
+static struct kdbus_bloom_filter *
+g_kdbus_msg_append_bloom (struct kdbus_msg *msg,
+ gsize size)
+{
+ struct kdbus_item *bloom_item;
+ gsize bloom_item_size;
+
+ bloom_item_size = (gulong) G_STRUCT_OFFSET (struct kdbus_item, bloom_filter) +
+ (gulong) G_STRUCT_OFFSET (struct kdbus_bloom_filter, data) +
+ size;
+
+ msg->size += (-msg->size) & 7;
+ bloom_item = (struct kdbus_item *) ((guchar *) msg + msg->size);
+
+ bloom_item->size = bloom_item_size;
+ bloom_item->type = KDBUS_ITEM_BLOOM_FILTER;
+
+ msg->size += bloom_item->size;
+ return &bloom_item->bloom_filter;
+}
+
+/*
+ * Returns header size.
+ */
+static gsize
+prepare_body_vectors (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GVariantVectors *body_vectors,
+ gboolean *lg_h_field_exist)
+{
+ struct dbus_fixed_header fh;
+ GHashTableIter header_iter;
+ GVariantBuilder builder;
+ gpointer key, value;
+ GVariant *parts[3];
+ GVariant *body;
+ gsize header_size;
+
+ *lg_h_field_exist = FALSE;
+
+ fh.endian = (G_BYTE_ORDER == G_LITTLE_ENDIAN) ? 'l': 'B';
+ fh.type = g_dbus_message_get_message_type (message);
+ fh.flags = g_dbus_message_get_flags (message);
+ fh.version = 2;
+ fh.reserved = 0;
+ fh.serial = g_dbus_message_get_serial (message);
+ parts[0] = g_variant_new_from_data (DBUS_FIXED_HEADER_TYPE, &fh, sizeof fh, TRUE, NULL, NULL);
+ g_assert_nonnull (parts[0]);
+
+ g_dbus_message_init_header_iter (message, &header_iter);
+ g_variant_builder_init (&builder, DBUS_EXTENDED_HEADER_TYPE);
+
+ /* We set the sender field to the correct value for ourselves */
+ g_variant_builder_add (&builder, "{tv}",
+ (guint64) G_DBUS_MESSAGE_HEADER_FIELD_SENDER,
+ g_variant_new_printf (":1.%"G_GUINT64_FORMAT, worker->unique_id));
+
+ while (g_hash_table_iter_next (&header_iter, &key, &value))
+ {
+ guint64 key_int = (gsize) key;
+
+ switch (key_int)
+ {
+ /* These are the normal header fields that get passed
+ * straight through.
+ */
+ case G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL:
+ g_variant_builder_add (&builder, "{tv}", key_int, g_variant_new_uint64 (g_dbus_message_get_reply_serial(message)));
+ continue;
+
+
+ case G_DBUS_MESSAGE_HEADER_FIELD_PATH:
+ case G_DBUS_MESSAGE_HEADER_FIELD_INTERFACE:
+ case G_DBUS_MESSAGE_HEADER_FIELD_MEMBER:
+ case G_DBUS_MESSAGE_HEADER_FIELD_ERROR_NAME:
+ case G_DBUS_MESSAGE_HEADER_FIELD_DESTINATION:
+ case G_DBUS_MESSAGE_HEADER_FIELD_NUM_UNIX_FDS:
+ g_variant_builder_add (&builder, "{tv}", key_int, value);
+ /* This is a little bit gross.
+ *
+ * We must send the header part of the message in a single
+ * vector as per kdbus rules, but the GVariant serialiser
+ * code will split any item >= 128 bytes into its own
+ * vector to save the copy.
+ *
+ * Anyway, kdbus does not check it, and libraries handle it...
+ */
+
+ if (g_variant_get_size (value) >= 128)
+ *lg_h_field_exist = TRUE;
+
+ continue;
+
+ /* We send this one unconditionally, but set it ourselves */
+ case G_DBUS_MESSAGE_HEADER_FIELD_SENDER:
+ continue;
+
+ /* We don't send these at all in GVariant format */
+ case G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE:
+ continue;
+
+ default:
+ g_assert_not_reached ();
+ }
+ }
+ parts[1] = g_variant_builder_end (&builder);
+ g_assert_nonnull (parts[1]);
+
+ body = g_dbus_message_get_body (message);
+ if (!body)
+ body = g_variant_new ("()");
+ parts[2] = g_variant_new_variant (body);
+ g_assert_nonnull (parts[2]);
+
+ header_size = g_variant_get_size (parts[0]) + g_variant_get_size (parts[1]);
+
+ body = g_variant_ref_sink (g_variant_new_tuple (parts, G_N_ELEMENTS (parts)));
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (body, body_vectors);
+
+ /* Sanity check to make sure the header is really contiguous:
+ *
+ * - we must have at least one vector in the output
+ * - the first vector must completely contain at least the header; this
+ * condition must be assured later, during composing kdbus vectors.
+ */
+ g_assert_cmpint (body_vectors->vectors->len, >, 0);
+
+ g_variant_unref (body);
+
+ return header_size;
+}
+
+static void
+make_single_header_vector (GVariantVectors *body_vectors,
+ gsize header_size,
+ gboolean lg_h_field_exist)
+{
+ guint i = 0;
+ gsize added_vectors_size = 0;
+ GVariantVector *first_vector;
+
+ /* Merge all header vectors into single vector */
+ first_vector = &g_array_index (body_vectors->vectors, GVariantVector, 0);
+ if (first_vector->size < header_size)
+ {
+ /* There are multiple header vectors, we have to join them together into a single one */
+ GByteArray *header = g_byte_array_sized_new (header_size);
+ gsize dummy_size;
+
+ g_assert_nonnull (header);
+ g_assert_true (lg_h_field_exist);
+
+ while (added_vectors_size < header_size && i < body_vectors->vectors->len)
+ {
+ GVariantVector *vector = &g_array_index (body_vectors->vectors, GVariantVector, i);
+
+ if (vector->gbytes)
+ {
+ g_byte_array_append (header, vector->data.pointer, vector->size);
+ g_bytes_unref (vector->gbytes);
+ }
+ else
+ {
+ g_byte_array_append (header, body_vectors->extra_bytes->data + vector->data.offset, vector->size);
+ }
+
+ added_vectors_size += vector->size;
+ i++;
+ }
+
+ /* Sanity check if the first vector contains at least the complete header */
+ g_assert_cmpint (added_vectors_size, >=, header_size);
+
+ first_vector->gbytes = g_byte_array_free_to_bytes (header);
+ first_vector->data.pointer = g_bytes_get_data (first_vector->gbytes, &dummy_size);
+ first_vector->size = added_vectors_size;
+
+ g_array_remove_range (body_vectors->vectors, 1, i-1);
+ }
+ /* else: If there is only a single header vector, then just go */
+}
+
+static gboolean
+add_message_destination_item (struct kdbus_msg *msg,
+ GDBusMessage *message,
+ GError **error)
+{
+ const gchar *dst_name;
+
+ dst_name = g_dbus_message_get_destination (message);
+ if (dst_name != NULL)
+ {
+ if (g_dbus_is_unique_name (dst_name))
+ {
+ if (dst_name[1] != '1' || dst_name[2] != '.')
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Invalid unique D-Bus name '%s'", dst_name);
+ return FALSE;
+ }
+
+ /* We already know that it passes the checks for unique
+ * names, so no need to perform error checking on strtoull.
+ */
+ msg->dst_id = strtoull (dst_name + 3, NULL, 10);
+ }
+ else
+ {
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_DST_NAME, dst_name, strlen (dst_name) + 1);
+ msg->dst_id = KDBUS_DST_ID_NAME;
+ }
+ }
+ else
+ msg->dst_id = KDBUS_DST_ID_BROADCAST;
+
+ return TRUE;
+}
+
+static void
+add_file_descriptors_item (struct kdbus_msg *msg,
+ GDBusMessage *message)
+{
+ GUnixFDList *fd_list;
+
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list != NULL)
+ {
+ const gint *fds;
+ gint n_fds;
+
+ fds = g_unix_fd_list_peek_fds (fd_list, &n_fds);
+
+ if (n_fds)
+ g_kdbus_msg_append_item (msg, KDBUS_ITEM_FDS, fds, sizeof (gint) * n_fds);
+ }
+}
+
+static gboolean
+add_body_vectors (struct kdbus_msg *msg,
+ GVariantVectors *body_vectors,
+ gint *memfd_fd)
+{
+ guint i = 0;
+
+ /* Add all the vectors to the kdbus message */
+ for (; i < body_vectors->vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors->vectors, GVariantVector, i);
+
+ if (vector.gbytes)
+ {
+ const guchar *bytes_data;
+ gboolean use_memfd;
+ gsize bytes_size;
+
+ use_memfd = FALSE;
+ bytes_data = g_bytes_get_data (vector.gbytes, &bytes_size);
+
+ /* check whether we can and should use memfd */
+ if ((msg->dst_id != KDBUS_DST_ID_BROADCAST) && (bytes_size > KDBUS_MEMFD_THRESHOLD))
+ use_memfd = TRUE;
+
+ if (use_memfd)
+ {
+ const guchar *bytes_data_wr;
+ gint64 wr;
+
+ /* create memfd object */
+ *memfd_fd = glib_linux_memfd_create ("glib-kdbus-memfd", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ if (*memfd_fd == -1)
+ {
+ g_warning ("kdbus: missing kernel memfd support");
+ use_memfd = FALSE; /* send as PAYLOAD_VEC item */
+ }
+ else
+ {
+ /* write data to memfd */
+ bytes_data_wr = bytes_data;
+ while (bytes_size)
+ {
+ wr = write (*memfd_fd, bytes_data_wr, bytes_size);
+ if (wr < 0)
+ g_warning ("kdbus: writing to memfd failed: (%d) %m", errno);
+
+ bytes_size -= wr;
+ bytes_data_wr += wr;
+ }
+
+ /* seal memfd */
+ if (!g_unix_fd_ensure_zero_copy_safe (*memfd_fd))
+ {
+ g_warning ("kdbus: memfd sealing failed");
+ use_memfd = FALSE; /* send as PAYLOAD_VEC item */
+ }
+ else
+ {
+ /* attach memfd item */
+ if (!g_kdbus_msg_append_payload_memfd (msg, *memfd_fd, vector.data.pointer - bytes_data, vector.size))
+ return FALSE;
+ }
+ } /* *memfd_fd == -1 */
+ } /* use_memfd */
+
+ if (!use_memfd)
+ if (!g_kdbus_msg_append_payload_vec (msg, vector.data.pointer, vector.size))
+ return FALSE;
+ }
+ else
+ if (!g_kdbus_msg_append_payload_vec (msg, body_vectors->extra_bytes->data + vector.data.offset, vector.size))
+ return FALSE;
+ }
+ return TRUE;
+}
+
+static gboolean
+add_bloom_item (struct kdbus_msg *msg,
+ GDBusMessage *message,
+ GKDBusWorker *worker)
+{
+ struct kdbus_bloom_filter *bloom_filter;
+
+ if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ {
+ msg->flags |= KDBUS_MSG_SIGNAL;
+ bloom_filter = g_kdbus_msg_append_bloom (msg, worker->bloom_size);
+ if (bloom_filter == NULL)
+ return FALSE;
+ g_kdbus_setup_bloom (worker, message, bloom_filter);
+ }
+ return TRUE;
+}
+
+static gsize
+compute_msg_size (GDBusMessage *message,
+ GKDBusWorker *worker,
+ GVariantVectors *body_vectors)
+{
+ gsize items_size = 0;
+ GUnixFDList *fd_list;
+ const gchar *dst_name;
+ guint i;
+ GDBusMessageType msg_type = g_dbus_message_get_message_type (message);
+
+ /* payload - check which vectors will become memfds */
+ for (i = 0; i < body_vectors->vectors->len; i++)
+ {
+ GVariantVector vector = g_array_index (body_vectors->vectors, GVariantVector, i);
+ gsize payload_size;
+ gsize kdbus_num_vectors;
+
+ if (vector.gbytes)
+ {
+ payload_size = g_bytes_get_size (vector.gbytes);
+ if (msg_type != G_DBUS_MESSAGE_TYPE_SIGNAL && payload_size > KDBUS_MEMFD_THRESHOLD)
+ {
+ /* We can do this because we know that struct kdbus_memfd is larger or equal than
+ struct kdbus_vec. struct kdbus_vec is fallback option if memfd does not work */
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_memfd));
+ continue;
+ }
+ }
+ else
+ {
+ payload_size = vector.size;
+ }
+
+ kdbus_num_vectors = (payload_size + KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE - 1) / KDBUS_MSG_MAX_PAYLOAD_VEC_SIZE;
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_vec)) * kdbus_num_vectors;
+ }
+
+ /* file descriptors */
+ fd_list = g_dbus_message_get_unix_fd_list (message);
+ if (fd_list != NULL)
+ items_size += KDBUS_ITEM_SIZE (g_unix_fd_list_get_length (fd_list) * sizeof(gint));
+
+ /* destination */
+ dst_name = g_dbus_message_get_destination (message);
+ if (dst_name != NULL)
+ items_size += KDBUS_ITEM_SIZE (strlen (dst_name) + 1);
+
+ /* bloom filters */
+ if (msg_type == G_DBUS_MESSAGE_TYPE_SIGNAL)
+ items_size += KDBUS_ITEM_SIZE (sizeof (struct kdbus_bloom_filter) + worker->bloom_size);
+
+ return sizeof (struct kdbus_msg) + items_size;
+}
+
+#ifdef LIBDBUSPOLICY
+static GDBusMessage*
+create_access_error_reply (GDBusMessage *message,
+ const GQuark domain,
+ const gint code,
+ const gchar *format,
+ ...)
+{
+ gchar *error_text;
+ GError *access_error;
+ gchar *dbus_error_name;
+ GDBusMessage *error_reply;
+ va_list args;
+
+ va_start (args, format);
+ error_text = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ access_error = NULL;
+ g_set_error (&access_error, domain, code, "%s", error_text);
+ dbus_error_name = g_dbus_error_encode_gerror (access_error);
+ g_error_free (access_error);
+
+ error_reply = g_dbus_message_new_method_error (message, dbus_error_name, "%s", error_text);
+ g_free (dbus_error_name);
+ g_free (error_text);
+ return error_reply;
+}
+#endif
+
+#ifdef LIBDBUSPOLICY
+static GDBusMessage*
+check_result_to_error_reply (GDBusMessage *message,
+ const gint check_result)
+{
+ switch (check_result)
+ {
+ case DBUSPOLICY_RESULT_DENY:
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+ "Cannot send message - message rejected due to XML security policies");
+
+ case DBUSPOLICY_RESULT_DEST_NOT_AVAILABLE:
+ if (g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START)
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Name \"%s\" does not exist", g_dbus_message_get_destination (message));
+ else
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
+ "Cannot send message - destination '%s' not known", g_dbus_message_get_destination (message));
+
+ case DBUSPOLICY_RESULT_KDBUS_ERROR:
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+ "Cannot send message - message rejected due to internal libdbuspolicy error (kdbus)");
+
+ case DBUSPOLICY_RESULT_CYNARA_ERROR:
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+ "Cannot send message - message rejected due to internal libdbuspolicy error (Cynara)");
+
+ default:
+ return create_access_error_reply (message, G_DBUS_ERROR, G_DBUS_ERROR_ACCESS_DENIED,
+ "Cannot send message - unknown libdbuspolicy error");
+ }
+}
+#endif
+
+/*
+ * _g_kdbus_send
+ */
+static gboolean
+_g_kdbus_send (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GDBusMessage **out_reply,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error)
+{
+ struct kdbus_msg *msg;
+ GVariantVectors body_vectors;
+ struct kdbus_cmd_send *send;
+ gsize send_size;
+ gboolean result = FALSE;
+ gboolean lg_h_field_exist = FALSE;
+
+ gint memfd_fd;
+ gint cancel_fd;
+
+ gsize header_size;
+ gsize msg_size;
+
+ g_return_val_if_fail (G_IS_KDBUS_WORKER (worker), FALSE);
+
+ send = NULL;
+ send_size = sizeof(*send);
+
+ /* Prepare message body - it is needed for kdbus msg size computation */
+ header_size = prepare_body_vectors (worker, message, &body_vectors, &lg_h_field_exist);
+ make_single_header_vector (&body_vectors, header_size, lg_h_field_exist);
+
+ /* We precompute needed size for the message to allocate exact space instead
+ of some arbitrary amount */
+ msg_size = compute_msg_size (message, worker, &body_vectors);
+ if (msg_size <= KDBUS_MSG_MAX_SIZE)
+ {
+ msg = g_alloca (msg_size);
+ memset (msg, 0, msg_size);
+ }
+ else
+ {
+ msg = g_malloc0 (msg_size);
+ }
+ g_assert_nonnull (msg);
+
+ memfd_fd = -1;
+ cancel_fd = -1;
+
+ /* fill in as we go... */
+ msg->size = sizeof (struct kdbus_msg);
+ msg->payload_type = KDBUS_PAYLOAD_DBUS;
+ msg->cookie = g_dbus_message_get_serial(message);
+
+ /* Message destination */
+ if (!add_message_destination_item (msg, message, error))
+ goto out;
+
+ /* File descriptors */
+ add_file_descriptors_item (msg, message);
+
+ if (!add_body_vectors (msg, &body_vectors, &memfd_fd))
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "message serialisation error: body vectors");
+ g_warning ("kdbus: message serialisation error: body vectors");
+ goto out;
+ }
+
+ /*
+ * set message flags
+ */
+ msg->flags = ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_REPLY_EXPECTED) ? 0 : KDBUS_MSG_EXPECT_REPLY) |
+ ((g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START) ? KDBUS_MSG_NO_AUTO_START : 0);
+
+ if ((msg->flags) & KDBUS_MSG_EXPECT_REPLY)
+ msg->timeout_ns = 1U | ( /* ensure nonzero */
+ 1000U * g_get_monotonic_time() + (
+ timeout_msec == -1 ? DBUS_DEFAULT_TIMEOUT_MSEC * 1000000LLU :
+ timeout_msec == G_MAXINT ? KDBUS_INFINITE_TIMEOUT_NS :
+ (guint64)timeout_msec * 1000000U
+ )
+ );
+ else
+ msg->cookie_reply = g_dbus_message_get_reply_serial(message);
+
+ /*
+ * append bloom filter item for broadcast signals
+ */
+ if (!add_bloom_item (msg, message, worker))
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED,
+ "message serialisation error: bloom filters");
+ g_warning ("kdbus: message serialisation error: bloom filters");
+ goto out;
+ }
+
+ if (out_reply != NULL && cancellable)
+ {
+ cancel_fd = g_cancellable_get_fd (cancellable);
+ if (cancel_fd != -1)
+ send_size += KDBUS_ITEM_SIZE (sizeof(cancel_fd));
+ }
+
+ g_assert_cmpuint (msg->size, <=, msg_size);
+
+ send = g_alloca0 (send_size);
+ send->size = send_size;
+ send->msg_address = (gsize) msg;
+
+ if (out_reply != NULL)
+ {
+ /* synchronous call */
+ send->flags = KDBUS_SEND_SYNC_REPLY;
+
+ if (cancel_fd != -1)
+ {
+ struct kdbus_item *item;
+
+ item = send->items;
+ item->type = KDBUS_ITEM_CANCEL_FD;
+ item->size = KDBUS_ITEM_HEADER_SIZE + sizeof(cancel_fd);
+ item->fds[0] = cancel_fd;
+ }
+ }
+ else
+ {
+ /* asynchronous call */
+ send->flags = 0;
+ }
+
+ /*
+ * show debug
+ */
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " >>>> SENT D-Bus/kdbus message\n");
+ s = g_dbus_message_print (message, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
+
+ /*
+ * check policy
+ */
+#ifdef LIBDBUSPOLICY
+ if (worker->dbuspolicy != NULL)
+ {
+ if (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_METHOD_CALL ||
+ (g_dbus_message_get_message_type (message) == G_DBUS_MESSAGE_TYPE_SIGNAL &&
+ g_dbus_message_get_destination (message) != NULL))
+ {
+ gint check;
+
+ check = dbuspolicy1_check_out (worker->dbuspolicy,
+ g_dbus_message_get_destination (message),
+ worker->unique_name,
+ g_dbus_message_get_path (message),
+ g_dbus_message_get_interface (message),
+ g_dbus_message_get_member (message),
+ g_dbus_message_get_message_type (message),
+ NULL, 0, 0);
+ if (check != DBUSPOLICY_RESULT_ALLOW)
+ {
+ GDBusMessage *access_error_message;
+ access_error_message = check_result_to_error_reply (message, check);
+ result = TRUE;
+ if (out_reply != NULL)
+ {
+ *out_reply = access_error_message;
+ }
+ else
+ {
+ send_synthetic_message (worker, access_error_message);
+ }
+
+ goto out;
+ }
+ }
+ }
+#endif
+
+ /*
+ * send message
+ */
+ if (ioctl(worker->fd, KDBUS_CMD_SEND, send))
+ {
+ int ret = errno;
+ gchar *info;
+ if (asprintf (&info, "sender=%s destination=%s path=%s interface=%s member=%s type=%d",
+ g_dbus_message_get_sender (message),
+ g_dbus_message_get_destination (message),
+ g_dbus_message_get_path (message),
+ g_dbus_message_get_interface (message),
+ g_dbus_message_get_member (message),
+ g_dbus_message_get_message_type (message)) < 0)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s", g_strerror(errno));
+ /* If asprintf fails, we lose the ioctl errno,
+ * but without info, we can't give a useful error message.
+ * In practice though, asprintf failure is exceedingly rare.
+ */
+ }
+ else
+ {
+ errno = ret;
+ if (errno == ENXIO || errno == ESRCH)
+ {
+ if (g_dbus_message_get_flags (message) & G_DBUS_MESSAGE_FLAGS_NO_AUTO_START)
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_NAME_HAS_NO_OWNER,
+ "Name \"%s\" does not exist, %s", g_dbus_message_get_destination (message), info);
+ else
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
+ "Destination '%s' not known, %s", g_dbus_message_get_destination (message), info);
+ }
+ else if (errno == EADDRNOTAVAIL)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_SERVICE_UNKNOWN,
+ "No support for activation for name: %s, %s", g_dbus_message_get_destination (message), info);
+ }
+ else if (errno == EXFULL)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
+ "The memory pool of the receiver is full, %s", info);
+ }
+ else if (errno == ENOBUFS)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
+ "Too many pending messages on the receiver side, %s", info);
+ }
+ else if (errno == EMSGSIZE)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
+ "The size of the message is excessive, %s", info);
+ }
+ else if (errno == EMLINK)
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_LIMITS_EXCEEDED,
+ "The maximum number of pending replies per connection has been reached, %s", info);
+ }
+ else if (errno == ECANCELED)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_CANCELLED,
+ "Operation was cancelled, %s", info);
+ }
+ else if (errno == ETIMEDOUT)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_TIMED_OUT,
+ "Timeout was reached, %s", info);
+ }
+ else if (errno == EPERM)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
+ "Permission denied, %s", info);
+ }
+ else
+ {
+ g_set_error (error, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, "%s, %s", g_strerror(errno), info);
+ g_warning ("kdbus: %s, %s", g_strerror(errno), info);
+ }
+ free(info);
+ }
+ }
+ else
+ {
+ result = TRUE;
+ if (out_reply != NULL)
+ {
+ GKDBusMessage *kmsg;
+ struct kdbus_msg *kdbus_msg;
+
+ kdbus_msg = (struct kdbus_msg *)((guint8 *)worker->kdbus_buffer + send->reply.offset);
+
+ kmsg = g_kdbus_decode_dbus_msg (worker, kdbus_msg);
+ g_kdbus_close_msg (worker, kdbus_msg);
+
+ *out_reply = kmsg->message;
+
+ if (kmsg->sender_seclabel != NULL)
+ g_free (kmsg->sender_seclabel);
+
+ if (kmsg->sender_names != NULL)
+ g_free (kmsg->sender_names);
+
+ g_free (kmsg);
+
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " <<<< RECEIVED D-Bus message\n");
+ s = g_dbus_message_print (*out_reply, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
+ }
+ }
+
+out:
+ if (msg_size > KDBUS_MSG_MAX_SIZE)
+ g_free (msg);
+
+ if (cancel_fd != -1)
+ g_cancellable_release_fd (cancellable);
+
+ if (memfd_fd != -1)
+ close (memfd_fd);
+
+ GLIB_PRIVATE_CALL(g_variant_vectors_deinit) (&body_vectors);
+
+ return result;
+}
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+static void
+g_kdbus_worker_finalize (GObject *object)
+{
+ GKDBusWorker *worker;
+ GList *match;
+
+ worker = G_KDBUS_WORKER (object);
+
+ if (worker->kdbus_buffer != NULL)
+ {
+ munmap (worker->kdbus_buffer, worker->receive_pool_size);
+ worker->kdbus_buffer = NULL;
+ worker->receive_pool_size = 0;
+ }
+
+ if (worker->unique_name != NULL)
+ g_free (worker->unique_name);
+ worker->unique_name = NULL;
+
+ for (match = worker->matches; match != NULL; match = match->next)
+ match_free (match->data);
+ g_list_free (worker->matches);
+ g_mutex_clear (&worker->matches_mutex);
+
+#ifdef LIBDBUSPOLICY
+ if (worker->dbuspolicy != NULL)
+ dbuspolicy1_free (worker->dbuspolicy);
+#endif
+
+ if (worker->fd != -1 && !worker->closed)
+ _g_kdbus_close (worker);
+
+ G_OBJECT_CLASS (g_kdbus_worker_parent_class)->finalize (object);
+}
+
+static void
+g_kdbus_worker_class_init (GKDBusWorkerClass *class)
+{
+ class->finalize = g_kdbus_worker_finalize;
+}
+
+static void
+g_kdbus_worker_init (GKDBusWorker *worker)
+{
+ worker->fd = -1;
+
+ worker->context = NULL;
+ worker->loop = NULL;
+ worker->thread = NULL;
+ worker->source = 0;
+
+ worker->kdbus_buffer = NULL;
+ worker->receive_pool_size = 0;
+ worker->unique_name = NULL;
+ worker->unique_id = -1;
+
+ worker->flags = KDBUS_HELLO_ACCEPT_FD;
+ worker->attach_flags_send = _KDBUS_ATTACH_ALL;
+ worker->attach_flags_recv = _KDBUS_ATTACH_ALL;
+
+ worker->bloom_size = 0;
+ worker->bloom_n_hash = 0;
+ worker->matches = NULL;
+ g_mutex_init (&worker->matches_mutex);
+
+#ifdef LIBDBUSPOLICY
+ worker->dbuspolicy = NULL;
+#endif
+}
+
+static gpointer
+_g_kdbus_worker_thread (gpointer _data)
+{
+ GMainLoop *loop = (GMainLoop *) _data;
+
+ g_main_loop_run (loop);
+
+ g_main_loop_unref (loop);
+
+ return NULL;
+}
+
+GKDBusWorker *
+_g_kdbus_worker_new (const gchar *address,
+ GError **error)
+{
+ GKDBusWorker *worker;
+
+ worker = g_object_new (G_TYPE_KDBUS_WORKER, NULL);
+ if (!_g_kdbus_open (worker, address, error))
+ {
+ g_object_unref (worker);
+ return NULL;
+ }
+
+ worker->context = g_main_context_new ();
+ worker->loop = g_main_loop_new (worker->context, FALSE);
+ worker->thread = g_thread_new ("gkdbus", _g_kdbus_worker_thread, g_main_loop_ref(worker->loop));
+
+ return worker;
+}
+
+void
+_g_kdbus_worker_associate (GKDBusWorker *worker,
+ GDBusCapabilityFlags capabilities,
+ GDBusWorkerMessageReceivedCallback message_received_callback,
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
+ GDBusWorkerDisconnectedCallback disconnected_callback,
+ gpointer user_data)
+{
+ worker->capabilities = capabilities;
+ worker->message_received_callback = message_received_callback;
+ worker->message_about_to_be_sent_callback = message_about_to_be_sent_callback;
+ worker->disconnected_callback = disconnected_callback;
+ worker->user_data = user_data;
+}
+
+static gboolean
+g_kdbus_ready (gint fd,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ GKDBusWorker *worker;
+ GError *error;
+
+ worker = user_data;
+ error = NULL;
+
+ _g_kdbus_receive (worker, &error);
+ g_assert_no_error (error);
+
+ return G_SOURCE_CONTINUE;
+}
+
+void
+_g_kdbus_worker_unfreeze (GKDBusWorker *worker)
+{
+ gchar *name;
+
+ if (worker->source != NULL)
+ return;
+
+ worker->source = g_unix_fd_source_new (worker->fd, G_IO_IN);
+
+ g_source_set_callback (worker->source, (GSourceFunc) g_kdbus_ready,
+ g_object_ref (worker), g_object_unref);
+ name = g_strdup_printf ("kdbus worker");
+ g_source_set_name (worker->source, name);
+ g_free (name);
+
+ g_source_attach (worker->source, worker->context);
+}
+
+gboolean
+_g_kdbus_worker_send_message (GKDBusWorker *worker,
+ GDBusMessage *message,
+ gint timeout_msec,
+ GError **error)
+{
+#ifdef DBUS_DAEMON_EMULATION
+ if (_is_message_to_dbus_daemon (message))
+ {
+ GDBusMessage *reply = NULL;
+ reply = _dbus_daemon_synthetic_reply (worker, message, FALSE);
+
+ if (reply)
+ {
+ SyntheticReplyData *data;
+
+ data = g_new0 (SyntheticReplyData, 1);
+
+ data->worker = worker;
+ data->message = reply;
+
+ g_main_context_invoke (worker->context, deliver_synthetic_reply, data);
+ }
+
+ return TRUE;
+ }
+#endif /* DBUS_DAEMON_EMULATION */
+
+ return _g_kdbus_send (worker, message, NULL, timeout_msec, NULL, error);
+}
+
+gboolean
+_g_kdbus_worker_send_message_sync (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GDBusMessage **out_reply,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error)
+{
+#ifdef DBUS_DAEMON_EMULATION
+ if (_is_message_to_dbus_daemon (message))
+ {
+ *out_reply = _dbus_daemon_synthetic_reply (worker, message, TRUE);
+ return TRUE;
+ }
+#endif /* DBUS_DAEMON_EMULATION */
+
+ return _g_kdbus_send (worker, message, out_reply, timeout_msec, cancellable, error);
+}
+
+gboolean
+_g_kdbus_worker_flush_sync (GKDBusWorker *worker)
+{
+ return TRUE;
+}
+
+void
+_g_kdbus_worker_stop (GKDBusWorker *worker)
+{
+ g_source_destroy (worker->source);
+ g_source_unref (worker->source);
+ worker->source = 0;
+
+ g_object_unref (worker);
+}
+
+void
+_g_kdbus_worker_close (GKDBusWorker *worker,
+ GTask *task)
+{
+ worker->disconnected_callback (FALSE, NULL, worker->user_data);
+ g_task_return_boolean (task, TRUE);
+}
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Lukasz Skalski <l.skalski@samsung.com>
+ * Author: Michal Eljasiewicz <m.eljasiewic@samsung.com>
+ */
+
+#ifndef __G_KDBUS_H__
+#define __G_KDBUS_H__
+
+#if !defined (GIO_COMPILATION)
+#error "gkdbus.h is a private header file."
+#endif
+
+#include <gio/giotypes.h>
+#include "gdbusprivate.h"
+
+#define G_TYPE_KDBUS_WORKER (g_kdbus_worker_get_type ())
+#define G_KDBUS_WORKER(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \
+ G_TYPE_KDBUS_WORKER, GKDBusWorker))
+#define G_KDBUS_WORKER_CLASS(class) (G_TYPE_CHECK_CLASS_CAST ((class), \
+ G_TYPE_KDBUS_WORKER, GKDBusWorkerClass))
+#define G_IS_KDBUS_WORKER(inst) (G_TYPE_CHECK_INSTANCE_TYPE ((inst), \
+ G_TYPE_KDBUS_WORKER))
+#define G_IS_KDBUS_WORKER_CLASS(class) (G_TYPE_CHECK_CLASS_TYPE ((class), \
+ G_TYPE_KDBUS_WORKER))
+#define G_KDBUS_WORKER_GET_CLASS(inst) (G_TYPE_INSTANCE_GET_CLASS ((inst), \
+ G_TYPE_KDBUS_WORKER, GKDBusWorkerClass))
+typedef enum {
+ G_DBUS_CREDS_NONE = 0,
+ G_DBUS_CREDS_PID = (1<<0),
+ G_DBUS_CREDS_UID = (1<<1),
+ G_DBUS_CREDS_UNIQUE_NAME = (1<<2),
+ G_DBUS_CREDS_SEC_LABEL = (1<<3)
+} GDBusCredentialsFlags;
+
+typedef struct
+{
+ guint pid;
+ guint uid;
+ gchar *unique_name;
+ gchar *sec_label;
+} GDBusCredentials;
+
+typedef struct
+{
+ GDBusMessage *message;
+ uid_t sender_euid;
+ gid_t sender_egid;
+ gchar *sender_seclabel;
+ gchar *sender_names;
+} GKDBusMessage;
+
+typedef struct _GKDBusWorker GKDBusWorker;
+
+void _g_kdbus_worker_associate (GKDBusWorker *worker,
+ GDBusCapabilityFlags capabilities,
+ GDBusWorkerMessageReceivedCallback message_received_callback,
+ GDBusWorkerMessageAboutToBeSentCallback message_about_to_be_sent_callback,
+ GDBusWorkerDisconnectedCallback disconnected_callback,
+ gpointer user_data);
+
+GType g_kdbus_worker_get_type (void);
+
+GKDBusWorker * _g_kdbus_worker_new (const gchar *address,
+ GError **error);
+
+void _g_kdbus_worker_unfreeze (GKDBusWorker *worker);
+
+gboolean _g_kdbus_worker_send_message (GKDBusWorker *worker,
+ GDBusMessage *message,
+ gint timeout_msec,
+ GError **error);
+
+gboolean _g_kdbus_worker_send_message_sync (GKDBusWorker *worker,
+ GDBusMessage *message,
+ GDBusMessage **out_reply,
+ gint timeout_msec,
+ GCancellable *cancellable,
+ GError **error);
+
+void _g_kdbus_worker_stop (GKDBusWorker *worker);
+
+gboolean _g_kdbus_worker_flush_sync (GKDBusWorker *worker);
+
+void _g_kdbus_worker_close (GKDBusWorker *worker,
+ GTask *task);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean _g_kdbus_open (GKDBusWorker *worker,
+ const gchar *address,
+ GError **error);
+
+gboolean _g_kdbus_can_connect (GKDBusWorker *worker,
+ GError **error);
+
+gboolean _g_kdbus_close (GKDBusWorker *worker);
+
+gboolean _g_kdbus_is_closed (GKDBusWorker *worker);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+const gchar * _g_kdbus_Hello (GKDBusWorker *worker,
+ GError **error);
+
+gchar * _g_kdbus_GetBusId (GKDBusWorker *worker,
+ GError **error);
+
+GBusRequestNameReplyFlags _g_kdbus_RequestName (GKDBusWorker *worker,
+ const gchar *name,
+ GBusNameOwnerFlags flags,
+ GError **error);
+
+GBusReleaseNameReplyFlags _g_kdbus_ReleaseName (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+gchar ** _g_kdbus_GetListNames (GKDBusWorker *worker,
+ gboolean activatable,
+ GError **error);
+
+gchar ** _g_kdbus_GetListQueuedOwners (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+gboolean _g_kdbus_NameHasOwner (GKDBusWorker *connection,
+ const gchar *name,
+ GError **error);
+
+gchar * _g_kdbus_GetNameOwner (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+pid_t _g_kdbus_GetConnectionUnixProcessID (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+uid_t _g_kdbus_GetConnectionUnixUser (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+gchar * _g_kdbus_GetConnectionSecurityLabel (GKDBusWorker *worker,
+ const gchar *name,
+ GError **error);
+
+GBusStartServiceReplyFlags _g_kdbus_StartServiceByName (GKDBusWorker *worker,
+ const gchar *name,
+ guint32 flags,
+ GDBusMessage *message,
+ GError **error);
+
+gboolean _g_kdbus_AddMatch (GKDBusWorker *worker,
+ const gchar *match_rule,
+ GError **error);
+
+gboolean _g_kdbus_RemoveMatch (GKDBusWorker *worker,
+ const gchar *match_rule,
+ GError **error);
+
+GDBusCredentials * _g_kdbus_GetConnInfo (GKDBusWorker *worker,
+ const gchar *name,
+ guint flags,
+ GError **error);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+gboolean _g_kdbus_subscribe_name_acquired (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error);
+
+gboolean _g_kdbus_subscribe_name_lost (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error);
+
+gboolean _g_kdbus_subscribe_name_owner_changed (GKDBusWorker *worker,
+ const gchar *match_rule,
+ const gchar *name,
+ GError **error);
+
+/* ---------------------------------------------------------------------------------------------------- */
+
+G_END_DECLS
+
+#endif /* __G_KDBUS_H__ */
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Lukasz Skalski <l.skalski@samsung.com>
+ */
+
+#include "config.h"
+#include "gkdbus.h"
+#include "gkdbusfakedaemon.h"
+
+#include <gio/gio.h>
+#include <string.h>
+
+static gchar *introspect =
+ "<!DOCTYPE node PUBLIC \"-//freedesktop//DTD D-BUS Object Introspection 1.0//EN\" "
+ "\"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd\">\n"
+ "<node>\n"
+ " <interface name=\"org.freedesktop.DBus.Introspectable\">\n"
+ " <method name=\"Introspect\">\n"
+ " <arg name=\"data\" type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " </interface>\n"
+ " <interface name=\"org.freedesktop.DBus\">\n"
+ " <method name=\"AddMatch\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " </method>\n"
+ " <method name=\"RemoveMatch\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " </method>\n"
+ " <method name=\"GetConnectionCredentials\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"a{sv}\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"GetConnectionSELinuxSecurityContext\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"ay\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"GetConnectionUnixProcessID\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"GetConnectionUnixUser\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"GetId\">\n"
+ " <arg type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"GetNameOwner\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"Hello\">\n"
+ " <arg type=\"s\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"ListActivatableNames\">\n"
+ " <arg type=\"as\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"ListNames\">\n"
+ " <arg type=\"as\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"ListQueuedOwners\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"as\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"NameHasOwner\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"b\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"ReleaseName\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"ReloadConfig\">\n"
+ " </method>\n"
+ " <method name=\"RequestName\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"StartServiceByName\">\n"
+ " <arg type=\"s\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"in\"/>\n"
+ " <arg type=\"u\" direction=\"out\"/>\n"
+ " </method>\n"
+ " <method name=\"UpdateActivationEnvironment\">\n"
+ " <arg type=\"a{ss}\" direction=\"in\"/>\n"
+ " </method>\n"
+ " <signal name=\"NameAcquired\">\n"
+ " <arg type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"NameLost\">\n"
+ " <arg type=\"s\"/>\n"
+ " </signal>\n"
+ " <signal name=\"NameOwnerChanged\">\n"
+ " <arg type=\"s\"/>\n"
+ " <arg type=\"s\"/>\n"
+ " <arg type=\"s\"/>\n"
+ " </signal>\n"
+ " </interface>\n"
+ "</node>\n";
+
+static gboolean
+_mac_smack_use (void)
+{
+ static int cached_use = -1;
+
+ if (cached_use < 0)
+ cached_use = access("/sys/fs/smackfs/", F_OK) >= 0;
+
+ return cached_use;
+}
+
+/**
+ * _is_message_to_dbus_daemon()
+ */
+gboolean
+_is_message_to_dbus_daemon (GDBusMessage *message)
+{
+ return g_strcmp0 (g_dbus_message_get_destination (message), "org.freedesktop.DBus") == 0 &&
+ (g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus") == 0 ||
+ g_strcmp0 (g_dbus_message_get_interface (message), "org.freedesktop.DBus.Introspectable") == 0) &&
+ (g_strcmp0 (g_dbus_message_get_path (message), "/org/freedesktop/DBus") == 0 ||
+ g_strcmp0 (g_dbus_message_get_path (message), "/") == 0);
+}
+
+
+/**
+ * _dbus_daemon_synthetic_reply()
+ */
+GDBusMessage *
+_dbus_daemon_synthetic_reply (GKDBusWorker *worker,
+ GDBusMessage *message,
+ gboolean sync)
+{
+ GDBusMessage *reply;
+ GVariant *reply_body;
+ GVariant *body;
+ GError *local_error;
+ const gchar *member;
+
+ reply = NULL;
+ reply_body = NULL;
+ local_error = NULL;
+
+ member = g_dbus_message_get_member (message);
+ body = g_dbus_message_get_body (message);
+
+ /* show debug */
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " >>>> SENT D-Bus/kdbus message\n");
+ s = g_dbus_message_print (message, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
+
+ /*
+ * Introspect
+ */
+ if (!g_strcmp0 (member, "Introspect"))
+ {
+ reply_body = g_variant_new ("(s)", introspect);
+ }
+
+ /*
+ * AddMatch
+ */
+ else if (!g_strcmp0 (member, "AddMatch"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *rule;
+
+ g_variant_get (body, "(&s)", &rule);
+
+ _g_kdbus_AddMatch (worker, rule, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("()", NULL);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'AddMatch' has wrong args (expected s)");
+ }
+
+ /*
+ * RemoveMatch
+ */
+ else if (!g_strcmp0 (member, "RemoveMatch"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *rule;
+
+ g_variant_get (body, "(&s)", &rule);
+
+ _g_kdbus_RemoveMatch (worker, rule, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("()", NULL);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'RemoveMatch' has wrong args (expected s)");
+ }
+
+ /*
+ * GetConnectionCredentials
+ */
+ else if (!g_strcmp0 (member, "GetConnectionCredentials"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ GDBusCredentials *creds;
+ gchar *name;
+ guint flags;
+
+ creds = NULL;
+ flags = G_DBUS_CREDS_PID | G_DBUS_CREDS_UID | G_DBUS_CREDS_SEC_LABEL;
+
+ g_variant_get (body, "(&s)", &name);
+
+ creds = _g_kdbus_GetConnInfo (worker,
+ name,
+ flags,
+ &local_error);
+ if (local_error == NULL)
+ {
+ GVariantBuilder builder;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(a{sv})"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}"));
+
+ g_variant_builder_add (&builder, "{sv}", "UnixUserID", g_variant_new_uint32 (creds->uid));
+ g_variant_builder_add (&builder, "{sv}", "ProcessID", g_variant_new_uint32 (creds->pid));
+
+ if (creds->sec_label != NULL)
+ {
+ GVariantBuilder *label_builder;
+ gint counter;
+ gint label_size;
+
+ label_size = strlen (creds->sec_label);
+ label_builder = g_variant_builder_new (G_VARIANT_TYPE ("ay"));
+ for (counter = 0 ; counter < label_size + 1; counter++) /* label_size + 1 : include the \0 in the payload, for zero-copy reading. From dbus/bus/driver.c */
+ g_variant_builder_add (label_builder, "y", creds->sec_label[counter]);
+
+ g_variant_builder_add (&builder, "{sv}", "LinuxSecurityLabel", g_variant_new ("ay", label_builder));
+
+ g_variant_builder_unref (label_builder);
+ g_free (creds->sec_label);
+ }
+
+ g_variant_builder_close (&builder);
+ reply_body = g_variant_builder_end (&builder);
+ g_free (creds);
+ }
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetConnectionCredentials' has wrong args (expected s)");
+ }
+
+ /*
+ * GetConnectionSELinuxSecurityContext
+ */
+ else if (!g_strcmp0 (member, "GetConnectionSELinuxSecurityContext"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *name;
+ gchar *label;
+
+ g_variant_get (body, "(&s)", &name);
+
+ label = _g_kdbus_GetConnectionSecurityLabel (worker, name, &local_error);
+ if (label == NULL && local_error == NULL)
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED, "Operation not supported");
+ else if (local_error == NULL)
+ {
+ /* 'label' (KDBUS_ITEM_SECLABEL item) contains valid LSM security label... */
+ if (_mac_smack_use())
+ {
+ /* but if we are using SMACK - to keep compatibility with legacy dbus1 - return error */
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_SELINUX_SECURITY_CONTEXT_UNKNOWN,
+ "Could not determine security context for '%s'", name);
+ }
+ else
+ {
+ /* if it is not SMACK - let's assume that it's SELinux label */
+ GVariantBuilder builder;
+ gint counter;
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ay)"));
+ g_variant_builder_open (&builder, G_VARIANT_TYPE ("ay"));
+
+ for (counter = 0 ; counter < strlen (label) ; counter++)
+ g_variant_builder_add (&builder, "y", label[counter]);
+
+ g_variant_builder_close (&builder);
+ reply_body = g_variant_builder_end (&builder);
+ }
+ g_free (label);
+ }
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetConnectionSELinuxSecurityContext' has wrong args (expected s)");
+ }
+
+ /*
+ * GetConnectionUnixProcessID
+ */
+ else if (!g_strcmp0 (member, "GetConnectionUnixProcessID"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *name;
+ pid_t pid;
+
+ g_variant_get (body, "(&s)", &name);
+ pid = _g_kdbus_GetConnectionUnixProcessID (worker, name, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(u)", pid);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetConnectionUnixProcessID' has wrong args (expected s)");
+ }
+
+ /*
+ * GetConnectionUnixUser
+ */
+ else if (!g_strcmp0 (member, "GetConnectionUnixUser"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *name;
+ uid_t uid;
+
+ g_variant_get (body, "(&s)", &name);
+ uid = _g_kdbus_GetConnectionUnixUser (worker, name, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(u)", uid);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetConnectionUnixUser' has wrong args (expected s)");
+ }
+
+ /*
+ * GetId
+ */
+ else if (!g_strcmp0 (member, "GetId"))
+ {
+ if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ {
+ gchar *bus_id;
+
+ bus_id = _g_kdbus_GetBusId (worker, NULL);
+ reply_body = g_variant_new ("(s)", bus_id);
+
+ g_free (bus_id);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetId' has wrong args");
+ }
+
+ /*
+ * GetNameOwner
+ */
+ else if (!g_strcmp0 (member, "GetNameOwner"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar *unique_name;
+ gchar *name;
+
+ g_variant_get (body, "(&s)", &name);
+
+ unique_name = _g_kdbus_GetNameOwner (worker, name, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(s)", unique_name);
+ g_free (unique_name);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'GetNameOwner' has wrong args (expected s)");
+ }
+
+ /*
+ * Hello
+ */
+ else if (!g_strcmp0 (member, "Hello"))
+ {
+ if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ {
+ const gchar *unique_name;
+
+ unique_name = _g_kdbus_Hello (worker, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(s)", unique_name);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'Hello' has wrong args");
+ }
+
+ /*
+ * ListActivatableNames
+ */
+ else if (!g_strcmp0 (member, "ListActivatableNames"))
+ {
+ if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ {
+ gchar **strv;
+ gint cnt;
+
+ cnt = 0;
+
+ strv = _g_kdbus_GetListNames (worker, TRUE, &local_error);
+ if (local_error == NULL)
+ {
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+
+ while (strv[cnt])
+ g_variant_builder_add (builder, "s", strv[cnt++]);
+
+ reply_body = g_variant_new ("(as)", builder);
+
+ g_variant_builder_unref (builder);
+ }
+ g_strfreev (strv);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'ListActivatableNames' has wrong args");
+ }
+
+ /*
+ * ListNames
+ */
+ else if (!g_strcmp0 (member, "ListNames"))
+ {
+ if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ {
+ gchar **strv;
+ gint cnt;
+
+ cnt = 0;
+
+ strv = _g_kdbus_GetListNames (worker, FALSE, &local_error);
+ if (local_error == NULL)
+ {
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+
+ while (strv[cnt])
+ g_variant_builder_add (builder, "s", strv[cnt++]);
+
+ reply_body = g_variant_new ("(as)", builder);
+
+ g_variant_builder_unref (builder);
+ }
+ g_strfreev (strv);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'ListNames' has wrong args");
+ }
+
+ /*
+ * ListQueuedOwners
+ */
+ else if (!g_strcmp0 (member, "ListQueuedOwners"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gchar **strv;
+ gchar *name;
+ gint cnt;
+
+ cnt = 0;
+
+ g_variant_get (body, "(&s)", &name);
+ strv = _g_kdbus_GetListQueuedOwners (worker, name, &local_error);
+ if (local_error == NULL)
+ {
+ GVariantBuilder *builder;
+
+ builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
+
+ while (strv[cnt])
+ g_variant_builder_add (builder, "s", strv[cnt++]);
+
+ reply_body = g_variant_new ("(as)", builder);
+
+ g_variant_builder_unref (builder);
+ }
+ g_strfreev (strv);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'ListQueuedOwners' has wrong args (expected s)");
+ }
+
+ /*
+ * NameHasOwner
+ */
+ else if (!g_strcmp0 (member, "NameHasOwner"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ gboolean ret;
+ gchar *name;
+
+ g_variant_get (body, "(&s)", &name);
+
+ ret = _g_kdbus_NameHasOwner (worker, name, &local_error);
+ if (local_error == NULL)
+ {
+ if (ret)
+ reply_body = g_variant_new ("(b)", TRUE);
+ else
+ reply_body = g_variant_new ("(b)", FALSE);
+ }
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'NameHasOwner' has wrong args (expected s)");
+ }
+
+ /*
+ * ReleaseName
+ */
+ else if (!g_strcmp0 (member, "ReleaseName"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(s)")))
+ {
+ GBusReleaseNameReplyFlags status;
+ gchar *name;
+
+ g_variant_get (body, "(&s)", &name);
+
+ status = _g_kdbus_ReleaseName (worker, name, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(u)", status);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'ReleaseName' has wrong args (expected s)");
+ }
+
+ /*
+ * ReloadConfig
+ */
+ else if (!g_strcmp0 (member, "ReloadConfig"))
+ {
+ if ((body == NULL) || g_variant_is_of_type (body, G_VARIANT_TYPE ("()")))
+ reply_body = g_variant_new ("()", NULL);
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'ReloadConfig' has wrong args");
+ }
+
+ /*
+ * RequestName
+ */
+ else if (!g_strcmp0 (member, "RequestName"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(su)")))
+ {
+ GBusRequestNameReplyFlags status;
+ guint32 flags;
+ gchar *name;
+
+ g_variant_get (body, "(&su)", &name, &flags);
+
+ status = _g_kdbus_RequestName (worker, name, flags, &local_error);
+ if (local_error == NULL)
+ reply_body = g_variant_new ("(u)", status);
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'RequestName' has wrong args (expected su)");
+ }
+
+ /*
+ * StartServiceByName
+ */
+ else if (!g_strcmp0 (member, "StartServiceByName"))
+ {
+ if (body != NULL && g_variant_is_of_type (body, G_VARIANT_TYPE ("(su)")))
+ {
+ GBusStartServiceReplyFlags status;
+ gchar *name;
+ guint32 flags;
+
+ g_variant_get (body, "(&su)", &name, &flags);
+
+ if (sync)
+ status = _g_kdbus_StartServiceByName (worker, name, flags, NULL, &local_error);
+ else
+ status = _g_kdbus_StartServiceByName (worker, name, flags, message, &local_error);
+
+ if (local_error == NULL)
+ {
+ if (status == G_BUS_START_SERVICE_REPLY_ALREADY_RUNNING || sync)
+ reply_body = g_variant_new ("(u)", status);
+ else
+ return NULL;
+ }
+ }
+ else
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "Call to 'StartServiceByName' has wrong args (expected su)");
+ }
+
+ /*
+ * UpdateActivationEnvironment
+ */
+ else if (!g_strcmp0 (member, "UpdateActivationEnvironment"))
+ {
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_NOT_SUPPORTED,
+ "'%s' method not supported", member);
+ }
+
+ /*
+ * Method not supported
+ */
+ else
+ {
+ g_set_error (&local_error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD,
+ "org.freedesktop.DBus does not understand message %s", member);
+ }
+
+ if (reply_body == NULL && local_error)
+ {
+ gchar *dbus_error_name;
+
+ dbus_error_name = g_dbus_error_encode_gerror (local_error);
+ reply = g_dbus_message_new_method_error (message, dbus_error_name, "%s", local_error->message);
+ g_free (dbus_error_name);
+ }
+ else
+ {
+ reply = g_dbus_message_new_method_reply (message);
+ g_dbus_message_set_body (reply, reply_body);
+ }
+
+ g_dbus_message_set_serial (reply, -1);
+
+ if (local_error)
+ g_error_free (local_error);
+
+ if (G_UNLIKELY (_g_dbus_debug_message ()))
+ {
+ gchar *s;
+ _g_dbus_debug_print_lock ();
+ g_print ("========================================================================\n"
+ "GDBus-debug:Message:\n"
+ " <<<< RECEIVED synthetic D-Bus message\n");
+ s = g_dbus_message_print (reply, 2);
+ g_print ("%s", s);
+ g_free (s);
+ _g_dbus_debug_print_unlock ();
+ }
+
+ return reply;
+}
--- /dev/null
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2015 Samsung Electronics
+ *
+ * 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 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, write to the
+ * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ *
+ * Author: Lukasz Skalski <l.skalski@samsung.com>
+ */
+
+#ifndef __G_KDBUSFAKEDAEMON_H__
+#define __G_KDBUSFAKEDAEMON_H__
+
+#if !defined (GIO_COMPILATION)
+#error "gkdbusfakedaemon.h is a private header file."
+#endif
+
+#include <gio/giotypes.h>
+
+gboolean _is_message_to_dbus_daemon (GDBusMessage *message);
+
+GDBusMessage * _dbus_daemon_synthetic_reply (GKDBusWorker *worker,
+ GDBusMessage *message,
+ gboolean sync);
+G_END_DECLS
+
+#endif /* __G_KDBUSFAKEDAEMON_H__ */
GUnixFDList * g_unix_fd_list_new_from_array (const gint *fds,
gint n_fds);
+GLIB_AVAILABLE_IN_2_44
+void g_unix_fd_list_lock (GUnixFDList *list);
+
GLIB_AVAILABLE_IN_ALL
gint g_unix_fd_list_append (GUnixFDList *list,
gint fd,
$(AM_V_at) chmod a+x $(DESTDIR)$(installed_testdir)/x-content/win32-software/autorun.exe
endif
endif
+
+gdbus_addresses_LDFLAGS = -pie
+gdbus_auth_LDFLAGS = -pie
+gdbus_bz627724_LDFLAGS = -pie
+gdbus_close_pending_LDFLAGS = -pie
+gdbus_connection_LDFLAGS = -pie
+gdbus_connection_flush_LDFLAGS = -pie
+gdbus_connection_flush_helper_LDFLAGS = -pie
+gdbus_connection_loss_LDFLAGS = -pie
+gdbus_connection_slow_LDFLAGS = -pie
+gdbus_error_LDFLAGS = -pie
+gdbus_exit_on_close_LDFLAGS = -pie
+gdbus_export_LDFLAGS = -pie
+gdbus_introspection_LDFLAGS = -pie
+gdbus_message_LDFLAGS = -pie
+gdbus_names_LDFLAGS = -pie
+gdbus_non_socket_LDFLAGS = -pie
+gdbus_overflow_LDFLAGS = -pie
+gdbus_peer_LDFLAGS = -pie
+gdbus_peer_object_manager_LDFLAGS = -pie
+gdbus_proxy_LDFLAGS = -pie
+gdbus_proxy_threads_LDFLAGS = -pie
+gdbus_proxy_well_known_name_LDFLAGS = -pie
+gdbus_test_codegen_LDFLAGS = -pie
+gdbus_test_codegen_old_LDFLAGS = -pie
+gdbus_threading_LDFLAGS = -pie
+gdbus_unix_addresses_LDFLAGS = -pie
--- /dev/null
+/*
+ * Copyright (c) 2011 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * 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 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 __TIZEN_HEADER_GLIB_H__
+#define __TIZEN_HEADER_GLIB_H__
+
+#ifndef TIZEN_PUBLIC_DEPRECATED_API
+ #ifdef TIZEN_DEPRECATION
+ #define TIZEN_PUBLIC_DEPRECATED_API __attribute__((__visibility__("default"), deprecated))
+ #else
+ #define TIZEN_PUBLIC_DEPRECATED_API
+ #endif
+#endif
+
+#endif // __TIZEN_HEADER_GLIB_H__
else
PRINTF_SUBDIR = gnulib
printf_la = gnulib/libgnulib.la
-endif
+endif
if USE_SYSTEM_PCRE
else
-MAYBE_PCRE = pcre
+MAYBE_PCRE = pcre
endif
SUBDIRS = libcharset $(PRINTF_SUBDIR) $(MAYBE_PCRE) update-pcre . tests
glib_trace.h \
glib-init.h \
glib-init.c \
+ glib-linux.h \
glib-private.h \
glib-private.c \
glist.c \
gvariant-parser.c \
gvariant-serialiser.h \
gvariant-serialiser.c \
+ gvariant-vectors.h \
+ gvariant-vectors.c \
gvarianttypeinfo.h \
gvarianttypeinfo.c \
gvarianttype.c \
if OS_WIN32_X64
INSTALL_PROGS += gspawn-win64-helper gspawn-win64-helper-console
gspawn_win64_helper_LDADD = libglib-2.0.la
-gspawn_win64_helper_LDFLAGS = -mwindows
+gspawn_win64_helper_LDFLAGS = -pie -mwindows
gspawn_win64_helper_console_LDADD = libglib-2.0.la
else
INSTALL_PROGS += gspawn-win32-helper gspawn-win32-helper-console
gspawn_win32_helper_LDADD = libglib-2.0.la
-gspawn_win32_helper_LDFLAGS = -mwindows
+gspawn_win32_helper_LDFLAGS = -pie -mwindows
gspawn_win32_helper_console_LDADD = libglib-2.0.la
endif
endif
INSTALL_PROGS += gtester
gtester_SOURCES = gtester.c
-gtester_LDADD = libglib-2.0.la
+gtester_LDADD = libglib-2.0.la
+gtester_LDFLAGS = -pie
auto_config_binscripts = gtester-report
bin_SCRIPTS = ${auto_config_binscripts}
#include <glib/gmessages.h>
#include <string.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#ifdef G_OS_UNIX
+#include "glib-unix.h"
+#include <sys/mman.h>
+#endif
/**
* GBytes:
struct _GBytes
{
- gconstpointer data; /* may be NULL iff (size == 0) */
- gsize size; /* may be 0 */
- gint ref_count;
- GDestroyNotify free_func;
- gpointer user_data;
+ gsize size;
+ gint ref_count;
+ gint type_or_fd;
};
+typedef struct
+{
+ GBytes bytes;
+#if GLIB_SIZEOF_SIZE_T == 4
+ guint pad;
+#endif
+
+ guchar data[1];
+} GBytesInline;
+
+/* important: the ->data field of GBytesInline should always be 'nicely
+ * aligned'.
+ */
+G_STATIC_ASSERT (G_STRUCT_OFFSET (GBytesInline, data) % (2 * sizeof (gpointer)) == 0);
+G_STATIC_ASSERT (G_STRUCT_OFFSET (GBytesInline, data) % 8 == 0);
+
+
+typedef struct
+{
+ GBytes bytes;
+
+ gpointer data;
+} GBytesData;
+
+typedef struct
+{
+ GBytesData data_bytes;
+
+ GDestroyNotify notify;
+ gpointer user_data;
+} GBytesNotify;
+
+#define G_BYTES_TYPE_INLINE (-1)
+#define G_BYTES_TYPE_STATIC (-2)
+#define G_BYTES_TYPE_FREE (-3)
+#define G_BYTES_TYPE_NOTIFY (-4)
+
+/* All bytes are either inline or subtypes of GBytesData */
+#define G_BYTES_IS_INLINE(bytes) ((bytes)->type_or_fd == G_BYTES_TYPE_INLINE)
+#define G_BYTES_IS_DATA(bytes) (!G_BYTES_IS_INLINE(bytes))
+
+/* More specific subtypes of GBytesData */
+#define G_BYTES_IS_STATIC(bytes) ((bytes)->type_or_fd == G_BYTES_TYPE_STATIC)
+#define G_BYTES_IS_FREE(bytes) ((bytes)->type_or_fd == G_BYTES_TYPE_FREE)
+#define G_BYTES_IS_NOTIFY(bytes) ((bytes)->type_or_fd == G_BYTES_TYPE_NOTIFY)
+
+/* we have a memfd if type_or_fd >= 0 */
+#define G_BYTES_IS_MEMFD(bytes) ((bytes)->type_or_fd >= 0)
+
+static gpointer
+g_bytes_allocate (guint struct_size,
+ guint type_or_fd,
+ gsize data_size)
+{
+ GBytes *bytes;
+
+ bytes = g_slice_alloc (struct_size);
+ bytes->size = data_size;
+ bytes->ref_count = 1;
+ bytes->type_or_fd = type_or_fd;
+
+ return bytes;
+}
+
/**
* g_bytes_new:
* @data: (transfer none) (array length=size) (element-type guint8) (nullable):
g_bytes_new (gconstpointer data,
gsize size)
{
+ GBytesInline *bytes;
+
g_return_val_if_fail (data != NULL || size == 0, NULL);
- return g_bytes_new_take (g_memdup (data, size), size);
+ bytes = g_bytes_allocate (G_STRUCT_OFFSET (GBytesInline, data[size]), G_BYTES_TYPE_INLINE, size);
+ memcpy (bytes->data, data, size);
+
+ return (GBytes *) bytes;
+}
+
+/**
+ * g_bytes_new_take_zero_copy_fd:
+ * @fd: a file descriptor capable of being zero-copy-safe
+ *
+ * Creates a new #GBytes from @fd.
+ *
+ * @fd must be capable of being made zero-copy-safe. In concrete terms,
+ * this means that a call to g_unix_fd_ensure_zero_copy_safe() on @fd
+ * will succeed. This call will be made before returning.
+ *
+ * This call consumes @fd, transferring ownership to the returned
+ * #GBytes.
+ *
+ * Returns: (transfer full): a new #GBytes
+ *
+ */
+#ifdef G_OS_UNIX
+GBytes *
+g_bytes_new_take_zero_copy_fd (gint fd)
+{
+ GBytes *bytes;
+ struct stat buf;
+
+ /* We already checked this is a memfd... */
+ g_assert_se (fstat (fd, &buf) == 0);
+
+ bytes = g_bytes_new_take_zero_copy_fd_size(fd, buf.st_size);
+
+ if (buf.st_size == 0)
+ {
+ g_assert_se (close (fd) == 0);
+ }
+
+ return bytes;
+}
+
+GBytes *
+g_bytes_new_take_zero_copy_fd_size (gint fd, gsize size)
+{
+ GBytesData *bytes;
+
+ g_return_val_if_fail_se (g_unix_fd_ensure_zero_copy_safe (fd), NULL);
+
+ /* We already checked this is a memfd... */
+ if (size == 0)
+ {
+ return g_bytes_new (NULL, 0);
+ }
+
+ bytes = g_bytes_allocate (sizeof (GBytesData), fd, size);
+ bytes->data = mmap (NULL, size, PROT_READ, MAP_PRIVATE, fd, 0);
+ if (bytes->data == MAP_FAILED)
+ /* this is similar to malloc() failing, so do the same... */
+ g_error ("mmap() on memfd failed: %s\n", g_strerror (errno));
+
+ return (GBytes *) bytes;
}
+#endif /* G_OS_UNIX */
/**
* g_bytes_new_take:
g_bytes_new_take (gpointer data,
gsize size)
{
- return g_bytes_new_with_free_func (data, size, g_free, data);
-}
+ GBytesData *bytes;
+
+ bytes = g_bytes_allocate (sizeof (GBytesData), G_BYTES_TYPE_FREE, size);
+ bytes->data = data;
+ return (GBytes *) bytes;
+}
/**
* g_bytes_new_static: (skip)
g_bytes_new_static (gconstpointer data,
gsize size)
{
- return g_bytes_new_with_free_func (data, size, NULL, NULL);
+ GBytesData *bytes;
+
+ g_return_val_if_fail (data != NULL || size == 0, NULL);
+
+ bytes = g_bytes_allocate (sizeof (GBytesData), G_BYTES_TYPE_STATIC, size);
+ bytes->data = (gpointer) data;
+
+ return (GBytes *) bytes;
}
/**
GDestroyNotify free_func,
gpointer user_data)
{
- GBytes *bytes;
+ GBytesNotify *bytes;
- g_return_val_if_fail (data != NULL || size == 0, NULL);
+ if (!free_func)
+ return g_bytes_new_static (data, size);
- bytes = g_slice_new (GBytes);
- bytes->data = data;
- bytes->size = size;
- bytes->free_func = free_func;
+ bytes = g_bytes_allocate (sizeof (GBytesNotify), G_BYTES_TYPE_NOTIFY, size);
+ bytes->data_bytes.data = (gpointer) data;
+ bytes->notify = free_func;
bytes->user_data = user_data;
- bytes->ref_count = 1;
- return (GBytes *)bytes;
+ return (GBytes *) bytes;
}
/**
g_return_val_if_fail (offset <= bytes->size, NULL);
g_return_val_if_fail (offset + length <= bytes->size, NULL);
- return g_bytes_new_with_free_func ((gchar *)bytes->data + offset, length,
+ return g_bytes_new_with_free_func ((gchar *) g_bytes_get_data (bytes, NULL) + offset, length,
(GDestroyNotify)g_bytes_unref, g_bytes_ref (bytes));
}
*/
gconstpointer
g_bytes_get_data (GBytes *bytes,
- gsize *size)
+ gsize *size)
{
g_return_val_if_fail (bytes != NULL, NULL);
+
if (size)
*size = bytes->size;
- return bytes->data;
+
+ if (G_BYTES_IS_DATA (bytes))
+ {
+ GBytesData *data_bytes = (GBytesData *) bytes;
+
+ return data_bytes->data;
+ }
+ else if (G_BYTES_IS_INLINE (bytes))
+ {
+ GBytesInline *inline_bytes = (GBytesInline *) bytes;
+
+ return inline_bytes->data;
+ }
+ else
+ g_assert_not_reached ();
}
/**
return bytes->size;
}
+/**
+ * g_bytes_get_zero_copy_fd:
+ * @bytes: a #GBytes
+ *
+ * Gets the zero-copy fd from a #GBytes, if it has one.
+ *
+ * Returns -1 if @bytes was not created from a zero-copy fd.
+ *
+ * A #GBytes created with a zero-copy fd may have been internally
+ * converted into another type of #GBytes for any reason at all. This
+ * function may therefore return -1 at any time, even for a #GBytes that
+ * was created with g_bytes_new_take_zero_copy_fd().
+ *
+ * The returned file descriptor belongs to @bytes. Do not close it.
+ *
+ * Returns: a file descriptor, or -1
+ *
+ * Since: 2.44
+ */
+gint
+g_bytes_get_zero_copy_fd (GBytes *bytes)
+{
+ g_return_val_if_fail (bytes != NULL, -1);
+
+ if (G_BYTES_IS_MEMFD (bytes))
+ return bytes->type_or_fd;
+ else
+ return -1;
+}
/**
* g_bytes_ref:
if (g_atomic_int_dec_and_test (&bytes->ref_count))
{
- if (bytes->free_func != NULL)
- bytes->free_func (bytes->user_data);
- g_slice_free (GBytes, bytes);
+ switch (bytes->type_or_fd)
+ {
+ case G_BYTES_TYPE_STATIC:
+ /* data does not need to be freed */
+ g_slice_free (GBytesData, (GBytesData *) bytes);
+ break;
+
+ case G_BYTES_TYPE_INLINE:
+ /* data will be freed along with struct */
+ g_slice_free1 (G_STRUCT_OFFSET (GBytesInline, data[bytes->size]), bytes);
+ break;
+
+ case G_BYTES_TYPE_FREE:
+ {
+ GBytesData *data_bytes = (GBytesData *) bytes;
+
+ g_free (data_bytes->data);
+
+ g_slice_free (GBytesData, data_bytes);
+ break;
+ }
+
+ case G_BYTES_TYPE_NOTIFY:
+ {
+ GBytesNotify *notify_bytes = (GBytesNotify *) bytes;
+
+ /* We don't create GBytesNotify if callback was NULL */
+ (* notify_bytes->notify) (notify_bytes->user_data);
+
+ g_slice_free (GBytesNotify, notify_bytes);
+ break;
+ }
+
+ default:
+ {
+ GBytesData *data_bytes = (GBytesData *) bytes;
+
+ g_assert (bytes->type_or_fd >= 0);
+
+ g_assert_se (munmap (data_bytes->data, bytes->size) == 0);
+ g_assert_se (close (bytes->type_or_fd) == 0);
+
+ g_slice_free (GBytesData, data_bytes);
+ break;
+ }
+ }
}
}
g_bytes_equal (gconstpointer bytes1,
gconstpointer bytes2)
{
- const GBytes *b1 = bytes1;
- const GBytes *b2 = bytes2;
+ gconstpointer d1, d2;
+ gsize s1, s2;
g_return_val_if_fail (bytes1 != NULL, FALSE);
g_return_val_if_fail (bytes2 != NULL, FALSE);
- return b1->size == b2->size &&
- memcmp (b1->data, b2->data, b1->size) == 0;
+ d1 = g_bytes_get_data ((GBytes *) bytes1, &s1);
+ d2 = g_bytes_get_data ((GBytes *) bytes2, &s2);
+
+ if (s1 != s2)
+ return FALSE;
+
+ if (d1 == d2)
+ return TRUE;
+
+ return memcmp (d1, d2, s1) == 0;
}
/**
guint
g_bytes_hash (gconstpointer bytes)
{
- const GBytes *a = bytes;
- const signed char *p, *e;
+ const guchar *data;
+ const guchar *end;
+ gsize size;
guint32 h = 5381;
g_return_val_if_fail (bytes != NULL, 0);
- for (p = (signed char *)a->data, e = (signed char *)a->data + a->size; p != e; p++)
- h = (h << 5) + h + *p;
+ data = g_bytes_get_data ((GBytes *) bytes, &size);
+ end = data + size;
+
+ while (data != end)
+ h = (h << 5) + h + *(data++);
return h;
}
g_bytes_compare (gconstpointer bytes1,
gconstpointer bytes2)
{
- const GBytes *b1 = bytes1;
- const GBytes *b2 = bytes2;
+ gconstpointer d1, d2;
+ gsize s1, s2;
gint ret;
g_return_val_if_fail (bytes1 != NULL, 0);
g_return_val_if_fail (bytes2 != NULL, 0);
- ret = memcmp (b1->data, b2->data, MIN (b1->size, b2->size));
- if (ret == 0 && b1->size != b2->size)
- ret = b1->size < b2->size ? -1 : 1;
- return ret;
-}
-
-static gpointer
-try_steal_and_unref (GBytes *bytes,
- GDestroyNotify free_func,
- gsize *size)
-{
- gpointer result;
-
- if (bytes->free_func != free_func || bytes->data == NULL)
- return NULL;
+ d1 = g_bytes_get_data ((GBytes *) bytes1, &s1);
+ d2 = g_bytes_get_data ((GBytes *) bytes2, &s2);
- /* Are we the only reference? */
- if (g_atomic_int_get (&bytes->ref_count) == 1)
- {
- *size = bytes->size;
- result = (gpointer)bytes->data;
- g_slice_free (GBytes, bytes);
- return result;
- }
+ ret = memcmp (d1, d2, MIN (s1, s2));
+ if (ret == 0 && s1 != s2)
+ ret = s1 < s2 ? -1 : 1;
- return NULL;
+ return ret;
}
-
/**
* g_bytes_unref_to_data:
* @bytes: (transfer full): a #GBytes
g_return_val_if_fail (bytes != NULL, NULL);
g_return_val_if_fail (size != NULL, NULL);
+
/*
* Optimal path: if this is was the last reference, then we can return
* the data from this GBytes without copying.
*/
-
- result = try_steal_and_unref (bytes, g_free, size);
- if (result == NULL)
+ if (G_BYTES_IS_FREE(bytes) && g_atomic_int_get (&bytes->ref_count) == 1)
{
- /*
- * Copy: Non g_malloc (or compatible) allocator, or static memory,
- * so we have to copy, and then unref.
- */
- result = g_memdup (bytes->data, bytes->size);
+ GBytesData *data_bytes = (GBytesData *) bytes;
+
+ result = data_bytes->data;
*size = bytes->size;
+
+ g_slice_free (GBytesData, data_bytes);
+ }
+ else
+ {
+ gconstpointer data;
+
+ data = g_bytes_get_data (bytes, size);
+ result = g_memdup (data, *size);
g_bytes_unref (bytes);
}
GBytes * g_bytes_new_take (gpointer data,
gsize size);
+#ifdef G_OS_UNIX
+GLIB_AVAILABLE_IN_2_44
+GBytes * g_bytes_new_take_zero_copy_fd (gint fd);
+
+GLIB_AVAILABLE_IN_2_44
+GBytes * g_bytes_new_take_zero_copy_fd_size (gint fd,
+ gsize size);
+#endif
+
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_new_static (gconstpointer data,
gsize size);
GLIB_AVAILABLE_IN_ALL
gsize g_bytes_get_size (GBytes *bytes);
+GLIB_AVAILABLE_IN_2_44
+gint g_bytes_get_zero_copy_fd (GBytes *bytes);
+
GLIB_AVAILABLE_IN_ALL
GBytes * g_bytes_ref (GBytes *bytes);
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
static const int NLETTERS = sizeof (letters) - 1;
glong value;
- GTimeVal tv;
+ gint64 now_us;
static int counter = 0;
g_return_val_if_fail (tmpl != NULL, -1);
}
/* Get some more or less random data. */
- g_get_current_time (&tv);
- value = (tv.tv_usec ^ tv.tv_sec) + counter++;
+ now_us = g_get_real_time ();
+ value = ((now_us % G_USEC_PER_SEC) ^ (now_us / G_USEC_PER_SEC)) + counter++;
for (count = 0; count < 100; value += 7777, ++count)
{
}
static inline void
-g_autoptr_cleanup_gstring_free (GString *string)
+g_autoptr_cleanup_gstring_free (GString *__string__)
{
- if (string)
- g_string_free (string, TRUE);
+ if (__string__)
+ g_string_free (__string__, TRUE);
}
/* If adding a cleanup here, please also add a test case to
--- /dev/null
+/*
+ * Copyright © 2014 Canonical Limited
+ *
+ * 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 of the licence, 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/>.
+ *
+ * Author: Ryan Lortie <desrt@desrt.ca>
+ */
+
+#ifndef __GLIB_LINUX_H__
+#define __GLIB_LINUX_H__
+
+#include <errno.h>
+
+/* If we know that we are on Linux, add some features, even if they are
+ * not (yet) advertised in the glibc or kernel headers.
+ *
+ * This allows us to use functionality regardless of if it was available
+ * when GLib was compiled or not.
+ *
+ * We take care not to define these things on non-Linux systems where
+ * certain numeric values could mean something different.
+ *
+ * This file is populated on an as-needed basis.
+ *
+ * As things in this file filter into glibc and the distributions we can
+ * remove them from this file and add unconditional dependencies. Never
+ * add a configure.ac check in order to remove something from this file.
+ *
+ * import: include this header LAST
+ */
+
+#ifdef __linux__
+
+#define GLIB_LINUX
+
+#include <sys/syscall.h>
+
+static inline int
+glib_linux_enosys (void)
+{
+ errno = ENOSYS;
+ return -1;
+}
+
+/* futex */
+#include <linux/futex.h>
+
+static inline int
+glib_linux_futex (int *uaddr,
+ int op,
+ int val,
+ const struct timespec *timeout,
+ int *uaddr2,
+ int val3)
+{
+ return syscall (__NR_futex, uaddr, op, val, timeout, uaddr2, val3);
+}
+
+/* memfd */
+#ifndef MFD_CLOEXEC
+#define MFD_CLOEXEC 0x0001U
+#endif
+
+#ifndef MFD_ALLOW_SEALING
+#define MFD_ALLOW_SEALING 0x0002U
+#endif
+
+#ifndef __NR_memfd_create
+# if defined __x86_64__
+# define __NR_memfd_create 319
+# elif defined i386
+# define __NR_memfd_create 356
+# elif defined __arm__
+ /* arm and arm64 have the same value */
+# define __NR_memfd_create 385
+# elif defined _MIPS_SIM
+# if _MIPS_SIM == _MIPS_SIM_ABI32
+# define __NR_memfd_create 4354
+# endif
+# if _MIPS_SIM == _MIPS_SIM_NABI32
+# define __NR_memfd_create 6318
+# endif
+# if _MIPS_SIM == _MIPS_SIM_ABI64
+# define __NR_memfd_create 5314
+# endif
+# endif
+#endif
+
+static inline int
+glib_linux_memfd_create (const char *name,
+ unsigned int flags)
+{
+#ifdef __NR_memfd_create
+ return syscall (__NR_memfd_create, name, flags);
+#else
+ return glib_linux_enosys ();
+#endif
+}
+
+/* Linux-specific fcntl() operations */
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+
+#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+#define F_SEAL_GROW 0x0004 /* prevent file from growing */
+#define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+#endif /* __linux __ */
+
+#endif /* __GLIB_LINUX_H__ */
g_dir_open_with_errno,
g_dir_new_from_dirp,
- glib_init,
+ g_variant_to_vectors,
+ g_variant_from_vectors,
+ g_variant_vectors_deinit,
+
+ glib_init
};
return &table;
#include <glib.h>
#include "gwakeup.h"
+#include "gvariant-vectors.h"
#if defined(__GNUC__)
# define _g_alignof(type) (__alignof__ (type))
GMainContext * g_get_worker_context (void);
gboolean g_check_setuid (void);
GMainContext * g_main_context_new_with_next_id (guint next_id);
+void g_variant_to_vectors (GVariant *value,
+ GVariantVectors *vectors);
+GVariant * g_variant_from_vectors (const GVariantType *type,
+ GVariantVector *vectors,
+ gsize n_vectors,
+ gsize size,
+ gboolean trusted);
#ifdef G_OS_WIN32
gchar *_glib_get_dll_directory (void);
guint flags);
GDir * (* g_dir_new_from_dirp) (gpointer dirp);
+ void (* g_variant_to_vectors) (GVariant *value,
+ GVariantVectors *vectors);
+ GVariant * (* g_variant_from_vectors) (const GVariantType *type,
+ GVariantVector *vectors,
+ gsize n_vectors,
+ gsize size,
+ gboolean trusted);
+ void (* g_variant_vectors_deinit) (GVariantVectors *vectors);
+
/* See glib-init.c */
void (* glib_init) (void);
#include <string.h>
+#include <fcntl.h>
+#include <sys/syscall.h>
+#include <unistd.h>
+
+#ifdef __linux__
+
+/* We want to support these features of Linux even when building GLib
+ * against older versions of system headers. This will allow us to
+ * 'automatically' start supporting a particular feature when GLib is
+ * used with a newer kernel, without recompile.
+ *
+ * This means that we're not changing functionality of GLib simply based
+ * on the set of headers we happen to compile against...
+ */
+
+#ifndef F_LINUX_SPECIFIC_BASE
+#define F_LINUX_SPECIFIC_BASE 1024
+#endif
+
+#ifndef F_ADD_SEALS
+#define F_ADD_SEALS (F_LINUX_SPECIFIC_BASE + 9)
+#define F_GET_SEALS (F_LINUX_SPECIFIC_BASE + 10)
+
+#define F_SEAL_SEAL 0x0001 /* prevent further seals from being set */
+#define F_SEAL_SHRINK 0x0002 /* prevent file from shrinking */
+#define F_SEAL_GROW 0x0004 /* prevent file from growing */
+#define F_SEAL_WRITE 0x0008 /* prevent writes */
+#endif
+
+#endif
+
/**
* SECTION:gunix
* @title: UNIX-specific utilities and integration
{
return g_unix_fd_add_full (G_PRIORITY_DEFAULT, fd, condition, function, user_data, NULL);
}
+
+/**
+ * g_unix_fd_ensure_zero_copy_safe:
+ * @fd: a file descriptor
+ *
+ * Checks whether @fd can be use in zero-copy mode. On Linux, this checks that
+ * the descriptor is a memfd, created with memfd_create(), and tries to apply
+ * seals to it so that it can be safely consumed by another process. On other
+ * Unix systems, this function will fail.
+ *
+ * Returns: whether the fd is safe to use in zero-copy mode. Sealing of memfds
+ * is required for the @fd to be considered safe. If sealing fails, or
+ * memfds are not available, or the @fd is not a memfd, returns %FALSE
+ *
+ * Since: 2.44
+ **/
+gboolean
+g_unix_fd_ensure_zero_copy_safe (gint fd)
+{
+#ifdef F_GET_SEALS
+ gint seals;
+ const gint IMMUTABLE_SEALS = F_SEAL_WRITE |
+ F_SEAL_SHRINK |
+ F_SEAL_GROW |
+ F_SEAL_SEAL;
+
+ g_return_val_if_fail (fd >= 0, FALSE);
+
+ /* Seal the fd if possible (only on Linux 3.17+, and if the fd was created
+ * with memfd_create()). */
+ seals = fcntl (fd, F_GET_SEALS);
+ if (seals == -1)
+ {
+ g_debug ("Retrieving fd seals failed: %s", g_strerror (errno));
+ return FALSE;
+ }
+
+ /* Seal the fd, if it is not already. */
+ if ((seals & (IMMUTABLE_SEALS)) >= IMMUTABLE_SEALS)
+ {
+ g_debug ("%s", "fd already sealed");
+ }
+ else
+ {
+ gint error;
+
+ error = fcntl (fd, F_ADD_SEALS, IMMUTABLE_SEALS);
+ if (error == -1)
+ {
+ g_debug ("fd sealing failed: %s", g_strerror (errno));
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+#else
+ return FALSE;
+#endif
+}
GUnixFDSourceFunc function,
gpointer user_data);
+GLIB_AVAILABLE_IN_2_44
+gboolean g_unix_fd_ensure_zero_copy_safe (gint fd);
+
G_END_DECLS
#endif /* __G_UNIX_H__ */
return buf;
}
+/* Format the next UTF-8 character as a gchar* for printing in error output
+ * when we encounter a syntax error. This correctly handles invalid UTF-8,
+ * emitting it as hex escapes. */
static gchar*
utf8_str (const gchar *utf8,
gchar *buf)
{
- char_str (g_utf8_get_char (utf8), buf);
+ gunichar c = g_utf8_get_char_validated (utf8, -1);
+ if (c == (gunichar) -1 || c == (gunichar) -2)
+ {
+ gchar *temp = g_strdup_printf ("\\x%02x", (guint)(guchar)*utf8);
+ memset (buf, 0, 8);
+ memcpy (buf, temp, strlen (temp));
+ g_free (temp);
+ }
+ else
+ char_str (c, buf);
return buf;
}
case STATE_AFTER_CLOSE_TAG_SLASH:
case STATE_INSIDE_CLOSE_TAG_NAME:
case STATE_AFTER_CLOSE_TAG_NAME:
- set_error (context, error, G_MARKUP_ERROR_PARSE,
- _("Document ended unexpectedly inside the close tag for "
- "element '%s'"), current_element (context));
+ if (context->tag_stack != NULL)
+ set_error (context, error, G_MARKUP_ERROR_PARSE,
+ _("Document ended unexpectedly inside the close tag for "
+ "element “%s”"), current_element (context));
+ else
+ set_error (context, error, G_MARKUP_ERROR_PARSE,
+ _("Document ended unexpectedly inside the close tag for an "
+ "unopened element"));
break;
case STATE_INSIDE_PASSTHROUGH:
static gsize initialized;
static gboolean fd_is_journal = FALSE;
- g_return_val_if_fail (output_fd >= 0, FALSE);
+ if (output_fd < 0)
+ return FALSE;
if (g_once_init_enter (&initialized))
{
* returned from the current function.
*
* If G_DISABLE_CHECKS is defined then the check is not performed. You
- * should therefore not depend on any side effects of @expr.
+ * should therefore not depend on any side effects of @expr. See
+ * g_return_if_fail_se() for a version that guarantees side effects.
*/
#define g_return_val_if_fail(expr,val) G_STMT_START{ (void)0; }G_STMT_END
/**
+ * g_return_if_fail_se:
+ * @expr: the expression to check
+ *
+ * Verifies that the expression @expr, usually representing a
+ * precondition, evaluates to %TRUE.
+ *
+ * This is the same as g_return_if_fail() except that @expr is
+ * guaranteed to be evaluated, so it may contain side effects.
+ *
+ * Note: it is still undefined if this function will actually return or
+ * not, or if any side effects of @val will be evaluated. There is only
+ * a guarantee with respect to side effects of @expr.
+ *
+ * Since: 2.44
+ */
+#define g_return_if_fail_se(expr) ((void) (expr))
+
+/**
+ * g_return_val_if_fail_se:
+ * @expr: the expression to check
+ * @val: the value to return from the current function
+ * if the expression is not true
+ *
+ * Verifies that the expression @expr, usually representing a
+ * precondition, evaluates to %TRUE.
+ *
+ * This is the same as g_return_val_if_fail() except that @expr is
+ * guaranteed to be evaluated, so it may contain side effects.
+ *
+ * Note: it is still undefined if this function will actually return or
+ * not, or if any side effects of @val will be evaluated. There is only
+ * a guarantee with respect to side effects of @expr.
+ *
+ * Since: 2.44
+ */
+#define g_return_val_if_fail_se(expr,val) ((void) (expr))
+
+/**
* g_return_if_reached:
*
* Logs a critical message and returns from the current function.
return (val); \
}; }G_STMT_END
+#define g_return_if_fail_se(expr) g_return_if_fail((expr))
+#define g_return_val_if_fail_se(expr,val) g_return_val_if_fail((expr), (val))
+
#define g_return_if_reached() G_STMT_START{ \
g_log (G_LOG_DOMAIN, \
G_LOG_LEVEL_CRITICAL, \
#include "gmem.h"
#include "gtestutils.h"
#include "gthread.h"
+#include "gtimer.h"
#ifdef G_OS_UNIX
#include <unistd.h>
guint32 seed[4];
#ifdef G_OS_UNIX
static gboolean dev_urandom_exists = TRUE;
- GTimeVal now;
if (dev_urandom_exists)
{
}
if (!dev_urandom_exists)
- {
- g_get_current_time (&now);
- seed[0] = now.tv_sec;
- seed[1] = now.tv_usec;
+ {
+ gint64 now_us = g_get_real_time ();
+ seed[0] = now_us / G_USEC_PER_SEC;
+ seed[1] = now_us % G_USEC_PER_SEC;
seed[2] = getpid ();
seed[3] = getppid ();
}
{
if (allocator->stamp_counter >= MAX_STAMP_COUNTER)
{
- GTimeVal tv;
- g_get_current_time (&tv);
- allocator->last_stamp = tv.tv_sec * 1000 + tv.tv_usec / 1000; /* milli seconds */
+ gint64 now_us = g_get_real_time ();
+ allocator->last_stamp = now_us / 1000; /* milli seconds */
allocator->stamp_counter = 0;
}
else
* The macro can be turned off in final releases of code by defining
* `G_DISABLE_ASSERT` when compiling the application, so code must
* not depend on any side effects from @expr.
+ *
+ * For a version which is guaranteed to evaluate side effects in @expr,
+ * see g_assert_se().
+ */
+
+/**
+ * g_assert_se:
+ * @expr: the expression to check
+ *
+ * Debugging macro to terminate the application if the assertion
+ * fails. If the assertion fails (i.e. the expression is not true),
+ * an error message is logged and the application is terminated.
+ *
+ * The check can be turned off in final releases of code by defining
+ * `G_DISABLE_ASSERT` when compiling the application.
+ *
+ * Unlike g_assert(), this macro is guaranteed to evaluate side effects
+ * of @expr, even if checks are disabled. It is still undefined if the
+ * program will actually be aborted or not.
*/
/**
#ifdef G_DISABLE_ASSERT
#define g_assert_not_reached() G_STMT_START { (void) 0; } G_STMT_END
#define g_assert(expr) G_STMT_START { (void) 0; } G_STMT_END
+#define g_assert_se(expr) ((void) (expr))
#else /* !G_DISABLE_ASSERT */
#define g_assert_not_reached() G_STMT_START { g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, NULL); } G_STMT_END
#define g_assert(expr) G_STMT_START { \
g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
#expr); \
} G_STMT_END
+#define g_assert_se(expr) g_assert((expr))
#endif /* !G_DISABLE_ASSERT */
GLIB_AVAILABLE_IN_ALL
#include "config.h"
#include <glib/gvariant-core.h>
+#include "glib-private.h"
#include <glib/gvariant-serialiser.h>
#include <glib/gtestutils.h>
* The type_info field never changes during the life of the
* instance, so it can be accessed without a lock.
*
- * size: this is the size of the serialised form for the instance, if it
- * is known. If the instance is in serialised form then it is, by
- * definition, known. If the instance is in tree form then it may
- * be unknown (in which case it is -1). It is possible for the
- * size to be known when in tree form if, for example, the user
- * has called g_variant_get_size() without calling
- * g_variant_get_data(). Additionally, even when the user calls
- * g_variant_get_data() the size of the data must first be
- * determined so that a large enough buffer can be allocated for
- * the data.
- *
- * Once the size is known, it can never become unknown again.
- * g_variant_ensure_size() is used to ensure that the size is in
- * the known state -- it calculates the size if needed. After
- * that, the size field can be accessed without a lock.
+ * size: this is the size of the serialised form for the instance. It
+ * is known for serialised instances and also tree-form instances
+ * (for which it is calculated at construction time, from the
+ * known sizes of the children used). After construction, it
+ * never changes and therefore can be accessed without a lock.
*
* contents: a union containing either the information associated with
* holding a value in serialised form or holding a value in
g_free (value->contents.tree.children);
}
+/* < private >
+ * g_variant_lock_in_tree_form:
+ * @value: a #GVariant
+ *
+ * Locks @value if it is in tree form.
+ *
+ * Returns: %TRUE if @value is now in tree form with the lock acquired
+ */
+static gboolean
+g_variant_lock_in_tree_form (GVariant *value)
+{
+ if (g_atomic_int_get (&value->state) & STATE_SERIALISED)
+ return FALSE;
+
+ g_variant_lock (value);
+
+ if (value->state & STATE_SERIALISED)
+ {
+ g_variant_unlock (value);
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
/* This begins the main body of the recursive serialiser.
*
* There are 3 functions here that work as a team with the serialiser to
* instances are always in serialised form. For these instances,
* storing their serialised form merely involves a memcpy().
*
- * Serialisation is a two-step process. First, the size of the
- * serialised data must be calculated so that an appropriately-sized
- * buffer can be allocated. Second, the data is written into the
- * buffer.
+ * Converting to serialised form:
*
- * Determining the size:
- * The process of determining the size is triggered by a call to
- * g_variant_ensure_size() on a container. This invokes the
- * serialiser code to determine the size. The serialiser is passed
- * g_variant_fill_gvs() as a callback.
- *
- * g_variant_fill_gvs() is called by the serialiser on each child of
- * the container which, in turn, calls g_variant_ensure_size() on
- * itself and fills in the result of its own size calculation.
+ * The first step in the process of converting a GVariant to
+ * serialised form is to allocate a buffer. The size of the buffer is
+ * always known because we computed at construction time of the
+ * GVariant.
*
- * The serialiser uses the size information from the children to
- * calculate the size needed for the entire container.
- *
- * Writing the data:
* After the buffer has been allocated, g_variant_serialise() is
* called on the container. This invokes the serialiser code to write
- * the bytes to the container. The serialiser is, again, passed
+ * the bytes to the container. The serialiser is passed
* g_variant_fill_gvs() as a callback.
*
- * This time, when g_variant_fill_gvs() is called for each child, the
+ * At the time that g_variant_fill_gvs() is called for each child, the
* child is given a pointer to a sub-region of the allocated buffer
* where it should write its data. This is done by calling
* g_variant_store(). In the event that the instance is in serialised
static void g_variant_fill_gvs (GVariantSerialised *, gpointer);
/* < private >
- * g_variant_ensure_size:
- * @value: a #GVariant
- *
- * Ensures that the ->size field of @value is filled in properly. This
- * must be done as a precursor to any serialisation of the value in
- * order to know how large of a buffer is needed to store the data.
- *
- * The current thread must hold the lock on @value.
- */
-static void
-g_variant_ensure_size (GVariant *value)
-{
- g_assert (value->state & STATE_LOCKED);
-
- if (value->size == (gssize) -1)
- {
- gpointer *children;
- gsize n_children;
-
- children = (gpointer *) value->contents.tree.children;
- n_children = value->contents.tree.n_children;
- value->size = g_variant_serialiser_needed_size (value->type_info,
- g_variant_fill_gvs,
- children, n_children);
- }
-}
-
-/* < private >
* g_variant_serialise:
* @value: a #GVariant
* @data: an appropriately-sized buffer
*
* - reporting its type
*
- * - reporting its serialised size (requires knowing the size first)
+ * - reporting its serialised size
*
* - possibly storing its serialised form into the provided buffer
+ *
+ * This callback is also used during g_variant_new_from_children() in
+ * order to discover the size and type of each child.
*/
static void
g_variant_fill_gvs (GVariantSerialised *serialised,
{
GVariant *value = data;
- g_variant_lock (value);
- g_variant_ensure_size (value);
- g_variant_unlock (value);
-
if (serialised->type_info == NULL)
serialised->type_info = value->type_info;
g_assert (serialised->type_info == value->type_info);
*
* Ensures that @value is in serialised form.
*
- * If @value is in tree form then this function ensures that the
- * serialised size is known and then allocates a buffer of that size and
- * serialises the instance into the buffer. The 'children' array is
- * then released and the instance is set to serialised form based on the
- * contents of the buffer.
- *
- * The current thread must hold the lock on @value.
+ * If @value is in tree form then this function allocates a buffer of
+ * that size and serialises the instance into the buffer. The
+ * 'children' array is then released and the instance is set to
+ * serialised form based on the contents of the buffer.
*/
static void
g_variant_ensure_serialised (GVariant *value)
{
- g_assert (value->state & STATE_LOCKED);
-
- if (~value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
{
GBytes *bytes;
gpointer data;
- g_variant_ensure_size (value);
data = g_malloc (value->size);
g_variant_serialise (value, data);
value->contents.serialised.data = g_bytes_get_data (bytes, NULL);
value->contents.serialised.bytes = bytes;
value->state |= STATE_SERIALISED;
+
+ g_variant_unlock (value);
}
}
+/* Now we have the code to recursively serialise a GVariant into a
+ * GVariantVectors structure.
+ *
+ * We want to do this in cases where the GVariant contains large chunks
+ * of serialised data in order to avoid having to copy this data.
+ *
+ * This generally works the same as normal serialising (co-recursion
+ * with the serialiser) but instead of using a callback we just hard-code
+ * the callback with the name g_variant_callback_write_to_vectors().
+ *
+ * This is a private API that will be used by GDBus.
+ */
+gsize
+g_variant_callback_write_to_vectors (GVariantVectors *vectors,
+ gpointer data,
+ GVariantTypeInfo **type_info)
+{
+ GVariant *value = data;
+
+ if (g_variant_lock_in_tree_form (value))
+ {
+ g_variant_serialiser_write_to_vectors (vectors, value->type_info, value->size,
+ (gpointer *) value->contents.tree.children,
+ value->contents.tree.n_children);
+
+ g_variant_unlock (value);
+ }
+ else
+ g_variant_vectors_append_gbytes (vectors, value->contents.serialised.bytes,
+ value->contents.serialised.data, value->size);
+
+ if (type_info)
+ *type_info = value->type_info;
+
+ return value->size;
+}
+
+/* < private >
+ * g_variant_serialise_to_vectors:
+ * @value: a #GVariant
+ * @vectors: (out): the result
+ *
+ * Serialises @value into @vectors.
+ *
+ * The caller must free @vectors.
+ */
+void
+g_variant_to_vectors (GVariant *value,
+ GVariantVectors *vectors)
+{
+ g_variant_vectors_init (vectors);
+
+ g_variant_callback_write_to_vectors (vectors, value, NULL);
+}
+
/* < private >
* g_variant_alloc:
- * @type: the type of the new instance
+ * @type_info: (transfer full) the type info of the new instance
* @serialised: if the instance will be in serialised form
* @trusted: if the instance will be trusted
*
* Returns: a new #GVariant with a floating reference
*/
static GVariant *
-g_variant_alloc (const GVariantType *type,
- gboolean serialised,
- gboolean trusted)
+g_variant_alloc (GVariantTypeInfo *type_info,
+ gboolean serialised,
+ gboolean trusted)
{
GVariant *value;
value = g_slice_new (GVariant);
- value->type_info = g_variant_type_info_get (type);
+ value->type_info = type_info;
value->state = (serialised ? STATE_SERIALISED : 0) |
(trusted ? STATE_TRUSTED : 0) |
STATE_FLOATING;
- value->size = (gssize) -1;
value->ref_count = 1;
return value;
}
-/**
- * g_variant_new_from_bytes:
- * @type: a #GVariantType
- * @bytes: a #GBytes
- * @trusted: if the contents of @bytes are trusted
- *
- * Constructs a new serialised-mode #GVariant instance. This is the
- * inner interface for creation of new serialised values that gets
- * called from various functions in gvariant.c.
+/* -- internal -- */
+
+/* < internal >
+ * g_variant_new_from_children:
+ * @type_info: (transfer full) a #GVariantTypeInfo
+ * @children: an array of #GVariant pointers. Consumed.
+ * @n_children: the length of @children
+ * @trusted: %TRUE if every child in @children in trusted
*
- * A reference is taken on @bytes.
+ * Constructs a new tree-mode #GVariant instance. This is the inner
+ * interface for creation of new tree-mode values that gets called from
+ * various functions in gvariant.c.
*
- * Returns: (transfer none): a new #GVariant with a floating reference
+ * @children is consumed by this function. g_free() will be called on
+ * it some time later.
*
- * Since: 2.36
+ * Returns: a new #GVariant with a floating reference
*/
GVariant *
-g_variant_new_from_bytes (const GVariantType *type,
- GBytes *bytes,
- gboolean trusted)
+g_variant_new_from_children (GVariantTypeInfo *type_info,
+ GVariant **children,
+ gsize n_children,
+ gboolean trusted)
{
GVariant *value;
- guint alignment;
- gsize size;
-
- value = g_variant_alloc (type, TRUE, trusted);
-
- value->contents.serialised.bytes = g_bytes_ref (bytes);
-
- g_variant_type_info_query (value->type_info,
- &alignment, &size);
- if (size && g_bytes_get_size (bytes) != size)
- {
- /* Creating a fixed-sized GVariant with a bytes of the wrong
- * size.
- *
- * We should do the equivalent of pulling a fixed-sized child out
- * of a brozen container (ie: data is NULL size is equal to the correct
- * fixed size).
- */
- value->contents.serialised.data = NULL;
- value->size = size;
- }
- else
- {
- value->contents.serialised.data = g_bytes_get_data (bytes, &value->size);
- }
+ value = g_variant_alloc (type_info, FALSE, trusted);
+ value->contents.tree.children = children;
+ value->contents.tree.n_children = n_children;
+ value->size = g_variant_serialiser_needed_size (value->type_info, g_variant_fill_gvs,
+ (gpointer *) children, n_children);
return value;
}
-/* -- internal -- */
-
/* < internal >
- * g_variant_new_from_children:
- * @type: a #GVariantType
- * @children: an array of #GVariant pointers. Consumed.
- * @n_children: the length of @children
- * @trusted: %TRUE if every child in @children in trusted
- *
- * Constructs a new tree-mode #GVariant instance. This is the inner
+ * g_variant_new_serialised:
+ * @type_info: (transfer full): a #GVariantTypeInfo
+ * @bytes: (transfer full): the #GBytes holding @data
+ * @data: a pointer to the serialised data
+ * @size: the size of @data, in bytes
+ * @trusted: %TRUE if @data is trusted
+ *
+ * Constructs a new serialised #GVariant instance. This is the inner
* interface for creation of new serialised values that gets called from
* various functions in gvariant.c.
*
- * @children is consumed by this function. g_free() will be called on
- * it some time later.
+ * @bytes is consumed by this function. g_bytes_unref() will be called
+ * on it some time later.
*
* Returns: a new #GVariant with a floating reference
*/
GVariant *
-g_variant_new_from_children (const GVariantType *type,
- GVariant **children,
- gsize n_children,
- gboolean trusted)
+g_variant_new_serialised (GVariantTypeInfo *type_info,
+ GBytes *bytes,
+ gconstpointer data,
+ gsize size,
+ gboolean trusted)
{
GVariant *value;
+ gsize fixed_size;
- value = g_variant_alloc (type, FALSE, trusted);
- value->contents.tree.children = children;
- value->contents.tree.n_children = n_children;
+ value = g_variant_alloc (type_info, TRUE, trusted);
+ value->contents.serialised.bytes = bytes;
+ value->contents.serialised.data = data;
+ value->size = size;
+
+ g_variant_type_info_query (value->type_info, NULL, &fixed_size);
+ if G_UNLIKELY (fixed_size && size != fixed_size)
+ {
+ /* Creating a fixed-sized GVariant with a bytes of the wrong
+ * size.
+ *
+ * We should do the equivalent of pulling a fixed-sized child out
+ * of a broken container (ie: data is NULL size is equal to the correct
+ * fixed size).
+ *
+ * This really ought not to happen if the data is trusted...
+ */
+ if (trusted)
+ g_error ("Attempting to create a trusted GVariant instance out of invalid data");
+
+ /* We hang on to the GBytes (even though we don't use it anymore)
+ * because every GVariant must have a GBytes.
+ */
+ value->contents.serialised.data = NULL;
+ value->size = fixed_size;
+ }
return value;
}
return (value->state & STATE_TRUSTED) != 0;
}
+/* < internal >
+ * g_variant_get_serialised:
+ * @value: a #GVariant
+ * @bytes: (out) (transfer none): a location to store the #GBytes
+ * @size: (out): a location to store the size of the returned data
+ *
+ * Ensures that @value is in serialised form and returns information
+ * about it. This is called from various APIs in gvariant.c
+ *
+ * Returns: data, of length @size
+ */
+gconstpointer
+g_variant_get_serialised (GVariant *value,
+ GBytes **bytes,
+ gsize *size)
+{
+ g_variant_ensure_serialised (value);
+
+ if (bytes)
+ *bytes = value->contents.serialised.bytes;
+
+ *size = value->size;
+
+ return value->contents.serialised.data;
+}
+
+static GVariant *
+g_variant_vector_deserialise (GVariantTypeInfo *type_info,
+ GVariantVector *first_vector,
+ GVariantVector *last_vector,
+ gsize size,
+ gboolean trusted,
+ GArray *unpacked_children)
+{
+ g_assert (size > 0);
+
+ if (first_vector < last_vector)
+ {
+ GVariantVector *vector = first_vector;
+ const guchar *end_pointer;
+ GVariant **children;
+ guint save_point;
+ guint n_children;
+ gboolean failed;
+ guint i;
+
+ end_pointer = last_vector->data.pointer + last_vector->size;
+ save_point = unpacked_children->len;
+
+ if (!g_variant_serialiser_unpack_all (type_info, end_pointer, last_vector->size, size, unpacked_children))
+ {
+ for (i = save_point; i < unpacked_children->len; i++)
+ g_variant_type_info_unref (g_array_index (unpacked_children, GVariantUnpacked, i).type_info);
+ g_array_set_size (unpacked_children, save_point);
+
+ g_variant_type_info_unref (type_info);
+
+ return NULL;
+ }
+
+ n_children = unpacked_children->len - save_point;
+ children = g_new (GVariant *, n_children);
+ failed = FALSE;
+
+ for (i = 0; i < n_children; i++)
+ {
+ GVariantUnpacked *unpacked = &g_array_index (unpacked_children, GVariantUnpacked, save_point + i);
+ const guchar *resume_at_data;
+ gsize resume_at_size;
+ GVariantVector *fv;
+
+ /* Skip the alignment.
+ *
+ * We can destroy vectors because we won't be going back.
+ *
+ * We do a >= compare because we want to go to the next vector
+ * if it is the start of our child.
+ */
+ while (unpacked->skip >= vector->size)
+ {
+ unpacked->skip -= vector->size;
+ vector++;
+ }
+ g_assert (vector <= last_vector);
+
+ fv = vector;
+ fv->data.pointer += unpacked->skip;
+ fv->size -= unpacked->skip;
+
+ if (unpacked->size == 0)
+ {
+ children[i] = g_variant_new_serialised (unpacked->type_info, g_bytes_new (NULL, 0), NULL, 0, trusted);
+ g_variant_ref_sink (children[i]);
+ continue;
+ }
+
+ /* Now skip to the end, according to 'size'.
+ *
+ * We cannot destroy everything here because we will probably
+ * end up reusing the last one.
+ *
+ * We do a > compare because we want to stay on this vector if
+ * it is the end of our child.
+ */
+ size = unpacked->size;
+ while (unpacked->size > vector->size)
+ {
+ unpacked->size -= vector->size;
+ vector++;
+ }
+ g_assert (vector <= last_vector);
+
+ /* We have to modify the vectors for the benefit of the
+ * recursive step. We also have to remember where we left
+ * off, keeping in mind that the recursive step may itself
+ * modify the vectors.
+ */
+ resume_at_data = vector->data.pointer + unpacked->size;
+ resume_at_size = vector->size - unpacked->size;
+ vector->size = unpacked->size;
+
+ children[i] = g_variant_vector_deserialise (unpacked->type_info, fv, vector,
+ size, trusted, unpacked_children);
+
+ vector->data.pointer = resume_at_data;
+ vector->size = resume_at_size;
+
+ if (children[i])
+ g_variant_ref_sink (children[i]);
+ else
+ failed = TRUE;
+ }
+
+ /* We consumed all the type infos */
+ g_array_set_size (unpacked_children, save_point);
+
+ if G_UNLIKELY (failed)
+ {
+ for (i = 0; i < n_children; i++)
+ if (children[i])
+ g_variant_unref (children[i]);
+
+ g_variant_type_info_unref (type_info);
+ g_free (children);
+
+ return NULL;
+ }
+
+ return g_variant_new_from_children (type_info, children, n_children, trusted);
+ }
+ else
+ {
+ g_assert (first_vector == last_vector);
+ g_assert (size == first_vector->size);
+
+ return g_variant_new_serialised (type_info, g_bytes_ref (first_vector->gbytes),
+ first_vector->data.pointer, size, trusted);
+ }
+}
+
+GVariant *
+g_variant_from_vectors (const GVariantType *type,
+ GVariantVector *vectors,
+ gsize n_vectors,
+ gsize size,
+ gboolean trusted)
+{
+ GVariant *result;
+ GArray *tmp;
+
+ g_return_val_if_fail (vectors != NULL || n_vectors == 0, NULL);
+
+ if (size == 0)
+ return g_variant_new_serialised (g_variant_type_info_get (type), g_bytes_new (NULL, 0), NULL, 0, trusted);
+
+ tmp = g_array_new (FALSE, FALSE, sizeof (GVariantUnpacked));
+ result = g_variant_vector_deserialise (g_variant_type_info_get (type),
+ vectors, vectors + n_vectors - 1, size, trusted, tmp);
+ if (result)
+ g_variant_ref_sink (result);
+ g_array_free (tmp, TRUE);
+
+ return result;
+}
+
/* -- public -- */
/**
gsize
g_variant_get_size (GVariant *value)
{
- g_variant_lock (value);
- g_variant_ensure_size (value);
- g_variant_unlock (value);
-
return value->size;
}
gconstpointer
g_variant_get_data (GVariant *value)
{
- g_variant_lock (value);
g_variant_ensure_serialised (value);
- g_variant_unlock (value);
return value->contents.serialised.data;
}
-/**
- * g_variant_get_data_as_bytes:
- * @value: a #GVariant
- *
- * Returns a pointer to the serialised form of a #GVariant instance.
- * The semantics of this function are exactly the same as
- * g_variant_get_data(), except that the returned #GBytes holds
- * a reference to the variant data.
- *
- * Returns: (transfer full): A new #GBytes representing the variant data
- *
- * Since: 2.36
- */
-GBytes *
-g_variant_get_data_as_bytes (GVariant *value)
-{
- const gchar *bytes_data;
- const gchar *data;
- gsize bytes_size;
- gsize size;
-
- g_variant_lock (value);
- g_variant_ensure_serialised (value);
- g_variant_unlock (value);
-
- bytes_data = g_bytes_get_data (value->contents.serialised.bytes, &bytes_size);
- data = value->contents.serialised.data;
- size = value->size;
-
- if (data == bytes_data && size == bytes_size)
- return g_bytes_ref (value->contents.serialised.bytes);
- else
- return g_bytes_new_from_bytes (value->contents.serialised.bytes,
- data - bytes_data, size);
-}
-
/**
* g_variant_n_children:
{
gsize n_children;
- g_variant_lock (value);
-
- if (value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
+ {
+ n_children = value->contents.tree.n_children;
+ g_variant_unlock (value);
+ }
+ else
{
GVariantSerialised serialised = {
value->type_info,
n_children = g_variant_serialised_n_children (serialised);
}
- else
- n_children = value->contents.tree.n_children;
-
- g_variant_unlock (value);
return n_children;
}
g_variant_get_child_value (GVariant *value,
gsize index_)
{
+ GVariant *child;
+
g_return_val_if_fail (index_ < g_variant_n_children (value), NULL);
- if (~g_atomic_int_get (&value->state) & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
{
- g_variant_lock (value);
-
- if (~value->state & STATE_SERIALISED)
- {
- GVariant *child;
-
- child = g_variant_ref (value->contents.tree.children[index_]);
- g_variant_unlock (value);
-
- return child;
- }
+ child = g_variant_ref (value->contents.tree.children[index_]);
g_variant_unlock (value);
}
+ else
+ {
+ GVariantSerialised serialised = {
+ value->type_info,
+ (gpointer) value->contents.serialised.data,
+ value->size
+ };
+ GVariantSerialised s_child;
- {
- GVariantSerialised serialised = {
- value->type_info,
- (gpointer) value->contents.serialised.data,
- value->size
- };
- GVariantSerialised s_child;
- GVariant *child;
-
- /* get the serialiser to extract the serialised data for the child
- * from the serialised data for the container
- */
- s_child = g_variant_serialised_get_child (serialised, index_);
-
- /* create a new serialised instance out of it */
- child = g_slice_new (GVariant);
- child->type_info = s_child.type_info;
- child->state = (value->state & STATE_TRUSTED) |
- STATE_SERIALISED;
- child->size = s_child.size;
- child->ref_count = 1;
- child->contents.serialised.bytes =
- g_bytes_ref (value->contents.serialised.bytes);
- child->contents.serialised.data = s_child.data;
-
- return child;
- }
+ /* get the serialiser to extract the serialised data for the child
+ * from the serialised data for the container
+ */
+ s_child = g_variant_serialised_get_child (serialised, index_);
+
+ /* create a new serialised instance out of it */
+ child = g_variant_new_serialised (s_child.type_info,
+ g_bytes_ref (value->contents.serialised.bytes),
+ s_child.data, s_child.size,
+ value->state & STATE_TRUSTED);
+ child->state &= ~STATE_FLOATING;
+ }
+
+ return child;
}
/**
g_variant_store (GVariant *value,
gpointer data)
{
- g_variant_lock (value);
-
- if (value->state & STATE_SERIALISED)
+ if (g_variant_lock_in_tree_form (value))
+ {
+ g_variant_serialise (value, data);
+ g_variant_unlock (value);
+ }
+ else
{
if (value->contents.serialised.data != NULL)
memcpy (data, value->contents.serialised.data, value->size);
else
memset (data, 0, value->size);
}
- else
- g_variant_serialise (value, data);
-
- g_variant_unlock (value);
}
/**
gboolean
g_variant_is_normal_form (GVariant *value)
{
- if (value->state & STATE_TRUSTED)
+ if (g_atomic_int_get (&value->state) & STATE_TRUSTED)
return TRUE;
+ /* We always take the lock here because we expect to find that the
+ * value is in normal form and in that case, we need to update the
+ * state, which requires holding the lock.
+ */
g_variant_lock (value);
if (value->state & STATE_SERIALISED)
/* gvariant-core.c */
-GVariant * g_variant_new_from_children (const GVariantType *type,
+GVariant * g_variant_new_from_children (GVariantTypeInfo *type_info,
GVariant **children,
gsize n_children,
gboolean trusted);
+GVariant * g_variant_new_serialised (GVariantTypeInfo *type_info,
+ GBytes *bytes,
+ gconstpointer data,
+ gsize size,
+ gboolean trusted);
+
gboolean g_variant_is_trusted (GVariant *value);
GVariantTypeInfo * g_variant_get_type_info (GVariant *value);
+gconstpointer g_variant_get_serialised (GVariant *value,
+ GBytes **bytes,
+ gsize *size);
+
#endif /* __G_VARIANT_CORE_H__ */
(*one)++;
}
- else if (**one == 'N' && strchr ("ynqiuxthd", **the_other))
+ else if (**one == 'N' && strchr ("ynqiuxthfd", **the_other))
+ {
+ *out++ = *(*the_other)++;
+ (*one)++;
+ }
+
+ else if (**one == 'D' && (**the_other == 'f' || **the_other == 'd'))
{
*out++ = *(*the_other)++;
(*one)++;
pattern[j++] = 'i';
break;
+ case 'D':
+ pattern[j++] = 'd';
+ break;
+
default:
pattern[j++] = pattern[i];
break;
/* the basic types,
* plus undetermined number type and undetermined string type.
*/
- if (!strchr ("bynqiuxthdsogNS", key_char))
+ if (!strchr ("bynqiuxthfdsogNDS", key_char))
{
ast_set_error (ast, error, NULL,
G_VARIANT_PARSE_ERROR_BASIC_TYPE_EXPECTED,
(!g_str_has_prefix (number->token, "0x") && strchr (number->token, 'e')) ||
strstr (number->token, "inf") ||
strstr (number->token, "nan"))
- return g_strdup ("Md");
+ return g_strdup ("MD");
return g_strdup ("MN");
}
Number *number = (Number *) ast;
const gchar *token;
gboolean negative;
- gboolean floating;
guint64 abs_val;
gdouble dbl_val;
+ gchar typechar;
gchar *end;
+ typechar = *g_variant_type_peek_string (type);
token = number->token;
- if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
+ if (typechar == 'f' || typechar == 'd')
{
- floating = TRUE;
-
errno = 0;
dbl_val = g_ascii_strtod (token, &end);
if (dbl_val != 0.0 && errno == ERANGE)
}
else
{
- floating = FALSE;
negative = token[0] == '-';
if (token[0] == '-')
token++;
return NULL;
}
- if (floating)
- return g_variant_new_double (dbl_val);
-
- switch (*g_variant_type_peek_string (type))
+ switch (typechar)
{
case 'y':
if (negative || abs_val > G_MAXUINT8)
return number_overflow (ast, type, error);
return g_variant_new_handle (negative ? -abs_val : abs_val);
+ case 'f':
+ return g_variant_new_float (dbl_val);
+
+ case 'd':
+ return g_variant_new_double (dbl_val);
+
default:
return ast_type_error (ast, type, error);
}
else if (token_stream_consume (stream, "uint64"))
type = g_variant_type_copy (G_VARIANT_TYPE_UINT64);
+ else if (token_stream_consume (stream, "float"))
+ type = g_variant_type_copy (G_VARIANT_TYPE_FLOAT);
+
else if (token_stream_consume (stream, "double"))
type = g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
return value;
}
+static gboolean
+gvs_fixed_sized_maybe_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ if (total_size)
+ {
+ GVariantUnpacked unpacked;
+
+ unpacked.type_info = g_variant_type_info_ref (g_variant_type_info_element (type_info));
+ unpacked.skip = 0;
+ unpacked.size = total_size;
+
+ g_array_append_val (unpacked_children, unpacked);
+ }
+
+ return TRUE;
+}
+
static gsize
gvs_fixed_sized_maybe_needed_size (GVariantTypeInfo *type_info,
GVariantSerialisedFiller gvs_filler,
}
}
+static gsize
+gvs_fixed_sized_maybe_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ if (!n_children)
+ return 0;
+
+ return g_variant_callback_write_to_vectors (vectors, children[0], NULL);
+}
+
static gboolean
gvs_fixed_sized_maybe_is_normal (GVariantSerialised value)
{
return value;
}
+static gboolean
+gvs_variable_sized_maybe_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ if (total_size)
+ {
+ GVariantUnpacked unpacked;
+
+ unpacked.type_info = g_variant_type_info_ref (g_variant_type_info_element (type_info));
+ unpacked.skip = 0;
+ unpacked.size = total_size - 1;
+
+ g_array_append_val (unpacked_children, unpacked);
+ }
+
+ return TRUE;
+}
+
static gsize
gvs_variable_sized_maybe_needed_size (GVariantTypeInfo *type_info,
GVariantSerialisedFiller gvs_filler,
}
}
+static void
+gvs_variable_sized_maybe_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ if (n_children)
+ {
+ g_variant_callback_write_to_vectors (vectors, children[0], NULL);
+ g_variant_vectors_append_copy (vectors, "", 1);
+ }
+}
+
static gboolean
gvs_variable_sized_maybe_is_normal (GVariantSerialised value)
{
return child;
}
+static gboolean
+gvs_fixed_sized_array_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ GVariantTypeInfo *element;
+ gsize element_fixed_size;
+ gsize i, n;
+
+ element = g_variant_type_info_element (type_info);
+ g_variant_type_info_query (element, NULL, &element_fixed_size);
+
+ if (total_size % element_fixed_size)
+ return FALSE;
+
+ n = total_size / element_fixed_size;
+
+ for (i = 0; i < n; i++)
+ {
+ GVariantUnpacked unpacked;
+
+ unpacked.type_info = g_variant_type_info_ref (element);
+ unpacked.skip = 0;
+ unpacked.size = element_fixed_size;
+
+ g_array_append_val (unpacked_children, unpacked);
+ }
+
+ return TRUE;
+}
+
static gsize
gvs_fixed_sized_array_needed_size (GVariantTypeInfo *type_info,
GVariantSerialisedFiller gvs_filler,
}
}
+static void
+gvs_fixed_sized_array_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ gsize i;
+
+ for (i = 0; i < n_children; i++)
+ g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+}
+
static gboolean
gvs_fixed_sized_array_is_normal (GVariantSerialised value)
{
/* bytes may be NULL if (size == 0). */
static inline gsize
-gvs_read_unaligned_le (guchar *bytes,
- guint size)
+gvs_read_unaligned_le (const guchar *bytes,
+ guint size)
{
union
{
return child;
}
+static gboolean
+gvs_variable_sized_array_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ GVariantTypeInfo *element;
+ guint element_alignment;
+ const guchar *offsets;
+ gsize offset_size;
+ gsize offsets_array_size;
+ gsize prev_end;
+ gsize last_end;
+ gsize i, n;
+
+ if (total_size == 0)
+ return TRUE;
+
+ element = g_variant_type_info_element (type_info);
+ g_variant_type_info_query (element, &element_alignment, NULL);
+
+ offset_size = gvs_get_offset_size (total_size);
+
+ if (offset_size > end_size)
+ return FALSE;
+
+ last_end = gvs_read_unaligned_le (end_pointer - offset_size, offset_size);
+
+ if (last_end > total_size)
+ return 0;
+
+ offsets_array_size = total_size - last_end;
+
+ if (offsets_array_size > end_size)
+ return FALSE;
+
+ offsets = end_pointer - offsets_array_size;
+
+ if (offsets_array_size % offset_size)
+ return FALSE;
+
+ n = offsets_array_size / offset_size;
+
+ if (n == 0)
+ return FALSE;
+
+ prev_end = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ GVariantUnpacked unpacked;
+ gsize start;
+ gsize end;
+
+ start = prev_end + ((-prev_end) & element_alignment);
+ end = gvs_read_unaligned_le (offsets, offset_size);
+ offsets += offset_size;
+
+ if (start < prev_end || end < start || end > last_end)
+ return FALSE;
+
+ unpacked.type_info = g_variant_type_info_ref (element);
+ unpacked.skip = start - prev_end;
+ unpacked.size = end - start;
+
+ g_array_append_val (unpacked_children, unpacked);
+
+ prev_end = end;
+ }
+
+ return TRUE;
+}
+
static gsize
gvs_variable_sized_array_needed_size (GVariantTypeInfo *type_info,
GVariantSerialisedFiller gvs_filler,
}
}
+static void
+gvs_variable_sized_array_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ guint offset_key;
+ guint alignment;
+ gsize offset;
+ gsize i;
+
+ if (n_children == 0)
+ return;
+
+ offset_key = g_variant_vectors_reserve_offsets (vectors, n_children, gvs_get_offset_size (size));
+ g_variant_type_info_query (type_info, &alignment, NULL);
+ offset = 0;
+
+ for (i = 0; i < n_children; i++)
+ {
+ if ((-offset) & alignment)
+ offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+ offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+
+ g_variant_vectors_write_to_offsets (vectors, i, offset, offset_key);
+ }
+
+ g_variant_vectors_commit_offsets (vectors, offset_key);
+}
+
static gboolean
gvs_variable_sized_array_is_normal (GVariantSerialised value)
{
return child;
}
+static gboolean
+gvs_tuple_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ gsize offset_size;
+ gsize prev_end;
+ gsize i, n;
+
+ n = g_variant_type_info_n_members (type_info);
+
+ /* An empty tuple (n = 0) is always encoded as a single byte, which
+ * means that we should not be attempting to unpack it from multiple
+ * vectors.
+ */
+ if (n == 0)
+ return FALSE;
+
+ offset_size = gvs_get_offset_size (total_size);
+
+ prev_end = 0;
+
+ for (i = 0; i < n; i++)
+ {
+ const GVariantMemberInfo *member_info;
+ GVariantUnpacked unpacked;
+ gsize fixed_size;
+ guint alignment;
+ gsize start;
+ gsize end;
+
+ member_info = g_variant_type_info_member_info (type_info, i);
+ g_variant_type_info_query (member_info->type_info, &alignment, &fixed_size);
+
+ start = prev_end + ((-prev_end) & alignment);
+
+ switch (member_info->ending_type)
+ {
+ case G_VARIANT_MEMBER_ENDING_FIXED:
+ end = start + fixed_size;
+ break;
+
+ case G_VARIANT_MEMBER_ENDING_LAST:
+ end = total_size;
+ break;
+
+ case G_VARIANT_MEMBER_ENDING_OFFSET:
+ if (end_size < offset_size)
+ return FALSE;
+
+ end_pointer -= offset_size;
+ total_size -= offset_size;
+ end_size -= offset_size;
+
+ end = gvs_read_unaligned_le (end_pointer, offset_size);
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (start < prev_end || end < start || end > total_size)
+ return FALSE;
+
+ unpacked.type_info = g_variant_type_info_ref (member_info->type_info);
+ unpacked.skip = start - prev_end;
+ unpacked.size = end - start;
+
+ g_array_append_val (unpacked_children, unpacked);
+
+ prev_end = end;
+ }
+
+ g_assert (prev_end == total_size);
+
+ return TRUE;
+}
+
static gsize
gvs_tuple_needed_size (GVariantTypeInfo *type_info,
GVariantSerialisedFiller gvs_filler,
value.data[offset++] = '\0';
}
+
+static void
+gvs_tuple_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ const GVariantMemberInfo *member_info = NULL;
+ gsize fixed_size;
+ gsize offset;
+ gsize i;
+
+ if (n_children == 0)
+ {
+ g_variant_vectors_append_copy (vectors, "", 1);
+ return;
+ }
+
+ g_variant_type_info_query (type_info, NULL, &fixed_size);
+ offset = 0;
+
+ if (!fixed_size)
+ {
+ gsize n_offsets;
+
+ member_info = g_variant_type_info_member_info (type_info, n_children - 1);
+ n_offsets = member_info->i + 1;
+
+ if (n_offsets)
+ {
+ gsize offset_key = 0;
+
+ offset_key = g_variant_vectors_reserve_offsets (vectors, n_offsets, gvs_get_offset_size (size));
+
+ for (i = 0; i < n_children; i++)
+ {
+ guint alignment;
+
+ member_info = g_variant_type_info_member_info (type_info, i);
+ g_variant_type_info_query (member_info->type_info, &alignment, NULL);
+
+ if ((-offset) & alignment)
+ offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+ offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+
+ if (member_info->ending_type == G_VARIANT_MEMBER_ENDING_OFFSET)
+ g_variant_vectors_write_to_offsets (vectors, --n_offsets, offset, offset_key);
+ }
+
+ g_variant_vectors_commit_offsets (vectors, offset_key);
+ }
+ else
+ {
+ for (i = 0; i < n_children; i++)
+ {
+ guint alignment;
+
+ member_info = g_variant_type_info_member_info (type_info, i);
+ g_variant_type_info_query (member_info->type_info, &alignment, NULL);
+
+ if ((-offset) & alignment)
+ offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+ offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+ }
+ }
+ }
+ else
+ {
+ for (i = 0; i < n_children; i++)
+ {
+ guint alignment;
+
+ member_info = g_variant_type_info_member_info (type_info, i);
+ g_variant_type_info_query (member_info->type_info, &alignment, NULL);
+
+ if ((-offset) & alignment)
+ offset += g_variant_vectors_append_pad (vectors, (-offset) & alignment);
+
+ offset += g_variant_callback_write_to_vectors (vectors, children[i], NULL);
+ }
+
+ g_assert (fixed_size - offset < 8);
+ g_variant_vectors_append_pad (vectors, fixed_size - offset);
+ }
+}
+
static gboolean
gvs_tuple_is_normal (GVariantSerialised value)
{
return 1;
}
+static GVariantTypeInfo *
+gvs_variant_find_type (const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ gsize *child_size)
+{
+ gsize i;
+
+ for (i = 1; i <= end_size; i++)
+ if (end_pointer[-i] == '\0')
+ {
+ const gchar *type_string = (gchar *) end_pointer - i + 1;
+ const gchar *limit = (gchar *) end_pointer;
+ const gchar *end;
+
+ /* We may have a type string of length 'i'. Check for validity. */
+ if (g_variant_type_string_scan (type_string, limit, &end) && end == limit)
+ {
+ const GVariantType *type = (GVariantType *) type_string;
+
+ if (g_variant_type_is_definite (type))
+ {
+ GVariantTypeInfo *type_info;
+ gsize fixed_size;
+
+ type_info = g_variant_type_info_get (type);
+
+ g_variant_type_info_query (type_info, NULL, &fixed_size);
+
+ if (!fixed_size || fixed_size == total_size - i)
+ {
+ *child_size = total_size - i;
+
+ return type_info;
+ }
+
+ g_variant_type_info_unref (type_info);
+ }
+ }
+
+ /* No sense in trying other lengths if we already failed */
+ break;
+ }
+
+ return NULL;
+}
+
static inline GVariantSerialised
gvs_variant_get_child (GVariantSerialised value,
gsize index_)
{
GVariantSerialised child = { 0, };
- /* NOTE: not O(1) and impossible for it to be... */
- if (value.size)
+ if ((child.type_info = gvs_variant_find_type (value.data + value.size, value.size, value.size, &child.size)))
{
- /* find '\0' character */
- for (child.size = value.size - 1; child.size; child.size--)
- if (value.data[child.size] == '\0')
- break;
-
- /* ensure we didn't just hit the start of the string */
- if (value.data[child.size] == '\0')
- {
- const gchar *type_string = (gchar *) &value.data[child.size + 1];
- const gchar *limit = (gchar *) &value.data[value.size];
- const gchar *end;
-
- if (g_variant_type_string_scan (type_string, limit, &end) &&
- end == limit)
- {
- const GVariantType *type = (GVariantType *) type_string;
-
- if (g_variant_type_is_definite (type))
- {
- gsize fixed_size;
+ if (child.size != 0)
+ child.data = value.data;
+ }
+ else
+ {
+ child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
+ child.size = 1;
+ }
- child.type_info = g_variant_type_info_get (type);
+ return child;
+}
- if (child.size != 0)
- /* only set to non-%NULL if size > 0 */
- child.data = value.data;
+static gboolean
+gvs_variant_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ GVariantUnpacked unpacked;
- g_variant_type_info_query (child.type_info,
- NULL, &fixed_size);
+ if ((unpacked.type_info = gvs_variant_find_type (end_pointer, end_size, total_size, &unpacked.size)))
+ {
+ unpacked.skip = 0;
- if (!fixed_size || fixed_size == child.size)
- return child;
+ g_array_append_val (unpacked_children, unpacked);
- g_variant_type_info_unref (child.type_info);
- }
- }
- }
+ return TRUE;
}
- child.type_info = g_variant_type_info_get (G_VARIANT_TYPE_UNIT);
- child.data = NULL;
- child.size = 1;
-
- return child;
+ return FALSE;
}
static inline gsize
memcpy (value.data + child.size + 1, type_string, strlen (type_string));
}
+static void
+gvs_variant_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ GVariantTypeInfo *child_type_info;
+ const gchar *type_string;
+
+ g_variant_callback_write_to_vectors (vectors, children[0], &child_type_info);
+ type_string = g_variant_type_info_get_type_string (child_type_info);
+
+ g_variant_vectors_append_copy (vectors, "", 1);
+ g_variant_vectors_append_copy (vectors, type_string, strlen (type_string));
+}
+
static inline gboolean
gvs_variant_is_normal (GVariantSerialised value)
{
return gvs_/**/,/**/_needed_size (type_info, gvs_filler,
children, n_children);
+ )
+ g_assert_not_reached ();
+}
+
+gboolean
+g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children)
+{
+ DISPATCH_CASES (type_info,
+ return gvs_/**/,/**/_unpack_all (type_info, end_pointer, end_size, total_size, unpacked_children);
+ )
+
+ /* We are here because type_info is not a container type */
+ return FALSE;
+}
+void
+g_variant_serialiser_write_to_vectors (GVariantVectors *vectors,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children)
+{
+ DISPATCH_CASES (type_info,
+ gvs_/**/,/**/_write_to_vectors (vectors, type_info, size, children, n_children);
+ return;
)
g_assert_not_reached ();
}
#define __G_VARIANT_SERIALISER_H__
#include "gvarianttypeinfo.h"
+#include "gvariant-vectors.h"
typedef struct
{
gsize size;
} GVariantSerialised;
+typedef struct
+{
+ GVariantTypeInfo *type_info;
+ gsize skip;
+ gsize size;
+} GVariantUnpacked;
+
/* deserialisation */
GLIB_AVAILABLE_IN_ALL
gsize g_variant_serialised_n_children (GVariantSerialised container);
GVariantSerialised g_variant_serialised_get_child (GVariantSerialised container,
gsize index);
+gboolean g_variant_serialiser_unpack_all (GVariantTypeInfo *type_info,
+ const guchar *end_pointer,
+ gsize end_size,
+ gsize total_size,
+ GArray *unpacked_children);
+
/* serialisation */
typedef void (*GVariantSerialisedFiller) (GVariantSerialised *serialised,
gpointer data);
gboolean g_variant_serialiser_is_signature (gconstpointer data,
gsize size);
+
+gsize g_variant_callback_write_to_vectors (GVariantVectors *vectors,
+ gpointer data,
+ GVariantTypeInfo **type_info);
+void g_variant_serialiser_write_to_vectors (GVariantVectors *items,
+ GVariantTypeInfo *type_info,
+ gsize size,
+ const gpointer *children,
+ gsize n_children);
+
#endif /* __G_VARIANT_SERIALISER_H__ */
--- /dev/null
+#include "config.h"
+
+#include "gvariant-vectors.h"
+#include "gtestutils.h"
+
+static void
+append_zeros (GByteArray *array,
+ guint n)
+{
+ guchar zeros[8] = "";
+
+ g_byte_array_append (array, zeros, n);
+}
+
+void
+g_variant_vectors_init (GVariantVectors *vectors)
+{
+
+ /* The first 8 bytes of 'extra_bytes' is always 0. We use this for
+ * inserting padding in between two GBytes records.
+ */
+ vectors->extra_bytes = g_byte_array_new ();
+ append_zeros (vectors->extra_bytes, 8);
+
+ vectors->vectors = g_array_new (FALSE, FALSE, sizeof (GVariantVector));
+
+ vectors->offsets = g_byte_array_new ();
+}
+
+void
+g_variant_vectors_deinit (GVariantVectors *vectors)
+{
+ int i;
+ for (i = 0; i < vectors->vectors->len; i++)
+ {
+ GVariantVector *v = &g_array_index (vectors->vectors, GVariantVector, i);
+ g_bytes_unref (v->gbytes);
+ }
+ g_byte_array_unref (vectors->extra_bytes);
+ g_array_unref (vectors->vectors);
+ g_byte_array_unref (vectors->offsets);
+}
+
+gsize
+g_variant_vectors_append_pad (GVariantVectors *vectors,
+ gsize padding)
+{
+ /* If the last vector that we stored was 'pad' or 'copy' then we will
+ * expand it instead of adding a new one.
+ */
+ if (vectors->vectors->len)
+ {
+ GVariantVector *expand_vector = &g_array_index (vectors->vectors, GVariantVector, vectors->vectors->len - 1);
+
+ if (expand_vector->gbytes == NULL)
+ {
+ expand_vector->size += padding;
+
+ /* If the vector points to data, we need to add the padding to
+ * the end of that data. If it points to the zero bytes at
+ * the start then we can just grow it (but we must ensure that
+ * it doesn't get too large).
+ */
+ if (expand_vector->data.offset)
+ append_zeros (vectors->extra_bytes, padding);
+ else
+ g_assert (expand_vector->size < 8);
+
+ return padding;
+ }
+
+ /* If the last vector was a GBytes then fall through */
+ }
+
+ /* Otherwise, record a new vector pointing to the padding bytes at the
+ * start.
+ */
+ {
+ GVariantVector v;
+
+ v.gbytes = NULL;
+ v.data.offset = 0;
+ v.size = padding;
+
+ g_array_append_val (vectors->vectors, v);
+ }
+
+ return padding;
+}
+
+void
+g_variant_vectors_append_copy (GVariantVectors *vectors,
+ gconstpointer data,
+ gsize size)
+{
+ /* If the last vector that we stored was 'pad' or 'copy' then we will
+ * expand it instead of adding a new one.
+ */
+ if (vectors->vectors->len)
+ {
+ GVariantVector *expand_vector = &g_array_index (vectors->vectors, GVariantVector, vectors->vectors->len - 1);
+
+ if (expand_vector->gbytes == NULL)
+ {
+ /* If this was a padding vector then we must convert it to
+ * data first.
+ */
+ if (expand_vector->data.offset == 0)
+ {
+ expand_vector->data.offset = vectors->extra_bytes->len;
+ append_zeros (vectors->extra_bytes, expand_vector->size);
+ }
+
+ /* We have a vector pointing to data at the end of the
+ * extra_bytes array, so just append there and grow the
+ * vector.
+ */
+ g_byte_array_append (vectors->extra_bytes, data, size);
+ expand_vector->size += size;
+ return;
+ }
+
+ /* If the last vector was a GBytes then fall through */
+ }
+
+ /* Otherwise, copy the data and record a new vector. */
+ {
+ GVariantVector v;
+
+ v.gbytes = NULL;
+ v.data.offset = vectors->extra_bytes->len;
+ v.size = size;
+
+ g_byte_array_append (vectors->extra_bytes, data, size);
+ g_array_append_val (vectors->vectors, v);
+ }
+}
+
+void
+g_variant_vectors_append_gbytes (GVariantVectors *vectors,
+ GBytes *gbytes,
+ gconstpointer data,
+ gsize size)
+{
+ GVariantVector v;
+
+ /* Some very rough profiling has indicated that the trade-off for
+ * overhead on the atomic operations involved in the ref/unref on the
+ * GBytes is larger than the cost of the copy at ~128 bytes.
+ */
+ if (size < 128)
+ {
+ g_variant_vectors_append_copy (vectors, data, size);
+ return;
+ }
+
+ v.gbytes = g_bytes_ref (gbytes);
+ v.data.pointer = data;
+ v.size = size;
+
+ g_array_append_val (vectors->vectors, v);
+}
+
+typedef void (* WriteFunction) (gpointer base, gsize offset, gsize value);
+static void write_1 (gpointer base, gsize offset, gsize value) { ((guint8 *) base)[offset] = value; }
+static void write_2 (gpointer base, gsize offset, gsize value) { ((guint16 *) base)[offset] = GUINT16_TO_LE (value); }
+static void write_4 (gpointer base, gsize offset, gsize value) { ((guint32 *) base)[offset] = GUINT32_TO_LE (value); }
+static void write_8 (gpointer base, gsize offset, gsize value) { ((guint64 *) base)[offset] = GUINT64_TO_LE (value); }
+
+typedef struct
+{
+ gsize size;
+ WriteFunction func;
+} OffsetsHeader;
+
+gsize
+g_variant_vectors_reserve_offsets (GVariantVectors *vectors,
+ guint n_offsets,
+ guint offset_size)
+{
+ OffsetsHeader *header;
+ gsize total_size;
+ gsize add_size;
+ guint key;
+
+ total_size = n_offsets * offset_size;
+
+ /* Add room for the metadata and round up to multiple of 8 */
+ add_size = (sizeof (OffsetsHeader) + total_size + 7) & ~7ull;
+ key = vectors->offsets->len;
+ g_byte_array_set_size (vectors->offsets, key + add_size);
+ header = (OffsetsHeader *) (vectors->offsets->data + key);
+ key += sizeof (OffsetsHeader);
+ header->size = total_size;
+
+ switch (offset_size)
+ {
+ case 1:
+ header->func = write_1;
+ break;
+
+ case 2:
+ header->func = write_2;
+ break;
+
+ case 4:
+ header->func = write_4;
+ break;
+
+ case 8:
+ header->func = write_8;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ return key;
+}
+
+void
+g_variant_vectors_write_to_offsets (GVariantVectors *vectors,
+ gsize offset,
+ gsize value,
+ gsize key)
+{
+ OffsetsHeader *header;
+ guchar *offsets;
+
+ offsets = vectors->offsets->data + key;
+ header = (OffsetsHeader *) (offsets - sizeof (OffsetsHeader));
+
+ header->func (offsets, offset, value);
+}
+
+void
+g_variant_vectors_commit_offsets (GVariantVectors *vectors,
+ gsize key)
+{
+ OffsetsHeader *header;
+ guchar *offsets;
+
+ offsets = vectors->offsets->data + key;
+ header = (OffsetsHeader *) (offsets - sizeof (OffsetsHeader));
+
+ g_variant_vectors_append_copy (vectors, offsets, header->size);
+ g_byte_array_set_size (vectors->offsets, key - sizeof (OffsetsHeader));
+}
--- /dev/null
+
+#ifndef __G_VARIANT_VECTORS_H__
+#define __G_VARIANT_VECTORS_H__
+
+#include <glib/garray.h>
+
+typedef struct
+{
+ GByteArray *extra_bytes;
+ GArray *vectors;
+ GByteArray *offsets;
+} GVariantVectors;
+
+
+/* If ->bytes is NULL then offset/size point inside of extra_bytes,
+ * otherwise pointer/size point to memory owned by the GBytes.
+ */
+typedef struct
+{
+ GBytes *gbytes;
+ union {
+ const guchar *pointer;
+ gsize offset;
+ } data;
+ gsize size;
+} GVariantVector;
+
+void g_variant_vectors_init (GVariantVectors *vectors);
+
+
+void g_variant_vectors_deinit (GVariantVectors *vectors);
+
+
+gsize g_variant_vectors_append_pad (GVariantVectors *vectors,
+ gsize padding);
+
+
+void g_variant_vectors_append_copy (GVariantVectors *vectors,
+ gconstpointer data,
+ gsize size);
+
+
+void g_variant_vectors_append_gbytes (GVariantVectors *vectors,
+ GBytes *gbytes,
+ gconstpointer data,
+ gsize size);
+
+
+gsize g_variant_vectors_reserve_offsets (GVariantVectors *vectors,
+ guint n_offsets,
+ guint offset_size);
+
+
+void g_variant_vectors_write_to_offsets (GVariantVectors *vectors,
+ gsize offset,
+ gsize value,
+ gsize offset_key);
+
+
+void g_variant_vectors_commit_offsets (GVariantVectors *vectors,
+ gsize offset_key);
+
+#endif /* __G_GVARIANT_VECTORS_H__ */
* endianness, or of the length or type of the top-level variant.
*
* The amount of memory required to store a boolean is 1 byte. 16,
- * 32 and 64 bit integers and double precision floating point numbers
+ * 32 and 64 bit integers and floating point numbers
* use their "natural" size. Strings (including object path and
* signature strings) are stored with a nul terminator, and as such
* use the length of the string plus 1 byte.
gconstpointer data,
gsize size)
{
- GVariant *value;
- GBytes *bytes;
-
- bytes = g_bytes_new (data, size);
- value = g_variant_new_from_bytes (type, bytes, TRUE);
- g_bytes_unref (bytes);
+ gpointer mydata = g_memdup (data, size);
- return value;
+ return g_variant_new_serialised (g_variant_type_info_get (type),
+ g_bytes_new_take (mydata, size), mydata, size, TRUE);
}
/**
}
/* the constructors and accessors for byte, int{16,32,64}, handles and
- * doubles all look pretty much exactly the same, so we reduce
+ * floats all look pretty much exactly the same, so we reduce
* copy/pasting here.
*/
#define NUMERIC_TYPE(TYPE, type, ctype) \
NUMERIC_TYPE (HANDLE, handle, gint32)
/**
+ * g_variant_new_float:
+ * @value: a #gfloat floating point value
+ *
+ * Creates a new float #GVariant instance.
+ *
+ * Returns: (transfer none): a floating reference to a new float #GVariant instance
+ *
+ * Since: 2.44
+ **/
+/**
+ * g_variant_get_float:
+ * @value: a float #GVariant instance
+ *
+ * Returns the single precision floating point value of @value.
+ *
+ * It is an error to call this function with a @value of any type
+ * other than %G_VARIANT_TYPE_FLOAT.
+ *
+ * Returns: a #gfloat
+ *
+ * Since: 2.44
+ **/
+NUMERIC_TYPE (FLOAT, float, gfloat)
+
+/**
* g_variant_new_double:
* @value: a #gdouble floating point value
*
g_variant_new_maybe (const GVariantType *child_type,
GVariant *child)
{
+ GVariantTypeInfo *type_info;
GVariantType *maybe_type;
- GVariant *value;
g_return_val_if_fail (child_type == NULL || g_variant_type_is_definite
(child_type), 0);
child_type = g_variant_get_type (child);
maybe_type = g_variant_type_new_maybe (child_type);
+ type_info = g_variant_type_info_get (maybe_type);
+ g_variant_type_free (maybe_type);
if (child != NULL)
{
children[0] = g_variant_ref_sink (child);
trusted = g_variant_is_trusted (children[0]);
- value = g_variant_new_from_children (maybe_type, children, 1, trusted);
+ return g_variant_new_from_children (type_info, children, 1, trusted);
}
else
- value = g_variant_new_from_children (maybe_type, NULL, 0, TRUE);
-
- g_variant_type_free (maybe_type);
-
- return value;
+ return g_variant_new_from_children (type_info, NULL, 0, TRUE);
}
/**
g_variant_ref_sink (value);
- return g_variant_new_from_children (G_VARIANT_TYPE_VARIANT,
+ return g_variant_new_from_children (g_variant_type_info_get (G_VARIANT_TYPE_VARIANT),
g_memdup (&value, sizeof value),
1, g_variant_is_trusted (value));
}
GVariant * const *children,
gsize n_children)
{
+ GVariantTypeInfo *type_info;
GVariantType *array_type;
GVariant **my_children;
gboolean trusted;
- GVariant *value;
gsize i;
g_return_val_if_fail (n_children > 0 || child_type != NULL, NULL);
if (child_type == NULL)
child_type = g_variant_get_type (children[0]);
array_type = g_variant_type_new_array (child_type);
+ type_info = g_variant_type_info_get (array_type);
+ g_variant_type_free (array_type);
for (i = 0; i < n_children; i++)
{
trusted &= g_variant_is_trusted (children[i]);
}
- value = g_variant_new_from_children (array_type, my_children,
- n_children, trusted);
- g_variant_type_free (array_type);
-
- return value;
+ return g_variant_new_from_children (type_info, my_children, n_children, trusted);
}
/*< private >
g_variant_new_tuple (GVariant * const *children,
gsize n_children)
{
+ GVariantTypeInfo *type_info;
GVariantType *tuple_type;
GVariant **my_children;
gboolean trusted;
- GVariant *value;
gsize i;
g_return_val_if_fail (n_children == 0 || children != NULL, NULL);
}
tuple_type = g_variant_make_tuple_type (children, n_children);
- value = g_variant_new_from_children (tuple_type, my_children,
- n_children, trusted);
+ type_info = g_variant_type_info_get (tuple_type);
g_variant_type_free (tuple_type);
- return value;
+ return g_variant_new_from_children (type_info, my_children, n_children, trusted);
}
/*< private >
g_variant_new_dict_entry (GVariant *key,
GVariant *value)
{
+ GVariantTypeInfo *type_info;
GVariantType *dict_type;
GVariant **children;
gboolean trusted;
trusted = g_variant_is_trusted (key) && g_variant_is_trusted (value);
dict_type = g_variant_make_dict_entry_type (key, value);
- value = g_variant_new_from_children (dict_type, children, 2, trusted);
+ type_info = g_variant_type_info_get (dict_type);
g_variant_type_free (dict_type);
- return value;
+ return g_variant_new_from_children (type_info, children, 2, trusted);
}
/**
* - %G_VARIANT_TYPE_BOOLEAN: #guchar (not #gboolean!)
* - %G_VARIANT_TYPE_BYTE: #guchar
* - %G_VARIANT_TYPE_HANDLE: #guint32
+ * - %G_VARIANT_TYPE_FLOAT: #gfloat
* - %G_VARIANT_TYPE_DOUBLE: #gdouble
*
* For example, if calling this function for an array of 32-bit integers,
for (i = 0; i < length; i++)
strings[i] = g_variant_ref_sink (g_variant_new_string (strv[i]));
- return g_variant_new_from_children (G_VARIANT_TYPE_STRING_ARRAY,
+ return g_variant_new_from_children (g_variant_type_info_get (G_VARIANT_TYPE_STRING_ARRAY),
strings, length, TRUE);
}
for (i = 0; i < length; i++)
strings[i] = g_variant_ref_sink (g_variant_new_object_path (strv[i]));
- return g_variant_new_from_children (G_VARIANT_TYPE_OBJECT_PATH_ARRAY,
+ return g_variant_new_from_children (g_variant_type_info_get (G_VARIANT_TYPE_OBJECT_PATH_ARRAY),
strings, length, TRUE);
}
for (i = 0; i < length; i++)
strings[i] = g_variant_ref_sink (g_variant_new_bytestring (strv[i]));
- return g_variant_new_from_children (G_VARIANT_TYPE_BYTESTRING_ARRAY,
+ return g_variant_new_from_children (g_variant_type_info_get (G_VARIANT_TYPE_BYTESTRING_ARRAY),
strings, length, TRUE);
}
* @G_VARIANT_CLASS_INT64: The #GVariant is a signed 64 bit integer.
* @G_VARIANT_CLASS_UINT64: The #GVariant is an unsigned 64 bit integer.
* @G_VARIANT_CLASS_HANDLE: The #GVariant is a file handle index.
+ * @G_VARIANT_CLASS_FLOAT: The #GVariant is a single precision floating
+ * point value.
* @G_VARIANT_CLASS_DOUBLE: The #GVariant is a double precision floating
* point value.
* @G_VARIANT_CLASS_STRING: The #GVariant is a normal string.
g_variant_get_uint64 (value));
break;
+ case G_VARIANT_CLASS_FLOAT:
+ {
+ gchar buffer[100];
+ gint i;
+
+ g_ascii_dtostr (buffer, sizeof buffer, g_variant_get_float (value));
+
+ for (i = 0; buffer[i]; i++)
+ if (buffer[i] == '.' || buffer[i] == 'e' ||
+ buffer[i] == 'n' || buffer[i] == 'N')
+ break;
+
+ /* if there is no '.' or 'e' in the float then add one */
+ if (buffer[i] == '\0')
+ {
+ buffer[i++] = '.';
+ buffer[i++] = '0';
+ buffer[i++] = '\0';
+ }
+
+ if (type_annotate)
+ g_string_append (string, "float ");
+ g_string_append (string, buffer);
+ }
+ break;
+
case G_VARIANT_CLASS_DOUBLE:
{
gchar buffer[100];
case G_VARIANT_CLASS_INT32:
case G_VARIANT_CLASS_UINT32:
case G_VARIANT_CLASS_HANDLE:
+ case G_VARIANT_CLASS_FLOAT:
{
const guint *ptr;
* two values that have types that are not exactly equal. For example,
* you cannot compare a 32-bit signed integer with a 32-bit unsigned
* integer. Also note that this function is not particularly
- * well-behaved when it comes to comparison of doubles; in particular,
+ * well-behaved when it comes to comparison of floats; in particular,
* the handling of incomparable values (ie: NaN) is undefined.
*
* If you only require an equality comparison, g_variant_equal() is more
return (a_val == b_val) ? 0 : (a_val > b_val) ? 1 : -1;
}
+ case G_VARIANT_CLASS_FLOAT:
+ {
+ gfloat a_val = g_variant_get_float (a);
+ gfloat b_val = g_variant_get_float (b);
+
+ return (a_val == b_val) ? 0 : (a_val > b_val) ? 1 : -1;
+ }
+
case G_VARIANT_CLASS_DOUBLE:
{
gdouble a_val = g_variant_get_double (a);
else
g_assert_not_reached ();
- value = g_variant_new_from_children (my_type,
+ value = g_variant_new_from_children (g_variant_type_info_get (my_type),
g_renew (GVariant *,
GVSB(builder)->children,
GVSB(builder)->offset),
switch (next_char())
{
case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
- case 'x': case 't': case 'h': case 'd': case 's': case 'o':
- case 'g': case 'v': case '*': case '?': case 'r':
+ case 'x': case 't': case 'h': case 'f': case 'd': case 's':
+ case 'o': case 'g': case 'v': case '*': case '?': case 'r':
break;
case 'm':
va_arg (*app, guint64);
return;
+ case 'f':
case 'd':
va_arg (*app, gdouble);
return;
case 'h':
return g_variant_new_handle (va_arg (*app, gint));
+ case 'f':
+ return g_variant_new_float (va_arg (*app, gdouble));
+
case 'd':
return g_variant_new_double (va_arg (*app, gdouble));
/* The code below assumes this */
G_STATIC_ASSERT (sizeof (gboolean) == sizeof (guint32));
+G_STATIC_ASSERT (sizeof (gfloat) == sizeof (guint32));
G_STATIC_ASSERT (sizeof (gdouble) == sizeof (guint64));
static void
*(gint32 *) ptr = g_variant_get_handle (value);
return;
+ case 'f':
+ *(gfloat *) ptr = g_variant_get_float (value);
+ return;
+
case 'd':
*(gdouble *) ptr = g_variant_get_double (value);
return;
case 'u':
case 'h':
case 'b':
+ case 'f':
*(guint32 *) ptr = 0;
return;
case G_VARIANT_CLASS_HANDLE:
return g_variant_new_handle (g_variant_get_handle (value));
+ case G_VARIANT_CLASS_FLOAT:
+ return g_variant_new_float (g_variant_get_float (value));
+
case G_VARIANT_CLASS_DOUBLE:
return g_variant_new_double (g_variant_get_double (value));
* Performs a byteswapping operation on the contents of @value. The
* result is that all multi-byte numeric data contained in @value is
* byteswapped. That includes 16, 32, and 64bit signed and unsigned
- * integers as well as file handles and double precision floating point
- * values.
+ * integers as well as file handles and floating point values.
*
* This function is an identity mapping on any value that does not
* contain multi-byte numeric data. That include strings, booleans,
GDestroyNotify notify,
gpointer user_data)
{
- GVariant *value;
GBytes *bytes;
g_return_val_if_fail (g_variant_type_is_definite (type), NULL);
g_return_val_if_fail (data != NULL || size == 0, NULL);
+ if (size == 0)
+ {
+ if (notify)
+ {
+ (* notify) (user_data);
+ notify = NULL;
+ }
+
+ data = NULL;
+ }
+
if (notify)
bytes = g_bytes_new_with_free_func (data, size, notify, user_data);
else
bytes = g_bytes_new_static (data, size);
- value = g_variant_new_from_bytes (type, bytes, trusted);
- g_bytes_unref (bytes);
+ return g_variant_new_serialised (g_variant_type_info_get (type), bytes, data, size, trusted);
+}
- return value;
+/**
+ * g_variant_new_from_bytes:
+ * @type: a #GVariantType
+ * @bytes: a #GBytes
+ * @trusted: if the contents of @bytes are trusted
+ *
+ * Constructs a new serialised-mode #GVariant instance. This is the
+ * inner interface for creation of new serialised values that gets
+ * called from various functions in gvariant.c.
+ *
+ * A reference is taken on @bytes.
+ *
+ * Returns: (transfer none): a new #GVariant with a floating reference
+ *
+ * Since: 2.36
+ */
+GVariant *
+g_variant_new_from_bytes (const GVariantType *type,
+ GBytes *bytes,
+ gboolean trusted)
+{
+ gconstpointer data;
+ gsize size;
+
+ g_return_val_if_fail (g_variant_type_is_definite (type), NULL);
+
+ data = g_bytes_get_data (bytes, &size);
+
+ return g_variant_new_serialised (g_variant_type_info_get (type), g_bytes_ref (bytes), data, size, trusted);
+}
+
+/**
+ * g_variant_get_data_as_bytes:
+ * @value: a #GVariant
+ *
+ * Returns a pointer to the serialised form of a #GVariant instance.
+ * The semantics of this function are exactly the same as
+ * g_variant_get_data(), except that the returned #GBytes holds
+ * a reference to the variant data.
+ *
+ * Returns: (transfer full): A new #GBytes representing the variant data
+ *
+ * Since: 2.36
+ */
+GBytes *
+g_variant_get_data_as_bytes (GVariant *value)
+{
+ gconstpointer data;
+ GBytes *bytes;
+ gsize size;
+ gconstpointer bytes_data;
+ gsize bytes_size;
+
+ data = g_variant_get_serialised (value, &bytes, &size);
+ bytes_data = g_bytes_get_data (bytes, &bytes_size);
+
+ /* Try to reuse the GBytes held internally by GVariant, if it exists
+ * and is covering exactly the correct range.
+ */
+ if (data == bytes_data && size == bytes_size)
+ return g_bytes_ref (bytes);
+
+ /* See g_variant_get_data() about why it can return NULL... */
+ else if (data == NULL)
+ return g_bytes_new_take (g_malloc0 (size), size);
+
+ /* Otherwise, make a new GBytes with reference to the old. */
+ else
+ return g_bytes_new_with_free_func (data, size, (GDestroyNotify) g_bytes_unref, g_bytes_ref (bytes));
}
/* Epilogue {{{1 */
G_VARIANT_CLASS_INT64 = 'x',
G_VARIANT_CLASS_UINT64 = 't',
G_VARIANT_CLASS_HANDLE = 'h',
+ G_VARIANT_CLASS_FLOAT = 'f',
G_VARIANT_CLASS_DOUBLE = 'd',
G_VARIANT_CLASS_STRING = 's',
G_VARIANT_CLASS_OBJECT_PATH = 'o',
GVariant * g_variant_new_uint64 (guint64 value);
GLIB_AVAILABLE_IN_ALL
GVariant * g_variant_new_handle (gint32 value);
+GLIB_AVAILABLE_IN_2_44
+GVariant * g_variant_new_float (gfloat value);
GLIB_AVAILABLE_IN_ALL
GVariant * g_variant_new_double (gdouble value);
GLIB_AVAILABLE_IN_ALL
guint64 g_variant_get_uint64 (GVariant *value);
GLIB_AVAILABLE_IN_ALL
gint32 g_variant_get_handle (GVariant *value);
+GLIB_AVAILABLE_IN_2_44
+gfloat g_variant_get_float (GVariant *value);
GLIB_AVAILABLE_IN_ALL
gdouble g_variant_get_double (GVariant *value);
GLIB_AVAILABLE_IN_ALL
* A basic type string describes a basic type (as per
* g_variant_type_is_basic()) and is always a single character in length.
* The valid basic type strings are "b", "y", "n", "q", "i", "u", "x", "t",
- * "h", "d", "s", "o", "g" and "?".
+ * "h", "f", "d", "s", "o", "g" and "?".
*
* The above definition is recursive to arbitrary depth. "aaaaai" and
* "(ui(nq((y)))s)" are both valid type strings, as is
* - `h`: the type string of %G_VARIANT_TYPE_HANDLE; a signed 32 bit value
* that, by convention, is used as an index into an array of file
* descriptors that are sent alongside a D-Bus message.
+ * - `f`: the type string of %G_VARIANT_TYPE_FLOAT; a single precision
+ * floating point value.
* - `d`: the type string of %G_VARIANT_TYPE_DOUBLE; a double precision
* floating point value.
* - `s`: the type string of %G_VARIANT_TYPE_STRING; a string.
case '{':
if (string == limit || *string == '\0' || /* { */
- !strchr ("bynqihuxtdsog?", *string++) || /* key */
+ !strchr ("bynqihuxtfdsog?", *string++) || /* key */
!g_variant_type_string_scan (string, limit, &string) || /* value */
string == limit || *string++ != '}') /* } */
return FALSE;
case 'b': case 'y': case 'n': case 'q': case 'i': case 'u':
case 'x': case 't': case 'd': case 's': case 'o': case 'g':
- case 'v': case 'r': case '*': case '?': case 'h':
+ case 'v': case 'r': case '*': case '?': case 'h': case 'f':
break;
default:
*
* Determines if the given @type is a basic type.
*
- * Basic types are booleans, bytes, integers, doubles, strings, object
- * paths and signatures.
+ * Basic types are booleans, bytes, integers, floats, doubles, strings,
+ * object paths and signatures.
*
* Only a basic type may be used as the key of a dictionary entry.
*
case 'u':
case 't':
case 'x':
+ case 'f':
case 'd':
case 's':
case 'o':
#define G_VARIANT_TYPE_UINT64 ((const GVariantType *) "t")
/**
+ * G_VARIANT_TYPE_FLOAT:
+ *
+ * The type of a single precision IEEE754 floating point number. You
+ * can store a number as large as 3.40e38 in these (plus and minus) but
+ * there are some gaps on the way.
+ **/
+#define G_VARIANT_TYPE_FLOAT ((const GVariantType *) "f")
+
+/**
* G_VARIANT_TYPE_DOUBLE:
*
* The type of a double precision IEEE754 floating point number.
/* 'c' */ { not_a_type },
/* 'd' */ { fixed_aligned(8) }, /* double */
/* 'e' */ { not_a_type },
- /* 'f' */ { not_a_type },
+ /* 'f' */ { fixed_aligned(4) }, /* float */
/* 'g' */ { unaligned }, /* signature string */
/* 'h' */ { fixed_aligned(4) }, /* file handle (int32) */
/* 'i' */ { fixed_aligned(4) }, /* int32 */
* GVariantTypeInfo itself, we save a bunch of relocations.
*/
static const char g_variant_type_info_basic_chars[24][2] = {
- "b", " ", "d", " ", " ", "g", "h", "i", " ", " ", " ", " ",
+ "b", " ", "d", " ", "f", "g", "h", "i", " ", " ", " ", " ",
"n", "o", " ", "q", " ", "s", "t", "u", "v", " ", "x", "y"
};
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <errno.h>
+#include <unistd.h>
#include "glib.h"
+#include "glib-unix.h"
+
+#include "glib-linux.h"
static const gchar *NYAN = "nyannyan";
static const gsize N_NYAN = 8;
GBytes *bytes;
/* Memory transferred: one reference, and allocated with g_malloc */
- bytes = g_bytes_new (NYAN, N_NYAN);
+ bytes = g_bytes_new_take (g_memdup (NYAN, N_NYAN), N_NYAN);
memory = g_bytes_get_data (bytes, NULL);
data = g_bytes_unref_to_data (bytes, &size);
g_assert (data == memory);
GBytes *bytes;
/* Memory transferred: one reference, and allocated with g_malloc */
- bytes = g_bytes_new (NYAN, N_NYAN);
+ bytes = g_bytes_new_take (g_memdup (NYAN, N_NYAN), N_NYAN);
memory = g_bytes_get_data (bytes, NULL);
array = g_bytes_unref_to_array (bytes);
g_assert (array != NULL);
g_assert (size == 0);
}
+#ifdef GLIB_LINUX
+static void
+test_memfd (void)
+{
+ GBytes *bytes;
+ gint fd;
+
+ fd = glib_linux_memfd_create ("", MFD_CLOEXEC);
+ if (fd == -1 && errno == EINVAL)
+ {
+ g_test_skip ("missing kernel memfd support");
+ return;
+ }
+
+ /* We should not be able to seal this one */
+ g_assert (!g_unix_fd_ensure_zero_copy_safe (fd));
+ close (fd);
+
+ /* but this one will work */
+ fd = glib_linux_memfd_create ("", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ bytes = g_bytes_new_take_zero_copy_fd (fd);
+ g_assert_cmpint (g_bytes_get_size (bytes), ==, 0);
+ g_bytes_unref (bytes);
+
+ /* try with real data */
+ fd = glib_linux_memfd_create ("", MFD_CLOEXEC | MFD_ALLOW_SEALING);
+ g_assert_se (write (fd, NYAN, N_NYAN) == N_NYAN);
+ bytes = g_bytes_new_take_zero_copy_fd (fd);
+ g_assert_cmpint (g_bytes_get_size (bytes), ==, N_NYAN);
+ g_assert (memcmp (g_bytes_get_data (bytes, NULL), NYAN, N_NYAN) == 0);
+ g_assert (g_bytes_get_zero_copy_fd (bytes) == fd);
+
+ /* ensure that we cannot modify the fd further */
+ g_assert_se (write (fd, NYAN, N_NYAN) == -1);
+
+ /* that's enough for now */
+ g_bytes_unref (bytes);
+}
+#endif
+
int
main (int argc, char *argv[])
{
g_test_add_func ("/bytes/to-array/two-refs", test_to_array_two_refs);
g_test_add_func ("/bytes/to-array/non-malloc", test_to_array_non_malloc);
g_test_add_func ("/bytes/null", test_null);
+#ifdef GLIB_LINUX
+ g_test_add_func ("/bytes/memfd", test_memfd);
+#endif
return g_test_run ();
}
#include "config.h"
#include <glib/gvariant-internal.h>
+#include <glib/glib-private.h>
#include <string.h>
#include <stdlib.h>
#include <glib.h>
-#define BASIC "bynqiuxthdsog?"
+#define BASIC "bynqiuxthfdsog?"
#define N_BASIC (G_N_ELEMENTS (BASIC) - 1)
-#define INVALIDS "cefjklpwz&@^$"
+#define INVALIDS "cejklpwz&@^$"
#define N_INVALIDS (G_N_ELEMENTS (INVALIDS) - 1)
/* see comment in gvariant-serialiser.c about this madness.
return g_variant_type_copy (G_VARIANT_TYPE_UINT64);
case 'h':
return g_variant_type_copy (G_VARIANT_TYPE_HANDLE);
+ case 'f':
+ return g_variant_type_copy (G_VARIANT_TYPE_FLOAT);
case 'd':
return g_variant_type_copy (G_VARIANT_TYPE_DOUBLE);
case 's':
result = g_strdup ("t");
else if (g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
result = g_strdup ("h");
+ else if (g_variant_type_equal (type, G_VARIANT_TYPE_FLOAT))
+ result = g_strdup ("f");
else if (g_variant_type_equal (type, G_VARIANT_TYPE_DOUBLE))
result = g_strdup ("d");
else if (g_variant_type_equal (type, G_VARIANT_TYPE_STRING))
else if (g_variant_type_equal (type, G_VARIANT_TYPE_INT32) ||
g_variant_type_equal (type, G_VARIANT_TYPE_UINT32) ||
+ g_variant_type_equal (type, G_VARIANT_TYPE_FLOAT) ||
g_variant_type_equal (type, G_VARIANT_TYPE_HANDLE))
{
al = fs = 4;
union {
guint64 integer;
+ gfloat single;
gdouble floating;
gchar string[200];
} data;
instance->data_size = 8;
break;
+ case 'f':
+ instance->data.single = g_test_rand_double ();
+ instance->data_size = 4;
+ break;
+
case 'd':
instance->data.floating = g_test_rand_double ();
instance->data_size = 8;
result = g_variant_new_handle (tree->data.integer);
break;
+ case 'f':
+ result = g_variant_new_float (tree->data.single);
+ break;
+
case 'd':
result = g_variant_new_double (tree->data.floating);
break;
return result;
}
+static GVariant *
+create_random_gvariant (guint depth)
+{
+ TreeInstance *tree;
+ GVariant *value;
+
+ tree = tree_instance_new (NULL, depth);
+ value = g_variant_take_ref (tree_instance_get_gvariant (tree));
+ tree_instance_free (tree);
+
+ return value;
+}
+
static gboolean
tree_instance_check_gvariant (TreeInstance *tree,
GVariant *value)
case 'h':
return g_variant_get_handle (value) == (gint32) tree->data.integer;
+ case 'f':
+ {
+ gfloat floating = g_variant_get_float (value);
+
+ return memcmp (&floating, &tree->data.single, sizeof floating) == 0;
+ }
+
case 'd':
{
gdouble floating = g_variant_get_double (value);
static void
test_parser (void)
{
+ GError *error = NULL;
TreeInstance *tree;
GVariant *parsed;
GVariant *value;
pt = g_variant_print (value, TRUE);
p = g_variant_print (value, FALSE);
- parsed = g_variant_parse (NULL, pt, NULL, NULL, NULL);
+ parsed = g_variant_parse (NULL, pt, NULL, NULL, &error);
+ g_assert_no_error (error);
res = g_variant_print (parsed, FALSE);
- g_assert_cmpstr (p, ==, res);
+ if (!strstr (pt, "float")) /* FIXME: need reliable round-trip for floats */
+ g_assert_cmpstr (p, ==, res);
g_variant_unref (parsed);
g_free (res);
- parsed = g_variant_parse (g_variant_get_type (value), p,
- NULL, NULL, NULL);
+ parsed = g_variant_parse (g_variant_get_type (value), p, NULL, NULL, &error);
+ g_assert_no_error (error);
res = g_variant_print (parsed, TRUE);
- g_assert_cmpstr (pt, ==, res);
+ if (!strstr (pt, "float")) /* FIXME: need reliable round-trip for floats */
+ g_assert_cmpstr (pt, ==, res);
g_variant_unref (parsed);
g_free (res);
{
GVariant *a;
GVariant *tuple;
+ GVariant *b;
+ GVariant *c;
GBytes *bytes;
GBytes *bytes2;
const guint8 values[5] = { 1, 2, 3, 4, 5 };
const guint8 *elts;
+ gchar *tmp;
gsize n_elts;
gint i;
g_bytes_unref (bytes2);
g_variant_unref (a);
g_variant_unref (tuple);
+
+ /* Feed in some non-normal data... make sure it's aligned.
+ *
+ * Here we have an array of three elements. The first and last are
+ * normal ints ('iiii') and array-of-bytes data ('ayay'). The middle
+ * element is zero-bytes wide, which will present a problem when
+ * fetching the fixed-size integer out of it.
+ * */
+ tmp = g_strdup ("iiiiayayiiiisayay\x08\x08\x10");
+ bytes = g_bytes_new_take (tmp, strlen (tmp));
+ a = g_variant_new_from_bytes (G_VARIANT_TYPE ("a(iay)"), bytes, FALSE);
+ g_bytes_unref (bytes);
+
+ /* The middle tuple is zero bytes */
+ b = g_variant_get_child_value (a, 1);
+ g_assert_cmpint (g_variant_get_size (b), ==, 0);
+
+ /* But we're going to pull a 4-byte child out of it... */
+ c = g_variant_get_child_value (b, 0);
+ g_assert_cmpint (g_variant_get_size (c), ==, 4);
+
+ /* g_variant_get_data() is allowed to fail in this case.
+ * NB: if someone finds a way to avoid this then that's fine too...
+ */
+ g_assert (g_variant_get_data (c) == NULL);
+
+ /* but since it's four bytes, it ought to have data... */
+ bytes = g_variant_get_data_as_bytes (c);
+ g_assert_cmpint (g_bytes_get_size (bytes), ==, 4);
+ g_assert (memcmp (g_bytes_get_data (bytes, NULL), "\0\0\0\0", 4) == 0);
+ g_bytes_unref (bytes);
+
+ g_variant_unref (c);
+ g_variant_unref (b);
+ g_variant_unref (a);
}
typedef struct {
G_GNUC_END_IGNORE_DEPRECATIONS
}
+static GByteArray *
+flatten_vectors (GVariantVectors *v)
+{
+ GByteArray *result;
+ guint i;
+
+ result = g_byte_array_new ();
+
+ for (i = 0; i < v->vectors->len; i++)
+ {
+ GVariantVector vec = g_array_index (v->vectors, GVariantVector, i);
+
+ if (vec.gbytes)
+ g_byte_array_append (result, vec.data.pointer, vec.size);
+ else
+ g_byte_array_append (result, v->extra_bytes->data + vec.data.offset, vec.size);
+ }
+
+ return result;
+}
+
+static void
+test_vector_serialiser (void)
+{
+ GVariantVectors vectors;
+ GByteArray *flattened;
+ GVariant *value;
+ guint i;
+
+ for (i = 0; i < 100; i++)
+ {
+ guint j;
+
+ value = create_random_gvariant (2);
+ //g_print (">>> %s\n", g_variant_print (value, TRUE));
+
+ GLIB_PRIVATE_CALL(g_variant_to_vectors) (value, &vectors);
+ for (j = 0; j < vectors.vectors->len; j++)
+ {
+ GVariantVector *v = &g_array_index (vectors.vectors, GVariantVector, j);
+
+ if (!v->gbytes)
+ {
+ v->gbytes = g_bytes_new (NULL, 0);
+ v->data.pointer = v->data.offset + vectors.extra_bytes->data;
+ }
+
+ //g_print (" V %p %p %d\n", v, v->data.pointer, (guint) v->size);
+ }
+ GLIB_PRIVATE_CALL(g_variant_from_vectors) (g_variant_get_type (value), (GVariantVector *) vectors.vectors->data, vectors.vectors->len, g_variant_get_size (value), TRUE);
+ continue;
+ flattened = flatten_vectors (&vectors);
+ g_byte_array_free (vectors.extra_bytes, TRUE);
+ g_byte_array_free (vectors.offsets, TRUE);
+ g_array_free (vectors.vectors, TRUE);
+
+#if 0
+ if (flattened->len != g_variant_get_size (value) ||
+ memcmp (flattened->data, g_variant_get_data (value), flattened->len) != 0)
+ {
+ g_file_set_contents ("flattened", flattened->data, flattened->len, NULL);
+ g_file_set_contents ("serialised", g_variant_get_data (value), g_variant_get_size (value), NULL);
+ g_print ("type is %s\n", g_variant_get_type_string (value));
+ g_assert_not_reached ();
+ }
+#endif
+
+ g_assert_cmpint (flattened->len, ==, g_variant_get_size (value));
+ g_assert (memcmp (flattened->data, g_variant_get_data (value), flattened->len) == 0);
+
+ g_byte_array_free (flattened, TRUE);
+ g_variant_unref (value);
+ }
+}
+
static void
test_stack_builder_init (void)
{
g_test_add_func ("/gvariant/gbytes", test_gbytes);
g_test_add_func ("/gvariant/print-context", test_print_context);
g_test_add_func ("/gvariant/error-quark", test_error_quark);
+ g_test_add_func ("/gvariant/vector-serialiser", test_vector_serialiser);
g_test_add_func ("/gvariant/stack-builder-init", test_stack_builder_init);
g_test_add_func ("/gvariant/stack-dict-init", test_stack_dict_init);
# link programs against libgobject
progs_LDADD = ./libgobject-2.0.la $(libglib)
glib_genmarshal_LDADD = $(libglib)
+glib_genmarshal_LDFLAGS = -pie
gobject_query_LDADD = $(progs_LDADD)
+gobject_query_LDFLAGS = -pie
#
# auxillary files
AC_SUBST(installed_test_metadir, [${datadir}/installed-tests/]AC_PACKAGE_NAME)
AC_SUBST(installed_testdir, [${libexecdir}/installed-tests/]AC_PACKAGE_NAME)
fi
+ AC_ARG_ENABLE(force-dbus-tests,
+ AS_HELP_STRING([--enable-force-dbus-tests],
+ [Force including dbus tests even if dbus-daemon is not detected]),
+ [case ${enableval} in
+ yes) FORCE_DBUS_TESTS="1" ;;
+ no) FORCE_DBUS_TESTS="" ;;
+ *) AC_MSG_ERROR([bad value ${enableval} for --enable-force-dbus-tests]) ;;
+ esac])
])
--- /dev/null
+Quoting the "Vendor overrides" section from [1]:
+
+Default values are defined in the schemas that get installed by an application.
+Sometimes, it is necessary for a vendor or distributor to adjust these
+defaults. Since patching the XML source for the schema is inconvenient and
+error-prone, glib-compile-schemas reads so-called 'vendor override' files.
+These are keyfiles in the same directory as the XML schema sources which can
+override default values. The schema id serves as the group name in the key
+file, and the values are expected in serialized GVariant form, as in the
+following example:
+
+ [org.gtk.Example]
+ key1='string'
+ key2=1.5
+
+glib-compile-schemas expects schema files to have the extension
+.gschema.override
+
+[1] http://developer.gnome.org/gio/stable/GSettings.html
--- /dev/null
+glib2-tools
+ +/usr/bin/gio-querymodules(-64)?
+libglib
+ obsoletes "glib2-<targettype> <= <version>"
+ provides "glib2-<targettype> = <version>"
+libgmodule
+libgio
+libgthread
+libgobject
+libgio-fam
+ requires "glib2-tools-<targettype>"
+ post "%if "%_lib" == "lib64""
+ post "<prefix>%{_bindir}/gio-querymodules-64 <prefix>%{_libdir}/gio/modules"
+ post "%else"
+ post "<prefix>%{_bindir}/gio-querymodules <prefix>%{_libdir}/gio/modules"
+ post "%endif"
+ postun "%if "%_lib" == "lib64""
+ postun "<prefix>%{_bindir}/gio-querymodules-64 <prefix>%{_libdir}/gio/modules"
+ postun "%else"
+ postun "<prefix>%{_bindir}/gio-querymodules <prefix>%{_libdir}/gio/modules"
+ postun "%endif"
+
--- /dev/null
+How to analyze coverage:
+1. gbs build adding --define '_with_coverage 1'
+2. take *.o and *.gcno files from compilation (
+ <gbs-build-root>/home/abuild/rpmbuild/BUILD/glib2-2.44.1/gio/.libs
+ <gbs-build-root>/home/abuild/rpmbuild/BUILD/glib2-2.44.1/glib/.libs
+ <gbs-build-root>/home/abuild/rpmbuild/BUILD/glib2-2.44.1/gmodule/.libs
+ <gbs-build-root>/home/abuild/rpmbuild/BUILD/glib2-2.44.1/gobject/.libs
+ <gbs-build-root>/home/abuild/rpmbuild/BUILD/glib2-2.44.1/gthread/.libs
+ ) into a /safe/place
+ you may also use generated rpm package glib2-coverage-objects.
+3. install coverage package (glib2-coverage) on the target
+4. run test programs adding LD_LIBRARY_PATH=/usr/lib/dbus-tests/coverage-libs
+ Data gathering is cumulative, so you can run multiple programs one after another.
+ Use GCOV_PREFIX and GCOV_PREFIX_STRIP environment variables to set output directory.
+ If not set, data files (*.gcda) will be generated in /home/abuild/rpmbuild/BUILD/glib2-2.44.1/.
+5. download generated gcda files from the target to /safe/place
+6. put source code *.c files together with object files into a /safe/place
+7. run gcov /safe/place/*.o
+ or gcov -r /safe/place/*.o for only local source code output
--- /dev/null
+addFilter(".*shlib-fixed-dependency.*glib2")
+
--- /dev/null
+# GNOME Default Applications Source
+# /etc/gnome-defaults.conf
+#
+# WARNING: This is a dumb file, which provides only upstream GNOME
+# packages as preferred defaults. You most probably don't want this
+# package!
+# You probably want to install distribution glib2-branding and prefer
+# distribution wise GNOME defaults.
+#
+# After any change of this file run
+# SuSEconfig --module glib2
+#
+# This list is a source for defaults.list.
+#
+# If application in this list is installed, it is used as default in GNOME.
+# It works in following way:
+# 1. Read this file.
+# 2. Collect all available desktop files.
+# 3. Go through all declared MIME types and search for default application
+# for defaults.list in following order:
+# 3.1 Installed application listed here for certain MIME type.
+# 3.2 Installed application listed here as preferred default.
+# 3.3 Installed application listed here as default.
+# 3.4 Installed application with GNOME in Categories.
+# 3.5 Installed application with GTK in Categories.
+# 3.6 Installed application.
+# If there are more applications in the same order, it uses pseudo-randomly
+# one of them (last in aplhabetical order).
+#
+# Syntax:
+# Use xxx as default for all MIME types it declares (see 3.3):
+# xxx.desktop
+# Use xxx as preferred default for all MIME types it declares (see 3.2):
+# !xxx.desktop
+# Use xxx as default for mime/type (see 3.1):
+# mime/type=xxx.desktop
+
+# Upstream GNOME default applications
+eog.desktop
+evince.desktop
+gedit.desktop
+file-roller.desktop
+epiphany.desktop
+nautilus-folder-handler.desktop
+# evince supports multi-page tiff, but most people will prefer eog:
+image/tiff=eog.desktop
--- /dev/null
+* Tue Aug 13 2013 Anas Nashif <anas.nashif@intel.com> 2.36.3@0540f90
+- add .gbs.conf and update to 2.36.4
+
+* Tue Aug 13 2013 Anas Nashif <anas.nashif@intel.com> accepted/tizen/20130520.095512@84a55be
+- Remove empty docs package
+
+* Fri Jul 19 2013 Philippe Coval <philippe.coval@eurogiciel.fr> accepted/tizen/20130710.220535@5c863cc
+- gdesktopappinfo: Allow getting the desktop ID from the filename
+ Bug-Tizen: TZPC-3317 (... remove the fav apps icon ...)
+ Origin: upstream, https://git.gnome.org/browse/glib/commit/?id=c0af442909e1304b799a4b6c145f8444c752e3da
+- resetting manifest requested domain to floor
+- GSocks5Proxy: don't crash if parsing negotiation reply fails
+ Applied-upstream: 2.36.2, commit:0ba982e05
+ Bug: https://bugzilla.gnome.org/show_bug.cgi?id=699493
+ Bug-Tizen: TZPC-34 (Empathy / Telepathy - Proxy support)
+
+* Sat Apr 27 2013 Anas Nashif <anas.nashif@intel.com> 2.36.1@1b0d9ca
+- Update to 2.36.1
+
+* Wed Mar 27 2013 Anas Nashif <anas.nashif@intel.com> 2.36.0@3e8939c
+- Update to 2.36.0
+
+* Fri Mar 22 2013 Anas Nashif <anas.nashif@intel.com> 2.35.9@14fe501
+- Update to 2.35.9
+
+* Tue Mar 05 2013 Anas Nashif <anas.nashif@intel.com> 2.35.8@89b88e0
+- Remove previous crash fix (TZPC-453)
+
+* Tue Feb 26 2013 Anas Nashif <anas.nashif@intel.com> 2.35.8@8aed25e
+- Update to 2.35.8
+
+* Thu Feb 07 2013 Anas Nashif <anas.nashif@intel.com> 2.35.7@c7a2158
+- Update to 2.35.7
+
+* Thu Jan 31 2013 Anas Nashif <anas.nashif@intel.com> submit/trunk/20130131.165010@88f28c3
+- Update to 2.35.4
+
+* Thu Jan 03 2013 jbollo <jose.bollo@eurogiciel.fr> accepted/trunk/20121220.211950@7fcf93d
+- Avoiding SIGSEGV when running gio-querymodules
+
+* Tue Dec 18 2012 Anas Nashif <anas.nashif@intel.com> 2.35.3@28d76f3
+- update to 2.35.3
+
+* Sun Dec 09 2012 Anas Nashif <anas.nashif@intel.com> submit/devel/20121210.025910@9a11327
+- package license file
+- update to 2.35.2
+
--- /dev/null
+# GLib filename encoding guesser.
+# Author: Stanislav Brabec <sbrabec@suse.cz>
+# Additions are welcome.
+# This script must be executed after setting LANG variable.
+
+# Try filenames which are invalid in UTF-8 as locale specific.
+# For selected locales, G_FILENAME_ENCODING takes precedence.
+setenv G_BROKEN_FILENAMES 1
+
+# In West Europe there was used both ISO-8859-15 and ISO-8859-1.
+# There is no chance to recognize it, so we must guess.
+#set west_europe_legacy_encoding=ISO-8859-1
+set west_europe_legacy_encoding=ISO-8859-15
+
+# In Russia, "official" encoding is ISO-8859-5, but most GNOME users
+# preferred KOI8-R. We must guess.
+#set russian_legacy_encoding=ISO-8859-5
+set russian_legacy_encoding=KOI8-R
+
+# In former Yugoslavia sr_YU have covered two different alphabets -
+# one Latin and on Cyrillic. No chance to guess.
+set sr_YU_legacy_encoding=ISO-8859-2,CP1250
+#set sr_YU_legacy_encoding=ISO-8859-5
+
+# Japanese uses two legacy encodings. Guess sometimes fails, sometimes not.
+# Defining preferred encoding increases chance for success.
+set japanese_legacy_encoding=EUC-JP
+#set japanese_legacy_encoding=SHIFT_JIS
+
+if (! ${?LANG} ) goto skip
+
+switch ( $LANG )
+ case aa_DJ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case af_ZA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case an_ES*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-15,CP1252
+ breaksw
+ case ar_AE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_BH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_DZ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_EG*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_IQ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_JO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_KW*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_LB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_LY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_MA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_OM*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_QA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_SA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_SD*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_SY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_TN*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case ar_YE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-6
+ breaksw
+ case be_BY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,CP1251
+ breaksw
+ case bg_BG*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,CP1251
+ breaksw
+ case br_FR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case bs_BA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case ca_ES*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case cs_CZ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case cy_GB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-14,CP1252
+ breaksw
+ case da_DK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case de_AT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case de_BE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case de_DE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case de_CH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case de_LU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case el_GR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-7
+ breaksw
+ case en_AU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_BE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case en_BW*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_CA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_DK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_GB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case en_HK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_IE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case en_NZ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_PH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_SG*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_US*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case en_ZA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case en_ZW*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_AR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_BO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_CL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_CO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_CR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_DO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_EC*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_ES*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case es_GT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_HN*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_MX*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_NI*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_PA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_PE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_PR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_PY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_SV*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_US*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_UY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case es_VE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case et_EE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case eu_ES*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case fa_IR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,CP1256
+ breaksw
+ case fi_FI*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case fo_FO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case fr_BE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case fr_CA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case fr_FR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case fr_CH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case fr_LU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case ga_IE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case gd_GB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-15,CP1252
+ breaksw
+ case gl_ES*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case gv_GB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case he_IL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-8
+ breaksw
+ case hr_HR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case hu_HU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case hy_AM*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ARMSCII-8
+ breaksw
+ case id_ID*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case is_IS*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case it_CH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case it_IT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case iw_IL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-8
+ breaksw
+ case ja_JP*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$japanese_legacy_encoding,EUC-JP,SHIFT_JIS,ISO-8859-1
+ breaksw
+ case ka_GE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,GEORGIAN-PS
+ breaksw
+ case kl_GL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case km_KH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,GB18030
+ breaksw
+ case ko_KR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,EUC-KR,ISO-8859-1
+ breaksw
+ case kw_GB*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case lg_UG*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-10,CP1252
+ breaksw
+ case lt_LT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-13,CP1252
+ breaksw
+ case lv_LV*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-13,CP1252
+ breaksw
+ case mi_NZ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-13,CP1252
+ breaksw
+ case mk_MK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-5,CP1251
+ breaksw
+ case ms_MY*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case mt_MT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-3
+ breaksw
+ case nb_NO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case nl_BE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case nl_NL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case nn_NO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case no_NO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case oc_FR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case om_KE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case pl_PL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case pt_BR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case pt_PT*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case ro_RO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case ru_RU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$russian_legacy_encoding,CP1251
+ breaksw
+ case ru_UA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,KOI8-U
+ breaksw
+ case sh_YU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case sk_SK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case sl_SI*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-2,CP1250
+ breaksw
+ case so_DJ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case so_KE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case so_SO*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case sq_AL*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case sr_YU*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$sr_YU_legacy_encoding
+ breaksw
+ case st_ZA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case sv_FI*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case sv_SE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case tg_TJ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,KOI8-T
+ breaksw
+ case th_TH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,TIS-620,ISO-8859-1
+ breaksw
+ case tl_PH*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case tr_TR*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-9
+ breaksw
+ case uk_UA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,KOI8-U
+ breaksw
+ case uz_UZ*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case vi_VN*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,TCVN5712-1,ISO-8859-1
+ breaksw
+ case wa_BE*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ breaksw
+ case xh_ZA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+ case yi_US*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,CP1255
+ breaksw
+ case zh_CN*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,GB2312,GB18030,GBK,ISO-8859-1
+ breaksw
+ case zh_HK*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,BIG5-HKSCS,ISO-8859-1
+ breaksw
+ case zh_SG*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,GB2312,GB18030,GBK,ISO-8859-1
+ breaksw
+ case zh_TW*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,BIG5,EUC-TW,ISO-8859-1
+ breaksw
+ case zu_ZA*:
+ setenv G_FILENAME_ENCODING @locale,UTF-8,ISO-8859-1,CP1252
+ breaksw
+endsw
+
+skip:
+
+unset west_europe_legacy_encoding
+unset russian_legacy_encoding
+unset sr_YU_legacy_encoding
--- /dev/null
+<manifest>
+ <request>
+ <domain name="_"/>
+ </request>
+</manifest>
--- /dev/null
+# GLib filename encoding guesser.
+# Author: Stanislav Brabec <sbrabec@suse.cz>
+# Additions are welcome.
+# This script must be executed after setting LANG variable.
+
+# Try filenames which are invalid in UTF-8 as locale specific.
+# For selected locales, G_FILENAME_ENCODING takes precedence.
+export G_BROKEN_FILENAMES=1
+
+# In West Europe there was used both ISO-8859-15 and ISO-8859-1.
+# There is no chance to recognize it, so we must guess.
+#west_europe_legacy_encoding=ISO-8859-1
+west_europe_legacy_encoding=ISO-8859-15
+
+# In Russia, "official" encoding is ISO-8859-5, but most GNOME users
+# preferred KOI8-R. We must guess.
+#russian_legacy_encoding=ISO-8859-5
+russian_legacy_encoding=KOI8-R
+
+# In former Yugoslavia sr_YU have covered two different alphabets -
+# one Latin and on Cyrillic. No chance to guess.
+sr_YU_legacy_encoding=ISO-8859-2,CP1250
+#sr_YU_legacy_encoding=ISO-8859-5
+
+# Japanese uses two legacy encodings. Guess sometimes fails, sometimes not.
+# Defining preferred encoding increases chance for success.
+japanese_legacy_encoding=EUC-JP
+#japanese_legacy_encoding=SHIFT_JIS
+
+case $LANG in
+ aa_DJ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ af_ZA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ an_ES* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-15,CP1252
+ ;;
+ ar_AE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_BH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_DZ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_EG* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_IQ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_JO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_KW* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_LB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_LY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_MA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_OM* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_QA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_SA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_SD* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_SY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_TN* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ ar_YE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-6
+ ;;
+ be_BY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,CP1251
+ ;;
+ bg_BG* )
+ G_FILENAME_ENCODING=@locale,UTF-8,CP1251
+ ;;
+ br_FR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ bs_BA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ ca_ES* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ cs_CZ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ cy_GB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-14,CP1252
+ ;;
+ da_DK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ de_AT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ de_BE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ de_DE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ de_CH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ de_LU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ el_GR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-7
+ ;;
+ en_AU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_BE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ en_BW* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_CA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_DK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_GB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ en_HK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_IE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ en_NZ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_PH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_SG* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_US* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ en_ZA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ en_ZW* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_AR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_BO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_CL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_CO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_CR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_DO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_EC* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_ES* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ es_GT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_HN* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_MX* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_NI* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_PA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_PE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_PR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_PY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_SV* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_US* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_UY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ es_VE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ et_EE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ eu_ES* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ fa_IR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,CP1256
+ ;;
+ fi_FI* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ fo_FO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ fr_BE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ fr_CA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ fr_FR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ fr_CH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ fr_LU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ ga_IE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ gd_GB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-15,CP1252
+ ;;
+ gl_ES* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ gv_GB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ he_IL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-8
+ ;;
+ hr_HR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ hu_HU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ hy_AM* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ARMSCII-8
+ ;;
+ id_ID* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ is_IS* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ it_CH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ it_IT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ iw_IL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-8
+ ;;
+ ja_JP* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$japanese_legacy_encoding,EUC-JP,SHIFT_JIS,ISO-8859-1
+ ;;
+ ka_GE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,GEORGIAN-PS
+ ;;
+ kl_GL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ km_KH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,GB18030
+ ;;
+ ko_KR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,EUC-KR,ISO-8859-1
+ ;;
+ kw_GB* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ lg_UG* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-10,CP1252
+ ;;
+ lt_LT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-13,CP1252
+ ;;
+ lv_LV* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-13,CP1252
+ ;;
+ mi_NZ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-13,CP1252
+ ;;
+ mk_MK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-5,CP1251
+ ;;
+ ms_MY* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ mt_MT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-3
+ ;;
+ nb_NO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ nl_BE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ nl_NL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ nn_NO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ no_NO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ oc_FR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ om_KE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ pl_PL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ pt_BR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ pt_PT* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ ro_RO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ ru_RU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$russian_legacy_encoding,CP1251
+ ;;
+ ru_UA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,KOI8-U
+ ;;
+ sh_YU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ sk_SK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ sl_SI* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-2,CP1250
+ ;;
+ so_DJ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ so_KE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ so_SO* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ sq_AL* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ sr_YU* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$sr_YU_legacy_encoding
+ ;;
+ st_ZA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ sv_FI* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ sv_SE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ tg_TJ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,KOI8-T
+ ;;
+ th_TH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,TIS-620,ISO-8859-1
+ ;;
+ tl_PH* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ tr_TR* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-9
+ ;;
+ uk_UA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,KOI8-U
+ ;;
+ uz_UZ* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ vi_VN* )
+ G_FILENAME_ENCODING=@locale,UTF-8,TCVN5712-1,ISO-8859-1
+ ;;
+ wa_BE* )
+ G_FILENAME_ENCODING=@locale,UTF-8,$west_europe_legacy_encoding,CP1252
+ ;;
+ xh_ZA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+ yi_US* )
+ G_FILENAME_ENCODING=@locale,UTF-8,CP1255
+ ;;
+ zh_CN* )
+ G_FILENAME_ENCODING=@locale,UTF-8,GB2312,GB18030,GBK,ISO-8859-1
+ ;;
+ zh_HK* )
+ G_FILENAME_ENCODING=@locale,UTF-8,BIG5-HKSCS,ISO-8859-1
+ ;;
+ zh_SG* )
+ G_FILENAME_ENCODING=@locale,UTF-8,GB2312,GB18030,GBK,ISO-8859-1
+ ;;
+ zh_TW* )
+ G_FILENAME_ENCODING=@locale,UTF-8,BIG5,EUC-TW,ISO-8859-1
+ ;;
+ zu_ZA* )
+ G_FILENAME_ENCODING=@locale,UTF-8,ISO-8859-1,CP1252
+ ;;
+esac
+export G_FILENAME_ENCODING
+
+unset west_europe_legacy_encoding
+unset russian_legacy_encoding
+unset sr_YU_legacy_encoding
--- /dev/null
+# Do not create provides from extension .so files because the main package
+# should anchor any reverse-dependencies
+%global __provides_exclude_from ^(.*\\.extension-kdbus)$
+
+%bcond_with coverage
+%define baseline 2.52
+%define with_systemtap 0
+%define keepstatic 1
+
+Name: glib2
+Version: 2.52.2
+Release: 0
+# FIXME: find out if tapsets should really be in devel package or in main package
+Summary: General-Purpose Utility Library
+License: LGPL-2.0+
+Group: Base/Libraries
+Url: http://www.gtk.org/
+Source: http://download.gnome.org/sources/glib/%{baseline}/%{name}-%{version}.tar.xz
+Source1: glib2.sh
+Source2: glib2.csh
+Source3: test-runner.c
+# Not upstream file. Only proposes upstream packages:
+Source4: glib2-upstream-gnome_defaults.conf
+Source6: macros.glib2
+# Not depending on gtk-doc shortens bootstrap compilation path.
+# Please update this file from the latest gtk-doc package:
+Source7: gtk-doc.m4
+Source99: baselibs.conf
+Source1001: glib2.manifest
+BuildRequires: automake
+BuildRequires: fdupes
+BuildRequires: gcc-c++
+BuildRequires: pkg-config
+BuildRequires: python
+BuildRequires: gettext-tools
+# gdbus-codegen is run during the build, so we need python-xml
+BuildRequires: python-xml
+%if 0%{?with_systemtap}
+BuildRequires: systemtap-sdt-devel
+%endif
+# Needed for gresource
+BuildRequires: pkgconfig(libelf) >= 0.8.12
+BuildRequires: pkgconfig(libffi)
+BuildRequires: pkgconfig(libpcre) >= 8.13
+BuildRequires: pkgconfig(zlib)
+# Enable support for libdbuspolicy (only for kdbus transport)
+BuildRequires: pkgconfig(libdbuspolicy1)
+
+%description
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+%package tools
+Summary: General-Purpose Utility Library -- Tools
+
+%description tools
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+%package -n gio-branding-upstream
+Summary: Upstream definitions of default settings and applications
+Requires: libgio = %{version}
+Provides: %{name}-branding-upstream = %{version}
+Obsoletes: %{name}-branding-upstream < %{version}
+Provides: gio-branding = %{version}
+Conflicts: otherproviders(gio-branding)
+Supplements: packageand(libgio:branding-upstream)
+BuildArch: noarch
+#BRAND: The /etc/gnome_defaults.conf allows to define arbitrary
+#BRAND: applications as preferred defaults.
+#BRAND: A /usr/share/glib-2.0/schemas/$NAME.gschema.override file can
+#BRAND: be used to override the default value for GSettings keys. See
+#BRAND: README.Gsettings-overrides for more details. The branding
+#BRAND: package should then have proper Requires for features changed
+#BRAND: with such an override file.
+# NOTE: gnome_defaults is not an upstream feature, but a SuSE
+# enhancement, but to conform branding conventions, the package is named
+# as gio-branding-upstream.
+
+%description -n gio-branding-upstream
+This package provides upstream defaults for settings stored with
+GSettings and applications used by the MIME system.
+
+%package devel
+#'
+Requires: %{name} = %{version}
+Requires: glibc-devel
+Requires: pkg-config
+# Now require the subpackages too
+Requires: glib2-tools = %{version}
+Requires: libgio = %{version}
+Requires: libglib = %{version}
+Requires: libgmodule = %{version}
+Requires: libgobject = %{version}
+Requires: libgthread = %{version}
+# Required by gdbus-codegen
+Requires: python-xml
+Provides: glib2-doc = 2.19.6
+Obsoletes: glib2-doc < 2.19.6
+Summary: General-Purpose Utility Library -- Development Files
+
+%description devel
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+This package contains the development files for GLib.
+
+%package devel-static
+Requires: %{name}-devel = %{version}
+Summary: General-Purpose Utility Library -- Static Libraries
+
+%description devel-static
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+This package contains static versions of the GLib libraries.
+
+%package -n libglib
+Summary: General-Purpose Utility Library
+Provides: %{name} = %{version}
+Obsoletes: %{name} < %{version}
+
+%description -n libglib
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+%package -n libgmodule
+Summary: General-Purpose Utility Library -- Library for Modules
+
+%description -n libgmodule
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+The libgmodule library provides a portable way to dynamically load
+object files (commonly known as 'plug-ins').
+
+%package -n libgio
+Summary: General-Purpose Utility Library -- Library for VFS
+Requires: gio-branding = %{version}
+# bnc#555605: shared-mime-info is required by libgio to properly detect mime types.
+Requires: shared-mime-info
+# bnc#678518: libgio interacts with others by means of dbus-launch
+#Requires: dbus-1-x11
+Provides: gio = %{version}
+
+%description -n libgio
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+GIO provides a modern, easy-to-use VFS API.
+
+%package -n libgio-extension-kdbus
+Summary: Extension for libgio to support KDBUS in Tizen
+Requires: libgio = %{version}-%{release}
+
+%description -n libgio-extension-kdbus
+This modifies libgio to support KDBUS in Tizen.
+
+
+%package -n libgthread
+Summary: General-Purpose Utility Library -- Library for Threads
+
+%description -n libgthread
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+The libgthread library provides a portable way to write multi-threaded
+software.
+
+%package -n libgobject
+Summary: General-Purpose Utility Library -- Object-Oriented Framework for C
+
+%description -n libgobject
+GLib is a general-purpose utility library, which provides many useful
+data types, macros, type conversions, string utilities, file utilities,
+a main loop abstraction, and so on.
+
+The GObject library provides an object-oriented framework for C.
+
+%package tests
+License: LGPL-2.0+ and Apache-2.0
+Summary: Set of tests for gdbus component
+Requires: %{name} = %{version}
+
+%description tests
+This package is part of 'dbus-integration-tests' framework and contains set of tests
+for gdbus component.
+
+%if %{with coverage}
+%package coverage
+Summary: Special version of glib libraries for getting coverage analysis
+
+%description coverage
+Special version of glib libraries for getting coverage analysis. *.gcda coverage files
+are generated on each use of library in directory set by GCOV_PREFIX and GCOV_PREFIX_STRIP.
+Use the library by modifying LD_LIBRARY_PATH.
+This package is intended for debug/test use only.
+
+%package coverage-objects
+Summary: Generated object files and gcov notes for coverage analysis
+
+%description coverage-objects
+Objects and gcno files to analyze coverage.
+This package is intended for debug/test use only.
+%endif
+
+%prep
+%setup -q -n %{name}-%{version}
+
+%build
+cp %{SOURCE3} .
+cp %{SOURCE1001} .
+cp -a %{S:1} %{S:2} .
+cp -a %{S:4} gnome_defaults.conf
+if ! test -f %{_datadir}/aclocal/gtk-doc.m4 ; then
+ cp -a %{S:7} m4macros/
+fi
+NOAUTORECONF=1 NOCONFIGURE=1 ./autogen.sh
+export CFLAGS+=" -D_TIZEN_DBUS_TOUCH"
+%ifarch %{arm}
+export CFLAGS=${CFLAGS/-Wa,-mimplicit-it=thumb/}" -marm"
+%endif
+
+export CFLAGS="${CFLAGS} -fPIC"
+export LDFLAGS="${LDFLAGS}"
+
+# Create kdbus extension first (libgio)
+%reconfigure \
+ --enable-static \
+%if 0%{?with_systemtap}
+ --enable-systemtap \
+%endif
+ --enable-libdbuspolicy \
+ --enable-always-build-tests \
+ --enable-installed-tests \
+ --enable-force-dbus-tests \
+%if %{with coverage}
+ --disable-gcov-coverage \
+%endif
+ --with-pcre=system \
+ --enable-libmount=no
+
+%{__make} %{?_smp_mflags} V=1
+
+mkdir -p extension-kdbus
+pushd gio/.libs/
+# rm if symlink. mv if regular file.
+for FILE in libgio-*.so*; do test -h "$FILE" && rm "$FILE" || mv "$FILE" ../../extension-kdbus/ ; done
+popd
+
+%{__make} clean
+
+
+
+# Support for generating separate packages with libraries generating coverage files
+# WARNING: if coverage build is enabled, incremental builds will not work correctly.
+# Use the option only to generate glib2-coverage packages.
+%if %{with coverage}
+%reconfigure \
+ --disable-static \
+ --enable-libdbuspolicy \
+ --with-pcre=system \
+ --enable-libmount=no \
+ --enable-gcov-coverage
+
+%{__make} %{?_smp_mflags} V=1
+
+mkdir -p coverage
+mv gio/.libs/libgio-2.0.so* glib/.libs/libglib-2.0.so* gthread/.libs/libgthread-2.0.so* gobject/.libs/libgobject-2.0.so* gmodule/.libs/libgmodule-2.0.so* coverage
+mkdir -p coverage-objects
+find g* -name '*.o' -exec mv '{}' coverage-objects ';'
+find g* -name '*.gcno' -exec mv '{}' coverage-objects ';'
+
+%{__make} clean
+%endif
+
+%reconfigure \
+ --enable-static \
+%if 0%{?with_systemtap}
+ --enable-systemtap \
+%endif
+ --enable-always-build-tests \
+ --enable-installed-tests \
+ --enable-force-dbus-tests \
+%if %{with coverage}
+ --disable-gcov-coverage \
+%endif
+ --with-pcre=system \
+ --enable-libmount=no
+
+%{__make} %{?_smp_mflags} V=1
+
+# compile test-runner for 'dbus-integration-test' framework
+%__cc %{_builddir}/%{name}-%{version}/test-runner.c -fPIC -pie -o %{_builddir}/%{name}-%{version}/glib-tests
+
+%install
+%make_install
+%find_lang glib20 %{?no_lang_C}
+
+# kdbus extension
+pushd extension-kdbus
+for FILE in *; do mv "$FILE" "%{buildroot}%{_libdir}/$FILE.extension-kdbus"; done
+popd
+
+mkdir -p %{buildroot}%{_sysconfdir}/profile.d
+install -D -m0644 glib2.sh %{buildroot}%{_sysconfdir}/profile.d/zzz-glib2.sh
+install -D -m0644 glib2.csh %{buildroot}%{_sysconfdir}/profile.d/zzz-glib2.csh
+install -D -m0644 gnome_defaults.conf %{buildroot}%{_sysconfdir}/gnome_defaults.conf
+# default apps magic
+mkdir -p %{buildroot}%{_localstatedir}/cache/gio-2.0 %{buildroot}%{_datadir}/applications
+touch %{buildroot}%{_localstatedir}/cache/gio-2.0/gnome-defaults.list
+touch %{buildroot}%{_localstatedir}/cache/gio-2.0/xfce-defaults.list
+touch %{buildroot}%{_localstatedir}/cache/gio-2.0/lxde-defaults.list
+ln -s %{_localstatedir}/cache/gio-2.0/gnome-defaults.list %{buildroot}%{_datadir}/applications/defaults.list
+# gio-querymodules magic
+%if "%{_lib}" == "lib64"
+mv %{buildroot}%{_bindir}/gio-querymodules %{buildroot}%{_bindir}/gio-querymodules-64
+%endif
+touch %{buildroot}%{_libdir}/gio/modules/giomodule.cache
+# gsettings magic
+touch %{buildroot}%{_datadir}/glib-2.0/schemas/gschemas.compiled
+# remove files we don't care about
+find %{buildroot}%{_libdir} -name '*.la' -type f -delete -print
+
+# prepare tests for 'dbus-integration-test' framework
+%define relative_dbus_tests_base_dir %{_prefix}/lib/dbus-tests
+%define dbus_tests_base_dir %{buildroot}%{relative_dbus_tests_base_dir}
+
+install -D -m 755 %{_builddir}/%{name}-%{version}/glib-tests %{dbus_tests_base_dir}/runner/glib-tests
+mkdir -p %{dbus_tests_base_dir}/test-suites/glib-tests/
+mv %{buildroot}%{_prefix}/libexec/installed-tests/glib/*gdbus-* %{dbus_tests_base_dir}/test-suites/glib-tests/
+# workaround for UNIX fd passing test (gdbus-peer)
+echo "Testfile - check for UNIX fd passing" > %{dbus_tests_base_dir}/test-suites/glib-tests/file.c
+rm %{dbus_tests_base_dir}/test-suites/glib-tests/gdbus-testserver
+rm -Rf %{buildroot}%{_prefix}/libexec/installed-tests/glib/
+rm -Rf %{buildroot}%{_prefix}/share/installed-tests/glib/
+
+# Install rpm macros
+mkdir -p %{buildroot}%{_sysconfdir}/rpm
+cp %{S:6} %{buildroot}%{_sysconfdir}/rpm
+%fdupes %{buildroot}
+
+# install libraries with coverage analysis enabled
+%if %{with coverage}
+%define relative_cov_lib_dir %{relative_dbus_tests_base_dir}/coverage-libs
+%define cov_lib_dir %{buildroot}%{relative_cov_lib_dir}
+
+mkdir -p %{cov_lib_dir}
+mkdir -p %{cov_lib_dir}/objects
+install -m 0755 coverage/*.so* %{cov_lib_dir}
+install -m 0644 coverage-objects/* %{cov_lib_dir}/objects
+%endif
+
+%post -n libglib -p /sbin/ldconfig
+
+%post -n libgobject -p /sbin/ldconfig
+
+%post -n libgthread -p /sbin/ldconfig
+
+%post -n libgio -p /sbin/ldconfig
+
+%post -n libgmodule -p /sbin/ldconfig
+
+%postun -n libglib -p /sbin/ldconfig
+
+%postun -n libgobject -p /sbin/ldconfig
+
+%postun -n libgthread -p /sbin/ldconfig
+
+%postun -n libgio -p /sbin/ldconfig
+
+%postun -n libgmodule -p /sbin/ldconfig
+
+
+%files tools
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%dir %{_datadir}/bash-completion
+%dir %{_datadir}/bash-completion/completions
+%{_datadir}/bash-completion/completions/gresource
+%{_datadir}/bash-completion/completions/gsettings
+%{_bindir}/gdbus
+%{_bindir}/gio-querymodules*
+%{_bindir}/glib-compile-schemas
+%{_bindir}/gresource
+%{_bindir}/gsettings
+%{_bindir}/gapplication
+%{_bindir}/gio
+# We put those files here, but they don't really belong here. They just don't
+# have a better home... The zzz-glib2 scripts could arguably be in
+# libglib but that would break the shared library policy.
+%{_sysconfdir}/profile.d/zzz-glib2.*
+
+%files -n gio-branding-upstream
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%config (noreplace) %{_sysconfdir}/gnome_defaults.conf
+
+%files -n libglib
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%license COPYING
+%{_libdir}/libglib*.so.*
+
+%files -n libgmodule
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%license COPYING
+%{_libdir}/libgmodule*.so.*
+
+%files -n libgobject
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%license COPYING
+%{_libdir}/libgobject*.so.*
+
+%files -n libgthread
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%license COPYING
+%{_libdir}/libgthread*.so.*
+
+%files -n libgio
+%manifest %{name}.manifest
+%defattr(-, root, root)
+%license COPYING
+%exclude %{_libdir}/libgio*.so.*.extension-kdbus
+%{_libdir}/libgio*.so.*
+%dir %{_libdir}/gio
+%dir %{_libdir}/gio/modules
+%ghost %{_libdir}/gio/modules/giomodule.cache
+%dir %{_datadir}/glib-2.0/
+%dir %{_datadir}/glib-2.0/schemas/
+%ghost %{_datadir}/glib-2.0/schemas/gschemas.compiled
+%{_datadir}/applications/defaults.list
+%dir %{_localstatedir}/cache/gio-2.0
+%ghost %{_localstatedir}/cache/gio-2.0/gnome-defaults.list
+%ghost %{_localstatedir}/cache/gio-2.0/xfce-defaults.list
+%ghost %{_localstatedir}/cache/gio-2.0/lxde-defaults.list
+
+
+%lang_package -f glib20
+
+%post -n libgio-extension-kdbus
+pushd %{_libdir}
+for FILE in libgio*.so.*.extension-kdbus; do mv "$FILE" "${FILE%.extension-kdbus}"; done
+popd
+%files -n libgio-extension-kdbus
+%manifest %{name}.manifest
+%license COPYING
+%{_libdir}/libgio*.so.*.extension-kdbus
+
+
+%files devel
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+
+%{_bindir}/gdbus-codegen
+%{_datadir}/bash-completion/completions/*
+%_datadir/glib-2.0/codegen
+
+%{_bindir}/glib-compile-resources
+%{_bindir}/glib-genmarshal
+%{_bindir}/glib-gettextize
+%{_bindir}/glib-mkenums
+%{_bindir}/gobject-query
+%{_bindir}/gtester
+%{_bindir}/gtester-report
+%dir %{_datadir}/aclocal
+%{_datadir}/aclocal/glib-2.0.m4
+%{_datadir}/aclocal/glib-gettext.m4
+%{_datadir}/aclocal/gsettings.m4
+%dir %{_datadir}/glib-2.0/
+%{_datadir}/glib-2.0/gdb/
+%{_datadir}/glib-2.0/gettext/
+%{_datadir}/glib-2.0/schemas/gschema.dtd
+%{_datadir}/glib-2.0/valgrind/glib.supp
+%{_includedir}/glib-2.0
+%{_includedir}/gio-unix-2.0
+%{_libdir}/lib*.so
+%dir %{_libdir}/glib-2.0/
+%{_libdir}/glib-2.0/include/
+%{_libdir}/pkgconfig/*.pc
+%{_datadir}/gdb/auto-load/%{_libdir}/*-gdb.py
+%{_datadir}/gettext/its/gschema.*
+%if 0%{?with_systemtap}
+%{_datadir}/systemtap/tapset/*.stp
+%endif
+%{_sysconfdir}/rpm/macros.glib2
+# Own these directories to not depend on gdb
+%dir %{_datadir}/gdb
+%dir %{_datadir}/gdb/auto-load
+%dir %{_datadir}/gdb/auto-load%{_prefix}
+%dir %{_datadir}/gdb/auto-load%{_libdir}
+
+%files devel-static
+%manifest %{name}.manifest
+%defattr(-,root,root)
+%license COPYING
+%{_libdir}/lib*.a
+
+%files tests
+%manifest %{name}.manifest
+%license COPYING
+%{relative_dbus_tests_base_dir}/test-suites/glib-tests/
+%{relative_dbus_tests_base_dir}/runner/glib-tests
+
+%if %{with coverage}
+%files coverage
+%license COPYING
+%{relative_cov_lib_dir}/*.so*
+
+%files coverage-objects
+%license COPYING
+%{relative_cov_lib_dir}/objects/*
+%endif
+
+%changelog
--- /dev/null
+dnl -*- mode: autoconf -*-
+
+# serial 1
+
+dnl Usage:
+dnl GTK_DOC_CHECK([minimum-gtk-doc-version])
+AC_DEFUN([GTK_DOC_CHECK],
+[
+ AC_REQUIRE([PKG_PROG_PKG_CONFIG])
+ AC_BEFORE([AC_PROG_LIBTOOL],[$0])dnl setup libtool first
+ AC_BEFORE([AM_PROG_LIBTOOL],[$0])dnl setup libtool first
+
+ dnl check for tools we added during development
+ AC_PATH_PROG([GTKDOC_CHECK],[gtkdoc-check])
+ AC_PATH_PROGS([GTKDOC_REBASE],[gtkdoc-rebase],[true])
+ AC_PATH_PROG([GTKDOC_MKPDF],[gtkdoc-mkpdf])
+
+ dnl for overriding the documentation installation directory
+ AC_ARG_WITH([html-dir],
+ AS_HELP_STRING([--with-html-dir=PATH], [path to installed docs]),,
+ [with_html_dir='${datadir}/gtk-doc/html'])
+ HTML_DIR="$with_html_dir"
+ AC_SUBST([HTML_DIR])
+
+ dnl enable/disable documentation building
+ AC_ARG_ENABLE([gtk-doc],
+ AS_HELP_STRING([--enable-gtk-doc],
+ [use gtk-doc to build documentation [[default=no]]]),,
+ [enable_gtk_doc=no])
+
+ if test x$enable_gtk_doc = xyes; then
+ ifelse([$1],[],
+ [PKG_CHECK_EXISTS([gtk-doc],,
+ AC_MSG_ERROR([gtk-doc not installed and --enable-gtk-doc requested]))],
+ [PKG_CHECK_EXISTS([gtk-doc >= $1],,
+ AC_MSG_ERROR([You need to have gtk-doc >= $1 installed to build $PACKAGE_NAME]))])
+ dnl don't check for glib if we build glib
+ if test "x$PACKAGE_NAME" != "xglib"; then
+ dnl don't fail if someone does not have glib
+ PKG_CHECK_MODULES(GTKDOC_DEPS, glib-2.0 >= 2.10.0 gobject-2.0 >= 2.10.0,,)
+ fi
+ fi
+
+ AC_MSG_CHECKING([whether to build gtk-doc documentation])
+ AC_MSG_RESULT($enable_gtk_doc)
+
+ dnl enable/disable output formats
+ AC_ARG_ENABLE([gtk-doc-html],
+ AS_HELP_STRING([--enable-gtk-doc-html],
+ [build documentation in html format [[default=yes]]]),,
+ [enable_gtk_doc_html=yes])
+ AC_ARG_ENABLE([gtk-doc-pdf],
+ AS_HELP_STRING([--enable-gtk-doc-pdf],
+ [build documentation in pdf format [[default=no]]]),,
+ [enable_gtk_doc_pdf=no])
+
+ if test -z "$GTKDOC_MKPDF"; then
+ enable_gtk_doc_pdf=no
+ fi
+
+
+ AM_CONDITIONAL([ENABLE_GTK_DOC], [test x$enable_gtk_doc = xyes])
+ AM_CONDITIONAL([GTK_DOC_BUILD_HTML], [test x$enable_gtk_doc_html = xyes])
+ AM_CONDITIONAL([GTK_DOC_BUILD_PDF], [test x$enable_gtk_doc_pdf = xyes])
+ AM_CONDITIONAL([GTK_DOC_USE_LIBTOOL], [test -n "$LIBTOOL"])
+ AM_CONDITIONAL([GTK_DOC_USE_REBASE], [test -n "$GTKDOC_REBASE"])
+])
--- /dev/null
+# RPM macros for packages installing a GSettings schema or GIO module
+#
+###
+#
+# When a package installs a GSettings schemas, it should use all
+# three macros:
+#
+# - %glib2_gsettings_schema_requires in the preamble
+# - %glib2_gsettings_schema_post in %post
+# - %glib2_gsettings_schema_postun in %postun
+#
+###
+#
+# When a package installs a GIO module, it should use all
+# three macros:
+#
+# - %glib2_gio_module_requires in the preamble
+# - %glib2_gio_module_post in %post
+# - %glib2_gio_module_postun in %postun
+#
+# Note that %glib2_gio_module_post and %glib2_gio_module_postun can
+# optionally take the path to the directory where modules live. This
+# is useful for applications using the GIO module system on their own,
+# since they will install modules in their own directory. If no
+# argument is passed, the path for the modules for GIO itself is used.
+#
+###
+
+%glib2_gsettings_schema_requires \
+Requires(post): glib2-tools \
+Requires(postun): glib2-tools
+
+%glib2_gsettings_schema_post \
+%{_bindir}/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || :
+
+# Note: we ignore upgrades (already handled in %post of the new package).
+%glib2_gsettings_schema_postun \
+if [ $1 -eq 0 ]; then \
+ %{_bindir}/glib-compile-schemas %{_datadir}/glib-2.0/schemas &> /dev/null || : \
+fi
+
+%glib2_gio_module_requires \
+Requires(post): glib2-tools \
+Requires(postun): glib2-tools
+
+# On install, update the cache
+%glib2_gio_module_post() \
+%if "x%1" != "x%%1" \
+ GIO_MODULES_DIR="%1" \
+%else \
+ GIO_MODULES_DIR="%{_libdir}/gio/modules" \
+%endif \
+%if "%{_lib}" == "lib64" \
+ %{_bindir}/gio-querymodules-64 "${GIO_MODULES_DIR}" \
+%else \
+ %{_bindir}/gio-querymodules "${GIO_MODULES_DIR}" \
+%endif
+
+# On uninstall, update the cache. Note: we ignore upgrades (already
+# handled in %post of the new package).
+%glib2_gio_module_postun() \
+if [ $1 -eq 0 ]; then \
+ %if "x%1" != "x%%1" \
+ GIO_MODULES_DIR="%1" \
+ %else \
+ GIO_MODULES_DIR="%{_libdir}/gio/modules" \
+ %endif \
+ %if "%_lib" == "lib64" \
+ %{_bindir}/gio-querymodules-64 "${GIO_MODULES_DIR}" \
+ %else \
+ %{_bindir}/gio-querymodules "${GIO_MODULES_DIR}" \
+ %endif \
+fi
--- /dev/null
+/*
+ * This file contains standalone test-runner.
+ * This file is NOT part of GLib project.
+ *
+ * Copyright (c) 2016 Samsung Electronics Co., Ltd All Rights Reserved
+ * Author: Kazimierz Krosman <k.krosman@samsung.com>
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/select.h>
+#include <sys/time.h>
+#include <ctype.h>
+#include <time.h>
+#include <sys/select.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <assert.h>
+#include <stdbool.h>
+
+#define MAX_TC_NUM 1024
+#define MAX_BUFFER (64*1024)
+#define MAX_COMMENT 1024
+
+enum {
+ INIT_TEST,
+ NEW_STDOUT,
+ NEW_STDERR,
+ RESULT_CODE,
+ RESULT_SIGNAL,
+ RESULT_ERROR,
+ RESULT_TIMEOUT
+};
+
+struct test_result {
+ bool is_positive;
+ char comment[MAX_COMMENT];
+ char result[MAX_COMMENT];
+ char name[MAX_COMMENT];
+};
+
+struct test_case {
+ const char* name;
+ const char* description;
+};
+
+struct binary {
+ const char* path;
+ const char* name;
+ struct test_case* test_cases;
+ int timeout;
+
+ char** (*prepare_args) (const struct binary* b, const char* test_name);
+ void (*parse) (const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
+ int (*init)(void);
+ int (*clean)(void);
+};
+
+char* get_test_id(char* dest, const struct binary* b, const char* test_name);
+void add_test_result(const char* test_id, const char* result, const char* comment, int res);
+
+enum {
+ PIPE_READ,
+ PIPE_WRITE,
+};
+
+void parse_test_state(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
+void parse_one_test_one_binary(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option);
+char** prepare_args_for_binary(const struct binary* b, const char* test_name);
+
+static struct test_case test_case_desc_01[] = {
+ {"", "Checks if the library supports format of addresses described in the D-Bus specification (key/value pairs for each transport are valid)"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_02[] = {
+ {"", "Test case for GNOME #662395"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_03[] = {
+ {"", "Test flushing connection with g_dbus_connection_flush_sync() function"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_04[] = {
+ {"", "Test 'lock' and 'copy' operations on GDBusMessage object"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_05[] = {
+ {"", "Test 'non-socket' connections (connection via pipes and GIOStreams objects)"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_06[] = {
+ {"", "Test overflowing socket buffer in producer/consumer scenario (UNIX sockets as a transport mechanism)"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_07[] = {
+ {"", "Test that peer-to-peer connections work"},
+ {NULL, NULL}
+};
+
+static struct test_case test_case_desc_08[] = {
+ {"", "Test that peer-to-peer connections work (using GDBusObjectManagerServer and GDBusObjectManager objects)"},
+ {NULL, NULL}
+};
+
+/* This table is used to start binaries */
+struct binary tests[] = {
+ /*path, name, TC_table, timeout in us, prepare_args_handler, parse_function_handler, init_handler, clean_handler*/
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-addresses", "gdbus-addresses", test_case_desc_01, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-connection-flush", "gdbus-connection-flush", test_case_desc_02, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-connection-flush-helper", "gdbus-connection-flush-helper", test_case_desc_03, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-message", "gdbus-message", test_case_desc_04, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-non-socket", "gdbus-non-socket", test_case_desc_05, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-overflow", "gdbus-overflow", test_case_desc_06, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-peer", "gdbus-peer", test_case_desc_07, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+ {"/usr/lib/dbus-tests/test-suites/glib-tests/gdbus-peer-object-manager", "gdbus-peer-object-manager", test_case_desc_08, 5000*1000, prepare_args_for_binary, parse_one_test_one_binary, NULL, NULL},
+};
+
+static char* args[3];
+char** prepare_args_for_binary(const struct binary* b, const char* test_name)
+{
+ args[0] = (char*)b->name;
+ args[1] = NULL;
+ return args;
+}
+
+void parse_one_test_one_binary(const struct binary* b, const char* test_name, char* buffer, int state_change, int state_option)
+{
+ char test_id[MAX_COMMENT];
+
+ switch(state_change) {
+ case INIT_TEST:
+ break;
+ case NEW_STDOUT:
+ buffer[state_option] = 0;
+ get_test_id(test_id, b, test_name);
+ fprintf(stderr, "[stdout][%s]%s\n",test_id, buffer);
+ break;
+ case NEW_STDERR:
+ buffer[state_option] = 0;
+ get_test_id(test_id, b, test_name);
+ fprintf(stderr, "[stderr][%s]%s\n",test_id, buffer);
+ break;
+ case RESULT_CODE:
+ get_test_id(test_id, b, test_name);
+ if (state_option == 0)
+ add_test_result(test_id, "PASS", "", 1);
+ else if (state_option == 77)
+ add_test_result(test_id, "SKIP", "", 0);
+ else
+ add_test_result(test_id, "FAIL", "", 0);
+ break;
+ case RESULT_SIGNAL:
+ get_test_id(test_id, b, test_name);
+ add_test_result(test_id, "FAIL", "Finished by SIGNAL", 0);
+ break;
+ case RESULT_TIMEOUT:
+ get_test_id(test_id, b, test_name);
+ add_test_result(test_id, "FAIL", "Test TIMEOUT", 0);
+ break;
+ }
+}
+
+static struct option long_options[] = {
+ {"list", no_argument, 0, 'l'},
+ {"run", required_argument, 0, 'r'},
+ {"description", required_argument, 0, 'd'},
+ {0, 0, 0, 0 }
+};
+
+static int stdin_pipe[2];
+static int stdout_pipe[2];
+static int stderr_pipe[2];
+static int gravedigger_pipe[2];
+static char buffer[MAX_BUFFER];
+static const char* requested_tc[MAX_TC_NUM];
+
+char* get_test_id(char* dest, const struct binary* b, const char* test_name)
+{
+ int len = strlen(b->name);
+ memcpy(dest, b->name, len);
+ memcpy(dest + len, test_name, strlen(test_name)+1);
+ return dest;
+}
+
+static void print_description(const char* name, const char* description)
+{
+ printf("%s;%s\n",name, description);
+}
+
+static void print_list(const char* test_name)
+{
+ unsigned int i;
+ char full_name[MAX_COMMENT];
+ for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
+ int j = 0;
+ int l = strlen(tests[i].name);
+ memcpy(full_name, tests[i].name, l+1);
+ if (test_name && strncmp(test_name, full_name, l) != 0)
+ continue;
+
+ while (tests[i].test_cases[j].name) {
+ memcpy(full_name + l, tests[i].test_cases[j].name, strlen(tests[i].test_cases[j].name) + 1);
+ if (!test_name || strncmp(full_name, test_name, sizeof(full_name)) == 0)
+ print_description(full_name,tests[i].test_cases[j].description);
+ j++;
+ }
+ }
+}
+
+
+static void stop_binary(const struct binary* b, pid_t pid, const char* test_name, int w_res)
+{
+ int status = 0;
+ int res = 0;
+ if (w_res == 0)
+ res = waitpid(pid, &status, WNOHANG);
+ else
+ res = waitpid(pid, &status, 0);
+
+ if (res == 0) {
+ //timeouted
+ kill(pid, SIGKILL);
+ res = waitpid(pid, &status, WNOHANG);
+ b->parse(b, test_name, buffer, RESULT_TIMEOUT, res);
+ } else if (res < 0) {
+ //errno check
+ kill(pid, SIGKILL);
+ res = waitpid(pid, &status, WNOHANG);
+ b->parse(b, test_name, buffer, RESULT_ERROR, res);
+ } else if (res > 0) {
+ if (WIFEXITED(status)) {
+ b->parse(b, test_name, buffer, RESULT_CODE, WEXITSTATUS(status));
+ } else if (WIFSIGNALED(status)) {
+ b->parse(b, test_name, buffer, RESULT_SIGNAL, WTERMSIG(status));
+ } else if (WIFSTOPPED(status)) {
+ b->parse(b, test_name, buffer, RESULT_SIGNAL, WSTOPSIG(status));
+ } else if (WIFCONTINUED(status)) {
+ kill(pid, SIGKILL);
+ b->parse(b, test_name, buffer, RESULT_SIGNAL, -1);
+ }
+ }
+}
+
+static void parse_output_with_timeout(const struct binary* b, pid_t pid, const char* test_name)
+{
+ struct timeval tv;
+ fd_set rfds;
+ int nfds;
+ int res;
+ int w_res = 0;
+ tv.tv_sec = b->timeout/(1000*1000);
+ tv.tv_usec = (b->timeout-tv.tv_sec*1000*1000);
+ while (1) {
+ FD_ZERO(&rfds);
+ if (stdout_pipe[PIPE_READ] > -1) {
+ assert(stdout_pipe[PIPE_READ] > -1);
+ assert(stdout_pipe[PIPE_READ] < 1024);
+ FD_SET(stdout_pipe[PIPE_READ], &rfds);
+ }
+ if (stderr_pipe[PIPE_READ] > -1) {
+ assert(stderr_pipe[PIPE_READ] > -1);
+ assert(stderr_pipe[PIPE_READ] < 1024);
+ FD_SET(stderr_pipe[PIPE_READ], &rfds);
+ }
+ FD_SET(gravedigger_pipe[PIPE_READ], &rfds);
+
+ nfds = select(FD_SETSIZE, &rfds, NULL, NULL, &tv);
+ if (nfds == -1) {
+ if (errno != EINTR) {
+ w_res = 0;
+ break;
+ }
+ } else if (nfds > 0) {
+ if (stdout_pipe[PIPE_READ] > -1 && FD_ISSET(stdout_pipe[PIPE_READ], &rfds)) {
+ res = read(stdout_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
+ if (res == 0 || (res < 0 && errno != EINTR)) {
+ close (stdout_pipe[PIPE_READ]);
+ stdout_pipe[PIPE_READ] = -1;
+ continue;
+ } else if (res >=0) {
+ b->parse(b, test_name, buffer, NEW_STDOUT, res);
+ }
+ }
+
+ if (stderr_pipe[PIPE_READ] > -1 && FD_ISSET(stderr_pipe[PIPE_READ], &rfds)) {
+ res = read(stderr_pipe[PIPE_READ], buffer, MAX_BUFFER-1);
+ if (res == 0 || (res < 0 && errno != EINTR)) {
+ close (stderr_pipe[PIPE_READ]);
+ stderr_pipe[PIPE_READ] = -1;
+ continue;
+ }
+ b->parse(b, test_name, buffer, NEW_STDERR, res);
+ }
+
+ if (FD_ISSET(gravedigger_pipe[PIPE_READ], &rfds)) {
+ w_res = 1;
+ break; //it has ended
+ }
+ } else {
+ //timeout
+ w_res = 0;
+ break;
+ }
+ }
+ stop_binary(b, pid, test_name, w_res);
+}
+
+static int create_child(const char* path, char* const arguments[])
+{
+ int child;
+ int nResult;
+ if (pipe(gravedigger_pipe) < 0) {
+ perror("allocating pipe for gravedigger failed");
+ goto error1;
+ }
+
+ if (pipe(stdin_pipe) < 0) {
+ perror("allocating pipe for child input redirect failed");
+ goto error1;
+ }
+
+ if (pipe(stdout_pipe) < 0) {
+ perror("allocating pipe for child output redirect failed");
+ goto error2;
+ }
+
+ if (pipe(stderr_pipe) < 0) {
+ perror("allocating pipe for child output redirect failed");
+ goto error3;
+ }
+
+ child = fork();
+ if (!child) {
+ char ld_path[512];
+ sprintf(ld_path, "/usr/lib/dbus-tests/test-suites/glib-tests/:");
+ // redirect stdin
+ if (dup2(stdin_pipe[PIPE_READ], STDIN_FILENO) == -1) {
+ perror("redirecting stdin failed");
+ return -1;
+ }
+
+ if (dup2(stdout_pipe[PIPE_WRITE], STDOUT_FILENO) == -1) {
+ perror("redirecting stdout failed");
+ return -1;
+ }
+
+ if (dup2(stderr_pipe[PIPE_WRITE], STDERR_FILENO) == -1) {
+ perror("redirecting stderr failed");
+ return -1;
+ }
+
+ close(stdin_pipe[PIPE_READ]);
+ close(stdin_pipe[PIPE_WRITE]);
+ close(stdout_pipe[PIPE_READ]);
+ close(stdout_pipe[PIPE_WRITE]);
+ close(stderr_pipe[PIPE_READ]);
+ close(stderr_pipe[PIPE_WRITE]);
+ close(gravedigger_pipe[PIPE_READ]);
+
+ char* ld_path_b = getenv("LD_LIBRARY_PATH");
+ if (ld_path_b != NULL)
+ memcpy(ld_path + strlen(ld_path), ld_path_b, strlen(ld_path_b)+1);
+ setenv("LD_LIBRARY_PATH", ld_path, 1);
+ setenv("G_TEST_SRCDIR", "/usr/lib/dbus-tests/test-suites/glib-tests", 1);
+
+ // run child process image
+ nResult = execv(path, arguments);
+
+ // if we get here at all, an error occurred, but we are in the child
+ // process, so just exit
+ perror("exec of the child process failed");
+ exit(nResult);
+ } else if (child > 0) {
+ // close unused file descriptors, these are for child only
+ close(stdin_pipe[PIPE_READ]);
+ close(stdout_pipe[PIPE_WRITE]);
+ close(stderr_pipe[PIPE_WRITE]);
+ close(gravedigger_pipe[PIPE_WRITE]);
+ } else {
+ // failed to create child
+ goto error4;
+ }
+
+ return child;
+
+error4:
+ close(stderr_pipe[PIPE_READ]);
+ close(stderr_pipe[PIPE_WRITE]);
+error3:
+ close(stdout_pipe[PIPE_READ]);
+ close(stdout_pipe[PIPE_WRITE]);
+error2:
+ close(stdin_pipe[PIPE_READ]);
+ close(stdin_pipe[PIPE_WRITE]);
+error1:
+ return -1;
+}
+
+static void run_test(const struct binary* b, const char* test_name)
+{
+ int res = -1;
+ char** arg;
+ char test_id[MAX_COMMENT];
+
+ assert(b);
+ assert(b->name);
+ assert(b->path);
+ assert(test_name);
+
+ arg = b->prepare_args(b, test_name);
+
+ if (b->init)
+ if (!b->init()) {
+ add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot init test", 0);
+ return;
+ }
+
+ res = create_child(b->path, arg);
+ if (res > 0)
+ parse_output_with_timeout(b, res, test_name);
+ else
+ add_test_result(get_test_id(test_id, b, test_name), "ERROR", "Cannot start test", 0);
+
+ if (b->clean)
+ b->clean();
+}
+
+static void parse_run_test(const char* tc) {
+ unsigned int i = 0;
+ for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++) {
+ int len = strlen(tests[i].name);
+ if (strncmp(tc, tests[i].name, len) == 0) {
+ if (tc[len] == '*' || tc[len] == '\0')
+ run_test(&tests[i], "");
+ else
+ run_test(&tests[i], tc + len);
+ }
+ }
+}
+
+static int parse_option(int argc, char* argv[])
+{
+ int ch = 0;
+ int c = 0;
+ while ((ch = getopt_long(argc, argv, "lr:d:", long_options, NULL)) != -1) {
+ switch (ch) {
+ case 'l':
+ print_list(NULL);
+ return 1;
+ case 'r':
+ if (c >= MAX_TC_NUM - 1) //NULL at the end
+ return 0;
+
+ if (optarg)
+ requested_tc[c++] = optarg;
+
+ break;
+ case 'd':
+ print_list(optarg);
+ return 1;
+ }
+ }
+ return 0;
+}
+
+void add_test_result(const char* test_id, const char* result, const char* comment, int res)
+{
+ printf("%s;%s;%s\n", test_id, result, comment);
+ fflush(stdout);
+}
+
+static void prepare_results(void)
+{
+}
+
+int main(int argc, char* argv[])
+{
+ unsigned int i;
+ signal(SIGPIPE, SIG_IGN);
+ if (parse_option(argc, argv))
+ return 0;
+
+ prepare_results();
+
+ if (!requested_tc[0]) {
+ for (i = 0;i < sizeof(tests)/sizeof(struct binary); i++)
+ run_test(&tests[i], "");
+ } else {
+ i = 0;
+ while(requested_tc[i]) {
+ parse_run_test(requested_tc[i]);
+ i++;
+ }
+ }
+
+ return 0;
+}