diff options
author | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 10:35:59 +0900 |
---|---|---|
committer | Hyunjee Kim <hj0426.kim@samsung.com> | 2019-12-03 10:35:59 +0900 |
commit | aedbffaae7e80f2e7d90374faea486abbc5e57f7 (patch) | |
tree | b32b9c1e815ddc6804f1b96f191688f1dd860802 /gio | |
parent | 5de945120591a487ffe65d50419ef336d3fe14d5 (diff) | |
download | glib-aedbffaae7e80f2e7d90374faea486abbc5e57f7.tar.gz glib-aedbffaae7e80f2e7d90374faea486abbc5e57f7.tar.bz2 glib-aedbffaae7e80f2e7d90374faea486abbc5e57f7.zip |
Imported Upstream version 2.57.1
Diffstat (limited to 'gio')
101 files changed, 2252 insertions, 2736 deletions
diff --git a/gio/Makefile.am b/gio/Makefile.am index 16c638732..df4f24014 100644 --- a/gio/Makefile.am +++ b/gio/Makefile.am @@ -334,6 +334,7 @@ win32_actual_sources = \ gwin32networking.h \ gwin32networkmonitor.c \ gwin32networkmonitor.h \ + gwin32notificationbackend.c \ $(NULL) win32_more_sources_for_vcproj = \ diff --git a/gio/gcontenttype.c b/gio/gcontenttype.c index 820e54258..af8ef44c6 100644 --- a/gio/gcontenttype.c +++ b/gio/gcontenttype.c @@ -1052,7 +1052,7 @@ read_tree_magic_from_directory (const gchar *prefix) } else { - g_warning ("%s: header corrupt; skipping\n", filename); + g_warning ("%s: header corrupt; skipping", filename); break; } } @@ -1060,7 +1060,7 @@ read_tree_magic_from_directory (const gchar *prefix) g_strfreev (lines); } else - g_warning ("%s: header not found, skipping\n", filename); + g_warning ("%s: header not found, skipping", filename); g_free (text); } diff --git a/gio/gcredentials.c b/gio/gcredentials.c index 2e050776c..cc0cd82ce 100644 --- a/gio/gcredentials.c +++ b/gio/gcredentials.c @@ -95,7 +95,10 @@ struct _GCredentials ucred_t *native; #else #ifdef __GNUC__ + #pragma GCC diagnostic push + #pragma GCC diagnostic warning "-Wcpp" #warning Please add GCredentials support for your OS + #pragma GCC diagnostic pop #endif #endif }; diff --git a/gio/gdbus-2.0/codegen/codegen.py b/gio/gdbus-2.0/codegen/codegen.py index d98f8973b..032a29ed5 100644 --- a/gio/gdbus-2.0/codegen/codegen.py +++ b/gio/gdbus-2.0/codegen/codegen.py @@ -29,7 +29,7 @@ from . import dbustypes from .utils import print_error LICENSE_STR = '''/* - * Generated by gdbus-codegen {!s}. DO NOT EDIT. + * Generated by gdbus-codegen {!s} from {!s}. DO NOT EDIT. * * The license of this code is the same as for the D-Bus interface description * it was derived from. @@ -53,19 +53,22 @@ def generate_namespace(namespace): class HeaderCodeGenerator: def __init__(self, ifaces, namespace, generate_objmanager, - generate_autocleanup, header_name, use_pragma, outfile): + generate_autocleanup, header_name, input_files_basenames, + use_pragma, outfile): self.ifaces = ifaces self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace) self.generate_objmanager = generate_objmanager self.generate_autocleanup = generate_autocleanup self.header_guard = header_name.upper().replace('.', '_').replace('-', '_').replace('/', '_').replace(':', '_') + self.input_files_basenames = input_files_basenames self.use_pragma = use_pragma self.outfile = outfile # ---------------------------------------------------------------------------------------------------- def generate_header_preamble(self): - self.outfile.write(LICENSE_STR.format(config.VERSION)) + basenames = ', '.join(self.input_files_basenames) + self.outfile.write(LICENSE_STR.format(config.VERSION, basenames)) self.outfile.write('\n') if self.use_pragma: @@ -612,18 +615,20 @@ class HeaderCodeGenerator: class CodeGenerator: def __init__(self, ifaces, namespace, generate_objmanager, header_name, - docbook_gen, outfile): + input_files_basenames, docbook_gen, outfile): self.ifaces = ifaces self.namespace, self.ns_upper, self.ns_lower = generate_namespace(namespace) self.generate_objmanager = generate_objmanager self.header_name = header_name + self.input_files_basenames = input_files_basenames self.docbook_gen = docbook_gen self.outfile = outfile # ---------------------------------------------------------------------------------------------------- def generate_body_preamble(self): - self.outfile.write(LICENSE_STR.format(config.VERSION)) + basenames = ', '.join(self.input_files_basenames) + self.outfile.write(LICENSE_STR.format(config.VERSION, basenames)) self.outfile.write('\n') self.outfile.write('#ifdef HAVE_CONFIG_H\n' '# include "config.h"\n' diff --git a/gio/gdbus-2.0/codegen/codegen_main.py b/gio/gdbus-2.0/codegen/codegen_main.py index 1cfe7c1bb..65876a2e8 100755 --- a/gio/gdbus-2.0/codegen/codegen_main.py +++ b/gio/gdbus-2.0/codegen/codegen_main.py @@ -212,11 +212,13 @@ def codegen_main(): header_name = os.path.splitext(os.path.basename(c_file))[0] + '.h' all_ifaces = [] + input_files_basenames = [] for fname in args.files + args.xml_files: with open(fname, 'rb') as f: xml_data = f.read() parsed_ifaces = parser.parse_dbus_xml(xml_data) all_ifaces.extend(parsed_ifaces) + input_files_basenames.append(os.path.basename(fname)) if args.annotate != None: apply_annotations(all_ifaces, args.annotate) @@ -236,6 +238,7 @@ def codegen_main(): args.c_generate_object_manager, args.c_generate_autocleanup, header_name, + input_files_basenames, args.pragma_once, outfile) gen.generate() @@ -246,6 +249,7 @@ def codegen_main(): args.c_namespace, args.c_generate_object_manager, header_name, + input_files_basenames, docbook_gen, outfile) gen.generate() diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c index f377378ec..2191c115a 100644 --- a/gio/gdbusaddress.c +++ b/gio/gdbusaddress.c @@ -418,10 +418,6 @@ g_dbus_is_supported_address (const gchar *string, supported = is_valid_nonce_tcp (a[n], key_value_pairs, error); else if (g_strcmp0 (a[n], "autolaunch:") == 0) supported = TRUE; - else - g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, - _("Unknown or unsupported transport “%s” for address “%s”"), - transport_name, a[n]); g_free (transport_name); g_hash_table_unref (key_value_pairs); diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c index 1a0ada5bf..1f8ea8057 100644 --- a/gio/gdbusauth.c +++ b/gio/gdbusauth.c @@ -365,12 +365,6 @@ _my_g_input_stream_read_line_safe (GInputStream *i, /* ---------------------------------------------------------------------------------------------------- */ -static void -append_nibble (GString *s, gint val) -{ - g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val)); -} - static gchar * hexdecode (const gchar *str, gsize *out_len, @@ -404,38 +398,17 @@ hexdecode (const gchar *str, g_string_append_c (s, value); } + *out_len = s->len; ret = g_string_free (s, FALSE); s = NULL; out: if (s != NULL) - g_string_free (s, TRUE); - return ret; -} - -/* TODO: take len */ -static gchar * -hexencode (const gchar *str) -{ - guint n; - GString *s; - - s = g_string_new (NULL); - for (n = 0; str[n] != '\0'; n++) { - gint val; - gint upper_nibble; - gint lower_nibble; - - val = ((const guchar *) str)[n]; - upper_nibble = val >> 4; - lower_nibble = val & 0x0f; - - append_nibble (s, upper_nibble); - append_nibble (s, lower_nibble); + *out_len = 0; + g_string_free (s, TRUE); } - - return g_string_free (s, FALSE); + return ret; } /* ---------------------------------------------------------------------------------------------------- */ @@ -532,7 +505,7 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth, goto again; } - initial_response_len = -1; + initial_response_len = 0; initial_response = _g_dbus_auth_mechanism_client_initiate (mech, &initial_response_len); #if 0 @@ -544,7 +517,7 @@ client_choose_mech_and_send_initial_response (GDBusAuth *auth, if (initial_response != NULL) { //g_printerr ("initial_response = '%s'\n", initial_response); - encoded = hexencode (initial_response); + encoded = _g_dbus_hexencode (initial_response, initial_response_len); s = g_strdup_printf ("AUTH %s %s\r\n", _g_dbus_auth_mechanism_get_name (auth_mech_to_use_gtype), encoded); @@ -836,7 +809,7 @@ _g_dbus_auth_run_client (GDBusAuth *auth, gsize data_len; gchar *encoded_data; data = _g_dbus_auth_mechanism_client_data_send (mech, &data_len); - encoded_data = hexencode (data); + encoded_data = _g_dbus_hexencode (data, data_len); s = g_strdup_printf ("DATA %s\r\n", encoded_data); g_free (encoded_data); g_free (data); @@ -1211,7 +1184,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth, { gchar *encoded_data; - encoded_data = hexencode (data); + encoded_data = _g_dbus_hexencode (data, data_len); s = g_strdup_printf ("DATA %s\r\n", encoded_data); g_free (encoded_data); g_free (data); diff --git a/gio/gdbusauthmechanismanon.c b/gio/gdbusauthmechanismanon.c index a166ede01..dd57826ff 100644 --- a/gio/gdbusauthmechanismanon.c +++ b/gio/gdbusauthmechanismanon.c @@ -262,6 +262,7 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism, gsize *out_initial_response_len) { GDBusAuthMechanismAnon *m = G_DBUS_AUTH_MECHANISM_ANON (mechanism); + gchar *result; g_return_val_if_fail (G_IS_DBUS_AUTH_MECHANISM_ANON (mechanism), NULL); g_return_val_if_fail (!m->priv->is_server && !m->priv->is_client, NULL); @@ -269,10 +270,11 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism, m->priv->is_client = TRUE; m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; - *out_initial_response_len = -1; - /* just return our library name and version */ - return g_strdup ("GDBus 0.1"); + result = g_strdup ("GDBus 0.1"); + *out_initial_response_len = strlen (result); + + return result; } static void diff --git a/gio/gdbusauthmechanismexternal.c b/gio/gdbusauthmechanismexternal.c index a4473a443..182c57278 100644 --- a/gio/gdbusauthmechanismexternal.c +++ b/gio/gdbusauthmechanismexternal.c @@ -177,7 +177,8 @@ mechanism_server_get_state (GDBusAuthMechanism *mechanism) } static gboolean -data_matches_credentials (const gchar *data, +data_matches_credentials (const gchar *data, + gsize data_len, GCredentials *credentials) { gboolean match; @@ -187,7 +188,7 @@ data_matches_credentials (const gchar *data, if (credentials == NULL) goto out; - if (data == NULL || strlen (data) == 0) + if (data == NULL || data_len == 0) goto out; #if defined(G_OS_UNIX) @@ -227,7 +228,9 @@ mechanism_server_initiate (GDBusAuthMechanism *mechanism, if (initial_response != NULL) { - if (data_matches_credentials (initial_response, _g_dbus_auth_mechanism_get_credentials (mechanism))) + if (data_matches_credentials (initial_response, + initial_response_len, + _g_dbus_auth_mechanism_get_credentials (mechanism))) { m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; } @@ -253,7 +256,9 @@ mechanism_server_data_receive (GDBusAuthMechanism *mechanism, g_return_if_fail (m->priv->is_server && !m->priv->is_client); g_return_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA); - if (data_matches_credentials (data, _g_dbus_auth_mechanism_get_credentials (mechanism))) + if (data_matches_credentials (data, + data_len, + _g_dbus_auth_mechanism_get_credentials (mechanism))) { m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; } @@ -332,7 +337,7 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism, m->priv->is_client = TRUE; m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; - *out_initial_response_len = -1; + *out_initial_response_len = 0; credentials = _g_dbus_auth_mechanism_get_credentials (mechanism); g_assert (credentials != NULL); @@ -340,9 +345,13 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism, /* return the uid */ #if defined(G_OS_UNIX) initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) g_credentials_get_unix_user (credentials, NULL)); + *out_initial_response_len = strlen (initial_response); #elif defined(G_OS_WIN32) #ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wcpp" #warning Dont know how to send credentials on this OS. The EXTERNAL D-Bus authentication mechanism will not work. +#pragma GCC diagnostic pop #endif m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; #endif diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c index 0cbaf946d..aba9cea59 100644 --- a/gio/gdbusauthmechanismsha1.c +++ b/gio/gdbusauthmechanismsha1.c @@ -280,7 +280,10 @@ ensure_keyring_directory (GError **error) } #else #ifdef __GNUC__ +#pragma GCC diagnostic push +#pragma GCC diagnostic warning "-Wcpp" #warning Please implement permission checking on this non-UNIX platform +#pragma GCC diagnostic pop #endif #endif } @@ -307,42 +310,6 @@ out: /* ---------------------------------------------------------------------------------------------------- */ -static void -append_nibble (GString *s, gint val) -{ - g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val)); -} - -static gchar * -hexencode (const gchar *str, - gssize len) -{ - guint n; - GString *s; - - if (len == -1) - len = strlen (str); - - s = g_string_new (NULL); - for (n = 0; n < len; n++) - { - gint val; - gint upper_nibble; - gint lower_nibble; - - val = ((const guchar *) str)[n]; - upper_nibble = val >> 4; - lower_nibble = val & 0x0f; - - append_nibble (s, upper_nibble); - append_nibble (s, lower_nibble); - } - - return g_string_free (s, FALSE); -} - -/* ---------------------------------------------------------------------------------------------------- */ - /* looks up an entry in the keyring */ static gchar * keyring_lookup_entry (const gchar *cookie_context, @@ -836,7 +803,7 @@ keyring_generate_entry (const gchar *cookie_context, gchar *raw_cookie; *out_id = max_line_id + 1; raw_cookie = random_blob (32); - *out_cookie = hexencode (raw_cookie, 32); + *out_cookie = _g_dbus_hexencode (raw_cookie, 32); g_free (raw_cookie); g_string_append_printf (new_contents, @@ -949,7 +916,7 @@ mechanism_server_initiate (GDBusAuthMechanism *mechanism, m->priv->is_server = TRUE; m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_REJECTED; - if (initial_response != NULL && strlen (initial_response) > 0) + if (initial_response != NULL && initial_response_len > 0) { #ifdef G_OS_UNIX gint64 uid; @@ -1035,6 +1002,7 @@ mechanism_server_data_send (GDBusAuthMechanism *mechanism, g_return_val_if_fail (m->priv->state == G_DBUS_AUTH_MECHANISM_STATE_HAVE_DATA_TO_SEND, NULL); s = NULL; + *out_data_len = 0; /* TODO: use GDBusAuthObserver here to get the cookie context to use? */ cookie_context = "org_gtk_gdbus_general"; @@ -1057,6 +1025,7 @@ mechanism_server_data_send (GDBusAuthMechanism *mechanism, cookie_context, cookie_id, m->priv->server_challenge); + *out_data_len = strlen (s); m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA; @@ -1116,12 +1085,14 @@ mechanism_client_initiate (GDBusAuthMechanism *mechanism, m->priv->is_client = TRUE; m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_WAITING_FOR_DATA; - *out_initial_response_len = -1; + *out_initial_response_len = 0; #ifdef G_OS_UNIX initial_response = g_strdup_printf ("%" G_GINT64_FORMAT, (gint64) getuid ()); + *out_initial_response_len = strlen (initial_response); #elif defined (G_OS_WIN32) -initial_response = _g_dbus_win32_get_user_sid (); + initial_response = _g_dbus_win32_get_user_sid (); + *out_initial_response_len = strlen (initial_response); #else #error Please implement for your OS #endif @@ -1208,6 +1179,7 @@ mechanism_client_data_send (GDBusAuthMechanism *mechanism, m->priv->state = G_DBUS_AUTH_MECHANISM_STATE_ACCEPTED; + *out_data_len = strlen (m->priv->to_send); return g_strdup (m->priv->to_send); } diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c index 6f7e5fefc..ae463e430 100644 --- a/gio/gdbusconnection.c +++ b/gio/gdbusconnection.c @@ -1500,7 +1500,7 @@ sync_close_cb (GObject *source_object, * @cancellable: (nullable): a #GCancellable or %NULL * @error: return location for error or %NULL * - * Synchronously closees @connection. The calling thread is blocked + * Synchronously closes @connection. The calling thread is blocked * until this is done. See g_dbus_connection_close() for the * asynchronous version of this method and more details about what it * does. @@ -7233,6 +7233,22 @@ _g_bus_get_singleton_if_exists (GBusType bus_type) return ret; } +/* May be called from any thread. Must not hold message_bus_lock. */ +void +_g_bus_forget_singleton (GBusType bus_type) +{ + GWeakRef *singleton; + + G_LOCK (message_bus_lock); + + singleton = message_bus_get_singleton (bus_type, NULL); + + if (singleton != NULL) + g_weak_ref_set (singleton, NULL); + + G_UNLOCK (message_bus_lock); +} + /** * g_bus_get_sync: * @bus_type: a #GBusType diff --git a/gio/gdbusdaemon.c b/gio/gdbusdaemon.c index 2e67b5d67..3516183f9 100644 --- a/gio/gdbusdaemon.c +++ b/gio/gdbusdaemon.c @@ -204,7 +204,7 @@ name_lookup (GDBusDaemon *daemon, const char *str) } static gboolean -is_key (const char *key_start, const char *key_end, char *value) +is_key (const char *key_start, const char *key_end, const char *value) { gsize len = strlen (value); @@ -1463,7 +1463,7 @@ filter_function (GDBusConnection *connection, gpointer user_data) { Client *client = user_data; - char *types[] = {"invalid", "method_call", "method_return", "error", "signal" }; + const char *types[] = {"invalid", "method_call", "method_return", "error", "signal" }; if (0) g_printerr ("%s%s %s %d(%d) sender: %s destination: %s %s %s.%s\n", diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c index 04bcf776f..be001ae55 100644 --- a/gio/gdbusmessage.c +++ b/gio/gdbusmessage.c @@ -983,10 +983,7 @@ g_dbus_message_set_serial (GDBusMessage *message, * * Gets a header field on @message. * - * The caller is responsible for checking the type of the returned #GVariant - * matches what is expected. - * - * Returns: (transfer none) (nullable): A #GVariant with the value if the header was found, %NULL + * Returns: A #GVariant with the value if the header was found, %NULL * otherwise. Do not free, it is owned by @message. * * Since: 2.26 @@ -1844,11 +1841,8 @@ parse_value_from_blob (GMemoryBuffer *buf, sig = read_string (buf, (gsize) siglen, &local_error); if (sig == NULL) goto fail; - if (!g_variant_is_signature (sig) || - !g_variant_type_string_is_valid (sig)) + if (!g_variant_is_signature (sig)) { - /* A D-Bus signature can contain zero or more complete types, - * but a GVariant has to be exactly one complete type. */ g_set_error (&local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT, @@ -1930,7 +1924,7 @@ parse_value_from_blob (GMemoryBuffer *buf, /** * g_dbus_message_bytes_needed: - * @blob: (array length=blob_len) (element-type guint8): A blob representing a binary D-Bus message. + * @blob: (array length=blob_len) (element-type guint8): A blob represent a binary D-Bus message. * @blob_len: The length of @blob (must be at least 16). * @error: Return location for error or %NULL. * @@ -2007,9 +2001,6 @@ g_dbus_message_bytes_needed (guchar *blob, * order that the message was in can be retrieved using * g_dbus_message_get_byte_order(). * - * If the @blob cannot be parsed, contains invalid fields, or contains invalid - * headers, %G_IO_ERROR_INVALID_ARGUMENT will be returned. - * * Returns: A new #GDBusMessage or %NULL if @error is set. Free with * g_object_unref(). * @@ -2122,15 +2113,6 @@ g_dbus_message_new_from_blob (guchar *blob, const gchar *signature_str; gsize signature_str_len; - if (!g_variant_is_of_type (signature, G_VARIANT_TYPE_SIGNATURE)) - { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Signature header found but is not of type signature")); - goto out; - } - signature_str = g_variant_get_string (signature, &signature_str_len); /* signature but no body */ @@ -2711,16 +2693,6 @@ g_dbus_message_to_blob (GDBusMessage *message, body_start_offset = mbuf.valid_len; signature = g_dbus_message_get_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE); - - if (signature != NULL && !g_variant_is_of_type (signature, G_VARIANT_TYPE_SIGNATURE)) - { - g_set_error_literal (error, - G_IO_ERROR, - G_IO_ERROR_INVALID_ARGUMENT, - _("Signature header found but is not of type signature")); - goto out; - } - signature_str = NULL; if (signature != NULL) signature_str = g_variant_get_string (signature, NULL); diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c index 08c94d506..6a59c28b4 100644 --- a/gio/gdbusobjectmanagerclient.c +++ b/gio/gdbusobjectmanagerclient.c @@ -531,7 +531,7 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass) * @manager: The #GDBusObjectManagerClient emitting the signal. * @object_proxy: The #GDBusObjectProxy on which an interface has properties that are changing. * @interface_proxy: The #GDBusProxy that has properties that are changing. - * @changed_properties: A #GVariant containing the properties that changed. + * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`). * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated * array of properties that were invalidated. * diff --git a/gio/gdbusprivate.c b/gio/gdbusprivate.c index 288c31f40..b5f8b6509 100644 --- a/gio/gdbusprivate.c +++ b/gio/gdbusprivate.c @@ -752,7 +752,7 @@ _g_dbus_worker_do_read_cb (GInputStream *input_stream, g_warning ("Error decoding D-Bus message of %" G_GSIZE_FORMAT " bytes\n" "The error is: %s\n" "The payload is as follows:\n" - "%s\n", + "%s", worker->read_buffer_cur_size, error->message, s); @@ -2232,3 +2232,38 @@ _g_signal_accumulator_false_handled (GSignalInvocationHint *ihint, return continue_emission; } + +/* ---------------------------------------------------------------------------------------------------- */ + +static void +append_nibble (GString *s, gint val) +{ + g_string_append_c (s, val >= 10 ? ('a' + val - 10) : ('0' + val)); +} + +/* ---------------------------------------------------------------------------------------------------- */ + +gchar * +_g_dbus_hexencode (const gchar *str, + gsize str_len) +{ + gsize n; + GString *s; + + s = g_string_new (NULL); + for (n = 0; n < str_len; n++) + { + gint val; + gint upper_nibble; + gint lower_nibble; + + val = ((const guchar *) str)[n]; + upper_nibble = val >> 4; + lower_nibble = val & 0x0f; + + append_nibble (s, upper_nibble); + append_nibble (s, lower_nibble); + } + + return g_string_free (s, FALSE); +} diff --git a/gio/gdbusprivate.h b/gio/gdbusprivate.h index 6a6a08014..0d85c1d85 100644 --- a/gio/gdbusprivate.h +++ b/gio/gdbusprivate.h @@ -141,8 +141,12 @@ void _g_dbus_object_proxy_add_interface (GDBusObjectProxy *proxy, void _g_dbus_object_proxy_remove_interface (GDBusObjectProxy *proxy, const gchar *interface_name); +gchar *_g_dbus_hexencode (const gchar *str, + gsize str_len); + /* Implemented in gdbusconnection.c */ GDBusConnection *_g_bus_get_singleton_if_exists (GBusType bus_type); +void _g_bus_forget_singleton (GBusType bus_type); G_END_DECLS diff --git a/gio/gdbusproxy.c b/gio/gdbusproxy.c index 38ccd285a..ae7058371 100644 --- a/gio/gdbusproxy.c +++ b/gio/gdbusproxy.c @@ -572,7 +572,7 @@ g_dbus_proxy_class_init (GDBusProxyClass *klass) /** * GDBusProxy::g-properties-changed: * @proxy: The #GDBusProxy emitting the signal. - * @changed_properties: A #GVariant containing the properties that changed + * @changed_properties: A #GVariant containing the properties that changed (type: `a{sv}`) * @invalidated_properties: A %NULL terminated array of properties that was invalidated * * Emitted when one or more D-Bus properties on @proxy changes. The diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c index 26bc53bd5..a2aa760c7 100644 --- a/gio/gdesktopappinfo.c +++ b/gio/gdesktopappinfo.c @@ -387,6 +387,22 @@ const gchar desktop_key_match_category[N_DESKTOP_KEYS] = { [DESKTOP_KEY_Comment] = 6 }; +/* Common prefix commands to ignore from Exec= lines */ +const char * const exec_key_match_blacklist[] = { + "bash", + "env", + "flatpak", + "gjs", + "pkexec", + "python", + "python2", + "python3", + "sh", + "wine", + "wine64", + NULL +}; + static gchar * desktop_key_get_name (guint key_id) { @@ -1089,6 +1105,10 @@ desktop_file_dir_unindexed_setup_search (DesktopFileDir *dir) /* Skip the pathname, if any */ if ((slash = strrchr (raw, '/'))) value = slash + 1; + + /* Don't match on blacklisted binaries like interpreters */ + if (g_strv_contains (exec_key_match_blacklist, value)) + value = NULL; } if (value) @@ -1838,7 +1858,7 @@ g_desktop_app_info_load_file (GDesktopAppInfo *self) * * Creates a new #GDesktopAppInfo. * - * Returns: a new #GDesktopAppInfo or %NULL on error. + * Returns: (nullable): a new #GDesktopAppInfo or %NULL on error. * * Since: 2.18 **/ @@ -1864,7 +1884,7 @@ g_desktop_app_info_new_from_keyfile (GKeyFile *key_file) * * Creates a new #GDesktopAppInfo. * - * Returns: a new #GDesktopAppInfo or %NULL on error. + * Returns: (nullable): a new #GDesktopAppInfo or %NULL on error. **/ GDesktopAppInfo * g_desktop_app_info_new_from_filename (const char *filename) @@ -1896,7 +1916,8 @@ g_desktop_app_info_new_from_filename (const char *filename) * (i.e. a desktop id of kde-foo.desktop will match * `/usr/share/applications/kde/foo.desktop`). * - * Returns: a new #GDesktopAppInfo, or %NULL if no desktop file with that id + * Returns: (nullable): a new #GDesktopAppInfo, or %NULL if no desktop + * file with that id exists. */ GDesktopAppInfo * g_desktop_app_info_new (const char *desktop_id) @@ -2886,7 +2907,7 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info, GAppLaunchContext *launch_context) { GList *ruris = uris; - g_autofree char *app_id = NULL; + char *app_id = NULL; g_return_val_if_fail (info != NULL, FALSE); @@ -2905,6 +2926,8 @@ g_desktop_app_info_launch_uris_with_dbus (GDesktopAppInfo *info, if (ruris != uris) g_list_free_full (ruris, g_free); + g_free (app_id); + return TRUE; } diff --git a/gio/gdocumentportal.c b/gio/gdocumentportal.c index 3e85bd22c..56378b1e6 100644 --- a/gio/gdocumentportal.c +++ b/gio/gdocumentportal.c @@ -203,7 +203,7 @@ g_document_portal_add_documents (GList *uris, { const char *uri = l->data; int idx = -1; - g_autofree char *path = NULL; + char *path = NULL; path = g_filename_from_uri (uri, NULL, NULL); if (path != NULL) @@ -221,6 +221,8 @@ g_document_portal_add_documents (GList *uris, } } + g_free (path); + if (idx != -1) g_variant_builder_add (&builder, "h", idx); else diff --git a/gio/gfdonotificationbackend.c b/gio/gfdonotificationbackend.c index ab5329497..a0d481433 100644 --- a/gio/gfdonotificationbackend.c +++ b/gio/gfdonotificationbackend.c @@ -62,6 +62,7 @@ typedef struct GVariant *default_action_target; } FreedesktopNotification; + static void freedesktop_notification_free (gpointer data) { @@ -76,24 +77,6 @@ freedesktop_notification_free (gpointer data) } static FreedesktopNotification * -freedesktop_notification_new (GFdoNotificationBackend *backend, - const gchar *id, - GNotification *notification) -{ - FreedesktopNotification *n; - - n = g_slice_new0 (FreedesktopNotification); - n->backend = backend; - n->id = g_strdup (id); - n->notify_id = 0; - g_notification_get_default_action (notification, - &n->default_action, - &n->default_action_target); - - return n; -} - -static FreedesktopNotification * g_fdo_notification_backend_find_notification (GFdoNotificationBackend *backend, const gchar *id) { @@ -336,19 +319,8 @@ notification_sent (GObject *source_object, val = g_dbus_connection_call_finish (G_DBUS_CONNECTION (source_object), result, &error); if (val) { - GFdoNotificationBackend *backend = n->backend; - FreedesktopNotification *match; - g_variant_get (val, "(u)", &n->notify_id); g_variant_unref (val); - - match = g_fdo_notification_backend_find_notification_by_notify_id (backend, n->notify_id); - if (match != NULL) - { - backend->notifications = g_slist_remove (backend->notifications, match); - freedesktop_notification_free (match); - } - backend->notifications = g_slist_prepend (backend->notifications, n); } else { @@ -359,7 +331,9 @@ notification_sent (GObject *source_object, warning_printed = TRUE; } + n->backend->notifications = g_slist_remove (n->backend->notifications, n); freedesktop_notification_free (n); + g_error_free (error); } } @@ -404,7 +378,7 @@ g_fdo_notification_backend_send_notification (GNotificationBackend *backend, GNotification *notification) { GFdoNotificationBackend *self = G_FDO_NOTIFICATION_BACKEND (backend); - FreedesktopNotification *n, *tmp; + FreedesktopNotification *n; if (self->notify_subscription == 0) { @@ -417,11 +391,24 @@ g_fdo_notification_backend_send_notification (GNotificationBackend *backend, notify_signal, backend, NULL); } - n = freedesktop_notification_new (self, id, notification); + n = g_fdo_notification_backend_find_notification (self, id); + if (n == NULL) + { + n = g_slice_new0 (FreedesktopNotification); + n->backend = self; + n->id = g_strdup (id); + n->notify_id = 0; + + n->backend->notifications = g_slist_prepend (n->backend->notifications, n); + } + else + { + /* Only clear default action. All other fields are still valid */ + g_clear_pointer (&n->default_action, g_free); + g_clear_pointer (&n->default_action_target, g_variant_unref); + } - tmp = g_fdo_notification_backend_find_notification (self, id); - if (tmp) - n->notify_id = tmp->notify_id; + g_notification_get_default_action (notification, &n->default_action, &n->default_action_target); call_notify (backend->dbus_connection, backend->application, n->notify_id, notification, notification_sent, n); } diff --git a/gio/gfile.c b/gio/gfile.c index a67aad383..c17aeb040 100644 --- a/gio/gfile.c +++ b/gio/gfile.c @@ -392,7 +392,7 @@ g_file_default_init (GFileIface *iface) * * Checks to see if a file is native to the platform. * - * A native file s one expressed in the platform-native filename format, + * A native file is one expressed in the platform-native filename format, * e.g. "C:\Windows" or "/usr/bin/". This does not mean the file is local, * as it might be on a locally mounted remote filesystem. * diff --git a/gio/gfileattribute.c b/gio/gfileattribute.c index 9b16a765f..c3a8ebf4b 100644 --- a/gio/gfileattribute.c +++ b/gio/gfileattribute.c @@ -612,7 +612,7 @@ _g_file_attribute_value_set_from_pointer (GFileAttributeValue *value, break; default: - g_warning ("Unknown type specified in g_file_info_set_attribute\n"); + g_warning ("Unknown type specified in g_file_info_set_attribute"); break; } } diff --git a/gio/gfileinfo.c b/gio/gfileinfo.c index be7bef019..a595c6f4a 100644 --- a/gio/gfileinfo.c +++ b/gio/gfileinfo.c @@ -1113,7 +1113,7 @@ _g_file_info_set_attribute_by_id (GFileInfo *info, * @value_p: (not nullable): pointer to the value * * Sets the @attribute to contain the given value, if possible. To unset the - * attribute, use %G_ATTRIBUTE_TYPE_INVALID for @type. + * attribute, use %G_FILE_ATTRIBUTE_TYPE_INVALID for @type. **/ void g_file_info_set_attribute (GFileInfo *info, diff --git a/gio/gio-tool-mount.c b/gio/gio-tool-mount.c index 1f51d7c77..9522713e9 100644 --- a/gio/gio-tool-mount.c +++ b/gio/gio-tool-mount.c @@ -39,7 +39,6 @@ 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; @@ -814,8 +813,11 @@ 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(); @@ -830,14 +832,19 @@ 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(); @@ -853,6 +860,8 @@ 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 @@ -903,9 +912,12 @@ 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) { @@ -938,6 +950,8 @@ 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 @@ -1091,6 +1105,10 @@ 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); @@ -1145,7 +1163,6 @@ handle_mount (int argc, char *argv[], gboolean do_help) g_option_context_free (context); main_loop = g_main_loop_new (NULL, FALSE); - volume_monitor = g_volume_monitor_get (); if (mount_list) list_monitor_items (); @@ -1173,7 +1190,5 @@ 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/giomodule.c b/gio/giomodule.c index 1ead84cf8..30731f7c2 100644 --- a/gio/giomodule.c +++ b/gio/giomodule.c @@ -722,8 +722,8 @@ try_class (GIOExtension *extension, * The result is cached after it is generated the first time, and * the function is thread-safe. * - * Returns: (transfer none): an object implementing - * @extension_point, or %NULL if there are no usable + * Returns: (transfer none): the type to instantiate to implement + * @extension_point, or %G_TYPE_INVALID if there are no usable * implementations. */ GType @@ -962,6 +962,7 @@ extern GType g_cocoa_notification_backend_get_type (void); #endif #ifdef G_PLATFORM_WIN32 +extern GType g_win32_notification_backend_get_type (void); #include <windows.h> extern GType _g_win32_network_monitor_get_type (void); @@ -1166,6 +1167,7 @@ _g_io_modules_ensure_loaded (void) g_type_ensure (g_cocoa_notification_backend_get_type ()); #endif #ifdef G_OS_WIN32 + g_type_ensure (g_win32_notification_backend_get_type ()); g_type_ensure (_g_winhttp_vfs_get_type ()); #endif g_type_ensure (_g_local_vfs_get_type ()); diff --git a/gio/glib-compile-resources.c b/gio/glib-compile-resources.c index 8a1a07dd1..99bcc58ba 100644 --- a/gio/glib-compile-resources.c +++ b/gio/glib-compile-resources.c @@ -76,6 +76,7 @@ typedef struct static gchar **sourcedirs = NULL; static gchar *xmllint = NULL; +static gchar *jsonformat = NULL; static gchar *gdk_pixbuf_pixdata = NULL; static void @@ -219,7 +220,6 @@ end_element (GMarkupParseContext *context, gchar *key; FileData *data = NULL; char *tmp_file = NULL; - char *tmp_file2 = NULL; file = state->string->str; key = file; @@ -274,6 +274,7 @@ end_element (GMarkupParseContext *context, gchar **options; guint i; gboolean xml_stripblanks = FALSE; + gboolean json_stripblanks = FALSE; gboolean to_pixdata = FALSE; options = g_strsplit (state->preproc_options, ",", -1); @@ -284,6 +285,8 @@ end_element (GMarkupParseContext *context, xml_stripblanks = TRUE; else if (!strcmp (options[i], "to-pixdata")) to_pixdata = TRUE; + else if (!strcmp (options[i], "json-stripblanks")) + json_stripblanks = TRUE; else { g_set_error (error, G_MARKUP_ERROR, G_MARKUP_ERROR_INVALID_CONTENT, @@ -294,73 +297,148 @@ end_element (GMarkupParseContext *context, } g_strfreev (options); - if (xml_stripblanks && xmllint != NULL) + if (xml_stripblanks) { - int fd; - GSubprocess *proc; - - tmp_file = g_strdup ("resource-XXXXXXXX"); - if ((fd = g_mkstemp (tmp_file)) == -1) + /* This is not fatal: pretty-printed XML is still valid XML */ + if (xmllint == NULL) { - int errsv = errno; - - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), - _("Failed to create temp file: %s"), - g_strerror (errsv)); - g_free (tmp_file); - tmp_file = NULL; - goto cleanup; + static gboolean xmllint_warned = FALSE; + + if (!xmllint_warned) + { + /* Translators: the first %s is a gresource XML attribute, + * the second %s is an environment variable, and the third + * %s is a command line tool + */ + char *warn = g_strdup_printf (_("%s preprocessing requested, but %s is not set, and %s is not in PATH"), + "xml-stripblanks", + "XMLLINT", + "xmllint"); + g_printerr ("%s\n", warn); + g_free (warn); + + /* Only warn once */ + xmllint_warned = TRUE; + } } - close (fd); + else + { + GSubprocess *proc; + int fd; - proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error, - xmllint, "--nonet", "--noblanks", "--output", tmp_file, real_file, NULL); - g_free (real_file); - real_file = NULL; + fd = g_file_open_tmp ("resource-XXXXXXXX", &tmp_file, error); + if (fd < 0) + goto cleanup; - if (!proc) - goto cleanup; + close (fd); - if (!g_subprocess_wait_check (proc, NULL, error)) - { - g_object_unref (proc); - goto cleanup; + proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error, + xmllint, "--nonet", "--noblanks", "--output", tmp_file, real_file, NULL); + g_free (real_file); + real_file = NULL; + + if (!proc) + goto cleanup; + + if (!g_subprocess_wait_check (proc, NULL, error)) + { + g_object_unref (proc); + goto cleanup; + } + + g_object_unref (proc); + + real_file = g_strdup (tmp_file); } + } - g_object_unref (proc); + if (json_stripblanks) + { + /* As above, this is not fatal: pretty-printed JSON is still + * valid JSON + */ + if (jsonformat == NULL) + { + static gboolean jsonformat_warned = FALSE; + + if (!jsonformat_warned) + { + /* Translators: the first %s is a gresource XML attribute, + * the second %s is an environment variable, and the third + * %s is a command line tool + */ + char *warn = g_strdup_printf (_("%s preprocessing requested, but %s is not set, and %s is not in PATH"), + "json-stripblanks", + "JSON_GLIB_FORMAT", + "json-glib-format"); + g_printerr ("%s\n", warn); + g_free (warn); + + /* Only warn once */ + jsonformat_warned = TRUE; + } + } + else + { + GSubprocess *proc; + int fd; - real_file = g_strdup (tmp_file); + fd = g_file_open_tmp ("resource-XXXXXXXX", &tmp_file, error); + if (fd < 0) + goto cleanup; + + close (fd); + + proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error, + jsonformat, "--output", tmp_file, real_file, NULL); + g_free (real_file); + real_file = NULL; + + if (!proc) + goto cleanup; + + if (!g_subprocess_wait_check (proc, NULL, error)) + { + g_object_unref (proc); + goto cleanup; + } + + g_object_unref (proc); + + real_file = g_strdup (tmp_file); + } } if (to_pixdata) { - int fd; GSubprocess *proc; + int fd; + /* This is a fatal error: if to-pixdata is used it means that + * the code loading the GResource expects a specific data format + */ if (gdk_pixbuf_pixdata == NULL) { - g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_FAILED, - "to-pixbuf preprocessing requested but GDK_PIXBUF_PIXDATA " - "not set and gdk-pixbuf-pixdata not found in path"); + /* Translators: the first %s is a gresource XML attribute, + * the second %s is an environment variable, and the third + * %s is a command line tool + */ + g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, + _("%s preprocessing requested, but %s is not set, and %s is not in PATH"), + "to-pixdata", + "GDK_PIXBUF_PIXDATA", + "gdk-pixbuf-pixdata"); goto cleanup; } - tmp_file2 = g_strdup ("resource-XXXXXXXX"); - if ((fd = g_mkstemp (tmp_file2)) == -1) - { - int errsv = errno; + fd = g_file_open_tmp ("resource-XXXXXXXX", &tmp_file, error); + if (fd < 0) + goto cleanup; - g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv), - _("Failed to create temp file: %s"), - g_strerror (errsv)); - g_free (tmp_file2); - tmp_file2 = NULL; - goto cleanup; - } close (fd); proc = g_subprocess_new (G_SUBPROCESS_FLAGS_STDOUT_SILENCE, error, - gdk_pixbuf_pixdata, real_file, tmp_file2, NULL); + gdk_pixbuf_pixdata, real_file, tmp_file, NULL); g_free (real_file); real_file = NULL; @@ -372,7 +450,7 @@ end_element (GMarkupParseContext *context, g_object_unref (proc); - real_file = g_strdup (tmp_file2); + real_file = g_strdup (tmp_file); } } @@ -437,12 +515,6 @@ done: g_free (tmp_file); } - if (tmp_file2) - { - unlink (tmp_file2); - g_free (tmp_file2); - } - if (data != NULL) file_data_free (data); } @@ -733,8 +805,10 @@ main (int argc, char **argv) xmllint = g_strdup (g_getenv ("XMLLINT")); if (xmllint == NULL) xmllint = g_find_program_in_path ("xmllint"); - if (xmllint == NULL) - g_printerr ("XMLLINT not set and xmllint not found in path; skipping xml preprocessing.\n"); + + jsonformat = g_strdup (g_getenv ("JSON_GLIB_FORMAT")); + if (jsonformat == NULL) + jsonformat = g_find_program_in_path ("json-glib-format"); gdk_pixbuf_pixdata = g_strdup (g_getenv ("GDK_PIXBUF_PIXDATA")); if (gdk_pixbuf_pixdata == NULL) @@ -1096,6 +1170,7 @@ main (int argc, char **argv) g_free (target); g_hash_table_destroy (table); g_free (xmllint); + g_free (jsonformat); g_free (c_name); g_hash_table_unref (files); diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c index 2dc8c7171..f6e1b4036 100644 --- a/gio/glib-compile-schemas.c +++ b/gio/glib-compile-schemas.c @@ -745,6 +745,8 @@ key_state_free (gpointer data) { KeyState *state = data; + g_free (state->child_schema); + if (state->type) g_variant_type_free (state->type); @@ -880,6 +882,8 @@ schema_state_free (gpointer data) g_free (state->path); g_free (state->gettext_domain); + g_free (state->extends_name); + g_free (state->list_of); g_hash_table_unref (state->keys); g_slice_free (SchemaState, state); } diff --git a/gio/gliststore.c b/gio/gliststore.c index 7cb118d76..c91dcb334 100644 --- a/gio/gliststore.c +++ b/gio/gliststore.c @@ -477,7 +477,6 @@ g_list_store_splice (GListStore *store, { gint i; - it = g_sequence_iter_next (it); for (i = 0; i < n_additions; i++) { if G_UNLIKELY (!g_type_is_a (G_OBJECT_TYPE (additions[i]), store->item_type)) @@ -488,6 +487,7 @@ g_list_store_splice (GListStore *store, } it = g_sequence_insert_before (it, g_object_ref (additions[i])); + it = g_sequence_iter_next (it); } } diff --git a/gio/glocalfile.c b/gio/glocalfile.c index e7481454e..3cd0137d6 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -199,112 +199,13 @@ _g_local_file_get_filename (GLocalFile *file) return file->filename; } -static char * -canonicalize_filename (const char *filename) -{ - char *canon, *start, *p, *q; - char *cwd; - int i; - - if (!g_path_is_absolute (filename)) - { - cwd = g_get_current_dir (); - canon = g_build_filename (cwd, filename, NULL); - g_free (cwd); - } - else - canon = g_strdup (filename); - - start = (char *)g_path_skip_root (canon); - - if (start == NULL) - { - /* This shouldn't really happen, as g_get_current_dir() should - return an absolute pathname, but bug 573843 shows this is - not always happening */ - g_free (canon); - return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL); - } - - /* POSIX allows double slashes at the start to - * mean something special (as does windows too). - * So, "//" != "/", but more than two slashes - * is treated as "/". - */ - i = 0; - for (p = start - 1; - (p >= canon) && - G_IS_DIR_SEPARATOR (*p); - p--) - i++; - if (i > 2) - { - i -= 1; - start -= i; - memmove (start, start+i, strlen (start+i)+1); - } - - /* Make sure we're using the canonical dir separator */ - p++; - while (p < start && G_IS_DIR_SEPARATOR (*p)) - *p++ = G_DIR_SEPARATOR; - - p = start; - while (*p != 0) - { - if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1]))) - { - memmove (p, p+1, strlen (p+1)+1); - } - else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2]))) - { - q = p + 2; - /* Skip previous separator */ - p = p - 2; - if (p < start) - p = start; - while (p > start && !G_IS_DIR_SEPARATOR (*p)) - p--; - if (G_IS_DIR_SEPARATOR (*p)) - *p++ = G_DIR_SEPARATOR; - memmove (p, q, strlen (q)+1); - } - else - { - /* Skip until next separator */ - while (*p != 0 && !G_IS_DIR_SEPARATOR (*p)) - p++; - - if (*p != 0) - { - /* Canonicalize one separator */ - *p++ = G_DIR_SEPARATOR; - } - } - - /* Remove additional separators */ - q = p; - while (*q && G_IS_DIR_SEPARATOR (*q)) - q++; - - if (p != q) - memmove (p, q, strlen (q)+1); - } - - /* Remove trailing slashes */ - if (p > start && G_IS_DIR_SEPARATOR (*(p-1))) - *(p-1) = 0; - - return canon; -} - GFile * _g_local_file_new (const char *filename) { GLocalFile *local; local = g_object_new (G_TYPE_LOCAL_FILE, NULL); - local->filename = canonicalize_filename (filename); + local->filename = g_canonicalize_filename (filename, NULL); return G_FILE (local); } @@ -1659,7 +1560,7 @@ expand_symlink (const char *link) #endif if (g_path_is_absolute (symlink_value)) - return canonicalize_filename (symlink_value); + return g_canonicalize_filename (symlink_value, NULL); else { link2 = strip_trailing_slashes (link); @@ -1669,7 +1570,7 @@ expand_symlink (const char *link) resolved = g_build_filename (parent, symlink_value, NULL); g_free (parent); - canonical = canonicalize_filename (resolved); + canonical = g_canonicalize_filename (resolved, NULL); g_free (resolved); @@ -2819,7 +2720,9 @@ g_local_file_measure_size_of_file (gint parent_fd, if (S_ISDIR (buf.st_mode)) { int dir_fd = -1; +#ifdef AT_FDCWD int errsv; +#endif if (g_cancellable_set_error_if_cancelled (state->cancellable, error)) return FALSE; diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c index 6d4cbc69c..801695ad0 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -897,19 +897,21 @@ get_access_rights (GFileAttributeMatcher *attribute_matcher, writable = FALSE; if (parent_info->writable) { +#ifdef G_OS_WIN32 + writable = TRUE; +#else if (parent_info->is_sticky) { -#ifndef G_OS_WIN32 uid_t uid = geteuid (); if (uid == statbuf->st_uid || uid == parent_info->owner || uid == 0) -#endif writable = TRUE; } else writable = TRUE; +#endif } if (_g_file_attribute_matcher_matches_id (attribute_matcher, G_FILE_ATTRIBUTE_ID_ACCESS_CAN_RENAME)) @@ -953,8 +955,7 @@ 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 || - statbuf->reparse_tag == IO_REPARSE_TAG_MOUNT_POINT) + if (statbuf->reparse_tag == IO_REPARSE_TAG_SYMLINK) file_type = G_FILE_TYPE_SYMBOLIC_LINK; #endif @@ -998,20 +999,13 @@ 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,8 +1017,6 @@ 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, @@ -1067,7 +1059,7 @@ make_valid_utf8 (const char *name) while (remaining_bytes != 0) { - if (g_utf8_validate (remainder, remaining_bytes, &invalid)) + if (g_utf8_validate (remainder, remaining_bytes, &invalid)) break; valid_bytes = invalid - remainder; @@ -1802,9 +1794,7 @@ _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 || - statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT); + is_symlink = stat_ok && statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK; #else is_symlink = FALSE; #endif @@ -2187,9 +2177,7 @@ 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 || - statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)); + is_symlink = (res == 0 && statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK); #endif if (is_symlink) { diff --git a/gio/glocalvfs.c b/gio/glocalvfs.c index 4f1462de9..c29d071b7 100644 --- a/gio/glocalvfs.c +++ b/gio/glocalvfs.c @@ -129,7 +129,7 @@ g_local_vfs_parse_name (GVfs *vfs, GFile *file; char *filename; char *user_prefix; - const char *user_start, *user_end; + const char *user_end; char *rest; g_return_val_if_fail (G_IS_VFS (vfs), NULL); @@ -141,19 +141,22 @@ g_local_vfs_parse_name (GVfs *vfs, { if (*parse_name == '~') { +#ifdef G_OS_UNIX + const char *user_start; + user_start = parse_name + 1; +#endif parse_name ++; - user_start = parse_name; while (*parse_name != 0 && *parse_name != '/') parse_name++; user_end = parse_name; +#ifdef G_OS_UNIX if (user_end == user_start) user_prefix = g_strdup (g_get_home_dir ()); else { -#ifdef G_OS_UNIX struct passwd *passwd_file_entry; char *user_name; @@ -165,9 +168,11 @@ g_local_vfs_parse_name (GVfs *vfs, passwd_file_entry->pw_dir != NULL) user_prefix = g_strdup (passwd_file_entry->pw_dir); else -#endif user_prefix = g_strdup (g_get_home_dir ()); } +#else + user_prefix = g_strdup (g_get_home_dir ()); +#endif rest = NULL; if (*user_end != 0) diff --git a/gio/gmenuexporter.c b/gio/gmenuexporter.c index e12a0f78e..f319b886b 100644 --- a/gio/gmenuexporter.c +++ b/gio/gmenuexporter.c @@ -72,7 +72,7 @@ org_gtk_Menus_get_interface (void) " </interface>" "</node>", &error); if (info == NULL) - g_error ("%s\n", error->message); + g_error ("%s", error->message); interface_info = g_dbus_node_info_lookup_interface (info, "org.gtk.Menus"); g_assert (interface_info != NULL); g_dbus_interface_info_ref (interface_info); diff --git a/gio/gnetworkmonitornetlink.c b/gio/gnetworkmonitornetlink.c index 3841e69e1..b308b3b65 100644 --- a/gio/gnetworkmonitornetlink.c +++ b/gio/gnetworkmonitornetlink.c @@ -113,7 +113,7 @@ g_network_monitor_netlink_initable_init (GInitable *initable, } nl->priv->sock = g_socket_new_from_fd (sockfd, error); - if (!nl->priv->sock) + if (error) { g_prefix_error (error, "%s", _("Could not create network monitor: ")); (void) g_close (sockfd, NULL); @@ -435,6 +435,12 @@ g_network_monitor_netlink_finalize (GObject *object) { GNetworkMonitorNetlink *nl = G_NETWORK_MONITOR_NETLINK (object); + if (nl->priv->sock) + { + g_socket_close (nl->priv->sock, NULL); + g_object_unref (nl->priv->sock); + } + if (nl->priv->source) { g_source_destroy (nl->priv->source); @@ -447,12 +453,6 @@ g_network_monitor_netlink_finalize (GObject *object) g_source_unref (nl->priv->dump_source); } - if (nl->priv->sock) - { - g_socket_close (nl->priv->sock, NULL); - g_object_unref (nl->priv->sock); - } - g_clear_pointer (&nl->priv->context, g_main_context_unref); g_clear_pointer (&nl->priv->dump_networks, g_ptr_array_unref); diff --git a/gio/gnetworkmonitorportal.c b/gio/gnetworkmonitorportal.c index bce8a338a..856f8aa5b 100644 --- a/gio/gnetworkmonitorportal.c +++ b/gio/gnetworkmonitorportal.c @@ -21,6 +21,7 @@ #include "gnetworkmonitorportal.h" #include "ginitable.h" #include "giomodule-priv.h" +#include "gnetworkmonitor.h" #include "xdp-dbus.h" #include "gportalsupport.h" @@ -38,13 +39,8 @@ enum struct _GNetworkMonitorPortalPrivate { - GDBusProxy *proxy; - gboolean has_network; - int version; - - gboolean available; - gboolean metered; - GNetworkConnectivity connectivity; + GXdpNetworkMonitor *proxy; + gboolean network_available; }; G_DEFINE_TYPE_WITH_CODE (GNetworkMonitorPortal, g_network_monitor_portal, G_TYPE_NETWORK_MONITOR_BASE, @@ -76,15 +72,22 @@ g_network_monitor_portal_get_property (GObject *object, switch (prop_id) { case PROP_NETWORK_AVAILABLE: - g_value_set_boolean (value, nm->priv->available); + g_value_set_boolean (value, + nm->priv->network_available && + gxdp_network_monitor_get_available (nm->priv->proxy)); break; case PROP_NETWORK_METERED: - g_value_set_boolean (value, nm->priv->metered); + g_value_set_boolean (value, + nm->priv->network_available && + gxdp_network_monitor_get_metered (nm->priv->proxy)); break; case PROP_CONNECTIVITY: - g_value_set_enum (value, nm->priv->connectivity); + g_value_set_enum (value, + nm->priv->network_available + ? gxdp_network_monitor_get_connectivity (nm->priv->proxy) + : G_NETWORK_CONNECTIVITY_LOCAL); break; default: @@ -94,191 +97,22 @@ g_network_monitor_portal_get_property (GObject *object, } static void -got_available (GObject *source, - GAsyncResult *res, - gpointer data) -{ - GDBusProxy *proxy = G_DBUS_PROXY (source); - GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); - GError *error = NULL; - GVariant *ret; - gboolean available; - - ret = g_dbus_proxy_call_finish (proxy, res, &error); - if (ret == NULL) - { - g_warning ("%s", error->message); - g_clear_error (&error); - return; - } - - g_variant_get (ret, "(b)", &available); - g_variant_unref (ret); - - if (nm->priv->available != available) - { - nm->priv->available = available; - g_object_notify (G_OBJECT (nm), "network-available"); - g_signal_emit_by_name (nm, "network-changed", available); - } -} - -static void -got_metered (GObject *source, - GAsyncResult *res, - gpointer data) -{ - GDBusProxy *proxy = G_DBUS_PROXY (source); - GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); - GError *error = NULL; - GVariant *ret; - gboolean metered; - - ret = g_dbus_proxy_call_finish (proxy, res, &error); - if (ret == NULL) - { - g_warning ("%s", error->message); - g_clear_error (&error); - return; - } - - g_variant_get (ret, "(b)", &metered); - g_variant_unref (ret); - - if (nm->priv->metered != metered) - { - nm->priv->metered = metered; - g_object_notify (G_OBJECT (nm), "network-metered"); - } -} - -static void -got_connectivity (GObject *source, - GAsyncResult *res, - gpointer data) -{ - GDBusProxy *proxy = G_DBUS_PROXY (source); - GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (data); - GError *error = NULL; - GVariant *ret; - GNetworkConnectivity connectivity; - - ret = g_dbus_proxy_call_finish (proxy, res, &error); - if (ret == NULL) - { - g_warning ("%s", error->message); - g_clear_error (&error); - return; - } - - g_variant_get (ret, "(u)", &connectivity); - g_variant_unref (ret); - - if (nm->priv->connectivity != connectivity) - { - nm->priv->connectivity = connectivity; - g_object_notify (G_OBJECT (nm), "connectivity"); - } -} - -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, - GVariant *parameters, - GNetworkMonitorPortal *nm) +proxy_changed (GXdpNetworkMonitor *proxy, + gboolean available, + GNetworkMonitorPortal *nm) { - if (!nm->priv->has_network) - return; - - if (nm->priv->version == 1) - { - gboolean available; - - g_variant_get (parameters, "(b)", &available); - g_signal_emit_by_name (nm, "network-changed", available); - } - else if (nm->priv->version == 2) - { - update_properties (proxy, nm); - } + if (nm->priv->network_available) + g_signal_emit_by_name (nm, "network-changed", available); } -static void -proxy_properties_changed (GDBusProxy *proxy, - GVariant *changed, - GVariant *invalidated, - GNetworkMonitorPortal *nm) -{ - if (!nm->priv->has_network) - return; - - if (nm->priv->version == 1) - { - GVariant *ret; - - ret = g_dbus_proxy_get_cached_property (proxy, "connectivity"); - if (ret) - { - GNetworkConnectivity connectivity = g_variant_get_uint32 (ret); - if (nm->priv->connectivity != connectivity) - { - nm->priv->connectivity = connectivity; - g_object_notify (G_OBJECT (nm), "connectivity"); - } - g_variant_unref (ret); - } - - ret = g_dbus_proxy_get_cached_property (proxy, "metered"); - if (ret) - { - gboolean metered = g_variant_get_boolean (ret); - if (nm->priv->metered != metered) - { - nm->priv->metered = metered; - g_object_notify (G_OBJECT (nm), "network-metered"); - } - g_variant_unref (ret); - } - - ret = g_dbus_proxy_get_cached_property (proxy, "available"); - if (ret) - { - gboolean available = g_variant_get_boolean (ret); - if (nm->priv->available != available) - { - nm->priv->available = available; - g_object_notify (G_OBJECT (nm), "network-available"); - g_signal_emit_by_name (nm, "network-changed", available); - } - g_variant_unref (ret); - } - } -} - static gboolean g_network_monitor_portal_initable_init (GInitable *initable, GCancellable *cancellable, GError **error) { GNetworkMonitorPortal *nm = G_NETWORK_MONITOR_PORTAL (initable); - GDBusProxy *proxy; + GXdpNetworkMonitor *proxy; gchar *name_owner = NULL; - int version; - GVariant *ret; - - nm->priv->available = FALSE; - nm->priv->metered = FALSE; - nm->priv->connectivity = G_NETWORK_CONNECTIVITY_LOCAL; if (!glib_should_use_portal ()) { @@ -286,19 +120,17 @@ g_network_monitor_portal_initable_init (GInitable *initable, return FALSE; } - proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, - G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START - | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, - NULL, - "org.freedesktop.portal.Desktop", - "/org/freedesktop/portal/desktop", - "org.freedesktop.portal.NetworkMonitor", - cancellable, - error); + proxy = gxdp_network_monitor_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START + | G_DBUS_PROXY_FLAGS_GET_INVALIDATED_PROPERTIES, + "org.freedesktop.portal.Desktop", + "/org/freedesktop/portal/desktop", + cancellable, + error); if (!proxy) return FALSE; - name_owner = g_dbus_proxy_get_name_owner (proxy); + name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (proxy)); if (!name_owner) { @@ -312,34 +144,11 @@ g_network_monitor_portal_initable_init (GInitable *initable, g_free (name_owner); - ret = g_dbus_proxy_get_cached_property (proxy, "version"); - g_variant_get (ret, "u", &version); - g_variant_unref (ret); - - if (version != 1 && version != 2) - { - g_object_unref (proxy); - g_set_error (error, - G_DBUS_ERROR, - G_DBUS_ERROR_NAME_HAS_NO_OWNER, - "NetworkMonitor portal unsupported version: %d", version); - return FALSE; - } - - g_signal_connect (proxy, "g-signal", G_CALLBACK (proxy_signal), nm); - g_signal_connect (proxy, "g-properties-changed", G_CALLBACK (proxy_properties_changed), nm); - + g_signal_connect (proxy, "changed", G_CALLBACK (proxy_changed), nm); nm->priv->proxy = proxy; - nm->priv->has_network = glib_network_available_in_sandbox (); - nm->priv->version = version; - - if (!initable_parent_iface->init (initable, cancellable, error)) - return FALSE; - - if (nm->priv->has_network && nm->priv->version == 2) - update_properties (proxy, nm); + nm->priv->network_available = glib_network_available_in_sandbox (); - return TRUE; + return initable_parent_iface->init (initable, cancellable, error); } static void diff --git a/gio/gopenuriportal.c b/gio/gopenuriportal.c index 247ed8ce7..38d60bf68 100644 --- a/gio/gopenuriportal.c +++ b/gio/gopenuriportal.c @@ -203,7 +203,7 @@ open_call_done (GObject *source, GError *error = NULL; gboolean open_file; gboolean res; - char *path; + char *path = NULL; const char *handle; guint signal_id; @@ -224,7 +224,7 @@ open_call_done (GObject *source, } handle = (const char *)g_object_get_data (G_OBJECT (task), "handle"); - if (strcmp (handle, path) != 0) + if (g_strcmp0 (handle, path) != 0) { signal_id = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (task), "signal-id")); g_dbus_connection_signal_unsubscribe (connection, signal_id); diff --git a/gio/gregistrysettingsbackend.c b/gio/gregistrysettingsbackend.c index 23a96486f..70d391a32 100644 --- a/gio/gregistrysettingsbackend.c +++ b/gio/gregistrysettingsbackend.c @@ -1800,7 +1800,7 @@ watch_thread_function (LPVOID parameter) * likely to block (only when changing notification subscriptions). */ event = g_slice_new (RegistryEvent); - event->self = g_object_ref (self->owner); + event->self = G_REGISTRY_BACKEND (g_object_ref (self->owner)); event->prefix = g_strdup (prefix); event->items = g_ptr_array_new_with_free_func (g_free); diff --git a/gio/gsettings-mapping.c b/gio/gsettings-mapping.c index 94d5cc705..bba8a8f7c 100644 --- a/gio/gsettings-mapping.c +++ b/gio/gsettings-mapping.c @@ -498,7 +498,7 @@ g_settings_get_mapping (GValue *value, return TRUE; } - g_warning ("Unable to lookup enum nick '%s' via GType\n", nick); + g_warning ("Unable to lookup enum nick '%s' via GType", nick); return FALSE; } } @@ -530,7 +530,7 @@ g_settings_get_mapping (GValue *value, else { - g_warning ("Unable to lookup flags nick '%s' via GType\n", + g_warning ("Unable to lookup flags nick '%s' via GType", nick); return FALSE; } diff --git a/gio/gsettings.c b/gio/gsettings.c index 10d394d69..e5ed54a46 100644 --- a/gio/gsettings.c +++ b/gio/gsettings.c @@ -587,7 +587,7 @@ g_settings_set_property (GObject *object, settings->priv->schema = g_settings_schema_source_lookup (default_source, schema_id, TRUE); if (settings->priv->schema == NULL) - g_error ("Settings schema '%s' is not installed\n", schema_id); + g_error ("Settings schema '%s' is not installed", schema_id); } } break; @@ -2475,8 +2475,7 @@ g_settings_list_keys (GSettings *settings) * to call g_settings_get_child(). * * For GSettings objects that are lists, this value can change at any - * time and you should connect to the "children-changed" signal to watch - * for those changes. Note that there is a race condition here: you may + * time. Note that there is a race condition here: you may * request a child after listing it only for it to have been destroyed * in the meantime. For this reason, g_settings_get_child() may return * %NULL even for a child that was listed by this function. @@ -2683,6 +2682,7 @@ g_settings_binding_property_changed (GObject *object, GSettingsBinding *binding = user_data; GValue value = G_VALUE_INIT; GVariant *variant; + gboolean valid = TRUE; g_assert (object == binding->object); g_assert (pspec == binding->property); @@ -2701,24 +2701,33 @@ g_settings_binding_property_changed (GObject *object, if (!g_settings_schema_key_type_check (&binding->key, variant)) { + gchar *type_str; + type_str = g_variant_type_dup_string (binding->key.type); g_critical ("binding mapping function for key '%s' returned " "GVariant of type '%s' when type '%s' was requested", binding->key.name, g_variant_get_type_string (variant), - g_variant_type_dup_string (binding->key.type)); - return; + type_str); + g_free (type_str); + valid = FALSE; } - if (!g_settings_schema_key_range_check (&binding->key, variant)) + if (valid && !g_settings_schema_key_range_check (&binding->key, variant)) { + gchar *variant_str; + variant_str = g_variant_print (variant, TRUE); g_critical ("GObject property '%s' on a '%s' object is out of " "schema-specified range for key '%s' of '%s': %s", binding->property->name, g_type_name (binding->property->owner_type), binding->key.name, g_settings_schema_get_id (binding->key.schema), - g_variant_print (variant, TRUE)); - return; + variant_str); + g_free (variant_str); + valid = FALSE; } - g_settings_write_to_backend (binding->settings, &binding->key, variant); + if (valid) + { + g_settings_write_to_backend (binding->settings, &binding->key, variant); + } g_variant_unref (variant); } g_value_unset (&value); diff --git a/gio/gsimpleaction.c b/gio/gsimpleaction.c index 54c554087..c788252bb 100644 --- a/gio/gsimpleaction.c +++ b/gio/gsimpleaction.c @@ -371,12 +371,14 @@ g_simple_action_class_init (GSimpleActionClass *class) /** * GSimpleAction::activate: * @simple: the #GSimpleAction - * @parameter: (nullable): the parameter to the activation + * @parameter: (nullable): the parameter to the activation, or %NULL if it has + * no parameter * * Indicates that the action was just activated. * - * @parameter will always be of the expected type. In the event that - * an incorrect type was given, no signal will be emitted. + * @parameter will always be of the expected type, i.e. the parameter type + * specified when the action was created. If an incorrect type is given when + * activating the action, this signal is not emitted. * * Since GLib 2.40, if no handler is connected to this signal then the * default behaviour for boolean-stated actions with a %NULL parameter @@ -405,8 +407,10 @@ g_simple_action_class_init (GSimpleActionClass *class) * Indicates that the action just received a request to change its * state. * - * @value will always be of the correct state type. In the event that - * an incorrect type was given, no signal will be emitted. + * @value will always be of the correct state type, i.e. the type of the + * initial state passed to g_simple_action_new_stateful(). If an incorrect + * type is given when requesting to change the state, this signal is not + * emitted. * * If no handler is connected to this signal then the default * behaviour is to call g_simple_action_set_state() to set the state @@ -591,11 +595,13 @@ g_simple_action_set_state_hint (GSimpleAction *simple, /** * g_simple_action_new: * @name: the name of the action - * @parameter_type: (nullable): the type of parameter to the activate function + * @parameter_type: (nullable): the type of parameter that will be passed to + * handlers for the #GSimpleAction::activate signal, or %NULL for no parameter * * Creates a new action. * - * The created action is stateless. See g_simple_action_new_stateful(). + * The created action is stateless. See g_simple_action_new_stateful() to create + * an action that has state. * * Returns: a new #GSimpleAction * @@ -616,15 +622,16 @@ g_simple_action_new (const gchar *name, /** * g_simple_action_new_stateful: * @name: the name of the action - * @parameter_type: (nullable): the type of the parameter to the activate function + * @parameter_type: (nullable): the type of the parameter that will be passed to + * handlers for the #GSimpleAction::activate signal, or %NULL for no parameter * @state: the initial state of the action * * Creates a new stateful action. * - * @state is the initial state of the action. All future state values - * must have the same #GVariantType as the initial state. + * All future state values must have the same #GVariantType as the initial + * @state. * - * If the @state GVariant is floating, it is consumed. + * If the @state #GVariant is floating, it is consumed. * * Returns: a new #GSimpleAction * diff --git a/gio/gsocket.c b/gio/gsocket.c index b4a941eb1..11be2e738 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -572,7 +572,7 @@ g_socket (gint domain, if (fd < 0) { - int errsv = get_socket_errno (); + errsv = get_socket_errno (); g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv), _("Unable to create socket: %s"), socket_strerror (errsv)); @@ -3251,7 +3251,7 @@ g_socket_send_with_timeout (GSocket *socket, { win32_unset_event_mask (socket, FD_WRITE); - if ((ret = send (socket->priv->fd, buffer, size, G_SOCKET_DEFAULT_SEND_FLAGS)) < 0) + if ((ret = send (socket->priv->fd, (const char *)buffer, size, G_SOCKET_DEFAULT_SEND_FLAGS)) < 0) { int errsv = get_socket_errno (); diff --git a/gio/gsocketlistener.c b/gio/gsocketlistener.c index df6b71b0d..ab17678a9 100644 --- a/gio/gsocketlistener.c +++ b/gio/gsocketlistener.c @@ -49,9 +49,16 @@ * of server sockets and helps you accept sockets from any of the * socket, either sync or async. * + * Add addresses and ports to listen on using g_socket_listener_add_address() + * and g_socket_listener_add_inet_port(). These will be listened on until + * g_socket_listener_close() is called. Dropping your final reference to the + * #GSocketListener will not cause g_socket_listener_close() to be called + * implicitly, as some references to the #GSocketListener may be held + * internally. + * * If you want to implement a network server, also look at #GSocketService - * and #GThreadedSocketService which are subclass of #GSocketListener - * that makes this even easier. + * and #GThreadedSocketService which are subclasses of #GSocketListener + * that make this even easier. * * Since: 2.22 */ @@ -309,6 +316,10 @@ g_socket_listener_add_socket (GSocketListener *listener, * requesting a binding to port 0 (ie: "any port"). This address, if * requested, belongs to the caller and must be freed. * + * Call g_socket_listener_close() to stop listening on @address; this will not + * be done automatically when you drop your final reference to @listener, as + * references may be held internally. + * * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 @@ -404,6 +415,10 @@ g_socket_listener_add_address (GSocketListener *listener, * useful if you're listening on multiple addresses and do * different things depending on what address is connected to. * + * Call g_socket_listener_close() to stop listening on @port; this will not + * be done automatically when you drop your final reference to @listener, as + * references may be held internally. + * * Returns: %TRUE on success, %FALSE on error. * * Since: 2.22 diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c index 2ce2428f0..31822e59c 100644 --- a/gio/gsubprocess.c +++ b/gio/gsubprocess.c @@ -1528,8 +1528,7 @@ g_subprocess_communicate_made_progress (GObject *source_object, } static gboolean -g_subprocess_communicate_cancelled (GCancellable *cancellable, - gpointer user_data) +g_subprocess_communicate_cancelled (gpointer user_data) { CommunicateState *state = user_data; @@ -1581,9 +1580,7 @@ g_subprocess_communicate_internal (GSubprocess *subprocess, { state->cancellable_source = g_cancellable_source_new (cancellable); /* No ref held here, but we unref the source from state's free function */ - g_source_set_callback (state->cancellable_source, - (GSourceFunc) g_subprocess_communicate_cancelled, - state, NULL); + g_source_set_callback (state->cancellable_source, g_subprocess_communicate_cancelled, state, NULL); g_source_attach (state->cancellable_source, g_main_context_get_thread_default ()); } diff --git a/gio/gtestdbus.c b/gio/gtestdbus.c index 6eaf060d9..685503c5e 100644 --- a/gio/gtestdbus.c +++ b/gio/gtestdbus.c @@ -96,7 +96,7 @@ _g_object_dispose_and_wait_weak_notify (gpointer object) if (data.timed_out) { - g_warning ("Weak notify timeout, object ref_count=%d\n", + g_warning ("Weak notify timeout, object ref_count=%d", G_OBJECT (object)->ref_count); } else @@ -823,6 +823,7 @@ g_test_dbus_down (GTestDBus *self) _g_object_dispose_and_wait_weak_notify (connection); g_test_dbus_unset (); + _g_bus_forget_singleton (G_BUS_TYPE_SESSION); self->priv->up = FALSE; } diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c index 4d19217ca..f2db27e66 100644 --- a/gio/gunixmounts.c +++ b/gio/gunixmounts.c @@ -126,6 +126,7 @@ struct _GUnixMountEntry { char *mount_path; char *device_path; char *filesystem_type; + char *options; gboolean is_read_only; gboolean is_system_internal; }; @@ -306,6 +307,7 @@ g_unix_is_system_fs_type (const char *fs_type) "autofs", "autofs4", "cgroup", + "cifs", "configfs", "cxfs", "debugfs", @@ -327,6 +329,8 @@ g_unix_is_system_fs_type (const char *fs_type) "mfs", "mqueue", "ncpfs", + "nfs", + "nfs4", "nfsd", "nullfs", "ocfs2", @@ -339,6 +343,7 @@ g_unix_is_system_fs_type (const char *fs_type) "rpc_pipefs", "securityfs", "selinuxfs", + "smbfs", "sysfs", "tmpfs", "usbfs", @@ -408,6 +413,7 @@ static GUnixMountEntry * create_unix_mount_entry (const char *device_path, const char *mount_path, const char *filesystem_type, + const char *options, gboolean is_read_only) { GUnixMountEntry *mount_entry = NULL; @@ -416,6 +422,7 @@ create_unix_mount_entry (const char *device_path, mount_entry->device_path = g_strdup (device_path); mount_entry->mount_path = g_strdup (mount_path); mount_entry->filesystem_type = g_strdup (filesystem_type); + mount_entry->options = g_strdup (options); mount_entry->is_read_only = is_read_only; mount_entry->is_system_internal = @@ -494,6 +501,7 @@ _g_get_unix_mounts (void) mount_entry = create_unix_mount_entry (device_path, mnt_fs_get_target (fs), mnt_fs_get_fstype (fs), + mnt_fs_get_options (fs), is_read_only); return_list = g_list_prepend (return_list, mount_entry); @@ -588,6 +596,7 @@ _g_get_unix_mounts (void) mount_entry = create_unix_mount_entry (device_path, mntent->mnt_dir, mntent->mnt_type, + mntent->mnt_opts, is_read_only); g_hash_table_insert (mounts_hash, @@ -701,6 +710,7 @@ _g_get_unix_mounts (void) mount_entry = create_unix_mount_entry (mntent.mnt_special, mntent.mnt_mountp, mntent.mnt_fstype, + mntent.mnt_opts, is_read_only); return_list = g_list_prepend (return_list, mount_entry); @@ -734,7 +744,7 @@ _g_get_unix_mounts (void) if (mntctl (MCTL_QUERY, sizeof (vmount_size), &vmount_size) != 0) { - g_warning ("Unable to know the number of mounted volumes\n"); + g_warning ("Unable to know the number of mounted volumes"); return NULL; } @@ -744,11 +754,11 @@ _g_get_unix_mounts (void) vmount_number = mntctl (MCTL_QUERY, vmount_size, vmount_info); if (vmount_info->vmt_revision != VMT_REVISION) - g_warning ("Bad vmount structure revision number, want %d, got %d\n", VMT_REVISION, vmount_info->vmt_revision); + g_warning ("Bad vmount structure revision number, want %d, got %d", VMT_REVISION, vmount_info->vmt_revision); if (vmount_number < 0) { - g_warning ("Unable to recover mounted volumes information\n"); + g_warning ("Unable to recover mounted volumes information"); g_free (vmount_info); return NULL; @@ -767,6 +777,7 @@ _g_get_unix_mounts (void) mount_entry = create_unix_mount_entry (vmt2dataptr (vmount_info, VMT_OBJECT), vmt2dataptr (vmount_info, VMT_STUB), fs_info == NULL ? "unknown" : fs_info->vfsent_name, + NULL, is_read_only); return_list = g_list_prepend (return_list, mount_entry); @@ -842,6 +853,7 @@ _g_get_unix_mounts (void) mount_entry = create_unix_mount_entry (mntent[i].f_mntfromname, mntent[i].f_mntonname, mntent[i].f_fstypename, + NULL, is_read_only); return_list = g_list_prepend (return_list, mount_entry); @@ -1985,6 +1997,7 @@ g_unix_mount_free (GUnixMountEntry *mount_entry) g_free (mount_entry->mount_path); g_free (mount_entry->device_path); g_free (mount_entry->filesystem_type); + g_free (mount_entry->options); g_free (mount_entry); } @@ -2009,6 +2022,7 @@ g_unix_mount_copy (GUnixMountEntry *mount_entry) copy->mount_path = g_strdup (mount_entry->mount_path); copy->device_path = g_strdup (mount_entry->device_path); copy->filesystem_type = g_strdup (mount_entry->filesystem_type); + copy->options = g_strdup (mount_entry->options); copy->is_read_only = mount_entry->is_read_only; copy->is_system_internal = mount_entry->is_system_internal; @@ -2092,6 +2106,10 @@ g_unix_mount_compare (GUnixMountEntry *mount1, if (res != 0) return res; + res = g_strcmp0 (mount1->options, mount2->options); + if (res != 0) + return res; + res = mount1->is_read_only - mount2->is_read_only; if (res != 0) return res; @@ -2148,6 +2166,29 @@ g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry) } /** + * g_unix_mount_get_options: + * @mount_entry: a #GUnixMountEntry. + * + * Gets a comma-separated list of mount options for the unix mount. For example, + * `rw,relatime,seclabel,data=ordered`. + * + * This is similar to g_unix_mount_point_get_options(), but it takes + * a #GUnixMountEntry as an argument. + * + * Returns: (nullable): a string containing the options, or %NULL if not + * available. + * + * Since: 2.58 + */ +const gchar * +g_unix_mount_get_options (GUnixMountEntry *mount_entry) +{ + g_return_val_if_fail (mount_entry != NULL, NULL); + + return mount_entry->options; +} + +/** * g_unix_mount_is_readonly: * @mount_entry: a #GUnixMount. * @@ -2684,18 +2725,29 @@ g_unix_mount_guess_should_display (GUnixMountEntry *mount_entry) mount_path = mount_entry->mount_path; if (mount_path != NULL) { + const gboolean running_as_root = (getuid () == 0); gboolean is_in_runtime_dir = FALSE; + /* Hide mounts within a dot path, suppose it was a purpose to hide this mount */ if (g_strstr_len (mount_path, -1, "/.") != NULL) return FALSE; - /* Check /run/media/$USER/ */ - user_name = g_get_user_name (); - user_name_len = strlen (user_name); - if (strncmp (mount_path, "/run/media/", sizeof ("/run/media/") - 1) == 0 && - strncmp (mount_path + sizeof ("/run/media/") - 1, user_name, user_name_len) == 0 && - mount_path[sizeof ("/run/media/") - 1 + user_name_len] == '/') - is_in_runtime_dir = TRUE; + /* Check /run/media/$USER/. If running as root, display any mounts below + * /run/media/. */ + if (running_as_root) + { + if (strncmp (mount_path, "/run/media/", strlen ("/run/media/")) == 0) + is_in_runtime_dir = TRUE; + } + else + { + user_name = g_get_user_name (); + user_name_len = strlen (user_name); + if (strncmp (mount_path, "/run/media/", strlen ("/run/media/")) == 0 && + strncmp (mount_path + strlen ("/run/media/"), user_name, user_name_len) == 0 && + mount_path[strlen ("/run/media/") + user_name_len] == '/') + is_in_runtime_dir = TRUE; + } if (is_in_runtime_dir || g_str_has_prefix (mount_path, "/media/")) { diff --git a/gio/gunixmounts.h b/gio/gunixmounts.h index 04d6b0726..a392d497f 100644 --- a/gio/gunixmounts.h +++ b/gio/gunixmounts.h @@ -81,6 +81,8 @@ GLIB_AVAILABLE_IN_ALL const char * g_unix_mount_get_device_path (GUnixMountEntry *mount_entry); GLIB_AVAILABLE_IN_ALL const char * g_unix_mount_get_fs_type (GUnixMountEntry *mount_entry); +GLIB_AVAILABLE_IN_2_58 +const char * g_unix_mount_get_options (GUnixMountEntry *mount_entry); GLIB_AVAILABLE_IN_ALL gboolean g_unix_mount_is_readonly (GUnixMountEntry *mount_entry); GLIB_AVAILABLE_IN_ALL diff --git a/gio/gunixvolume.c b/gio/gunixvolume.c index a3768e11d..b54d1fd6e 100644 --- a/gio/gunixvolume.c +++ b/gio/gunixvolume.c @@ -274,7 +274,6 @@ 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)) { @@ -287,12 +286,8 @@ 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 */ - 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); - } + /* ...and successful exit code */ + g_task_return_boolean (task, TRUE); g_free (stderr_str); } diff --git a/gio/gunixvolumemonitor.c b/gio/gunixvolumemonitor.c index 4b99423d7..b7711ff52 100644 --- a/gio/gunixvolumemonitor.c +++ b/gio/gunixvolumemonitor.c @@ -183,21 +183,15 @@ 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; - _g_unix_volume_monitor_update (unix_monitor); + /* Update both to make sure volumes are created before mounts */ + update_volumes (unix_monitor); + update_mounts (unix_monitor); } static void @@ -206,7 +200,9 @@ mounts_changed (GUnixMountMonitor *mount_monitor, { GUnixVolumeMonitor *unix_monitor = user_data; - _g_unix_volume_monitor_update (unix_monitor); + /* Update both to make sure volumes are created before mounts */ + update_volumes (unix_monitor); + update_mounts (unix_monitor); } static void @@ -223,7 +219,8 @@ g_unix_volume_monitor_init (GUnixVolumeMonitor *unix_monitor) "mountpoints-changed", G_CALLBACK (mountpoints_changed), unix_monitor); - _g_unix_volume_monitor_update (unix_monitor); + update_volumes (unix_monitor); + update_mounts (unix_monitor); } GVolumeMonitor * diff --git a/gio/gunixvolumemonitor.h b/gio/gunixvolumemonitor.h index 14e07fb9f..4f54fc23c 100644 --- a/gio/gunixvolumemonitor.h +++ b/gio/gunixvolumemonitor.h @@ -55,7 +55,6 @@ 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/gwin32notificationbackend.c b/gio/gwin32notificationbackend.c new file mode 100644 index 000000000..7200fdffb --- /dev/null +++ b/gio/gwin32notificationbackend.c @@ -0,0 +1,90 @@ +/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */ +/* GIO - GLib Input, Output and Streaming Library + * + * Copyright © 2018 Endless Mobile, Inc. + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General + * Public License along with this library; if not, see + * <http://www.gnu.org/licenses/>. + * + * Authors: + * - Philip Withnall <withnall@endlessm.com> + */ + +#include "config.h" + +#include "gnotificationbackend.h" + +#include "giomodule-priv.h" +#include "gnotification-private.h" + +#define G_TYPE_WIN32_NOTIFICATION_BACKEND (g_win32_notification_backend_get_type ()) +#define G_WIN32_NOTIFICATION_BACKEND(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_WIN32_NOTIFICATION_BACKEND, GWin32NotificationBackend)) + +typedef struct _GWin32NotificationBackend GWin32NotificationBackend; +typedef GNotificationBackendClass GWin32NotificationBackendClass; + +struct _GWin32NotificationBackend +{ + GNotificationBackend parent; +}; + +GType g_win32_notification_backend_get_type (void); + +G_DEFINE_TYPE_WITH_CODE (GWin32NotificationBackend, g_win32_notification_backend, G_TYPE_NOTIFICATION_BACKEND, + _g_io_modules_ensure_extension_points_registered (); + g_io_extension_point_implement (G_NOTIFICATION_BACKEND_EXTENSION_POINT_NAME, + g_define_type_id, "win32", 0)) + +static gboolean +g_win32_notification_backend_is_supported (void) +{ + /* This is the only backend supported on Windows, and always needs to be + * present to avoid no backend being selected. */ + return TRUE; +} + +static void +g_win32_notification_backend_send_notification (GNotificationBackend *backend, + const gchar *id, + GNotification *notification) +{ + /* FIXME: See https://bugzilla.gnome.org/show_bug.cgi?id=776583. This backend + * exists purely to stop crashes when applications use g_notification*() + * on Windows, by providing a dummy backend implementation. (The alternative + * was to modify all of the backend call sites in g_notification*(), which + * seemed less scalable.) */ + g_warning ("Notifications are not yet supported on Windows."); +} + +static void +g_win32_notification_backend_withdraw_notification (GNotificationBackend *backend, + const gchar *id) +{ + /* FIXME: Nothing needs doing here until send_notification() is implemented. */ +} + +static void +g_win32_notification_backend_init (GWin32NotificationBackend *backend) +{ +} + +static void +g_win32_notification_backend_class_init (GWin32NotificationBackendClass *class) +{ + GNotificationBackendClass *backend_class = G_NOTIFICATION_BACKEND_CLASS (class); + + backend_class->is_supported = g_win32_notification_backend_is_supported; + backend_class->send_notification = g_win32_notification_backend_send_notification; + backend_class->withdraw_notification = g_win32_notification_backend_withdraw_notification; +} diff --git a/gio/gzlibcompressor.c b/gio/gzlibcompressor.c index 239d143cc..53f3e4745 100644 --- a/gio/gzlibcompressor.c +++ b/gio/gzlibcompressor.c @@ -90,7 +90,7 @@ g_zlib_compressor_set_gzheader (GZlibCompressor *compressor) G_FILE_ATTRIBUTE_TIME_MODIFIED); if (deflateSetHeader (&compressor->zstream, &compressor->gzheader) != Z_OK) - g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); + g_warning ("unexpected zlib error: %s", compressor->zstream.msg); #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */ } @@ -211,7 +211,7 @@ g_zlib_compressor_constructed (GObject *object) g_error ("GZlibCompressor: Not enough memory for zlib use"); if (res != Z_OK) - g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); + g_warning ("unexpected zlib error: %s", compressor->zstream.msg); g_zlib_compressor_set_gzheader (compressor); } @@ -351,7 +351,7 @@ g_zlib_compressor_reset (GConverter *converter) res = deflateReset (&compressor->zstream); if (res != Z_OK) - g_warning ("unexpected zlib error: %s\n", compressor->zstream.msg); + g_warning ("unexpected zlib error: %s", compressor->zstream.msg); /* deflateReset reset the header too, so re-set it */ g_zlib_compressor_set_gzheader (compressor); diff --git a/gio/gzlibdecompressor.c b/gio/gzlibdecompressor.c index d16d3f717..cf2542ef8 100644 --- a/gio/gzlibdecompressor.c +++ b/gio/gzlibdecompressor.c @@ -95,7 +95,7 @@ g_zlib_decompressor_set_gzheader (GZlibDecompressor *decompressor) decompressor->header_data->gzheader.name_max = 256; if (inflateGetHeader (&decompressor->zstream, &decompressor->header_data->gzheader) != Z_OK) - g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); + g_warning ("unexpected zlib error: %s", decompressor->zstream.msg); #endif /* !G_OS_WIN32 || ZLIB >= 1.2.4 */ } @@ -205,7 +205,7 @@ g_zlib_decompressor_constructed (GObject *object) g_error ("GZlibDecompressor: Not enough memory for zlib use"); if (res != Z_OK) - g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); + g_warning ("unexpected zlib error: %s", decompressor->zstream.msg); g_zlib_decompressor_set_gzheader (decompressor); } @@ -305,7 +305,7 @@ g_zlib_decompressor_reset (GConverter *converter) res = inflateReset (&decompressor->zstream); if (res != Z_OK) - g_warning ("unexpected zlib error: %s\n", decompressor->zstream.msg); + g_warning ("unexpected zlib error: %s", decompressor->zstream.msg); g_zlib_decompressor_set_gzheader (decompressor); } diff --git a/gio/inotify/inotify-helper.c b/gio/inotify/inotify-helper.c index 0a0a84ab9..d94458753 100644 --- a/gio/inotify/inotify-helper.c +++ b/gio/inotify/inotify-helper.c @@ -205,6 +205,8 @@ ih_event_callback (ik_event_t *event, /* unpaired event -- no 'other' field */ interesting = g_file_monitor_source_handle_event (sub->user_data, event_flags, event->name, NULL, NULL, event->timestamp); + else + interesting = FALSE; if (event->mask & IN_CREATE) { diff --git a/gio/kqueue/Makefile.am b/gio/kqueue/Makefile.am index d5657d7e4..24e9724e5 100644 --- a/gio/kqueue/Makefile.am +++ b/gio/kqueue/Makefile.am @@ -4,19 +4,9 @@ noinst_LTLIBRARIES += libkqueue.la libkqueue_la_SOURCES = \ gkqueuefilemonitor.c \ - gkqueuefilemonitor.h \ kqueue-helper.c \ kqueue-helper.h \ - kqueue-thread.c \ - kqueue-thread.h \ - kqueue-sub.c \ - kqueue-sub.h \ kqueue-missing.c \ - kqueue-missing.h \ - kqueue-utils.c \ - kqueue-utils.h \ - kqueue-exclusions.c \ - kqueue-exclusions.h \ dep-list.c \ dep-list.h \ $(NULL) diff --git a/gio/kqueue/dep-list.c b/gio/kqueue/dep-list.c index af0010c72..d8c3d8a01 100644 --- a/gio/kqueue/dep-list.c +++ b/gio/kqueue/dep-list.c @@ -84,18 +84,22 @@ dep_list* dl_create (char *path, ino_t inode) dep_list* dl_shallow_copy (const dep_list *dl) { + dep_list *head; + dep_list *cp; + const dep_list *it; + if (dl == NULL) { return NULL; } - dep_list *head = calloc (1, sizeof (dep_list)); + head = calloc (1, sizeof (dep_list)); if (head == NULL) { perror_msg ("Failed to allocate head during shallow copy"); return NULL; } - dep_list *cp = head; - const dep_list *it = dl; + cp = head; + it = dl; while (it != NULL) { cp->path = it->path; @@ -162,15 +166,19 @@ dl_free (dep_list *dl) dep_list* dl_listing (const char *path) { - assert (path != NULL); - dep_list *head = NULL; dep_list *prev = NULL; - DIR *dir = opendir (path); + DIR *dir; + + assert (path != NULL); + + dir = opendir (path); if (dir != NULL) { struct dirent *ent; while ((ent = readdir (dir)) != NULL) { + dep_list *iter; + if (!strcmp (ent->d_name, ".") || !strcmp (ent->d_name, "..")) { continue; } @@ -183,7 +191,7 @@ dl_listing (const char *path) } } - dep_list *iter = (prev == NULL) ? head : calloc (1, sizeof (dep_list)); + iter = (prev == NULL) ? head : calloc (1, sizeof (dep_list)); if (iter == NULL) { perror_msg ("Failed to allocate a new element during listing"); goto error; @@ -229,6 +237,9 @@ error: void dl_diff (dep_list **before, dep_list **after) { + dep_list *before_iter; + dep_list *before_prev; + assert (before != NULL); assert (after != NULL); @@ -236,12 +247,13 @@ dl_diff (dep_list **before, dep_list **after) return; } - dep_list *before_iter = *before; - dep_list *before_prev = NULL; + before_iter = *before; + before_prev = NULL; while (before_iter != NULL) { dep_list *after_iter = *after; dep_list *after_prev = NULL; + dep_list *oldptr; int matched = 0; while (after_iter != NULL) { @@ -266,7 +278,7 @@ dl_diff (dep_list **before, dep_list **after) after_iter = after_iter->next; } - dep_list *oldptr = before_iter; + oldptr = before_iter; before_iter = before_iter->next; if (matched == 0) { before_prev = oldptr; @@ -283,17 +295,21 @@ dl_diff (dep_list **before, dep_list **after) * from the both lists. **/ #define EXCLUDE_SIMILAR(removed_list, added_list, match_expr, matched_code) \ +G_STMT_START { \ + dep_list *removed_list##_iter; \ + dep_list *removed_list##_prev; \ + int productive = 0; \ + \ assert (removed_list != NULL); \ assert (added_list != NULL); \ \ - dep_list *removed_list##_iter = *removed_list; \ - dep_list *removed_list##_prev = NULL; \ - \ - int productive = 0; \ + removed_list##_iter = *removed_list; \ + removed_list##_prev = NULL; \ \ while (removed_list##_iter != NULL) { \ dep_list *added_list##_iter = *added_list; \ dep_list *added_list##_prev = NULL; \ + dep_list *oldptr; \ \ int matched = 0; \ while (added_list##_iter != NULL) { \ @@ -317,7 +333,7 @@ dl_diff (dep_list **before, dep_list **after) } \ added_list##_iter = added_list##_iter->next; \ } \ - dep_list *oldptr = removed_list##_iter; \ + oldptr = removed_list##_iter; \ removed_list##_iter = removed_list##_iter->next; \ if (matched == 0) { \ removed_list##_prev = oldptr; \ @@ -325,7 +341,8 @@ dl_diff (dep_list **before, dep_list **after) free (oldptr); \ } \ } \ - return (productive > 0); + return (productive > 0); \ +} G_STMT_END #define cb_invoke(cbs, name, udata, ...) \ @@ -488,15 +505,14 @@ dl_calculate (dep_list *before, const traverse_cbs *cbs, void *udata) { - assert (cbs != NULL); - int need_update = 0; - dep_list *was = dl_shallow_copy (before); dep_list *pre = dl_shallow_copy (before); dep_list *now = dl_shallow_copy (after); dep_list *lst = dl_shallow_copy (after); + assert (cbs != NULL); + dl_diff (&was, &now); need_update += dl_detect_moves (&was, &now, cbs, udata); diff --git a/gio/kqueue/gkqueuefilemonitor.c b/gio/kqueue/gkqueuefilemonitor.c index 78b749637..d6fea41cf 100644 --- a/gio/kqueue/gkqueuefilemonitor.c +++ b/gio/kqueue/gkqueuefilemonitor.c @@ -22,33 +22,73 @@ #include "config.h" -#include "gkqueuefilemonitor.h" -#include "kqueue-helper.h" -#include "kqueue-exclusions.h" +#include <sys/types.h> +#include <sys/event.h> +#include <sys/time.h> +#include <sys/socket.h> +#include <sys/stat.h> + +#include <errno.h> +#include <fcntl.h> +#include <string.h> + +#include <glib-object.h> +#include <gio/gfilemonitor.h> +#include <gio/glocalfilemonitor.h> +#include <gio/giomodule.h> #include <gio/gpollfilemonitor.h> #include <gio/gfile.h> -#include <gio/giomodule.h> +#include <glib-unix.h> +#include "glib-private.h" + +#include "kqueue-helper.h" +#include "dep-list.h" + +G_LOCK_DEFINE_STATIC (kq_lock); +static GSource *kq_source; +static int kq_queue = -1; + +#define G_TYPE_KQUEUE_FILE_MONITOR (g_kqueue_file_monitor_get_type ()) +#define G_KQUEUE_FILE_MONITOR(inst) (G_TYPE_CHECK_INSTANCE_CAST ((inst), \ + G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor)) +typedef GLocalFileMonitorClass GKqueueFileMonitorClass; -struct _GKqueueFileMonitor +typedef struct { GLocalFileMonitor parent_instance; kqueue_sub *sub; - +#ifndef O_EVTONLY GFileMonitor *fallback; GFile *fbfile; -}; +#endif +} GKqueueFileMonitor; + +GType g_kqueue_file_monitor_get_type (void); +G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR, + g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, + g_define_type_id, + "kqueue", + 20)) + +#ifndef O_EVTONLY +#define O_KQFLAG O_RDONLY +#else +#define O_KQFLAG O_EVTONLY +#endif + +#define NOTE_ALL (NOTE_DELETE|NOTE_WRITE|NOTE_EXTEND|NOTE_ATTRIB|NOTE_RENAME) static gboolean g_kqueue_file_monitor_cancel (GFileMonitor* monitor); +static gboolean g_kqueue_file_monitor_is_supported (void); -G_DEFINE_TYPE_WITH_CODE (GKqueueFileMonitor, g_kqueue_file_monitor, G_TYPE_LOCAL_FILE_MONITOR, - g_io_extension_point_implement (G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME, - g_define_type_id, - "kqueue", - 20)) +static kqueue_sub *_kqsub_new (const gchar *, GLocalFileMonitor *, GFileMonitorSource *); +static void _kqsub_free (kqueue_sub *); +static gboolean _kqsub_cancel (kqueue_sub *); +#ifndef O_EVTONLY static void _fallback_callback (GFileMonitor *unused, GFile *first, @@ -57,21 +97,41 @@ _fallback_callback (GFileMonitor *unused, gpointer udata) { GKqueueFileMonitor *kq_mon = G_KQUEUE_FILE_MONITOR (udata); - GFileMonitor *mon = G_FILE_MONITOR (kq_mon); - g_assert (kq_mon != NULL); - g_assert (mon != NULL); - (void) unused; - if (event == G_FILE_MONITOR_EVENT_CHANGED) - { - GLocalFileMonitor *local_monitor = G_LOCAL_FILE_MONITOR (kq_mon); - - _kh_dir_diff (kq_mon->sub, local_monitor->source); - } - else - g_file_monitor_emit_event (mon, first, second, event); + g_file_monitor_emit_event (G_FILE_MONITOR (kq_mon), first, second, event); } +/* + * _ke_is_excluded: + * @full_path - a path to file to check. + * + * Returns: TRUE if the file should be excluded from the kqueue-powered + * monitoring, FALSE otherwise. + **/ +gboolean +_ke_is_excluded (const char *full_path) +{ + GFile *f = NULL; + GMount *mount = NULL; + + f = g_file_new_for_path (full_path); + + if (f != NULL) { + mount = g_file_find_enclosing_mount (f, NULL, NULL); + g_object_unref (f); + } + + if ((mount != NULL && (g_mount_can_unmount (mount))) || g_str_has_prefix (full_path, "/mnt/")) + { + g_warning ("Excluding %s from kernel notification, falling back to poll", full_path); + if (mount) + g_object_unref (mount); + return TRUE; + } + + return FALSE; +} +#endif /* !O_EVTONLY */ static void g_kqueue_file_monitor_finalize (GObject *object) @@ -80,16 +140,18 @@ g_kqueue_file_monitor_finalize (GObject *object) if (kqueue_monitor->sub) { - _kh_cancel_sub (kqueue_monitor->sub); - _kh_sub_free (kqueue_monitor->sub); + _kqsub_cancel (kqueue_monitor->sub); + _kqsub_free (kqueue_monitor->sub); kqueue_monitor->sub = NULL; } +#ifndef O_EVTONLY if (kqueue_monitor->fallback) g_object_unref (kqueue_monitor->fallback); if (kqueue_monitor->fbfile) g_object_unref (kqueue_monitor->fbfile); +#endif if (G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (*G_OBJECT_CLASS (g_kqueue_file_monitor_parent_class)->finalize) (object); @@ -103,21 +165,25 @@ g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor, GFileMonitorSource *source) { GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (local_monitor); - GObject *obj; - GKqueueFileMonitorClass *klass; - GObjectClass *parent_class; - kqueue_sub *sub = NULL; - gboolean ret_kh_startup = FALSE; - const gchar *path = NULL; - - - ret_kh_startup = _kh_startup (); - g_assert (ret_kh_startup); + kqueue_sub *sub; + const gchar *path; path = filename; - if (!path) + if (path == NULL) path = dirname; +#ifndef O_EVTONLY + if (_ke_is_excluded (path)) + { + GFile *file = g_file_new_for_path (path); + kqueue_monitor->fbfile = file; + kqueue_monitor->fallback = _g_poll_file_monitor_new (file); + g_signal_connect (kqueue_monitor->fallback, "changed", + G_CALLBACK (_fallback_callback), kqueue_monitor); + return; + } +#endif + /* For a directory monitor, create a subscription object anyway. * It will be used for directory diff calculation routines. * Wait, directory diff in a GKqueueFileMonitor? @@ -125,33 +191,13 @@ g_kqueue_file_monitor_start (GLocalFileMonitor *local_monitor, * file, GIO uses a GKqueueFileMonitor object for that. If a directory * will be created under that path, GKqueueFileMonitor will have to * handle the directory notifications. */ + sub = _kqsub_new (path, local_monitor, source); + if (sub == NULL) + return; - sub = _kh_sub_new (path, TRUE, source); - - /* FIXME: what to do about errors here? we can't return NULL or another - * kind of error and an assertion is probably too hard (same issue as in - * the inotify backend) */ - g_assert (sub != NULL); kqueue_monitor->sub = sub; - - if (!_ke_is_excluded (path)) - _kh_add_sub (sub); - else - { - GFile *file = g_file_new_for_path (path); - kqueue_monitor->fbfile = file; - kqueue_monitor->fallback = _g_poll_file_monitor_new (file); - g_signal_connect (kqueue_monitor->fallback, - "changed", - G_CALLBACK (_fallback_callback), - kqueue_monitor); - } -} - -static gboolean -g_kqueue_file_monitor_is_supported (void) -{ - return _kh_startup (); + if (!_kqsub_start_watching (sub)) + _km_add_missing (sub); } static void @@ -175,24 +221,218 @@ g_kqueue_file_monitor_init (GKqueueFileMonitor *monitor) } static gboolean +g_kqueue_file_monitor_callback (gint fd, GIOCondition condition, gpointer user_data) +{ + gint64 now = g_source_get_time (kq_source); + kqueue_sub *sub; + GFileMonitorSource *source; + struct kevent ev; + struct timespec ts; + + memset (&ts, 0, sizeof(ts)); + while (kevent(fd, NULL, 0, &ev, 1, &ts) > 0) + { + GFileMonitorEvent mask = 0; + + if (ev.filter != EVFILT_VNODE || ev.udata == NULL) + continue; + + sub = ev.udata; + source = sub->source; + + if (ev.flags & EV_ERROR) + ev.fflags = NOTE_REVOKE; + + if (ev.fflags & (NOTE_DELETE | NOTE_REVOKE)) + { + _kqsub_cancel (sub); + _km_add_missing (sub); + } + + if (sub->is_dir && ev.fflags & (NOTE_WRITE | NOTE_EXTEND)) + { + _kh_dir_diff (sub); + ev.fflags &= ~(NOTE_WRITE | NOTE_EXTEND); + } + + if (ev.fflags & NOTE_DELETE) + { + mask = G_FILE_MONITOR_EVENT_DELETED; + } + else if (ev.fflags & NOTE_ATTRIB) + { + mask = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED; + } + else if (ev.fflags & (NOTE_WRITE | NOTE_EXTEND)) + { + mask = G_FILE_MONITOR_EVENT_CHANGED; + } + else if (ev.fflags & NOTE_RENAME) + { + /* Since there’s apparently no way to get the new name of the + * file out of kqueue(), all we can do is say that this one has + * been deleted. */ + mask = G_FILE_MONITOR_EVENT_DELETED; + } + else if (ev.fflags & NOTE_REVOKE) + { + mask = G_FILE_MONITOR_EVENT_UNMOUNTED; + } + + if (mask) + g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, now); + } + + return TRUE; +} + +static gboolean +g_kqueue_file_monitor_is_supported (void) +{ + int errsv; + + G_LOCK (kq_lock); + + if (kq_queue == -1) + { + kq_queue = kqueue (); + errsv = errno; + + if (kq_queue == -1) + { + g_warning ("Unable to create a kqueue: %s", g_strerror (errsv)); + G_UNLOCK (kq_lock); + return FALSE; + } + + kq_source = g_unix_fd_source_new (kq_queue, G_IO_IN); + g_source_set_callback (kq_source, (GSourceFunc) g_kqueue_file_monitor_callback, NULL, NULL); + g_source_attach (kq_source, GLIB_PRIVATE_CALL (g_get_worker_context) ()); + } + + G_UNLOCK (kq_lock); + + return TRUE; +} + +static gboolean g_kqueue_file_monitor_cancel (GFileMonitor *monitor) { GKqueueFileMonitor *kqueue_monitor = G_KQUEUE_FILE_MONITOR (monitor); if (kqueue_monitor->sub) { - _kh_cancel_sub (kqueue_monitor->sub); - _kh_sub_free (kqueue_monitor->sub); + _kqsub_cancel (kqueue_monitor->sub); + _kqsub_free (kqueue_monitor->sub); kqueue_monitor->sub = NULL; } +#ifndef O_EVTONLY else if (kqueue_monitor->fallback) { g_signal_handlers_disconnect_by_func (kqueue_monitor->fallback, _fallback_callback, kqueue_monitor); g_file_monitor_cancel (kqueue_monitor->fallback); } +#endif if (G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (*G_FILE_MONITOR_CLASS (g_kqueue_file_monitor_parent_class)->cancel) (monitor); return TRUE; } + +static kqueue_sub * +_kqsub_new (const gchar *filename, GLocalFileMonitor *mon, GFileMonitorSource *source) +{ + kqueue_sub *sub; + + sub = g_slice_new (kqueue_sub); + sub->filename = g_strdup (filename); + sub->mon = mon; + g_source_ref ((GSource *) source); + sub->source = source; + sub->fd = -1; + sub->deps = NULL; + sub->is_dir = 0; + + return sub; +} + +static void +_kqsub_free (kqueue_sub *sub) +{ + g_assert (sub->deps == NULL); + g_assert (sub->fd == -1); + + g_source_unref ((GSource *) sub->source); + g_free (sub->filename); + g_slice_free (kqueue_sub, sub); +} + +static gboolean +_kqsub_cancel (kqueue_sub *sub) +{ + struct kevent ev; + + /* Remove the event and close the file descriptor to automatically + * delete pending events. */ + if (sub->fd != -1) + { + EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_DELETE, NOTE_ALL, 0, sub); + if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1) + { + g_warning ("Unable to remove event for %s: %s", sub->filename, g_strerror (errno)); + return FALSE; + } + close (sub->fd); + sub->fd = -1; + } + + _km_remove (sub); + + if (sub->deps) + { + dl_free (sub->deps); + sub->deps = NULL; + } + + return TRUE; +} + +gboolean +_kqsub_start_watching (kqueue_sub *sub) +{ + struct stat st; + struct kevent ev; + + sub->fd = open (sub->filename, O_KQFLAG); + if (sub->fd == -1) + return FALSE; + + if (fstat (sub->fd, &st) == -1) + { + g_warning ("fstat failed for %s: %s", sub->filename, g_strerror (errno)); + close (sub->fd); + sub->fd = -1; + return FALSE; + } + + sub->is_dir = (st.st_mode & S_IFDIR) ? 1 : 0; + if (sub->is_dir) + { + if (sub->deps) + dl_free (sub->deps); + + sub->deps = dl_listing (sub->filename); + } + + EV_SET (&ev, sub->fd, EVFILT_VNODE, EV_ADD | EV_CLEAR, NOTE_ALL, 0, sub); + if (kevent (kq_queue, &ev, 1, NULL, 0, NULL) == -1) + { + g_warning ("Unable to add event for %s: %s", sub->filename, g_strerror (errno)); + close (sub->fd); + sub->fd = -1; + return FALSE; + } + + return TRUE; +} diff --git a/gio/kqueue/gkqueuefilemonitor.h b/gio/kqueue/gkqueuefilemonitor.h deleted file mode 100644 index 32752f105..000000000 --- a/gio/kqueue/gkqueuefilemonitor.h +++ /dev/null @@ -1,51 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __G_KQUEUE_FILE_MONITOR_H__ -#define __G_KQUEUE_FILE_MONITOR_H__ - -#include <glib-object.h> -#include <string.h> -#include <gio/gfilemonitor.h> -#include <gio/glocalfilemonitor.h> -#include <gio/giomodule.h> - -G_BEGIN_DECLS - -#define G_TYPE_KQUEUE_FILE_MONITOR (g_kqueue_file_monitor_get_type ()) -#define G_KQUEUE_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitor)) -#define G_KQUEUE_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), G_TYPE_KQUEUE_FILE_MONITOR, GKqueueFileMonitorClass)) -#define G_IS_KQUEUE_FILE_MONITOR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_KQUEUE_FILE_MONITOR)) -#define G_IS_KQUEUE_FILE_MONITOR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_KQUEUE_FILE_MONITOR)) - -typedef struct _GKqueueFileMonitor GKqueueFileMonitor; -typedef struct _GKqueueFileMonitorClass GKqueueFileMonitorClass; - -struct _GKqueueFileMonitorClass { - GLocalFileMonitorClass parent_class; -}; - -GType g_kqueue_file_monitor_get_type (void); - -G_END_DECLS - -#endif /* __G_KQUEUE_FILE_MONITOR_H__ */ diff --git a/gio/kqueue/kqueue-exclusions.c b/gio/kqueue/kqueue-exclusions.c deleted file mode 100644 index 748d7a92a..000000000 --- a/gio/kqueue/kqueue-exclusions.c +++ /dev/null @@ -1,65 +0,0 @@ -/******************************************************************************* - Copyright (c) 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - Copyright (c) 2012 Antoine Jacoutot <ajacoutot@openbsd.org> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#include <fcntl.h> -#include <glib.h> -#include <gio/gio.h> -#include "kqueue-exclusions.h" - -static gboolean ke_debug_enabled = FALSE; -#define KE_W if (ke_debug_enabled) g_warning - -/* - * _ke_is_excluded: - * @full_path - a path to file to check. - * - * Returns: TRUE if the file should be excluded from the kqueue-powered - * monitoring, FALSE otherwise. - **/ -gboolean -_ke_is_excluded (const char *full_path) -{ -#if defined (O_EVTONLY) - return FALSE; -#else - GFile *f = NULL; - GMount *mount = NULL; - - f = g_file_new_for_path (full_path); - - if (f != NULL) { - mount = g_file_find_enclosing_mount (f, NULL, NULL); - g_object_unref (f); - } - - if ((mount != NULL && (g_mount_can_unmount (mount))) || g_str_has_prefix (full_path, "/mnt/")) - { - KE_W ("Excluding %s from kernel notification, falling back to poll", full_path); - if (mount) - g_object_unref (mount); - return TRUE; - } - else - return FALSE; -#endif -} diff --git a/gio/kqueue/kqueue-exclusions.h b/gio/kqueue/kqueue-exclusions.h deleted file mode 100644 index f1dad0e7e..000000000 --- a/gio/kqueue/kqueue-exclusions.h +++ /dev/null @@ -1,28 +0,0 @@ -/******************************************************************************* - Copyright (c) 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __KQUEUE_EXCLUSIONS_H -#define __KQUEUE_EXCLUSIONS_H - -gboolean _ke_is_excluded (const char *full_path); - -#endif /* __KQUEUE_EXCLUDES_H */ diff --git a/gio/kqueue/kqueue-helper.c b/gio/kqueue/kqueue-helper.c index e7d583c8b..497c30b15 100644 --- a/gio/kqueue/kqueue-helper.c +++ b/gio/kqueue/kqueue-helper.c @@ -34,83 +34,6 @@ #include <errno.h> #include <pthread.h> #include "kqueue-helper.h" -#include "kqueue-utils.h" -#include "kqueue-thread.h" -#include "kqueue-missing.h" -#include "kqueue-exclusions.h" - -static gboolean kh_debug_enabled = FALSE; -#define KH_W if (kh_debug_enabled) g_warning - -static GHashTable *subs_hash_table = NULL; -G_LOCK_DEFINE_STATIC (hash_lock); - -static int kqueue_descriptor = -1; -static int kqueue_socket_pair[] = {-1, -1}; -static pthread_t kqueue_thread; - - -void _kh_file_appeared_cb (kqueue_sub *sub); - -/** - * accessor function for kqueue_descriptor - **/ -int -get_kqueue_descriptor() -{ - return kqueue_descriptor; -} - -/** - * convert_kqueue_events_to_gio: - * @flags: a set of kqueue filter flags - * @done: a pointer to #gboolean indicating that the - * conversion has been done (out) - * - * Translates kqueue filter flags into GIO event flags. - * - * Returns: a #GFileMonitorEvent - **/ -static GFileMonitorEvent -convert_kqueue_events_to_gio (uint32_t flags, gboolean *done) -{ - g_assert (done != NULL); - *done = FALSE; - - /* TODO: The following notifications should be emulated, if possible: - * - G_FILE_MONITOR_EVENT_PRE_UNMOUNT - */ - if (flags & NOTE_DELETE) - { - *done = TRUE; - return G_FILE_MONITOR_EVENT_DELETED; - } - if (flags & NOTE_ATTRIB) - { - *done = TRUE; - return G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED; - } - if (flags & (NOTE_WRITE | NOTE_EXTEND)) - { - *done = TRUE; - return G_FILE_MONITOR_EVENT_CHANGED; - } - if (flags & NOTE_RENAME) - { - /* Since there’s apparently no way to get the new name of the file out of - * kqueue(), all we can do is say that this one has been deleted. */ - *done = TRUE; - return G_FILE_MONITOR_EVENT_DELETED; - } - if (flags & NOTE_REVOKE) - { - *done = TRUE; - return G_FILE_MONITOR_EVENT_UNMOUNTED; - } - - /* done is FALSE */ - return 0; -} typedef struct { kqueue_sub *sub; @@ -238,318 +161,21 @@ static const traverse_cbs cbs = { void -_kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source) +_kh_dir_diff (kqueue_sub *sub) { dep_list *was; handle_ctx ctx; - g_assert (sub != NULL); - g_assert (source != NULL); - memset (&ctx, 0, sizeof (handle_ctx)); ctx.sub = sub; - ctx.source = source; + ctx.source = sub->source; was = sub->deps; sub->deps = dl_listing (sub->filename); - + dl_calculate (was, sub->deps, &cbs, &ctx); dl_free (was); } -/** - * process_kqueue_notifications: - * @gioc: unused. - * @cond: unused. - * @data: unused. - * - * Processes notifications, coming from the kqueue thread. - * - * Reads notifications from the command file descriptor, emits the - * "changed" event on the appropriate monitor. - * - * A typical GIO Channel callback function. - * - * Returns: %TRUE - **/ -static gboolean -process_kqueue_notifications (GIOChannel *gioc, - GIOCondition cond, - gpointer data) -{ - struct kqueue_notification n; - kqueue_sub *sub = NULL; - GFileMonitorSource *source = NULL; - GFileMonitorEvent mask = 0; - - g_assert (kqueue_socket_pair[0] != -1); - if (!_ku_read (kqueue_socket_pair[0], &n, sizeof (struct kqueue_notification))) - { - KH_W ("Failed to read a kqueue notification, error %d", errno); - return TRUE; - } - - G_LOCK (hash_lock); - sub = (kqueue_sub *) g_hash_table_lookup (subs_hash_table, GINT_TO_POINTER (n.fd)); - G_UNLOCK (hash_lock); - - if (sub == NULL) - { - KH_W ("Got a notification for a deleted or non-existing subscription %d", - n.fd); - return TRUE; - } - - source = sub->user_data; - g_assert (source != NULL); - - if (n.flags & (NOTE_DELETE | NOTE_REVOKE)) - { - if (sub->deps) - { - dl_free (sub->deps); - sub->deps = NULL; - } - _km_add_missing (sub); - - if (!(n.flags & NOTE_REVOKE)) - { - /* Note that NOTE_REVOKE is issued by the kqueue thread - * on EV_ERROR kevent. In this case, a file descriptor is - * already closed from the kqueue thread, no need to close - * it manually */ - _kh_cancel_sub (sub); - } - } - - if (sub->is_dir && n.flags & (NOTE_WRITE | NOTE_EXTEND)) - { - _kh_dir_diff (sub, source); - n.flags &= ~(NOTE_WRITE | NOTE_EXTEND); - } - - if (n.flags) - { - gboolean done = FALSE; - mask = convert_kqueue_events_to_gio (n.flags, &done); - if (done == TRUE) - g_file_monitor_source_handle_event (source, mask, NULL, NULL, NULL, g_get_monotonic_time ()); - } - - return TRUE; -} - - -/* - * _kh_startup_impl: - * @unused: unused - * - * Kqueue backend startup code. Should be called only once. - * - * Returns: %TRUE on success, %FALSE otherwise. - **/ -static gpointer -_kh_startup_impl (gpointer unused) -{ - GIOChannel *channel = NULL; - gboolean result = FALSE; - - kqueue_descriptor = kqueue (); - result = (kqueue_descriptor != -1); - if (!result) - { - KH_W ("Failed to initialize kqueue\n!"); - return GINT_TO_POINTER (FALSE); - } - - result = socketpair (AF_UNIX, SOCK_STREAM, 0, kqueue_socket_pair); - if (result != 0) - { - KH_W ("Failed to create socket pair\n!"); - return GINT_TO_POINTER (FALSE) ; - } - - result = pthread_create (&kqueue_thread, - NULL, - _kqueue_thread_func, - &kqueue_socket_pair[1]); - if (result != 0) - { - KH_W ("Failed to run kqueue thread\n!"); - return GINT_TO_POINTER (FALSE); - } - - _km_init (_kh_file_appeared_cb); - - channel = g_io_channel_unix_new (kqueue_socket_pair[0]); - g_io_add_watch (channel, G_IO_IN, process_kqueue_notifications, NULL); - - subs_hash_table = g_hash_table_new (g_direct_hash, g_direct_equal); - - KH_W ("started gio kqueue backend\n"); - return GINT_TO_POINTER (TRUE); -} - - -/* - * _kh_startup: - * Kqueue backend initialization. - * - * Returns: %TRUE on success, %FALSE otherwise. - **/ -gboolean -_kh_startup (void) -{ - static GOnce init_once = G_ONCE_INIT; - g_once (&init_once, _kh_startup_impl, NULL); - return GPOINTER_TO_INT (init_once.retval); -} - - -/** - * _kh_start_watching: - * @sub: a #kqueue_sub - * - * Starts watching on a subscription. - * - * Returns: %TRUE on success, %FALSE otherwise. - **/ -gboolean -_kh_start_watching (kqueue_sub *sub) -{ - g_assert (kqueue_socket_pair[0] != -1); - g_assert (sub != NULL); - g_assert (sub->filename != NULL); - - /* kqueue requires a file descriptor to monitor. Sad but true */ -#if defined (O_EVTONLY) - sub->fd = open (sub->filename, O_EVTONLY); -#else - sub->fd = open (sub->filename, O_RDONLY); -#endif - - if (sub->fd == -1) - { - KH_W ("failed to open file %s (error %d)", sub->filename, errno); - return FALSE; - } - - _ku_file_information (sub->fd, &sub->is_dir, NULL); - if (sub->is_dir) - { - /* I know, it is very bad to make such decisions in this way and here. - * We already do have an user_data at the #kqueue_sub, and it may point to - * GKqueueFileMonitor or GKqueueDirectoryMonitor. For a directory case, - * we need to scan in contents for the further diffs. Ideally this process - * should be delegated to the GKqueueDirectoryMonitor, but for now I will - * do it in a dirty way right here. */ - if (sub->deps) - dl_free (sub->deps); - - sub->deps = dl_listing (sub->filename); - } - - G_LOCK (hash_lock); - g_hash_table_insert (subs_hash_table, GINT_TO_POINTER (sub->fd), sub); - G_UNLOCK (hash_lock); - - _kqueue_thread_push_fd (sub->fd); - - /* Bump the kqueue thread. It will pick up a new sub entry to monitor */ - if (!_ku_write (kqueue_socket_pair[0], "A", 1)) - KH_W ("Failed to bump the kqueue thread (add fd, error %d)", errno); - return TRUE; -} - - -/** - * _kh_add_sub: - * @sub: a #kqueue_sub - * - * Adds a subscription for monitoring. - * - * This funciton tries to start watching a subscription with - * _kh_start_watching(). On failure, i.e. when a file does not exist yet, - * the subscription will be added to a list of missing files to continue - * watching when the file will appear. - * - * Returns: %TRUE - **/ -gboolean -_kh_add_sub (kqueue_sub *sub) -{ - g_assert (sub != NULL); - - if (!_kh_start_watching (sub)) - _km_add_missing (sub); - - return TRUE; -} - - -/** - * _kh_cancel_sub: - * @sub a #kqueue_sub - * - * Stops monitoring on a subscription. - * - * Returns: %TRUE - **/ -gboolean -_kh_cancel_sub (kqueue_sub *sub) -{ - gboolean removed = FALSE; - g_assert (kqueue_socket_pair[0] != -1); - g_assert (sub != NULL); - - _km_remove (sub); - - G_LOCK (hash_lock); - removed = g_hash_table_remove (subs_hash_table, GINT_TO_POINTER (sub->fd)); - G_UNLOCK (hash_lock); - - if (removed) - { - /* fd will be closed in the kqueue thread */ - _kqueue_thread_remove_fd (sub->fd); - - /* Bump the kqueue thread. It will pick up a new sub entry to remove*/ - if (!_ku_write (kqueue_socket_pair[0], "R", 1)) - KH_W ("Failed to bump the kqueue thread (remove fd, error %d)", errno); - } - - return TRUE; -} - - -/** - * _kh_file_appeared_cb: - * @sub: a #kqueue_sub - * - * A callback function for kqueue-missing subsystem. - * - * Signals that a missing file has finally appeared in the filesystem. - * Emits %G_FILE_MONITOR_EVENT_CREATED. - **/ -void -_kh_file_appeared_cb (kqueue_sub *sub) -{ - GFile* child; - - g_assert (sub != NULL); - g_assert (sub->filename); - - if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS)) - return; - - child = g_file_new_for_path (sub->filename); - - g_file_monitor_emit_event (G_FILE_MONITOR (sub->user_data), - child, - NULL, - G_FILE_MONITOR_EVENT_CREATED); - - g_object_unref (child); -} diff --git a/gio/kqueue/kqueue-helper.h b/gio/kqueue/kqueue-helper.h index b12a28fae..38a32a2f9 100644 --- a/gio/kqueue/kqueue-helper.h +++ b/gio/kqueue/kqueue-helper.h @@ -23,16 +23,31 @@ #ifndef __KQUEUE_HELPER_H #define __KQUEUE_HELPER_H -#include "kqueue-sub.h" #include <gio/glocalfilemonitor.h> #include <gio/gfilemonitor.h> -gboolean _kh_startup (void); -gboolean _kh_add_sub (kqueue_sub *sub); -gboolean _kh_cancel_sub (kqueue_sub *sub); - -gboolean _kh_start_watching (kqueue_sub *sub); - -void _kh_dir_diff (kqueue_sub *sub, GFileMonitorSource *source); +#include "dep-list.h" + +/** + * kqueue_sub: + * @filename: a name of the file to monitor + * @fd: the associated file descriptor (used by kqueue) + * + * Represents a subscription on a file or directory. + */ +typedef struct +{ + GLocalFileMonitor *mon; + GFileMonitorSource *source; + gchar* filename; + int fd; + dep_list* deps; + int is_dir; +} kqueue_sub; + +gboolean _kqsub_start_watching (kqueue_sub *sub); +void _kh_dir_diff (kqueue_sub *sub); +void _km_add_missing (kqueue_sub *sub); +void _km_remove (kqueue_sub *sub); #endif /* __KQUEUE_HELPER_H */ diff --git a/gio/kqueue/kqueue-missing.c b/gio/kqueue/kqueue-missing.c index 9decdc937..93135b962 100644 --- a/gio/kqueue/kqueue-missing.c +++ b/gio/kqueue/kqueue-missing.c @@ -23,12 +23,12 @@ #include <glib.h> #include "kqueue-helper.h" -#include "kqueue-sub.h" -#include "kqueue-missing.h" #define SCAN_MISSING_TIME 4 /* 1/4 Hz */ +void _kh_file_appeared_cb (kqueue_sub *sub); + static gboolean km_scan_missing (gpointer user_data); static gboolean km_debug_enabled = FALSE; @@ -38,21 +38,6 @@ static GSList *missing_subs_list = NULL; G_LOCK_DEFINE_STATIC (missing_lock); static volatile gboolean scan_missing_running = FALSE; -static on_create_cb file_appeared_callback; - - -/** - * _km_init: - * @cb: a callback function. It will be called when a watched file - * will appear. - * - * Initialize the kqueue-missing module (optional). - **/ -void -_km_init (on_create_cb cb) -{ - file_appeared_callback = cb; -} /** @@ -83,6 +68,35 @@ _km_add_missing (kqueue_sub *sub) } } +/** + * _kh_file_appeared_cb: + * @sub: a #kqueue_sub + * + * A callback function for kqueue-missing subsystem. + * + * Signals that a missing file has finally appeared in the filesystem. + * Emits %G_FILE_MONITOR_EVENT_CREATED. + **/ +void +_kh_file_appeared_cb (kqueue_sub *sub) +{ + GFile *child; + + g_assert (sub != NULL); + g_assert (sub->filename); + + if (!g_file_test (sub->filename, G_FILE_TEST_EXISTS)) + return; + + child = g_file_new_for_path (sub->filename); + + g_file_monitor_emit_event (G_FILE_MONITOR (sub->mon), + child, + NULL, + G_FILE_MONITOR_EVENT_CREATED); + + g_object_unref (child); +} /** * km_scan_missing: @@ -114,11 +128,10 @@ km_scan_missing (gpointer user_data) g_assert (sub != NULL); g_assert (sub->filename != NULL); - if (_kh_start_watching (sub)) + if (_kqsub_start_watching (sub)) { KM_W ("file %s now exists, starting watching", sub->filename); - if (file_appeared_callback) - file_appeared_callback (sub); + _kh_file_appeared_cb (sub); not_missing = g_slist_prepend (not_missing, head); } } diff --git a/gio/kqueue/kqueue-missing.h b/gio/kqueue/kqueue-missing.h deleted file mode 100644 index 704a6f300..000000000 --- a/gio/kqueue/kqueue-missing.h +++ /dev/null @@ -1,32 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __G_KQUEUE_MISSING_H -#define __G_KQUEUE_MISSING_H - -typedef void (*on_create_cb) (kqueue_sub *); - -void _km_init (on_create_cb cb); -void _km_add_missing (kqueue_sub *sub); -void _km_remove (kqueue_sub *sub); - -#endif /* __G_KQUEUE_MISSING_H */ diff --git a/gio/kqueue/kqueue-sub.c b/gio/kqueue/kqueue-sub.c deleted file mode 100644 index 8b864ba90..000000000 --- a/gio/kqueue/kqueue-sub.c +++ /dev/null @@ -1,79 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#include <glib.h> - -#include "kqueue-sub.h" - -static gboolean ks_debug_enabled = FALSE; -#define KS_W if (ks_debug_enabled) g_warning - -/** - * _kh_sub_new: - * @filename: a file path to monitor (will be copied) - * @pair_moves: pair moves flag. Refer to #GFileMonitorFlags documentation. - * @user_data: user-supplied poiner. - * - * Creates a new subscription object. - * - * Returns: a pointer to a created subscription object. - **/ -kqueue_sub* -_kh_sub_new (const gchar *filename, - gboolean pair_moves, - gpointer user_data) -{ - kqueue_sub *sub = g_slice_new (kqueue_sub); - g_assert (sub != NULL); - - sub->filename = g_strdup (filename); - sub->pair_moves = pair_moves; - sub->user_data = user_data; - sub->fd = -1; - sub->deps = NULL; - /* I think that having such flag in the subscription is not good */ - sub->is_dir = 0; - - KS_W ("new subscription for %s being setup\n", sub->filename); - - return sub; -} - - -/** - * _kh_sub_free: - * @sub: a #kqueue_sub - * - * Frees a subscription object and all its associated memory. - **/ -void -_kh_sub_free (kqueue_sub *sub) -{ - if (sub->deps) - { - dl_free (sub->deps); - sub->deps = NULL; - } - - g_free (sub->filename); - g_slice_free (kqueue_sub, sub); -} diff --git a/gio/kqueue/kqueue-sub.h b/gio/kqueue/kqueue-sub.h deleted file mode 100644 index 215c49142..000000000 --- a/gio/kqueue/kqueue-sub.h +++ /dev/null @@ -1,50 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __KQUEUE_SUB_H -#define __KQUEUE_SUB_H - -#include "dep-list.h" - -/** - * kqueue_sub: - * @filename: a name of the file to monitor - * @user_data: the pointer to user data - * @pair_moves: unused (currently not implemented) - * @fd: the associated file descriptor (used by kqueue) - * - * Represents a subscription on a file or directory. - */ -typedef struct -{ - gchar* filename; - gpointer user_data; - gboolean pair_moves; - int fd; - dep_list* deps; - int is_dir; -} kqueue_sub; - -kqueue_sub* _kh_sub_new (const gchar* filename, gboolean pair_moves, gpointer user_data); -void _kh_sub_free (kqueue_sub* sub); - -#endif /* __KQUEUE_SUB_H */ diff --git a/gio/kqueue/kqueue-thread.c b/gio/kqueue/kqueue-thread.c deleted file mode 100644 index 642b997db..000000000 --- a/gio/kqueue/kqueue-thread.c +++ /dev/null @@ -1,304 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#include "config.h" -#include <sys/types.h> -#include <sys/event.h> -#include <sys/time.h> -#include <unistd.h> -#include <errno.h> -#include <glib.h> - -#include "kqueue-thread.h" -#include "kqueue-sub.h" -#include "kqueue-utils.h" - -static gboolean kt_debug_enabled = FALSE; -#define KT_W if (kt_debug_enabled) g_warning - -static GQueue pick_up_fds_queue = G_QUEUE_INIT; -G_LOCK_DEFINE_STATIC (pick_up_lock); - -static GSList *remove_fds_list = NULL; -G_LOCK_DEFINE_STATIC (remove_lock); - -/* GIO does not have analogues for NOTE_LINK and(?) NOTE_REVOKE, so - * we do not ask kqueue() to watch for these events for now. */ -const uint32_t KQUEUE_VNODE_FLAGS = - NOTE_DELETE | NOTE_WRITE | NOTE_EXTEND | NOTE_ATTRIB | NOTE_RENAME; - -extern int get_kqueue_descriptor(void); - -/** - * _kqueue_thread_collect_fds: - * @events: a #kevents - the list of events to monitor. Will be extended - * with new items. - * - * Picks up new file descriptors for monitoring from a global queue. - * - * To add new items to the list, use _kqueue_thread_push_fd(). - */ -static void -_kqueue_thread_collect_fds (kevents *events) -{ - g_assert (events != NULL); - gint length = 0; - - G_LOCK (pick_up_lock); - if ((length = g_queue_get_length (&pick_up_fds_queue)) != 0) - { - gpointer fdp = NULL; - kevents_extend_sz (events, length); - - while ((fdp = g_queue_pop_head (&pick_up_fds_queue)) != NULL) - { - struct kevent *pevent = &events->memory[events->kq_size++]; - EV_SET (pevent, - GPOINTER_TO_INT (fdp), - EVFILT_VNODE, - EV_ADD | EV_ENABLE | EV_ONESHOT, - KQUEUE_VNODE_FLAGS, - 0, - 0); - } - } - G_UNLOCK (pick_up_lock); -} - - -/** - * _kqueue_thread_cleanup_fds: - * @events: a #kevents -- list of events to monitor. Cancelled - * subscriptions will be removed from it, and its size - * probably will be reduced. - * - * Removes file descriptors from monitoring. - * - * This function will pick up file descriptors from a global list - * to cancel monitoring on them. The list will be freed then. - * - * To add new items to the list, use _kqueue_thread_remove_fd(). - */ -static void -_kqueue_thread_cleanup_fds (kevents *events) -{ - g_assert (events != NULL); - - G_LOCK (remove_lock); - if (remove_fds_list) - { - size_t oldsize = events->kq_size; - int i, j; - - for (i = 1, j = 1; i < oldsize; i++) - { - int fd = events->memory[i].ident; - GSList *elem = g_slist_find (remove_fds_list, GINT_TO_POINTER (fd)); - if (elem == NULL) - { - if (i != j) - events->memory[j] = events->memory[i]; - ++j; - } - else if (close (fd) == -1) - KT_W ("Failed to close fd %d, error %d", fd, errno); - } - - KT_W ("FD Clean up complete, kq_size now %d\n", j); - events->kq_size = j; - kevents_reduce (events); - g_slist_free (remove_fds_list); - remove_fds_list = NULL; - } - G_UNLOCK (remove_lock); -} - - -/** - * _kqueue_thread_drop_fd: - * @events: a #kevents -- list of events to monitor. Cancelled - * subscriptions will be removed from it, and its size - * probably will be reduced. - * - * Removes a concrete file descriptor from monitoring. - */ -static void -_kqueue_thread_drop_fd (kevents *events, int fd) -{ - g_assert (events != NULL); - - int i; - for (i = 1; i < events->kq_size; i++) - { - if (events->memory[i].ident == fd) - { - if (close (fd) == -1) - KT_W ("Failed to close fd %d, error %d", fd, errno); - - events->memory[i] = events->memory[--events->kq_size]; - return; - } - } -} - -/** - * _kqueue_thread_func: - * @arg: a pointer to int -- control file descriptor. - * - * The thread communicates with the outside world through a so-called - * command file descriptor. The thread reads control commands from it - * and writes the notifications into it. - * - * Control commands are single-byte characters: - * - 'A' - pick up new file descriptors to monitor - * - 'R' - remove some descriptors from monitoring. - * - * For details, see _kqueue_thread_collect_fds() and - * _kqueue_thread_cleanup_fds(). - * - * Notifications, that thread writes into the command file descriptor, - * are represented with #kqueue_notification objects. - * - * Returns: %NULL - */ -void* -_kqueue_thread_func (void *arg) -{ - int fd, kqueue_descriptor; - kevents waiting; - - g_assert (arg != NULL); - kevents_init_sz (&waiting, 1); - - fd = *(int *) arg; - - kqueue_descriptor = get_kqueue_descriptor(); - if (kqueue_descriptor == -1) - { - KT_W ("fatal: kqueue is not initialized!\n"); - return NULL; - } - - EV_SET (&waiting.memory[0], - fd, - EVFILT_READ, - EV_ADD | EV_ENABLE | EV_ONESHOT, - NOTE_LOWAT, - 1, - 0); - waiting.kq_size = 1; - - for (;;) - { - /* TODO: Provide more items in the 'eventlist' to kqueue(2). - * Currently the backend takes notifications from the kernel one - * by one, i.e. there will be a lot of system calls and context - * switches when the application will monitor a lot of files with - * high filesystem activity on each. */ - - struct kevent received; - KT_W ("Watching for %zi items", waiting.kq_size); - int ret = kevent (kqueue_descriptor, waiting.memory, waiting.kq_size, &received, 1, NULL); - int kevent_errno = errno; - KT_W ("Awoken."); - - if (ret == -1) - { - KT_W ("kevent failed: %d", kevent_errno); - if (kevent_errno == EINTR) - continue; - else - return NULL; - } - - if (received.ident == fd) - { - char c; - if (!_ku_read (fd, &c, 1)) - { - KT_W ("Failed to read command, error %d", errno); - continue; - } - if (c == 'A') - _kqueue_thread_collect_fds (&waiting); - else if (c == 'R') - _kqueue_thread_cleanup_fds (&waiting); - } - else - { - struct kqueue_notification kn; - kn.fd = received.ident; - - if (received.flags & EV_ERROR) - { - kn.flags = NOTE_REVOKE; - _kqueue_thread_drop_fd (&waiting, received.ident); - } - else - kn.flags = (received.fflags & ~NOTE_REVOKE); - - if (!_ku_write (fd, &kn, sizeof (struct kqueue_notification))) - KT_W ("Failed to write a kqueue notification, error %d", errno); - } - } - kevents_free (&waiting); - return NULL; -} - - -/** - * _kqueue_thread_push_fd: - * @fd: a file descriptor - * - * Puts a new file descriptor into the pick up list for monitroing. - * - * The kqueue thread will not start monitoring on it immediately, it - * should be bumped via its command file descriptor manually. - * See kqueue_thread() and _kqueue_thread_collect_fds() for details. - */ -void -_kqueue_thread_push_fd (int fd) -{ - G_LOCK (pick_up_lock); - g_queue_push_tail (&pick_up_fds_queue, GINT_TO_POINTER (fd)); - G_UNLOCK (pick_up_lock); -} - - -/** - * _kqueue_thread_remove_fd: - * @fd: a file descriptor - * - * Puts a new file descriptor into the remove list to cancel monitoring - * on it. - * - * The kqueue thread will not stop monitoring on it immediately, it - * should be bumped via its command file descriptor manually. - * See kqueue_thread() and _kqueue_thread_collect_fds() for details. - */ -void -_kqueue_thread_remove_fd (int fd) -{ - G_LOCK (remove_lock); - remove_fds_list = g_slist_prepend (remove_fds_list, GINT_TO_POINTER (fd)); - G_UNLOCK (remove_lock); -} diff --git a/gio/kqueue/kqueue-thread.h b/gio/kqueue/kqueue-thread.h deleted file mode 100644 index 0e46a0d69..000000000 --- a/gio/kqueue/kqueue-thread.h +++ /dev/null @@ -1,45 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __KQUEUE_THREAD_H -#define __KQUEUE_THREAD_H - -/** - * kqueue_notification: - * @fd: file descriptor, on which an activity has occured. - * @flags: kqueue event flags, see man kevent(2). - * - * Represents an event occured on a file descriptor. Used for marshalling from - * kqueue thread to its subscribers. - */ -struct kqueue_notification { - /*< public >*/ - int fd; - uint32_t flags; -}; - - -void* _kqueue_thread_func (void *arg); -void _kqueue_thread_push_fd (int fd); -void _kqueue_thread_remove_fd (int fd); - -#endif /* __KQUEUE_SUB_H */ diff --git a/gio/kqueue/kqueue-utils.c b/gio/kqueue/kqueue-utils.c deleted file mode 100644 index bba652278..000000000 --- a/gio/kqueue/kqueue-utils.c +++ /dev/null @@ -1,210 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#include <sys/types.h> -#include <sys/event.h> -#include <string.h> -#include <glib.h> -#include <unistd.h> -#include <sys/stat.h> -#include <errno.h> -#include "kqueue-utils.h" - -static gboolean ku_debug_enabled = FALSE; -#define KU_W if (ku_debug_enabled) g_warning - - - -#define KEVENTS_EXTEND_COUNT 10 - - -/** - * kevents_init_sz: - * @kv: a #kevents - * @n_initial: the initial preallocated memory size. If it is less than - * %KEVENTS_EXTEND_COUNT, this value will be used instead. - * - * Initializes a #kevents object. - **/ -void -kevents_init_sz (kevents *kv, gsize n_initial) -{ - g_assert (kv != NULL); - - memset (kv, 0, sizeof (kevents)); - - if (n_initial < KEVENTS_EXTEND_COUNT) - n_initial = KEVENTS_EXTEND_COUNT; - - kv->memory = g_new0 (struct kevent, n_initial); - kv->kq_allocated = n_initial; -} - - -/** - * kevents_extend_sz: - * @kv: a #kevents - * @n_new: the number of new objects to be added - * - * Extends the allocated memory, if needed. - **/ -void -kevents_extend_sz (kevents *kv, gsize n_new) -{ - g_assert (kv != NULL); - - if (kv->kq_size + n_new <= kv->kq_allocated) - return; - - kv->kq_allocated += (n_new + KEVENTS_EXTEND_COUNT); - kv->memory = g_renew (struct kevent, kv->memory, kv->kq_allocated); -} - - -/** - * kevents_reduce: - * @kv: a #kevents - * - * Reduces the allocated heap size, if needed. - * - * If the allocated heap size is >= 3*used - * and 2*used >= %KEVENTS_EXTEND_COUNT, reduce it to 2*used. - **/ -void -kevents_reduce (kevents *kv) -{ - g_assert (kv != NULL); - gsize candidate_sz; - - if (kv->kq_size == 0 || kv->kq_allocated == 0 || kv->memory == NULL) - return; - - candidate_sz = 2 * kv->kq_size; - - if (((double) kv->kq_allocated / kv->kq_size) >= 3 && - candidate_sz >= KEVENTS_EXTEND_COUNT) - { - kv->kq_allocated = candidate_sz; - kv->memory = g_renew (struct kevent, kv->memory, kv->kq_allocated); - } -} - - -/** - * kevents_free: - * @kv: a #kevents - * - * Resets the kevents object and frees all the associated memory. - **/ -void -kevents_free (kevents *kv) -{ - g_assert (kv != NULL); - - g_free (kv->memory); - memset (kv, 0, sizeof (kevents)); -} - - -#define SAFE_GENERIC_OP(fcn, fd, data, size) \ - while (size > 0) \ - { \ - gsize retval = fcn (fd, data, size); \ - if (retval == -1) \ - { \ - if (errno == EINTR) \ - continue; \ - else \ - return FALSE; \ - } \ - size -= retval; \ - data += retval; \ - } \ - return TRUE; - - -/** - * _ku_read: - * @fd: a file descriptor - * @data: the destination buffer - * @size: how many bytes to read - * - * A ready-to-EINTR version of read(). - * - * This function expects to work with a blocking socket. - * - * Returns: %TRUE on success, %FALSE otherwise - **/ -gboolean -_ku_read (int fd, gpointer data, gsize size) -{ - SAFE_GENERIC_OP (read, fd, data, size); -} - - -/** - * _ku_write: - * @fd: a file descriptor - * @data: the buffer to write - * @size: how many bytes to write - * - * A ready-to-EINTR version of write(). - * - * This function expects to work with a blocking socket. - * - * Returns: %TRUE on success, %FALSE otherwise - **/ -gboolean -_ku_write (int fd, gconstpointer data, gsize size) -{ - SAFE_GENERIC_OP (write, fd, data, size); -} - - -/** - * Get some file information by its file descriptor. - * - * @param[in] fd A file descriptor. - * @param[out] is_dir A flag indicating directory. - * @param[out] inode A file's inode number. - **/ -void -_ku_file_information (int fd, int *is_dir, ino_t *inode) -{ - g_assert (fd != -1); - - struct stat st; - memset (&st, 0, sizeof (struct stat)); - - if (fstat (fd, &st) == -1) - { - KU_W ("fstat failed, assuming it is just a file"); - is_dir = NULL; - return; - } - - if (is_dir != NULL) - *is_dir = ((st.st_mode & S_IFDIR) == S_IFDIR) ? 1 : 0; - - if (inode != NULL) - *inode = st.st_ino; -} diff --git a/gio/kqueue/kqueue-utils.h b/gio/kqueue/kqueue-utils.h deleted file mode 100644 index 4e37f4a99..000000000 --- a/gio/kqueue/kqueue-utils.h +++ /dev/null @@ -1,53 +0,0 @@ -/******************************************************************************* - Copyright (c) 2011, 2012 Dmitry Matveev <me@dmitrymatveev.co.uk> - - Permission is hereby granted, free of charge, to any person obtaining a copy - of this software and associated documentation files (the "Software"), to deal - in the Software without restriction, including without limitation the rights - to use, copy, modify, merge, publish, distribute, sublicense, and/or sell - copies of the Software, and to permit persons to whom the Software is - furnished to do so, subject to the following conditions: - - The above copyright notice and this permission notice shall be included in - all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR - IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, - FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE - AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER - LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, - OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN - THE SOFTWARE. -*******************************************************************************/ - -#ifndef __KQUEUE_UTILS_H -#define __KQUEUE_UTILS_H - -#include <sys/types.h> /* ino_t */ - -/** - * kqueue_notification: - * @memory: a pointer to the allocated memory - * @kq_size: the number of used items - * @kq_allocated: the number of allocated items - * - * Represents a pool of (struct kevent) objects. - */ -typedef struct { - struct kevent *memory; - gsize kq_size; - gsize kq_allocated; -} kevents; - -void kevents_init_sz (kevents *kv, gsize n_initial); -void kevents_extend_sz (kevents *kv, gsize n_new); -void kevents_reduce (kevents *kv); -void kevents_free (kevents *kv); - - -gboolean _ku_read (int fd, gpointer data, gsize size); -gboolean _ku_write (int fd, gconstpointer data, gsize size); - -void _ku_file_information (int fd, int *is_dir, ino_t *inode); - -#endif /* __KQUEUE_UTILS_H */ diff --git a/gio/kqueue/meson.build b/gio/kqueue/meson.build index 51c5e788f..e5057c83d 100644 --- a/gio/kqueue/meson.build +++ b/gio/kqueue/meson.build @@ -1,18 +1,13 @@ kqueue_sources = [ 'gkqueuefilemonitor.c', 'kqueue-helper.c', - 'kqueue-thread.c', - 'kqueue-sub.c', 'kqueue-missing.c', - 'kqueue-utils.c', - 'kqueue-exclusions.c', 'dep-list.c', - # gkqueuefilemonitor.h includes gio.h which includes this - gioenumtypes_h, ] kqueue_lib = static_library('kqueue', sources : kqueue_sources, include_directories : [configinc, glibinc, gmoduleinc], + dependencies : [gioenumtypes_dep], pic : true, c_args : [ '-DG_DISABLE_DEPRECATED' ] + gio_c_args) diff --git a/gio/meson.build b/gio/meson.build index 7393f374d..42f67715d 100644 --- a/gio/meson.build +++ b/gio/meson.build @@ -137,10 +137,8 @@ if host_system != 'windows' glib_conf.set('HAVE_RES_NQUERY', 1) endif - if cc.compiles('''#include <netinet/in.h> - struct ip_mreqn foo;''', - name : 'struct ip_mreqn') - glib_conf.set('HAVE_IP_MREQN', '/**/') + if cc.has_type('struct ip_mreqn', prefix : '#include <netinet/in.h>') + glib_conf.set('HAVE_IP_MREQN', 1) endif if cc.compiles('''#include <sys/ioctl.h> @@ -154,11 +152,6 @@ 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; @@ -168,6 +161,7 @@ if host_system.contains('android') name : 'ip_mreq_source.imr_interface has s_addr member') glib_conf.set('BROKEN_IP_MREQ_SOURCE_STRUCT', 1) endif + endif network_args_string = '' @@ -454,6 +448,7 @@ else 'gwin32outputstream.c', 'gwin32networkmonitor.c', 'gwin32networkmonitor.h', + 'gwin32notificationbackend.c', ) gio_win_rc = configure_file( @@ -798,16 +793,55 @@ libgio = library('gio-2.0', install : true, include_directories : [configinc, gioinc], link_with : internal_deps, - #libgio_2_0_la_LDFLAGS = $(GLIB_LINK_FLAGS)', # '$(gio_win32_res_ldflag)', - dependencies : [libintl, libz_dep, libdl_dep, libmount_dep, libglib_dep, + dependencies : [libz_dep, libdl_dep, libmount_dep, libglib_dep, libgobject_dep, libgmodule_dep, selinux_dep, xattr_dep, platform_deps, network_libs], c_args : gio_c_args, # intl.lib is not compatible with SAFESEH - link_args : noseh_link_args, + link_args : [noseh_link_args, glib_link_flags], +) + +giomodulesdir = get_option('gio_module_dir') +if giomodulesdir == '' + giomodulesdir = join_paths('${libdir}', 'gio', 'modules') +endif + +pkg.generate(libraries : libgio, + libraries_private : [osx_ldflags], + requires : ['glib-2.0', 'gobject-2.0'], + variables : ['bindir=' + join_paths('${prefix}', get_option('bindir')), + 'giomoduledir=' + giomodulesdir, + 'glib_compile_schemas=' + join_paths('${bindir}', 'glib-compile-schemas'), + 'glib_compile_resources=' + join_paths('${bindir}', 'glib-compile-resources'), + 'gdbus_codegen=' + join_paths('${bindir}', 'gdbus-codegen')], + version : glib_version, + install_dir : glib_pkgconfigreldir, + filebase : 'gio-2.0', + name : 'GIO', + description : 'glib I/O library', ) +if host_system == 'windows' + pkg.generate(requires : ['gobject-2.0', 'gmodule-no-export-2.0', 'gio-2.0'], + subdirs : ['gio-win32-2.0'], + version : glib_version, + install_dir : glib_pkgconfigreldir, + filebase : 'gio-windows-2.0', + name : 'GIO Windows specific APIs', + description : 'Windows specific headers for glib I/O library', + ) +else + pkg.generate(requires : ['gobject-2.0', 'gio-2.0'], + subdirs : ['gio-unix-2.0'], + version : glib_version, + install_dir : glib_pkgconfigreldir, + filebase : 'gio-unix-2.0', + name : 'GIO unix specific APIs', + description : 'unix specific headers for glib I/O library', + ) +endif + libgio_dep = declare_dependency(link_with : libgio, dependencies : [gioenumtypes_dep], # We sadly need to export configinc here because everyone includes <gio/*.h> @@ -860,13 +894,13 @@ executable('gio', gio_tool_sources, c_args : gio_c_args, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) executable('gresource', 'gresource-tool.c', install : true, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libelf, libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libelf, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) executable('gio-querymodules', 'gio-querymodules.c', 'giomodule-priv.c', install : true, @@ -880,7 +914,7 @@ glib_compile_schemas = executable('glib-compile-schemas', install : true, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) glib_compile_resources = executable('glib-compile-resources', [gconstructor_as_data_h, 'gvdb/gvdb-builder.c', 'glib-compile-resources.c'], @@ -888,14 +922,14 @@ glib_compile_resources = executable('glib-compile-resources', c_args : gio_c_args, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) executable('gsettings', 'gsettings-tool.c', install : true, c_args : gio_c_args, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) install_data('gschema.dtd', install_dir : join_paths(get_option('datadir'), 'glib-2.0/schemas')) @@ -907,7 +941,7 @@ executable('gdbus', 'gdbus-tool.c', c_args : gio_c_args, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) if host_system != 'windows' executable('gapplication', 'gapplication-tool.c', @@ -915,7 +949,7 @@ if host_system != 'windows' c_args : gio_c_args, # intl.lib is not compatible with SAFESEH link_args : noseh_link_args, - dependencies : [libintl, libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) + dependencies : [libgio_dep, libgobject_dep, libgmodule_dep, libglib_dep]) endif if enable_systemtap diff --git a/gio/org.freedesktop.portal.NetworkMonitor.xml b/gio/org.freedesktop.portal.NetworkMonitor.xml index fb551d6ed..8d3a471d5 100644 --- a/gio/org.freedesktop.portal.NetworkMonitor.xml +++ b/gio/org.freedesktop.portal.NetworkMonitor.xml @@ -5,86 +5,25 @@ This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either - version 2 of the License, or (at your option) any later version. + version 2.1 of the License, or (at your option) any later version. This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details. - You should have received a copy of the GNU Lesser General Public - License along with this library. If not, see <http://www.gnu.org/licenses/>. + You should have received a copy of the GNU Lesser General Public License + along with this library; if not, see <http://www.gnu.org/licenses/>. Author: Matthias Clasen <mclasen@redhat.com> --> -<node name="/" xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd"> - <!-- - org.freedesktop.portal.NetworkMonitor: - @short_description: Network monitoring portal - - The NetworkMonitor interface provides network status information - to sandboxed applications. It is not a portal in the strict sense, - since it does not involve user interaction. Applications are - expected to use this interface indirectly, via a library API - such as the GLib GNetworkMonitor interface. - - This documentation describes version 2 of this interface. - --> +<node xmlns:doc="http://www.freedesktop.org/dbus/1.0/doc.dtd" name="/"> <interface name="org.freedesktop.portal.NetworkMonitor"> - <!-- - changed: - - Emitted when the network configuration changes. - --> - <signal name="changed"/> - <!-- - GetAvailable: - @available: whether the network is available - - Returns whether the network is considered available. - That is, whether the system as a default route for - at least one of IPv4 or IPv6. - - This method was added in version 2 to replace - the available property. - --> - <method name="GetAvailable"> - <arg type='b' name='available' direction='out'/> - </method> - <!-- - GetMetered: - @metered: whether the network is metered - - Returns whether the network is considered metered. - That is, whether the system as traffic flowing through - the default connection that is subject ot limitations - by service providers. - - This method was added in version 2 to replace - the metered property. - --> - <method name="GetMetered"> - <arg type='b' name='metered' direction='out'/> - </method> - <!-- - GetConnectivity: - @connectivity: the level of connectivity - - Returs more detailed information about the host's network - connectivity. The meaning of the value is: - <simplelist> - <member>1: Local only. The host is not configured with a route to the internet.</member> - <member>2: Limited connectivity. The host is connected to a network, but can't reach the full internet.</member> - <member>3: Captive portal. The host is behind a captive portal and cannot reach the full internet.</member> - <member>4: Full network. The host connected to a network, and can reach the full internet.</member> - </simplelist> - - This method was added in version 2 to replace - the connectivity property. - --> - <method name="GetConnectivity"> - <arg type='u' name='connectivity' direction='out'/> - </method> - <property name="version" type="u" access="read"/> + <signal name="changed"> + <arg type="b" name="available"/> + </signal> + <property name="available" type="b" access="read"/> + <property name="metered" type="b" access="read"/> + <property name="connectivity" type="u" access="read"/> </interface> </node> diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am index 49a19bf4a..410f11d95 100644 --- a/gio/tests/Makefile.am +++ b/gio/tests/Makefile.am @@ -300,11 +300,11 @@ usr_desktop_files = \ evince-previewer.desktop \ evince.desktop \ file-roller.desktop \ + frobnicator.desktop \ gcr-prompter.desktop \ gcr-viewer.desktop \ gedit.desktop \ glade.desktop \ - gnome-clocks.desktop \ gnome-contacts.desktop \ gnome-font-viewer.desktop \ gnome-music.desktop \ @@ -319,6 +319,7 @@ usr_desktop_files = \ nautilus-classic.desktop \ nautilus-connect-server.desktop \ nautilus.desktop \ + org.gnome.clocks.desktop \ totem.desktop \ yelp.desktop diff --git a/gio/tests/desktop-app-info.c b/gio/tests/desktop-app-info.c index d1b68c441..669db5769 100644 --- a/gio/tests/desktop-app-info.c +++ b/gio/tests/desktop-app-info.c @@ -626,7 +626,7 @@ assert_implementations (const gchar *interface, } #define ALL_USR_APPS "evince-previewer.desktop nautilus-classic.desktop gnome-font-viewer.desktop " \ - "baobab.desktop yelp.desktop eog.desktop cheese.desktop gnome-clocks.desktop " \ + "baobab.desktop yelp.desktop eog.desktop cheese.desktop org.gnome.clocks.desktop " \ "gnome-contacts.desktop kde4-kate.desktop gcr-prompter.desktop totem.desktop " \ "gnome-terminal.desktop nautilus-autorun-software.desktop gcr-viewer.desktop " \ "nautilus-connect-server.desktop kde4-dolphin.desktop gnome-music.desktop " \ @@ -667,6 +667,17 @@ test_search (void) assert_search ("image viewer", "", FALSE, TRUE, NULL, NULL); assert_search ("image viewer", "", TRUE, TRUE, NULL, NULL); + /* There're "flatpak" apps (clocks) installed as well - they should *not* + * match the prefix command ("/bin/sh") in the Exec= line though. + */ + assert_search ("sh", "gnome-terminal.desktop\n", TRUE, FALSE, NULL, NULL); + + /* "frobnicator.desktop" is ignored by get_all() because the binary is + * missing, but search should still find it (to avoid either stale results + * from the cache or expensive stat() calls for each potential result) + */ + assert_search ("frobni", "frobnicator.desktop\n", TRUE, FALSE, NULL, NULL); + /* Obvious multi-word search */ assert_search ("gno hel", "yelp.desktop\n", TRUE, TRUE, NULL, NULL); @@ -685,7 +696,7 @@ test_search (void) * yelp and gnome-contacts, though. */ assert_search ("gnome", "eog.desktop\n" - "gnome-clocks.desktop\n" + "org.gnome.clocks.desktop\n" "yelp.desktop gnome-contacts.desktop\n", TRUE, TRUE, NULL, NULL); /* eog has exec name 'false' in usr only */ diff --git a/gio/tests/desktop-files/usr/applications/frobnicator.desktop b/gio/tests/desktop-files/usr/applications/frobnicator.desktop new file mode 100644 index 000000000..0a8dbfa39 --- /dev/null +++ b/gio/tests/desktop-files/usr/applications/frobnicator.desktop @@ -0,0 +1,9 @@ +[Desktop Entry] +Name=Frobnicator +Comment=Frobnicate your life! +Exec=/does-not-exist +Icon=frobnicator +StartupNotify=true +Terminal=false +Type=Application +Categories=GNOME;GTK;Utilities diff --git a/gio/tests/desktop-files/usr/applications/gnome-clocks.desktop b/gio/tests/desktop-files/usr/applications/gnome-clocks.desktop deleted file mode 100644 index 3f533e963..000000000 --- a/gio/tests/desktop-files/usr/applications/gnome-clocks.desktop +++ /dev/null @@ -1,41 +0,0 @@ -[Desktop Entry] -Name=Clocks -Name[ca]=Rellotges -Name[ca@valencia]=Rellotges -Name[en_GB]=Clocks -Name[eo]=Horloĝoj -Name[pt]=Relógios -Name[pt_BR]=Relógios -GenericName=Clocks -GenericName[ca]=Rellotges -GenericName[ca@valencia]=Rellotges -GenericName[en_GB]=Clocks -GenericName[eo]=Horloĝoj -GenericName[pt]=Relógios -GenericName[pt_BR]=Relógios -X-GNOME-FullName=GNOME Clocks -X-GNOME-FullName[ca]=Rellotges del GNOME -X-GNOME-FullName[ca@valencia]=Rellotges del GNOME -X-GNOME-FullName[en_GB]=GNOME Clocks -X-GNOME-FullName[eo]=GNOME-horloĝoj -X-GNOME-FullName[pt]=Relógios GNOME -X-GNOME-FullName[pt_BR]=Relógios do GNOME -Comment=Clocks for world times, plus alarms, stopwatch and a timer -Comment[ca]=Rellotges de tot el món, a més d'alarmes, de cronòmetres i de temporitzadors -Comment[ca@valencia]=Rellotges de tot el món, a més d'alarmes, de cronòmetres i de temporitzadors -Comment[en_GB]=Clocks for world times, plus alarms, stopwatch and a timer -Comment[pt]=Relógios com as horas do mundo, alarmes, cronómetros e um temporizador -Comment[pt_BR]=Relógios para horários mundiais além de alarmes, cronômetro e um temporizador -Keywords=time;timer;alarm;world clock;stopwatch;time zone; -Keywords[ca]=temps;temporitzador;alarma;rellotge global;cronòmetre;zona horària; -Keywords[ca@valencia]=temps;temporitzador;alarma;rellotge global;cronòmetre;zona horària; -Keywords[en_GB]=time;timer;alarm;world clock;stopwatch;time zone; -Keywords[pt]=horas;temporizador;alarme;relógio mundial;cronómetro;fuso horário; -Keywords[pt_BR]=hora;temporizador;alarme;relógio mundial;cronômetro;fuso horário; -Exec=true -Icon=gnome-clocks -Terminal=false -Type=Application -Categories=GNOME;GTK;Utility;Clock; -StartupNotify=true -X-GNOME-UsesNotifications=true diff --git a/gio/tests/desktop-files/usr/applications/org.gnome.clocks.desktop b/gio/tests/desktop-files/usr/applications/org.gnome.clocks.desktop new file mode 100755 index 000000000..92a6b35bc --- /dev/null +++ b/gio/tests/desktop-files/usr/applications/org.gnome.clocks.desktop @@ -0,0 +1,404 @@ +[Desktop Entry] +Name[af]=Horlosies +Name[an]=Reloches +Name[ar]=الساعات +Name[as]=ঘড়ী +Name[be]=Гадзіннікі +Name[bg]=Часовници +Name[bn_IN]=ঘড়ি +Name[bs]=Satovi +Name[ca]=Rellotges +Name[ca@valencia]=Rellotges +Name[cs]=Hodiny +Name[da]=Ure +Name[de]=Uhren +Name[el]=Ρολόγια +Name[en_GB]=Clocks +Name[eo]=Horloĝoj +Name[es]=Relojes +Name[et]=Kell +Name[eu]=Ordulariak +Name[fa]=ساعتها +Name[fi]=Kellot +Name[fr]=Horloges +Name[fur]=Orlois +Name[ga]=Cloig +Name[gd]=Uaireadairean +Name[gl]=Reloxos +Name[gu]=ઘડિયાળ +Name[he]=שעונים +Name[hi]=घड़ी +Name[hr]=Satovi +Name[hu]=Órák +Name[id]=Jam +Name[is]=Klukkur +Name[it]=Orologi +Name[ja]=時計 +Name[kk]=Сағаттар +Name[ko]=시계 +Name[kn]=ಗಡಿಯಾರಗಳು +Name[lt]=Laikrodžiai +Name[lv]=Pulksteņi +Name[ml]=ക്ലോക്കുകൾ +Name[mr]=घड्याळी +Name[nb]=Klokker +Name[ne]=घडिहरू +Name[nl]=Klok +Name[oc]=Relòtges +Name[or]=ଘଣ୍ଟାଗୁଡ଼ିକ +Name[pa]=ਘੜੀ +Name[pl]=Zegar +Name[pt]=Relógios +Name[pt_BR]=Relógios +Name[ro]=Ceasuri +Name[ru]=Часы +Name[sk]=Hodiny +Name[sl]=Ure +Name[sr]=Сатови +Name[sr@latin]=Satovi +Name[sv]=Klockor +Name[ta]=கடிகாரங்கள் +Name[te]=గడియారాలు +Name[tg]=Соатҳо +Name[th]=นาฬิกา +Name[tr]=Saatler +Name[uk]=Годинники +Name[vi]=Đồng hồ +Name[zh_CN]=时钟 +Name[zh_HK]=時鐘 +Name[zh_TW]=時鐘 +Name[ug]=سائەتلەر +Name=Clocks +GenericName[af]=Horlosies +GenericName[an]=Reloches +GenericName[ar]=الساعات +GenericName[as]=ঘড়ী +GenericName[be]=Гадзіннікі +GenericName[bg]=Часовници +GenericName[bn_IN]=ঘড়ি +GenericName[bs]=Satovi +GenericName[ca]=Rellotges +GenericName[ca@valencia]=Rellotges +GenericName[cs]=Hodiny +GenericName[da]=Ure +GenericName[de]=Uhren +GenericName[el]=Ρολόγια +GenericName[en_GB]=Clocks +GenericName[eo]=Horloĝoj +GenericName[es]=Relojes +GenericName[et]=Kell +GenericName[eu]=Ordulariak +GenericName[fa]=ساعتها +GenericName[fi]=Kellot +GenericName[fr]=Horloges +GenericName[fur]=Orlois +GenericName[ga]=Cloig +GenericName[gd]=Uaireadairean +GenericName[gl]=Reloxos +GenericName[gu]=ઘડિયાળ +GenericName[he]=שעונים +GenericName[hi]=घड़ी +GenericName[hr]=Satovi +GenericName[hu]=Órák +GenericName[id]=Jam +GenericName[is]=Klukkur +GenericName[it]=Orologi +GenericName[ja]=時計 +GenericName[kk]=Сағаттар +GenericName[ko]=시계 +GenericName[kn]=ಗಡಿಯಾರಗಳು +GenericName[lt]=Laikrodžiai +GenericName[lv]=Pulksteņi +GenericName[ml]=ക്ലോക്കുകൾ +GenericName[mr]=घड्याळी +GenericName[nb]=Klokker +GenericName[ne]=घडिहरू +GenericName[nl]=Klok +GenericName[oc]=Relòtges +GenericName[or]=ଘଣ୍ଟାଗୁଡ଼ିକ +GenericName[pa]=ਘੜੀ +GenericName[pl]=Zegar +GenericName[pt]=Relógios +GenericName[pt_BR]=Relógios +GenericName[ro]=Ceasuri +GenericName[ru]=Часы +GenericName[sk]=Hodiny +GenericName[sl]=Ure +GenericName[sr]=Сатови +GenericName[sr@latin]=Satovi +GenericName[sv]=Klockor +GenericName[ta]=கடிகாரங்கள் +GenericName[te]=గడియారాలు +GenericName[tg]=Соатҳо +GenericName[th]=นาฬิกา +GenericName[tr]=Saatler +GenericName[uk]=Годинники +GenericName[vi]=Đồng hồ +GenericName[zh_CN]=时钟 +GenericName[zh_HK]=時鐘 +GenericName[zh_TW]=時鐘 +GenericName[ug]=سائەتلەر +GenericName=Clocks +X-GNOME-FullName[af]=GNOME Horlosies +X-GNOME-FullName[an]=Reloches d'o GNOME +X-GNOME-FullName[ar]=ساعات جنوم +X-GNOME-FullName[as]=GNOME ঘড়ী +X-GNOME-FullName[be]=Гадзіннікі GNOME +X-GNOME-FullName[bg]=Часовници +X-GNOME-FullName[bn_IN]=GNOME ঘড়ি +X-GNOME-FullName[bs]=GNOME satovi +X-GNOME-FullName[ca]=Rellotges del GNOME +X-GNOME-FullName[ca@valencia]=Rellotges del GNOME +X-GNOME-FullName[cs]=Hodiny GNOME +X-GNOME-FullName[da]=GNOME Ure +X-GNOME-FullName[de]=GNOME-Uhren +X-GNOME-FullName[el]=Ρολόγια GNOME +X-GNOME-FullName[en_GB]=GNOME Clocks +X-GNOME-FullName[eo]=GNOME-horloĝoj +X-GNOME-FullName[es]=Relojes de GNOME +X-GNOME-FullName[et]=GNOME kell +X-GNOME-FullName[eu]=GNOMEren ordulariak +X-GNOME-FullName[fa]=ساعتهای گنوم +X-GNOME-FullName[fi]=Gnomen kellot +X-GNOME-FullName[fr]=Horloges de GNOME +X-GNOME-FullName[fur]=Orlois par GNOME +X-GNOME-FullName[ga]=Cloig GNOME +X-GNOME-FullName[gd]=Uaireadairean GNOME +X-GNOME-FullName[gl]=Reloxos de GNOME +X-GNOME-FullName[gu]=GNOME ઘડિયાળ +X-GNOME-FullName[he]=שעונים מבית GNOME +X-GNOME-FullName[hi]=गनोम घड़ी +X-GNOME-FullName[hr]=GNOME satovi +X-GNOME-FullName[hu]=GNOME órák +X-GNOME-FullName[id]=Jam GNOME +X-GNOME-FullName[is]=GNOME Klukkur +X-GNOME-FullName[it]=Orologi per GNOME +X-GNOME-FullName[ja]=GNOME Clocks +X-GNOME-FullName[kk]=GNOME сағаттары +X-GNOME-FullName[ko]=그놈 시계 +X-GNOME-FullName[kn]=GNOME ಕ್ಲಾಕ್ಸ್ +X-GNOME-FullName[lt]=GNOME laikrodžiai +X-GNOME-FullName[lv]=GNOME pulksteņi +X-GNOME-FullName[ml]=ഗ്നോം ക്ലോക്കുകൾ +X-GNOME-FullName[mr]=GNOME घड्याळी +X-GNOME-FullName[nb]=GNOME klokker +X-GNOME-FullName[ne]=जिनोम घडी +X-GNOME-FullName[nl]=Gnome Klok +X-GNOME-FullName[oc]=Relòtges GNOME +X-GNOME-FullName[or]=GNOME ଘଣ୍ଟାଗୁଡ଼ିକ +X-GNOME-FullName[pa]=ਗਨੋਮ ਘੜੀ +X-GNOME-FullName[pl]=Zegar GNOME +X-GNOME-FullName[pt]=Relógios GNOME +X-GNOME-FullName[pt_BR]=Relógios do GNOME +X-GNOME-FullName[ro]=Ceasuri GNOME +X-GNOME-FullName[ru]=Часы GNOME +X-GNOME-FullName[sk]=Hodiny prostredia GNOME +X-GNOME-FullName[sl]=Gnomeove ure +X-GNOME-FullName[sr]=Гномови сатови +X-GNOME-FullName[sr@latin]=Gnomovi satovi +X-GNOME-FullName[sv]=GNOME Klockor +X-GNOME-FullName[ta]=க்னோம் கடிகாரங்கள் +X-GNOME-FullName[te]=గ్నోమ్ గడియారాలు +X-GNOME-FullName[tg]=Соатҳои GNOME +X-GNOME-FullName[th]=นาฬิกา GNOME +X-GNOME-FullName[tr]=GNOME Saatleri +X-GNOME-FullName[vi]=Đồng hồ GNOME +X-GNOME-FullName[zh_CN]=GNOME 时钟 +X-GNOME-FullName[zh_HK]=GNOME Clocks +X-GNOME-FullName[zh_TW]=GNOME 時鐘 +X-GNOME-FullName[ug]=گىنوم سائەتلىرى +X-GNOME-FullName=GNOME Clocks +Comment[af]=Horlosies vir wêreldtyd, plus wekkers, stophorlosie en 'n tydteller +Comment[an]=Reloches d'horas mundials, amás d'alarmas, cronometro y un temporizador +Comment[ar]=ساعات لتوقيتات العالم، مع منبه ومُؤقّت وساعة إيقاف. +Comment[as]=বিশ্বৰ সময়সমূহৰ বাবে ঘড়ী, লগতে এলাৰ্ম, স্টপৱাচ আৰু এটা টাইমাৰ +Comment[be]=Гадзіннікі для адсочвання часу ў розных кутках свету, з будзільнікам, таймерам і секундамерам +Comment[bg]=Часовници за различни градове, аларми, хронометър и отброяване +Comment[bn_IN]=বিশ্বঘড়ি, প্লাস অ্যালার্ম, স্টপওয়াচ এবং টাইমারের জন্য ঘড়ি +Comment[bs]=Satovi za svjetsko vrijeme, plus alarmi, štoperica i tajmer +Comment[ca]=Rellotges de tot el món, a més d'alarmes, de cronòmetres i de temporitzadors +Comment[ca@valencia]=Rellotges de tot el món, a més d'alarmes, de cronòmetres i de temporitzadors +Comment[cs]=Hodiny s časy ve světě, budíkem, stopkami a odpočtem +Comment[da]=Verdensur plus alarmer, stopur og et minutur +Comment[de]=Uhren für die Weltzeit mit Alarm, Stoppuhr und einem Timer +Comment[el]=Ρολόγια για παγκόσμιες ώρες, για ειδοποιήσεις, με χρονόμετρο και αντίστροφη μέτρηση +Comment[en_GB]=Clocks for world times, plus alarms, stopwatch and a timer +Comment[eo]=Horloĝoj por mondaj horoj, plus alarmoj, kronometro kaj minutatoro +Comment[es]=Relojes de horas mundiales, además de alarmas, cronómetro y un temporizador +Comment[et]=Kell maailmaajaga, alarmide, stopperi ja taimeriga +Comment[eu]=Ordulariak munduko orduetarako, gehi alarmak, kronometroa eta tenporizadorea +Comment[fa]=ساعتهایی برای زمانها در دنیا، با اضافهی زنگ هشدار، کرنومتر و زمانسنج +Comment[fi]=Kellot eri puolille maailmaa, hälytykset, sekuntikello ja ajastin +Comment[fr]=Des horloges pour connaître l’heure dans le monde, régler des alarmes, chronométrer ou lancer un décompte +Comment[fur]=Orlois par i fûs oraris tal mont, sveis, cronometri e un timer +Comment[gd]=Uaireadairean airson àm an t-saoghail le caismeachdan, stad-uaireadair ’s tìmear +Comment[gl]=Reloxos para todo o mundo, ademais de alarmas, cronómetro e un temporizador +Comment[gu]=વિશ્ર્વનો સમય, વત્તા એલાર્મ, સ્ટોપવૉચ અને ટાઇમર માટે ઘડિયાળો +Comment[he]=שעונים לזמנים שונים ברחבי העולם לרבות התרעות, שעון עצר וקוצב זמן +Comment[hi]=विश्व समय, के साथ साथ अलार्म, स्टॉपवॉच और एक टाइमर के लिए घड़ियां +Comment[hr]=Satovi sa svjetskim vremenima, uključujući alarme, štopericu i odbrojavanje vremena +Comment[hu]=Világidő, figyelmeztetés, stopper és időzítő +Comment[id]=Jam untuk waktu dunia, alarm, stopwatch dan penghitung waktu +Comment[is]=Klukkur á ýmsum stöðum, vekjaraklukkur, skeiðklukka og niðurteljari. +Comment[it]=Orologi per i fusi orari nel mondo, sveglie, cronometro e un timer +Comment[ja]=世界時計、アラーム、ストップウォッチ、およびタイマー機能をもつ時計アプリケーション +Comment[kk]=Дүниежүзілік уақыттары үшін сағаттар, құрамында тағы оятқыш, секундтар өлшегіші және таймері бар +Comment[ko]=세계 시계, 알림, 초시계, 타이머 기능이 있는 시계 +Comment[kn]=ಪ್ರಪಂಚದ ಸಮಯಕ್ಕಾಗಿನ, ಜೊತೆಗೆ ಅಲಾರಂಗಳಿಗಾಗಿನ, ಸ್ಟಾಪ್ವಾಚ್ಗಾಗಿನ ಮತ್ತು ಟೈಮರಿಗಾಗಿನ ಗಡಿಯಾರಗಳು +Comment[lt]=Pasaulio laikų laikrodžiai, taip pat žadintuvai, chronometras ir laikmatis +Comment[lv]=Pulksteņi pasaules laikiem, kā arī modinātājs, hronometrs un taimeris +Comment[ml]=ലോകത്തെവിടെയുമുള്ള സമയം കാണിയ്ക്കുന്ന ക്ലോക്കുകൾ, അലാറങ്ങൾ, സ്റ്റോപ്പ്വാച്ച്, ടൈമര് എന്നിവയും +Comment[mr]=जागतिक वेळ, तसेच गजर, स्टॉपवॉच व टाइमरकरीता घड्याळी +Comment[nb]=Klokker med verdenstid, alarm, stoppeklokke og nedtelling +Comment[nl]=Wereldklok, wekker, stopwatch en timer +Comment[oc]=De relòtges per conéisser l'ora dins lo mond, reglar d'alarmas, cronometrar o aviar un descompte +Comment[or]=ବିଶ୍ୱ ସମୟ ପାଇଁ ଘଣ୍ଟାଗୁଡ଼ିକ, ଏହା ସହିତ ଆଲାର୍ମ, ଷ୍ଟପୱାଚ ଏବଂ ସମୟ ମାପକ +Comment[pa]=ਸੰਸਾਰ ਸਮਾਂ, ਅਲਾਰਮ, ਸਟਾਪਵਾਚ ਅਤੇ ਟਾਈਮਰ ਦੇ ਨਾਲ ਘੜੀਆਂ +Comment[pl]=Zegar światowy, budzik, stoper i minutnik +Comment[pt]=Relógios com as horas do mundo, alarmes, cronómetros e um temporizador +Comment[pt_BR]=Relógios para horários mundiais além de alarmes, cronômetro e um temporizador +Comment[ro]=Ora în lume, alarme, cronometru și temporizator +Comment[ru]=Часы мирового времени, а также будильник, секундомер и таймер +Comment[sk]=Hodiny svetového času, budík, stopky a časovač +Comment[sl]=Ure za prikazovanje svetovnega časa, alarmi, štoparica in časomer +Comment[sr]=Сатови за светска времена, будилници, штоперица и одбројавач +Comment[sr@latin]=Satovi za svetska vremena, budilnici, štoperica i odbrojavač +Comment[sv]=Klockor för världstider, alarm, stoppur och en timer +Comment[ta]=உலக நேரம், எச்சரிக்கை மணிகள், நிறுத்த கடிகாரம், நேர அளவி கொண்ட கடிகாரங்கள் +Comment[te]=ప్రపంచ సమయాలకు,అలారాలకు, స్టాప్వాచ్ ఇంకా సమయకానికి ఉపయోగపడే గడియారాలు +Comment[tg]=Соат барои вақти ҷаҳон, аз ҷумла истифодаи ҳушдорҳо, сонияшумор ва вақтсанҷ +Comment[th]=นาฬิกาสำหรับเวลาทั่วโลก, พร้อมด้วยนาฬิกาปลุก, นาฬิกาจับเวลา และนาฬิกานับถอยหลัง +Comment[tr]=Dünya saatleri, alarmlar, kronometre ve zaman ölçer +Comment[vi]=Đồng hồ thế giới, kèm báo thức và đo giờ +Comment[zh_CN]=时钟可用来查看世界时间,外加闹钟、秒表和定时器功能 +Comment[zh_HK]=包含世界時刻的時鐘,加上鬧鐘、碼表和計時器 +Comment[zh_TW]=包含世界時刻的時鐘,加上鬧鐘、碼表和計時器 +Comment[ug]=دۇنيا ۋاقىتلىرى، قوڭغۇراقلىق سائەت، ۋاقىت ئۆلچىگۈچ +Comment=Clocks for world times, plus alarms, stopwatch and a timer +Keywords[af]=time;timer;alarm;world clock;stopwatch;time zone;tyd;tydteller;wekker;wêreldtyd;stophorlosie;tydsone;tydhou; +Keywords[an]=Hora;Temporizador;Alarma;Hora mundial;Cronometro;Zona horaria; +Keywords[ar]=وقت;موقت;منبه;ساعة عالمية;ساعة إيقاف;منطقة زمنية; +Keywords[as]=time;timer;alarm;world clock;stopwatch;time zone; +Keywords[be]=час;таймер;гадзіннік;будзільнік;сусветны гадзіннік;секундамер;часавы пояс; +Keywords[bg]=време;обратно;отброяване;напомняне;аларма;часовник;секундомер;пояс;хронометър;time;timer;alarm;world clock;stopwatch;time zone; +Keywords[bn_IN]=সময়;টাইমার;অ্যালার্ম;বিশ্বঘড়ি;স্টপওয়াচ;সময় জোন; +Keywords[bs]=vrijeme;tajmer;alarm;svjetski sat;štoperica;vremenska zona; +Keywords[ca]=temps;temporitzador;alarma;rellotge global;cronòmetre;zona horària; +Keywords[ca@valencia]=temps;temporitzador;alarma;rellotge global;cronòmetre;zona horària; +Keywords[cs]=čas;časovač;minutka;odpočet;budík;buzení;světový čas;stopky;časové pásmo; +Keywords[da]=tid;timer;minutur;alarm;vækkeur;verdensur;stopur;ur;tidszone;klokken; +Keywords[de]=Zeit;Uhrzeit;Alarm;Weltuhr;Stoppuhr;Zeitzone; +Keywords[el]=χρόνος;χρονόμετρο;ξυπνητήρι;παγκόσμιο ρολόι;χρονόμετρο;ώρα ζώνης;time;timer;alarm;world clock;stopwatch;time zone; +Keywords[en_GB]=time;timer;alarm;world clock;stopwatch;time zone; +Keywords[eo]=horo;minutatoro;alarmo;monda horloĝo;kronometro;horzono; +Keywords[es]=Hora;Temporizador;Alarma;Hora mundial;Cronómetro;Zona horaria; +Keywords[et]=aeg;kell;kuupäev;taimer;alarm;äratus;maailmakell;stopper;ajavöönd;ajatsoon; +Keywords[eu]=ordua;tenporizadorea;alarma;munduko ordulariak;kronometroa;ordu-zona; +Keywords[fa]=time;timer;alarm;world clock;stopwatch;time zone;زمان;زمانسنج;زنگ;ساعت جهانی;منطقه زمانی; +Keywords[fi]=time;timer;alarm;world clock;stopwatch;time zone;aika;ajastin;hälytys;maailmankello;aikavyöhyke; +Keywords[fr]=heure;minuterie;décompte;alarme;horloge mondiale;chronomètre;fuseau horaire; +Keywords[fur]=ore;orari;timp;orloi;cronometri;fûs orari;svee;alarme; +Keywords[gd]=time;timer;alarm;world clock;stopwatch;time zone;àm;ùine;tìmear;uaireadair an t-saoghail;uaireadair;saoghal;cleoc;gleoc;stad-uaireadair;roinn-tìde; +Keywords[gl]=tempo;temporizador;alarma;reloxo mundial;reloxo de parada;fuso horario; +Keywords[gu]=સમય;ટાઇમર;એલાર્મ;વિશ્ર્વ ઘડિયાળો;સ્ટોપવૉચ;ટાઇમઝોન; +Keywords[he]=זמן;שעה;טיימר;קוצב זמן;שעון עולמי;שעון עצר;סטופר;אזור זמן;שעון; +Keywords[hi]=समय; टाइमर;अलार्म;दुनिया घड़ी; स्टॉपवॉच; समय क्षेत्र; +Keywords[hr]=vrijeme;odbrojavanje;alarm;svjetski sat;štoperica;vremenska zona; +Keywords[hu]=idő;időzítő;riasztás;világóra;stopper;időzóna; +Keywords[id]=time;timer;alarm;world clock;stopwatch;time zone;jam;waktu; +Keywords[is]=tími;heimsklukka;vekjari;skeiðklukka;niðurteljari;tímabelti; +Keywords[it]=ora;orario;tempo;orologio;cronometro;fuso orario;sveglia;allarme; +Keywords[ja]=time;timer;alarm;world clock;stopwatch;time zone;時間;時刻;タイム;タイマー;アラーム;世界時計;時計;ストップウォッチ;ストップウオッチ;タイムゾーン; +Keywords[kk]=time;timer;alarm;world clock;stopwatch;time zone;уақыт;таймер;оятқыш;дүниежүзі сағаты;секундтар өлшегіші;уақыт белдеуі; +Keywords[ko]=time;시간;timer;타이머;alarm;알림;world clock;세계 시계;stopwatch;스톱워치;time zone;시간대; +Keywords[kn]=ಸಮಯ;ಟೈಮರ್;ಅಲಾರಂ;ಪ್ರಪಂಚದ ಗಡಿಯಾರ;ಸ್ಟಾಪ್ವಾಚ್;ಕಾಲ ವಲಯ; +Keywords[lt]=laikas;laikmatis;žadintuvas;pasaulio laikrodis;chronometras;laiko juosta; +Keywords[lv]=laiks;taimeris;modinātājs;pasaules pulkstenis;hronometrs;laika zona;signāls; +Keywords[ml]=time;timer;alarm;world clock;stopwatch;time zone; +Keywords[mr]=वेळ;टाइमर;गजर;जागतिक घड्याळ;स्टॉपवॉच;वेळ क्षेत्र; +Keywords[nb]=tid;nedtelling;alarm;verdensklokke;stoppeklokke;tidssone; +Keywords[nl]=time;timer;alarm;world clock;stopwatch;time zone;klok;tijd;wekker;wereldtijd;wereldklok;tijdzone; +Keywords[oc]=ora;minutariá;descompte;alarma;relòtge mondiala;cronomètre;fus orari; +Keywords[or]=ସମୟ;ସମୟ ମାପକ;ଆଲାର୍ମ;ବିଶ୍ୱ ସମୟ;ଷ୍ଟପ ୱାଚ;ସମୟ ମଣ୍ଡଳ; +Keywords[pa]=ਸਮਾਂ;ਟਾਈਮ;ਟਾਈਮਰ;ਅਲਾਰਮ;ਸੰਸਾਰ ਘੜੀ;ਸਟਾਪਵਾਚ;ਸਮਾਂ ਖੇਤਰ;ਟਾਈਮ ਜ਼ੋਨ;ਖੇਤਰ;ਵੇਲਾ;ਦੁਨਿਆਂ;ਕਲਾਕ;ਵਕਤ; +Keywords[pl]=czas;minutnik;timer;budzik;alarm;zegar światowy;stoper;strefa czasowa; +Keywords[pt]=horas;temporizador;alarme;relógio mundial;cronómetro;fuso horário; +Keywords[pt_BR]=hora;temporizador;alarme;relógio mundial;cronômetro;fuso horário; +Keywords[ro]=timp;temporizator;fus orar;cronometru;alarmă;time;timer;alarm;world clock;stopwatch;time zone; +Keywords[ru]=время;таймер;будильник;мировое время;часовой пояс; +Keywords[sk]=čas;časovač;budík;svetový čas;stopky;časová zóna; +Keywords[sl]=čas;časomer;alarm;svetovne ure;štoparica;časovni pas; +Keywords[sr]=време;одбројавач;аларм;будилник;светски сат;штоперица;временска зона; +Keywords[sr@latin]=vreme;odbrojavač;alarm;budilnik;svetski sat;štoperica;vremenska zona; +Keywords[sv]=tid;timer;alarm:världsklocka;världsur;stoppur;tidszon; +Keywords[ta]=நேரம்;நேர அளவி;எச்சரிப்பான்;உலக கடிகாரம்;நிறுத்தக் கடிகாரம்;காலப்பகுதி; +Keywords[te]=సమయం;సమయకం;అలారం;ప్రపంచ గడియారం;స్టాప్వాచ్;సమయక్షేత్రం; +Keywords[tg]=вақт;вақтсанҷ;ҳушдор;соати ҷаҳон;сонияшумор;минтақаи вақт; +Keywords[th]=เวลา;นาฬิกานับถอยหลัง;นาฬิกาปลุก;นาฬิกาทั่วโลก;นาฬิกาจับเวลา;เขตเวลา; +Keywords[tr]=saat;zaman;geri sayım;alarm;dünya saatleri;kronometre;saat dilimi; +Keywords[vi]=time;thời;gian;thoi;timer;hẹn;giờ;hen;gio;alarm;world clock;đồng;hồ;dong;ho;stopwatch;time zone;múi;mui;bấm; +Keywords[zh_CN]=time;timer;alarm;world clock;stopwatch;time zone;钟;表;定时;计时;时间;时区; +Keywords[zh_HK]=time;timer;alarm;world clock;stopwatch;time zone;時間;計時器;鬧鐘;鬧鈴;世界時鐘;碼表;時區; +Keywords[zh_TW]=time;timer;alarm;world clock;stopwatch;time zone;時間;倒數;計時器;鬧鐘;鬧鈴;世界時鐘;碼表;時區; +Keywords[ug]=time;timer;alarm;world clock;stopwatch;time zone;ۋاقىت;ئۆلچىگۈچ;قوڭغۇراق;دۇنيا سائىتى;ۋاقىت رايونى; +Keywords=time;timer;alarm;world clock;stopwatch;time zone; +# GDesktopAppInfo requires that the command exists, so use /bin/sh +# rather than /usr/bin/flatpak, since that's guaranteed to exist on +# all test systems (in particular CI machines). +Exec=/bin/sh run --branch=stable --arch=x86_64 --command=gnome-clocks org.gnome.clocks +Icon=org.gnome.clocks +Terminal=false +Type=Application +Categories=GNOME;GTK;Utility;Clock; +StartupNotify=true +DBusActivatable=true +X-GNOME-UsesNotifications=true +X-Geoclue-Reason[af]=Laat wêreldhorlosies toe om vir jou tydsone vertoon te word. +X-Geoclue-Reason[ar]=يتيح عرض الساعات العالمية في منطقة الزمنية الحالية. +X-Geoclue-Reason[be]=Дазваляе паказваць сусветныя гадзіннікі для вашага часавога пояса. +X-Geoclue-Reason[ca]=Permet que els rellotges del món es mostrin a la vostra zona horària. +X-Geoclue-Reason[ca@valencia]=Permet que els rellotges del món es mostren a la vostra zona horària. +X-Geoclue-Reason[cs]=Umožňuje zobrazit světové časy pro vaše časová pásma. +X-Geoclue-Reason[da]=Lader verdensure blive vist for din tidszone. +X-Geoclue-Reason[de]=Ermöglicht die Anzeige von Weltuhren für Ihre Zeitzone. +X-Geoclue-Reason[el]=Επιτρέπει την εμφάνιση των παγκόσμιων ρολογιών για την ζώνη ώρας σας. +X-Geoclue-Reason[en_GB]=Allows world clocks to be displayed for your time zone. +X-Geoclue-Reason[es]=Permite a los relojes del mundo mostrarse para su zona horaria. +X-Geoclue-Reason[eu]=Munduko ordulariak zure ordu-zonan bistaratzea baimentzen du. +X-Geoclue-Reason[fa]=اجازه میدهد تا ساعتهای جهانی برای منطقه زمانی شما نمایش داده شود. +X-Geoclue-Reason[fi]=Mahdollistaa maailmankellojen esityksen aikavyöhykkeellesi. +X-Geoclue-Reason[fr]=Permet d’afficher des horloges mondiales selon votre fuseau horaire. +X-Geoclue-Reason[fur]=Al permet di mostrâ orlois di dut il mont pal tô fûs orari. +X-Geoclue-Reason[gd]=Leigidh seo leat uaireadairean an t-saoghail a shealltainn airson na roinn-tìde agad. +X-Geoclue-Reason[gl]=Permítelle mostrar reloxos do mundio para o seu fuso horario. +X-Geoclue-Reason[he]=מאפשר הצגת שעונים מסביב לעולם עבור אזור הזמן שלך. +X-Geoclue-Reason[hr]=Dopušta svjetskim satovima prikaz u vašoj vremenskoj zoni. +X-Geoclue-Reason[hu]=Világórák megjelenítése az időzónájához. +X-Geoclue-Reason[id]=Mengijinkan jam dunia ditampilkan untuk zona waktu Anda. +X-Geoclue-Reason[is]=Gerir kleift að birta klukku fyrir staðinn þar sem þú ert. +X-Geoclue-Reason[it]=Consente di visualizzare orologi per il proprio fuso orario. +X-Geoclue-Reason[ja]=タイムゾーンに対応した世界時計を表示します。 +X-Geoclue-Reason[kk]=Сіздің уақыт белдеуіңіз үшін дүниежүзілік сағаттарды көрсетуді мүмкін етеді. +X-Geoclue-Reason[ko]=현재 시간대에 해당하는 세계 시계 표시 허용. +X-Geoclue-Reason[lt]=Leidžia rodyti pasaulio laikrodžius jūsų laiko zonai. +X-Geoclue-Reason[lv]=Ļauj parādīt pasaules pulksteņus jūsu laika joslai. +X-Geoclue-Reason[ml]=താങ്കളുടെ സമയമേഖലയ്ക്കനുസരിച്ച് ലോകത്തെ മറ്റു സ്ഥലങ്ങളിലെ ക്ലോക്കുകൾ പ്രദർശിപ്പിക്കാൻ അനുവദിക്കുന്നു. +X-Geoclue-Reason[nb]=Tillat visning av verdensklokker for din tidssone. +X-Geoclue-Reason[nl]=Uw tijdzone kan worden weergegeven in de wereldklok. +X-Geoclue-Reason[pa]=ਤੁਹਾਡੇ ਸਮਾਂ ਖੇਤਰ ਲਈ ਸੰਸਾਰ ਘੜੀਆਂ ਵਿਖਾਉਣ ਦੀ ਇਜਾਜ਼ਤ ਦਿਉ। +X-Geoclue-Reason[pl]=Umożliwia wyświetlanie zegara dla strefy czasowej użytkownika. +X-Geoclue-Reason[pt]=Permite que o relógio mundial apresente o seu fuso horário. +X-Geoclue-Reason[pt_BR]=Permite que relógios mundiais sejam exibidos para o seu fuso horário. +X-Geoclue-Reason[ru]=Позволяет отображать мировые часы для вашего часового пояса. +X-Geoclue-Reason[sk]=Umožňuje zobrazenie svetových hodín pre vašu časovú zónu. +X-Geoclue-Reason[sl]=Dovoli prikaz svetovnih časov za trenutno časovno območje. +X-Geoclue-Reason[sr]=Допустите да светски сатови буду приказани за вашу временску зону. +X-Geoclue-Reason[sr@latin]=Dopustite da svetski satovi budu prikazani za vašu vremensku zonu. +X-Geoclue-Reason[sv]=Låter världsklockor visas för din tidszon. +X-Geoclue-Reason[th]=เพื่อให้สามารถแสดงนาฬิกาทั่วโลกสำหรับเขตเวลาของคุณ +X-Geoclue-Reason[tr]=Saat diliminiz için dünya saatlerinin gösterilmesine olanak tanır. +X-Geoclue-Reason[vi]=Cho phép các đồng hồ thế giới hiển thị cho múi giờ của bạn. +X-Geoclue-Reason[zh_CN]=允许为您的时区显示世界时钟 +X-Geoclue-Reason[zh_TW]=允許為您的時區顯示世界時鐘。 +X-Geoclue-Reason=Allows world clocks to be displayed for your time zone. +X-Flatpak=org.gnome.clocks diff --git a/gio/tests/file.c b/gio/tests/file.c index 98eeb85d4..04625fd68 100644 --- a/gio/tests/file.c +++ b/gio/tests/file.c @@ -155,7 +155,7 @@ typedef struct gint monitor_changed; gchar *monitor_path; gint pos; - gchar *data; + const gchar *data; gchar *buffer; guint timeout; } CreateDeleteData; @@ -510,7 +510,7 @@ test_create_delete (gconstpointer d) skip: g_object_unref (data->monitor); g_object_unref (data->file); - free (data->monitor_path); + g_free (data->monitor_path); g_free (data->buffer); g_free (data); } @@ -962,7 +962,7 @@ test_measure (void) if (size > 0) g_assert_cmpuint (num_bytes, ==, size); g_assert_cmpuint (num_dirs, ==, 6); - g_assert_cmpuint (num_files, ==, 30); + g_assert_cmpuint (num_files, ==, 31); g_object_unref (file); g_free (path); @@ -1056,7 +1056,7 @@ test_measure_async (void) g_free (path); data->expected_dirs = 6; - data->expected_files = 30; + data->expected_files = 31; g_file_measure_disk_usage_async (file, G_FILE_MEASURE_APPARENT_SIZE, diff --git a/gio/tests/fileattributematcher.c b/gio/tests/fileattributematcher.c index 6956e6a36..553d57b19 100644 --- a/gio/tests/fileattributematcher.c +++ b/gio/tests/fileattributematcher.c @@ -3,7 +3,7 @@ static void test_exact (void) { - char *exact_matches[] = { + const char *exact_matches[] = { "*", "a::*", "a::*,b::*", @@ -29,8 +29,8 @@ static void test_equality (void) { struct { - char *expected; - char *actual; + const char *expected; + const char *actual; } equals[] = { /* star makes everything else go away */ { "*", "*,*" }, @@ -70,9 +70,9 @@ static void test_subtract (void) { struct { - char *attributes; - char *subtract; - char *result; + const char *attributes; + const char *subtract; + const char *result; } subtractions[] = { /* * subtracts everything */ { "*", "*", NULL }, diff --git a/gio/tests/g-file-info-filesystem-readonly.c b/gio/tests/g-file-info-filesystem-readonly.c index 9a185b081..c2b0aa518 100644 --- a/gio/tests/g-file-info-filesystem-readonly.c +++ b/gio/tests/g-file-info-filesystem-readonly.c @@ -29,7 +29,7 @@ test_filesystem_readonly (gconstpointer with_mount_monitor) { GFileInfo *file_info; GFile *mounted_file; - GUnixMountMonitor *mount_monitor; + GUnixMountMonitor *mount_monitor = NULL; gchar *bindfs, *fusermount; gchar *command_mount, *command_mount_ro, *command_umount; gchar *curdir, *dir_to_mount, *dir_mountpoint; @@ -62,9 +62,7 @@ test_filesystem_readonly (gconstpointer with_mount_monitor) } if (with_mount_monitor) - { - mount_monitor = g_unix_mount_monitor_get (); - } + mount_monitor = g_unix_mount_monitor_get (); /* Use bindfs, which does not need root privileges, to mount the contents of one dir * into another dir (and do the mount as readonly as per passed '-o ro' option) */ @@ -125,9 +123,7 @@ test_filesystem_readonly (gconstpointer with_mount_monitor) } /* Clean up */ - if (with_mount_monitor) - g_clear_object (&mount_monitor); - + g_clear_object (&mount_monitor); g_clear_object (&file_info); g_clear_object (&mounted_file); g_spawn_command_line_sync (command_umount, NULL, NULL, NULL, NULL); /* unmount */ diff --git a/gio/tests/gdbus-addresses.c b/gio/tests/gdbus-addresses.c index 0ab05661a..2e662d000 100644 --- a/gio/tests/gdbus-addresses.c +++ b/gio/tests/gdbus-addresses.c @@ -39,86 +39,65 @@ test_empty_address (void) g_error_free (error); } -static void -assert_is_supported_address (const gchar *address) -{ - GError *error = NULL; - - g_assert_true (g_dbus_is_supported_address (address, NULL)); - g_assert_true (g_dbus_is_supported_address (address, &error)); - g_assert_no_error (error); -} - -static void -assert_not_supported_address (const gchar *address) -{ - GError *error = NULL; - - g_assert_false (g_dbus_is_supported_address (address, NULL)); - g_assert_false (g_dbus_is_supported_address (address, &error)); - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); - g_clear_error (&error); -} - #ifdef G_OS_UNIX static void test_unix_address (void) { - assert_not_supported_address ("some-imaginary-transport:foo=bar"); - assert_is_supported_address ("unix:path=/tmp/dbus-test"); - assert_is_supported_address ("unix:abstract=/tmp/dbus-another-test"); + g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar", NULL)); + g_assert (g_dbus_is_supported_address ("unix:path=/tmp/dbus-test", NULL)); + g_assert (g_dbus_is_supported_address ("unix:abstract=/tmp/dbus-another-test", NULL)); g_assert (g_dbus_is_address ("unix:foo=bar")); - assert_not_supported_address ("unix:foo=bar"); + g_assert (!g_dbus_is_supported_address ("unix:foo=bar", NULL)); g_assert (!g_dbus_is_address ("unix:path=/foo;abstract=/bar")); - assert_not_supported_address ("unix:path=/foo;abstract=/bar"); - assert_is_supported_address ("unix:path=/tmp/concrete;unix:abstract=/tmp/abstract"); + g_assert (!g_dbus_is_supported_address ("unix:path=/foo;abstract=/bar", NULL)); + g_assert (g_dbus_is_supported_address ("unix:path=/tmp/concrete;unix:abstract=/tmp/abstract", NULL)); g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar")); g_assert (g_dbus_is_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid")); - assert_not_supported_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid"); + g_assert (!g_dbus_is_supported_address ("some-imaginary-transport:foo=bar;unix:path=/this/is/valid", NULL)); } #endif static void test_nonce_tcp_address (void) { - assert_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar"); - assert_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv6"); - assert_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv4"); - - assert_not_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=blah"); - assert_not_supported_address ("nonce-tcp:host=localhost,port=420000,noncefile=/foo/bar,family=ipv4"); - assert_not_supported_address ("nonce-tcp:host=,port=x42,noncefile=/foo/bar,family=ipv4"); - assert_not_supported_address ("nonce-tcp:host=,port=42x,noncefile=/foo/bar,family=ipv4"); - assert_not_supported_address ("nonce-tcp:host=,port=420000,noncefile=/foo/bar,family=ipv4"); + g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar", NULL)); + g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv6", NULL)); + g_assert (g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=ipv4", NULL)); + + g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=42,noncefile=/foo/bar,family=blah", NULL)); + g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=localhost,port=420000,noncefile=/foo/bar,family=ipv4", NULL)); + g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=x42,noncefile=/foo/bar,family=ipv4", NULL)); + g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=42x,noncefile=/foo/bar,family=ipv4", NULL)); + g_assert (!g_dbus_is_supported_address ("nonce-tcp:host=,port=420000,noncefile=/foo/bar,family=ipv4", NULL)); } static void test_tcp_address (void) { - assert_is_supported_address ("tcp:host=localhost"); - assert_not_supported_address ("tcp:host=localhost,noncefile=/tmp/foo"); - assert_is_supported_address ("tcp:host=localhost,port=42"); - assert_not_supported_address ("tcp:host=localhost,port=-1"); - assert_not_supported_address ("tcp:host=localhost,port=420000"); - assert_not_supported_address ("tcp:host=localhost,port=42x"); - assert_is_supported_address ("tcp:host=localhost,port=42,family=ipv4"); - assert_is_supported_address ("tcp:host=localhost,port=42,family=ipv6"); - assert_not_supported_address ("tcp:host=localhost,port=42,family=sopranos"); + g_assert (g_dbus_is_supported_address ("tcp:host=localhost", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,noncefile=/tmp/foo", NULL)); + g_assert (g_dbus_is_supported_address ("tcp:host=localhost,port=42", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=-1", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=420000", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=42x", NULL)); + g_assert (g_dbus_is_supported_address ("tcp:host=localhost,port=42,family=ipv4", NULL)); + g_assert (g_dbus_is_supported_address ("tcp:host=localhost,port=42,family=ipv6", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=42,family=sopranos", NULL)); } static void test_autolaunch_address (void) { - assert_is_supported_address ("autolaunch:"); + g_assert (g_dbus_is_supported_address ("autolaunch:", NULL)); } static void test_mixed_address (void) { - assert_is_supported_address ("unix:path=/tmp/dbus1;unix:path=/tmp/dbus2"); - assert_is_supported_address ("tcp:host=localhost,port=42;autolaunch:"); - assert_not_supported_address ("tcp:host=localhost,port=42;tcp:family=bla"); + g_assert (g_dbus_is_supported_address ("unix:path=/tmp/dbus1;unix:path=/tmp/dbus2", NULL)); + g_assert (g_dbus_is_supported_address ("tcp:host=localhost,port=42;autolaunch:", NULL)); + g_assert (!g_dbus_is_supported_address ("tcp:host=localhost,port=42;tcp:family=bla", NULL)); } static const struct { const char *before; const char *after; } escaping[] = { diff --git a/gio/tests/gdbus-connection-slow.c b/gio/tests/gdbus-connection-slow.c index 82e02587c..dd1ababd4 100644 --- a/gio/tests/gdbus-connection-slow.c +++ b/gio/tests/gdbus-connection-slow.c @@ -123,7 +123,7 @@ large_message_timeout_cb (gpointer data) { (void)data; - g_error ("Error: timeout waiting for dbus name to appear\n"); + g_error ("Error: timeout waiting for dbus name to appear"); return FALSE; } diff --git a/gio/tests/gdbus-serialization.c b/gio/tests/gdbus-serialization.c index a6c242a13..da28f1bc1 100644 --- a/gio/tests/gdbus-serialization.c +++ b/gio/tests/gdbus-serialization.c @@ -855,7 +855,7 @@ message_serialize_header_checks (void) { GDBusMessage *message; GDBusMessage *reply; - GError *error = NULL; + GError *error; guchar *blob; gsize blob_size; @@ -863,73 +863,65 @@ message_serialize_header_checks (void) * check we can't serialize messages with INVALID type */ message = g_dbus_message_new (); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: type is INVALID"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); g_object_unref (message); /* - * check that we can't serialize messages with SIGNATURE set to a non-signature-typed value - */ - message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember"); - g_dbus_message_set_header (message, G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, g_variant_new_boolean (FALSE)); - blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); - - g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); - g_assert_cmpstr (error->message, ==, "Signature header found but is not of type signature"); - g_assert_null (blob); - - g_clear_error (&error); - g_clear_object (&message); - - /* * check we can't serialize signal messages with INTERFACE, PATH or MEMBER unset / set to reserved value */ message = g_dbus_message_new_signal ("/the/path", "The.Interface", "TheMember"); /* ----- */ /* interface NULL => error */ g_dbus_message_set_interface (message, NULL); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* interface reserved value => error */ g_dbus_message_set_interface (message, "org.freedesktop.DBus.Local"); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The INTERFACE header field is using the reserved value org.freedesktop.DBus.Local"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset interface */ g_dbus_message_set_interface (message, "The.Interface"); /* ----- */ /* path NULL => error */ g_dbus_message_set_path (message, NULL); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* path reserved value => error */ g_dbus_message_set_path (message, "/org/freedesktop/DBus/Local"); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: The PATH header field is using the reserved value /org/freedesktop/DBus/Local"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset path */ g_dbus_message_set_path (message, "/the/path"); /* ----- */ /* member NULL => error */ g_dbus_message_set_member (message, NULL); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: SIGNAL message: PATH, INTERFACE or MEMBER header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset member */ g_dbus_message_set_member (message, "TheMember"); /* ----- */ @@ -943,21 +935,23 @@ message_serialize_header_checks (void) /* ----- */ /* path NULL => error */ g_dbus_message_set_path (message, NULL); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset path */ g_dbus_message_set_path (message, "/the/path"); /* ----- */ /* member NULL => error */ g_dbus_message_set_member (message, NULL); + error = NULL; blob = g_dbus_message_to_blob (message, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_CALL message: PATH or MEMBER header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset member */ g_dbus_message_set_member (message, "TheMember"); /* ----- */ @@ -973,31 +967,34 @@ message_serialize_header_checks (void) reply = g_dbus_message_new_method_reply (message); g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42); g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL); + error = NULL; blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: METHOD_RETURN message: REPLY_SERIAL header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); g_object_unref (reply); /* method error - first nuke ERROR_NAME, then REPLY_SERIAL */ reply = g_dbus_message_new_method_error (message, "Some.Error.Name", "the message"); g_assert_cmpint (g_dbus_message_get_reply_serial (reply), ==, 42); /* nuke ERROR_NAME */ g_dbus_message_set_error_name (reply, NULL); + error = NULL; blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); /* reset ERROR_NAME */ g_dbus_message_set_error_name (reply, "Some.Error.Name"); /* nuke REPLY_SERIAL */ g_dbus_message_set_header (reply, G_DBUS_MESSAGE_HEADER_FIELD_REPLY_SERIAL, NULL); + error = NULL; blob = g_dbus_message_to_blob (reply, &blob_size, G_DBUS_CAPABILITY_FLAGS_NONE, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); g_assert_cmpstr (error->message, ==, "Cannot serialize message: ERROR message: REPLY_SERIAL or ERROR_NAME header field is missing"); - g_clear_error (&error); - g_assert_null (blob); + g_error_free (error); + g_assert (blob == NULL); g_object_unref (reply); g_object_unref (message); } @@ -1084,125 +1081,6 @@ test_double_array (void) /* ---------------------------------------------------------------------------------------------------- */ -/* Test that an invalid header in a D-Bus message (specifically, with a type - * which doesn’t match what’s expected for the given header) is gracefully - * handled with an error rather than a crash. - * The set of bytes here come directly from fuzzer output. */ -static void -test_message_parse_non_signature_header (void) -{ - const guint8 data[] = { - 'l', /* little-endian byte order */ - 0x04, /* message type */ - 0x0f, /* message flags */ - 0x01, /* major protocol version */ - 0x00, 0x00, 0x00, 0x00, /* body length */ - 0x00, 0x00, 0x00, 0xbc, /* message serial */ - /* a{yv} of header fields: - * (things start to be invalid below here) */ - 0x02, 0x00, 0x00, 0x00, /* array length (in bytes) */ - G_DBUS_MESSAGE_HEADER_FIELD_SIGNATURE, /* array key */ - /* Variant array value: */ - 0x04, /* signature length */ - 'd', 0x00, 0x00, 'F', /* signature (invalid) */ - 0x00, /* nul terminator */ - /* (Variant array value payload missing) */ - /* (message body length missing) */ - }; - gsize size = sizeof (data); - GDBusMessage *message = NULL; - GError *local_error = NULL; - - message = g_dbus_message_new_from_blob ((guchar *) data, size, - G_DBUS_CAPABILITY_FLAGS_NONE, - &local_error); - g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); - g_assert_null (message); - - g_clear_error (&local_error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/* Test that an invalid header in a D-Bus message (specifically, containing a - * variant with an empty type signature) is gracefully handled with an error - * rather than a crash. The set of bytes here come directly from fuzzer - * output. */ -static void -test_message_parse_empty_signature_header (void) -{ - const guint8 data[] = { - 'l', /* little-endian byte order */ - 0x20, /* message type */ - 0x20, /* message flags */ - 0x01, /* major protocol version */ - 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */ - 0x20, 0x20, 0x20, 0x20, /* message serial */ - /* a{yv} of header fields: - * (things start to be even more invalid below here) */ - 0x20, 0x20, 0x20, 0x00, /* array length (in bytes) */ - 0x20, /* array key */ - /* Variant array value: */ - 0x00, /* signature length */ - 0x00, /* nul terminator */ - /* (Variant array value payload missing) */ - /* (message body length missing) */ - }; - gsize size = sizeof (data); - GDBusMessage *message = NULL; - GError *local_error = NULL; - - message = g_dbus_message_new_from_blob ((guchar *) data, size, - G_DBUS_CAPABILITY_FLAGS_NONE, - &local_error); - g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); - g_assert_null (message); - - g_clear_error (&local_error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - -/* Test that an invalid header in a D-Bus message (specifically, containing a - * variant with a type signature containing multiple complete types) is - * gracefully handled with an error rather than a crash. The set of bytes here - * come directly from fuzzer output. */ -static void -test_message_parse_multiple_signature_header (void) -{ - const guint8 data[] = { - 'l', /* little-endian byte order */ - 0x20, /* message type */ - 0x20, /* message flags */ - 0x01, /* major protocol version */ - 0x20, 0x20, 0x20, 0x00, /* body length (invalid) */ - 0x20, 0x20, 0x20, 0x20, /* message serial */ - /* a{yv} of header fields: - * (things start to be even more invalid below here) */ - 0x20, 0x20, 0x20, 0x00, /* array length (in bytes) */ - 0x20, /* array key */ - /* Variant array value: */ - 0x02, /* signature length */ - 'b', 'b', /* two complete types */ - 0x00, /* nul terminator */ - /* (Variant array value payload missing) */ - /* (message body length missing) */ - }; - gsize size = sizeof (data); - GDBusMessage *message = NULL; - GError *local_error = NULL; - - message = g_dbus_message_new_from_blob ((guchar *) data, size, - G_DBUS_CAPABILITY_FLAGS_NONE, - &local_error); - g_assert_error (local_error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); - g_assert_null (message); - - g_clear_error (&local_error); -} - -/* ---------------------------------------------------------------------------------------------------- */ - int main (int argc, char *argv[]) @@ -1221,12 +1099,6 @@ main (int argc, message_parse_empty_arrays_of_arrays); g_test_add_func ("/gdbus/message-serialize/double-array", test_double_array); - g_test_add_func ("/gdbus/message-parse/non-signature-header", - test_message_parse_non_signature_header); - g_test_add_func ("/gdbus/message-parse/empty-signature-header", - test_message_parse_empty_signature_header); - g_test_add_func ("/gdbus/message-parse/multiple-signature-header", - test_message_parse_multiple_signature_header); return g_test_run(); } diff --git a/gio/tests/gengiotypefuncs.py b/gio/tests/gengiotypefuncs.py index 9732d7892..47219f357 100644 --- a/gio/tests/gengiotypefuncs.py +++ b/gio/tests/gengiotypefuncs.py @@ -19,11 +19,11 @@ if debug: print (len(in_files), 'input files') for filename in in_files: if debug: print ('Input file: ', filename) - with open(filename, "r") as f: + with open(filename, 'rb') as f: for line in f: - line = line.rstrip('\n').rstrip('\r') + line = line.rstrip(b'\n').rstrip(b'\r') # print line - match = re.search(r'\bg_[a-zA-Z0-9_]*_get_type\b', line) + match = re.search(b'\bg_[a-zA-Z0-9_]*_get_type\b', line) if match: func = match.group(0) if not func in funcs: diff --git a/gio/tests/glistmodel.c b/gio/tests/glistmodel.c index 898b62886..dcf571f29 100644 --- a/gio/tests/glistmodel.c +++ b/gio/tests/glistmodel.c @@ -216,13 +216,550 @@ test_store_sorted (void) g_object_unref (store); } +/* Test that using splice() to replace the middle element in a list store works. */ +static void +test_store_splice_replace_middle (void) +{ + GListStore *store; + GListModel *model; + GAction *item; + GPtrArray *array; + + g_test_bug ("795307"); + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + array = g_ptr_array_new_full (0, g_object_unref); + g_ptr_array_add (array, g_simple_action_new ("1", NULL)); + g_ptr_array_add (array, g_simple_action_new ("2", NULL)); + g_ptr_array_add (array, g_simple_action_new ("3", NULL)); + g_ptr_array_add (array, g_simple_action_new ("4", NULL)); + g_ptr_array_add (array, g_simple_action_new ("5", NULL)); + + /* Add three items through splice */ + g_list_store_splice (store, 0, 0, array->pdata, 3); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 3); + + item = g_list_model_get_item (model, 0); + g_assert_cmpstr (g_action_get_name (item), ==, "1"); + g_object_unref (item); + item = g_list_model_get_item (model, 1); + g_assert_cmpstr (g_action_get_name (item), ==, "2"); + g_object_unref (item); + item = g_list_model_get_item (model, 2); + g_assert_cmpstr (g_action_get_name (item), ==, "3"); + g_object_unref (item); + + /* Replace the middle one with two new items */ + g_list_store_splice (store, 1, 1, array->pdata + 3, 2); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 4); + + item = g_list_model_get_item (model, 0); + g_assert_cmpstr (g_action_get_name (item), ==, "1"); + g_object_unref (item); + item = g_list_model_get_item (model, 1); + g_assert_cmpstr (g_action_get_name (item), ==, "4"); + g_object_unref (item); + item = g_list_model_get_item (model, 2); + g_assert_cmpstr (g_action_get_name (item), ==, "5"); + g_object_unref (item); + item = g_list_model_get_item (model, 3); + g_assert_cmpstr (g_action_get_name (item), ==, "3"); + g_object_unref (item); + + g_ptr_array_unref (array); + g_object_unref (store); +} + +/* Test that using splice() to replace the whole list store works. */ +static void +test_store_splice_replace_all (void) +{ + GListStore *store; + GListModel *model; + GPtrArray *array; + GAction *item; + + g_test_bug ("795307"); + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + array = g_ptr_array_new_full (0, g_object_unref); + g_ptr_array_add (array, g_simple_action_new ("1", NULL)); + g_ptr_array_add (array, g_simple_action_new ("2", NULL)); + g_ptr_array_add (array, g_simple_action_new ("3", NULL)); + g_ptr_array_add (array, g_simple_action_new ("4", NULL)); + + /* Add the first two */ + g_list_store_splice (store, 0, 0, array->pdata, 2); + + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2); + item = g_list_model_get_item (model, 0); + g_assert_cmpstr (g_action_get_name (item), ==, "1"); + g_object_unref (item); + item = g_list_model_get_item (model, 1); + g_assert_cmpstr (g_action_get_name (item), ==, "2"); + g_object_unref (item); + + /* Replace all with the last two */ + g_list_store_splice (store, 0, 2, array->pdata + 2, 2); + + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2); + item = g_list_model_get_item (model, 0); + g_assert_cmpstr (g_action_get_name (item), ==, "3"); + g_object_unref (item); + item = g_list_model_get_item (model, 1); + g_assert_cmpstr (g_action_get_name (item), ==, "4"); + g_object_unref (item); + + g_ptr_array_unref (array); + g_object_unref (store); +} + +/* Test that using splice() without removing or adding anything works */ +static void +test_store_splice_noop (void) +{ + GListStore *store; + GListModel *model; + GAction *item; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + /* splice noop with an empty list */ + g_list_store_splice (store, 0, 0, NULL, 0); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0); + + /* splice noop with a non-empty list */ + item = G_ACTION (g_simple_action_new ("1", NULL)); + g_list_store_append (store, item); + g_object_unref (item); + + g_list_store_splice (store, 0, 0, NULL, 0); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1); + + g_list_store_splice (store, 1, 0, NULL, 0); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1); + + item = g_list_model_get_item (model, 0); + g_assert_cmpstr (g_action_get_name (item), ==, "1"); + g_object_unref (item); + + g_object_unref (store); +} + +static gboolean +model_array_equal (GListModel *model, GPtrArray *array) +{ + guint i; + + if (g_list_model_get_n_items (model) != array->len) + return FALSE; + + for (i = 0; i < array->len; i++) + { + GObject *ptr; + gboolean ptrs_equal; + + ptr = g_list_model_get_item (model, i); + ptrs_equal = (g_ptr_array_index (array, i) == ptr); + g_object_unref (ptr); + if (!ptrs_equal) + return FALSE; + } + + return TRUE; +} + +/* Test that using splice() to remove multiple items at different + * positions works */ +static void +test_store_splice_remove_multiple (void) +{ + GListStore *store; + GListModel *model; + GPtrArray *array; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + array = g_ptr_array_new_full (0, g_object_unref); + g_ptr_array_add (array, g_simple_action_new ("1", NULL)); + g_ptr_array_add (array, g_simple_action_new ("2", NULL)); + g_ptr_array_add (array, g_simple_action_new ("3", NULL)); + g_ptr_array_add (array, g_simple_action_new ("4", NULL)); + g_ptr_array_add (array, g_simple_action_new ("5", NULL)); + g_ptr_array_add (array, g_simple_action_new ("6", NULL)); + g_ptr_array_add (array, g_simple_action_new ("7", NULL)); + g_ptr_array_add (array, g_simple_action_new ("8", NULL)); + g_ptr_array_add (array, g_simple_action_new ("9", NULL)); + g_ptr_array_add (array, g_simple_action_new ("10", NULL)); + + /* Add all */ + g_list_store_splice (store, 0, 0, array->pdata, array->len); + g_assert_true (model_array_equal (model, array)); + + /* Remove the first two */ + g_list_store_splice (store, 0, 2, NULL, 0); + g_assert_false (model_array_equal (model, array)); + g_ptr_array_remove_range (array, 0, 2); + g_assert_true (model_array_equal (model, array)); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 8); + + /* Remove two in the middle */ + g_list_store_splice (store, 2, 2, NULL, 0); + g_assert_false (model_array_equal (model, array)); + g_ptr_array_remove_range (array, 2, 2); + g_assert_true (model_array_equal (model, array)); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 6); + + /* Remove two at the end */ + g_list_store_splice (store, 4, 2, NULL, 0); + g_assert_false (model_array_equal (model, array)); + g_ptr_array_remove_range (array, 4, 2); + g_assert_true (model_array_equal (model, array)); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 4); + + g_ptr_array_unref (array); + g_object_unref (store); +} + +/* Test that using splice() to add multiple items at different + * positions works */ +static void +test_store_splice_add_multiple (void) +{ + GListStore *store; + GListModel *model; + GPtrArray *array; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + array = g_ptr_array_new_full (0, g_object_unref); + g_ptr_array_add (array, g_simple_action_new ("1", NULL)); + g_ptr_array_add (array, g_simple_action_new ("2", NULL)); + g_ptr_array_add (array, g_simple_action_new ("3", NULL)); + g_ptr_array_add (array, g_simple_action_new ("4", NULL)); + g_ptr_array_add (array, g_simple_action_new ("5", NULL)); + g_ptr_array_add (array, g_simple_action_new ("6", NULL)); + + /* Add two at the beginning */ + g_list_store_splice (store, 0, 0, array->pdata, 2); + + /* Add two at the end */ + g_list_store_splice (store, 2, 0, array->pdata + 4, 2); + + /* Add two in the middle */ + g_list_store_splice (store, 2, 0, array->pdata + 2, 2); + + g_assert_true (model_array_equal (model, array)); + + g_ptr_array_unref (array); + g_object_unref (store); +} + +/* Test that get_item_type() returns the right type */ +static void +test_store_item_type (void) +{ + GListStore *store; + GType gtype; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + gtype = g_list_model_get_item_type (G_LIST_MODEL (store)); + g_assert (gtype == G_TYPE_SIMPLE_ACTION); + + g_object_unref (store); +} + +/* Test that remove_all() removes all items */ +static void +test_store_remove_all (void) +{ + GListStore *store; + GListModel *model; + GSimpleAction *item; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + /* Test with an empty list */ + g_list_store_remove_all (store); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0); + + /* Test with a non-empty list */ + item = g_simple_action_new ("42", NULL); + g_list_store_append (store, item); + g_list_store_append (store, item); + g_object_unref (item); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 2); + g_list_store_remove_all (store); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 0); + + g_object_unref (store); +} + +/* Test that splice() logs an error when passed the wrong item type */ +static void +test_store_splice_wrong_type (void) +{ + GListStore *store; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + + g_test_expect_message (G_LOG_DOMAIN, + G_LOG_LEVEL_CRITICAL, + "*GListStore instead of a GSimpleAction*"); + g_list_store_splice (store, 0, 0, (gpointer)&store, 1); + + g_object_unref (store); +} + +static gint +ptr_array_cmp_action_by_name (GAction **a, GAction **b) +{ + return g_strcmp0 (g_action_get_name (*a), g_action_get_name (*b)); +} + +static gint +list_model_cmp_action_by_name (GAction *a, GAction *b, gpointer user_data) +{ + return g_strcmp0 (g_action_get_name (a), g_action_get_name (b)); +} + +/* Test if sort() works */ +static void +test_store_sort (void) +{ + GListStore *store; + GListModel *model; + GPtrArray *array; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + array = g_ptr_array_new_full (0, g_object_unref); + g_ptr_array_add (array, g_simple_action_new ("2", NULL)); + g_ptr_array_add (array, g_simple_action_new ("3", NULL)); + g_ptr_array_add (array, g_simple_action_new ("9", NULL)); + g_ptr_array_add (array, g_simple_action_new ("4", NULL)); + g_ptr_array_add (array, g_simple_action_new ("5", NULL)); + g_ptr_array_add (array, g_simple_action_new ("8", NULL)); + g_ptr_array_add (array, g_simple_action_new ("6", NULL)); + g_ptr_array_add (array, g_simple_action_new ("7", NULL)); + g_ptr_array_add (array, g_simple_action_new ("1", NULL)); + + /* Sort an empty list */ + g_list_store_sort (store, (GCompareDataFunc)list_model_cmp_action_by_name, NULL); + + /* Add all */ + g_list_store_splice (store, 0, 0, array->pdata, array->len); + g_assert_true (model_array_equal (model, array)); + + /* Sort both and check if the result is the same */ + g_ptr_array_sort (array, (GCompareFunc)ptr_array_cmp_action_by_name); + g_assert_false (model_array_equal (model, array)); + g_list_store_sort (store, (GCompareDataFunc)list_model_cmp_action_by_name, NULL); + g_assert_true (model_array_equal (model, array)); + + g_ptr_array_unref (array); + g_object_unref (store); +} + +/* Test the cases where the item store tries to speed up item access by caching + * the last iter/position */ +static void +test_store_get_item_cache (void) +{ + GListStore *store; + GListModel *model; + GSimpleAction *item1, *item2, *temp; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + /* Add two */ + item1 = g_simple_action_new ("1", NULL); + g_list_store_append (store, item1); + item2 = g_simple_action_new ("2", NULL); + g_list_store_append (store, item2); + + /* Clear the cache */ + g_assert_null (g_list_model_get_item (model, 42)); + + /* Access the same position twice */ + temp = g_list_model_get_item (model, 1); + g_assert (temp == item2); + g_object_unref (temp); + temp = g_list_model_get_item (model, 1); + g_assert (temp == item2); + g_object_unref (temp); + + g_assert_null (g_list_model_get_item (model, 42)); + + /* Access forwards */ + temp = g_list_model_get_item (model, 0); + g_assert (temp == item1); + g_object_unref (temp); + temp = g_list_model_get_item (model, 1); + g_assert (temp == item2); + g_object_unref (temp); + + g_assert_null (g_list_model_get_item (model, 42)); + + /* Access backwards */ + temp = g_list_model_get_item (model, 1); + g_assert (temp == item2); + g_object_unref (temp); + temp = g_list_model_get_item (model, 0); + g_assert (temp == item1); + g_object_unref (temp); + + g_object_unref (item1); + g_object_unref (item2); + g_object_unref (store); +} + +struct ItemsChangedData +{ + guint position; + guint removed; + guint added; + gboolean called; +}; + +static void +expect_items_changed (struct ItemsChangedData *expected, + guint position, + guint removed, + guint added) +{ + expected->position = position; + expected->removed = removed; + expected->added = added; + expected->called = FALSE; +} + +static void +on_items_changed (GListModel *model, + guint position, + guint removed, + guint added, + struct ItemsChangedData *expected) +{ + g_assert_false (expected->called); + g_assert_cmpuint (expected->position, ==, position); + g_assert_cmpuint (expected->removed, ==, removed); + g_assert_cmpuint (expected->added, ==, added); + expected->called = TRUE; +} + +/* Test that all operations on the list emit the items-changed signal */ +static void +test_store_signal_items_changed (void) +{ + GListStore *store; + GListModel *model; + GSimpleAction *item; + struct ItemsChangedData expected = {0}; + + store = g_list_store_new (G_TYPE_SIMPLE_ACTION); + model = G_LIST_MODEL (store); + + g_object_connect (model, "signal::items-changed", + on_items_changed, &expected, NULL); + + /* Emit the signal manually */ + expect_items_changed (&expected, 0, 0, 0); + g_list_model_items_changed (model, 0, 0, 0); + g_assert_true (expected.called); + + /* Append an item */ + expect_items_changed (&expected, 0, 0, 1); + item = g_simple_action_new ("2", NULL); + g_list_store_append (store, item); + g_object_unref (item); + g_assert_true (expected.called); + + /* Insert an item */ + expect_items_changed (&expected, 1, 0, 1); + item = g_simple_action_new ("1", NULL); + g_list_store_insert (store, 1, item); + g_object_unref (item); + g_assert_true (expected.called); + + /* Sort the list */ + expect_items_changed (&expected, 0, 2, 2); + g_list_store_sort (store, + (GCompareDataFunc)list_model_cmp_action_by_name, + NULL); + g_assert_true (expected.called); + + /* Insert sorted */ + expect_items_changed (&expected, 2, 0, 1); + item = g_simple_action_new ("3", NULL); + g_list_store_insert_sorted (store, + item, + (GCompareDataFunc)list_model_cmp_action_by_name, + NULL); + g_object_unref (item); + g_assert_true (expected.called); + + /* Remove an item */ + expect_items_changed (&expected, 1, 1, 0); + g_list_store_remove (store, 1); + g_assert_true (expected.called); + + /* Splice */ + expect_items_changed (&expected, 0, 2, 1); + item = g_simple_action_new ("4", NULL); + g_assert_cmpuint (g_list_model_get_n_items (model), >=, 2); + g_list_store_splice (store, 0, 2, (gpointer)&item, 1); + g_object_unref (item); + g_assert_true (expected.called); + + /* Remove all */ + expect_items_changed (&expected, 0, 1, 0); + g_assert_cmpuint (g_list_model_get_n_items (model), ==, 1); + g_list_store_remove_all (store); + g_assert_true (expected.called); + + g_object_unref (store); +} + int main (int argc, char *argv[]) { g_test_init (&argc, &argv, NULL); + g_test_bug_base ("https://bugzilla.gnome.org/"); g_test_add_func ("/glistmodel/store/boundaries", test_store_boundaries); g_test_add_func ("/glistmodel/store/refcounts", test_store_refcounts); g_test_add_func ("/glistmodel/store/sorted", test_store_sorted); + g_test_add_func ("/glistmodel/store/splice-replace-middle", + test_store_splice_replace_middle); + g_test_add_func ("/glistmodel/store/splice-replace-all", + test_store_splice_replace_all); + g_test_add_func ("/glistmodel/store/splice-noop", test_store_splice_noop); + g_test_add_func ("/glistmodel/store/splice-remove-multiple", + test_store_splice_remove_multiple); + g_test_add_func ("/glistmodel/store/splice-add-multiple", + test_store_splice_add_multiple); + g_test_add_func ("/glistmodel/store/splice-wrong-type", + test_store_splice_wrong_type); + g_test_add_func ("/glistmodel/store/item-type", + test_store_item_type); + g_test_add_func ("/glistmodel/store/remove-all", + test_store_remove_all); + g_test_add_func ("/glistmodel/store/sort", + test_store_sort); + g_test_add_func ("/glistmodel/store/get-item-cache", + test_store_get_item_cache); + g_test_add_func ("/glistmodel/store/items-changed", + test_store_signal_items_changed); return g_test_run (); } diff --git a/gio/tests/gschema-compile.c b/gio/tests/gschema-compile.c index 65f656c52..81ded83fa 100644 --- a/gio/tests/gschema-compile.c +++ b/gio/tests/gschema-compile.c @@ -22,17 +22,17 @@ test_schema_do_compile (gpointer data) SchemaTest *test = (SchemaTest *) data; gchar *filename = g_strconcat (test->name, ".gschema.xml", NULL); gchar *path = g_test_build_filename (G_TEST_DIST, "schema-tests", filename, NULL); - gchar *argv[] = { + const gchar *argv[] = { GLIB_COMPILE_SCHEMAS, "--strict", "--dry-run", "--schema-file", path, - (gchar *)test->opt, + test->opt, NULL }; gchar *envp[] = { NULL }; - execve (argv[0], argv, envp); + execve (argv[0], (char **) argv, envp); g_assert_not_reached (); } diff --git a/gio/tests/gsettings.c b/gio/tests/gsettings.c index 2be4122fe..2f056ee95 100644 --- a/gio/tests/gsettings.c +++ b/gio/tests/gsettings.c @@ -1324,6 +1324,33 @@ test_simple_binding (void) g_object_get (obj, "flags", &i, NULL); g_assert_cmpint (i, ==, TEST_FLAGS_MOURNING | TEST_FLAGS_WALKING); + g_settings_bind (settings, "uint", obj, "uint", G_SETTINGS_BIND_DEFAULT); + + g_object_set (obj, "uint", 12345, NULL); + g_assert_cmpuint (g_settings_get_uint (settings, "uint"), ==, 12345); + + g_settings_set_uint (settings, "uint", 54321); + u = 1111; + g_object_get (obj, "uint", &u, NULL); + g_assert_cmpuint (u, ==, 54321); + + g_settings_bind (settings, "range", obj, "uint", G_SETTINGS_BIND_DEFAULT); + g_object_set (obj, "uint", 22, NULL); + u = 1111; + g_assert_cmpuint (g_settings_get_uint (settings, "range"), ==, 22); + g_object_get (obj, "uint", &u, NULL); + g_assert_cmpuint (u, ==, 22); + + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "* is out of schema-specified range for*"); + g_object_set (obj, "uint", 45, NULL); + g_test_assert_expected_messages (); + u = 1111; + g_object_get (obj, "uint", &u, NULL); + g_assert_cmpuint (g_settings_get_uint (settings, "range"), ==, 22); + /* The value of the object is currently not reset back to its initial value + g_assert_cmpuint (u, ==, 22); */ + g_object_unref (obj); g_object_unref (settings); } @@ -1472,6 +1499,14 @@ bool_to_string (const GValue *value, return g_variant_new_string ("false"); } +static GVariant * +bool_to_bool (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + return g_variant_new_boolean (g_value_get_boolean (value)); +} + /* Test custom bindings. * Translate strings to booleans and back */ @@ -1508,6 +1543,17 @@ test_custom_binding (void) g_assert_cmpstr (s, ==, "true"); g_free (s); + g_settings_bind_with_mapping (settings, "string", + obj, "bool", + G_SETTINGS_BIND_DEFAULT, + string_to_bool, bool_to_bool, + NULL, NULL); + g_test_expect_message (G_LOG_DOMAIN, G_LOG_LEVEL_CRITICAL, + "*binding mapping function for key 'string' returned" + " GVariant of type 'b' when type 's' was requested*"); + g_object_set (obj, "bool", FALSE, NULL); + g_test_assert_expected_messages (); + g_object_unref (obj); g_object_unref (settings); } diff --git a/gio/tests/gsubprocess.c b/gio/tests/gsubprocess.c index f617bc599..ac7051d6d 100644 --- a/gio/tests/gsubprocess.c +++ b/gio/tests/gsubprocess.c @@ -849,167 +849,6 @@ test_communicate (gconstpointer test_data) g_object_unref (proc); } -typedef struct { - GSubprocess *proc; - GCancellable *cancellable; - gboolean is_utf8; - gboolean running; - GError *error; -} TestCancelledCommunicateData; - -static gboolean -on_test_communicate_cancelled_idle (gpointer user_data) -{ - TestCancelledCommunicateData *data = user_data; - GBytes *input; - const gchar *hellostring; - GBytes *stdout_bytes = NULL, *stderr_bytes = NULL; - gchar *stdout_buf = NULL, *stderr_buf = NULL; - - /* Include a leading hash and trailing newline so that if this gets onto the - * test’s stdout, it doesn’t mess up TAP output. */ - hellostring = "# hello world\n"; - input = g_bytes_new_static (hellostring, strlen (hellostring)); - - if (data->is_utf8) - g_subprocess_communicate_utf8 (data->proc, hellostring, data->cancellable, - &stdout_buf, &stderr_buf, &data->error); - else - g_subprocess_communicate (data->proc, input, data->cancellable, &stdout_bytes, - &stderr_bytes, &data->error); - - data->running = FALSE; - - if (data->is_utf8) - { - g_assert_null (stdout_buf); - g_assert_null (stderr_buf); - } - else - { - g_assert_null (stdout_bytes); - g_assert_null (stderr_bytes); - } - - g_bytes_unref (input); - - return G_SOURCE_REMOVE; -} - -/* Test g_subprocess_communicate() can be cancelled correctly */ -static void -test_communicate_cancelled (gconstpointer test_data) -{ - GSubprocessFlags flags = GPOINTER_TO_INT (test_data); - GPtrArray *args; - GSubprocess *proc; - GCancellable *cancellable = NULL; - GError *error = NULL; - TestCancelledCommunicateData data = { 0 }; - - args = get_test_subprocess_args ("cat", NULL); - proc = g_subprocess_newv ((const gchar* const*)args->pdata, - G_SUBPROCESS_FLAGS_STDIN_PIPE | flags, - &error); - g_assert_no_error (error); - g_ptr_array_free (args, TRUE); - - cancellable = g_cancellable_new (); - - data.proc = proc; - data.cancellable = cancellable; - data.error = error; - - g_cancellable_cancel (cancellable); - g_idle_add (on_test_communicate_cancelled_idle, &data); - - data.running = TRUE; - while (data.running) - g_main_context_iteration (NULL, TRUE); - - g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&data.error); - - g_object_unref (cancellable); - g_object_unref (proc); -} - -static void -on_communicate_cancelled_complete (GObject *proc, - GAsyncResult *result, - gpointer user_data) -{ - TestAsyncCommunicateData *data = user_data; - GBytes *stdout_bytes = NULL, *stderr_bytes = NULL; - char *stdout_str = NULL, *stderr_str = NULL; - - data->running = FALSE; - if (data->is_utf8) - (void) g_subprocess_communicate_utf8_finish ((GSubprocess*)proc, result, - &stdout_str, &stderr_str, &data->error); - else - (void) g_subprocess_communicate_finish ((GSubprocess*)proc, result, - &stdout_bytes, &stderr_bytes, &data->error); - - if (data->is_utf8) - { - g_assert_null (stdout_str); - g_assert_null (stderr_str); - } - else - { - g_assert_null (stdout_bytes); - g_assert_null (stderr_bytes); - } -} - -/* Test g_subprocess_communicate_async() can be cancelled correctly, - * as passed in via @test_data. */ -static void -test_communicate_cancelled_async (gconstpointer test_data) -{ - GSubprocessFlags flags = GPOINTER_TO_INT (test_data); - GError *error = NULL; - GPtrArray *args; - TestAsyncCommunicateData data = { 0 }; - GSubprocess *proc; - GCancellable *cancellable = NULL; - GBytes *input; - const char *hellostring; - - args = get_test_subprocess_args ("cat", NULL); - proc = g_subprocess_newv ((const gchar* const*)args->pdata, - G_SUBPROCESS_FLAGS_STDIN_PIPE | flags, - &error); - g_assert_no_error (error); - g_ptr_array_free (args, TRUE); - - /* Include a leading hash and trailing newline so that if this gets onto the - * test’s stdout, it doesn’t mess up TAP output. */ - hellostring = "# hello world\n"; - input = g_bytes_new_static (hellostring, strlen (hellostring)); - - cancellable = g_cancellable_new (); - - g_subprocess_communicate_async (proc, input, - cancellable, - on_communicate_cancelled_complete, - &data); - - g_cancellable_cancel (cancellable); - - data.running = TRUE; - while (data.running) - g_main_context_iteration (NULL, TRUE); - - g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&data.error); - - g_bytes_unref (input); - g_object_unref (cancellable); - g_object_unref (proc); -} - /* Test g_subprocess_communicate_utf8_async() works correctly with a variety of * flags, as passed in via @test_data. */ static void @@ -1044,44 +883,6 @@ test_communicate_utf8_async (gconstpointer test_data) g_object_unref (proc); } -/* Test g_subprocess_communicate_utf8_async() can be cancelled correclty. */ -static void -test_communicate_utf8_cancelled_async (gconstpointer test_data) -{ - GSubprocessFlags flags = GPOINTER_TO_INT (test_data); - GError *error = NULL; - GPtrArray *args; - TestAsyncCommunicateData data = { flags, 0, }; - GSubprocess *proc; - GCancellable *cancellable = NULL; - - args = get_test_subprocess_args ("cat", NULL); - proc = g_subprocess_newv ((const gchar* const*)args->pdata, - G_SUBPROCESS_FLAGS_STDIN_PIPE | flags, - &error); - g_assert_no_error (error); - g_ptr_array_free (args, TRUE); - - cancellable = g_cancellable_new (); - data.is_utf8 = TRUE; - g_subprocess_communicate_utf8_async (proc, "# hello world\n", - cancellable, - on_communicate_cancelled_complete, - &data); - - g_cancellable_cancel (cancellable); - - data.running = TRUE; - while (data.running) - g_main_context_iteration (NULL, TRUE); - - g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&data.error); - - g_object_unref (cancellable); - g_object_unref (proc); -} - /* Test g_subprocess_communicate_utf8() works correctly with a variety of flags, * as passed in via @test_data. */ static void @@ -1122,45 +923,6 @@ test_communicate_utf8 (gconstpointer test_data) g_object_unref (proc); } -/* Test g_subprocess_communicate_utf8() can be cancelled correctly */ -static void -test_communicate_utf8_cancelled (gconstpointer test_data) -{ - GSubprocessFlags flags = GPOINTER_TO_INT (test_data); - GPtrArray *args; - GSubprocess *proc; - GCancellable *cancellable = NULL; - GError *error = NULL; - TestCancelledCommunicateData data = { 0 }; - - args = get_test_subprocess_args ("cat", NULL); - proc = g_subprocess_newv ((const gchar* const*)args->pdata, - G_SUBPROCESS_FLAGS_STDIN_PIPE | flags, - &error); - g_assert_no_error (error); - g_ptr_array_free (args, TRUE); - - cancellable = g_cancellable_new (); - - data.proc = proc; - data.cancellable = cancellable; - data.error = error; - - g_cancellable_cancel (cancellable); - g_idle_add (on_test_communicate_cancelled_idle, &data); - - data.is_utf8 = TRUE; - data.running = TRUE; - while (data.running) - g_main_context_iteration (NULL, TRUE); - - g_assert_error (data.error, G_IO_ERROR, G_IO_ERROR_CANCELLED); - g_clear_error (&data.error); - - g_object_unref (cancellable); - g_object_unref (proc); -} - static void test_communicate_nothing (void) { @@ -1747,40 +1509,20 @@ main (int argc, char **argv) test_communicate); g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/cancelled%s", flags_vectors[i].subtest); - g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), - test_communicate_cancelled); - g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/async%s", flags_vectors[i].subtest); g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), test_communicate_async); g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/async/cancelled%s", flags_vectors[i].subtest); - g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), - test_communicate_cancelled_async); - g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/utf8%s", flags_vectors[i].subtest); g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), test_communicate_utf8); g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/cancelled%s", flags_vectors[i].subtest); - g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), - test_communicate_utf8_cancelled); - g_free (test_path); - test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async%s", flags_vectors[i].subtest); g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), test_communicate_utf8_async); g_free (test_path); - - test_path = g_strdup_printf ("/gsubprocess/communicate/utf8/async/cancelled%s", flags_vectors[i].subtest); - g_test_add_data_func (test_path, GINT_TO_POINTER (flags_vectors[i].flags), - test_communicate_utf8_cancelled_async); - g_free (test_path); } g_test_add_func ("/gsubprocess/communicate/utf8/invalid", test_communicate_utf8_invalid); diff --git a/gio/tests/meson.build b/gio/tests/meson.build index fb4ffcf7d..96229bd8b 100644 --- a/gio/tests/meson.build +++ b/gio/tests/meson.build @@ -3,7 +3,6 @@ common_gio_tests_deps = [ libgmodule_dep, libgobject_dep, libgio_dep, - libintl ] subdir('gdbus-object-manager-example') @@ -296,7 +295,7 @@ foreach test_name : gio_tests install : false, c_args : test_c_args, dependencies : common_gio_tests_deps + extra_deps) - if test_name == 'testfilemonitor' or test_name == 'network-monitor-race' + if test_name == 'testfilemonitor' test(test_name, exe, env : test_env, timeout : 45) else test(test_name, exe, env : test_env) diff --git a/gio/tests/network-address.c b/gio/tests/network-address.c index da1b92413..1a7f8e797 100644 --- a/gio/tests/network-address.c +++ b/gio/tests/network-address.c @@ -149,6 +149,8 @@ test_resolve_address (gconstpointer d) GSocketAddress *addr; GError *error = NULL; + g_test_message ("Input: %s", test->input); + g_assert_cmpint (test->valid_ip, ==, g_hostname_is_ip_address (test->input)); connectable = g_network_address_parse (test->input, 1234, &error); @@ -187,6 +189,8 @@ test_resolve_address_gresolver (gconstpointer d) GInetAddress *iaddr; GError *error = NULL; + g_test_message ("Input: %s", test->input); + resolver = g_resolver_get_default (); addrs = g_resolver_lookup_by_name (resolver, test->input, NULL, &error); g_object_unref (resolver); @@ -204,6 +208,8 @@ test_resolve_address_gresolver (gconstpointer d) } else { + g_assert_nonnull (error); + g_test_message ("Error: %s", error->message); g_assert_false (test->valid_resolve); if (!test->valid_parse) diff --git a/gio/tests/network-monitor-race.c b/gio/tests/network-monitor-race.c index 4b92c87a5..cadd62cee 100644 --- a/gio/tests/network-monitor-race.c +++ b/gio/tests/network-monitor-race.c @@ -18,7 +18,7 @@ #include <glib/glib.h> #include <gio/gio.h> -#define MAX_RUNS 333 +#define MAX_RUNS 20 static gboolean quit_loop (gpointer user_data) diff --git a/gio/tests/org.gtk.test.gschema.xml.orig b/gio/tests/org.gtk.test.gschema.xml.orig index c07558335..3c9d7b779 100644 --- a/gio/tests/org.gtk.test.gschema.xml.orig +++ b/gio/tests/org.gtk.test.gschema.xml.orig @@ -131,6 +131,10 @@ <key name="flags" flags="org.gtk.test.TestFlags"> <default>['mourning', 'laughing']</default> </key> + <key name="range" type='u'> + <default>33</default> + <range min="2" max="44"/> + </key> </schema> <schema id='org.gtk.test.enums' path='/tests/enums/'> diff --git a/gio/tests/pollable.c b/gio/tests/pollable.c index c61525d09..826eaecad 100644 --- a/gio/tests/pollable.c +++ b/gio/tests/pollable.c @@ -61,7 +61,7 @@ check_source_readability_callback (gpointer user_data) static gboolean write_callback (gpointer user_data) { - char *buf = "x"; + const char *buf = "x"; gssize nwrote; GError *error = NULL; diff --git a/gio/tests/send-data.c b/gio/tests/send-data.c index a30bdca56..514442976 100644 --- a/gio/tests/send-data.c +++ b/gio/tests/send-data.c @@ -170,7 +170,7 @@ main (int argc, char *argv[]) if (!g_output_stream_write_all (out, buffer, strlen (buffer), NULL, cancellable, &error)) { - g_warning ("send error: %s\n", error->message); + g_warning ("send error: %s", error->message); g_error_free (error); error = NULL; } @@ -187,7 +187,7 @@ main (int argc, char *argv[]) res, &error)) { g_object_unref (res); - g_warning ("close error: %s\n", error->message); + g_warning ("close error: %s", error->message); return 1; } g_object_unref (res); @@ -196,7 +196,7 @@ main (int argc, char *argv[]) { if (!g_io_stream_close (G_IO_STREAM (connection), cancellable, &error)) { - g_warning ("close error: %s\n", error->message); + g_warning ("close error: %s", error->message); return 1; } } diff --git a/gio/tests/simple-proxy.c b/gio/tests/simple-proxy.c index 00bdb2ea4..f1eb6af9b 100644 --- a/gio/tests/simple-proxy.c +++ b/gio/tests/simple-proxy.c @@ -32,7 +32,7 @@ static void test_uris (void) { GProxyResolver *resolver; - gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; + const gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; gchar **proxies; GError *error = NULL; const gchar *uri; @@ -41,7 +41,7 @@ test_uris (void) /* Valid URI. */ uri = "http://%E0%B4%A8%E0%B4%B2:80/"; - resolver = g_simple_proxy_resolver_new (NULL, ignore_hosts); + resolver = g_simple_proxy_resolver_new (NULL, (char **) ignore_hosts); proxies = g_proxy_resolver_lookup (resolver, uri, NULL, &error); g_assert_no_error (error); @@ -60,7 +60,7 @@ test_uris (void) /* Invalid URI. */ uri = "%E0%B4%A8%E0%B4%B2"; str = g_strdup_printf ("Invalid URI ‘%s’", uri); - resolver = g_simple_proxy_resolver_new (NULL, ignore_hosts); + resolver = g_simple_proxy_resolver_new (NULL, (char **) ignore_hosts); proxies = g_proxy_resolver_lookup (resolver, uri, NULL, &error); g_assert_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT); @@ -81,7 +81,7 @@ test_uris (void) g_object_unref (resolver); g_free (str); - resolver = g_simple_proxy_resolver_new ("default://", ignore_hosts); + resolver = g_simple_proxy_resolver_new ("default://", (char **) ignore_hosts); g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), "http", "http://proxy.example.com"); g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), @@ -136,11 +136,11 @@ static void test_socks (void) { GProxyResolver *resolver; - gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; + const gchar *ignore_hosts[2] = { "127.0.0.1", NULL }; gchar **proxies; GError *error = NULL; - resolver = g_simple_proxy_resolver_new ("socks://proxy.example.com", ignore_hosts); + resolver = g_simple_proxy_resolver_new ("socks://proxy.example.com", (char **) ignore_hosts); proxies = g_proxy_resolver_lookup (resolver, "http://one.example.com/", NULL, &error); @@ -160,7 +160,7 @@ test_socks (void) g_object_unref (resolver); - resolver = g_simple_proxy_resolver_new ("default-proxy://", ignore_hosts); + resolver = g_simple_proxy_resolver_new ("default-proxy://", (char **) ignore_hosts); g_simple_proxy_resolver_set_uri_proxy (G_SIMPLE_PROXY_RESOLVER (resolver), "http", "socks://proxy.example.com"); diff --git a/gio/tests/socket-client.c b/gio/tests/socket-client.c index 62dda8991..803f4d6e9 100644 --- a/gio/tests/socket-client.c +++ b/gio/tests/socket-client.c @@ -173,7 +173,7 @@ make_connection (const char *argument, if (g_socket_connect (*socket, *address, cancellable, &err)) break; - g_message ("Connection to %s failed: %s, trying next\n", socket_address_to_string (*address), err->message); + g_message ("Connection to %s failed: %s, trying next", socket_address_to_string (*address), err->message); g_clear_error (&err); g_object_unref (*address); diff --git a/gio/tests/unix-mounts.c b/gio/tests/unix-mounts.c index 67b8c8d98..3d54047dc 100644 --- a/gio/tests/unix-mounts.c +++ b/gio/tests/unix-mounts.c @@ -33,12 +33,6 @@ test_is_system_fs_type (void) { g_assert_true (g_unix_is_system_fs_type ("tmpfs")); g_assert_false (g_unix_is_system_fs_type ("ext4")); - - /* Check that some common network file systems aren’t considered ‘system’. */ - g_assert_false (g_unix_is_system_fs_type ("cifs")); - g_assert_false (g_unix_is_system_fs_type ("nfs")); - g_assert_false (g_unix_is_system_fs_type ("nfs4")); - g_assert_false (g_unix_is_system_fs_type ("smbfs")); } static void diff --git a/gio/xdgmime/xdgmime.c b/gio/xdgmime/xdgmime.c index 95adf7ee0..12028927d 100644 --- a/gio/xdgmime/xdgmime.c +++ b/gio/xdgmime/xdgmime.c @@ -60,6 +60,8 @@ XdgMimeCache **_caches = NULL; static int n_caches = 0; const char xdg_mime_type_unknown[] = "application/octet-stream"; +const char xdg_mime_type_empty[] = "application/x-zerosize"; +const char xdg_mime_type_textplain[] = "text/plain"; enum @@ -463,17 +465,23 @@ xdg_mime_get_mime_type_for_data (const void *data, { const char *mime_type; + if (len == 0) + { + *result_prio = 100; + return XDG_MIME_TYPE_EMPTY; + } + xdg_mime_init (); if (_caches) - return _xdg_mime_cache_get_mime_type_for_data (data, len, result_prio); - - mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, result_prio, NULL, 0); + mime_type = _xdg_mime_cache_get_mime_type_for_data (data, len, result_prio); + else + mime_type = _xdg_mime_magic_lookup_data (global_magic, data, len, result_prio, NULL, 0); if (mime_type) return mime_type; - return XDG_MIME_TYPE_UNKNOWN; + return _xdg_binary_or_text_fallback(data, len); } #ifdef NOT_USED_IN_GIO @@ -554,7 +562,7 @@ xdg_mime_get_mime_type_for_file (const char *file_name, if (mime_type) return mime_type; - return XDG_MIME_TYPE_UNKNOWN; + return _xdg_binary_or_text_fallback(data, bytes_read); } const char * diff --git a/gio/xdgmime/xdgmime.h b/gio/xdgmime/xdgmime.h index d30106245..cd20c77a9 100644 --- a/gio/xdgmime/xdgmime.h +++ b/gio/xdgmime/xdgmime.h @@ -66,6 +66,8 @@ typedef void (*XdgMimeDestroy) (void *user_data); #define xdg_mime_register_reload_callback XDG_ENTRY(register_reload_callback) #define xdg_mime_remove_callback XDG_ENTRY(remove_callback) #define xdg_mime_type_unknown XDG_ENTRY(type_unknown) +#define xdg_mime_type_empty XDG_ENTRY(type_empty) +#define xdg_mime_type_textplain XDG_ENTRY(type_textplain) #define xdg_mime_get_icon XDG_ENTRY(get_icon) #define xdg_mime_get_generic_icon XDG_ENTRY(get_generic_icon) @@ -75,7 +77,11 @@ typedef void (*XdgMimeDestroy) (void *user_data); #endif extern const char xdg_mime_type_unknown[]; +extern const char xdg_mime_type_empty[]; +extern const char xdg_mime_type_textplain[]; #define XDG_MIME_TYPE_UNKNOWN xdg_mime_type_unknown +#define XDG_MIME_TYPE_EMPTY xdg_mime_type_empty +#define XDG_MIME_TYPE_TEXTPLAIN xdg_mime_type_textplain const char *xdg_mime_get_mime_type_for_data (const void *data, size_t len, diff --git a/gio/xdgmime/xdgmimecache.c b/gio/xdgmime/xdgmimecache.c index eab6119b6..8010f9e5b 100644 --- a/gio/xdgmime/xdgmimecache.c +++ b/gio/xdgmime/xdgmimecache.c @@ -760,12 +760,11 @@ cache_get_mime_type_for_data (const void *data, for (n = 0; n < n_mime_types; n++) { - if (mime_types[n]) return mime_types[n]; } - return XDG_MIME_TYPE_UNKNOWN; + return NULL; } const char * @@ -812,6 +811,9 @@ _xdg_mime_cache_get_mime_type_for_file (const char *file_name, statbuf = &buf; } + if (statbuf->st_size == 0) + return XDG_MIME_TYPE_EMPTY; + if (!S_ISREG (statbuf->st_mode)) return XDG_MIME_TYPE_UNKNOWN; @@ -841,6 +843,9 @@ _xdg_mime_cache_get_mime_type_for_file (const char *file_name, mime_type = cache_get_mime_type_for_data (data, bytes_read, NULL, mime_types, n); + if (!mime_type) + mime_type = _xdg_binary_or_text_fallback(data, bytes_read); + free (data); fclose (file); diff --git a/gio/xdgmime/xdgmimeint.c b/gio/xdgmime/xdgmimeint.c index d56bb8340..35c3635e2 100644 --- a/gio/xdgmime/xdgmimeint.c +++ b/gio/xdgmime/xdgmimeint.c @@ -185,3 +185,18 @@ _xdg_reverse_ucs4 (xdg_unichar_t *source, int len) } } +const char * +_xdg_binary_or_text_fallback(const void *data, size_t len) +{ + unsigned char *chardata; + int i; + + chardata = (unsigned char *) data; + for (i = 0; i < 128 && i < len; ++i) + { + if (chardata[i] < 32 && chardata[i] != 9 && chardata[i] != 10 && chardata[i] != 13) + return XDG_MIME_TYPE_UNKNOWN; /* binary data */ + } + + return XDG_MIME_TYPE_TEXTPLAIN; +} diff --git a/gio/xdgmime/xdgmimeint.h b/gio/xdgmime/xdgmimeint.h index 8acd8d5cd..c9270139e 100644 --- a/gio/xdgmime/xdgmimeint.h +++ b/gio/xdgmime/xdgmimeint.h @@ -71,5 +71,6 @@ int _xdg_utf8_validate (const char *source); xdg_unichar_t *_xdg_convert_to_ucs4 (const char *source, int *len); void _xdg_reverse_ucs4 (xdg_unichar_t *source, int len); const char *_xdg_get_base_name (const char *file_name); +const char *_xdg_binary_or_text_fallback(const void *data, size_t len); #endif /* __XDG_MIME_INT_H__ */ |