g_unix_fd_add
g_unix_fd_add_full
g_unix_fd_source_new
+g_unix_fd_ensure_zero_copy_safe
+ <SUBSECTION>
+ g_unix_get_passwd_entry
+
<SUBSECTION Private>
g_unix_error_quark
</SECTION>
g_bytes_new_with_free_func
g_bytes_new_from_bytes
g_bytes_get_data
+ g_bytes_get_region
g_bytes_get_size
+g_bytes_get_zero_copy_fd
g_bytes_hash
g_bytes_equal
g_bytes_compare
GCancellable *cancellable,
GError **error)
{
- const static GDBusInterfaceVTable vtable = {
+ static const GDBusInterfaceVTable vtable = {
g_application_impl_method_call,
g_application_impl_get_property,
- NULL /* set_property */
+ NULL, /* set_property */
+ { 0 }
};
GApplicationClass *app_class = G_APPLICATION_GET_CLASS (impl->app);
+ GBusRequestNameReplyFlags rval;
GBusNameOwnerFlags name_owner_flags;
GApplicationFlags app_flags;
- GVariant *reply;
- guint32 rval;
+ GError *local_error = NULL;
if (org_gtk_Application == NULL)
{
switch (bus_type)
{
case G_BUS_TYPE_SYSTEM:
- ret = g_strdup (g_getenv ("DBUS_SYSTEM_BUS_ADDRESS"));
+ if (has_elevated_privileges)
+ ret = NULL;
+ else
+ 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;
case G_BUS_TYPE_SESSION:
- ret = g_strdup (g_getenv ("DBUS_SESSION_BUS_ADDRESS"));
+ if (has_elevated_privileges)
+ ret = NULL;
+ else
+ 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;
g_dbus_connection_send_message_unlocked (GDBusConnection *connection,
GDBusMessage *message,
GDBusSendMessageFlags flags,
- volatile guint32 *out_serial,
+ guint32 *out_serial,
- GError **error)
+ GError **error,
+ gint timeout_msec)
{
guchar *blob;
gsize blob_size;
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, -1);
- ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error);
++ ret = g_dbus_connection_send_message_unlocked (connection, message, flags, (guint32 *) out_serial, error, -1);
CONNECTION_UNLOCK (connection);
return ret;
}
goto out;
/* if we end up here, the message has not been not handled - so return an error saying this */
- reply = g_dbus_message_new_method_error (message,
+ if (object_found == TRUE)
+ {
+ reply = g_dbus_message_new_method_error (message,
+ "org.freedesktop.DBus.Error.UnknownMethod",
+ _("No such interface “%s” on object at path %s"),
+ interface_name,
+ object_path);
+ }
+ else
+ {
+ reply = g_dbus_message_new_method_error (message,
"org.freedesktop.DBus.Error.UnknownMethod",
- _("No such interface “%s” on object at path %s"),
- interface_name,
+ _("Object does not exist at path “%s”"),
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:
#define G_DBUS_METHOD_INVOCATION(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_DBUS_METHOD_INVOCATION, GDBusMethodInvocation))
#define G_IS_DBUS_METHOD_INVOCATION(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_DBUS_METHOD_INVOCATION))
+ /**
+ * G_DBUS_METHOD_INVOCATION_HANDLED:
+ *
+ * The value returned by handlers of the signals generated by
+ * the `gdbus-codegen` tool to indicate that a method call has been
+ * handled by an implementation. It is equal to %TRUE, but using
+ * this macro is sometimes more readable.
+ *
+ * In code that needs to be backwards-compatible with older GLib,
+ * use %TRUE instead, often written like this:
+ *
+ * |[
+ * g_dbus_method_invocation_return_error (invocation, ...);
+ * return TRUE; // handled
+ * ]|
+ *
+ * Since: 2.68
+ */
+ #define G_DBUS_METHOD_INVOCATION_HANDLED TRUE GLIB_AVAILABLE_MACRO_IN_2_68
+
+ /**
+ * G_DBUS_METHOD_INVOCATION_UNHANDLED:
+ *
+ * The value returned by handlers of the signals generated by
+ * the `gdbus-codegen` tool to indicate that a method call has not been
+ * handled by an implementation. It is equal to %FALSE, but using
+ * this macro is sometimes more readable.
+ *
+ * In code that needs to be backwards-compatible with older GLib,
+ * use %FALSE instead.
+ *
+ * Since: 2.68
+ */
+ #define G_DBUS_METHOD_INVOCATION_UNHANDLED FALSE GLIB_AVAILABLE_MACRO_IN_2_68
+
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,
}
else
{
- call_vanished_handler (client, FALSE);
+ call_vanished_handler (client);
}
- client->initialized = TRUE;
-
+ out:
if (result != NULL)
g_variant_unref (result);
+
client_unref (client);
}
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_2_70
+ gboolean g_dbus_is_error_name (const gchar *string);
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;
+ GLIB_AVAILABLE_IN_2_68
+ gchar *g_dbus_escape_object_path_bytestring (const guint8 *bytes);
+ GLIB_AVAILABLE_IN_2_68
+ gchar *g_dbus_escape_object_path (const gchar *s);
+ GLIB_AVAILABLE_IN_2_68
+ guint8 *g_dbus_unescape_object_path (const gchar *s);
G_END_DECLS
# '$(gio_win32_res_ldflag)',
dependencies : [libz_dep, libdl_dep, libmount_dep, libglib_dep,
libgobject_dep, libgmodule_dep, selinux_dep, xattr_dep,
- platform_deps, network_libs, libdbuspolicy_dep],
- platform_deps, network_libs, libsysprof_capture_dep],
++ platform_deps, network_libs, libdbuspolicy_dep, libsysprof_capture_dep],
c_args : gio_c_args,
objc_args : gio_c_args,
# intl.lib is not compatible with SAFESEH
data = g_bytes_unref_to_data (bytes, &size);
return g_byte_array_new_take (data, size);
}
- return ((guchar *) bytes->data) + offset;
-}
+
+ /**
+ * g_bytes_get_region:
+ * @bytes: a #GBytes
+ * @element_size: a non-zero element size
+ * @offset: an offset to the start of the region within the @bytes
+ * @n_elements: the number of elements in the region
+ *
+ * Gets a pointer to a region in @bytes.
+ *
+ * The region starts at @offset many bytes from the start of the data
+ * and contains @n_elements many elements of @element_size size.
+ *
+ * @n_elements may be zero, but @element_size must always be non-zero.
+ * Ideally, @element_size is a static constant (eg: sizeof a struct).
+ *
+ * This function does careful bounds checking (including checking for
+ * arithmetic overflows) and returns a non-%NULL pointer if the
+ * specified region lies entirely within the @bytes. If the region is
+ * in some way out of range, or if an overflow has occurred, then %NULL
+ * is returned.
+ *
+ * Note: it is possible to have a valid zero-size region. In this case,
+ * the returned pointer will be equal to the base pointer of the data of
+ * @bytes, plus @offset. This will be non-%NULL except for the case
+ * where @bytes itself was a zero-sized region. Since it is unlikely
+ * that you will be using this function to check for a zero-sized region
+ * in a zero-sized @bytes, %NULL effectively always means "error".
+ *
+ * Returns: (nullable): the requested region, or %NULL in case of an error
+ *
+ * Since: 2.70
+ */
+ gconstpointer
+ g_bytes_get_region (GBytes *bytes,
+ gsize element_size,
+ gsize offset,
+ gsize n_elements)
+ {
+ gsize total_size;
+ gsize end_offset;
+
+ g_return_val_if_fail (element_size > 0, NULL);
+
+ /* No other assertion checks here. If something is wrong then we will
+ * simply crash (via NULL dereference or divide-by-zero).
+ */
+
+ if (!g_size_checked_mul (&total_size, element_size, n_elements))
+ return NULL;
+
+ if (!g_size_checked_add (&end_offset, offset, total_size))
+ return NULL;
+
+ /* We now have:
+ *
+ * 0 <= offset <= end_offset
+ *
+ * So we need only check that end_offset is within the range of the
+ * size of @bytes and we're good to go.
+ */
+
+ if (end_offset > bytes->size)
+ return NULL;
+
+ /* We now have:
+ *
+ * 0 <= offset <= end_offset <= bytes->size
+ */
+
++ /* NB: The following line has been adapted to the kdbus rework by Mateusz
++ * and not by a competent programmer. Tread with caution!
++ */
++ return ((guchar *) g_bytes_get_data (bytes, NULL)) + offset;
++}
}
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);
}
+ /* Ignore deprecations in case we refer to a type which was added in a more
+ * recent GLib version than the user’s #GLIB_VERSION_MAX_ALLOWED definition. */
+ G_GNUC_BEGIN_IGNORE_DEPRECATIONS
+
/* If adding a cleanup here, please also add a test case to
* glib/tests/autoptr.c
*/
#include <glib.h>
#include "gwakeup.h"
+#include "gvariant-vectors.h"
#include "gstdioprivate.h"
+ /* gcc defines __SANITIZE_ADDRESS__, clang sets the address_sanitizer
+ * feature flag */
+ #if defined(__SANITIZE_ADDRESS__) || g_macro__has_feature(address_sanitizer)
+
+ /*
+ * %_GLIB_ADDRESS_SANITIZER:
+ *
+ * Private macro defined if the AddressSanitizer is in use.
+ */
+ #define _GLIB_ADDRESS_SANITIZER
+
+ #include <sanitizer/lsan_interface.h>
+
+ #endif
+
+ /*
+ * g_ignore_leak:
+ * @p: any pointer
+ *
+ * Tell AddressSanitizer and similar tools that if the object pointed to
+ * by @p is leaked, it is not a problem. Use this to suppress memory leak
+ * reports when a potentially unreachable pointer is deliberately not
+ * going to be deallocated.
+ */
+ static inline void
+ g_ignore_leak (gconstpointer p)
+ {
+ #ifdef _GLIB_ADDRESS_SANITIZER
+ if (p != NULL)
+ __lsan_ignore_object (p);
+ #endif
+ }
+
+ /*
+ * g_ignore_strv_leak:
+ * @strv: (nullable) (array zero-terminated=1): an array of strings
+ *
+ * The same as g_ignore_leak(), but for the memory pointed to by @strv,
+ * and for each element of @strv.
+ */
+ static inline void
+ g_ignore_strv_leak (GStrv strv)
+ {
+ #ifdef _GLIB_ADDRESS_SANITIZER
+ gchar **item;
+
+ if (strv)
+ {
+ g_ignore_leak (strv);
+
+ for (item = strv; *item != NULL; item++)
+ g_ignore_leak (*item);
+ }
+ #endif
+ }
+
GMainContext * g_get_worker_context (void);
gboolean g_check_setuid (void);
GMainContext * g_main_context_new_with_next_id (guint next_id);
#include "gmain-internal.h"
#include <string.h>
+ #include <sys/types.h>
+ #include <pwd.h>
+
+ G_STATIC_ASSERT (sizeof (ssize_t) == GLIB_SIZEOF_SSIZE_T);
+ G_STATIC_ASSERT (G_ALIGNOF (gssize) == G_ALIGNOF (ssize_t));
+
+ G_STATIC_ASSERT (sizeof (GPid) == sizeof (pid_t));
+ G_STATIC_ASSERT (G_ALIGNOF (GPid) == G_ALIGNOF (pid_t));
+#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
}
/**
+ * 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
+}
++
++/**
+ * g_unix_get_passwd_entry:
+ * @user_name: the username to get the passwd file entry for
+ * @error: return location for a #GError, or %NULL
+ *
+ * Get the `passwd` file entry for the given @user_name using `getpwnam_r()`.
+ * This can fail if the given @user_name doesn’t exist.
+ *
+ * The returned `struct passwd` has been allocated using g_malloc() and should
+ * be freed using g_free(). The strings referenced by the returned struct are
+ * included in the same allocation, so are valid until the `struct passwd` is
+ * freed.
+ *
+ * This function is safe to call from multiple threads concurrently.
+ *
+ * You will need to include `pwd.h` to get the definition of `struct passwd`.
+ *
+ * Returns: (transfer full): passwd entry, or %NULL on error; free the returned
+ * value with g_free()
+ * Since: 2.64
+ */
+ struct passwd *
+ g_unix_get_passwd_entry (const gchar *user_name,
+ GError **error)
+ {
+ struct passwd *passwd_file_entry;
+ struct
+ {
+ struct passwd pwd;
+ char string_buffer[];
+ } *buffer = NULL;
+ gsize string_buffer_size = 0;
+ GError *local_error = NULL;
+ int errsv = 0;
+
+ g_return_val_if_fail (user_name != NULL, NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ #ifdef _SC_GETPW_R_SIZE_MAX
+ {
+ /* Get the recommended buffer size */
+ glong string_buffer_size_long = sysconf (_SC_GETPW_R_SIZE_MAX);
+ if (string_buffer_size_long > 0)
+ string_buffer_size = string_buffer_size_long;
+ }
+ #endif /* _SC_GETPW_R_SIZE_MAX */
+
+ /* Default starting size. */
+ if (string_buffer_size == 0)
+ string_buffer_size = 64;
+
+ do
+ {
+ int retval;
+
+ g_free (buffer);
+ /* Allocate space for the `struct passwd`, and then a buffer for all its
+ * strings (whose size is @string_buffer_size, which increases in this
+ * loop until it’s big enough). Add 6 extra bytes to work around a bug in
+ * macOS < 10.3. See #156446.
+ */
+ buffer = g_malloc0 (sizeof (*buffer) + string_buffer_size + 6);
+
+ errno = 0;
+ retval = getpwnam_r (user_name, &buffer->pwd, buffer->string_buffer,
+ string_buffer_size, &passwd_file_entry);
+ errsv = errno;
+
+ /* Bail out if: the lookup was successful, or if the user id can't be
+ * found (should be pretty rare case actually), or if the buffer should be
+ * big enough and yet lookups are still not successful.
+ */
+ if (passwd_file_entry != NULL)
+ {
+ /* Success. */
+ break;
+ }
+ else if (retval == 0 ||
+ errsv == ENOENT || errsv == ESRCH ||
+ errsv == EBADF || errsv == EPERM)
+ {
+ /* Username not found. */
+ g_unix_set_error_from_errno (&local_error, errsv);
+ break;
+ }
+ else if (errsv == ERANGE)
+ {
+ /* Can’t allocate enough string buffer space. */
+ if (string_buffer_size > 32 * 1024)
+ {
+ g_unix_set_error_from_errno (&local_error, errsv);
+ break;
+ }
+
+ string_buffer_size *= 2;
+ continue;
+ }
+ else
+ {
+ g_unix_set_error_from_errno (&local_error, errsv);
+ break;
+ }
+ }
+ while (passwd_file_entry == NULL);
+
+ g_assert (passwd_file_entry == NULL ||
+ (gpointer) passwd_file_entry == (gpointer) buffer);
+
+ /* Success or error. */
+ if (local_error != NULL)
+ {
+ g_clear_pointer (&buffer, g_free);
+ g_propagate_error (error, g_steal_pointer (&local_error));
+ errno = errsv;
+ }
+
+ return (struct passwd *) g_steal_pointer (&buffer);
+ }
GUnixFDSourceFunc function,
gpointer user_data);
+GLIB_AVAILABLE_IN_2_44
+gboolean g_unix_fd_ensure_zero_copy_safe (gint fd);
+
+ GLIB_AVAILABLE_IN_2_64
+ struct passwd *g_unix_get_passwd_entry (const gchar *user_name,
+ GError **error);
+
G_END_DECLS
#endif /* __G_UNIX_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 serialized form for the instance, if it
- * is known. If the instance is in serialized 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
+ * holding a value in serialized form or holding a value in
* tree form.
*
- * .serialised: Only valid when the instance is in serialised form.
+ * .serialised: Only valid when the instance is in serialized form.
*
* Since an instance can never transition away from
- * serialised form, once these fields are set, they will
+ * serialized form, once these fields are set, they will
* never be changed. It is therefore valid to access
* them without holding a lock.
*
g_free (value->contents.tree.children);
}
-/* This begins the main body of the recursive serializer.
+/* < 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
+ * There are 3 functions here that work as a team with the serializer to
* get things done. g_variant_store() has a trivial role, but as a
* public API function, it has its definition elsewhere.
*
- * Note that "serialisation" of an instance does not mean that the
- * instance is converted to serialised form -- it means that the
- * serialised form of an instance is written to an external buffer.
+ * Note that "serialization" of an instance does not mean that the
+ * instance is converted to serialized form -- it means that the
+ * serialized form of an instance is written to an external buffer.
* g_variant_ensure_serialised() (which is not part of this set of
* functions) is the function that is responsible for converting an
- * instance to serialised form.
+ * instance to serialized form.
*
* We are only concerned here with container types since non-container
- * instances are always in serialised form. For these instances,
- * storing their serialised form merely involves a memcpy().
+ * instances are always in serialized form. For these instances,
+ * storing their serialized form merely involves a memcpy().
*
- * Serialization is a two-step process. First, the size of the
- * serialized 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
- * serializer code to determine the size. The serializer is passed
- * g_variant_fill_gvs() as a callback.
- *
- * g_variant_fill_gvs() is called by the serializer 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 serializer 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 serializer code to write
- * the bytes to the container. The serializer is, again, passed
+ * called on the container. This invokes the serialiser code to write
+ * 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
- * form this means a memcpy() of the serialised data into the
+ * g_variant_store(). In the event that the instance is in serialized
+ * form this means a memcpy() of the serialized data into the
* allocated buffer. In the event that the instance is in tree form
* this means a recursive call back into g_variant_serialise().
*
* g_variant_ensure_serialised:
* @value: a #GVariant
*
- * Ensures that @value is in serialised form.
+ * Ensures that @value is in serialized form.
*
- * If @value is in tree form then this function ensures that the
- * serialized size is known and then allocates a buffer of that size and
- * serializes the instance into the buffer. The 'children' array is
- * then released and the instance is set to serialized 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)
aligned_size) != 0)
g_error ("posix_memalign failed");
- memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size);
+ if (aligned_size != 0)
+ memcpy (aligned_data, g_bytes_get_data (bytes, NULL), aligned_size);
- bytes = owned_bytes = g_bytes_new_with_free_func (aligned_data,
- aligned_size,
- free, aligned_data);
+ owned_bytes = g_bytes_new_with_free_func (aligned_data,
+ aligned_size,
+ free, aligned_data);
aligned_data = NULL;
#else
/* NOTE: there may be platforms that lack posix_memalign() and also
}
/* < 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;
+}
+
++/* < internal >
+ * g_variant_get_depth:
+ * @value: a #GVariant
+ *
+ * Gets the nesting depth of a #GVariant. This is 0 for a #GVariant with no
+ * children.
+ *
+ * Returns: nesting depth of @value
+ */
+ gsize
+ g_variant_get_depth (GVariant *value)
+ {
+ return value->depth;
+ }
+
/* -- public -- */
/**
GVariantTypeInfo * g_variant_get_type_info (GVariant *value);
+gconstpointer g_variant_get_serialised (GVariant *value,
+ GBytes **bytes,
+ gsize *size);
+
+ gsize g_variant_get_depth (GVariant *value);
+
#endif /* __G_VARIANT_CORE_H__ */
*
* The range of possible values is determined by the type.
*
-- * The type system used by #GVariant is #GVariantType.
++ * The type system used by #GVariant is #GVariantType.
*
* #GVariant instances always have a type and a value (which are given
* at construction time). The type and value of a #GVariant instance
*
* This means that in total, for our "a{sv}" example, 91 bytes of
* type information would be allocated.
-- *
++ *
* The type information cache, additionally, uses a #GHashTable to
* store and look up the cached items and stores a pointer to this
* hash table in static storage. The hash table is freed when there
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),
+ g_memdup2 (&value, sizeof value),
1, g_variant_is_trusted (value));
}
* @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_DOUBLE: The #GVariant is a double precision floating
+ * @G_VARIANT_CLASS_FLOAT: The #GVariant is a single precision floating
+ * point value.
- * @G_VARIANT_CLASS_DOUBLE: The #GVariant is a double precision floating
++ * @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_CLASS_OBJECT_PATH: The #GVariant is a D-Bus object path
++ * @G_VARIANT_CLASS_OBJECT_PATH: The #GVariant is a D-Bus object path
* string.
* @G_VARIANT_CLASS_SIGNATURE: The #GVariant is a D-Bus signature string.
* @G_VARIANT_CLASS_VARIANT: The #GVariant is a variant.
* you no longer need it.
*
* Here is an example for iterating with g_variant_iter_next_value():
-- * |[<!-- language="C" -->
++ * |[<!-- language="C" -->
* // recursively iterate a container
* void
* iterate_container_recursive (GVariant *container)
*
* This function might be used as follows:
*
-- * |[<!-- language="C" -->
++ * |[<!-- language="C" -->
* GVariant *
* make_pointless_dictionary (void)
* {
* the unpacking process.
*
* Here is an example for memory management with g_variant_iter_next():
-- * |[<!-- language="C" -->
++ * |[<!-- language="C" -->
* // Iterates a dictionary of type 'a{sv}'
* void
* iterate_dictionary (GVariant *dictionary)
* g_variant_get(). Failure to do so will cause a memory leak.
*
* Here is an example for memory management with g_variant_iter_loop():
-- * |[<!-- language="C" -->
++ * |[<!-- language="C" -->
* // Iterates a dictionary of type 'a{sv}'
* void
* iterate_dictionary (GVariant *dictionary)
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);
+ g_assert_true (data == memory);
g_assert_cmpmem (data, size, NYAN, N_NYAN);
g_free (data);
}
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 (array->data == memory);
+ g_assert_nonnull (array);
+ g_assert_true (array->data == memory);
g_assert_cmpmem (array->data, array->len, NYAN, N_NYAN);
g_byte_array_unref (array);
}
data = g_bytes_unref_to_data (bytes, &size);
- g_assert (data == NULL);
- g_assert (size == 0);
+ g_assert_null (data);
+ g_assert_cmpuint (size, ==, 0);
+ }
+
+ static void
+ test_get_region (void)
+ {
+ GBytes *bytes;
+
+ bytes = g_bytes_new_static (NYAN, N_NYAN);
+
+ /* simple valid gets at the start */
+ g_assert_true (g_bytes_get_region (bytes, 1, 0, 1) == NYAN);
+ g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN) == NYAN);
+
+ /* an invalid get because the range is too wide */
+ g_assert_true (g_bytes_get_region (bytes, 1, 0, N_NYAN + 1) == NULL);
+
+ /* an valid get, but of a zero-byte range at the end */
+ g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 0) == NYAN + N_NYAN);
+
+ /* not a valid get because it overlap ones byte */
+ g_assert_true (g_bytes_get_region (bytes, 1, N_NYAN, 1) == NULL);
+
+ /* let's try some multiplication overflow now */
+ g_assert_true (g_bytes_get_region (bytes, 32, 0, G_MAXSIZE / 32 + 1) == NULL);
+ g_assert_true (g_bytes_get_region (bytes, G_MAXSIZE / 32 + 1, 0, 32) == NULL);
+
+ /* and some addition overflow */
+ g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, -G_MAXSIZE) == NULL);
+ g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSSIZE, ((gsize) G_MAXSSIZE) + 1) == NULL);
+ g_assert_true (g_bytes_get_region (bytes, 1, G_MAXSIZE, 1) == NULL);
+
+ g_bytes_unref (bytes);
+ }
+
+ static void
+ test_unref_null (void)
+ {
+ g_test_summary ("Test that calling g_bytes_unref() on NULL is a no-op");
+ g_bytes_unref (NULL);
}
+#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
+ g_test_add_func ("/bytes/get-region", test_get_region);
+ g_test_add_func ("/bytes/unref-null", test_unref_null);
return g_test_run ();
}
--- /dev/null
- %{_bindir}/gio-launch-desktop
+# Do not create provides from extension .so files because the main package
+# should anchor any reverse-dependencies
+%global __provides_exclude_from ^(.*\\.extension-kdbus)$
+
+%define baseline 2.62
+%define with_systemtap 0
+%define keepstatic 1
+%define build_dir _build
+%define build_dir_kdbus _build_kdbus
+
+# The 'meson' macro is defined in rpm macros, but it uses features from rpm 4.15 ({shrink, set_build_flags)
+# Below is a version suitable for our purposes
+%define meson \
+ CFLAGS="${CFLAGS:-%optflags}" \
+ export CFLAGS \
+ %{__meson} \\\
+ --buildtype=plain \\\
+ --prefix=%{_prefix} \\\
+ --libdir=%{_libdir} \\\
+ --libexecdir=%{_libexecdir} \\\
+ --bindir=%{_bindir} \\\
+ --sbindir=%{_sbindir} \\\
+ --includedir=%{_includedir} \\\
+ --datadir=%{_datadir} \\\
+ --mandir=%{_mandir} \\\
+ --infodir=%{_infodir} \\\
+ --localedir=%{_datadir}/locale \\\
+ --sysconfdir=%{_sysconfdir} \\\
+ --localstatedir=%{_localstatedir} \\\
+ --sharedstatedir=%{_sharedstatedir} \\\
+ --wrap-mode=%{__meson_wrap_mode} \\\
+ %{_vpath_builddir}
+# Ninja macros below are defined for ninja in e.g. fedora distro, but
+# so far they are not provided by Tizen's ninja package.
+%define __ninja %{_bindir}/ninja
+%define __ninja_common_opts -v %{?_smp_flags}
+%define ninja_build \
+ %{__ninja} %{__ninja_common_opts}
+%define ninja_install \
+ DESTDIR=%{buildroot} %{__ninja} install %{__ninja_common_opts}
+
+Name: glib2
+Version: 2.62.3
+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.1+
+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
+Source98: q_quark_block_size.patch
+Source99: baselibs.conf
+Source1001: glib2.manifest
+BuildRequires: automake
+BuildRequires: fdupes
+BuildRequires: gcc-c++
+BuildRequires: m4
+BuildRequires: meson >= 0.49.2
+BuildRequires: pkg-config
+BuildRequires: python3
+BuildRequires: gettext-tools
+# gdbus-codegen is run during the build, so we need python-xml
+BuildRequires: python3-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.31
+BuildRequires: pkgconfig(mount) >= 2.28
+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: python3-xml
+Requires: python3
+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
+Summary: Static libraries for glib, a general-purpose utility library
+Group: Development/Libraries/C and C++
+Requires: %{name}-devel = %{version}
+
+%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 MIT
+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.
+
+%prep
+%setup -q -n %{name}-%{version}
+%{__patch} -p1 < %{SOURCE98}
+
+%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
+
+%define _vpath_srcdir .
+
+# Normal build
+%define _vpath_builddir %{build_dir}
+%meson \
+ --default-library=both \
+ -Dinstalled_tests=true \
+ -Db_pie=true
+%meson_build
+
+# Configure kdbus extension build
+%define _vpath_builddir %{build_dir_kdbus}
+%meson \
+ --default-library=both \
+ -Dkdbus=true \
+ -Dlibdbuspolicy=true \
+ -Db_pie=true
+%meson_build
+
+# compile test-runner for 'dbus-integration-test' framework
+%__cc %{_builddir}/%{name}-%{version}/test-runner.c -fPIC -pie -o %{_builddir}/%{name}-%{version}/glib-tests
+
+%install
+# kdbus extension install and gather required files
+%define _vpath_builddir %{build_dir_kdbus}
+%meson_install
+for FILE in %{buildroot}%{_libdir}/libgio*; do mv "$FILE" "$FILE.extension-kdbus"; done
+
+# normal install overwriting kdbus extension install
+%define _vpath_builddir %{build_dir}
+%meson_install
+%find_lang glib20 %{?no_lang_C}
+
+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
+
+# gio-querymodules magic
+%if "%{_lib}" == "lib64"
+mv %{buildroot}%{_bindir}/gio-querymodules %{buildroot}%{_bindir}/gio-querymodules-64
+%endif
+
+# 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 %{SOURCE6} %{buildroot}%{_sysconfdir}/rpm
+
+mkdir -p %{buildroot}%{_libdir}/gio/modules
+mkdir -p %{buildroot}%{_datadir}/glib-2.0/schemas/
+
+chmod 755 %{buildroot}%{_bindir}/*
+
+%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
+%{_bindir}/gio-querymodules*
+%{_bindir}/glib-compile-schemas
+%{_bindir}/gresource
+%{_bindir}/gsettings
+%{_bindir}/gapplication
+
+# 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/
+
+%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
+%{_libdir}/lib*.a.extension-kdbus
+
+%files tests
+%manifest %{name}.manifest
+%license COPYING LICENSE.MIT
+%{relative_dbus_tests_base_dir}/test-suites/glib-tests/
+%{relative_dbus_tests_base_dir}/runner/glib-tests
+
+%changelog