diff options
author | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 10:37:40 +0900 |
---|---|---|
committer | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 10:37:40 +0900 |
commit | 245e1f302c8a605f79125d38557e70992fa57bc9 (patch) | |
tree | 69c07ff7bb85a482225636853da37bc4dae4b2f7 /gio | |
parent | 9d4dc80d1464c073554d6816992036babadad25a (diff) | |
download | glib-245e1f302c8a605f79125d38557e70992fa57bc9.tar.gz glib-245e1f302c8a605f79125d38557e70992fa57bc9.tar.bz2 glib-245e1f302c8a605f79125d38557e70992fa57bc9.zip |
Imported Upstream version 2.57.3
Diffstat (limited to 'gio')
32 files changed, 1004 insertions, 765 deletions
diff --git a/gio/gapplicationimpl-dbus.c b/gio/gapplicationimpl-dbus.c index ac029a9f3..f9e5e710d 100644 --- a/gio/gapplicationimpl-dbus.c +++ b/gio/gapplicationimpl-dbus.c @@ -426,10 +426,12 @@ g_application_impl_attempt_primary (GApplicationImpl *impl, * the well-known name and fall back to remote mode (!is_primary) * 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)"), + g_variant_new ("(su)", + impl->bus_name, + G_BUS_NAME_OWNER_FLAGS_DO_NOT_QUEUE), + G_VARIANT_TYPE ("(u)"), 0, -1, cancellable, error); if (reply == NULL) diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 68122387b..8de836bf6 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -1994,7 +1994,7 @@ g_dbus_message_bytes_needed (guchar *blob, /** * g_dbus_message_new_from_blob: - * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message. + * @blob: (array length=blob_len) (element-type guint8): A blob representing a binary D-Bus message. * @blob_len: The length of @blob. * @capabilities: A #GDBusCapabilityFlags describing what protocol features are supported. * @error: Return location for error or %NULL. diff --git a/gio/gio-tool-mount.c b/gio/gio-tool-mount.c index b5aaa1af2..05647d91e 100644 --- a/gio/gio-tool-mount.c +++ b/gio/gio-tool-mount.c @@ -39,6 +39,7 @@ typedef enum { static int outstanding_mounts = 0; static GMainLoop *main_loop; +static GVolumeMonitor *volume_monitor; static gboolean mount_mountable = FALSE; static gboolean mount_unmount = FALSE; @@ -484,12 +485,9 @@ stop_with_device_file_cb (GObject *object, static void stop_with_device_file (const char *device_file) { - GVolumeMonitor *volume_monitor; GList *drives; GList *l; - volume_monitor = g_volume_monitor_get (); - drives = g_volume_monitor_get_connected_drives (volume_monitor); for (l = drives; l != NULL; l = l->next) { @@ -524,8 +522,6 @@ stop_with_device_file (const char *device_file) print_error ("%s: %s", device_file, _("No drive for device file")); success = FALSE; } - - g_object_unref (volume_monitor); } static gboolean @@ -905,11 +901,8 @@ list_drives (GList *drives, static void list_monitor_items (void) { - GVolumeMonitor *volume_monitor; GList *drives, *volumes, *mounts; - volume_monitor = g_volume_monitor_get(); - /* populate gvfs network mounts */ iterate_gmain(); @@ -924,19 +917,14 @@ list_monitor_items (void) mounts = g_volume_monitor_get_mounts (volume_monitor); list_mounts (mounts, 0, TRUE); g_list_free_full (mounts, g_object_unref); - - g_object_unref (volume_monitor); } static void unmount_all_with_scheme (const char *scheme) { - GVolumeMonitor *volume_monitor; GList *mounts; GList *l; - volume_monitor = g_volume_monitor_get(); - /* populate gvfs network mounts */ iterate_gmain(); @@ -952,8 +940,6 @@ unmount_all_with_scheme (const char *scheme) g_object_unref (root); } g_list_free_full (mounts, g_object_unref); - - g_object_unref (volume_monitor); } static void @@ -1004,12 +990,9 @@ mount_with_device_file_cb (GObject *object, static void mount_with_device_file (const char *device_file) { - GVolumeMonitor *volume_monitor; GList *volumes; GList *l; - volume_monitor = g_volume_monitor_get(); - volumes = g_volume_monitor_get_volumes (volume_monitor); for (l = volumes; l != NULL; l = l->next) { @@ -1044,8 +1027,6 @@ mount_with_device_file (const char *device_file) print_error ("%s: %s", device_file, _("No volume for device file")); success = FALSE; } - - g_object_unref (volume_monitor); } static void @@ -1199,10 +1180,6 @@ monitor_drive_eject_button (GVolumeMonitor *volume_monitor, GDrive *drive) static void monitor (void) { - GVolumeMonitor *volume_monitor; - - volume_monitor = g_volume_monitor_get (); - g_signal_connect (volume_monitor, "mount-added", (GCallback) monitor_mount_added, NULL); g_signal_connect (volume_monitor, "mount-removed", (GCallback) monitor_mount_removed, NULL); g_signal_connect (volume_monitor, "mount-changed", (GCallback) monitor_mount_changed, NULL); @@ -1255,6 +1232,7 @@ handle_mount (int argc, char *argv[], gboolean do_help) } main_loop = g_main_loop_new (NULL, FALSE); + volume_monitor = g_volume_monitor_get (); if (mount_list) list_monitor_items (); @@ -1284,6 +1262,7 @@ handle_mount (int argc, char *argv[], gboolean do_help) { show_help (context, _("No locations given")); g_option_context_free (context); + g_object_unref (volume_monitor); return 1; } @@ -1292,5 +1271,7 @@ handle_mount (int argc, char *argv[], gboolean do_help) if (outstanding_mounts > 0) g_main_loop_run (main_loop); + g_object_unref (volume_monitor); + return success ? 0 : 2; } diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c index d4340d463..5e1bebbba 100644 --- a/gio/glib-compile-schemas.c +++ b/gio/glib-compile-schemas.c @@ -2112,6 +2112,7 @@ set_overrides (GHashTable *schema_table, } g_strfreev (groups); + g_key_file_free (key_file); } return TRUE; diff --git a/gio/glocalfile.c b/gio/glocalfile.c index 354ac7c8c..30fa2281c 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -983,15 +983,20 @@ g_local_file_query_filesystem_info (GFile *file, block_size = statfs_buffer.f_bsize; /* Many backends can't report free size (for instance the gvfs fuse - backend for backend not supporting this), and set f_bfree to 0, - but it can be 0 for real too. We treat the available == 0 and - free == 0 case as "both of these are invalid". - */ -#ifndef G_OS_WIN32 + * backend for backend not supporting this), and set f_bfree to 0, + * but it can be 0 for real too. We treat the available == 0 and + * free == 0 case as "both of these are invalid", but only on file systems + * which are known to not support this (otherwise we can omit metadata for + * systems which are legitimately full). */ +#if defined(__linux__) if (statfs_result == 0 && - statfs_buffer.f_bavail == 0 && statfs_buffer.f_bfree == 0) + statfs_buffer.f_bavail == 0 && statfs_buffer.f_bfree == 0 && + (/* linux/ncp_fs.h: NCP_SUPER_MAGIC == 0x564c */ + statfs_buffer.f_type == 0x564c || + /* man statfs: FUSE_SUPER_MAGIC == 0x65735546 */ + statfs_buffer.f_type == 0x65735546)) no_size = TRUE; -#endif /* G_OS_WIN32 */ +#endif /* __linux__ */ #elif defined(USE_STATVFS) statfs_result = statvfs (local->filename, &statfs_buffer); @@ -1677,20 +1682,16 @@ find_mountpoint_for (const char *file, } } -static char * -_g_local_file_find_topdir_for_internal (const char *file, dev_t file_dev) +char * +_g_local_file_find_topdir_for (const char *file) { char *dir; char *mountpoint = NULL; dev_t dir_dev; dir = get_parent (file, &dir_dev); - if (dir == NULL || dir_dev != file_dev) - { - g_free (dir); - - return NULL; - } + if (dir == NULL) + return NULL; mountpoint = find_mountpoint_for (dir, dir_dev); g_free (dir); @@ -1698,17 +1699,6 @@ _g_local_file_find_topdir_for_internal (const char *file, dev_t file_dev) return mountpoint; } -char * -_g_local_file_find_topdir_for (const char *file) -{ - GStatBuf file_stat; - - if (g_lstat (file, &file_stat) != 0) - return NULL; - - return _g_local_file_find_topdir_for_internal (file, file_stat.st_dev); -} - static char * get_unique_filename (const char *basename, int id) @@ -1908,6 +1898,7 @@ g_local_file_trash (GFile *file, char *original_name, *original_name_escaped; int i; char *data; + char *path; gboolean is_homedir_trash; char *delete_time = NULL; int fd; @@ -1932,6 +1923,24 @@ g_local_file_trash (GFile *file, is_homedir_trash = FALSE; trashdir = NULL; + + /* On overlayfs, a file's st_dev will be different to the home directory's. + * We still want to create our trash directory under the home directory, so + * instead we should stat the directory that the file we're deleting is in as + * this will have the same st_dev. + */ + if (!S_ISDIR (file_stat.st_mode)) + { + path = g_path_get_dirname (local->filename); + /* If the parent is a symlink to a different device then it might have + * st_dev equal to the home directory's, in which case we will end up + * trying to rename across a filesystem boundary, which doesn't work. So + * we use g_stat here instead of g_lstat, to know where the symlink + * points to. */ + g_stat (path, &file_stat); + g_free (path); + } + if (file_stat.st_dev == home_stat.st_dev) { is_homedir_trash = TRUE; @@ -1962,8 +1971,7 @@ g_local_file_trash (GFile *file, uid = geteuid (); g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid); - topdir = _g_local_file_find_topdir_for_internal (local->filename, - file_stat.st_dev); + topdir = _g_local_file_find_topdir_for (local->filename); if (topdir == NULL) { g_set_io_error (error, diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index b3e29374a..58802fd43 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -924,13 +924,9 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher, _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_DELETE, writable); - /* Trashing is supported only if the parent device is the same */ if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH)) - _g_file_info_set_attribute_boolean_by_id (info, - G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, - writable && - parent_info->has_trash_dir && - parent_info->device == statbuf->st_dev); + _g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_TRASH, + writable && parent_info->has_trash_dir); } } @@ -961,7 +957,8 @@ set_info_from_stat (GFileInfo *info, else if (S_ISLNK (statbuf->st_mode)) file_type = G_FILE_TYPE_SYMBOLIC_LINK; #elif defined (G_OS_WIN32) - if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK) + if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK || + statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT) file_type = G_FILE_TYPE_SYMBOLIC_LINK; #endif @@ -1005,13 +1002,20 @@ set_info_from_stat (GFileInfo *info, #elif defined (HAVE_STRUCT_STAT_ST_ATIM_TV_NSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_ACCESS_USEC, statbuf->st_atim.tv_nsec / 1000); #endif - + +#ifndef G_OS_WIN32 + /* Microsoft uses st_ctime for file creation time, + * instead of file change time: + * https://docs.microsoft.com/en-us/cpp/c-runtime-library/reference/stat-functions#generic-text-routine-mappings + * Thank you, Microsoft! + */ _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED, statbuf->st_ctime); #if defined (HAVE_STRUCT_STAT_ST_CTIMENSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctimensec / 1000); #elif defined (HAVE_STRUCT_STAT_ST_CTIM_TV_NSEC) _g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CHANGED_USEC, statbuf->st_ctim.tv_nsec / 1000); #endif +#endif #if defined (HAVE_STRUCT_STAT_ST_BIRTHTIME) && defined (HAVE_STRUCT_STAT_ST_BIRTHTIMENSEC) _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime); @@ -1023,6 +1027,8 @@ set_info_from_stat (GFileInfo *info, _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtime); #elif defined (HAVE_STRUCT_STAT_ST_BIRTHTIM) _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_birthtim); +#elif defined (G_OS_WIN32) + _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_CREATED, statbuf->st_ctime); #endif if (_g_file_attribute_matcher_matches_id (attribute_matcher, @@ -1799,7 +1805,9 @@ _g_local_file_info_get (const char *basename, is_symlink = stat_ok && S_ISLNK (statbuf.st_mode); #elif defined (G_OS_WIN32) /* glib already checked the FILE_ATTRIBUTE_REPARSE_POINT for us */ - is_symlink = stat_ok && statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK; + is_symlink = stat_ok && + (statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK || + statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT); #else is_symlink = FALSE; #endif @@ -2182,7 +2190,9 @@ set_unix_mode (char *filename, GWin32PrivateStat statbuf; res = GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (filename, &statbuf); - is_symlink = (res == 0 && statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK); + is_symlink = (res == 0 && + (statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK || + statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)); #endif if (is_symlink) { diff --git a/gio/gnetworkmonitorportal.c b/gio/gnetworkmonitorportal.c index 16249ac55..bce8a338a 100644 --- a/gio/gnetworkmonitorportal.c +++ b/gio/gnetworkmonitorportal.c @@ -182,6 +182,15 @@ got_connectivity (GObject *source, } static void +update_properties (GDBusProxy *proxy, + GNetworkMonitorPortal *nm) +{ + g_dbus_proxy_call (proxy, "GetConnectivity", NULL, 0, -1, NULL, got_connectivity, nm); + g_dbus_proxy_call (proxy, "GetMetered", NULL, 0, -1, NULL, got_metered, nm); + g_dbus_proxy_call (proxy, "GetAvailable", NULL, 0, -1, NULL, got_available, nm); +} + +static void proxy_signal (GDBusProxy *proxy, const char *sender, const char *signal, @@ -200,9 +209,7 @@ proxy_signal (GDBusProxy *proxy, } else if (nm->priv->version == 2) { - g_dbus_proxy_call (proxy, "GetConnectivity", NULL, 0, -1, NULL, got_connectivity, nm); - g_dbus_proxy_call (proxy, "GetMetered", NULL, 0, -1, NULL, got_metered, nm); - g_dbus_proxy_call (proxy, "GetAvailable", NULL, 0, -1, NULL, got_available, nm); + update_properties (proxy, nm); } } @@ -326,7 +333,13 @@ g_network_monitor_portal_initable_init (GInitable *initable, nm->priv->has_network = glib_network_available_in_sandbox (); nm->priv->version = version; - return initable_parent_iface->init (initable, cancellable, error); + if (!initable_parent_iface->init (initable, cancellable, error)) + return FALSE; + + if (nm->priv->has_network && nm->priv->version == 2) + update_properties (proxy, nm); + + return TRUE; } static void diff --git a/gio/gresource-tool.c b/gio/gresource-tool.c index b25eebf3d..d1de02631 100644 --- a/gio/gresource-tool.c +++ b/gio/gresource-tool.c @@ -31,6 +31,9 @@ #ifdef HAVE_LIBELF #include <libelf.h> #include <gelf.h> +#endif + +#ifdef HAVE_MMAP #include <sys/mman.h> #endif @@ -42,6 +45,10 @@ #include "glib/glib-private.h" #endif +#if defined(HAVE_LIBELF) && defined(HAVE_MMAP) +#define USE_LIBELF +#endif + /* GResource functions {{{1 */ static GResource * get_resource (const gchar *file) @@ -133,7 +140,7 @@ extract_resource (GResource *resource, /* Elf functions {{{1 */ -#ifdef HAVE_LIBELF +#ifdef USE_LIBELF static Elf * get_elf (const gchar *file, @@ -353,7 +360,7 @@ print_section_name (GElf_Shdr *shdr, return TRUE; } -#endif /* HAVE_LIBELF */ +#endif /* USE_LIBELF */ /* Toplevel commands {{{1 */ @@ -365,7 +372,7 @@ cmd_sections (const gchar *file, { GResource *resource; -#ifdef HAVE_LIBELF +#ifdef USE_LIBELF Elf *elf; gint fd; @@ -388,7 +395,7 @@ cmd_sections (const gchar *file, else { g_printerr ("Don't know how to handle %s\n", file); -#ifndef HAVE_LIBELF +#ifndef USE_LIBELF g_printerr ("gresource is built without elf support\n"); #endif } @@ -402,7 +409,7 @@ cmd_list (const gchar *file, { GResource *resource; -#ifdef HAVE_LIBELF +#ifdef USE_LIBELF Elf *elf; int fd; @@ -424,7 +431,7 @@ cmd_list (const gchar *file, else { g_printerr ("Don't know how to handle %s\n", file); -#ifndef HAVE_LIBELF +#ifndef USE_LIBELF g_printerr ("gresource is built without elf support\n"); #endif } @@ -438,7 +445,7 @@ cmd_extract (const gchar *file, { GResource *resource; -#ifdef HAVE_LIBELF +#ifdef USE_LIBELF Elf *elf; int fd; @@ -461,7 +468,7 @@ cmd_extract (const gchar *file, else { g_printerr ("Don't know how to handle %s\n", file); -#ifndef HAVE_LIBELF +#ifndef USE_LIBELF g_printerr ("gresource is built without elf support\n"); #endif } diff --git a/gio/gresource.c b/gio/gresource.c index bf54f1d78..2844f4808 100644 --- a/gio/gresource.c +++ b/gio/gresource.c @@ -489,7 +489,7 @@ g_resource_unref (GResource *resource) { if (g_atomic_int_dec_and_test (&resource->ref_count)) { - gvdb_table_unref (resource->table); + gvdb_table_free (resource->table); g_free (resource); } } @@ -512,6 +512,19 @@ g_resource_new_from_table (GvdbTable *table) return resource; } +static void +g_resource_error_from_gvdb_table_error (GError **g_resource_error, + GError *gvdb_table_error /* (transfer full) */) +{ + if (g_error_matches (gvdb_table_error, G_FILE_ERROR, G_FILE_ERROR_INVAL)) + g_set_error_literal (g_resource_error, + G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL, + gvdb_table_error->message); + else + g_propagate_error (g_resource_error, g_steal_pointer (&gvdb_table_error)); + g_clear_error (&gvdb_table_error); +} + /** * g_resource_new_from_data: * @data: A #GBytes @@ -528,6 +541,8 @@ g_resource_new_from_table (GvdbTable *table) * Otherwise this function will internally create a copy of the memory since * GLib 2.56, or in older versions fail and exit the process. * + * If @data is empty or corrupt, %G_RESOURCE_ERROR_INTERNAL will be returned. + * * Returns: (transfer full): a new #GResource, or %NULL on error * * Since: 2.32 @@ -538,6 +553,7 @@ g_resource_new_from_data (GBytes *data, { GvdbTable *table; gboolean unref_data = FALSE; + GError *local_error = NULL; if (((guintptr) g_bytes_get_data (data, NULL)) % sizeof (gpointer) != 0) { @@ -546,19 +562,16 @@ g_resource_new_from_data (GBytes *data, unref_data = TRUE; } - table = gvdb_table_new_from_data (g_bytes_get_data (data, NULL), - g_bytes_get_size (data), - TRUE, - g_bytes_ref (data), - (GvdbRefFunc)g_bytes_ref, - (GDestroyNotify)g_bytes_unref, - error); + table = gvdb_table_new_from_bytes (data, TRUE, &local_error); if (unref_data) g_bytes_unref (data); if (table == NULL) - return NULL; + { + g_resource_error_from_gvdb_table_error (error, g_steal_pointer (&local_error)); + return NULL; + } return g_resource_new_from_table (table); } @@ -574,6 +587,11 @@ g_resource_new_from_data (GBytes *data, * If you want to use this resource in the global resource namespace you need * to register it with g_resources_register(). * + * If @filename is empty or the data in it is corrupt, + * %G_RESOURCE_ERROR_INTERNAL will be returned. If @filename doesn’t exist, or + * there is an error in reading it, an error from g_mapped_file_new() will be + * returned. + * * Returns: (transfer full): a new #GResource, or %NULL on error * * Since: 2.32 @@ -583,10 +601,14 @@ g_resource_load (const gchar *filename, GError **error) { GvdbTable *table; + GError *local_error = NULL; - table = gvdb_table_new (filename, FALSE, error); + table = gvdb_table_new (filename, FALSE, &local_error); if (table == NULL) - return NULL; + { + g_resource_error_from_gvdb_table_error (error, g_steal_pointer (&local_error)); + return NULL; + } return g_resource_new_from_table (table); } diff --git a/gio/gschema.dtd b/gio/gschema.dtd index 8cd552d4a..1599f8de7 100644 --- a/gio/gschema.dtd +++ b/gio/gschema.dtd @@ -49,8 +49,8 @@ <!ELEMENT range EMPTY > <!-- min and max must be parseable as values of the key type and min must be less than or equal to max --> -<!ATTLIST range min CDATA #REQUIRED - max CDATA #REQUIRED > +<!ATTLIST range min CDATA #IMPLIED + max CDATA #IMPLIED > <!-- choices is only allowed for keys with string or string array type --> <!ELEMENT choices (choice+) > diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c index 17b7e3b01..38c9d78b9 100644 --- a/gio/gsettingsschema.c +++ b/gio/gsettingsschema.c @@ -231,7 +231,7 @@ g_settings_schema_source_unref (GSettingsSchemaSource *source) if (source->parent) g_settings_schema_source_unref (source->parent); - gvdb_table_unref (source->table); + gvdb_table_free (source->table); g_free (source->directory); if (source->text_tables) @@ -267,6 +267,9 @@ g_settings_schema_source_unref (GSettingsSchemaSource *source) * Generally, you should set @trusted to %TRUE for files installed by the * system and to %FALSE for files in the home directory. * + * In either case, an empty file or some types of corruption in the file will + * result in %G_FILE_ERROR_INVAL being returned. + * * If @parent is non-%NULL then there are two effects. * * First, if g_settings_schema_source_lookup() is called with the @@ -802,7 +805,7 @@ g_settings_schema_source_list_schemas (GSettingsSchemaSource *source, else g_hash_table_add (reloc, schema); - gvdb_table_unref (table); + gvdb_table_free (table); } } @@ -928,7 +931,7 @@ g_settings_schema_unref (GSettingsSchema *schema) g_settings_schema_unref (schema->extends); g_settings_schema_source_unref (schema->source); - gvdb_table_unref (schema->table); + gvdb_table_free (schema->table); g_free (schema->items); g_free (schema->id); @@ -1188,7 +1191,7 @@ g_settings_schema_list (GSettingsSchema *schema, g_hash_table_iter_remove (&iter); } - gvdb_table_unref (child_table); + gvdb_table_free (child_table); } /* Now create the list */ diff --git a/gio/gtask.c b/gio/gtask.c index df40357dd..4087543e6 100644 --- a/gio/gtask.c +++ b/gio/gtask.c @@ -52,7 +52,7 @@ * where it was created (waiting until the next iteration of the main * loop first, if necessary). The caller will pass the #GTask back to * the operation's finish function (as a #GAsyncResult), and you can - * can use g_task_propagate_pointer() or the like to extract the + * use g_task_propagate_pointer() or the like to extract the * return value. * * Here is an example for using GTask as a GAsyncResult: diff --git a/gio/gtestdbus.c b/gio/gtestdbus.c index 685503c5e..2fc2d51f5 100644 --- a/gio/gtestdbus.c +++ b/gio/gtestdbus.c @@ -179,7 +179,7 @@ watch_parent (gint fd) if (num_events == 0) continue; - if (fds[0].revents == G_IO_HUP) + if (fds[0].revents & G_IO_HUP) { /* Parent quit, cleanup the mess and exit */ for (n = 0; n < pids_to_kill->len; n++) diff --git a/gio/gthemedicon.c b/gio/gthemedicon.c index 3ada77b6c..35970deff 100644 --- a/gio/gthemedicon.c +++ b/gio/gthemedicon.c @@ -49,6 +49,7 @@ struct _GThemedIcon { GObject parent_instance; + char **init_names; char **names; gboolean use_default_fallbacks; }; @@ -66,6 +67,8 @@ enum PROP_USE_DEFAULT_FALLBACKS }; +static void g_themed_icon_update_names (GThemedIcon *themed); + G_DEFINE_TYPE_WITH_CODE (GThemedIcon, g_themed_icon, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_ICON, g_themed_icon_icon_iface_init)) @@ -81,7 +84,7 @@ g_themed_icon_get_property (GObject *object, switch (prop_id) { case PROP_NAMES: - g_value_set_boxed (value, icon->names); + g_value_set_boxed (value, icon->init_names); break; case PROP_USE_DEFAULT_FALLBACKS: @@ -111,12 +114,12 @@ g_themed_icon_set_property (GObject *object, if (!name) break; - if (icon->names) - g_strfreev (icon->names); + if (icon->init_names) + g_strfreev (icon->init_names); - icon->names = g_new (char *, 2); - icon->names[0] = g_strdup (name); - icon->names[1] = NULL; + icon->init_names = g_new (char *, 2); + icon->init_names[0] = g_strdup (name); + icon->init_names[1] = NULL; break; case PROP_NAMES: @@ -125,10 +128,10 @@ g_themed_icon_set_property (GObject *object, if (!names) break; - if (icon->names) - g_strfreev (icon->names); + if (icon->init_names) + g_strfreev (icon->init_names); - icon->names = names; + icon->init_names = names; break; case PROP_USE_DEFAULT_FALLBACKS: @@ -143,63 +146,7 @@ g_themed_icon_set_property (GObject *object, static void g_themed_icon_constructed (GObject *object) { - GThemedIcon *themed = G_THEMED_ICON (object); - - g_return_if_fail (themed->names != NULL && themed->names[0] != NULL); - - if (themed->use_default_fallbacks) - { - int i = 0, dashes = 0; - const char *p; - char *dashp; - char *last; - gboolean is_symbolic; - char *name; - char **names; - - is_symbolic = g_str_has_suffix (themed->names[0], "-symbolic"); - if (is_symbolic) - name = g_strndup (themed->names[0], strlen (themed->names[0]) - 9); - else - name = g_strdup (themed->names[0]); - - p = name; - while (*p) - { - if (*p == '-') - dashes++; - p++; - } - - last = name; - - g_strfreev (themed->names); - - names = g_new (char *, dashes + 1 + 1); - names[i++] = last; - - while ((dashp = strrchr (last, '-')) != NULL) - names[i++] = last = g_strndup (last, dashp - last); - - names[i++] = NULL; - - if (is_symbolic) - { - themed->names = g_new (char *, 2 * dashes + 3); - for (i = 0; names[i] != NULL; i++) - { - themed->names[i] = g_strconcat (names[i], "-symbolic", NULL); - themed->names[dashes + 1 + i] = names[i]; - } - - themed->names[dashes + 1 + i] = NULL; - g_free (names); - } - else - { - themed->names = names; - } - } + g_themed_icon_update_names (G_THEMED_ICON (object)); } static void @@ -209,6 +156,7 @@ g_themed_icon_finalize (GObject *object) themed = G_THEMED_ICON (object); + g_strfreev (themed->init_names); g_strfreev (themed->names); G_OBJECT_CLASS (g_themed_icon_parent_class)->finalize (object); @@ -278,7 +226,136 @@ g_themed_icon_class_init (GThemedIconClass *klass) static void g_themed_icon_init (GThemedIcon *themed) { - themed->names = NULL; + themed->init_names = NULL; + themed->names = NULL; +} + +/** + * g_themed_icon_update_names: + * @themed: a #GThemedIcon. + * + * Update the actual icon name list, based on the requested names (from + * construction, or later added with g_themed_icon_prepend_name() and + * g_themed_icon_append_name()). + * The order of the list matters, indicating priority: + * - The first requested icon is first in priority. + * - If "use-default-fallbacks" is #TRUE, then it is followed by all its + * fallbacks (starting from top to lower context levels). + * - Then next requested icons, and optionally their fallbacks, follow. + * - Finally all the style variants (symbolic or regular, opposite to whatever + * is the requested style) follow in the same order. + * + * An icon is not added twice in the list if it was previously added. + * + * For instance, if requested names are: + * [ "some-icon-symbolic", "some-other-icon" ] + * and use-default-fallbacks is TRUE, the final name list shall be: + * [ "some-icon-symbolic", "some-symbolic", "some-other-icon", + * "some-other", "some", "some-icon", "some-other-icon-symbolic", + * "some-other-symbolic" ] + * + * Returns: (transfer full) (type GThemedIcon): a new #GThemedIcon + **/ +static void +g_themed_icon_update_names (GThemedIcon *themed) +{ + GList *names = NULL; + GList *variants = NULL; + GList *iter; + guint i; + + g_return_if_fail (themed->init_names != NULL && themed->init_names[0] != NULL); + + for (i = 0; themed->init_names[i]; i++) + { + gchar *name; + gboolean is_symbolic; + + is_symbolic = g_str_has_suffix (themed->init_names[i], "-symbolic"); + if (is_symbolic) + name = g_strndup (themed->init_names[i], strlen (themed->init_names[i]) - 9); + else + name = g_strdup (themed->init_names[i]); + + if (g_list_find_custom (names, name, (GCompareFunc) g_strcmp0)) + { + g_free (name); + continue; + } + + if (is_symbolic) + names = g_list_prepend (names, g_strdup (themed->init_names[i])); + else + names = g_list_prepend (names, name); + + if (themed->use_default_fallbacks) + { + char *dashp; + char *last; + + last = name; + + while ((dashp = strrchr (last, '-')) != NULL) + { + gchar *tmp = last; + gchar *fallback; + + last = g_strndup (last, dashp - last); + if (is_symbolic) + { + g_free (tmp); + fallback = g_strdup_printf ("%s-symbolic", last); + } + else + fallback = last; + if (g_list_find_custom (names, fallback, (GCompareFunc) g_strcmp0)) + { + g_free (fallback); + break; + } + names = g_list_prepend (names, fallback); + } + if (is_symbolic) + g_free (last); + } + else if (is_symbolic) + g_free (name); + } + for (iter = names; iter; iter = iter->next) + { + gchar *name = (gchar *) iter->data; + gchar *variant; + gboolean is_symbolic; + + is_symbolic = g_str_has_suffix (name, "-symbolic"); + if (is_symbolic) + variant = g_strndup (name, strlen (name) - 9); + else + variant = g_strdup_printf ("%s-symbolic", name); + if (g_list_find_custom (names, variant, (GCompareFunc) g_strcmp0) || + g_list_find_custom (variants, variant, (GCompareFunc) g_strcmp0)) + { + g_free (variant); + continue; + } + + variants = g_list_prepend (variants, variant); + } + names = g_list_reverse (names); + + g_strfreev (themed->names); + themed->names = g_new (char *, g_list_length (names) + g_list_length (variants) + 1); + + for (iter = names, i = 0; iter; iter = iter->next, i++) + themed->names[i] = iter->data; + for (iter = variants; iter; iter = iter->next, i++) + themed->names[i] = iter->data; + themed->names[i] = NULL; + + g_list_free (names); + g_list_free (variants); + + g_object_notify (G_OBJECT (themed), "names"); } /** @@ -402,12 +479,12 @@ g_themed_icon_append_name (GThemedIcon *icon, g_return_if_fail (G_IS_THEMED_ICON (icon)); g_return_if_fail (iconname != NULL); - num_names = g_strv_length (icon->names); - icon->names = g_realloc (icon->names, sizeof (char*) * (num_names + 2)); - icon->names[num_names] = g_strdup (iconname); - icon->names[num_names + 1] = NULL; + num_names = g_strv_length (icon->init_names); + icon->init_names = g_realloc (icon->init_names, sizeof (char*) * (num_names + 2)); + icon->init_names[num_names] = g_strdup (iconname); + icon->init_names[num_names + 1] = NULL; - g_object_notify (G_OBJECT (icon), "names"); + g_themed_icon_update_names (icon); } /** @@ -433,17 +510,17 @@ g_themed_icon_prepend_name (GThemedIcon *icon, g_return_if_fail (G_IS_THEMED_ICON (icon)); g_return_if_fail (iconname != NULL); - num_names = g_strv_length (icon->names); + num_names = g_strv_length (icon->init_names); names = g_new (char*, num_names + 2); - for (i = 0; icon->names[i]; i++) - names[i + 1] = icon->names[i]; + for (i = 0; icon->init_names[i]; i++) + names[i + 1] = icon->init_names[i]; names[0] = g_strdup (iconname); names[num_names + 1] = NULL; - g_free (icon->names); - icon->names = names; + g_free (icon->init_names); + icon->init_names = names; - g_object_notify (G_OBJECT (icon), "names"); + g_themed_icon_update_names (icon); } static guint diff --git a/gio/gtlsclientconnection.c b/gio/gtlsclientconnection.c index f80c62572..b38fad630 100644 --- a/gio/gtlsclientconnection.c +++ b/gio/gtlsclientconnection.c @@ -105,14 +105,7 @@ g_tls_client_connection_default_init (GTlsClientConnectionInterface *iface) * * If %TRUE, forces the connection to use a fallback version of TLS * or SSL, rather than trying to negotiate the best version of TLS - * to use. This can be used when talking to servers that don't - * implement version negotiation correctly and therefore refuse to - * handshake at all with a modern TLS handshake. - * - * Despite the property name, the fallback version is usually not - * SSL 3.0, because SSL 3.0 is generally disabled by the #GTlsBackend. - * #GTlsClientConnection will use the next-highest available version - * as the fallback version. + * to use. See g_tls_client_connection_set_use_ssl3(). * * Since: 2.28 * @@ -304,14 +297,19 @@ g_tls_client_connection_get_use_ssl3 (GTlsClientConnection *conn) * @conn: the #GTlsClientConnection * @use_ssl3: whether to use the lowest-supported protocol version * - * If @use_ssl3 is %TRUE, this forces @conn to use the lowest-supported - * TLS protocol version rather than trying to properly negotiate the - * highest mutually-supported protocol version with the peer. This can - * be used when talking to broken TLS servers that exhibit protocol - * version intolerance. - * - * Be aware that SSL 3.0 is generally disabled by the #GTlsBackend, so - * the lowest-supported protocol version is probably not SSL 3.0. + * Since 2.42.1, if @use_ssl3 is %TRUE, this forces @conn to use the + * lowest-supported TLS protocol version rather than trying to properly + * negotiate the highest mutually-supported protocol version with the + * peer. Be aware that SSL 3.0 is generally disabled by the + * #GTlsBackend, so the lowest-supported protocol version is probably + * not SSL 3.0. + * + * Since 2.58, this may additionally cause an RFC 7507 fallback SCSV to + * be sent to the server, causing modern TLS servers to immediately + * terminate the connection. You should generally only use this function + * if you need to connect to broken servers that exhibit TLS protocol + * version intolerance, and when an initial attempt to connect to a + * server normally has already failed. * * Since: 2.28 * diff --git a/gio/gtlsconnection.c b/gio/gtlsconnection.c index e13d98614..b0353af9d 100644 --- a/gio/gtlsconnection.c +++ b/gio/gtlsconnection.c @@ -674,7 +674,8 @@ g_tls_connection_get_require_close_notify (GTlsConnection *conn) * @conn: a #GTlsConnection * @mode: the rehandshaking mode * - * Sets how @conn behaves with respect to rehandshaking requests. + * Sets how @conn behaves with respect to rehandshaking requests, when + * TLS 1.2 or older is in use. * * %G_TLS_REHANDSHAKE_NEVER means that it will never agree to * rehandshake after the initial handshake is complete. (For a client, @@ -756,7 +757,8 @@ g_tls_connection_get_rehandshake_mode (GTlsConnection *conn) * the beginning of the communication, you do not need to call this * function explicitly unless you want clearer error reporting. * However, you may call g_tls_connection_handshake() later on to - * renegotiate parameters (encryption methods, etc) with the client. + * rehandshake, if TLS 1.2 or older is in use. With TLS 1.3, this will + * instead perform a rekey. * * #GTlsConnection::accept_certificate may be emitted during the * handshake. diff --git a/gio/gunixvolume.c b/gio/gunixvolume.c index b54d1fd6e..a3768e11d 100644 --- a/gio/gunixvolume.c +++ b/gio/gunixvolume.c @@ -274,6 +274,7 @@ eject_mount_done (GObject *source, GTask *task = user_data; GError *error = NULL; gchar *stderr_str; + GUnixVolume *unix_volume; if (!g_subprocess_communicate_utf8_finish (subprocess, result, NULL, &stderr_str, &error)) { @@ -286,8 +287,12 @@ eject_mount_done (GObject *source, /* ...but bad exit code */ g_task_return_new_error (task, G_IO_ERROR, G_IO_ERROR_FAILED, "%s", stderr_str); else - /* ...and successful exit code */ - g_task_return_boolean (task, TRUE); + { + /* ...and successful exit code */ + unix_volume = G_UNIX_VOLUME (g_task_get_source_object (task)); + _g_unix_volume_monitor_update (G_UNIX_VOLUME_MONITOR (unix_volume->volume_monitor)); + g_task_return_boolean (task, TRUE); + } g_free (stderr_str); } diff --git a/gio/gunixvolumemonitor.c b/gio/gunixvolumemonitor.c index b7711ff52..4b99423d7 100644 --- a/gio/gunixvolumemonitor.c +++ b/gio/gunixvolumemonitor.c @@ -183,15 +183,21 @@ g_unix_volume_monitor_class_init (GUnixVolumeMonitorClass *klass) native_class->get_mount_for_mount_path = get_mount_for_mount_path; } +void +_g_unix_volume_monitor_update (GUnixVolumeMonitor *unix_monitor) +{ + /* Update both to make sure volumes are created before mounts */ + update_volumes (unix_monitor); + update_mounts (unix_monitor); +} + static void mountpoints_changed (GUnixMountMonitor *mount_monitor, gpointer user_data) { GUnixVolumeMonitor *unix_monitor = user_data; - /* Update both to make sure volumes are created before mounts */ - update_volumes (unix_monitor); - update_mounts (unix_monitor); + _g_unix_volume_monitor_update (unix_monitor); } static void @@ -200,9 +206,7 @@ mounts_changed (GUnixMountMonitor *mount_monitor, { GUnixVolumeMonitor *unix_monitor = user_data; - /* Update both to make sure volumes are created before mounts */ - update_volumes (unix_monitor); - update_mounts (unix_monitor); + _g_unix_volume_monitor_update (unix_monitor); } static void @@ -219,8 +223,7 @@ g_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor) "mountpoints-changed", G_CALLBACK (mountpoints_changed), unix_monitor); - update_volumes (unix_monitor); - update_mounts (unix_monitor); + _g_unix_volume_monitor_update (unix_monitor); } GVolumeMonitor * diff --git a/gio/gunixvolumemonitor.h b/gio/gunixvolumemonitor.h index 4f54fc23c..14e07fb9f 100644 --- a/gio/gunixvolumemonitor.h +++ b/gio/gunixvolumemonitor.h @@ -55,6 +55,7 @@ GType _g_unix_volume_monitor_get_type (void) G_GN GVolumeMonitor * _g_unix_volume_monitor_new (void); GUnixVolume * _g_unix_volume_monitor_lookup_volume_for_mount_path (GUnixVolumeMonitor *monitor, const char *mount_path); +void _g_unix_volume_monitor_update (GUnixVolumeMonitor *monitor); G_END_DECLS diff --git a/gio/gvdb/gvdb-builder.c b/gio/gvdb/gvdb-builder.c index 8b9baa007..2383e6002 100644 --- a/gio/gvdb/gvdb-builder.c +++ b/gio/gvdb/gvdb-builder.c @@ -339,6 +339,13 @@ file_builder_allocate_for_hash (FileBuilder *fb, #undef chunk memset (*bloom_filter, 0, n_bloom_words * sizeof (guint32_le)); + + /* NOTE - the code to actually fill in the bloom filter here is missing. + * Patches welcome! + * + * http://en.wikipedia.org/wiki/Bloom_filter + * http://0pointer.de/blog/projects/bloom.html + */ } static void diff --git a/gio/gvdb/gvdb-reader.c b/gio/gvdb/gvdb-reader.c index 510eba205..aa3154feb 100644 --- a/gio/gvdb/gvdb-reader.c +++ b/gio/gvdb/gvdb-reader.c @@ -23,15 +23,11 @@ #include <string.h> struct _GvdbTable { - gint ref_count; + GBytes *bytes; const gchar *data; gsize size; - gpointer user_data; - GvdbRefFunc ref_user_data; - GDestroyNotify unref_user_data; - gboolean byteswapped; gboolean trusted; @@ -124,80 +120,81 @@ gvdb_table_setup_root (GvdbTable *file, file->n_hash_items = size / sizeof (struct gvdb_hash_item); } -static GvdbTable * -new_from_data (const void *data, - gsize data_len, - gboolean trusted, - gpointer user_data, - GvdbRefFunc ref, - GDestroyNotify unref, - const char *filename, - GError **error) +/** + * gvdb_table_new_from_bytes: + * @bytes: the #GBytes with the data + * @trusted: if the contents of @bytes are trusted + * @error: %NULL, or a pointer to a %NULL #GError + * + * Creates a new #GvdbTable from the contents of @bytes. + * + * This call can fail if the header contained in @bytes is invalid or if @bytes + * is empty; if so, %G_FILE_ERROR_INVAL will be returned. + * + * You should call gvdb_table_free() on the return result when you no + * longer require it. + * + * Returns: a new #GvdbTable + **/ +GvdbTable * +gvdb_table_new_from_bytes (GBytes *bytes, + gboolean trusted, + GError **error) { + const struct gvdb_header *header; GvdbTable *file; file = g_slice_new0 (GvdbTable); - file->data = data; - file->size = data_len; + file->bytes = g_bytes_ref (bytes); + file->data = g_bytes_get_data (bytes, &file->size); file->trusted = trusted; - file->ref_count = 1; - file->ref_user_data = ref; - file->unref_user_data = unref; - file->user_data = user_data; - if (sizeof (struct gvdb_header) <= file->size) - { - const struct gvdb_header *header = (gpointer) file->data; + if (file->size < sizeof (struct gvdb_header)) + goto invalid; - if (header->signature[0] == GVDB_SIGNATURE0 && - header->signature[1] == GVDB_SIGNATURE1 && - guint32_from_le (header->version) == 0) - file->byteswapped = FALSE; + header = (gpointer) file->data; - else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 && - header->signature[1] == GVDB_SWAPPED_SIGNATURE1 && - guint32_from_le (header->version) == 0) - file->byteswapped = TRUE; + if (header->signature[0] == GVDB_SIGNATURE0 && + header->signature[1] == GVDB_SIGNATURE1 && + guint32_from_le (header->version) == 0) + file->byteswapped = FALSE; - else - { - if (filename) - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, - "%s: invalid header", filename); - else - g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, - "invalid gvdb header"); - g_slice_free (GvdbTable, file); - if (unref) - unref (user_data); - - return NULL; - } + else if (header->signature[0] == GVDB_SWAPPED_SIGNATURE0 && + header->signature[1] == GVDB_SWAPPED_SIGNATURE1 && + guint32_from_le (header->version) == 0) + file->byteswapped = TRUE; - gvdb_table_setup_root (file, &header->root); - } + else + goto invalid; + + gvdb_table_setup_root (file, &header->root); return file; + +invalid: + g_set_error_literal (error, G_FILE_ERROR, G_FILE_ERROR_INVAL, "invalid gvdb header"); + + g_bytes_unref (file->bytes); + + g_slice_free (GvdbTable, file); + + return NULL; } /** * gvdb_table_new: - * @filename: the path to the hash file - * @trusted: if the contents of @filename are trusted + * @filename: a filename + * @trusted: if the contents of @bytes are trusted * @error: %NULL, or a pointer to a %NULL #GError * - * Creates a new #GvdbTable from the contents of the file found at - * @filename. + * Creates a new #GvdbTable using the #GMappedFile for @filename as the + * #GBytes. * - * The only time this function fails is if the file cannot be opened. + * This function will fail if the file cannot be opened. * In that case, the #GError that is returned will be an error from * g_mapped_file_new(). * - * An empty or otherwise corrupted file is considered to be a valid - * #GvdbTable with no entries. - * - * You should call gvdb_table_unref() on the return result when you no - * longer require it. + * An empty or corrupt file will result in %G_FILE_ERROR_INVAL. * * Returns: a new #GvdbTable **/ @@ -207,53 +204,21 @@ gvdb_table_new (const gchar *filename, GError **error) { GMappedFile *mapped; + GvdbTable *table; + GBytes *bytes; - if ((mapped = g_mapped_file_new (filename, FALSE, error)) == NULL) + mapped = g_mapped_file_new (filename, FALSE, error); + if (!mapped) return NULL; - return new_from_data (g_mapped_file_get_contents (mapped), - g_mapped_file_get_length (mapped), - trusted, - mapped, - (GvdbRefFunc)g_mapped_file_ref, - (GDestroyNotify)g_mapped_file_unref, - filename, - error); -} + bytes = g_mapped_file_get_bytes (mapped); + table = gvdb_table_new_from_bytes (bytes, trusted, error); + g_mapped_file_unref (mapped); + g_bytes_unref (bytes); -/** - * gvdb_table_new_from_data: - * @data: the data - * @data_len: the length of @data in bytes - * @trusted: if the contents of @data are trusted - * @user_data: User supplied data that owns @data - * @ref: Ref function for @user_data - * @unref: Unref function for @user_data - * - * Creates a new #GvdbTable from the data in @data. - * - * An empty or otherwise corrupted data is considered to be a valid - * #GvdbTable with no entries. - * - * You should call gvdb_table_unref() on the return result when you no - * longer require it. - * - * Returns: a new #GvdbTable - **/ -GvdbTable * -gvdb_table_new_from_data (const void *data, - gsize data_len, - gboolean trusted, - gpointer user_data, - GvdbRefFunc ref, - GDestroyNotify unref, - GError **error) -{ - return new_from_data (data, data_len, - trusted, - user_data, ref, unref, - NULL, - error); + g_prefix_error (error, "%s: ", filename); + + return table; } static gboolean @@ -346,18 +311,6 @@ gvdb_table_lookup (GvdbTable *file, return NULL; } -static const struct gvdb_hash_item * -gvdb_table_get_item (GvdbTable *table, - guint32_le item_no) -{ - guint32 item_no_native = guint32_from_le (item_no); - - if G_LIKELY (item_no_native < table->n_hash_items) - return table->hash_items + item_no_native; - - return NULL; -} - static gboolean gvdb_table_list_from_item (GvdbTable *table, const struct gvdb_hash_item *item, @@ -376,6 +329,155 @@ gvdb_table_list_from_item (GvdbTable *table, return TRUE; } +/** + * gvdb_table_get_names: + * @table: a #GvdbTable + * @length: the number of items returned, or %NULL + * + * Gets a list of all names contained in @table. + * + * No call to gvdb_table_get_table(), gvdb_table_list() or + * gvdb_table_get_value() will succeed unless it is for one of the + * names returned by this function. + * + * Note that some names that are returned may still fail for all of the + * above calls in the case of the corrupted file. Note also that the + * returned strings may not be utf8. + * + * Returns: a %NULL-terminated list of strings, of length @length + **/ +gchar ** +gvdb_table_get_names (GvdbTable *table, + gint *length) +{ + gchar **names; + gint n_names; + gint filled; + gint total; + gint i; + + /* We generally proceed by iterating over the list of items in the + * hash table (in order of appearance) recording them into an array. + * + * Each item has a parent item (except root items). The parent item + * forms part of the name of the item. We could go fetching the + * parent item chain at the point that we encounter each item but then + * we would need to implement some sort of recursion along with checks + * for self-referential items. + * + * Instead, we do a number of passes. Each pass will build up one + * level of names (starting from the root). We continue to do passes + * until no more items are left. The first pass will only add root + * items and each further pass will only add items whose direct parent + * is an item added in the immediately previous pass. It's also + * possible that items get filled if they follow their parent within a + * particular pass. + * + * At most we will have a number of passes equal to the depth of the + * tree. Self-referential items will never be filled in (since their + * parent will have never been filled in). We continue until we have + * a pass that fills in no additional items. + * + * This takes an O(n) algorithm and turns it into O(n*m) where m is + * the depth of the tree, but in all sane cases the tree won't be very + * deep and the constant factor of this algorithm is lower (and the + * complexity of coding it, as well). + */ + + n_names = table->n_hash_items; + names = g_new0 (gchar *, n_names + 1); + + /* 'names' starts out all-NULL. On each pass we record the number + * of items changed from NULL to non-NULL in 'filled' so we know if we + * should repeat the loop. 'total' counts the total number of items + * filled. If 'total' ends up equal to 'n_names' then we know that + * 'names' has been completely filled. + */ + + total = 0; + do + { + /* Loop until we have filled no more entries */ + filled = 0; + + for (i = 0; i < n_names; i++) + { + const struct gvdb_hash_item *item = &table->hash_items[i]; + const gchar *name; + gsize name_length; + guint32 parent; + + /* already got it on a previous pass */ + if (names[i] != NULL) + continue; + + parent = guint32_from_le (item->parent); + + if (parent == 0xffffffffu) + { + /* it's a root item */ + name = gvdb_table_item_get_key (table, item, &name_length); + + if (name != NULL) + { + names[i] = g_strndup (name, name_length); + filled++; + } + } + + else if (parent < n_names && names[parent] != NULL) + { + /* It's a non-root item whose parent was filled in already. + * + * Calculate the name of this item by combining it with + * its parent name. + */ + name = gvdb_table_item_get_key (table, item, &name_length); + + if (name != NULL) + { + const gchar *parent_name = names[parent]; + gsize parent_length; + gchar *fullname; + + parent_length = strlen (parent_name); + fullname = g_malloc (parent_length + name_length + 1); + memcpy (fullname, parent_name, parent_length); + memcpy (fullname + parent_length, name, name_length); + fullname[parent_length + name_length] = '\0'; + names[i] = fullname; + filled++; + } + } + } + + total += filled; + } + while (filled && total < n_names); + + /* If the table was corrupted then 'names' may have holes in it. + * Collapse those. + */ + if G_UNLIKELY (total != n_names) + { + GPtrArray *fixed_names; + + fixed_names = g_ptr_array_new (); + for (i = 0; i < n_names; i++) + if (names[i] != NULL) + g_ptr_array_add (fixed_names, names[i]); + + g_free (names); + n_names = fixed_names->len; + g_ptr_array_add (fixed_names, NULL); + names = (gchar **) g_ptr_array_free (fixed_names, FALSE); + } + + if (length) + *length = n_names; + + return names; +} /** * gvdb_table_list: @@ -457,7 +559,15 @@ gboolean gvdb_table_has_value (GvdbTable *file, const gchar *key) { - return gvdb_table_lookup (file, key, 'v') != NULL; + static const struct gvdb_hash_item *item; + gsize size; + + item = gvdb_table_lookup (file, key, 'v'); + + if (item == NULL) + return FALSE; + + return gvdb_table_dereference (file, &item->value.pointer, 8, &size) != NULL; } static GVariant * @@ -466,6 +576,7 @@ gvdb_table_value_from_item (GvdbTable *table, { GVariant *variant, *value; gconstpointer data; + GBytes *bytes; gsize size; data = gvdb_table_dereference (table, &item->value.pointer, 8, &size); @@ -473,12 +584,11 @@ gvdb_table_value_from_item (GvdbTable *table, if G_UNLIKELY (data == NULL) return NULL; - variant = g_variant_new_from_data (G_VARIANT_TYPE_VARIANT, - data, size, table->trusted, - table->unref_user_data, - table->ref_user_data ? table->ref_user_data (table->user_data) : table->user_data); + bytes = g_bytes_new_from_bytes (table->bytes, ((gchar *) data) - table->data, size); + variant = g_variant_new_from_bytes (G_VARIANT_TYPE_VARIANT, bytes, table->trusted); value = g_variant_get_variant (variant); g_variant_unref (variant); + g_bytes_unref (bytes); return value; } @@ -562,7 +672,7 @@ gvdb_table_get_raw_value (GvdbTable *table, * contained in the file. This newly-created #GvdbTable does not depend * on the continued existence of @file. * - * You should call gvdb_table_unref() on the return result when you no + * You should call gvdb_table_free() on the return result when you no * longer require it. * * Returns: a new #GvdbTable, or %NULL @@ -580,14 +690,11 @@ gvdb_table_get_table (GvdbTable *file, return NULL; new = g_slice_new0 (GvdbTable); - new->user_data = file->ref_user_data ? file->ref_user_data (file->user_data) : file->user_data; - new->ref_user_data = file->ref_user_data; - new->unref_user_data = file->unref_user_data; + new->bytes = g_bytes_ref (file->bytes); new->byteswapped = file->byteswapped; new->trusted = file->trusted; new->data = file->data; new->size = file->size; - new->ref_count = 1; gvdb_table_setup_root (new, &item->value.pointer); @@ -595,38 +702,16 @@ gvdb_table_get_table (GvdbTable *file, } /** - * gvdb_table_ref: + * gvdb_table_free: * @file: a #GvdbTable * - * Increases the reference count on @file. - * - * Returns: a new reference on @file - **/ -GvdbTable * -gvdb_table_ref (GvdbTable *file) -{ - g_atomic_int_inc (&file->ref_count); - - return file; -} - -/** - * gvdb_table_unref: - * @file: a #GvdbTable - * - * Decreases the reference count on @file, possibly freeing it. - * - * Since: 2.26 + * Frees @file. **/ void -gvdb_table_unref (GvdbTable *file) +gvdb_table_free (GvdbTable *file) { - if (g_atomic_int_dec_and_test (&file->ref_count)) - { - if (file->unref_user_data) - file->unref_user_data (file->user_data); - g_slice_free (GvdbTable, file); - } + g_bytes_unref (file->bytes); + g_slice_free (GvdbTable, file); } /** @@ -646,105 +731,3 @@ gvdb_table_is_valid (GvdbTable *table) { return !!*table->data; } - -/** - * gvdb_table_walk: - * @table: a #GvdbTable - * @key: a key corresponding to a list - * @open_func: the #GvdbWalkOpenFunc - * @value_func: the #GvdbWalkValueFunc - * @close_func: the #GvdbWalkCloseFunc - * @user_data: data to pass to the callbacks - * - * Looks up the list at @key and iterate over the items in it. - * - * First, @open_func is called to signal that we are starting to iterate over - * the list. Then the list is iterated. When all items in the list have been - * iterated over, the @close_func is called. - * - * When iterating, if a given item in the list is a value then @value_func is - * called. - * - * If a given item in the list is itself a list then @open_func is called. If - * that function returns %TRUE then the walk begins iterating the items in the - * sublist, until there are no more items, at which point a matching - * @close_func call is made. If @open_func returns %FALSE then no iteration of - * the sublist occurs and no corresponding @close_func call is made. - **/ -void -gvdb_table_walk (GvdbTable *table, - const gchar *key, - GvdbWalkOpenFunc open_func, - GvdbWalkValueFunc value_func, - GvdbWalkCloseFunc close_func, - gpointer user_data) -{ - const struct gvdb_hash_item *item; - const guint32_le *pointers[64]; - const guint32_le *enders[64]; - gsize name_lengths[64]; - gint index = 0; - - item = gvdb_table_lookup (table, key, 'L'); - name_lengths[0] = 0; - pointers[0] = NULL; - enders[0] = NULL; - goto start_here; - - while (index) - { - close_func (name_lengths[index], user_data); - index--; - - while (pointers[index] < enders[index]) - { - const gchar *name; - gsize name_len; - - item = gvdb_table_get_item (table, *pointers[index]++); - start_here: - - if (item != NULL && - (name = gvdb_table_item_get_key (table, item, &name_len))) - { - if (item->type == 'L') - { - if (open_func (name, name_len, user_data)) - { - guint length = 0; - - index++; - g_assert (index < 64); - - gvdb_table_list_from_item (table, item, - &pointers[index], - &length); - enders[index] = pointers[index] + length; - name_lengths[index] = name_len; - } - } - else if (item->type == 'v') - { - GVariant *value; - - value = gvdb_table_value_from_item (table, item); - - if (value != NULL) - { - if (table->byteswapped) - { - GVariant *tmp; - - tmp = g_variant_byteswap (value); - g_variant_unref (value); - value = tmp; - } - - value_func (name, name_len, value, user_data); - g_variant_unref (value); - } - } - } - } - } -} diff --git a/gio/gvdb/gvdb-reader.h b/gio/gvdb/gvdb-reader.h index 449241eaa..39827737d 100644 --- a/gio/gvdb/gvdb-reader.h +++ b/gio/gvdb/gvdb-reader.h @@ -24,27 +24,21 @@ typedef struct _GvdbTable GvdbTable; -typedef gpointer (*GvdbRefFunc) (gpointer data); - G_BEGIN_DECLS G_GNUC_INTERNAL -GvdbTable * gvdb_table_new (const gchar *filename, +GvdbTable * gvdb_table_new_from_bytes (GBytes *bytes, gboolean trusted, GError **error); G_GNUC_INTERNAL -GvdbTable * gvdb_table_new_from_data (const void *data, - gsize data_len, +GvdbTable * gvdb_table_new (const gchar *filename, gboolean trusted, - gpointer user_data, - GvdbRefFunc ref, - GDestroyNotify unref, - GError **error); + GError **error); G_GNUC_INTERNAL -GvdbTable * gvdb_table_ref (GvdbTable *table); +void gvdb_table_free (GvdbTable *table); G_GNUC_INTERNAL -void gvdb_table_unref (GvdbTable *table); - +gchar ** gvdb_table_get_names (GvdbTable *table, + gint *length); G_GNUC_INTERNAL gchar ** gvdb_table_list (GvdbTable *table, const gchar *key); @@ -61,28 +55,9 @@ GVariant * gvdb_table_get_value (GvdbTab G_GNUC_INTERNAL gboolean gvdb_table_has_value (GvdbTable *table, const gchar *key); - G_GNUC_INTERNAL gboolean gvdb_table_is_valid (GvdbTable *table); -typedef void (*GvdbWalkValueFunc) (const gchar *name, - gsize name_len, - GVariant *value, - gpointer user_data); -typedef gboolean (*GvdbWalkOpenFunc) (const gchar *name, - gsize name_len, - gpointer user_data); -typedef void (*GvdbWalkCloseFunc) (gsize name_len, - gpointer user_data); - -G_GNUC_INTERNAL -void gvdb_table_walk (GvdbTable *table, - const gchar *key, - GvdbWalkOpenFunc open_func, - GvdbWalkValueFunc value_func, - GvdbWalkCloseFunc close_func, - gpointer user_data); - G_END_DECLS #endif /* __gvdb_reader_h__ */ diff --git a/gio/gvdb/gvdb.doap b/gio/gvdb/gvdb.doap index b4ae60c8c..8c5f3e802 100644 --- a/gio/gvdb/gvdb.doap +++ b/gio/gvdb/gvdb.doap @@ -23,9 +23,34 @@ <maintainer> <foaf:Person> - <foaf:name>Ryan Lortie</foaf:name> - <foaf:mbox rdf:resource='mailto:desrt@desrt.ca'/> - <gnome:userid>ryanl</gnome:userid> + <foaf:name>Matthias Clasen</foaf:name> + <foaf:mbox rdf:resource="mailto:mclasen@redhat.com"/> + <gnome:userid>matthiasc</gnome:userid> + </foaf:Person> + </maintainer> + + <maintainer> + <foaf:Person> + <foaf:name>Allison Ryan Lortie</foaf:name> + <foaf:mbox rdf:resource="mailto:desrt@desrt.ca"/> + <gnome:userid>desrt</gnome:userid> + </foaf:Person> + </maintainer> + + <maintainer> + <foaf:Person> + <foaf:name>Philip Withnall</foaf:name> + <foaf:mbox rdf:resource="mailto:philip@tecnocode.co.uk"/> + <foaf:mbox rdf:resource="mailto:withnall@endlessm.com"/> + <gnome:userid>pwithnall</gnome:userid> + </foaf:Person> + </maintainer> + + <maintainer> + <foaf:Person> + <foaf:name>Emmanuele Bassi</foaf:name> + <foaf:mbox rdf:resource="mailto:ebassi@gnome.org"/> + <gnome:userid>ebassi</gnome:userid> </foaf:Person> </maintainer> diff --git a/gio/meson.build b/gio/meson.build index a6af822b5..4b2c8f2ca 100644 --- a/gio/meson.build +++ b/gio/meson.build @@ -152,6 +152,11 @@ if host_system != 'windows' glib_conf.set('HAVE_SIOCGIFADDR', '/**/') endif +endif + +if host_system.contains('android') + # struct ip_mreq_source definition is broken on Android NDK <= r16 + # See https://bugzilla.gnome.org/show_bug.cgi?id=740791 if not cc.compiles('''#include <netinet/in.h> int main(int argc, char ** argv) { struct ip_mreq_source mc_req_src; @@ -161,7 +166,6 @@ if host_system != 'windows' name : 'ip_mreq_source.imr_interface has s_addr member') glib_conf.set('BROKEN_IP_MREQ_SOURCE_STRUCT', 1) endif - endif gnetworking_h_conf.set('WSPIAPI_INCLUDE', gnetworking_h_wspiapi_include) diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index e3e8da05a..1f0bed7b6 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -383,7 +383,10 @@ CLEANFILES += \ org.gtk.test.enums.xml \ gsettings.store \ gschemas.compiled \ - schema-source/gschemas.compiled + schema-source/gschemas.compiled \ + schema-source-corrupt/gschemas.compiled \ + schema-source-empty/gschemas.compiled \ + $(NULL) test_programs += gdbus-connection-flush gdbus_connection_flush_SOURCES = \ diff --git a/gio/tests/g-icon.c b/gio/tests/g-icon.c index 598ae94b8..7f87e4952 100644 --- a/gio/tests/g-icon.c +++ b/gio/tests/g-icon.c @@ -108,9 +108,18 @@ test_g_icon_to_string (void) g_object_unref (location); #endif + icon = g_themed_icon_new_with_default_fallbacks ("some-icon-symbolic"); + g_themed_icon_append_name (G_THEMED_ICON (icon), "some-other-icon"); + data = g_icon_to_string (icon); + g_assert_cmpstr (data, ==, ". GThemedIcon " + "some-icon-symbolic some-symbolic some-other-icon some-other some " + "some-icon some-other-icon-symbolic some-other-symbolic"); + g_free (data); + g_object_unref (icon); + icon = g_themed_icon_new ("network-server"); data = g_icon_to_string (icon); - g_assert_cmpstr (data, ==, "network-server"); + g_assert_cmpstr (data, ==, ". GThemedIcon network-server network-server-symbolic"); icon2 = g_icon_new_for_string (data, &error); g_assert_no_error (error); g_assert (g_icon_equal (icon, icon2)); @@ -371,7 +380,7 @@ test_themed_icon (void) { GIcon *icon1, *icon2, *icon3, *icon4; const gchar *const *names; - const gchar *names2[] = { "first", "testicon", "last", NULL }; + const gchar *names2[] = { "first-symbolic", "testicon", "last", NULL }; gchar *str; gboolean fallbacks; GVariant *variant; @@ -382,17 +391,21 @@ test_themed_icon (void) g_assert (!fallbacks); names = g_themed_icon_get_names (G_THEMED_ICON (icon1)); - g_assert_cmpint (g_strv_length ((gchar **)names), ==, 1); + g_assert_cmpint (g_strv_length ((gchar **)names), ==, 2); g_assert_cmpstr (names[0], ==, "testicon"); + g_assert_cmpstr (names[1], ==, "testicon-symbolic"); - g_themed_icon_prepend_name (G_THEMED_ICON (icon1), "first"); + g_themed_icon_prepend_name (G_THEMED_ICON (icon1), "first-symbolic"); g_themed_icon_append_name (G_THEMED_ICON (icon1), "last"); names = g_themed_icon_get_names (G_THEMED_ICON (icon1)); - g_assert_cmpint (g_strv_length ((gchar **)names), ==, 3); - g_assert_cmpstr (names[0], ==, "first"); + g_assert_cmpint (g_strv_length ((gchar **)names), ==, 6); + g_assert_cmpstr (names[0], ==, "first-symbolic"); g_assert_cmpstr (names[1], ==, "testicon"); g_assert_cmpstr (names[2], ==, "last"); - g_assert_cmpuint (g_icon_hash (icon1), ==, 2400773466U); + g_assert_cmpstr (names[3], ==, "first"); + g_assert_cmpstr (names[4], ==, "testicon-symbolic"); + g_assert_cmpstr (names[5], ==, "last-symbolic"); + g_assert_cmpuint (g_icon_hash (icon1), ==, 1812785139); icon2 = g_themed_icon_new_from_names ((gchar**)names2, -1); g_assert (g_icon_equal (icon1, icon2)); @@ -448,11 +461,11 @@ test_emblemed_icon (void) emblem = emblems->data; g_assert (g_emblem_get_icon (emblem) == icon2); - g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_TAG); + g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_UNKNOWN); emblem = emblems->next->data; g_assert (g_emblem_get_icon (emblem) == icon2); - g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_UNKNOWN); + g_assert (g_emblem_get_origin (emblem) == G_EMBLEM_ORIGIN_TAG); g_emblemed_icon_clear_emblems (G_EMBLEMED_ICON (icon4)); g_assert (g_emblemed_icon_get_emblems (G_EMBLEMED_ICON (icon4)) == NULL); diff --git a/gio/tests/gdbus-unix-addresses.c b/gio/tests/gdbus-unix-addresses.c index 746a7c2a7..531ce7a85 100644 --- a/gio/tests/gdbus-unix-addresses.c +++ b/gio/tests/gdbus-unix-addresses.c @@ -128,6 +128,7 @@ test_x11_autolaunch (void) g_unsetenv ("DISPLAY"); g_unsetenv ("DBUS_SESSION_BUS_ADDRESS"); g_unsetenv ("XDG_RUNTIME_DIR"); + g_unsetenv ("G_MESSAGES_DEBUG"); set_up_mock_dbus_launch (); print_address (); diff --git a/gio/tests/gnotification.c b/gio/tests/gnotification.c index c896af684..80d476d5a 100644 --- a/gio/tests/gnotification.c +++ b/gio/tests/gnotification.c @@ -219,7 +219,8 @@ test_properties (void) g_assert (G_IS_THEMED_ICON (rn->icon)); names = g_themed_icon_get_names (G_THEMED_ICON (rn->icon)); g_assert_cmpstr (names[0], ==, "i-c-o-n"); - g_assert (names[1] == NULL); + g_assert_cmpstr (names[1], ==, "i-c-o-n-symbolic"); + g_assert_null (names[2]); g_assert (rn->priority == G_NOTIFICATION_PRIORITY_HIGH); g_assert_cmpint (rn->buttons->len, ==, 1); diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index 2d18d4dd2..852a8b710 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -2353,6 +2353,18 @@ test_schema_source (void) g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT); g_clear_error (&error); + /* Test error handling of corrupt compiled files. */ + source = g_settings_schema_source_new_from_directory ("schema-source-corrupt", parent, TRUE, &error); + g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL); + g_assert_null (source); + g_clear_error (&error); + + /* Test error handling of empty compiled files. */ + source = g_settings_schema_source_new_from_directory ("schema-source-empty", parent, TRUE, &error); + g_assert_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL); + g_assert_null (source); + g_clear_error (&error); + /* create a source with the parent */ source = g_settings_schema_source_new_from_directory ("schema-source", parent, TRUE, &error); g_assert_no_error (error); @@ -2770,6 +2782,12 @@ main (int argc, char *argv[]) if (!g_test_subprocess ()) { + GError *local_error = NULL; + /* A GVDB header is 6 guint32s, and requires a magic number in the first + * two guint32s. A set of zero bytes of a greater length is considered + * corrupt. */ + const guint8 gschemas_compiled_corrupt[sizeof (guint32) * 7] = { 0, }; + backend_set = g_getenv ("GSETTINGS_BACKEND") != NULL; g_setenv ("XDG_DATA_DIRS", ".", TRUE); @@ -2821,6 +2839,21 @@ main (int argc, char *argv[]) "--schema-file=" SRCDIR "/org.gtk.schemasourcecheck.gschema.xml", NULL, NULL, &result, NULL)); g_assert (result == 0); + + g_remove ("schema-source-corrupt/gschemas.compiled"); + g_mkdir ("schema-source-corrupt", 0777); + g_file_set_contents ("schema-source-corrupt/gschemas.compiled", + (const gchar *) gschemas_compiled_corrupt, + sizeof (gschemas_compiled_corrupt), + &local_error); + g_assert_no_error (local_error); + + g_remove ("schema-source-empty/gschemas.compiled"); + g_mkdir ("schema-source-empty", 0777); + g_file_set_contents ("schema-source-empty/gschemas.compiled", + "", 0, + &local_error); + g_assert_no_error (local_error); } g_test_add_func ("/gsettings/basic", test_basic); diff --git a/gio/tests/meson.build b/gio/tests/meson.build index 85d31d622..4e5ad25df 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -15,69 +15,67 @@ giotypefuncs_inc = custom_target( command: [gengiotypefuncs_prog, '@OUTPUT@', '@INPUT@']) # Test programs buildable on all platforms -gio_tests = [ - 'appmonitor', - 'async-close-output-stream', - 'async-splice-output-stream', - 'buffered-input-stream', - 'buffered-output-stream', - 'cancellable', - 'contexts', - 'contenttype', - 'converter-stream', - 'credentials', - 'data-input-stream', - 'data-output-stream', - 'defaultvalue', - 'fileattributematcher', - 'filter-streams', - 'giomodule', - 'gsubprocess', - 'g-file', - 'g-file-info', - 'g-icon', - 'gdbus-addresses', - 'gdbus-message', - 'inet-address', - 'io-stream', - 'memory-input-stream', - 'memory-output-stream', - 'monitor', - 'mount-operation', - 'network-address', - 'network-monitor', - 'network-monitor-race', - 'permission', - 'pollable', - 'proxy-test', - 'readwrite', - 'simple-async-result', - 'simple-proxy', - 'sleepy-stream', - 'socket', - 'socket-listener', - 'socket-service', - 'srvtarget', - 'task', - 'vfs', - 'volumemonitor', - 'glistmodel', - 'testfilemonitor', - 'thumbnail-verification', - 'tls-certificate', - 'tls-interaction', -] -slow_tests = [ - 'actions', - 'gdbus-export', - 'gdbus-threading', - 'testfilemonitor', -] - -test_extra_programs = [ - ['gdbus-connection-flush-helper'], - ['gdbus-testserver'], -] +# FIXME: We are using list of dictionnaries until we can depend on Meson 0.48.0 +# that supports '+=' operator on dictionnaries. +gio_tests = [{ + 'appmonitor' : {}, + 'async-close-output-stream' : {}, + 'async-splice-output-stream' : {}, + 'buffered-input-stream' : {}, + 'buffered-output-stream' : {}, + 'cancellable' : {}, + 'contexts' : {}, + 'contenttype' : {}, + 'converter-stream' : {}, + 'credentials' : {}, + 'data-input-stream' : {}, + 'data-output-stream' : {}, + 'defaultvalue' : {'extra_sources' : [giotypefuncs_inc]}, + 'fileattributematcher' : {}, + 'filter-streams' : {}, + 'giomodule' : {}, + 'gsubprocess' : {}, + 'g-file' : {}, + 'g-file-info' : {}, + 'g-icon' : {}, + 'gdbus-addresses' : {}, + 'gdbus-message' : {}, + 'inet-address' : {}, + 'io-stream' : {}, + 'memory-input-stream' : {}, + 'memory-output-stream' : {}, + 'monitor' : {}, + 'mount-operation' : {}, + 'network-address' : {}, + 'network-monitor' : {}, + 'network-monitor-race' : {}, + 'permission' : {}, + 'pollable' : {}, + 'proxy-test' : {}, + 'readwrite' : {}, + 'simple-async-result' : {}, + 'simple-proxy' : {}, + 'sleepy-stream' : {}, + 'socket' : {}, + 'socket-listener' : {}, + 'socket-service' : {}, + 'srvtarget' : {}, + 'task' : {}, + 'vfs' : {}, + 'volumemonitor' : {}, + 'glistmodel' : {}, + 'testfilemonitor' : {'suite' : ['slow']}, + 'thumbnail-verification' : {}, + 'tls-certificate' : {'extra_sources' : ['gtesttlsbackend.c']}, + 'tls-interaction' : {'extra_sources' : ['gtesttlsbackend.c']}, +}] + +# FIXME: We are using list of dictionnaries until we can depend on Meson 0.48.0 +# that supports '+=' operator on dictionnaries. +test_extra_programs = [{ + 'gdbus-connection-flush-helper' : {}, + 'gdbus-testserver' : {}, +}] test_env = environment() test_env.set('G_TEST_SRCDIR', meson.current_source_dir()) @@ -110,49 +108,57 @@ endif if dbus1_dep.found() glib_conf.set('HAVE_DBUS1', 1) - exe = executable('gdbus-serialization', - 'gdbus-serialization.c', 'gdbus-tests.c', - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps + [dbus1_dep]) - test('gdbus-serialization', exe, env : test_env, suite : ['gio']) + gio_tests += [{ + 'gdbus-serialization' : { + 'extra_sources' : ['gdbus-tests.c'], + 'dependencies' : [dbus1_dep], + } + }] endif # Test programs buildable on UNIX only if host_machine.system() != 'windows' - gio_tests += [ - 'file', - 'gdbus-peer', - 'gdbus-peer-object-manager', - 'live-g-file', - 'socket-address', - 'stream-rw_all', - 'unix-fd', - 'unix-mounts', - 'unix-streams', - 'g-file-info-filesystem-readonly', - 'gschema-compile', - 'trash', - ] + gio_tests += [{ + 'file' : {}, + 'gdbus-peer' : {'dependencies' : [libgdbus_example_objectmanager_dep]}, + 'gdbus-peer-object-manager' : {}, + 'live-g-file' : {}, + 'socket-address' : {}, + 'stream-rw_all' : {}, + 'unix-fd' : {}, + 'unix-mounts' : {}, + 'unix-streams' : {}, + 'g-file-info-filesystem-readonly' : {}, + 'gschema-compile' : {'install' : false}, + 'trash' : {}, + }] # Uninstalled because of the check-for-executable logic in DesktopAppInfo # unable to find the installed executable if not glib_have_cocoa - gio_tests += [ - 'appinfo', - 'desktop-app-info', - ] + gio_tests += [{ + 'appinfo' : { + 'install' : false, + }, + 'desktop-app-info' : { + 'install' : false, + }, + }] endif - test_extra_programs += [ - ['basic-application'], - ['dbus-launch'], - ['appinfo-test'], - ] + test_extra_programs += [{ + 'basic-application' : {}, + 'dbus-launch' : {}, + 'appinfo-test' : {}, + }] if not glib_have_cocoa - test_extra_programs += [['apps']] - gio_tests += ['mimeapps'] + test_extra_programs += [{ + 'apps' : {}, + }] + gio_tests += [{ + 'mimeapps' : {}, + }] endif # Test programs that need to bring up a session bus (requires dbus-daemon) @@ -181,71 +187,61 @@ if host_machine.system() != 'windows' '--annotate', 'org.project.Bar::TestSignal[array_of_strings]', 'Key8', 'Value8', '@INPUT@']) - gio_dbus_tests = [ - ['actions', [], []], - ['gdbus-auth', [], []], - ['gdbus-bz627724', [], []], - ['gdbus-close-pending', [], []], - ['gdbus-connection', [], []], - ['gdbus-connection-loss', [], []], - ['gdbus-connection-slow', [], []], - ['gdbus-error', [], []], - ['gdbus-exit-on-close', [], []], - ['gdbus-export', [], []], - ['gdbus-introspection', [], []], - ['gdbus-names', [], []], - ['gdbus-proxy', [], []], - ['gdbus-proxy-threads', [], [dbus1_dep]], - ['gdbus-proxy-well-known-name', [], []], - ['gdbus-test-codegen', [gdbus_test_codegen_generated], []], - ['gdbus-threading', [], []], - ['gmenumodel', [], []], - ['gnotification', ['gnotification-server.c'], []], - ] + extra_sources = ['gdbus-sessionbus.c', 'gdbus-tests.c'] + + gio_tests += [{ + 'actions' : { + 'extra_sources' : extra_sources, + 'suite' : ['slow'], + }, + 'gdbus-auth' : {'extra_sources' : extra_sources}, + 'gdbus-bz627724' : {'extra_sources' : extra_sources}, + 'gdbus-close-pending' : {'extra_sources' : extra_sources}, + 'gdbus-connection' : {'extra_sources' : extra_sources}, + 'gdbus-connection-loss' : {'extra_sources' : extra_sources}, + 'gdbus-connection-slow' : {'extra_sources' : extra_sources}, + 'gdbus-error' : {'extra_sources' : extra_sources}, + 'gdbus-exit-on-close' : {'extra_sources' : extra_sources}, + 'gdbus-export' : { + 'extra_sources' : extra_sources, + 'suite' : ['slow'], + }, + 'gdbus-introspection' : {'extra_sources' : extra_sources}, + 'gdbus-names' : {'extra_sources' : extra_sources}, + 'gdbus-proxy' : {'extra_sources' : extra_sources}, + 'gdbus-proxy-threads' : { + 'extra_sources' : extra_sources, + 'dependencies' : [dbus1_dep], + }, + 'gdbus-proxy-well-known-name' : {'extra_sources' : extra_sources}, + 'gdbus-test-codegen' : { + 'extra_sources' : [extra_sources, gdbus_test_codegen_generated], + }, + 'gdbus-threading' : { + 'extra_sources' : extra_sources, + 'suite' : ['slow'], + }, + 'gmenumodel' : {'extra_sources' : extra_sources}, + 'gnotification' : { + 'extra_sources' : [extra_sources, 'gnotification-server.c'], + }, + 'gdbus-test-codegen-old' : { + 'source' : 'gdbus-test-codegen.c', + 'extra_sources' : [extra_sources, gdbus_test_codegen_generated], + 'c_args' : ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36', + '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36'], + }, + 'gapplication' : {'extra_sources' : extra_sources}, + 'gdbus-unix-addresses' : {}, + }] if not glib_have_cocoa - gio_dbus_tests += [['dbus-appinfo', [], []]] + gio_tests += [{ + 'dbus-appinfo' : { + 'extra_sources' : extra_sources, + }, + }] endif - - # separate loop because extra source files for each test - foreach dbus_test : gio_dbus_tests - test_name = dbus_test[0] - extra_src = dbus_test[1] - extra_deps = dbus_test[2] - exe = executable(test_name, '@0@.c'.format(test_name), - 'gdbus-sessionbus.c', 'gdbus-tests.c', extra_src, - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps + extra_deps) - # These tests may take more than 30 seconds to run on the CI infrastructure - if slow_tests.contains(test_name) - test(test_name, exe, env : test_env, timeout : 120, suite : ['gio', 'slow']) - else - test(test_name, exe, env : test_env, suite : ['gio']) - endif - endforeach - - exe = executable('gdbus-test-codegen-old', 'gdbus-test-codegen.c', - 'gdbus-sessionbus.c', 'gdbus-tests.c', gdbus_test_codegen_generated, - install : false, - c_args : test_c_args + ['-DGLIB_VERSION_MIN_REQUIRED=GLIB_VERSION_2_36', '-DGLIB_VERSION_MAX_ALLOWED=GLIB_VERSION_2_36'], - dependencies : common_gio_tests_deps) - test('gdbus-test-codegen-old', exe, env : test_env, suite : ['gio']) - - # There is already a gapplication exe target in gio so need to use a - # different name for the unit test executable, since we can't have two - # targets of the same name even if in different directories - # (FIXME: just rename source file to gapplication-test.c) - if not glib_have_cocoa - exe = executable('gapplication-test', 'gapplication.c', - 'gdbus-sessionbus.c', 'gdbus-tests.c', - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps) - endif - test('gapplication', exe, env : test_env, suite : ['gio']) - - gio_tests += ['gdbus-unix-addresses'] endif # have_dbus_daemon # This test is currently unreliable @@ -254,125 +250,100 @@ if host_machine.system() != 'windows' c_args : test_c_args, dependencies : common_gio_tests_deps) - exe = executable('gdbus-connection-flush', 'gdbus-connection-flush.c', - 'test-io-stream.c', 'test-pipe-unix.c', - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps) - test('gdbus-connection-flush', exe, env : test_env, suite : ['gio']) - - exe = executable('gdbus-non-socket', 'gdbus-non-socket.c', - 'gdbus-tests.c', 'test-io-stream.c', 'test-pipe-unix.c', - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps) - test('gdbus-non-socket', exe, env : test_env, suite : ['gio']) + gio_tests += [{ + 'gdbus-connection-flush' : { + 'extra_sources' : ['test-io-stream.c', 'test-pipe-unix.c'], + }, + 'gdbus-non-socket' : { + 'extra_sources' : ['gdbus-tests.c', 'test-io-stream.c', 'test-pipe-unix.c'], + }, + }] # Generate test.mo from de.po using msgfmt msgfmt = find_program('msgfmt', required : false) if msgfmt.found() subdir('de/LC_MESSAGES') - # gsettings target exe already exists in gio directory - exe = executable('gsettings-test', 'gsettings.c', test_mo, - install : false, - c_args : test_c_args + [ - '-DSRCDIR="@0@"'.format(meson.current_source_dir()), - '-DTEST_LOCALE_PATH="@0@"'.format(test_mo_dir), - ], - dependencies : common_gio_tests_deps) - test('gsettings', exe, env : test_env, suite : ['gio']) + gio_tests += [{ + 'gsettings' : { + 'extra_sources' : [test_mo], + 'c_args' : ['-DSRCDIR="@0@"'.format(meson.current_source_dir()), + '-DTEST_LOCALE_PATH="@0@"'.format(test_mo_dir)], + 'install' : false, + }, + }] endif endif # unix # Test programs buildable on Windows only if host_machine.system() == 'windows' - gio_tests += ['win32-streams'] + gio_tests += [{'win32-streams' : {}}] endif if cc.get_id() != 'msvc' - gio_tests += [ 'autoptr' ] + gio_tests += [{ + 'autoptr-gio' : { + 'source' : 'autoptr.c', + }, + }] endif -foreach test_name : gio_tests - extra_deps = [] - srcs = ['@0@.c'.format(test_name)] - # conflicts with glib/tests/autoptr, can't have two targets with same name - if test_name == 'autoptr' - test_name = 'autoptr-gio' - elif test_name == 'defaultvalue' - srcs += [giotypefuncs_inc] - elif test_name == 'gdbus-peer' - # This is peer to peer so it doesn't need a session bus, so we can run - # it automatically as a test by default - extra_deps = [libgdbus_example_objectmanager_dep] - elif test_name == 'tls-certificate' or test_name == 'tls-interaction' - srcs += ['gtesttlsbackend.c'] - endif - exe = executable(test_name, srcs, - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps + extra_deps) - # These tests may take more than 30 seconds to run on the CI infrastructure - if slow_tests.contains(test_name) - test(test_name, exe, env : test_env, timeout : 120, suite : ['gio', 'slow']) - else - test(test_name, exe, env : test_env, suite : ['gio']) - endif -endforeach - -uninstalled_test_extra_programs = [ - ['gio-du'], - ['echo-server'], - ['filter-cat'], - ['gapplication-example-actions'], - ['gapplication-example-cmdline'], - ['gapplication-example-cmdline2'], - ['gapplication-example-cmdline3'], - ['gapplication-example-cmdline4'], - ['gapplication-example-dbushooks'], - ['gapplication-example-open'], - ['gdbus-daemon', gdbus_daemon_sources], - ['gdbus-example-export'], - ['gdbus-example-own-name'], - ['gdbus-example-peer'], - ['gdbus-example-proxy-subclass'], - ['gdbus-example-server'], - ['gdbus-example-subtree'], - ['gdbus-example-watch-name'], - ['gdbus-example-watch-proxy'], - ['gsubprocess-testprog'], - ['httpd'], - ['proxy'], - ['resolver'], - ['send-data'], - ['socket-server'], - ['socket-client', ['gtlsconsoleinteraction.c']], +test_extra_programs += [{ + 'gio-du' : {'install' : false}, + 'echo-server' : {'install' : false}, + 'filter-cat' : {'install' : false}, + 'gapplication-example-actions' : {'install' : false}, + 'gapplication-example-cmdline' : {'install' : false}, + 'gapplication-example-cmdline2' : {'install' : false}, + 'gapplication-example-cmdline3' : {'install' : false}, + 'gapplication-example-cmdline4' : {'install' : false}, + 'gapplication-example-dbushooks' : {'install' : false}, + 'gapplication-example-open' : {'install' : false}, + 'gdbus-daemon' : { + 'extra_sources' : gdbus_daemon_sources, + 'install' : false, + }, + 'gdbus-example-export' : {'install' : false}, + 'gdbus-example-own-name' : {'install' : false}, + 'gdbus-example-peer' : {'install' : false}, + 'gdbus-example-proxy-subclass' : {'install' : false}, + 'gdbus-example-server' : {'install' : false}, + 'gdbus-example-subtree' : {'install' : false}, + 'gdbus-example-watch-name' : {'install' : false}, + 'gdbus-example-watch-proxy' : {'install' : false}, + 'gsubprocess-testprog' : {'install' : false}, + 'httpd' : {'install' : false}, + 'proxy' : {'install' : false}, + 'resolver' : {'install' : false}, + 'send-data' : {'install' : false}, + 'socket-server' : {'install' : false}, + 'socket-client' : { + 'extra_sources' : ['gtlsconsoleinteraction.c'], + 'install' : false, + }, # These three are manual-run tests because they need a session bus but don't bring one up themselves # FIXME: these build but don't seem to work! - ['gdbus-example-objectmanager-client', [], [libgdbus_example_objectmanager_dep]], - ['gdbus-example-objectmanager-server', [], [libgdbus_example_objectmanager_dep]], - ['gdbus-test-fixture', [], [libgdbus_example_objectmanager_dep]], -] + 'gdbus-example-objectmanager-client' : { + 'dependencies' : [libgdbus_example_objectmanager_dep], + 'install' : false, + }, + 'gdbus-example-objectmanager-server' : { + 'dependencies' : [libgdbus_example_objectmanager_dep], + 'install' : false, + }, + 'gdbus-test-fixture' : { + 'dependencies' : [libgdbus_example_objectmanager_dep], + 'install' : false, + }, +}] if host_machine.system() != 'windows' - uninstalled_test_extra_programs += [['gdbus-example-unix-fd-client']] + test_extra_programs += [{ + 'gdbus-example-unix-fd-client' : { + 'install' : false, + }, + }] endif -foreach extra_program : uninstalled_test_extra_programs + test_extra_programs - srcs = ['@0@.c'.format(extra_program[0])] - if extra_program.length() > 1 - srcs += extra_program[1] - endif - extra_deps = [] - if extra_program.length() > 2 - extra_deps = extra_program[2] - endif - executable(extra_program[0], srcs, - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps + extra_deps) -endforeach - if not meson.is_cross_build() or meson.has_exe_wrapper() plugin_resources_c = custom_target('plugin-resources.c', @@ -441,13 +412,58 @@ if not meson.is_cross_build() or meson.has_exe_wrapper() copy : true, install : false) - exe = executable('resources', 'resources.c', test_gresource, - test_resources_c, test_resources2_c, test_resources2_h, - install : false, - c_args : test_c_args, - dependencies : common_gio_tests_deps) - test('resources', exe, env : test_env, suite : ['gio']) + gio_tests += [{ + 'resources' : { + 'extra_sources' : [test_gresource, test_resources_c, test_resources2_c, + test_resources2_h], + }, + }] endif +foreach test_dict : gio_tests + foreach test_name, extra_args : test_dict + source = extra_args.get('source', test_name + '.c') + extra_sources = extra_args.get('extra_sources', []) + install = installed_tests_enabled and extra_args.get('install', true) + + if install + test_conf = configuration_data() + test_conf.set('installed_tests_dir', installed_tests_execdir) + test_conf.set('program', test_name) + configure_file( + input: installed_tests_template, + output: test_name + '.test', + install_dir: installed_tests_metadir, + configuration: test_conf + ) + endif + + exe = executable(test_name, [source, extra_sources], + c_args : test_c_args + extra_args.get('c_args', []), + dependencies : common_gio_tests_deps + extra_args.get('dependencies', []), + install_dir: installed_tests_execdir, + install: install, + ) + + suite = ['gio'] + extra_args.get('suite', []) + timeout = suite.contains('slow') ? 120 : 30 + test(test_name, exe, env : test_env, timeout : timeout, suite : suite) + endforeach +endforeach + +foreach program_dict : test_extra_programs + foreach program_name, extra_args : program_dict + source = extra_args.get('source', program_name + '.c') + extra_sources = extra_args.get('extra_sources', []) + install = installed_tests_enabled and extra_args.get('install', true) + executable(program_name, [source, extra_sources], + c_args : test_c_args, + dependencies : common_gio_tests_deps + extra_args.get('dependencies', []), + install_dir : installed_tests_execdir, + install : install, + ) + endforeach +endforeach + # FIXME: subdir('services') subdir('modules') diff --git a/gio/tests/resources.c b/gio/tests/resources.c index 6ae8e7d64..70d8c03a6 100644 --- a/gio/tests/resources.c +++ b/gio/tests/resources.c @@ -317,6 +317,45 @@ test_resource_data_unaligned (void) g_resource_unref (resource); } +/* Test error handling for corrupt GResource files (specifically, a corrupt + * GVDB header). */ +static void +test_resource_data_corrupt (void) +{ + /* A GVDB header is 6 guint32s, and requires a magic number in the first two + * guint32s. A set of zero bytes of a greater length is considered corrupt. */ + static const guint8 data[sizeof (guint32) * 7] = { 0, }; + GBytes *bytes = NULL; + GResource *resource = NULL; + GError *local_error = NULL; + + bytes = g_bytes_new_static (data, sizeof (data)); + resource = g_resource_new_from_data (bytes, &local_error); + g_bytes_unref (bytes); + g_assert_error (local_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL); + g_assert_null (resource); + + g_clear_error (&local_error); +} + +/* Test handling for empty GResource files. They should also be treated as + * corrupt. */ +static void +test_resource_data_empty (void) +{ + GBytes *bytes = NULL; + GResource *resource = NULL; + GError *local_error = NULL; + + bytes = g_bytes_new_static (NULL, 0); + resource = g_resource_new_from_data (bytes, &local_error); + g_bytes_unref (bytes); + g_assert_error (local_error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_INTERNAL); + g_assert_null (resource); + + g_clear_error (&local_error); +} + static void test_resource_registered (void) { @@ -785,6 +824,8 @@ main (int argc, g_test_add_func ("/resource/file-path", test_resource_file_path); g_test_add_func ("/resource/data", test_resource_data); g_test_add_func ("/resource/data_unaligned", test_resource_data_unaligned); + g_test_add_func ("/resource/data-corrupt", test_resource_data_corrupt); + g_test_add_func ("/resource/data-empty", test_resource_data_empty); g_test_add_func ("/resource/registered", test_resource_registered); g_test_add_func ("/resource/manual", test_resource_manual); g_test_add_func ("/resource/manual2", test_resource_manual2); diff --git a/gio/tests/trash.c b/gio/tests/trash.c index 2abe0aa0c..176c4b9c3 100644 --- a/gio/tests/trash.c +++ b/gio/tests/trash.c @@ -35,23 +35,26 @@ test_trash_not_supported (void) GFileInfo *info; GError *error = NULL; gboolean ret; - GStatBuf file_stat, home_stat; + gchar *parent_dirname; + GStatBuf parent_stat, home_stat; /* The test assumes that tmp file is located on system internal mount. */ file = g_file_new_tmp ("test-trashXXXXXX", &stream, &error); + parent_dirname = g_path_get_dirname (g_file_peek_path (file)); g_assert_no_error (error); - g_assert_cmpint (g_lstat (g_file_peek_path (file), &file_stat), ==, 0); - g_test_message ("File: %s (dev: %" G_GUINT64_FORMAT ")", - g_file_peek_path (file), (guint64) file_stat.st_dev); + g_assert_cmpint (g_stat (parent_dirname, &parent_stat), ==, 0); + g_test_message ("File: %s (parent st_dev: %" G_GUINT64_FORMAT ")", + g_file_peek_path (file), (guint64) parent_stat.st_dev); g_assert_cmpint (g_stat (g_get_home_dir (), &home_stat), ==, 0); - g_test_message ("Home: %s (dev: %" G_GUINT64_FORMAT ")", + g_test_message ("Home: %s (st_dev: %" G_GUINT64_FORMAT ")", g_get_home_dir (), (guint64) home_stat.st_dev); - if (file_stat.st_dev == home_stat.st_dev) + if (parent_stat.st_dev == home_stat.st_dev) { g_test_skip ("The file has to be on another filesystem than the home trash to run this test"); + g_free (parent_dirname); g_object_unref (stream); g_object_unref (file); @@ -85,6 +88,7 @@ test_trash_not_supported (void) g_io_stream_close (G_IO_STREAM (stream), NULL, &error); g_assert_no_error (error); + g_free (parent_dirname); g_object_unref (info); g_object_unref (stream); g_object_unref (file); |