summaryrefslogtreecommitdiff
path: root/gio
diff options
context:
space:
mode:
Diffstat (limited to 'gio')
-rw-r--r--gio/Makefile.am24
-rw-r--r--gio/completion/gsettings4
-rwxr-xr-xgio/data-to-c.pl37
-rwxr-xr-x[-rw-r--r--]gio/data-to-c.py2
-rw-r--r--gio/gappinfo.c30
-rw-r--r--gio/gappinfo.h12
-rw-r--r--gio/gapplication.c7
-rw-r--r--gio/gapplicationcommandline.c12
-rw-r--r--gio/gasynchelper.c4
-rw-r--r--gio/gasyncresult.c21
-rw-r--r--gio/gbufferedinputstream.c2
-rw-r--r--gio/gcancellable.c16
-rw-r--r--gio/gdbus-2.0/codegen/Makefile.am2
-rwxr-xr-x[-rw-r--r--]gio/gdbus-2.0/codegen/gdbus-codegen.in14
-rw-r--r--gio/gdbus-2.0/codegen/meson.build22
-rw-r--r--gio/gdbus-tool.c253
-rw-r--r--gio/gdbusaddress.c6
-rw-r--r--gio/gdbusauth.c9
-rw-r--r--gio/gdbusauthmechanismsha1.c10
-rw-r--r--gio/gdbusconnection.c16
-rw-r--r--gio/gdbuserror.c2
-rw-r--r--gio/gdbusinterfaceskeleton.c2
-rw-r--r--gio/gdbusmessage.c14
-rw-r--r--gio/gdbusnamewatching.h2
-rw-r--r--gio/gdbusobjectmanagerclient.c18
-rw-r--r--gio/gdesktopappinfo.c80
-rw-r--r--gio/gdtlsconnection.c4
-rw-r--r--gio/gfile.c236
-rw-r--r--gio/gfile.h19
-rw-r--r--gio/gfileenumerator.c2
-rw-r--r--gio/gioenums.h2
-rw-r--r--gio/giomodule.c4
-rw-r--r--gio/giotypes.h12
-rw-r--r--gio/glib-compile-resources.c8
-rw-r--r--gio/glib-compile-schemas.c4
-rw-r--r--gio/glistmodel.c18
-rw-r--r--gio/glocalfile.c56
-rw-r--r--gio/glocalfileinfo.c121
-rw-r--r--gio/glocalfileinfo.h5
-rw-r--r--gio/glocalfileoutputstream.c8
-rw-r--r--gio/gmount.c9
-rw-r--r--gio/gopenuriportal.c4
-rw-r--r--gio/gosxappinfo.c38
-rw-r--r--gio/gosxcontenttype.c103
-rw-r--r--gio/goutputstream.c10
-rw-r--r--gio/gpollfilemonitor.c3
-rw-r--r--gio/gresource.c54
-rw-r--r--gio/gresourcefile.c125
-rw-r--r--gio/gschema.dtd5
-rw-r--r--gio/gseekable.c12
-rw-r--r--gio/gsettings.c8
-rw-r--r--gio/gsettingsbackend.c4
-rw-r--r--gio/gsettingsschema.c17
-rw-r--r--gio/gsimpleasyncresult.c7
-rw-r--r--gio/gsocket.c483
-rw-r--r--gio/gsocket.h12
-rw-r--r--gio/gsocketlistener.h2
-rw-r--r--gio/gsubprocess.c2
-rw-r--r--gio/gsubprocesslauncher.c20
-rw-r--r--gio/gtask.c23
-rw-r--r--gio/gthreadedresolver.c4
-rw-r--r--gio/gtlsbackend.c30
-rw-r--r--gio/gtlsdatabase.c4
-rw-r--r--gio/gtlspassword.c4
-rw-r--r--gio/gunixmounts.c147
-rw-r--r--gio/gunixmounts.h6
-rw-r--r--gio/gvolume.c2
-rw-r--r--gio/gvolumemonitor.c5
-rw-r--r--gio/inotify/inotify-helper.c16
-rw-r--r--gio/inotify/inotify-path.c5
-rw-r--r--gio/kqueue/kqueue-helper.c4
-rw-r--r--gio/meson.build14
-rw-r--r--gio/tests/Makefile.am28
-rw-r--r--gio/tests/appinfo.c83
-rw-r--r--gio/tests/contenttype.c75
-rw-r--r--gio/tests/dbus-launch.c2
-rw-r--r--gio/tests/desktop-files/home/applications/epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop2
-rw-r--r--gio/tests/file.c120
-rw-r--r--gio/tests/g-file-info-filesystem-readonly.c176
-rw-r--r--gio/tests/g-file-info.c367
-rw-r--r--gio/tests/gdbus-proxy.c24
-rw-r--r--gio/tests/gmenumodel.c48
-rw-r--r--gio/tests/gschema-compile.c1
-rw-r--r--gio/tests/httpd.c15
-rw-r--r--gio/tests/meson.build3
-rw-r--r--gio/tests/resources.c101
-rw-r--r--gio/tests/schema-tests/enum-with-invalid-value.gschema.xml10
-rw-r--r--gio/tests/socket.c48
-rw-r--r--gio/tests/unix-mounts.c57
89 files changed, 2626 insertions, 836 deletions
diff --git a/gio/Makefile.am b/gio/Makefile.am
index b2db99581..0cfda50bf 100644
--- a/gio/Makefile.am
+++ b/gio/Makefile.am
@@ -3,10 +3,8 @@ include $(top_srcdir)/glib.mk
SUBDIRS = gdbus-2.0/codegen
if OS_UNIX
-if !OS_COCOA
SUBDIRS += xdgmime
endif
-endif
if OS_WIN32_AND_DLL_COMPILATION
if MS_LIB_AVAILABLE
@@ -92,7 +90,18 @@ gdbus_sources = \
# These are not built into the library yet
EXTRA_DIST += gdbusdaemon.c gdbusdaemon.h dbus-daemon.xml
-gdbus-daemon-generated.h gdbus-daemon-generated.c: $(srcdir)/dbus-daemon.xml $(srcdir)/gdbus-2.0/codegen/gdbus-codegen.in
+GDBUS_PYTHON_DEPS = \
+ $(srcdir)/gdbus-2.0/codegen/gdbus-codegen.in \
+ $(srcdir)/gdbus-2.0/codegen/codegen_main.py \
+ $(srcdir)/gdbus-2.0/codegen/parser.py \
+ $(srcdir)/gdbus-2.0/codegen/codegen_docbook.py \
+ $(srcdir)/gdbus-2.0/codegen/codegen.py \
+ $(srcdir)/gdbus-2.0/codegen/__init__.py \
+ $(srcdir)/gdbus-2.0/codegen/dbustypes.py \
+ $(builddir)/gdbus-2.0/codegen/config.py \
+ $(srcdir)/gdbus-2.0/codegen/utils.py
+
+gdbus-daemon-generated.h gdbus-daemon-generated.c: $(srcdir)/dbus-daemon.xml $(GDBUS_PYTHON_DEPS)
$(AM_V_GEN) UNINSTALLED_GLIB_SRCDIR=$(top_srcdir) \
UNINSTALLED_GLIB_BUILDDIR=$(top_builddir) \
$(PYTHON) $(srcdir)/gdbus-2.0/codegen/gdbus-codegen.in \
@@ -251,10 +260,9 @@ SUBDIRS += fam
endif
if OS_UNIX
-if !OS_COCOA
platform_libadd += xdgmime/libxdgmime.la
platform_deps += xdgmime/libxdgmime.la
-
+if !OS_COCOA
appinfo_headers += gdesktopappinfo.h
endif
@@ -754,7 +762,7 @@ BUILT_SOURCES += \
$(NULL)
EXTRA_DIST += \
- data-to-c.pl \
+ data-to-c.py \
gioenumtypes.h.template \
gioenumtypes.c.template \
gio.rc.in \
@@ -814,8 +822,8 @@ gio_querymodules_LDADD = libgio-2.0.la \
$(top_builddir)/glib/libglib-2.0.la \
$(NULL)
-gconstructor_as_data.h: $(top_srcdir)/glib/gconstructor.h data-to-c.pl
- $(AM_V_GEN) $(srcdir)/data-to-c.pl $(top_srcdir)/glib/gconstructor.h gconstructor_code > $@.tmp && mv $@.tmp $@
+gconstructor_as_data.h: $(top_srcdir)/glib/gconstructor.h data-to-c.py
+ $(AM_V_GEN) $(srcdir)/data-to-c.py $(top_srcdir)/glib/gconstructor.h gconstructor_code $@
glib_compile_schemas_LDADD = $(top_builddir)/glib/libglib-2.0.la
glib_compile_schemas_SOURCES = \
diff --git a/gio/completion/gsettings b/gio/completion/gsettings
index 0316e299f..22b2ac379 100644
--- a/gio/completion/gsettings
+++ b/gio/completion/gsettings
@@ -35,11 +35,11 @@ __gsettings() {
choices=$'list-schemas\nlist-relocatable-schemas\nlist-keys\nlist-children\nlist-recursively\nget\nrange\nset\nreset\nreset-recursively\nwritable\nmonitor'
;;
list-keys|list-children|list-recursively|reset-recursively)
- choices="$(gsettings $schemadir list-schemas)"$'\n'"$(gsettings $schemadir list-relocatable-schemas | sed -e 's.$.:/.')"
+ choices="$(gsettings $schemadir list-schemas 2> /dev/null)"$'\n'"$(gsettings $schemadir list-relocatable-schemas 2> /dev/null | sed -e 's.$.:/.')"
;;
get|range|set|reset|writable|monitor|describe)
- choices="$(gsettings $schemadir list-schemas | sed -e 's.$. .')"$'\n'"$(gsettings $schemadir list-relocatable-schemas | sed -e 's.$.:/.')"
+ choices="$(gsettings $schemadir list-schemas 2> /dev/null | sed -e 's.$. .')"$'\n'"$(gsettings $schemadir list-relocatable-schemas 2> /dev/null | sed -e 's.$.:/.')"
;;
esac
;;
diff --git a/gio/data-to-c.pl b/gio/data-to-c.pl
deleted file mode 100755
index 28c1d71e6..000000000
--- a/gio/data-to-c.pl
+++ /dev/null
@@ -1,37 +0,0 @@
-#!/usr/bin/env perl
-
-# Copyright © 2011 Red Hat, 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/>.
-#
-# Author: Kalev Lember <kalevlember@gmail.com>
-
-
-if (@ARGV != 2) {
- die "Usage: data-to-c.pl <filename> <variable>\n";
-}
-
-$file = $ARGV[0];
-
-open (FILE, $file) || die "Cannot open $file: $!\n";
-
-printf ("const char %s[] = \"", $ARGV[1]);
-while (my $line = <FILE>) {
- foreach my $c (split //, $line) {
- printf ("\\x%02x", ord ($c));
- }
-}
-print "\";\n";
-
-close (FILE);
diff --git a/gio/data-to-c.py b/gio/data-to-c.py
index 7a8d8a865..f226220ed 100644..100755
--- a/gio/data-to-c.py
+++ b/gio/data-to-c.py
@@ -1,4 +1,4 @@
-#!/usr/bin/env python3
+#!/usr/bin/env python
import sys
diff --git a/gio/gappinfo.c b/gio/gappinfo.c
index b0c03dda8..646b8ef2e 100644
--- a/gio/gappinfo.c
+++ b/gio/gappinfo.c
@@ -136,9 +136,9 @@ g_app_info_dup (GAppInfo *appinfo)
*
* Checks if two #GAppInfos are equal.
*
- * Note that the check <em>may not</em> compare each individual field, and
- * only does an identity check. In case detecting changes in the contents
- * is needed, program code must additionally compare relevant fields.
+ * Note that the check <emphasis>may not</emphasis> compare each individual
+ * field, and only does an identity check. In case detecting changes in the
+ * contents is needed, program code must additionally compare relevant fields.
*
* Returns: %TRUE if @appinfo1 is equal to @appinfo2. %FALSE otherwise.
**/
@@ -536,11 +536,11 @@ g_app_info_get_icon (GAppInfo *appinfo)
* g_app_info_launch:
* @appinfo: a #GAppInfo
* @files: (nullable) (element-type GFile): a #GList of #GFile objects
- * @launch_context: (nullable): a #GAppLaunchContext or %NULL
+ * @context: (nullable): a #GAppLaunchContext or %NULL
* @error: a #GError
*
* Launches the application. Passes @files to the launched application
- * as arguments, using the optional @launch_context to get information
+ * as arguments, using the optional @context to get information
* about the details of the launcher (like what screen it is on).
* On error, @error will be set accordingly.
*
@@ -565,7 +565,7 @@ g_app_info_get_icon (GAppInfo *appinfo)
* process. This can be used to ignore `GIO_LAUNCHED_DESKTOP_FILE`,
* should it be inherited by further processes. The `DISPLAY` and
* `DESKTOP_STARTUP_ID` environment variables are also set, based
- * on information provided in @launch_context.
+ * on information provided in @context.
*
* Returns: %TRUE on successful launch, %FALSE otherwise.
**/
@@ -631,11 +631,11 @@ g_app_info_supports_files (GAppInfo *appinfo)
* g_app_info_launch_uris:
* @appinfo: a #GAppInfo
* @uris: (nullable) (element-type utf8): a #GList containing URIs to launch.
- * @launch_context: (nullable): a #GAppLaunchContext or %NULL
+ * @context: (nullable): a #GAppLaunchContext or %NULL
* @error: a #GError
*
* Launches the application. This passes the @uris to the launched application
- * as arguments, using the optional @launch_context to get information
+ * as arguments, using the optional @context to get information
* about the details of the launcher (like what screen it is on).
* On error, @error will be set accordingly.
*
@@ -727,7 +727,7 @@ launch_default_for_uri (const char *uri,
/**
* g_app_info_launch_default_for_uri:
* @uri: the uri to show
- * @launch_context: (nullable): an optional #GAppLaunchContext
+ * @context: (nullable): an optional #GAppLaunchContext
* @error: (nullable): return location for an error, or %NULL
*
* Utility function that launches the default application
@@ -768,7 +768,7 @@ g_app_info_launch_default_for_uri (const char *uri,
* g_app_info_launch_default_for_uri_async:
* @uri: the uri to show
* @context: (nullable): an optional #GAppLaunchContext
- * cancellable: (nullable): a #GCancellable
+ * @cancellable: (nullable): a #GCancellable
* @callback: (nullable): a #GASyncReadyCallback to call when the request is done
* @user_data: (nullable): data to pass to @callback
*
@@ -987,8 +987,8 @@ g_app_launch_context_init (GAppLaunchContext *context)
/**
* g_app_launch_context_setenv:
* @context: a #GAppLaunchContext
- * @variable: the environment variable to set
- * @value: the value for to set the variable to.
+ * @variable: (type filename): the environment variable to set
+ * @value: (type filename): the value for to set the variable to.
*
* Arranges for @variable to be set to @value in the child's
* environment when @context is used to launch an application.
@@ -1010,7 +1010,7 @@ g_app_launch_context_setenv (GAppLaunchContext *context,
/**
* g_app_launch_context_unsetenv:
* @context: a #GAppLaunchContext
- * @variable: the environment variable to remove
+ * @variable: (type filename): the environment variable to remove
*
* Arranges for @variable to be unset in the child's environment
* when @context is used to launch an application.
@@ -1037,8 +1037,8 @@ g_app_launch_context_unsetenv (GAppLaunchContext *context,
* This is a %NULL-terminated array of strings, where each string has
* the form `KEY=VALUE`.
*
- * Returns: (array zero-terminated=1) (transfer full): the
- * child's environment
+ * Returns: (array zero-terminated=1) (element-type filename) (transfer full):
+ * the child's environment
*
* Since: 2.32
*/
diff --git a/gio/gappinfo.h b/gio/gappinfo.h
index 18f012689..4889be923 100644
--- a/gio/gappinfo.h
+++ b/gio/gappinfo.h
@@ -99,13 +99,13 @@ struct _GAppInfoIface
GIcon * (* get_icon) (GAppInfo *appinfo);
gboolean (* launch) (GAppInfo *appinfo,
GList *files,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GError **error);
gboolean (* supports_uris) (GAppInfo *appinfo);
gboolean (* supports_files) (GAppInfo *appinfo);
gboolean (* launch_uris) (GAppInfo *appinfo,
GList *uris,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GError **error);
gboolean (* should_show) (GAppInfo *appinfo);
@@ -162,7 +162,7 @@ GIcon * g_app_info_get_icon (GAppInfo *appin
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_launch (GAppInfo *appinfo,
GList *files,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_supports_uris (GAppInfo *appinfo);
@@ -171,7 +171,7 @@ gboolean g_app_info_supports_files (GAppInfo *appin
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_launch_uris (GAppInfo *appinfo,
GList *uris,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_should_show (GAppInfo *appinfo);
@@ -226,12 +226,12 @@ GAppInfo *g_app_info_get_default_for_uri_scheme (const char *uri_scheme);
GLIB_AVAILABLE_IN_ALL
gboolean g_app_info_launch_default_for_uri (const char *uri,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GError **error);
GLIB_AVAILABLE_IN_2_50
void g_app_info_launch_default_for_uri_async (const char *uri,
- GAppLaunchContext *launch_context,
+ GAppLaunchContext *context,
GCancellable *cancellable,
GAsyncReadyCallback callback,
gpointer user_data);
diff --git a/gio/gapplication.c b/gio/gapplication.c
index 0ee6ca6e8..9d880fc1d 100644
--- a/gio/gapplication.c
+++ b/gio/gapplication.c
@@ -2218,7 +2218,8 @@ g_application_open (GApplication *application,
* g_application_run:
* @application: a #GApplication
* @argc: the argc from main() (or 0 if @argv is %NULL)
- * @argv: (array length=argc) (nullable): the argv from main(), or %NULL
+ * @argv: (array length=argc) (element-type filename) (nullable):
+ * the argv from main(), or %NULL
*
* Runs the application.
*
@@ -2624,6 +2625,10 @@ g_application_set_default (GApplication *application)
* calling only the 'shutdown' function before doing so.
*
* The hold count is ignored.
+ * Take care if your code has called g_application_hold() on the application and
+ * is therefore still expecting it to exist.
+ * (Note that you may have called g_application_hold() indirectly, for example
+ * through gtk_application_add_window().)
*
* The result of calling g_application_run() again after it returns is
* unspecified.
diff --git a/gio/gapplicationcommandline.c b/gio/gapplicationcommandline.c
index b3a99e007..d6c5c45fa 100644
--- a/gio/gapplicationcommandline.c
+++ b/gio/gapplicationcommandline.c
@@ -463,8 +463,8 @@ g_application_command_line_class_init (GApplicationCommandLineClass *class)
* The return value is %NULL-terminated and should be freed using
* g_strfreev().
*
- * Returns: (array length=argc) (transfer full): the string array
- * containing the arguments (the argv)
+ * Returns: (array length=argc) (element-type filename) (transfer full)
+ * the string array containing the arguments (the argv)
*
* Since: 2.28
**/
@@ -582,8 +582,8 @@ g_application_command_line_get_cwd (GApplicationCommandLine *cmdline)
* See g_application_command_line_getenv() if you are only interested
* in the value of a single environment variable.
*
- * Returns: (array zero-terminated=1) (transfer none): the environment
- * strings, or %NULL if they were not sent
+ * Returns: (array zero-terminated=1) (element-type filename) (transfer none):
+ * the environment strings, or %NULL if they were not sent
*
* Since: 2.28
**/
@@ -596,7 +596,7 @@ g_application_command_line_get_environ (GApplicationCommandLine *cmdline)
/**
* g_application_command_line_getenv:
* @cmdline: a #GApplicationCommandLine
- * @name: the environment variable to get
+ * @name: (type filename): the environment variable to get
*
* Gets the value of a particular environment variable of the command
* line invocation, as would be returned by g_getenv(). The strings may
@@ -805,7 +805,7 @@ g_application_command_line_get_platform_data (GApplicationCommandLine *cmdline)
/**
* g_application_command_line_create_file_for_arg:
* @cmdline: a #GApplicationCommandLine
- * @arg: an argument from @cmdline
+ * @arg: (type filename): an argument from @cmdline
*
* Creates a #GFile corresponding to a filename that was given as part
* of the invocation of @cmdline.
diff --git a/gio/gasynchelper.c b/gio/gasynchelper.c
index fc2464ace..41bbb2ad5 100644
--- a/gio/gasynchelper.c
+++ b/gio/gasynchelper.c
@@ -44,7 +44,11 @@ _g_win32_overlap_wait_result (HANDLE hfile,
gboolean result = FALSE;
gint num, npoll;
+#if GLIB_SIZEOF_VOID_P == 8
+ pollfd[0].fd = (gint64)overlap->hEvent;
+#else
pollfd[0].fd = (gint)overlap->hEvent;
+#endif
pollfd[0].events = G_IO_IN;
num = 1;
diff --git a/gio/gasyncresult.c b/gio/gasyncresult.c
index fafda9a04..b96f1eeab 100644
--- a/gio/gasyncresult.c
+++ b/gio/gasyncresult.c
@@ -36,13 +36,16 @@
* which are chained together by a #GAsyncReadyCallback. To begin
* an asynchronous operation, provide a #GAsyncReadyCallback to the
* asynchronous function. This callback will be triggered when the
- * operation has completed, and will be passed a #GAsyncResult instance
- * filled with the details of the operation's success or failure, the
- * object the asynchronous function was started for and any error codes
- * returned. The asynchronous callback function is then expected to call
- * the corresponding "_finish()" function, passing the object the
- * function was called for, the #GAsyncResult instance, and (optionally)
- * an @error to grab any error conditions that may have occurred.
+ * operation has completed, and must be run in a later iteration of
+ * the [thread-default main context][g-main-context-push-thread-default]
+ * from where the operation was initiated. It will be passed a
+ * #GAsyncResult instance filled with the details of the operation's
+ * success or failure, the object the asynchronous function was
+ * started for and any error codes returned. The asynchronous callback
+ * function is then expected to call the corresponding "_finish()"
+ * function, passing the object the function was called for, the
+ * #GAsyncResult instance, and (optionally) an @error to grab any
+ * error conditions that may have occurred.
*
* The "_finish()" function for an operation takes the generic result
* (of type #GAsyncResult) and returns the specific result that the
@@ -147,8 +150,8 @@ g_async_result_get_user_data (GAsyncResult *res)
*
* Gets the source object from a #GAsyncResult.
*
- * Returns: (transfer full): a new reference to the source object for the @res,
- * or %NULL if there is none.
+ * Returns: (transfer full) (nullable): a new reference to the source
+ * object for the @res, or %NULL if there is none.
*/
GObject *
g_async_result_get_source_object (GAsyncResult *res)
diff --git a/gio/gbufferedinputstream.c b/gio/gbufferedinputstream.c
index f70ccb080..f5090d064 100644
--- a/gio/gbufferedinputstream.c
+++ b/gio/gbufferedinputstream.c
@@ -524,7 +524,7 @@ g_buffered_input_stream_fill_async (GBufferedInputStream *stream,
*
* Finishes an asynchronous read.
*
- * Returns: a #gssize of the read stream, or %-1 on an error.
+ * Returns: a #gssize of the read stream, or `-1` on an error.
*/
gssize
g_buffered_input_stream_fill_finish (GBufferedInputStream *stream,
diff --git a/gio/gcancellable.c b/gio/gcancellable.c
index dced16e05..d833bcfc0 100644
--- a/gio/gcancellable.c
+++ b/gio/gcancellable.c
@@ -594,7 +594,7 @@ g_cancellable_connect (GCancellable *cancellable,
/**
* g_cancellable_disconnect:
* @cancellable: (nullable): A #GCancellable or %NULL.
- * @handler_id: Handler id of the handler to be disconnected, or %0.
+ * @handler_id: Handler id of the handler to be disconnected, or `0`.
*
* Disconnects a handler from a cancellable instance similar to
* g_signal_handler_disconnect(). Additionally, in the event that a
@@ -608,7 +608,7 @@ g_cancellable_connect (GCancellable *cancellable,
* signal handler is removed. See #GCancellable::cancelled for
* details on how to use this.
*
- * If @cancellable is %NULL or @handler_id is %0 this function does
+ * If @cancellable is %NULL or @handler_id is `0` this function does
* nothing.
*
* Since: 2.22
@@ -644,18 +644,6 @@ typedef struct {
guint cancelled_handler;
} GCancellableSource;
-/*
- * We can't guarantee that the source still has references, so we are
- * relying on the fact that g_source_set_ready_time() no longer makes
- * assertions about the reference count - the source might be in the
- * window between last-unref and finalize, during which its refcount
- * is officially 0. However, we *can* guarantee that it's OK to
- * dereference it in a limited way, because we know we haven't yet reached
- * cancellable_source_finalize() - if we had, then we would have waited
- * for signal emission to finish, then disconnected the signal handler
- * under the lock.
- * See https://bugzilla.gnome.org/show_bug.cgi?id=791754
- */
static void
cancellable_source_cancelled (GCancellable *cancellable,
gpointer user_data)
diff --git a/gio/gdbus-2.0/codegen/Makefile.am b/gio/gdbus-2.0/codegen/Makefile.am
index b3fb2c292..b4e500cb0 100644
--- a/gio/gdbus-2.0/codegen/Makefile.am
+++ b/gio/gdbus-2.0/codegen/Makefile.am
@@ -21,7 +21,7 @@ CLEANFILES += gdbus-codegen
EXTRA_DIST += gdbus-codegen.in
gdbus-codegen: gdbus-codegen.in Makefile $(codegen_PYTHON)
- $(AM_V_GEN) sed -e 's,@datadir\@,$(datadir),' -e 's,@PYTHON\@,$(PYTHON),' $< > $@.tmp && mv $@.tmp $@
+ $(AM_V_GEN) sed -e 's,@DATADIR\@,$(datadir),' -e 's,@PYTHON\@,$(PYTHON),' $< > $@.tmp && mv $@.tmp $@
@chmod a+x $@
clean-local:
diff --git a/gio/gdbus-2.0/codegen/gdbus-codegen.in b/gio/gdbus-2.0/codegen/gdbus-codegen.in
index 805098188..67d367543 100644..100755
--- a/gio/gdbus-2.0/codegen/gdbus-codegen.in
+++ b/gio/gdbus-2.0/codegen/gdbus-codegen.in
@@ -37,7 +37,19 @@ else:
# parent directory to the python path.
path = os.path.join(filedir, '..')
-sys.path.insert(0, os.path.abspath(path))
+# Canonicalize, then do further testing
+path = os.path.abspath(path)
+
+# If the above path detection failed, use the hard-coded datadir. This can
+# happen when, for instance, bindir and datadir are not in the same prefix or
+# on Windows where we cannot make any guarantees about the directory structure.
+#
+# In these cases our installation cannot be relocatable, but at least we should
+# be able to find the codegen module.
+if not os.path.isfile(os.path.join(path, 'codegen', 'codegen_main.py')):
+ path = os.path.join('@DATADIR@', 'glib-2.0')
+
+sys.path.insert(0, path)
from codegen import codegen_main
sys.exit(codegen_main.codegen_main())
diff --git a/gio/gdbus-2.0/codegen/meson.build b/gio/gdbus-2.0/codegen/meson.build
index 0e9ffbdfa..54a86b0d6 100644
--- a/gio/gdbus-2.0/codegen/meson.build
+++ b/gio/gdbus-2.0/codegen/meson.build
@@ -11,9 +11,9 @@ gdbus_codegen_files = [
gdbus_codegen_conf = configuration_data()
gdbus_codegen_conf.set('VERSION', glib_version)
gdbus_codegen_conf.set('PYTHON', python.path())
+gdbus_codegen_conf.set('DATADIR', glib_datadir)
# Install gdbus-codegen executable
-# FIXME: Set permissions
gdbus_codegen = configure_file(input : 'gdbus-codegen.in',
output : 'gdbus-codegen',
install : true,
@@ -23,19 +23,19 @@ gdbus_codegen = configure_file(input : 'gdbus-codegen.in',
codegen_dir = join_paths(get_option('datadir'), 'glib-2.0/codegen')
-configure_file(input : 'config.py.in',
- output : 'config.py',
- install : true,
- install_dir : codegen_dir,
- configuration : gdbus_codegen_conf
-)
+gdbus_codegen_built_files = []
+gdbus_codegen_built_files += configure_file(input : 'config.py.in',
+ output : 'config.py',
+ install : true,
+ install_dir : codegen_dir,
+ configuration : gdbus_codegen_conf)
blank_conf = configuration_data()
foreach f : gdbus_codegen_files
# Copy these into the builddir so that gdbus-codegen can be used uninstalled
# and then install it too so that it can be used after installation
- configure_file(input : f, output : f,
- install : true,
- install_dir : codegen_dir,
- configuration : blank_conf)
+ gdbus_codegen_built_files += configure_file(input : f, output : f,
+ install : true,
+ install_dir : codegen_dir,
+ configuration : blank_conf)
endforeach
diff --git a/gio/gdbus-tool.c b/gio/gdbus-tool.c
index fb285f1db..77863a2a0 100644
--- a/gio/gdbus-tool.c
+++ b/gio/gdbus-tool.c
@@ -137,9 +137,11 @@ modify_argv0_for_command (gint *argc, gchar **argv[], const gchar *command)
/* ---------------------------------------------------------------------------------------------------- */
static void
-print_methods (GDBusConnection *c,
- const gchar *name,
- const gchar *path)
+print_methods_and_signals (GDBusConnection *c,
+ const gchar *name,
+ const gchar *path,
+ gboolean print_methods,
+ gboolean print_signals)
{
GVariant *result;
GError *error;
@@ -181,11 +183,16 @@ print_methods (GDBusConnection *c,
for (n = 0; node->interfaces != NULL && node->interfaces[n] != NULL; n++)
{
const GDBusInterfaceInfo *iface = node->interfaces[n];
- for (m = 0; iface->methods != NULL && iface->methods[m] != NULL; m++)
+ for (m = 0; print_methods && iface->methods != NULL && iface->methods[m] != NULL; m++)
{
const GDBusMethodInfo *method = iface->methods[m];
g_print ("%s.%s \n", iface->name, method->name);
}
+ for (m = 0; print_signals && iface->signals != NULL && iface->signals[m] != NULL; m++)
+ {
+ const GDBusSignalInfo *signal = iface->signals[m];
+ g_print ("%s.%s \n", iface->name, signal->name);
+ }
}
g_dbus_node_info_unref (node);
@@ -302,7 +309,7 @@ print_names (GDBusConnection *c,
}
g_variant_get (result, "(as)", &iter);
while (g_variant_iter_loop (iter, "s", &str))
- g_hash_table_insert (name_set, g_strdup (str), NULL);
+ g_hash_table_add (name_set, g_strdup (str));
g_variant_iter_free (iter);
g_variant_unref (result);
@@ -326,7 +333,7 @@ print_names (GDBusConnection *c,
}
g_variant_get (result, "(as)", &iter);
while (g_variant_iter_loop (iter, "s", &str))
- g_hash_table_insert (name_set, g_strdup (str), NULL);
+ g_hash_table_add (name_set, g_strdup (str));
g_variant_iter_free (iter);
g_variant_unref (result);
@@ -565,6 +572,7 @@ handle_emit (gint *argc,
gboolean skip_dashes;
guint parm;
guint n;
+ gboolean complete_names, complete_paths, complete_signals;
ret = FALSE;
c = NULL;
@@ -580,6 +588,27 @@ handle_emit (gint *argc,
g_option_context_add_main_entries (o, emit_entries, GETTEXT_PACKAGE);
g_option_context_add_group (o, connection_get_group ());
+ complete_names = FALSE;
+ if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--dest") == 0)
+ {
+ complete_names = TRUE;
+ remove_arg ((*argc) - 1, argc, argv);
+ }
+
+ complete_paths = FALSE;
+ if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--object-path") == 0)
+ {
+ complete_paths = TRUE;
+ remove_arg ((*argc) - 1, argc, argv);
+ }
+
+ complete_signals = FALSE;
+ if (request_completion && *argc > 1 && g_strcmp0 ((*argv)[(*argc)-1], "--signal") == 0)
+ {
+ complete_signals = TRUE;
+ remove_arg ((*argc) - 1, argc, argv);
+ }
+
if (!g_option_context_parse (o, argc, argv, NULL))
{
if (!request_completion)
@@ -616,36 +645,99 @@ handle_emit (gint *argc,
goto out;
}
- /* All done with completion now */
- if (request_completion)
- goto out;
+ /* validate and complete destination (bus name) */
+ if (complete_names)
+ {
+ print_names (c, FALSE);
+ goto out;
+ }
+ if (opt_emit_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_emit_dest, ":"));
+ goto out;
+ }
+
+ if (!request_completion && !g_dbus_is_unique_name (opt_emit_dest))
+ {
+ g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
+ goto out;
+ }
+ /* validate and complete object path */
+ if (complete_paths)
+ {
+ print_paths (c, opt_emit_dest, "/");
+ goto out;
+ }
if (opt_emit_object_path == NULL)
{
- g_printerr (_("Error: object path not specified.\n"));
+ if (request_completion)
+ g_print ("--object-path \n");
+ else
+ g_printerr (_("Error: Object path is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--object-path", completion_prev) == 0)
+ {
+ gchar *p;
+ s = g_strdup (opt_emit_object_path);
+ p = strrchr (s, '/');
+ if (p != NULL)
+ {
+ if (p == s)
+ p++;
+ *p = '\0';
+ }
+ print_paths (c, opt_emit_dest, s);
+ g_free (s);
goto out;
}
- if (!g_variant_is_object_path (opt_emit_object_path))
+ if (!request_completion && !g_variant_is_object_path (opt_emit_object_path))
{
g_printerr (_("Error: %s is not a valid object path\n"), opt_emit_object_path);
goto out;
}
+ /* validate and complete signal (interface + signal name) */
+ if (complete_signals)
+ {
+ print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
+ goto out;
+ }
if (opt_emit_signal == NULL)
{
- g_printerr (_("Error: signal not specified.\n"));
+ if (request_completion)
+ g_print ("--signal \n");
+ else
+ g_printerr (_("Error: Signal name is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--signal", completion_prev) == 0)
+ {
+ print_methods_and_signals (c, opt_emit_dest, opt_emit_object_path, FALSE, TRUE);
goto out;
}
-
s = strrchr (opt_emit_signal, '.');
- if (s == NULL)
+ if (!request_completion && s == NULL)
{
- g_printerr (_("Error: signal must be the fully-qualified name.\n"));
+ g_printerr (_("Error: Signal name “%s” is invalid\n"), opt_emit_signal);
goto out;
}
signal_name = g_strdup (s + 1);
interface_name = g_strndup (opt_emit_signal, s - opt_emit_signal);
+ /* All done with completion now */
+ if (request_completion)
+ goto out;
+
if (!g_dbus_is_interface_name (interface_name))
{
g_printerr (_("Error: %s is not a valid interface name\n"), interface_name);
@@ -658,12 +750,6 @@ handle_emit (gint *argc,
goto out;
}
- if (opt_emit_dest != NULL && !g_dbus_is_unique_name (opt_emit_dest))
- {
- g_printerr (_("Error: %s is not a valid unique bus name.\n"), opt_emit_dest);
- goto out;
- }
-
/* Read parameters */
g_variant_builder_init (&builder, G_VARIANT_TYPE_TUPLE);
skip_dashes = TRUE;
@@ -862,27 +948,23 @@ handle_call (gint *argc,
}
/* validate and complete destination (bus name) */
- if (g_dbus_connection_get_unique_name (c) != NULL)
+ if (complete_names)
{
- /* this only makes sense on message bus connections */
- if (complete_names)
- {
- print_names (c, FALSE);
- goto out;
- }
- if (opt_call_dest == NULL)
- {
- if (request_completion)
- g_print ("--dest \n");
- else
- g_printerr (_("Error: Destination is not specified\n"));
- goto out;
- }
- if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
- {
- print_names (c, g_str_has_prefix (opt_call_dest, ":"));
- goto out;
- }
+ print_names (c, FALSE);
+ goto out;
+ }
+ if (opt_call_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_call_dest, ":"));
+ goto out;
}
if (!request_completion && !g_dbus_is_name (opt_call_dest))
@@ -929,7 +1011,7 @@ handle_call (gint *argc,
/* validate and complete method (interface + method name) */
if (complete_methods)
{
- print_methods (c, opt_call_dest, opt_call_object_path);
+ print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
goto out;
}
if (opt_call_method == NULL)
@@ -942,7 +1024,7 @@ handle_call (gint *argc,
}
if (request_completion && g_strcmp0 ("--method", completion_prev) == 0)
{
- print_methods (c, opt_call_dest, opt_call_object_path);
+ print_methods_and_signals (c, opt_call_dest, opt_call_object_path, TRUE, FALSE);
goto out;
}
s = strrchr (opt_call_method, '.');
@@ -1619,28 +1701,26 @@ handle_introspect (gint *argc,
goto out;
}
- if (g_dbus_connection_get_unique_name (c) != NULL)
+ if (complete_names)
{
- if (complete_names)
- {
- print_names (c, FALSE);
- goto out;
- }
- /* this only makes sense on message bus connections */
- if (opt_introspect_dest == NULL)
- {
- if (request_completion)
- g_print ("--dest \n");
- else
- g_printerr (_("Error: Destination is not specified\n"));
- goto out;
- }
- if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
- {
- print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
- goto out;
- }
+ print_names (c, FALSE);
+ goto out;
+ }
+ /* this only makes sense on message bus connections */
+ if (opt_introspect_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_introspect_dest, ":"));
+ goto out;
}
+
if (complete_paths)
{
print_paths (c, opt_introspect_dest, "/");
@@ -1649,7 +1729,7 @@ handle_introspect (gint *argc,
if (!request_completion && !g_dbus_is_name (opt_introspect_dest))
{
- g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
+ g_printerr (_("Error: %s is not a valid bus name\n"), opt_introspect_dest);
goto out;
}
@@ -1854,27 +1934,32 @@ handle_monitor (gint *argc,
goto out;
}
- if (g_dbus_connection_get_unique_name (c) != NULL)
+ /* Monitoring doesn’t make sense on a non-message-bus connection. */
+ if (g_dbus_connection_get_unique_name (c) == NULL)
{
- if (complete_names)
- {
- print_names (c, FALSE);
- goto out;
- }
- /* this only makes sense on message bus connections */
- if (opt_monitor_dest == NULL)
- {
- if (request_completion)
- g_print ("--dest \n");
- else
- g_printerr (_("Error: Destination is not specified\n"));
- goto out;
- }
- if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
- {
- print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
- goto out;
- }
+ if (!request_completion)
+ g_printerr (_("Error: can’t monitor a non-message-bus connection\n"));
+ goto out;
+ }
+
+ if (complete_names)
+ {
+ print_names (c, FALSE);
+ goto out;
+ }
+ /* this only makes sense on message bus connections */
+ if (opt_monitor_dest == NULL)
+ {
+ if (request_completion)
+ g_print ("--dest \n");
+ else
+ g_printerr (_("Error: Destination is not specified\n"));
+ goto out;
+ }
+ if (request_completion && g_strcmp0 ("--dest", completion_prev) == 0)
+ {
+ print_names (c, g_str_has_prefix (opt_monitor_dest, ":"));
+ goto out;
}
if (!request_completion && !g_dbus_is_name (opt_monitor_dest))
diff --git a/gio/gdbusaddress.c b/gio/gdbusaddress.c
index 6fb3d2ac8..faee80087 100644
--- a/gio/gdbusaddress.c
+++ b/gio/gdbusaddress.c
@@ -1702,10 +1702,10 @@ g_dbus_address_get_for_bus_sync (GBusType bus_type,
* Escape @string so it can appear in a D-Bus address as the value
* part of a key-value pair.
*
- * For instance, if @string is "/run/bus-for-:0",
- * this function would return "/run/bus-for-%3A0",
+ * For instance, if @string is `/run/bus-for-:0`,
+ * this function would return `/run/bus-for-%3A0`,
* which could be used in a D-Bus address like
- * "unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0".
+ * `unix:nonce-tcp:host=127.0.0.1,port=42,noncefile=/run/bus-for-%3A0`.
*
* Returns: (transfer full): a copy of @string with all
* non-optionally-escaped bytes escaped
diff --git a/gio/gdbusauth.c b/gio/gdbusauth.c
index e46e62260..1a0ada5bf 100644
--- a/gio/gdbusauth.c
+++ b/gio/gdbusauth.c
@@ -961,7 +961,6 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
GDataInputStream *dis;
GDataOutputStream *dos;
GError *local_error;
- guchar byte;
gchar *line;
gsize line_length;
GDBusAuthMechanism *mech;
@@ -997,7 +996,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
g_data_input_stream_set_newline_type (dis, G_DATA_STREAM_NEWLINE_TYPE_CR_LF);
- /* first read the NUL-byte (TODO: read credentials if using a unix domain socket) */
+ /* first read the NUL-byte */
#ifdef G_OS_UNIX
if (G_IS_UNIX_CONNECTION (auth->priv->stream))
{
@@ -1014,8 +1013,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
else
{
local_error = NULL;
- byte = g_data_input_stream_read_byte (dis, cancellable, &local_error);
- byte = byte; /* To avoid -Wunused-but-set-variable */
+ (void)g_data_input_stream_read_byte (dis, cancellable, &local_error);
if (local_error != NULL)
{
g_propagate_error (error, local_error);
@@ -1024,8 +1022,7 @@ _g_dbus_auth_run_server (GDBusAuth *auth,
}
#else
local_error = NULL;
- byte = g_data_input_stream_read_byte (dis, cancellable, &local_error);
- byte = byte; /* To avoid -Wunused-but-set-variable */
+ (void)g_data_input_stream_read_byte (dis, cancellable, &local_error);
if (local_error != NULL)
{
g_propagate_error (error, local_error);
diff --git a/gio/gdbusauthmechanismsha1.c b/gio/gdbusauthmechanismsha1.c
index a51430cfa..47cef7833 100644
--- a/gio/gdbusauthmechanismsha1.c
+++ b/gio/gdbusauthmechanismsha1.c
@@ -389,7 +389,6 @@ keyring_lookup_entry (const gchar *cookie_context,
gchar **tokens;
gchar *endp;
gint line_id;
- guint64 line_when;
if (line[0] == '\0')
continue;
@@ -422,8 +421,7 @@ keyring_lookup_entry (const gchar *cookie_context,
goto out;
}
- line_when = g_ascii_strtoll (tokens[1], &endp, 10);
- line_when = line_when; /* To avoid -Wunused-but-set-variable */
+ (void)g_ascii_strtoll (tokens[1], &endp, 10); /* do not care what the timestamp is */
if (*endp != '\0')
{
g_set_error (error,
@@ -490,7 +488,9 @@ keyring_acquire_lock (const gchar *path,
gchar *lock;
gint ret;
guint num_tries;
+#ifdef EEXISTS
guint num_create_tries;
+#endif
int errsv;
g_return_val_if_fail (path != NULL, FALSE);
@@ -512,8 +512,8 @@ keyring_acquire_lock (const gchar *path,
* real locking implementations are still flaky on network filesystems
*/
- num_create_tries = 0;
#ifdef EEXISTS
+ num_create_tries = 0;
again:
#endif
num_tries = 0;
@@ -562,7 +562,6 @@ keyring_acquire_lock (const gchar *path,
goto again;
}
#endif
- num_create_tries = num_create_tries; /* To avoid -Wunused-but-set-variable */
g_set_error (error,
G_IO_ERROR,
g_io_error_from_errno (errsv),
@@ -753,7 +752,6 @@ keyring_generate_entry (const gchar *cookie_context,
g_strfreev (tokens);
goto out;
}
- line_when = line_when; /* To avoid -Wunused-but-set-variable */
/* D-Bus spec says:
diff --git a/gio/gdbusconnection.c b/gio/gdbusconnection.c
index b56c5a875..421e9eab7 100644
--- a/gio/gdbusconnection.c
+++ b/gio/gdbusconnection.c
@@ -635,7 +635,7 @@ g_dbus_connection_dispose (GObject *object)
else
{
if (alive_connections != NULL)
- g_warn_if_fail (g_hash_table_lookup (alive_connections, connection) == NULL);
+ g_warn_if_fail (!g_hash_table_contains (alive_connections, connection));
}
CONNECTION_UNLOCK (connection);
G_UNLOCK (message_bus_lock);
@@ -2226,7 +2226,7 @@ on_worker_message_received (GDBusWorker *worker,
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
@@ -2324,7 +2324,7 @@ on_worker_message_about_to_be_sent (GDBusWorker *worker,
gboolean alive;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
@@ -2397,7 +2397,7 @@ on_worker_closed (GDBusWorker *worker,
guint old_atomic_flags;
G_LOCK (message_bus_lock);
- alive = (g_hash_table_lookup (alive_connections, user_data) != NULL);
+ alive = g_hash_table_contains (alive_connections, user_data);
if (!alive)
{
G_UNLOCK (message_bus_lock);
@@ -2572,7 +2572,7 @@ initable_init (GInitable *initable,
G_LOCK (message_bus_lock);
if (alive_connections == NULL)
alive_connections = g_hash_table_new (g_direct_hash, g_direct_equal);
- g_hash_table_insert (alive_connections, connection, connection);
+ g_hash_table_add (alive_connections, connection);
G_UNLOCK (message_bus_lock);
connection->worker = _g_dbus_worker_new (connection->stream,
@@ -4708,8 +4708,8 @@ maybe_add_path (const gchar *path, gsize path_len, const gchar *object_path, GHa
else
s = g_strdup (begin);
- if (g_hash_table_lookup (set, s) == NULL)
- g_hash_table_insert (set, s, GUINT_TO_POINTER (1));
+ if (!g_hash_table_contains (set, s))
+ g_hash_table_add (set, s);
else
g_free (s);
}
@@ -6126,7 +6126,7 @@ g_dbus_connection_call_finish (GDBusConnection *connection,
* operation will fail with %G_IO_ERROR_CANCELLED. If @parameters
* contains a value not compatible with the D-Bus protocol, the operation
* fails with %G_IO_ERROR_INVALID_ARGUMENT.
-
+ *
* If @reply_type is non-%NULL then the reply will be checked for having
* this type and an error will be raised if it does not match. Said
* another way, if you give a @reply_type then any non-%NULL return
diff --git a/gio/gdbuserror.c b/gio/gdbuserror.c
index c41c2039d..95949ead3 100644
--- a/gio/gdbuserror.c
+++ b/gio/gdbuserror.c
@@ -172,7 +172,7 @@ g_dbus_error_quark (void)
* g_dbus_error_register_error_domain:
* @error_domain_quark_name: The error domain name.
* @quark_volatile: A pointer where to store the #GQuark.
- * @entries: A pointer to @num_entries #GDBusErrorEntry struct items.
+ * @entries: (array length=num_entries): A pointer to @num_entries #GDBusErrorEntry struct items.
* @num_entries: Number of items to register.
*
* Helper function for associating a #GError error domain with D-Bus error names.
diff --git a/gio/gdbusinterfaceskeleton.c b/gio/gdbusinterfaceskeleton.c
index 4dd17af9c..4c82bd0a4 100644
--- a/gio/gdbusinterfaceskeleton.c
+++ b/gio/gdbusinterfaceskeleton.c
@@ -97,7 +97,7 @@ g_dbus_interface_skeleton_finalize (GObject *object)
{
GDBusInterfaceSkeleton *interface = G_DBUS_INTERFACE_SKELETON (object);
- /* Hold the lock just incase any code we call verifies that the lock is held */
+ /* Hold the lock just in case any code we call verifies that the lock is held */
g_mutex_lock (&interface->priv->lock);
/* unexport from all connections if we're exported anywhere */
diff --git a/gio/gdbusmessage.c b/gio/gdbusmessage.c
index e80794ff6..7dd458d20 100644
--- a/gio/gdbusmessage.c
+++ b/gio/gdbusmessage.c
@@ -1440,7 +1440,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
{
GVariant *ret;
GError *local_error;
+#ifdef DEBUG_SERIALIZER
gboolean is_leaf;
+#endif /* DEBUG_SERIALIZER */
const gchar *type_string;
type_string = g_variant_type_peek_string (type);
@@ -1460,7 +1462,9 @@ parse_value_from_blob (GMemoryBuffer *buf,
ret = NULL;
+#ifdef DEBUG_SERIALIZER
is_leaf = TRUE;
+#endif /* DEBUG_SERIALIZER */
local_error = NULL;
switch (type_string[0])
{
@@ -1643,8 +1647,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
array_len = g_memory_buffer_read_uint32 (buf);
- is_leaf = FALSE;
#ifdef DEBUG_SERIALIZER
+ is_leaf = FALSE;
g_print (": array spans 0x%04x bytes\n", array_len);
#endif /* DEBUG_SERIALIZER */
@@ -1751,8 +1755,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
ensure_input_padding (buf, 8);
- is_leaf = FALSE;
#ifdef DEBUG_SERIALIZER
+ is_leaf = FALSE;
g_print ("\n");
#endif /* DEBUG_SERIALIZER */
@@ -1786,8 +1790,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
{
ensure_input_padding (buf, 8);
- is_leaf = FALSE;
#ifdef DEBUG_SERIALIZER
+ is_leaf = FALSE;
g_print ("\n");
#endif /* DEBUG_SERIALIZER */
@@ -1821,8 +1825,8 @@ parse_value_from_blob (GMemoryBuffer *buf,
}
else if (g_variant_type_is_variant (type))
{
- is_leaf = FALSE;
#ifdef DEBUG_SERIALIZER
+ is_leaf = FALSE;
g_print ("\n");
#endif /* DEBUG_SERIALIZER */
@@ -1894,8 +1898,6 @@ parse_value_from_blob (GMemoryBuffer *buf,
g_free (s);
}
}
-#else
- is_leaf = is_leaf; /* To avoid -Wunused-but-set-variable */
#endif /* DEBUG_SERIALIZER */
/* sink the reference, if floating */
diff --git a/gio/gdbusnamewatching.h b/gio/gdbusnamewatching.h
index d803ecb5d..491e21e21 100644
--- a/gio/gdbusnamewatching.h
+++ b/gio/gdbusnamewatching.h
@@ -54,7 +54,7 @@ typedef void (*GBusNameAppearedCallback) (GDBusConnection *connection,
*
* Invoked when the name being watched is known not to have to have a owner.
*
- * This is also invoked when the #GDBusConection on which the watch was
+ * This is also invoked when the #GDBusConnection on which the watch was
* established has been closed. In that case, @connection will be
* %NULL.
*
diff --git a/gio/gdbusobjectmanagerclient.c b/gio/gdbusobjectmanagerclient.c
index 17a515a37..08c94d506 100644
--- a/gio/gdbusobjectmanagerclient.c
+++ b/gio/gdbusobjectmanagerclient.c
@@ -532,7 +532,8 @@ g_dbus_object_manager_client_class_init (GDBusObjectManagerClientClass *klass)
* @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.
- * @invalidated_properties: A %NULL terminated array of properties that was invalidated.
+ * @invalidated_properties: (array zero-terminated=1) (element-type utf8): A %NULL terminated
+ * array of properties that were invalidated.
*
* Emitted when one or more D-Bus properties on proxy changes. The
* local cache has already been updated when this signal fires. Note
@@ -1541,6 +1542,13 @@ add_interfaces (GDBusObjectManagerClient *manager,
g_variant_unref (properties);
}
+ if (added)
+ {
+ g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
+ g_strdup (object_path),
+ op);
+ }
+
g_mutex_unlock (&manager->priv->lock);
/* now that we don't hold the lock any more, emit signals */
@@ -1554,12 +1562,8 @@ add_interfaces (GDBusObjectManagerClient *manager,
g_list_free (interface_added_signals);
if (added)
- {
- g_hash_table_insert (manager->priv->map_object_path_to_object_proxy,
- g_strdup (object_path),
- op);
- g_signal_emit_by_name (manager, "object-added", op);
- }
+ g_signal_emit_by_name (manager, "object-added", op);
+
g_object_unref (manager);
g_object_unref (op);
}
diff --git a/gio/gdesktopappinfo.c b/gio/gdesktopappinfo.c
index fa52f8494..cb5ec48b5 100644
--- a/gio/gdesktopappinfo.c
+++ b/gio/gdesktopappinfo.c
@@ -2199,7 +2199,7 @@ g_desktop_app_info_get_show_in (GDesktopAppInfo *info,
/* Launching... {{{2 */
static char *
-expand_macro_single (char macro, const char *uri)
+expand_macro_single (char macro, char *uri)
{
GFile *file;
char *result = NULL;
@@ -2248,29 +2248,6 @@ expand_macro_single (char macro, const char *uri)
return result;
}
-static char *
-expand_macro_uri (char macro, const char *uri, gboolean force_file_uri, char force_file_uri_macro)
-{
- char *expanded = NULL;
-
- g_return_val_if_fail (uri != NULL, NULL);
-
- if (!force_file_uri ||
- /* Pass URI if it contains an anchor */
- strchr (uri, '#') != NULL)
- {
- expanded = expand_macro_single (macro, uri);
- }
- else
- {
- expanded = expand_macro_single (force_file_uri_macro, uri);
- if (expanded == NULL)
- expanded = expand_macro_single (macro, uri);
- }
-
- return expanded;
-}
-
static void
expand_macro (char macro,
GString *exec,
@@ -2278,10 +2255,10 @@ expand_macro (char macro,
GList **uri_list)
{
GList *uris = *uri_list;
- char *expanded = NULL;
+ char *expanded;
gboolean force_file_uri;
char force_file_uri_macro;
- const char *uri;
+ char *uri;
g_return_if_fail (exec != NULL);
@@ -2318,8 +2295,19 @@ expand_macro (char macro,
if (uris)
{
uri = uris->data;
- expanded = expand_macro_uri (macro, uri,
- force_file_uri, force_file_uri_macro);
+ if (!force_file_uri ||
+ /* Pass URI if it contains an anchor */
+ strchr (uri, '#') != NULL)
+ {
+ expanded = expand_macro_single (macro, uri);
+ }
+ else
+ {
+ expanded = expand_macro_single (force_file_uri_macro, uri);
+ if (expanded == NULL)
+ expanded = expand_macro_single (macro, uri);
+ }
+
if (expanded)
{
g_string_append (exec, expanded);
@@ -2337,8 +2325,20 @@ expand_macro (char macro,
while (uris)
{
uri = uris->data;
- expanded = expand_macro_uri (macro, uri,
- force_file_uri, force_file_uri_macro);
+
+ if (!force_file_uri ||
+ /* Pass URI if it contains an anchor */
+ strchr (uri, '#') != NULL)
+ {
+ expanded = expand_macro_single (macro, uri);
+ }
+ else
+ {
+ expanded = expand_macro_single (force_file_uri_macro, uri);
+ if (expanded == NULL)
+ expanded = expand_macro_single (macro, uri);
+ }
+
if (expanded)
{
g_string_append (exec, expanded);
@@ -2658,8 +2658,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
{
gboolean completed = FALSE;
GList *old_uris;
- GList *dup_uris;
-
char **argv, **envp;
int argc;
ChildSetupData data;
@@ -2673,11 +2671,6 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
else
envp = g_get_environ ();
- /* The GList* passed to expand_application_parameters() will be modified
- * internally by expand_macro(), so we need to pass a copy of it instead,
- * and also use that copy to control the exit condition of the loop below.
- */
- dup_uris = g_list_copy (uris);
do
{
GPid pid;
@@ -2685,13 +2678,13 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
GList *iter;
char *sn_id = NULL;
- old_uris = dup_uris;
- if (!expand_application_parameters (info, exec_line, &dup_uris, &argc, &argv, error))
+ old_uris = uris;
+ if (!expand_application_parameters (info, exec_line, &uris, &argc, &argv, error))
goto out;
/* Get the subset of URIs we're launching with this process */
launched_uris = NULL;
- for (iter = old_uris; iter != NULL && iter != dup_uris; iter = iter->next)
+ for (iter = old_uris; iter != NULL && iter != uris; iter = iter->next)
launched_uris = g_list_prepend (launched_uris, iter->data);
launched_uris = g_list_reverse (launched_uris);
@@ -2787,12 +2780,11 @@ g_desktop_app_info_launch_uris_with_spawn (GDesktopAppInfo *info,
g_strfreev (argv);
argv = NULL;
}
- while (dup_uris != NULL);
+ while (uris != NULL);
completed = TRUE;
out:
- g_list_free (dup_uris);
g_strfreev (argv);
g_strfreev (envp);
@@ -3011,7 +3003,7 @@ g_desktop_app_info_launch (GAppInfo *appinfo,
* @uris: (element-type utf8): List of URIs
* @launch_context: (nullable): a #GAppLaunchContext
* @spawn_flags: #GSpawnFlags, used for each process
- * @user_setup: (scope call) (nullable): a #GSpawnChildSetupFunc, used once
+ * @user_setup: (scope async) (nullable): a #GSpawnChildSetupFunc, used once
* for each process.
* @user_setup_data: (closure user_setup) (nullable): User data for @user_setup
* @pid_callback: (scope call) (nullable): Callback for child processes
@@ -3714,7 +3706,7 @@ g_desktop_app_info_delete (GAppInfo *appinfo)
/* Create for commandline {{{2 */
/**
* g_app_info_create_from_commandline:
- * @commandline: the commandline to use
+ * @commandline: (type filename): the commandline to use
* @application_name: (nullable): the application name, or %NULL to use @commandline
* @flags: flags that can specify details of the created #GAppInfo
* @error: a #GError location to store the error occurring, %NULL to ignore.
diff --git a/gio/gdtlsconnection.c b/gio/gdtlsconnection.c
index 67a038d18..cbcb720dc 100644
--- a/gio/gdtlsconnection.c
+++ b/gio/gdtlsconnection.c
@@ -112,7 +112,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface)
*
* The certificate database to use when verifying this TLS connection.
* If no certificate database is set, then the default database will be
- * used. See g_dtls_backend_get_default_database().
+ * used. See g_tls_backend_get_default_database().
*
* Since: 2.48
*/
@@ -294,7 +294,7 @@ g_dtls_connection_default_init (GDtlsConnectionInterface *iface)
*
* Sets the certificate database that is used to verify peer certificates.
* This is set to the default database by default. See
- * g_dtls_backend_get_default_database(). If set to %NULL, then
+ * g_tls_backend_get_default_database(). If set to %NULL, then
* peer certificate validation will always set the
* %G_TLS_CERTIFICATE_UNKNOWN_CA error (meaning
* #GDtlsConnection::accept-certificate will always be emitted on
diff --git a/gio/gfile.c b/gio/gfile.c
index 8a78e95c9..812b148b7 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -81,6 +81,7 @@
* - g_file_new_for_commandline_arg() for a command line argument.
* - g_file_new_tmp() to create a temporary file from a template.
* - g_file_parse_name() from a UTF-8 string gotten from g_file_get_parse_name().
+ * - g_file_new_build_filename() to create a file from path elements.
*
* One way to think of a #GFile is as an abstraction of a pathname. For
* normal files the system pathname is what is stored internally, but as
@@ -4368,7 +4369,7 @@ g_file_query_writable_namespaces (GFile *file,
*
* Sets an attribute in the file with attribute name @attribute to @value.
*
- * Some attributes can be unset by setting @attribute to
+ * Some attributes can be unset by setting @type to
* %G_FILE_ATTRIBUTE_TYPE_INVALID and @value_p to %NULL.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
@@ -6440,6 +6441,41 @@ g_file_parse_name (const char *parse_name)
return g_vfs_parse_name (g_vfs_get_default (), parse_name);
}
+/**
+ * g_file_new_build_filename:
+ * @first_element: (type filename): the first element in the path
+ * @...: remaining elements in path, terminated by %NULL
+ *
+ * Constructs a #GFile from a series of elements using the correct
+ * separator for filenames.
+ *
+ * Using this function is equivalent to calling g_build_filename(),
+ * followed by g_file_new_for_path() on the result.
+ *
+ * Returns: (transfer full): a new #GFile
+ *
+ * Since: 2.56
+ */
+GFile *
+g_file_new_build_filename (const gchar *first_element,
+ ...)
+{
+ gchar *str;
+ GFile *file;
+ va_list args;
+
+ g_return_val_if_fail (first_element != NULL, NULL);
+
+ va_start (args, first_element);
+ str = g_build_filename_valist (first_element, &args);
+ va_end (args);
+
+ file = g_file_new_for_path (str);
+ g_free (str);
+
+ return file;
+}
+
static gboolean
is_valid_scheme_character (char c)
{
@@ -6498,7 +6534,7 @@ new_for_cmdline_arg (const gchar *arg,
/**
* g_file_new_for_commandline_arg:
- * @arg: a command line string
+ * @arg: (type filename): a command line string
*
* Creates a #GFile with the given argument from the command line.
* The value of @arg can be either a URI, an absolute path or a
@@ -6528,7 +6564,7 @@ g_file_new_for_commandline_arg (const char *arg)
/**
* g_file_new_for_commandline_arg_and_cwd:
- * @arg: a command line string
+ * @arg: (type filename): a command line string
* @cwd: (type filename): the current working directory of the commandline
*
* Creates a #GFile with the given argument from the command line.
@@ -6957,9 +6993,11 @@ load_contents_open_callback (GObject *obj,
* g_file_load_partial_contents_async: (skip)
* @file: input #GFile
* @cancellable: optional #GCancellable object, %NULL to ignore
- * @read_more_callback: a #GFileReadMoreCallback to receive partial data
+ * @read_more_callback: (scope call) (closure user_data): a
+ * #GFileReadMoreCallback to receive partial data
* and to specify whether further data should be read
- * @callback: a #GAsyncReadyCallback to call when the request is satisfied
+ * @callback: (scope async) (closure user_data): a #GAsyncReadyCallback to call
+ * when the request is satisfied
* @user_data: the data to pass to the callback functions
*
* Reads the partial contents of a file. A #GFileReadMoreCallback should
@@ -8054,3 +8092,191 @@ g_file_supports_thread_contexts (GFile *file)
iface = G_FILE_GET_IFACE (file);
return iface->supports_thread_contexts;
}
+
+/**
+ * g_file_load_bytes:
+ * @file: a #GFile
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @etag_out: (out) (nullable) (optional): a location to place the current
+ * entity tag for the file, or %NULL if the entity tag is not needed
+ * @error: a location for a #GError or %NULL
+ *
+ * Loads the contents of @file and returns it as #GBytes.
+ *
+ * If @file is a resource:// based URI, the resulting bytes will reference the
+ * embedded resource instead of a copy. Otherwise, this is equivalent to calling
+ * g_file_load_contents() and g_bytes_new_take().
+ *
+ * For resources, @etag_out will be set to %NULL.
+ *
+ * The data contained in the resulting #GBytes is always zero-terminated, but
+ * this is not included in the #GBytes length. The resulting #GBytes should be
+ * freed with g_bytes_unref() when no longer in use.
+ *
+ * Returns: (transfer full): a #GBytes or %NULL and @error is set
+ *
+ * Since: 2.56
+ */
+GBytes *
+g_file_load_bytes (GFile *file,
+ GCancellable *cancellable,
+ gchar **etag_out,
+ GError **error)
+{
+ gchar *contents;
+ gsize len;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ if (etag_out != NULL)
+ *etag_out = NULL;
+
+ if (g_file_has_uri_scheme (file, "resource"))
+ {
+ GBytes *bytes;
+ gchar *uri, *unescaped;
+
+ uri = g_file_get_uri (file);
+ unescaped = g_uri_unescape_string (uri + strlen ("resource://"), NULL);
+ g_free (uri);
+
+ bytes = g_resources_lookup_data (unescaped, G_RESOURCE_LOOKUP_FLAGS_NONE, error);
+ g_free (unescaped);
+
+ return bytes;
+ }
+
+ /* contents is guaranteed to be \0 terminated */
+ if (g_file_load_contents (file, cancellable, &contents, &len, etag_out, error))
+ return g_bytes_new_take (g_steal_pointer (&contents), len);
+
+ return NULL;
+}
+
+static void
+g_file_load_bytes_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = G_FILE (object);
+ GTask *task = user_data;
+ GError *error = NULL;
+ gchar *etag = NULL;
+ gchar *contents = NULL;
+ gsize len = 0;
+
+ g_file_load_contents_finish (file, result, &contents, &len, &etag, &error);
+ g_task_set_task_data (task, g_steal_pointer (&etag), g_free);
+
+ if (error != NULL)
+ g_task_return_error (task, g_steal_pointer (&error));
+ else
+ g_task_return_pointer (task,
+ g_bytes_new_take (g_steal_pointer (&contents), len),
+ (GDestroyNotify)g_bytes_unref);
+
+ g_object_unref (task);
+}
+
+/**
+ * g_file_load_bytes_async:
+ * @file: a #GFile
+ * @cancellable: (nullable): a #GCancellable or %NULL
+ * @callback: (scope async): a #GAsyncReadyCallback to call when the
+ * request is satisfied
+ * @user_data: (closure): the data to pass to callback function
+ *
+ * Asynchronously loads the contents of @file as #GBytes.
+ *
+ * If @file is a resource:// based URI, the resulting bytes will reference the
+ * embedded resource instead of a copy. Otherwise, this is equivalent to calling
+ * g_file_load_contents_async() and g_bytes_new_take().
+ *
+ * @callback should call g_file_load_bytes_finish() to get the result of this
+ * asynchronous operation.
+ *
+ * See g_file_load_bytes() for more information.
+ *
+ * Since: 2.56
+ */
+void
+g_file_load_bytes_async (GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GError *error = NULL;
+ GBytes *bytes;
+ GTask *task;
+
+ g_return_if_fail (G_IS_FILE (file));
+ g_return_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable));
+
+ task = g_task_new (file, cancellable, callback, user_data);
+ g_task_set_source_tag (task, g_file_load_bytes_async);
+
+ if (!g_file_has_uri_scheme (file, "resource"))
+ {
+ g_file_load_contents_async (file,
+ cancellable,
+ g_file_load_bytes_cb,
+ g_steal_pointer (&task));
+ return;
+ }
+
+ bytes = g_file_load_bytes (file, cancellable, NULL, &error);
+
+ if (bytes == NULL)
+ g_task_return_error (task, g_steal_pointer (&error));
+ else
+ g_task_return_pointer (task,
+ g_steal_pointer (&bytes),
+ (GDestroyNotify)g_bytes_unref);
+
+ g_object_unref (task);
+}
+
+/**
+ * g_file_load_bytes_finish:
+ * @file: a #GFile
+ * @result: a #GAsyncResult provided to the callback
+ * @etag_out: (out) (nullable) (optional): a location to place the current
+ * entity tag for the file, or %NULL if the entity tag is not needed
+ * @error: a location for a #GError, or %NULL
+ *
+ * Completes an asynchronous request to g_file_load_bytes_async().
+ *
+ * For resources, @etag_out will be set to %NULL.
+ *
+ * The data contained in the resulting #GBytes is always zero-terminated, but
+ * this is not included in the #GBytes length. The resulting #GBytes should be
+ * freed with g_bytes_unref() when no longer in use.
+ *
+ * See g_file_load_bytes() for more information.
+ *
+ * Returns: (transfer full): a #GBytes or %NULL and @error is set
+ *
+ * Since: 2.56
+ */
+GBytes *
+g_file_load_bytes_finish (GFile *file,
+ GAsyncResult *result,
+ gchar **etag_out,
+ GError **error)
+{
+ GBytes *bytes;
+
+ g_return_val_if_fail (G_IS_FILE (file), NULL);
+ g_return_val_if_fail (G_IS_TASK (result), NULL);
+ g_return_val_if_fail (g_task_is_valid (G_TASK (result), file), NULL);
+ g_return_val_if_fail (error == NULL || *error == NULL, NULL);
+
+ bytes = g_task_propagate_pointer (G_TASK (result), error);
+
+ if (etag_out != NULL)
+ *etag_out = g_strdup (g_task_get_task_data (G_TASK (result)));
+
+ return bytes;
+}
diff --git a/gio/gfile.h b/gio/gfile.h
index 1efbfa03b..1717665e4 100644
--- a/gio/gfile.h
+++ b/gio/gfile.h
@@ -606,6 +606,9 @@ GFile * g_file_new_tmp (const char
GError **error);
GLIB_AVAILABLE_IN_ALL
GFile * g_file_parse_name (const char *parse_name);
+GLIB_AVAILABLE_IN_2_56
+GFile * g_file_new_build_filename (const gchar *first_element,
+ ...) G_GNUC_NULL_TERMINATED;
GLIB_AVAILABLE_IN_ALL
GFile * g_file_dup (GFile *file);
GLIB_AVAILABLE_IN_ALL
@@ -1248,6 +1251,22 @@ gboolean g_file_replace_contents_finish (GFile *file,
GLIB_AVAILABLE_IN_ALL
gboolean g_file_supports_thread_contexts (GFile *file);
+GLIB_AVAILABLE_IN_2_56
+GBytes *g_file_load_bytes (GFile *file,
+ GCancellable *cancellable,
+ gchar **etag_out,
+ GError **error);
+GLIB_AVAILABLE_IN_2_56
+void g_file_load_bytes_async (GFile *file,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+GLIB_AVAILABLE_IN_2_56
+GBytes *g_file_load_bytes_finish (GFile *file,
+ GAsyncResult *result,
+ gchar **etag_out,
+ GError **error);
+
G_END_DECLS
#endif /* __G_FILE_H__ */
diff --git a/gio/gfileenumerator.c b/gio/gfileenumerator.c
index 3e4db13b8..d96a798af 100644
--- a/gio/gfileenumerator.c
+++ b/gio/gfileenumerator.c
@@ -318,7 +318,7 @@ next_async_callback_wrapper (GObject *source_object,
* Request information for a number of files from the enumerator asynchronously.
* When all i/o for the operation is finished the @callback will be called with
* the requested information.
-
+ *
* See the documentation of #GFileEnumerator for information about the
* order of returned files.
*
diff --git a/gio/gioenums.h b/gio/gioenums.h
index bedc81b1f..c6ee8c433 100644
--- a/gio/gioenums.h
+++ b/gio/gioenums.h
@@ -1690,7 +1690,7 @@ typedef enum /*< flags >*/ {
* @G_TLS_DATABASE_LOOKUP_KEYPAIR: Restrict lookup to certificates that have
* a private key.
*
- * Flags for g_tls_database_lookup_certificate_handle(),
+ * Flags for g_tls_database_lookup_certificate_for_handle(),
* g_tls_database_lookup_certificate_issuer(),
* and g_tls_database_lookup_certificates_issued_by().
*
diff --git a/gio/giomodule.c b/gio/giomodule.c
index 6937932b2..40476957c 100644
--- a/gio/giomodule.c
+++ b/gio/giomodule.c
@@ -202,14 +202,14 @@ g_io_module_scope_block (GIOModuleScope *scope,
g_return_if_fail (basename != NULL);
key = g_strdup (basename);
- g_hash_table_insert (scope->basenames, key, key);
+ g_hash_table_add (scope->basenames, key);
}
static gboolean
_g_io_module_scope_contains (GIOModuleScope *scope,
const gchar *basename)
{
- return g_hash_table_lookup (scope->basenames, basename) ? TRUE : FALSE;
+ return g_hash_table_contains (scope->basenames, basename);
}
struct _GIOModule {
diff --git a/gio/giotypes.h b/gio/giotypes.h
index 67c9cc7b7..738e517bb 100644
--- a/gio/giotypes.h
+++ b/gio/giotypes.h
@@ -259,12 +259,18 @@ typedef struct _GVolumeMonitor GVolumeMonitor;
/**
* GAsyncReadyCallback:
- * @source_object: the object the asynchronous operation was started with.
+ * @source_object: (nullable): the object the asynchronous operation was started with.
* @res: a #GAsyncResult.
* @user_data: user data passed to the callback.
*
* Type definition for a function that will be called back when an asynchronous
- * operation within GIO has been completed.
+ * operation within GIO has been completed. #GAsyncReadyCallback
+ * callbacks from #GTask are guaranteed to be invoked in a later
+ * iteration of the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * where the #GTask was created. All other users of
+ * #GAsyncReadyCallback must likewise call it asynchronously in a
+ * later iteration of the main context.
**/
typedef void (*GAsyncReadyCallback) (GObject *source_object,
GAsyncResult *res,
@@ -288,7 +294,7 @@ typedef void (*GFileProgressCallback) (goffset current_num_bytes,
* GFileReadMoreCallback:
* @file_contents: the data as currently read.
* @file_size: the size of the data currently read.
- * @callback_data: data passed to the callback.
+ * @callback_data: (closure): data passed to the callback.
*
* When loading the partial contents of a file with g_file_load_partial_contents_async(),
* it may become necessary to determine if any more data from the file should be loaded.
diff --git a/gio/glib-compile-resources.c b/gio/glib-compile-resources.c
index a92fefd7d..8a1a07dd1 100644
--- a/gio/glib-compile-resources.c
+++ b/gio/glib-compile-resources.c
@@ -789,6 +789,7 @@ main (int argc, char **argv)
{
g_free (target);
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
@@ -858,6 +859,7 @@ main (int argc, char **argv)
g_string_free (dep_string, TRUE);
g_free (dependency_file);
g_error_free (error);
+ g_hash_table_unref (files);
return 1;
}
}
@@ -890,6 +892,7 @@ main (int argc, char **argv)
{
g_printerr ("Can't open temp file\n");
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
close (fd);
@@ -936,6 +939,7 @@ main (int argc, char **argv)
g_printerr ("%s\n", error->message);
g_free (target);
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
@@ -948,6 +952,7 @@ main (int argc, char **argv)
{
g_printerr ("can't write to file %s", target);
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
@@ -985,6 +990,7 @@ main (int argc, char **argv)
{
g_printerr ("can't read back temporary file");
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
g_unlink (binary_target);
@@ -994,6 +1000,7 @@ main (int argc, char **argv)
{
g_printerr ("can't write to file %s", target);
g_free (c_name);
+ g_hash_table_unref (files);
return 1;
}
@@ -1090,6 +1097,7 @@ main (int argc, char **argv)
g_hash_table_destroy (table);
g_free (xmllint);
g_free (c_name);
+ g_hash_table_unref (files);
return 0;
}
diff --git a/gio/glib-compile-schemas.c b/gio/glib-compile-schemas.c
index b8de09072..2dc8c7171 100644
--- a/gio/glib-compile-schemas.c
+++ b/gio/glib-compile-schemas.c
@@ -97,9 +97,9 @@ enum_state_add_value (EnumState *state,
}
value = g_ascii_strtoll (valuestr, &end, 0);
- if (*end || state->is_flags ?
+ if (*end || (state->is_flags ?
(value > G_MAXUINT32 || value < 0) :
- (value > G_MAXINT32 || value < G_MININT32))
+ (value > G_MAXINT32 || value < G_MININT32)))
{
g_set_error (error, G_MARKUP_ERROR,
G_MARKUP_ERROR_INVALID_CONTENT,
diff --git a/gio/glistmodel.c b/gio/glistmodel.c
index c2491be2d..2b943a87c 100644
--- a/gio/glistmodel.c
+++ b/gio/glistmodel.c
@@ -96,6 +96,22 @@ G_DEFINE_INTERFACE (GListModel, g_list_model, G_TYPE_OBJECT)
*/
/**
+ * GListModelInterface::get_item:
+ * @list: a #GListModel
+ * @position: the position of the item to fetch
+ *
+ * Get the item at @position. If @position is greater than the number of
+ * items in @list, %NULL is returned.
+ *
+ * %NULL is never returned for an index that is smaller than the length
+ * of the list. See g_list_model_get_n_items().
+ *
+ * Returns: (type GObject) (transfer full) (nullable): the object at @position.
+ *
+ * Since: 2.44
+ */
+
+/**
* GListModel:
*
* #GListModel is an opaque data structure and can only be accessed
@@ -186,7 +202,7 @@ g_list_model_get_n_items (GListModel *list)
* %NULL is never returned for an index that is smaller than the length
* of the list. See g_list_model_get_n_items().
*
- * Returns: (transfer full) (nullable) (type GObject): the item at @position.
+ * Returns: (transfer full) (nullable): the item at @position.
*
* Since: 2.44
*/
diff --git a/gio/glocalfile.c b/gio/glocalfile.c
index d417c4991..e484a31bf 100644
--- a/gio/glocalfile.c
+++ b/gio/glocalfile.c
@@ -62,11 +62,11 @@
#include "gunixmounts.h"
#include "gioerror.h"
#include <glib/gstdio.h>
+#include <glib/gstdioprivate.h>
#include "glibintl.h"
#ifdef G_OS_UNIX
#include "glib-unix.h"
#endif
-#include "glib-private.h"
#include "glib-private.h"
@@ -753,6 +753,8 @@ get_fs_type (long f_type)
return "xiafs";
case 0x52345362:
return "reiser4";
+ case 0x65735546:
+ return "fuse";
default:
return NULL;
}
@@ -1104,16 +1106,16 @@ g_local_file_query_filesystem_info (GFile *file,
#ifndef G_OS_WIN32
#ifdef USE_STATFS
#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME)
- fstype = g_strdup (statfs_buffer.f_fstypename);
+ fstype = statfs_buffer.f_fstypename;
#else
fstype = get_fs_type (statfs_buffer.f_type);
#endif
#elif defined(USE_STATVFS)
#if defined(HAVE_STRUCT_STATVFS_F_FSTYPENAME)
- fstype = g_strdup (statfs_buffer.f_fstypename);
+ fstype = statfs_buffer.f_fstypename;
#elif defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
- fstype = g_strdup (statfs_buffer.f_basetype);
+ fstype = statfs_buffer.f_basetype;
#else
fstype = NULL;
#endif
@@ -1395,7 +1397,8 @@ g_local_file_read (GFile *file,
#ifdef G_OS_WIN32
if (errsv == EACCES)
{
- ret = _stati64 (local->filename, &buf);
+ /* Exploit the fact that on W32 the glib filename encoding is UTF8 */
+ ret = GLIB_PRIVATE_CALL (g_win32_stat_utf8) (local->filename, &buf);
if (ret == 0 && S_ISDIR (buf.st_mode))
errsv = EISDIR;
}
@@ -1407,7 +1410,7 @@ g_local_file_read (GFile *file,
}
#ifdef G_OS_WIN32
- ret = _fstati64 (fd, &buf);
+ ret = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &buf);
#else
ret = fstat (fd, &buf);
#endif
@@ -1577,7 +1580,7 @@ expand_symlink (const char *link)
char symlink_value[4096];
#ifdef G_OS_WIN32
#else
- ssize_t res;
+ gssize res;
#endif
#ifdef G_OS_WIN32
@@ -2677,33 +2680,12 @@ g_local_file_measure_size_of_file (gint parent_fd,
int errsv = errno;
return g_local_file_measure_size_error (state->flags, errsv, name, error);
}
-#else
- {
- const char *filename = (const gchar *) name->data;
- wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL);
- int retval;
- int save_errno;
- int len;
-
- if (wfilename == NULL)
- return g_local_file_measure_size_error (state->flags, errno, name, error);
-
- len = wcslen (wfilename);
- while (len > 0 && G_IS_DIR_SEPARATOR (wfilename[len-1]))
- len--;
- if (len > 0 &&
- (!g_path_is_absolute (filename) || len > g_path_skip_root (filename) - filename))
- wfilename[len] = '\0';
-
- retval = _wstati64 (wfilename, &buf);
- save_errno = errno;
-
- g_free (wfilename);
-
- errno = save_errno;
- if (retval != 0)
- return g_local_file_measure_size_error (state->flags, errno, name, error);
- }
+#else /* !AT_FDCWD && !HAVE_LSTAT && G_OS_WIN32 */
+ if (GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (name->data, &buf) != 0)
+ {
+ int errsv = errno;
+ return g_local_file_measure_size_error (state->flags, errsv, name, error);
+ }
#endif
if (name->next)
@@ -2722,7 +2704,11 @@ g_local_file_measure_size_of_file (gint parent_fd,
state->contained_on = buf.st_dev;
}
-#if defined (HAVE_STRUCT_STAT_ST_BLOCKS)
+#if defined (G_OS_WIN32)
+ if (~state->flags & G_FILE_MEASURE_APPARENT_SIZE)
+ state->disk_usage += buf.allocated_size;
+ else
+#elif defined (HAVE_STRUCT_STAT_ST_BLOCKS)
if (~state->flags & G_FILE_MEASURE_APPARENT_SIZE)
state->disk_usage += buf.st_blocks * G_GUINT64_CONSTANT (512);
else
diff --git a/gio/glocalfileinfo.c b/gio/glocalfileinfo.c
index f46d4d6db..fad80d37c 100644
--- a/gio/glocalfileinfo.c
+++ b/gio/glocalfileinfo.c
@@ -53,6 +53,7 @@
#endif /* HAVE_XATTR */
#include <glib/gstdio.h>
+#include <glib/gstdioprivate.h>
#include <gfileattribute-priv.h>
#include <gfileinfo-priv.h>
#include <gvfs.h>
@@ -60,9 +61,10 @@
#ifdef G_OS_UNIX
#include <unistd.h>
#include "glib-unix.h"
-#include "glib-private.h"
#endif
+#include "glib-private.h"
+
#include "thumbnail-verify.h"
#ifdef G_OS_WIN32
@@ -136,9 +138,15 @@ _g_local_file_info_create_etag (GLocalFileStat *statbuf)
static char *
_g_local_file_info_create_file_id (GLocalFileStat *statbuf)
{
+ guint64 ino;
+#ifdef G_OS_WIN32
+ ino = statbuf->file_index;
+#else
+ ino = statbuf->st_ino;
+#endif
return g_strdup_printf ("l%" G_GUINT64_FORMAT ":%" G_GUINT64_FORMAT,
(guint64) statbuf->st_dev,
- (guint64) statbuf->st_ino);
+ ino);
}
static char *
@@ -148,13 +156,12 @@ _g_local_file_info_create_fs_id (GLocalFileStat *statbuf)
(guint64) statbuf->st_dev);
}
-
-#ifdef S_ISLNK
+#if defined (S_ISLNK) || defined (G_OS_WIN32)
static gchar *
read_link (const gchar *full_name)
{
-#ifdef HAVE_READLINK
+#if defined (HAVE_READLINK) || defined (G_OS_WIN32)
gchar *buffer;
guint size;
@@ -165,7 +172,11 @@ read_link (const gchar *full_name)
{
int read_size;
+#ifndef G_OS_WIN32
read_size = readlink (full_name, buffer, size);
+#else
+ read_size = GLIB_PRIVATE_CALL (g_win32_readlink_utf8) (full_name, buffer, size);
+#endif
if (read_size < 0)
{
g_free (buffer);
@@ -184,7 +195,7 @@ read_link (const gchar *full_name)
#endif
}
-#endif /* S_ISLNK */
+#endif /* S_ISLNK || G_OS_WIN32 */
#ifdef HAVE_SELINUX
/* Get the SELinux security context */
@@ -236,7 +247,7 @@ get_selinux_context (const char *path,
#define g_setxattr(path,name,value,size) setxattr(path,name,value,size,0)
#endif
-static ssize_t
+static gssize
g_getxattr (const char *path, const char *name, void *value, size_t size,
gboolean follow_symlinks)
{
@@ -250,7 +261,7 @@ g_getxattr (const char *path, const char *name, void *value, size_t size,
#endif
}
-static ssize_t
+static gssize
g_listxattr(const char *path, char *namebuf, size_t size,
gboolean follow_symlinks)
{
@@ -400,7 +411,7 @@ get_one_xattr (const char *path,
{
char value[64];
char *value_p;
- ssize_t len;
+ gssize len;
int errsv;
len = g_getxattr (path, xattr, value, sizeof (value)-1, follow_symlinks);
@@ -450,7 +461,7 @@ get_xattrs (const char *path,
#ifdef HAVE_XATTR
gboolean all;
gsize list_size;
- ssize_t list_res_size;
+ gssize list_res_size;
size_t len;
char *list;
const char *attr, *attr2;
@@ -562,7 +573,7 @@ get_one_xattr_from_fd (int fd,
{
char value[64];
char *value_p;
- ssize_t len;
+ gssize len;
int errsv;
len = g_fgetxattr (fd, xattr, value, sizeof (value) - 1);
@@ -610,7 +621,7 @@ get_xattrs_from_fd (int fd,
#ifdef HAVE_XATTR
gboolean all;
gsize list_size;
- ssize_t list_res_size;
+ gssize list_res_size;
size_t len;
char *list;
const char *attr, *attr2;
@@ -938,6 +949,9 @@ set_info_from_stat (GFileInfo *info,
#ifdef S_ISLNK
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)
+ file_type = G_FILE_TYPE_SYMBOLIC_LINK;
#endif
g_file_info_set_file_type (info, file_type);
@@ -960,7 +974,11 @@ set_info_from_stat (GFileInfo *info,
#if defined (HAVE_STRUCT_STAT_ST_BLOCKS)
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_UNIX_BLOCKS, statbuf->st_blocks);
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
- statbuf->st_blocks * G_GUINT64_CONSTANT (512));
+ statbuf->st_blocks * G_GUINT64_CONSTANT (512));
+#elif defined (G_OS_WIN32)
+ _g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_ALLOCATED_SIZE,
+ statbuf->allocated_size);
+
#endif
_g_file_info_set_attribute_uint64_by_id (info, G_FILE_ATTRIBUTE_ID_TIME_MODIFIED, statbuf->st_mtime);
@@ -1289,7 +1307,7 @@ get_content_type (const char *basename,
if (fd != -1)
{
- ssize_t res;
+ gssize res;
res = read (fd, sniff_buffer, sniff_length);
(void) g_close (fd, NULL);
@@ -1618,12 +1636,12 @@ get_icon_name (const char *path,
const char *name = NULL;
gboolean with_fallbacks = TRUE;
- if (strcmp (path, g_get_home_dir ()) == 0)
+ if (g_strcmp0 (path, g_get_home_dir ()) == 0)
{
name = use_symbolic ? "user-home-symbolic" : "user-home";
with_fallbacks = FALSE;
}
- else if (strcmp (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
+ else if (g_strcmp0 (path, g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP)) == 0)
{
name = use_symbolic ? "user-desktop-symbolic" : "user-desktop";
with_fallbacks = FALSE;
@@ -1711,13 +1729,12 @@ _g_local_file_info_get (const char *basename,
GLocalFileStat statbuf;
#ifdef S_ISLNK
struct stat statbuf2;
+#elif defined (G_OS_WIN32)
+ GWin32PrivateStat statbuf2;
#endif
int res;
gboolean stat_ok;
gboolean is_symlink, symlink_broken;
-#ifdef G_OS_WIN32
- DWORD dos_attributes;
-#endif
char *symlink_target;
GVfs *vfs;
GVfsClass *class;
@@ -1739,28 +1756,7 @@ _g_local_file_info_get (const char *basename,
#ifndef G_OS_WIN32
res = g_lstat (path, &statbuf);
#else
- {
- wchar_t *wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, error);
- int len;
-
- if (wpath == NULL)
- {
- g_object_unref (info);
- return NULL;
- }
-
- len = wcslen (wpath);
- while (len > 0 && G_IS_DIR_SEPARATOR (wpath[len-1]))
- len--;
- if (len > 0 &&
- (!g_path_is_absolute (path) || len > g_path_skip_root (path) - path))
- wpath[len] = '\0';
-
- res = _wstati64 (wpath, &statbuf);
- dos_attributes = GetFileAttributesW (wpath);
-
- g_free (wpath);
- }
+ res = GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (path, &statbuf);
#endif
if (res == -1)
@@ -1791,11 +1787,14 @@ _g_local_file_info_get (const char *basename,
#ifdef S_ISLNK
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;
#else
is_symlink = FALSE;
#endif
symlink_broken = FALSE;
-#ifdef S_ISLNK
+
if (is_symlink)
{
g_file_info_set_is_symlink (info, TRUE);
@@ -1803,7 +1802,11 @@ _g_local_file_info_get (const char *basename,
/* Unless NOFOLLOW was set we default to following symlinks */
if (!(flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS))
{
+#ifndef G_OS_WIN32
res = stat (path, &statbuf2);
+#else
+ res = GLIB_PRIVATE_CALL (g_win32_stat_utf8) (path, &statbuf2);
+#endif
/* Report broken links as symlinks */
if (res != -1)
@@ -1815,7 +1818,6 @@ _g_local_file_info_get (const char *basename,
symlink_broken = TRUE;
}
}
-#endif
if (stat_ok)
set_info_from_stat (info, &statbuf, attribute_matcher);
@@ -1839,27 +1841,28 @@ _g_local_file_info_get (const char *basename,
(stat_ok && S_ISREG (statbuf.st_mode)))
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_STANDARD_IS_BACKUP, TRUE);
#else
- if (dos_attributes & FILE_ATTRIBUTE_HIDDEN)
+ if (statbuf.attributes & FILE_ATTRIBUTE_HIDDEN)
g_file_info_set_is_hidden (info, TRUE);
- if (dos_attributes & FILE_ATTRIBUTE_ARCHIVE)
+ if (statbuf.attributes & FILE_ATTRIBUTE_ARCHIVE)
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_ARCHIVE, TRUE);
- if (dos_attributes & FILE_ATTRIBUTE_SYSTEM)
+ if (statbuf.attributes & FILE_ATTRIBUTE_SYSTEM)
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM, TRUE);
#endif
symlink_target = NULL;
-#ifdef S_ISLNK
if (is_symlink)
{
+#if defined (S_ISLNK) || defined (G_OS_WIN32)
symlink_target = read_link (path);
+#endif
if (symlink_target &&
_g_file_attribute_matcher_matches_id (attribute_matcher,
G_FILE_ATTRIBUTE_ID_STANDARD_SYMLINK_TARGET))
g_file_info_set_symlink_target (info, symlink_target);
}
-#endif
+
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
G_FILE_ATTRIBUTE_ID_STANDARD_CONTENT_TYPE) ||
_g_file_attribute_matcher_matches_id (attribute_matcher,
@@ -1975,11 +1978,7 @@ _g_local_file_info_get (const char *basename,
get_xattrs (path, FALSE, info, attribute_matcher, (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) == 0);
if (_g_file_attribute_matcher_matches_id (attribute_matcher,
- G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH) ||
- _g_file_attribute_matcher_matches_id (attribute_matcher,
- G_FILE_ATTRIBUTE_ID_THUMBNAIL_IS_VALID) ||
- _g_file_attribute_matcher_matches_id (attribute_matcher,
- G_FILE_ATTRIBUTE_ID_THUMBNAILING_FAILED))
+ G_FILE_ATTRIBUTE_ID_THUMBNAIL_PATH))
{
if (stat_ok)
get_thumbnail_attributes (path, info, &statbuf);
@@ -2018,7 +2017,7 @@ _g_local_file_info_get_from_fd (int fd,
GFileInfo *info;
#ifdef G_OS_WIN32
-#define FSTAT _fstati64
+#define FSTAT GLIB_PRIVATE_CALL (g_win32_fstat)
#else
#define FSTAT fstat
#endif
@@ -2152,16 +2151,26 @@ set_unix_mode (char *filename,
if (!get_uint32 (value, &val, error))
return FALSE;
-#ifdef HAVE_SYMLINK
+#if defined (HAVE_SYMLINK) || defined (G_OS_WIN32)
if (flags & G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS) {
#ifdef HAVE_LCHMOD
res = lchmod (filename, val);
#else
+ gboolean is_symlink;
+#ifndef G_OS_WIN32
struct stat statbuf;
/* Calling chmod on a symlink changes permissions on the symlink.
* We don't want to do this, so we need to check for a symlink */
res = g_lstat (filename, &statbuf);
- if (res == 0 && S_ISLNK (statbuf.st_mode))
+ is_symlink = (res == 0 && S_ISLNK (statbuf.st_mode));
+#else
+ /* FIXME: implement lchmod for W32, should be doable */
+ GWin32PrivateStat statbuf;
+
+ res = GLIB_PRIVATE_CALL (g_win32_lstat_utf8) (filename, &statbuf);
+ is_symlink = (res == 0 && statbuf.reparse_tag == IO_REPARSE_TAG_SYMLINK);
+#endif
+ if (is_symlink)
{
g_set_error_literal (error, G_IO_ERROR,
G_IO_ERROR_NOT_SUPPORTED,
diff --git a/gio/glocalfileinfo.h b/gio/glocalfileinfo.h
index f0362889f..a231c24ca 100644
--- a/gio/glocalfileinfo.h
+++ b/gio/glocalfileinfo.h
@@ -23,6 +23,7 @@
#include <gio/gfileinfo.h>
#include <gio/gfile.h>
+#include <glib/gstdioprivate.h>
#include <sys/stat.h>
#include <sys/types.h>
@@ -40,8 +41,8 @@ typedef struct
} GLocalParentFileInfo;
#ifdef G_OS_WIN32
-/* We want 64-bit file size support */
-#define GLocalFileStat struct _stati64
+/* We want 64-bit file size, file ID and symlink support */
+#define GLocalFileStat GWin32PrivateStat
#else
#define GLocalFileStat struct stat
#endif
diff --git a/gio/glocalfileoutputstream.c b/gio/glocalfileoutputstream.c
index 76005716f..57d2d5dfe 100644
--- a/gio/glocalfileoutputstream.c
+++ b/gio/glocalfileoutputstream.c
@@ -40,6 +40,8 @@
#include "gfiledescriptorbased.h"
#endif
+#include "glib-private.h"
+
#ifdef G_OS_WIN32
#include <io.h>
#ifndef S_ISDIR
@@ -234,7 +236,7 @@ _g_local_file_output_stream_really_close (GLocalFileOutputStream *file,
/* Must close before renaming on Windows, so just do the close first
* in all cases for now.
*/
- if (_fstati64 (file->priv->fd, &final_stat) == 0)
+ if (GLIB_PRIVATE_CALL (g_win32_fstat) (file->priv->fd, &final_stat) == 0)
file->priv->etag = _g_local_file_info_create_etag (&final_stat);
if (!g_close (file->priv->fd, NULL))
@@ -797,7 +799,7 @@ handle_overwrite_open (const char *filename,
}
#ifdef G_OS_WIN32
- res = _fstati64 (fd, &original_stat);
+ res = GLIB_PRIVATE_CALL (g_win32_fstat) (fd, &original_stat);
#else
res = fstat (fd, &original_stat);
#endif
@@ -891,7 +893,7 @@ handle_overwrite_open (const char *filename,
int tres;
#ifdef G_OS_WIN32
- tres = _fstati64 (tmpfd, &tmp_statbuf);
+ tres = GLIB_PRIVATE_CALL (g_win32_fstat) (tmpfd, &tmp_statbuf);
#else
tres = fstat (tmpfd, &tmp_statbuf);
#endif
diff --git a/gio/gmount.c b/gio/gmount.c
index 3d74b855d..0169ea54b 100644
--- a/gio/gmount.c
+++ b/gio/gmount.c
@@ -54,9 +54,9 @@
* g_mount_unmount_with_operation() with (at least) the #GMount instance and a
* #GAsyncReadyCallback. The callback will be fired when the
* operation has resolved (either with success or failure), and a
- * #GAsyncReady structure will be passed to the callback. That
+ * #GAsyncResult structure will be passed to the callback. That
* callback should then call g_mount_unmount_with_operation_finish() with the #GMount
- * and the #GAsyncReady data to see if the operation was completed
+ * and the #GAsyncResult data to see if the operation was completed
* successfully. If an @error is present when g_mount_unmount_with_operation_finish()
* is called, then it will be filled with any error information.
**/
@@ -101,9 +101,12 @@ g_mount_default_init (GMountInterface *iface)
* GMount::pre-unmount:
* @mount: the object on which the signal is emitted
*
- * This signal is emitted when the #GMount is about to be
+ * This signal may be emitted when the #GMount is about to be
* unmounted.
*
+ * This signal depends on the backend and is only emitted if
+ * GIO was used to unmount.
+ *
* Since: 2.22
**/
g_signal_new (I_("pre-unmount"),
diff --git a/gio/gopenuriportal.c b/gio/gopenuriportal.c
index 247ed8ce7..51a72dfc2 100644
--- a/gio/gopenuriportal.c
+++ b/gio/gopenuriportal.c
@@ -197,8 +197,7 @@ open_call_done (GObject *source,
GAsyncResult *result,
gpointer user_data)
{
- GXdpOpenURI *openuri = GXDP_OPEN_URI (source);
- GDBusConnection *connection;
+ GDBusConnection *connection = G_DBUS_CONNECTION (source);
GTask *task = user_data;
GError *error = NULL;
gboolean open_file;
@@ -207,7 +206,6 @@ open_call_done (GObject *source,
const char *handle;
guint signal_id;
- connection = g_dbus_proxy_get_connection (G_DBUS_PROXY (openuri));
open_file = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (task), "open-file"));
if (open_file)
diff --git a/gio/gosxappinfo.c b/gio/gosxappinfo.c
index b24b6fffa..463b2da3c 100644
--- a/gio/gosxappinfo.c
+++ b/gio/gosxappinfo.c
@@ -171,19 +171,26 @@ create_cfstring_from_cstr (const gchar *cstr)
return CFStringCreateWithCString (NULL, cstr, kCFStringEncodingUTF8);
}
+#ifdef G_ENABLE_DEBUG
static gchar *
create_cstr_from_cfstring (CFStringRef str)
{
- const gchar *cstr;
+ g_return_val_if_fail (str != NULL, NULL);
- if (str == NULL)
- return NULL;
-
- cstr = CFStringGetCStringPtr (str, kCFStringEncodingUTF8);
- CFRelease (str);
-
- return g_strdup (cstr);
+ CFIndex length = CFStringGetLength (str);
+ CFIndex maxlen = CFStringGetMaximumSizeForEncoding (length, kCFStringEncodingUTF8);
+ gchar *buffer = g_malloc (maxlen + 1);
+ Boolean success = CFStringGetCString (str, (char *) buffer, maxlen,
+ kCFStringEncodingUTF8);
+ if (success)
+ return buffer;
+ else
+ {
+ g_free (buffer);
+ return NULL;
+ }
}
+#endif
static char *
url_escape_hostname (const char *url)
@@ -328,13 +335,18 @@ get_bundle_for_id (CFStringRef bundle_id)
}
else
#else
- if (LSFindApplicationForInfo (kLSUnknownCreator, bundle_id, NULL, NULL, &app_url))
+ if (LSFindApplicationForInfo (kLSUnknownCreator, bundle_id, NULL, NULL, &app_url) == kLSApplicationNotFoundErr)
#endif
{
#ifdef G_ENABLE_DEBUG /* This can fail often, no reason to alloc strings */
gchar *id_str = create_cstr_from_cfstring (bundle_id);
- g_debug ("Application not found for id \"%s\".", id_str);
- g_free (id_str);
+ if (id_str)
+ {
+ g_debug ("Application not found for id \"%s\".", id_str);
+ g_free (id_str);
+ }
+ else
+ g_debug ("Application not found for unconvertable bundle id.");
#endif
return NULL;
}
@@ -594,7 +606,7 @@ g_osx_app_info_get_all_for_scheme (const char *cscheme)
info = G_APP_INFO (g_osx_app_info_new (bundle));
info_list = g_list_append (info_list, info);
}
-
+ CFRelease (bundle_list);
return info_list;
}
@@ -639,7 +651,7 @@ g_app_info_get_all_for_type (const char *content_type)
info = G_APP_INFO (g_osx_app_info_new (bundle));
info_list = g_list_append (info_list, info);
}
-
+ CFRelease (bundle_list);
return info_list;
}
diff --git a/gio/gosxcontenttype.c b/gio/gosxcontenttype.c
index 485f5bfb6..347477577 100644
--- a/gio/gosxcontenttype.c
+++ b/gio/gosxcontenttype.c
@@ -25,6 +25,12 @@
#include <CoreServices/CoreServices.h>
+#define XDG_PREFIX _gio_xdg
+#include "xdgmime/xdgmime.h"
+
+/* We lock this mutex whenever we modify global state in this module. */
+G_LOCK_DEFINE_STATIC (gio_xdgmime);
+
/*< internal >
* create_cfstring_from_cstr:
@@ -52,15 +58,21 @@ create_cfstring_from_cstr (const gchar *cstr)
static gchar *
create_cstr_from_cfstring (CFStringRef str)
{
- const gchar *cstr;
-
- if (str == NULL)
- return NULL;
+ g_return_val_if_fail (str != NULL, NULL);
- cstr = CFStringGetCStringPtr (str, kCFStringEncodingUTF8);
+ CFIndex length = CFStringGetLength (str);
+ CFIndex maxlen = CFStringGetMaximumSizeForEncoding (length, kCFStringEncodingUTF8);
+ gchar *buffer = g_malloc (maxlen + 1);
+ Boolean success = CFStringGetCString (str, (char *) buffer, maxlen,
+ kCFStringEncodingUTF8);
CFRelease (str);
-
- return g_strdup (cstr);
+ if (success)
+ return buffer;
+ else
+ {
+ g_free (buffer);
+ return NULL;
+ }
}
/*< internal >
@@ -78,9 +90,10 @@ static gchar *
create_cstr_from_cfstring_with_fallback (CFStringRef str,
const gchar *fallback)
{
- gchar *cstr;
+ gchar *cstr = NULL;
- cstr = create_cstr_from_cfstring (str);
+ if (str)
+ cstr = create_cstr_from_cfstring (str);
if (!cstr)
return g_strdup (fallback);
@@ -180,25 +193,59 @@ g_content_type_get_description (const gchar *type)
}
static GIcon *
-g_content_type_get_icon_internal (const gchar *type,
+g_content_type_get_icon_internal (const gchar *uti,
gboolean symbolic)
{
- GIcon *icon = NULL;
- gchar *name;
+ char *mimetype_icon;
+ char *type;
+ char *generic_mimetype_icon = NULL;
+ char *q;
+ char *icon_names[6];
+ int n = 0;
+ GIcon *themed_icon;
+ const char *xdg_icon;
+ int i;
- g_return_val_if_fail (type != NULL, NULL);
+ g_return_val_if_fail (uti != NULL, NULL);
- /* TODO: Show mimetype icons. */
- if (g_content_type_can_be_executable (type))
- name = "gtk-execute";
- else if (g_content_type_is_a (type, "public.directory"))
- name = symbolic ? "inode-directory-symbolic" : "inode-directory";
- else
- name = "gtk-file";
+ type = g_content_type_get_mime_type (uti);
+
+ G_LOCK (gio_xdgmime);
+ xdg_icon = xdg_mime_get_icon (type);
+ G_UNLOCK (gio_xdgmime);
+
+ if (xdg_icon)
+ icon_names[n++] = g_strdup (xdg_icon);
- icon = g_themed_icon_new_with_default_fallbacks (name);
+ mimetype_icon = g_strdup (type);
+ while ((q = strchr (mimetype_icon, '/')) != NULL)
+ *q = '-';
- return icon;
+ icon_names[n++] = mimetype_icon;
+
+ generic_mimetype_icon = g_content_type_get_generic_icon_name (type);
+ if (generic_mimetype_icon)
+ icon_names[n++] = generic_mimetype_icon;
+
+ if (symbolic)
+ {
+ for (i = 0; i < n; i++)
+ {
+ icon_names[n + i] = icon_names[i];
+ icon_names[i] = g_strconcat (icon_names[i], "-symbolic", NULL);
+ }
+
+ n += n;
+ }
+
+ themed_icon = g_themed_icon_new_from_names (icon_names, n);
+
+ for (i = 0; i < n; i++)
+ g_free (icon_names[i]);
+
+ g_free(type);
+
+ return themed_icon;
}
GIcon *
@@ -429,7 +476,17 @@ g_content_type_guess (const gchar *filename,
if (data && (!filename || !uti ||
CFStringCompare (uti, CFSTR ("public.data"), 0) == kCFCompareEqualTo))
{
- if (looks_like_text (data, data_size))
+ const char *sniffed_mimetype;
+ G_LOCK (gio_xdgmime);
+ sniffed_mimetype = xdg_mime_get_mime_type_for_data (data, data_size, NULL);
+ G_UNLOCK (gio_xdgmime);
+ if (sniffed_mimetype != XDG_MIME_TYPE_UNKNOWN)
+ {
+ gchar *uti_str = g_content_type_from_mime_type (sniffed_mimetype);
+ uti = create_cfstring_from_cstr (uti_str);
+ g_free (uti_str);
+ }
+ if (!uti && looks_like_text (data, data_size))
{
if (g_str_has_prefix ((const gchar*)data, "#!/"))
uti = CFStringCreateCopy (NULL, CFSTR ("public.script"));
diff --git a/gio/goutputstream.c b/gio/goutputstream.c
index c59eb67e0..6372fd9c9 100644
--- a/gio/goutputstream.c
+++ b/gio/goutputstream.c
@@ -234,7 +234,7 @@ g_output_stream_write (GOutputStream *stream,
* @stream: a #GOutputStream.
* @buffer: (array length=count) (element-type guint8): the buffer containing the data to write.
* @count: the number of bytes to write
- * @bytes_written: (out): location to store the number of bytes that was
+ * @bytes_written: (out) (optional): location to store the number of bytes that was
* written to the stream
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @error: location to store the error occurring, or %NULL to ignore
@@ -302,7 +302,7 @@ g_output_stream_write_all (GOutputStream *stream,
/**
* g_output_stream_printf:
* @stream: a #GOutputStream.
- * @bytes_written: (out): location to store the number of bytes that was
+ * @bytes_written: (out) (optional): location to store the number of bytes that was
* written to the stream
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @error: location to store the error occurring, or %NULL to ignore
@@ -348,7 +348,7 @@ g_output_stream_printf (GOutputStream *stream,
/**
* g_output_stream_vprintf:
* @stream: a #GOutputStream.
- * @bytes_written: (out): location to store the number of bytes that was
+ * @bytes_written: (out) (optional): location to store the number of bytes that was
* written to the stream
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @error: location to store the error occurring, or %NULL to ignore
@@ -384,7 +384,7 @@ g_output_stream_vprintf (GOutputStream *stream,
gboolean success;
g_return_val_if_fail (G_IS_OUTPUT_STREAM (stream), FALSE);
- g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE);
+ g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (stream), FALSE);
g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
g_return_val_if_fail (format != NULL, FALSE);
@@ -1019,7 +1019,7 @@ g_output_stream_write_all_async (GOutputStream *stream,
* g_output_stream_write_all_finish:
* @stream: a #GOutputStream
* @result: a #GAsyncResult
- * @bytes_written: (out): location to store the number of bytes that was written to the stream
+ * @bytes_written: (out) (optional): location to store the number of bytes that was written to the stream
* @error: a #GError location to store the error occurring, or %NULL to ignore.
*
* Finishes an asynchronous stream write operation started with
diff --git a/gio/gpollfilemonitor.c b/gio/gpollfilemonitor.c
index da7f1c5fa..411e00393 100644
--- a/gio/gpollfilemonitor.c
+++ b/gio/gpollfilemonitor.c
@@ -145,7 +145,8 @@ poll_file_timeout (gpointer data)
{
GPollFileMonitor* poll_monitor = data;
- poll_monitor->timeout = FALSE;
+ g_source_unref (poll_monitor->timeout);
+ poll_monitor->timeout = NULL;
g_file_query_info_async (poll_monitor->file, G_FILE_ATTRIBUTE_ETAG_VALUE "," G_FILE_ATTRIBUTE_STANDARD_SIZE,
0, 0, NULL, got_new_info, g_object_ref (poll_monitor));
diff --git a/gio/gresource.c b/gio/gresource.c
index ed0e474a4..8ead26bc6 100644
--- a/gio/gresource.c
+++ b/gio/gresource.c
@@ -525,7 +525,8 @@ g_resource_new_from_table (GvdbTable *table)
* to register it with g_resources_register().
*
* Note: @data must be backed by memory that is at least pointer aligned.
- * Otherwise this function will fail and exit the process.
+ * Otherwise this function will internally create a copy of the memory since
+ * GLib 2.56, or in older versions fail and exit the process.
*
* Returns: (transfer full): a new #GResource, or %NULL on error
*
@@ -536,6 +537,14 @@ g_resource_new_from_data (GBytes *data,
GError **error)
{
GvdbTable *table;
+ gboolean unref_data = FALSE;
+
+ if (((guintptr) g_bytes_get_data (data, NULL)) % sizeof (gpointer) != 0)
+ {
+ data = g_bytes_new (g_bytes_get_data (data, NULL),
+ g_bytes_get_size (data));
+ unref_data = TRUE;
+ }
table = gvdb_table_new_from_data (g_bytes_get_data (data, NULL),
g_bytes_get_size (data),
@@ -545,6 +554,9 @@ g_resource_new_from_data (GBytes *data,
(GDestroyNotify)g_bytes_unref,
error);
+ if (unref_data)
+ g_bytes_unref (data);
+
if (table == NULL)
return NULL;
@@ -850,9 +862,17 @@ g_resource_enumerate_children (GResource *resource,
GResourceLookupFlags lookup_flags,
GError **error)
{
+ gchar local_str[256];
+ const gchar *path_with_slash;
gchar **children;
+ gchar *free_path = NULL;
gsize path_len;
- char *path_with_slash;
+
+ /*
+ * Size of 256 is arbitrarily chosen based on being large enough
+ * for pretty much everything we come across, but not cumbersome
+ * on the stack. It also matches common cacheline sizes.
+ */
if (*path == 0)
{
@@ -863,13 +883,35 @@ g_resource_enumerate_children (GResource *resource,
}
path_len = strlen (path);
- if (path[path_len-1] != '/')
- path_with_slash = g_strconcat (path, "/", NULL);
+
+ if G_UNLIKELY (path[path_len-1] != '/')
+ {
+ if (path_len < sizeof (local_str) - 2)
+ {
+ /*
+ * We got a path that does not have a trailing /. It is not the
+ * ideal use of this API as we require trailing / for our lookup
+ * into gvdb. Some degenerate application configurations can hit
+ * this code path quite a bit, so we try to avoid using the
+ * g_strconcat()/g_free().
+ */
+ memcpy (local_str, path, path_len);
+ local_str[path_len] = '/';
+ local_str[path_len+1] = 0;
+ path_with_slash = local_str;
+ }
+ else
+ {
+ path_with_slash = free_path = g_strconcat (path, "/", NULL);
+ }
+ }
else
- path_with_slash = g_strdup (path);
+ {
+ path_with_slash = path;
+ }
children = gvdb_table_list (resource->table, path_with_slash);
- g_free (path_with_slash);
+ g_free (free_path);
if (children == NULL)
{
diff --git a/gio/gresourcefile.c b/gio/gresourcefile.c
index 739c6e2f1..429e9ef49 100644
--- a/gio/gresourcefile.c
+++ b/gio/gresourcefile.c
@@ -138,69 +138,92 @@ g_resource_file_init (GResourceFile *resource)
{
}
-static char *
-canonicalize_filename (const char *filename)
+static inline gchar *
+scan_backwards (const gchar *begin,
+ const gchar *end,
+ gchar c)
{
- char *canon, *start, *p, *q;
+ while (end >= begin)
+ {
+ if (*end == c)
+ return (gchar *)end;
+ end--;
+ }
- /* Skip multiple inital slashes */
- while (filename[0] == '/' && filename[1] == '/')
- filename++;
+ return NULL;
+}
- if (*filename != '/')
- canon = g_strconcat ("/", filename, NULL);
- else
- canon = g_strdup (filename);
+static inline void
+pop_to_previous_part (const gchar *begin,
+ gchar **out)
+{
+ if (*out > begin)
+ *out = scan_backwards (begin, *out - 1, '/');
+}
+
+/*
+ * canonicalize_filename:
+ * @in: the path to be canonicalized
+ *
+ * The path @in may contain non-canonical path pieces such as "../"
+ * or duplicated "/". This will resolve those into a form that only
+ * contains a single / at a time and resolves all "../". The resulting
+ * path must also start with a /.
+ *
+ * Returns: the canonical form of the path
+ */
+static char *
+canonicalize_filename (const char *in)
+{
+ gchar *bptr;
+ char *out;
- start = canon + 1;
+ bptr = out = g_malloc (strlen (in) + 2);
+ *out = '/';
- p = start;
- while (*p != 0)
+ while (*in != 0)
{
- if (p[0] == '.' && (p[1] == 0 || p[1] == '/'))
- {
- memmove (p, p+1, strlen (p+1)+1);
- }
- else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || p[2] == '/'))
- {
- q = p + 2;
- /* Skip previous separator */
- p = p - 2;
- if (p < start)
- p = start;
- while (p > start && *p != '/')
- p--;
- if (*p == '/')
- *p++ = '/';
- memmove (p, q, strlen (q)+1);
- }
- else
- {
- /* Skip until next separator */
- while (*p != 0 && *p != '/')
- p++;
+ g_assert (*out == '/');
- if (*p != 0)
- {
- /* Canonicalize one separator */
- *p++ = '/';
- }
- }
+ /* move past slashes */
+ while (*in == '/')
+ in++;
+
+ /* Handle ./ ../ .\0 ..\0 */
+ if (*in == '.')
+ {
+ /* If this is ../ or ..\0 move up */
+ if (in[1] == '.' && (in[2] == '/' || in[2] == 0))
+ {
+ pop_to_previous_part (bptr, &out);
+ in += 2;
+ continue;
+ }
+
+ /* If this is ./ skip past it */
+ if (in[1] == '/' || in[1] == 0)
+ {
+ in += 1;
+ continue;
+ }
+ }
- /* Remove additional separators */
- q = p;
- while (*q && *q == '/')
- q++;
+ /* Scan to the next path piece */
+ while (*in != 0 && *in != '/')
+ *(++out) = *(in++);
- if (p != q)
- memmove (p, q, strlen (q)+1);
+ /* Add trailing /, compress the rest on the next go round. */
+ if (*in == '/')
+ *(++out) = *(in++);
}
- /* Remove trailing slashes */
- if (p > start && *(p-1) == '/')
- *(p-1) = 0;
+ /* Trim trailing / from path */
+ if (out > bptr && *out == '/')
+ *out = 0;
+ else
+ *(++out) = 0;
- return canon;
+ return bptr;
}
static GFile *
diff --git a/gio/gschema.dtd b/gio/gschema.dtd
index 8cd552d4a..00e3a1653 100644
--- a/gio/gschema.dtd
+++ b/gio/gschema.dtd
@@ -1,4 +1,4 @@
-<!ELEMENT schemalist (schema|enum|flags)* >
+<!ELEMENT schemalist (schema|enum)* >
<!ATTLIST schemalist gettext-domain CDATA #IMPLIED >
<!ELEMENT schema (key|child|override)* >
@@ -47,8 +47,7 @@
<!-- range is only allowed for keys with numeric type -->
<!ELEMENT range EMPTY >
-<!-- min and max must be parseable as values of the key type and
- min must be less than or equal to max -->
+<!-- min and max must be parseable as values of the key type and min < max -->
<!ATTLIST range min CDATA #REQUIRED
max CDATA #REQUIRED >
diff --git a/gio/gseekable.c b/gio/gseekable.c
index 26159d07e..5237e7f2f 100644
--- a/gio/gseekable.c
+++ b/gio/gseekable.c
@@ -141,7 +141,8 @@ g_seekable_seek (GSeekable *seekable,
* g_seekable_can_truncate:
* @seekable: a #GSeekable.
*
- * Tests if the stream can be truncated.
+ * Tests if the length of the stream can be adjusted with
+ * g_seekable_truncate().
*
* Returns: %TRUE if the stream can be truncated, %FALSE otherwise.
**/
@@ -158,14 +159,16 @@ g_seekable_can_truncate (GSeekable *seekable)
}
/**
- * g_seekable_truncate:
+ * g_seekable_truncate: (virtual truncate_fn)
* @seekable: a #GSeekable.
- * @offset: a #goffset.
+ * @offset: new length for @seekable, in bytes.
* @cancellable: (nullable): optional #GCancellable object, %NULL to ignore.
* @error: a #GError location to store the error occurring, or %NULL to
* ignore.
*
- * Truncates a stream with a given #offset.
+ * Sets the length of the stream to @offset. If the stream was previously
+ * larger than @offset, the extra data is discarded. If the stream was
+ * previouly shorter than @offset, it is extended with NUL ('\0') bytes.
*
* If @cancellable is not %NULL, then the operation can be cancelled by
* triggering the cancellable object from another thread. If the operation
@@ -173,7 +176,6 @@ g_seekable_can_truncate (GSeekable *seekable)
* operation was partially finished when the operation was cancelled the
* partial result will be returned, without an error.
*
- * Virtual: truncate_fn
* Returns: %TRUE if successful. If an error
* has occurred, this function will return %FALSE and set @error
* appropriately if present.
diff --git a/gio/gsettings.c b/gio/gsettings.c
index 45b10dd7e..7b0b6a162 100644
--- a/gio/gsettings.c
+++ b/gio/gsettings.c
@@ -830,7 +830,7 @@ g_settings_class_init (GSettingsClass *class)
NULL, G_TYPE_BOOLEAN, 1, G_TYPE_UINT);
/**
- * GSettings:context:
+ * GSettings:backend:
*
* The name of the context that the settings are stored in.
*/
@@ -2767,7 +2767,7 @@ g_settings_bind_invert_boolean_set_mapping (const GValue *value,
* a boolean property by that name). See g_settings_bind_writable()
* for more details about writable bindings.
*
- * Note that the lifecycle of the binding is tied to the object,
+ * Note that the lifecycle of the binding is tied to @object,
* and that you can have only one binding per object property.
* If you bind the same property twice on the same object, the second
* binding overrides the first one.
@@ -2817,7 +2817,7 @@ g_settings_bind (GSettings *settings,
* The binding uses the provided mapping functions to map between
* settings and property values.
*
- * Note that the lifecycle of the binding is tied to the object,
+ * Note that the lifecycle of the binding is tied to @object,
* and that you can have only one binding per object property.
* If you bind the same property twice on the same object, the second
* binding overrides the first one.
@@ -3034,7 +3034,7 @@ g_settings_binding_writable_changed (GSettings *settings,
* value as it passes from the setting to the object, i.e. @property
* will be set to %TRUE if the key is not writable.
*
- * Note that the lifecycle of the binding is tied to the object,
+ * Note that the lifecycle of the binding is tied to @object,
* and that you can have only one binding per object property.
* If you bind the same property twice on the same object, the second
* binding overrides the first one.
diff --git a/gio/gsettingsbackend.c b/gio/gsettingsbackend.c
index 0d5df0f82..edc4ff4d3 100644
--- a/gio/gsettingsbackend.c
+++ b/gio/gsettingsbackend.c
@@ -70,12 +70,12 @@ static gboolean g_settings_has_backend;
* implementations must carefully adhere to the expectations of
* callers that are documented on each of the interface methods.
*
- * Some of the GSettingsBackend functions accept or return a #GTree.
+ * Some of the #GSettingsBackend functions accept or return a #GTree.
* These trees always have strings as keys and #GVariant as values.
* g_settings_backend_create_tree() is a convenience function to create
* suitable trees.
*
- * The GSettingsBackend API is exported to allow third-party
+ * The #GSettingsBackend API is exported to allow third-party
* implementations, but does not carry the same stability guarantees
* as the public GIO API. For this reason, you have to define the
* C preprocessor symbol %G_SETTINGS_ENABLE_BACKEND before including
diff --git a/gio/gsettingsschema.c b/gio/gsettingsschema.c
index bc7a4ac84..4e12243d8 100644
--- a/gio/gsettingsschema.c
+++ b/gio/gsettingsschema.c
@@ -68,7 +68,7 @@
* ...
*
* plugin->schema_source =
- * g_settings_new_schema_source_from_directory (dir,
+ * g_settings_schema_source_new_from_directory (dir,
* g_settings_schema_source_get_default (), FALSE, NULL);
*
* ...
@@ -376,11 +376,11 @@ initialise_schema_sources (void)
* lookups performed against the default source should probably be done
* recursively.
*
- * Returns: (transfer none): the default schema source
+ * Returns: (transfer none) (nullable): the default schema source
*
* Since: 2.32
**/
- GSettingsSchemaSource *
+GSettingsSchemaSource *
g_settings_schema_source_get_default (void)
{
initialise_schema_sources ();
@@ -785,18 +785,21 @@ g_settings_schema_source_list_schemas (GSettingsSchemaSource *source,
for (i = 0; list[i]; i++)
{
- if (!g_hash_table_lookup (single, list[i]) &&
- !g_hash_table_lookup (reloc, list[i]))
+ if (!g_hash_table_contains (single, list[i]) &&
+ !g_hash_table_contains (reloc, list[i]))
{
+ gchar *schema;
GvdbTable *table;
+ schema = g_strdup (list[i]);
+
table = gvdb_table_get_table (s->table, list[i]);
g_assert (table != NULL);
if (gvdb_table_has_value (table, ".path"))
- g_hash_table_insert (single, g_strdup (list[i]), NULL);
+ g_hash_table_add (single, schema);
else
- g_hash_table_insert (reloc, g_strdup (list[i]), NULL);
+ g_hash_table_add (reloc, schema);
gvdb_table_unref (table);
}
diff --git a/gio/gsimpleasyncresult.c b/gio/gsimpleasyncresult.c
index 7883463b8..c6ddd9771 100644
--- a/gio/gsimpleasyncresult.c
+++ b/gio/gsimpleasyncresult.c
@@ -84,9 +84,10 @@
* from the point where it is called. g_simple_async_result_complete_in_idle()
* will finish it from an idle handler in the
* [thread-default main context][g-main-context-push-thread-default]
- * . g_simple_async_result_run_in_thread() will run the
- * job in a separate thread and then deliver the result to the
- * thread-default main context.
+ * where the #GSimpleAsyncResult was created.
+ * g_simple_async_result_run_in_thread() will run the job in a
+ * separate thread and then use
+ * g_simple_async_result_complete_in_idle() to deliver the result.
*
* To set the results of an asynchronous function,
* g_simple_async_result_set_op_res_gpointer(),
diff --git a/gio/gsocket.c b/gio/gsocket.c
index ba90be54b..567b4802e 100644
--- a/gio/gsocket.c
+++ b/gio/gsocket.c
@@ -44,6 +44,10 @@
# include <sys/ioctl.h>
#endif
+#ifdef HAVE_SIOCGIFADDR
+#include <net/if.h>
+#endif
+
#ifdef HAVE_SYS_FILIO_H
# include <sys/filio.h>
#endif
@@ -59,6 +63,7 @@
#include "gdatagrambased.h"
#include "gioenumtypes.h"
#include "ginetaddress.h"
+#include "ginetsocketaddress.h"
#include "ginitable.h"
#include "gioerror.h"
#include "gioenums.h"
@@ -252,11 +257,14 @@ struct _GSocketPrivate
guint connect_pending : 1;
#ifdef G_OS_WIN32
WSAEVENT event;
+ gboolean waiting;
+ DWORD waiting_result;
int current_events;
int current_errors;
int selected_events;
GList *requested_conditions; /* list of requested GIOCondition * */
GMutex win32_source_lock;
+ GCond win32_source_cond;
#endif
struct {
@@ -343,8 +351,10 @@ socket_strerror (int err)
static void
_win32_unset_event_mask (GSocket *socket, int mask)
{
+ g_mutex_lock (&socket->priv->win32_source_lock);
socket->priv->current_events &= ~mask;
socket->priv->current_errors &= ~mask;
+ g_mutex_unlock (&socket->priv->win32_source_lock);
}
#else
#define win32_unset_event_mask(_socket, _mask)
@@ -842,6 +852,7 @@ g_socket_finalize (GObject *object)
g_assert (socket->priv->requested_conditions == NULL);
g_mutex_clear (&socket->priv->win32_source_lock);
+ g_cond_clear (&socket->priv->win32_source_cond);
#endif
for (i = 0; i < RECV_ADDR_CACHE_SIZE; i++)
@@ -1069,6 +1080,7 @@ g_socket_init (GSocket *socket)
#ifdef G_OS_WIN32
socket->priv->event = WSA_INVALID_EVENT;
g_mutex_init (&socket->priv->win32_source_lock);
+ g_cond_init (&socket->priv->win32_source_cond);
#endif
}
@@ -1945,7 +1957,7 @@ g_socket_get_local_address (GSocket *socket,
* @socket: a #GSocket.
* @error: #GError for error reporting, or %NULL to ignore.
*
- * Try to get the remove address of a connected socket. This is only
+ * Try to get the remote address of a connected socket. This is only
* useful for connection oriented sockets that have been connected.
*
* Returns: (transfer full): a #GSocketAddress or %NULL on error.
@@ -2148,63 +2160,6 @@ g_socket_bind (GSocket *socket,
return TRUE;
}
-#if !defined(HAVE_IF_NAMETOINDEX) && defined(G_OS_WIN32)
-static guint
-if_nametoindex (const gchar *iface)
-{
- PIP_ADAPTER_ADDRESSES addresses = NULL, p;
- gulong addresses_len = 0;
- guint idx = 0;
- DWORD res;
-
- if (ws2funcs.pIfNameToIndex != NULL)
- return ws2funcs.pIfNameToIndex (iface);
-
- res = GetAdaptersAddresses (AF_UNSPEC, 0, NULL, NULL, &addresses_len);
- if (res != NO_ERROR && res != ERROR_BUFFER_OVERFLOW)
- {
- if (res == ERROR_NO_DATA)
- errno = ENXIO;
- else
- errno = EINVAL;
- return 0;
- }
-
- addresses = g_malloc (addresses_len);
- res = GetAdaptersAddresses (AF_UNSPEC, 0, NULL, addresses, &addresses_len);
-
- if (res != NO_ERROR)
- {
- g_free (addresses);
- if (res == ERROR_NO_DATA)
- errno = ENXIO;
- else
- errno = EINVAL;
- return 0;
- }
-
- p = addresses;
- while (p)
- {
- if (strcmp (p->AdapterName, iface) == 0)
- {
- idx = p->IfIndex;
- break;
- }
- p = p->Next;
- }
-
- if (p == NULL)
- errno = ENXIO;
-
- g_free (addresses);
-
- return idx;
-}
-
-#define HAVE_IF_NAMETOINDEX 1
-#endif
-
static gboolean
g_socket_multicast_group_operation (GSocket *socket,
GInetAddress *group,
@@ -2322,6 +2277,9 @@ g_socket_multicast_group_operation (GSocket *socket,
* in RFC 4604 is used. Note that on older platforms this may fail
* with a %G_IO_ERROR_NOT_SUPPORTED error.
*
+ * To bind to a given source-specific multicast address, use
+ * g_socket_join_multicast_group_ssm() instead.
+ *
* Returns: %TRUE on success, %FALSE on error.
*
* Since: 2.32
@@ -2351,6 +2309,9 @@ g_socket_join_multicast_group (GSocket *socket,
* @socket remains bound to its address and port, and can still receive
* unicast messages after calling this.
*
+ * To unbind to a given source-specific multicast address, use
+ * g_socket_leave_multicast_group_ssm() instead.
+ *
* Returns: %TRUE on success, %FALSE on error.
*
* Since: 2.32
@@ -2365,6 +2326,282 @@ g_socket_leave_multicast_group (GSocket *socket,
return g_socket_multicast_group_operation (socket, group, source_specific, iface, FALSE, error);
}
+static gboolean
+g_socket_multicast_group_operation_ssm (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *source_specific,
+ const gchar *iface,
+ gboolean join_group,
+ GError **error)
+{
+ gint result;
+
+ g_return_val_if_fail (G_IS_SOCKET (socket), FALSE);
+ g_return_val_if_fail (socket->priv->type == G_SOCKET_TYPE_DATAGRAM, FALSE);
+ g_return_val_if_fail (G_IS_INET_ADDRESS (group), FALSE);
+ g_return_val_if_fail (iface == NULL || *iface != '\0', FALSE);
+ g_return_val_if_fail (error == NULL || *error == NULL, FALSE);
+
+ if (!source_specific)
+ {
+ return g_socket_multicast_group_operation (socket, group, FALSE, iface,
+ join_group, error);
+ }
+
+ if (!check_socket (socket, error))
+ return FALSE;
+
+ switch (g_inet_address_get_family (group))
+ {
+ case G_SOCKET_FAMILY_INVALID:
+ case G_SOCKET_FAMILY_UNIX:
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ join_group ?
+ _("Error joining multicast group: %s") :
+ _("Error leaving multicast group: %s"),
+ _("Unsupported socket family"));
+ return FALSE;
+ }
+ break;
+
+ case G_SOCKET_FAMILY_IPV4:
+ {
+#ifdef IP_ADD_SOURCE_MEMBERSHIP
+ gint optname;
+ struct ip_mreq_source mc_req_src;
+
+ if (g_inet_address_get_family (source_specific) !=
+ G_SOCKET_FAMILY_IPV4)
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ join_group ?
+ _("Error joining multicast group: %s") :
+ _("Error leaving multicast group: %s"),
+ _("source-specific not an IPv4 address"));
+ return FALSE;
+ }
+
+ memset (&mc_req_src, 0, sizeof (mc_req_src));
+
+ /* By default use the default IPv4 multicast interface. */
+ mc_req_src.imr_interface.s_addr = g_htonl (INADDR_ANY);
+
+ if (iface)
+ {
+#if defined(G_OS_WIN32) && defined (HAVE_IF_NAMETOINDEX)
+ guint iface_index = if_nametoindex (iface);
+ if (iface_index == 0)
+ {
+ int errsv = errno;
+
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+ _("Interface not found: %s"), g_strerror (errsv));
+ return FALSE;
+ }
+ /* (0.0.0.iface_index) only works on Windows. */
+ mc_req_src.imr_interface.s_addr = g_htonl (iface_index);
+#elif defined (HAVE_SIOCGIFADDR)
+ int ret;
+ struct ifreq ifr;
+ struct sockaddr_in *iface_addr;
+ size_t if_name_len = strlen (iface);
+
+ memset (&ifr, 0, sizeof (ifr));
+
+ if (if_name_len >= sizeof (ifr.ifr_name))
+ {
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_FILENAME_TOO_LONG,
+ _("Interface name too long"));
+ return FALSE;
+ }
+
+ memcpy (ifr.ifr_name, iface, if_name_len);
+
+ /* Get the IPv4 address of the given network interface name. */
+ ret = ioctl (socket->priv->fd, SIOCGIFADDR, &ifr);
+ if (ret < 0)
+ {
+ int errsv = errno;
+
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+ _("Interface not found: %s"), g_strerror (errsv));
+ return FALSE;
+ }
+
+ iface_addr = (struct sockaddr_in *) &ifr.ifr_addr;
+ mc_req_src.imr_interface.s_addr = iface_addr->sin_addr.s_addr;
+#endif /* defined(G_OS_WIN32) && defined (HAVE_IF_NAMETOINDEX) */
+ }
+ memcpy (&mc_req_src.imr_multiaddr, g_inet_address_to_bytes (group),
+ g_inet_address_get_native_size (group));
+ memcpy (&mc_req_src.imr_sourceaddr,
+ g_inet_address_to_bytes (source_specific),
+ g_inet_address_get_native_size (source_specific));
+
+ optname =
+ join_group ? IP_ADD_SOURCE_MEMBERSHIP : IP_DROP_SOURCE_MEMBERSHIP;
+ result = setsockopt (socket->priv->fd, IPPROTO_IP, optname,
+ &mc_req_src, sizeof (mc_req_src));
+#else
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ join_group ?
+ _("Error joining multicast group: %s") :
+ _("Error leaving multicast group: %s"),
+ _("No support for IPv4 source-specific multicast"));
+ return FALSE;
+#endif /* IP_ADD_SOURCE_MEMBERSHIP */
+ }
+ break;
+
+ case G_SOCKET_FAMILY_IPV6:
+ {
+#ifdef MCAST_JOIN_SOURCE_GROUP
+ gboolean res;
+ gint optname;
+ struct group_source_req mc_req_src;
+ GSocketAddress *saddr_group, *saddr_source_specific;
+ guint iface_index = 0;
+
+#if defined (HAVE_IF_NAMETOINDEX)
+ if (iface)
+ {
+ iface_index = if_nametoindex (iface);
+ if (iface_index == 0)
+ {
+ int errsv = errno;
+
+ g_set_error (error, G_IO_ERROR, g_io_error_from_errno (errsv),
+ _("Interface not found: %s"), g_strerror (errsv));
+ return FALSE;
+ }
+ }
+#endif /* defined (HAVE_IF_NAMETOINDEX) */
+ mc_req_src.gsr_interface = iface_index;
+
+ saddr_group = g_inet_socket_address_new (group, 0);
+ res = g_socket_address_to_native (saddr_group, &mc_req_src.gsr_group,
+ sizeof (mc_req_src.gsr_group),
+ error);
+ g_object_unref (saddr_group);
+ if (!res)
+ return FALSE;
+
+ saddr_source_specific = g_inet_socket_address_new (source_specific, 0);
+ res = g_socket_address_to_native (saddr_source_specific,
+ &mc_req_src.gsr_source,
+ sizeof (mc_req_src.gsr_source),
+ error);
+ g_object_unref (saddr_source_specific);
+
+ if (!res)
+ return FALSE;
+
+ optname =
+ join_group ? MCAST_JOIN_SOURCE_GROUP : MCAST_LEAVE_SOURCE_GROUP;
+ result = setsockopt (socket->priv->fd, IPPROTO_IPV6, optname,
+ &mc_req_src, sizeof (mc_req_src));
+#else
+ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ join_group ?
+ _("Error joining multicast group: %s") :
+ _("Error leaving multicast group: %s"),
+ _("No support for IPv6 source-specific multicast"));
+ return FALSE;
+#endif /* MCAST_JOIN_SOURCE_GROUP */
+ }
+ break;
+
+ default:
+ g_return_val_if_reached (FALSE);
+ }
+
+ if (result < 0)
+ {
+ int errsv = get_socket_errno ();
+
+ g_set_error (error, G_IO_ERROR, socket_io_error_from_errno (errsv),
+ join_group ?
+ _("Error joining multicast group: %s") :
+ _("Error leaving multicast group: %s"),
+ socket_strerror (errsv));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ * g_socket_join_multicast_group_ssm:
+ * @socket: a #GSocket.
+ * @group: a #GInetAddress specifying the group address to join.
+ * @source_specific: (nullable): a #GInetAddress specifying the
+ * source-specific multicast address or %NULL to ignore.
+ * @iface: (nullable): Name of the interface to use, or %NULL
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Registers @socket to receive multicast messages sent to @group.
+ * @socket must be a %G_SOCKET_TYPE_DATAGRAM socket, and must have
+ * been bound to an appropriate interface and port with
+ * g_socket_bind().
+ *
+ * If @iface is %NULL, the system will automatically pick an interface
+ * to bind to based on @group.
+ *
+ * If @source_specific is not %NULL, use source-specific multicast as
+ * defined in RFC 4604. Note that on older platforms this may fail
+ * with a %G_IO_ERROR_NOT_SUPPORTED error.
+ *
+ * Note that this function can be called multiple times for the same
+ * @group with different @source_specific in order to receive multicast
+ * packets from more than one source.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.56
+ */
+gboolean
+g_socket_join_multicast_group_ssm (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *source_specific,
+ const gchar *iface,
+ GError **error)
+{
+ return g_socket_multicast_group_operation_ssm (socket, group,
+ source_specific, iface, TRUE, error);
+}
+
+/**
+ * g_socket_leave_multicast_group_ssm:
+ * @socket: a #GSocket.
+ * @group: a #GInetAddress specifying the group address to leave.
+ * @source_specific: (nullable): a #GInetAddress specifying the
+ * source-specific multicast address or %NULL to ignore.
+ * @iface: (nullable): Name of the interface to use, or %NULL
+ * @error: #GError for error reporting, or %NULL to ignore.
+ *
+ * Removes @socket from the multicast group defined by @group, @iface,
+ * and @source_specific (which must all have the same values they had
+ * when you joined the group).
+ *
+ * @socket remains bound to its address and port, and can still receive
+ * unicast messages after calling this.
+ *
+ * Returns: %TRUE on success, %FALSE on error.
+ *
+ * Since: 2.56
+ */
+gboolean
+g_socket_leave_multicast_group_ssm (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *source_specific,
+ const gchar *iface,
+ GError **error)
+{
+ return g_socket_multicast_group_operation_ssm (socket, group,
+ source_specific, iface, FALSE, error);
+}
+
/**
* g_socket_speaks_ipv4:
* @socket: a #GSocket
@@ -2452,6 +2689,8 @@ g_socket_accept (GSocket *socket,
while (TRUE)
{
+ win32_unset_event_mask (socket, FD_ACCEPT);
+
if ((ret = accept (socket->priv->fd, NULL, 0)) < 0)
{
int errsv = get_socket_errno ();
@@ -2466,8 +2705,6 @@ g_socket_accept (GSocket *socket,
errsv == EAGAIN)
#endif
{
- win32_unset_event_mask (socket, FD_ACCEPT);
-
if (socket->priv->blocking)
{
if (!g_socket_condition_wait (socket,
@@ -2484,8 +2721,6 @@ g_socket_accept (GSocket *socket,
break;
}
- win32_unset_event_mask (socket, FD_ACCEPT);
-
#ifdef G_OS_WIN32
{
/* The socket inherits the accepting sockets event mask and even object,
@@ -2574,6 +2809,8 @@ g_socket_connect (GSocket *socket,
while (1)
{
+ win32_unset_event_mask (socket, FD_CONNECT);
+
if (connect (socket->priv->fd, (struct sockaddr *) &buffer,
g_socket_address_get_native_size (address)) < 0)
{
@@ -2588,8 +2825,6 @@ g_socket_connect (GSocket *socket,
if (errsv == WSAEWOULDBLOCK)
#endif
{
- win32_unset_event_mask (socket, FD_CONNECT);
-
if (socket->priv->blocking)
{
if (g_socket_condition_wait (socket, G_IO_OUT, cancellable, error))
@@ -2615,8 +2850,6 @@ g_socket_connect (GSocket *socket,
break;
}
- win32_unset_event_mask (socket, FD_CONNECT);
-
socket->priv->connected_read = TRUE;
socket->priv->connected_write = TRUE;
@@ -2796,6 +3029,8 @@ g_socket_receive_with_timeout (GSocket *socket,
while (1)
{
+ win32_unset_event_mask (socket, FD_READ);
+
if ((ret = recv (socket->priv->fd, buffer, size, 0)) < 0)
{
int errsv = get_socket_errno ();
@@ -2810,8 +3045,6 @@ g_socket_receive_with_timeout (GSocket *socket,
errsv == EAGAIN)
#endif
{
- win32_unset_event_mask (socket, FD_READ);
-
if (timeout != 0)
{
if (!block_on_timeout (socket, G_IO_IN, timeout, start_time,
@@ -2822,14 +3055,10 @@ g_socket_receive_with_timeout (GSocket *socket,
}
}
- win32_unset_event_mask (socket, FD_READ);
-
socket_set_error_lazy (error, errsv, _("Error receiving data: %s"));
return -1;
}
- win32_unset_event_mask (socket, FD_READ);
-
break;
}
@@ -2995,6 +3224,8 @@ g_socket_send_with_timeout (GSocket *socket,
while (1)
{
+ win32_unset_event_mask (socket, FD_WRITE);
+
if ((ret = send (socket->priv->fd, buffer, size, G_SOCKET_DEFAULT_SEND_FLAGS)) < 0)
{
int errsv = get_socket_errno ();
@@ -3009,8 +3240,6 @@ g_socket_send_with_timeout (GSocket *socket,
errsv == EAGAIN)
#endif
{
- win32_unset_event_mask (socket, FD_WRITE);
-
if (timeout != 0)
{
if (!block_on_timeout (socket, G_IO_OUT, timeout, start_time,
@@ -3425,7 +3654,7 @@ remove_condition_watch (GSocket *socket,
}
static GIOCondition
-update_condition (GSocket *socket)
+update_condition_unlocked (GSocket *socket)
{
WSANETWORKEVENTS events;
GIOCondition condition;
@@ -3492,6 +3721,16 @@ update_condition (GSocket *socket)
return condition;
}
+
+static GIOCondition
+update_condition (GSocket *socket)
+{
+ GIOCondition res;
+ g_mutex_lock (&socket->priv->win32_source_lock);
+ res = update_condition_unlocked (socket);
+ g_mutex_unlock (&socket->priv->win32_source_lock);
+ return res;
+}
#endif
typedef struct {
@@ -3505,24 +3744,38 @@ typedef struct {
GIOCondition condition;
} GSocketSource;
-#ifdef G_OS_WIN32
static gboolean
-socket_source_prepare_win32 (GSource *source,
- gint *timeout)
+socket_source_prepare (GSource *source,
+ gint *timeout)
{
GSocketSource *socket_source = (GSocketSource *)source;
*timeout = -1;
+#ifdef G_OS_WIN32
+ if ((socket_source->pollfd.revents & G_IO_NVAL) != 0)
+ return TRUE;
+
+ if (g_socket_is_closed (socket_source->socket))
+ {
+ g_source_remove_poll (source, &socket_source->pollfd);
+ socket_source->pollfd.revents = G_IO_NVAL;
+ return TRUE;
+ }
+
return (update_condition (socket_source->socket) & socket_source->condition) != 0;
+#else
+ return g_socket_is_closed (socket_source->socket) && socket_source->fd_tag != NULL;
+#endif
}
+#ifdef G_OS_WIN32
static gboolean
socket_source_check_win32 (GSource *source)
{
int timeout;
- return socket_source_prepare_win32 (source, &timeout);
+ return socket_source_prepare (source, &timeout);
}
#endif
@@ -3541,11 +3794,22 @@ socket_source_dispatch (GSource *source,
#ifdef G_OS_WIN32
events = update_condition (socket_source->socket);
#else
- events = g_source_query_unix_fd (source, socket_source->fd_tag);
+ if (g_socket_is_closed (socket_source->socket))
+ {
+ if (socket_source->fd_tag)
+ g_source_remove_unix_fd (source, socket_source->fd_tag);
+ socket_source->fd_tag = NULL;
+ events = G_IO_NVAL;
+ }
+ else
+ {
+ events = g_source_query_unix_fd (source, socket_source->fd_tag);
+ }
#endif
timeout = g_source_get_ready_time (source);
- if (timeout >= 0 && timeout < g_source_get_time (source))
+ if (timeout >= 0 && timeout < g_source_get_time (source) &&
+ !g_socket_is_closed (socket_source->socket))
{
socket->priv->timed_out = TRUE;
events |= (G_IO_IN | G_IO_OUT);
@@ -3553,7 +3817,7 @@ socket_source_dispatch (GSource *source,
ret = (*func) (socket, events & socket_source->condition, user_data);
- if (socket->priv->timeout)
+ if (socket->priv->timeout && !g_socket_is_closed (socket_source->socket))
g_source_set_ready_time (source, g_get_monotonic_time () + socket->priv->timeout * 1000000);
else
g_source_set_ready_time (source, -1);
@@ -3606,11 +3870,11 @@ socket_source_closure_callback (GSocket *socket,
static GSourceFuncs socket_source_funcs =
{
+ socket_source_prepare,
#ifdef G_OS_WIN32
- socket_source_prepare_win32,
socket_source_check_win32,
#else
- NULL, NULL, /* check, prepare */
+ NULL,
#endif
socket_source_dispatch,
socket_source_finalize,
@@ -3887,11 +4151,44 @@ g_socket_condition_timed_wait (GSocket *socket,
if (timeout == -1)
timeout = WSA_INFINITE;
- current_condition = update_condition (socket);
+ g_mutex_lock (&socket->priv->win32_source_lock);
+ current_condition = update_condition_unlocked (socket);
while ((condition & current_condition) == 0)
{
- res = WSAWaitForMultipleEvents (num_events, events,
- FALSE, timeout, FALSE);
+ if (!socket->priv->waiting)
+ {
+ socket->priv->waiting = TRUE;
+ socket->priv->waiting_result = 0;
+ g_mutex_unlock (&socket->priv->win32_source_lock);
+
+ res = WSAWaitForMultipleEvents (num_events, events, FALSE, timeout, FALSE);
+
+ g_mutex_lock (&socket->priv->win32_source_lock);
+ socket->priv->waiting = FALSE;
+ socket->priv->waiting_result = res;
+ g_cond_broadcast (&socket->priv->win32_source_cond);
+ }
+ else
+ {
+ if (timeout != WSA_INFINITE)
+ {
+ if (!g_cond_wait_until (&socket->priv->win32_source_cond, &socket->priv->win32_source_lock, timeout))
+ {
+ res = WSA_WAIT_TIMEOUT;
+ break;
+ }
+ else
+ {
+ res = socket->priv->waiting_result;
+ }
+ }
+ else
+ {
+ g_cond_wait (&socket->priv->win32_source_cond, &socket->priv->win32_source_lock);
+ res = socket->priv->waiting_result;
+ }
+ }
+
if (res == WSA_WAIT_FAILED)
{
int errsv = get_socket_errno ();
@@ -3912,7 +4209,7 @@ g_socket_condition_timed_wait (GSocket *socket,
if (g_cancellable_set_error_if_cancelled (cancellable, error))
break;
- current_condition = update_condition (socket);
+ current_condition = update_condition_unlocked (socket);
if (timeout != WSA_INFINITE)
{
@@ -3921,6 +4218,7 @@ g_socket_condition_timed_wait (GSocket *socket,
timeout = 0;
}
}
+ g_mutex_unlock (&socket->priv->win32_source_lock);
remove_condition_watch (socket, &condition);
if (num_events > 1)
g_cancellable_release_fd (cancellable);
@@ -4418,6 +4716,8 @@ g_socket_send_message_with_timeout (GSocket *socket,
while (1)
{
+ win32_unset_event_mask (socket, FD_WRITE);
+
if (address)
result = WSASendTo (socket->priv->fd,
bufs, num_vectors,
@@ -4439,8 +4739,6 @@ g_socket_send_message_with_timeout (GSocket *socket,
if (errsv == WSAEWOULDBLOCK)
{
- win32_unset_event_mask (socket, FD_WRITE);
-
if (timeout != 0)
{
if (!block_on_timeout (socket, G_IO_OUT, timeout,
@@ -4888,6 +5186,8 @@ g_socket_receive_message_with_timeout (GSocket *socket,
/* do it */
while (1)
{
+ win32_unset_event_mask (socket, FD_READ);
+
addrlen = sizeof addr;
if (address)
result = WSARecvFrom (socket->priv->fd,
@@ -4909,8 +5209,6 @@ g_socket_receive_message_with_timeout (GSocket *socket,
if (errsv == WSAEWOULDBLOCK)
{
- win32_unset_event_mask (socket, FD_READ);
-
if (timeout != 0)
{
if (!block_on_timeout (socket, G_IO_IN, timeout,
@@ -4924,7 +5222,6 @@ g_socket_receive_message_with_timeout (GSocket *socket,
socket_set_error_lazy (error, errsv, _("Error receiving message: %s"));
return -1;
}
- win32_unset_event_mask (socket, FD_READ);
break;
}
diff --git a/gio/gsocket.h b/gio/gsocket.h
index 613c8dd92..a65cbc22f 100644
--- a/gio/gsocket.h
+++ b/gio/gsocket.h
@@ -157,6 +157,18 @@ gboolean g_socket_leave_multicast_group (GSocket
gboolean source_specific,
const gchar *iface,
GError **error);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_socket_join_multicast_group_ssm (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *source_specific,
+ const gchar *iface,
+ GError **error);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_socket_leave_multicast_group_ssm (GSocket *socket,
+ GInetAddress *group,
+ GInetAddress *source_specific,
+ const gchar *iface,
+ GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_socket_connect (GSocket *socket,
GSocketAddress *address,
diff --git a/gio/gsocketlistener.h b/gio/gsocketlistener.h
index e5185c28d..687fab3d4 100644
--- a/gio/gsocketlistener.h
+++ b/gio/gsocketlistener.h
@@ -62,7 +62,7 @@ struct _GSocketListenerClass
void (* changed) (GSocketListener *listener);
void (* event) (GSocketListener *listener,
- GSocketListenerEvent event,
+ GSocketListenerEvent *event,
GSocket *socket);
/* Padding for future expansion */
diff --git a/gio/gsubprocess.c b/gio/gsubprocess.c
index 8525f3bfc..18de30e55 100644
--- a/gio/gsubprocess.c
+++ b/gio/gsubprocess.c
@@ -717,7 +717,7 @@ g_subprocess_new (GSubprocessFlags flags,
/**
* g_subprocess_newv: (rename-to g_subprocess_new)
- * @argv: (array zero-terminated=1) (element-type utf8): commandline arguments for the subprocess
+ * @argv: (array zero-terminated=1) (element-type filename): commandline arguments for the subprocess
* @flags: flags that define the behaviour of the subprocess
* @error: (nullable): return location for an error, or %NULL
*
diff --git a/gio/gsubprocesslauncher.c b/gio/gsubprocesslauncher.c
index 5cdec4d4e..12a5e44b2 100644
--- a/gio/gsubprocesslauncher.c
+++ b/gio/gsubprocesslauncher.c
@@ -228,7 +228,8 @@ g_subprocess_launcher_new (GSubprocessFlags flags)
/**
* g_subprocess_launcher_set_environ:
* @self: a #GSubprocess
- * @env: (array zero-terminated=1): the replacement environment
+ * @env: (array zero-terminated=1) (element-type filename) (transfer none):
+ * the replacement environment
*
* Replace the entire environment of processes launched from this
* launcher with the given 'environ' variable.
@@ -266,8 +267,9 @@ g_subprocess_launcher_set_environ (GSubprocessLauncher *self,
/**
* g_subprocess_launcher_setenv:
* @self: a #GSubprocess
- * @variable: the environment variable to set, must not contain '='
- * @value: the new value for the variable
+ * @variable: (type filename): the environment variable to set,
+ * must not contain '='
+ * @value: (type filename): the new value for the variable
* @overwrite: whether to change the variable if it already exists
*
* Sets the environment variable @variable in the environment of
@@ -291,7 +293,8 @@ g_subprocess_launcher_setenv (GSubprocessLauncher *self,
/**
* g_subprocess_launcher_unsetenv:
* @self: a #GSubprocess
- * @variable: the environment variable to unset, must not contain '='
+ * @variable: (type filename): the environment variable to unset,
+ * must not contain '='
*
* Removes the environment variable @variable from the environment of
* processes launched from this launcher.
@@ -311,7 +314,7 @@ g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
/**
* g_subprocess_launcher_getenv:
* @self: a #GSubprocess
- * @variable: the environment variable to get
+ * @variable: (type filename): the environment variable to get
*
* Returns the value of the environment variable @variable in the
* environment of processes launched from this launcher.
@@ -319,7 +322,8 @@ g_subprocess_launcher_unsetenv (GSubprocessLauncher *self,
* On UNIX, the returned string can be an arbitrary byte string.
* On Windows, it will be UTF-8.
*
- * Returns: the value of the environment variable, %NULL if unset
+ * Returns: (type filename): the value of the environment variable,
+ * %NULL if unset
*
* Since: 2.40
**/
@@ -640,7 +644,7 @@ g_subprocess_launcher_take_fd (GSubprocessLauncher *self,
}
/**
- * g_subprocess_launcher_set_child_setup:
+ * g_subprocess_launcher_set_child_setup: (skip)
* @self: a #GSubprocessLauncher
* @child_setup: a #GSpawnChildSetupFunc to use as the child setup function
* @user_data: user data for @child_setup
@@ -724,7 +728,7 @@ g_subprocess_launcher_spawn (GSubprocessLauncher *launcher,
/**
* g_subprocess_launcher_spawnv:
* @self: a #GSubprocessLauncher
- * @argv: (array zero-terminated=1) (element-type utf8): Command line arguments
+ * @argv: (array zero-terminated=1) (element-type filename): Command line arguments
* @error: Error
*
* Creates a #GSubprocess given a provided array of arguments.
diff --git a/gio/gtask.c b/gio/gtask.c
index 7eb018560..814ba9433 100644
--- a/gio/gtask.c
+++ b/gio/gtask.c
@@ -47,11 +47,13 @@
* Eventually, you will call a method such as
* g_task_return_pointer() or g_task_return_error(), which will
* save the value you give it and then invoke the task's callback
- * function (waiting until the next iteration of the main
- * loop first, if necessary). The caller will pass the #GTask back
- * to the operation's finish function (as a #GAsyncResult), and
- * you can use g_task_propagate_pointer() or the like to extract
- * the return value.
+ * function in the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * where it was created (waiting until the next iteration of the main
+ * loop first, if necessary). The caller will pass the #GTask back to
+ * the operation's finish function (as a #GAsyncResult), and you can
+ * can use g_task_propagate_pointer() or the like to extract the
+ * return value.
*
* Here is an example for using GTask as a GAsyncResult:
* |[<!-- language="C" -->
@@ -290,9 +292,10 @@
* ## Asynchronous operations from synchronous ones
*
* You can use g_task_run_in_thread() to turn a synchronous
- * operation into an asynchronous one, by running it in a thread
- * which will then dispatch the result back to the caller's
- * #GMainContext when it completes.
+ * operation into an asynchronous one, by running it in a thread.
+ * When it completes, the result will be dispatched to the
+ * [thread-default main context][g-main-context-push-thread-default]
+ * where the #GTask was created.
*
* Running a task in a thread:
* |[<!-- language="C" -->
@@ -504,7 +507,7 @@
* whether the task's callback can be invoked directly, or
* if it needs to be sent to another #GMainContext, or delayed
* until the next iteration of the current #GMainContext.)
- * - The "finish" functions for #GTask-based operations are generally
+ * - The "finish" functions for #GTask based operations are generally
* much simpler than #GSimpleAsyncResult ones, normally consisting
* of only a single call to g_task_propagate_pointer() or the like.
* Since g_task_propagate_pointer() "steals" the return value from
@@ -978,7 +981,7 @@ g_task_set_source_tag (GTask *task,
* Gets the source object from @task. Like
* g_async_result_get_source_object(), but does not ref the object.
*
- * Returns: (transfer none) (type GObject): @task's source object, or %NULL
+ * Returns: (transfer none) (nullable) (type GObject): @task's source object, or %NULL
*
* Since: 2.36
*/
diff --git a/gio/gthreadedresolver.c b/gio/gthreadedresolver.c
index 7fa266aa5..7941d95fc 100644
--- a/gio/gthreadedresolver.c
+++ b/gio/gthreadedresolver.c
@@ -537,7 +537,6 @@ g_resolver_records_from_res_query (const gchar *rrname,
gchar namebuf[1024];
guchar *end, *p;
guint16 type, qclass, rdlength;
- guint32 ttl;
HEADER *header;
GList *records;
GVariant *record;
@@ -587,8 +586,7 @@ g_resolver_records_from_res_query (const gchar *rrname,
p += dn_expand (answer, end, p, namebuf, sizeof (namebuf));
GETSHORT (type, p);
GETSHORT (qclass, p);
- GETLONG (ttl, p);
- ttl = ttl; /* To avoid -Wunused-but-set-variable */
+ p += 4; /* ignore the ttl (type=long) value */
GETSHORT (rdlength, p);
if (type != rrtype || qclass != C_IN)
diff --git a/gio/gtlsbackend.c b/gio/gtlsbackend.c
index a78d84be7..80af6ad49 100644
--- a/gio/gtlsbackend.c
+++ b/gio/gtlsbackend.c
@@ -143,10 +143,8 @@ g_tls_backend_supports_dtls (GTlsBackend *backend)
{
if (G_TLS_BACKEND_GET_INTERFACE (backend)->supports_dtls)
return G_TLS_BACKEND_GET_INTERFACE (backend)->supports_dtls (backend);
- else if (G_IS_DUMMY_TLS_BACKEND (backend))
- return FALSE;
- else
- return TRUE;
+
+ return FALSE;
}
/**
@@ -230,14 +228,22 @@ g_tls_backend_get_server_connection_type (GTlsBackend *backend)
* Gets the #GType of @backend’s #GDtlsClientConnection implementation.
*
* Returns: the #GType of @backend’s #GDtlsClientConnection
- * implementation.
+ * implementation, or %G_TYPE_INVALID if this backend doesn’t support DTLS.
*
* Since: 2.48
*/
GType
g_tls_backend_get_dtls_client_connection_type (GTlsBackend *backend)
{
- return G_TLS_BACKEND_GET_INTERFACE (backend)->get_dtls_client_connection_type ();
+ GTlsBackendInterface *iface;
+
+ g_return_val_if_fail (G_IS_TLS_BACKEND (backend), G_TYPE_INVALID);
+
+ iface = G_TLS_BACKEND_GET_INTERFACE (backend);
+ if (iface->get_dtls_client_connection_type == NULL)
+ return G_TYPE_INVALID;
+
+ return iface->get_dtls_client_connection_type ();
}
/**
@@ -247,14 +253,22 @@ g_tls_backend_get_dtls_client_connection_type (GTlsBackend *backend)
* Gets the #GType of @backend’s #GDtlsServerConnection implementation.
*
* Returns: the #GType of @backend’s #GDtlsServerConnection
- * implementation.
+ * implementation, or %G_TYPE_INVALID if this backend doesn’t support DTLS.
*
* Since: 2.48
*/
GType
g_tls_backend_get_dtls_server_connection_type (GTlsBackend *backend)
{
- return G_TLS_BACKEND_GET_INTERFACE (backend)->get_dtls_server_connection_type ();
+ GTlsBackendInterface *iface;
+
+ g_return_val_if_fail (G_IS_TLS_BACKEND (backend), G_TYPE_INVALID);
+
+ iface = G_TLS_BACKEND_GET_INTERFACE (backend);
+ if (iface->get_dtls_server_connection_type == NULL)
+ return G_TYPE_INVALID;
+
+ return iface->get_dtls_server_connection_type ();
}
/**
diff --git a/gio/gtlsdatabase.c b/gio/gtlsdatabase.c
index 424d9c178..5a77b56d7 100644
--- a/gio/gtlsdatabase.c
+++ b/gio/gtlsdatabase.c
@@ -459,7 +459,7 @@ g_tls_database_class_init (GTlsDatabaseClass *klass)
* adding any missing certificates to the chain.
*
* @chain is a chain of #GTlsCertificate objects each pointing to the next
- * certificate in the chain by its %issuer property. The chain may initially
+ * certificate in the chain by its #GTlsCertificate:issuer property. The chain may initially
* consist of one or more certificates. After the verification process is
* complete, @chain may be modified by adding missing certificates, or removing
* extra certificates. If a certificate anchor was found, then it is added to
@@ -741,7 +741,7 @@ g_tls_database_lookup_certificate_for_handle_async (GTlsDatabase *sel
* @error: a #GError pointer, or %NULL
*
* Finish an asynchronous lookup of a certificate by its handle. See
- * g_tls_database_lookup_certificate_handle() for more information.
+ * g_tls_database_lookup_certificate_by_handle() for more information.
*
* If the handle is no longer valid, or does not point to a certificate in
* this database, then %NULL will be returned.
diff --git a/gio/gtlspassword.c b/gio/gtlspassword.c
index 27364b1be..1e437a7b6 100644
--- a/gio/gtlspassword.c
+++ b/gio/gtlspassword.c
@@ -266,7 +266,7 @@ g_tls_password_get_value (GTlsPassword *password,
/**
* g_tls_password_set_value:
* @password: a #GTlsPassword object
- * @value: the new password value
+ * @value: (array length=length): the new password value
* @length: the length of the password, or -1
*
* Set the value for this password. The @value will be copied by the password
@@ -295,7 +295,7 @@ g_tls_password_set_value (GTlsPassword *password,
/**
* g_tls_password_set_value_full:
* @password: a #GTlsPassword object
- * @value: the value for the password
+ * @value: (array length=length): the value for the password
* @length: the length of the password, or -1
* @destroy: (nullable): a function to use to free the password.
*
diff --git a/gio/gunixmounts.c b/gio/gunixmounts.c
index 8e32b4f1e..fc3712987 100644
--- a/gio/gunixmounts.c
+++ b/gio/gunixmounts.c
@@ -148,6 +148,7 @@ G_DEFINE_BOXED_TYPE (GUnixMountPoint, g_unix_mount_point,
static GList *_g_get_unix_mounts (void);
static GList *_g_get_unix_mount_points (void);
+static gboolean proc_mounts_watch_is_running (void);
static guint64 mount_poller_time = 0;
@@ -280,35 +281,99 @@ g_unix_is_mount_path_system_internal (const char *mount_path)
return FALSE;
}
-static gboolean
-guess_system_internal (const char *mountpoint,
- const char *fs,
- const char *device)
+/**
+ * g_unix_is_system_fs_type:
+ * @fs_type: a file system type, e.g. `procfs` or `tmpfs`
+ *
+ * Determines if @fs_type is considered a type of file system which is only
+ * used in implementation of the OS. This is primarily used for hiding
+ * mounted volumes that are intended as APIs for programs to read, and system
+ * administrators at a shell; rather than something that should, for example,
+ * appear in a GUI. For example, the Linux `/proc` filesystem.
+ *
+ * The list of file system types considered ‘system’ ones may change over time.
+ *
+ * Returns: %TRUE if @fs_type is considered an implementation detail of the OS.
+ * Since: 2.56
+ */
+gboolean
+g_unix_is_system_fs_type (const char *fs_type)
{
const char *ignore_fs[] = {
+ "adfs",
+ "afs",
"auto",
"autofs",
+ "autofs4",
+ "cgroup",
+ "cifs",
+ "configfs",
+ "cxfs",
+ "debugfs",
"devfs",
"devpts",
+ "devtmpfs",
"ecryptfs",
"fdescfs",
+ "fusectl",
+ "gfs",
+ "gfs2",
+ "gpfs",
+ "hugetlbfs",
"kernfs",
"linprocfs",
+ "linsysfs",
+ "lustre",
+ "lustre_lite",
"mfs",
+ "mqueue",
+ "ncpfs",
+ "nfs",
+ "nfs4",
+ "nfsd",
"nullfs",
+ "ocfs2",
+ "overlay",
"proc",
"procfs",
+ "pstore",
"ptyfs",
"rootfs",
+ "rpc_pipefs",
+ "securityfs",
"selinuxfs",
+ "smbfs",
"sysfs",
"tmpfs",
"usbfs",
- "nfsd",
- "rpc_pipefs",
"zfs",
NULL
};
+
+ g_return_val_if_fail (fs_type != NULL && *fs_type != '\0', FALSE);
+
+ return is_in (fs_type, ignore_fs);
+}
+
+/**
+ * g_unix_is_system_device_path:
+ * @device_path: a device path, e.g. `/dev/loop0` or `nfsd`
+ *
+ * Determines if @device_path is considered a block device path which is only
+ * used in implementation of the OS. This is primarily used for hiding
+ * mounted volumes that are intended as APIs for programs to read, and system
+ * administrators at a shell; rather than something that should, for example,
+ * appear in a GUI. For example, the Linux `/proc` filesystem.
+ *
+ * The list of device paths considered ‘system’ ones may change over time.
+ *
+ * Returns: %TRUE if @device_path is considered an implementation detail of
+ * the OS.
+ * Since: 2.56
+ */
+gboolean
+g_unix_is_system_device_path (const char *device_path)
+{
const char *ignore_devices[] = {
"none",
"sunrpc",
@@ -318,11 +383,21 @@ guess_system_internal (const char *mountpoint,
"/dev/vn",
NULL
};
-
- if (is_in (fs, ignore_fs))
+
+ g_return_val_if_fail (device_path != NULL && *device_path != '\0', FALSE);
+
+ return is_in (device_path, ignore_devices);
+}
+
+static gboolean
+guess_system_internal (const char *mountpoint,
+ const char *fs,
+ const char *device)
+{
+ if (g_unix_is_system_fs_type (fs))
return TRUE;
- if (is_in (device, ignore_devices))
+ if (g_unix_is_system_device_path (device))
return TRUE;
if (g_unix_is_mount_path_system_internal (mountpoint))
@@ -430,7 +505,7 @@ _g_get_unix_mounts (void)
mnt_free_iter (iter);
out:
- mnt_unref_table (table);
+ mnt_free_table (table);
return g_list_reverse (return_list);
}
@@ -954,7 +1029,7 @@ _g_get_unix_mount_points (void)
mnt_free_iter (iter);
out:
- mnt_unref_table (table);
+ mnt_free_table (table);
return g_list_reverse (return_list);
}
@@ -1279,7 +1354,6 @@ _g_get_unix_mount_points (void)
GList *return_list;
#ifdef HAVE_SYS_SYSCTL_H
int usermnt = 0;
- size_t len = sizeof(usermnt);
struct stat sb;
#endif
@@ -1290,10 +1364,15 @@ _g_get_unix_mount_points (void)
#ifdef HAVE_SYS_SYSCTL_H
#if defined(HAVE_SYSCTLBYNAME)
- sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
+ {
+ size_t len = sizeof(usermnt);
+
+ sysctlbyname ("vfs.usermount", &usermnt, &len, NULL, 0);
+ }
#elif defined(CTL_VFS) && defined(VFS_USERMOUNT)
{
int mib[2];
+ size_t len = sizeof(usermnt);
mib[0] = CTL_VFS;
mib[1] = VFS_USERMOUNT;
@@ -1302,6 +1381,7 @@ _g_get_unix_mount_points (void)
#elif defined(CTL_KERN) && defined(KERN_USERMOUNT)
{
int mib[2];
+ size_t len = sizeof(usermnt);
mib[0] = CTL_KERN;
mib[1] = KERN_USERMOUNT;
@@ -1368,15 +1448,26 @@ get_mounts_timestamp (void)
struct stat buf;
monitor_file = get_mtab_monitor_file ();
- if (monitor_file)
+ /* Don't return mtime for /proc/ files */
+ if (monitor_file && !g_str_has_prefix (monitor_file, "/proc/"))
{
if (stat (monitor_file, &buf) == 0)
return (guint64)buf.st_mtime;
}
- else
+ else if (proc_mounts_watch_is_running ())
{
+ /* it's being monitored by poll, so return mount_poller_time */
return mount_poller_time;
}
+ else
+ {
+ /* Case of /proc/ file not being monitored - Be on the safe side and
+ * send a new timestamp to force g_unix_mounts_changed_since() to
+ * return TRUE so any application caches depending on it (like eg.
+ * the one in GIO) get invalidated and don't hold possibly outdated
+ * data - see Bug 787731 */
+ return (guint64) g_get_monotonic_time ();
+ }
return 0;
}
@@ -1566,6 +1657,13 @@ static GFileMonitor *mtab_monitor;
static GSource *proc_mounts_watch_source;
static GList *mount_poller_mounts;
+static gboolean
+proc_mounts_watch_is_running (void)
+{
+ return proc_mounts_watch_source != NULL &&
+ !g_source_is_destroyed (proc_mounts_watch_source);
+}
+
static void
fstab_file_changed (GFileMonitor *monitor,
GFile *file,
@@ -1602,7 +1700,10 @@ proc_mounts_changed (GIOChannel *channel,
gpointer user_data)
{
if (cond & G_IO_ERR)
- g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
+ {
+ mount_poller_time = (guint64) g_get_monotonic_time ();
+ g_context_specific_group_emit (&mount_monitor_group, signals[MOUNTS_CHANGED]);
+ }
return TRUE;
}
@@ -1652,7 +1753,10 @@ mount_monitor_stop (void)
}
if (proc_mounts_watch_source != NULL)
- g_source_destroy (proc_mounts_watch_source);
+ {
+ g_source_destroy (proc_mounts_watch_source);
+ proc_mounts_watch_source = NULL;
+ }
if (mtab_monitor)
{
@@ -2049,9 +2153,14 @@ g_unix_mount_is_readonly (GUnixMountEntry *mount_entry)
/**
* g_unix_mount_is_system_internal:
* @mount_entry: a #GUnixMount.
+ *
+ * Checks if a Unix mount is a system mount. This is the Boolean OR of
+ * g_unix_is_system_fs_type(), g_unix_is_system_device_path() and
+ * g_unix_is_mount_path_system_internal() on @mount_entry’s properties.
*
- * Checks if a unix mount is a system path.
- *
+ * The definition of what a ‘system’ mount entry is may change over time as new
+ * file system types and device paths are ignored.
+ *
* Returns: %TRUE if the unix mount is for a system path.
*/
gboolean
diff --git a/gio/gunixmounts.h b/gio/gunixmounts.h
index 853b16182..04d6b0726 100644
--- a/gio/gunixmounts.h
+++ b/gio/gunixmounts.h
@@ -96,6 +96,8 @@ GIcon * g_unix_mount_guess_icon (GUnixMountEntry *mount_e
GLIB_AVAILABLE_IN_ALL
GIcon * g_unix_mount_guess_symbolic_icon (GUnixMountEntry *mount_entry);
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountEntry, g_unix_mount_free)
+G_DEFINE_AUTOPTR_CLEANUP_FUNC(GUnixMountPoint, g_unix_mount_point_free)
GLIB_AVAILABLE_IN_ALL
gint g_unix_mount_point_compare (GUnixMountPoint *mount1,
@@ -151,6 +153,10 @@ void g_unix_mount_monitor_set_rate_limit (GUnixMountMonitor *mount
GLIB_AVAILABLE_IN_ALL
gboolean g_unix_is_mount_path_system_internal (const char *mount_path);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_unix_is_system_fs_type (const char *fs_type);
+GLIB_AVAILABLE_IN_2_56
+gboolean g_unix_is_system_device_path (const char *device_path);
G_END_DECLS
diff --git a/gio/gvolume.c b/gio/gvolume.c
index 67a70a924..f97ce4c12 100644
--- a/gio/gvolume.c
+++ b/gio/gvolume.c
@@ -633,7 +633,7 @@ g_volume_enumerate_identifiers (GVolume *volume)
* then the expression
* |[<!-- language="C" -->
* (g_file_has_prefix (volume_activation_root, mount_root) ||
- g_file_equal (volume_activation_root, mount_root))
+ * g_file_equal (volume_activation_root, mount_root))
* ]|
* will always be %TRUE.
*
diff --git a/gio/gvolumemonitor.c b/gio/gvolumemonitor.c
index cc8d917b9..cb22f8927 100644
--- a/gio/gvolumemonitor.c
+++ b/gio/gvolumemonitor.c
@@ -159,7 +159,10 @@ g_volume_monitor_class_init (GVolumeMonitorClass *klass)
* @volume_monitor: The volume monitor emitting the signal.
* @mount: a #GMount that is being unmounted.
*
- * Emitted when a mount is about to be removed.
+ * May be emitted when a mount is about to be removed.
+ *
+ * This signal depends on the backend and is only emitted if
+ * GIO was used to unmount.
**/
signals[MOUNT_PRE_UNMOUNT] = g_signal_new (I_("mount-pre-unmount"),
G_TYPE_VOLUME_MONITOR,
diff --git a/gio/inotify/inotify-helper.c b/gio/inotify/inotify-helper.c
index d64e34d0c..dce57e507 100644
--- a/gio/inotify/inotify-helper.c
+++ b/gio/inotify/inotify-helper.c
@@ -156,12 +156,9 @@ ih_event_callback (ik_event_t *event,
gboolean file_event)
{
gboolean interesting;
- GFileMonitorEvent event_flags;
g_assert (!file_event); /* XXX hardlink support */
- event_flags = ih_mask_to_EventFlags (event->mask);
-
if (event->mask & IN_MOVE)
{
/* We either have a rename (in the same directory) or a move
@@ -190,22 +187,17 @@ ih_event_callback (ik_event_t *event,
else
other = NULL;
- /* This is either an incoming or outgoing move. Since we checked the
- * event->mask above, it should have converted to a #GFileMonitorEvent
- * properly. If not, the assumption we have made about event->mask
- * only ever having a single bit set (apart from IN_ISDIR) is false.
- * The kernel documentation is lacking here. */
- g_assert (event_flags != -1);
- interesting = g_file_monitor_source_handle_event (sub->user_data, event_flags,
+ /* this is either an incoming or outgoing move */
+ interesting = g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask),
event->name, NULL, other, event->timestamp);
if (other)
g_object_unref (other);
}
}
- else if (event_flags != -1)
+ else
/* unpaired event -- no 'other' field */
- interesting = g_file_monitor_source_handle_event (sub->user_data, event_flags,
+ interesting = g_file_monitor_source_handle_event (sub->user_data, ih_mask_to_EventFlags (event->mask),
event->name, NULL, NULL, event->timestamp);
if (event->mask & IN_CREATE)
diff --git a/gio/inotify/inotify-path.c b/gio/inotify/inotify-path.c
index f0528f443..5110dff45 100644
--- a/gio/inotify/inotify-path.c
+++ b/gio/inotify/inotify-path.c
@@ -532,9 +532,8 @@ ip_event_callback (ik_event_t *event)
GList* dir_list = NULL;
GList *file_list = NULL;
- /* We can ignore the IGNORED events. Likewise, if the event queue overflowed,
- * there is not much we can do to recover. */
- if (event->mask & (IN_IGNORED | IN_Q_OVERFLOW))
+ /* We can ignore the IGNORED events */
+ if (event->mask & IN_IGNORED)
{
_ik_event_free (event);
return TRUE;
diff --git a/gio/kqueue/kqueue-helper.c b/gio/kqueue/kqueue-helper.c
index e7d583c8b..d4e66cd4d 100644
--- a/gio/kqueue/kqueue-helper.c
+++ b/gio/kqueue/kqueue-helper.c
@@ -97,10 +97,8 @@ convert_kqueue_events_to_gio (uint32_t flags, gboolean *done)
}
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;
+ return G_FILE_MONITOR_EVENT_MOVED;
}
if (flags & NOTE_REVOKE)
{
diff --git a/gio/meson.build b/gio/meson.build
index 325263626..4a10d49d7 100644
--- a/gio/meson.build
+++ b/gio/meson.build
@@ -93,6 +93,18 @@ if host_system != 'windows'
name : 'struct ip_mreqn')
glib_conf.set('HAVE_IP_MREQN', '/**/')
endif
+
+ if cc.compiles('''#include <sys/ioctl.h>
+ #include <net/if.h>
+ int main (int argc, char ** argv) {
+ struct ifreq ifr;
+ ioctl(0, SIOCGIFADDR, &ifr);
+ return 0;
+ }''',
+ name : 'ioctl with request SIOCGIFADDR')
+ glib_conf.set('HAVE_SIOCGIFADDR', '/**/')
+ endif
+
endif
network_args_string = ''
@@ -174,6 +186,7 @@ xdp_dbus_generated = custom_target('xdp-dbus',
'org.freedesktop.portal.NetworkMonitor.xml',
'org.freedesktop.portal.ProxyResolver.xml'],
output : ['xdp-dbus.h', 'xdp-dbus.c'],
+ depend_files : gdbus_codegen_built_files,
command : [python, gdbus_codegen,
'--interface-prefix', 'org.freedesktop.portal.',
'--output-directory', '@OUTDIR@',
@@ -193,6 +206,7 @@ xdp_dbus_generated = custom_target('xdp-dbus',
gdbus_daemon_generated = custom_target('gdbus-daemon-generated',
input : ['dbus-daemon.xml'],
output : ['gdbus-daemon-generated.h', 'gdbus-daemon-generated.c'],
+ depend_files : gdbus_codegen_built_files,
command : [python, gdbus_codegen,
'--interface-prefix', 'org.',
'--output-directory', '@OUTDIR@',
diff --git a/gio/tests/Makefile.am b/gio/tests/Makefile.am
index acc1da4f4..a553958e4 100644
--- a/gio/tests/Makefile.am
+++ b/gio/tests/Makefile.am
@@ -231,11 +231,29 @@ socket_client_SOURCES = \
EXTRA_DIST += socket-common.c
uninstalled_test_extra_programs += gdbus-daemon
+gdbus_daemon_SOURCES = gdbus-daemon.c
nodist_gdbus_daemon_SOURCES = \
- $(top_builddir)/gio/gdbus-daemon-generated.c
-gdbus_daemon_SOURCES = \
- gdbus-daemon.c \
- $(top_srcdir)/gio/gdbusdaemon.c
+ gdbus-daemon-generated.c \
+ gdbus-daemon-impl.c
+CLEANFILES += gdbus-daemon-impl.c gdbus-daemon-generated.c gdbus-daemon-generated.h
+
+# With subdir-objects we need to create a link to the original
+# file in the right directory, otherwise libtool will complain
+# that it cannot find the wrapper file
+gdbus-daemon-impl.c: $(top_srcdir)/gio/gdbusdaemon.c
+ $(AM_V_GEN) $(LN_S) $^ $@
+
+# These files are only generated on Windows builds inside GIO,
+# but we want them on non-Windows builds for the tests
+gdbus-daemon-generated.h gdbus-daemon-generated.c: $(top_srcdir)/gio/dbus-daemon.xml $(GDBUS_PYTHON_DEPS)
+ $(AM_V_GEN) UNINSTALLED_GLIB_SRCDIR=$(top_srcdir) \
+ UNINSTALLED_GLIB_BUILDDIR=$(top_builddir) \
+ $(PYTHON) $(top_srcdir)/gio/gdbus-2.0/codegen/gdbus-codegen.in \
+ --interface-prefix org. \
+ --generate-c-code gdbus-daemon-generated \
+ --c-namespace _G \
+ $(top_srcdir)/gio/dbus-daemon.xml \
+ $(NULL)
# -----------------------------------------------------------------------------
# Test programs buildable on UNIX only
@@ -248,7 +266,9 @@ test_programs += \
socket-address \
stream-rw_all \
unix-fd \
+ unix-mounts \
unix-streams \
+ g-file-info-filesystem-readonly \
$(NULL)
test_extra_programs += \
diff --git a/gio/tests/appinfo.c b/gio/tests/appinfo.c
index 2e69da051..190205398 100644
--- a/gio/tests/appinfo.c
+++ b/gio/tests/appinfo.c
@@ -7,8 +7,9 @@
#include <gio/gdesktopappinfo.h>
static void
-test_launch_for_app_info (GAppInfo *appinfo)
+test_launch (void)
{
+ GAppInfo *appinfo;
GError *error;
GFile *file;
GList *l;
@@ -21,6 +22,10 @@ test_launch_for_app_info (GAppInfo *appinfo)
return;
}
+ path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
+ appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
+ g_assert (appinfo != NULL);
+
error = NULL;
g_assert (g_app_info_launch (appinfo, NULL, NULL, &error));
g_assert_no_error (error);
@@ -28,7 +33,6 @@ test_launch_for_app_info (GAppInfo *appinfo)
g_assert (g_app_info_launch_uris (appinfo, NULL, NULL, &error));
g_assert_no_error (error);
- path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
file = g_file_new_for_path (path);
l = NULL;
l = g_list_append (l, file);
@@ -47,84 +51,11 @@ test_launch_for_app_info (GAppInfo *appinfo)
g_assert_no_error (error);
g_list_free (l);
g_free (uri);
-}
-
-static void
-test_launch (void)
-{
- GAppInfo *appinfo;
- const gchar *path;
- path = g_test_get_filename (G_TEST_DIST, "appinfo-test.desktop", NULL);
- appinfo = (GAppInfo*)g_desktop_app_info_new_from_filename (path);
- g_assert (appinfo != NULL);
-
- test_launch_for_app_info (appinfo);
g_object_unref (appinfo);
}
static void
-test_launch_no_app_id (void)
-{
- const gchar desktop_file_base_contents[] =
- "[Desktop Entry]\n"
- "Type=Application\n"
- "GenericName=generic-appinfo-test\n"
- "Name=appinfo-test\n"
- "Name[de]=appinfo-test-de\n"
- "X-GNOME-FullName=example\n"
- "X-GNOME-FullName[de]=Beispiel\n"
- "Comment=GAppInfo example\n"
- "Comment[de]=GAppInfo Beispiel\n"
- "Icon=testicon.svg\n"
- "Terminal=true\n"
- "StartupNotify=true\n"
- "StartupWMClass=appinfo-class\n"
- "MimeType=image/png;image/jpeg;\n"
- "Keywords=keyword1;test keyword;\n"
- "Categories=GNOME;GTK;\n";
-
- const char *exec_line_variants[] = {
- "Exec=./appinfo-test --option %U %i --name %c --filename %k %m %%",
- "Exec=./appinfo-test --option %u %i --name %c --filename %k %m %%"
- };
-
- gsize i;
-
- g_test_bug ("791337");
-
- for (i = 0; i < G_N_ELEMENTS (exec_line_variants); i++)
- {
- gchar *desktop_file_contents;
- GKeyFile *fake_desktop_file;
- GAppInfo *appinfo;
- gboolean loaded;
-
- g_test_message ("Exec line variant #%" G_GSIZE_FORMAT, i);
-
- desktop_file_contents = g_strdup_printf ("%s\n%s",
- desktop_file_base_contents,
- exec_line_variants[i]);
-
- /* We load a desktop file from memory to force the app not
- * to have an app ID, which would check different codepaths.
- */
- fake_desktop_file = g_key_file_new ();
- loaded = g_key_file_load_from_data (fake_desktop_file, desktop_file_contents, -1, G_KEY_FILE_NONE, NULL);
- g_assert_true (loaded);
-
- appinfo = (GAppInfo*)g_desktop_app_info_new_from_keyfile (fake_desktop_file);
- g_assert (appinfo != NULL);
-
- test_launch_for_app_info (appinfo);
-
- g_free (desktop_file_contents);
- g_object_unref (appinfo);
- g_key_file_unref (fake_desktop_file);
- }
-}
-
-static void
test_locale (const char *locale)
{
GAppInfo *appinfo;
@@ -549,7 +480,6 @@ main (int argc, char *argv[])
g_setenv ("XDG_CURRENT_DESKTOP", "GNOME", TRUE);
g_test_init (&argc, &argv, NULL);
- g_test_bug_base ("https://bugzilla.gnome.org/show_bug.cgi?id=");
/* With Meson build we need to change into right directory, so that the
* appinfo-test binary can be found. */
@@ -560,7 +490,6 @@ main (int argc, char *argv[])
g_test_add_func ("/appinfo/basic", test_basic);
g_test_add_func ("/appinfo/text", test_text);
g_test_add_func ("/appinfo/launch", test_launch);
- g_test_add_func ("/appinfo/launch/no-appid", test_launch_no_app_id);
g_test_add_func ("/appinfo/show-in", test_show_in);
g_test_add_func ("/appinfo/commandline", test_commandline);
g_test_add_func ("/appinfo/launch-context", test_launch_context);
diff --git a/gio/tests/contenttype.c b/gio/tests/contenttype.c
index 1acbd776f..2424b8e5f 100644
--- a/gio/tests/contenttype.c
+++ b/gio/tests/contenttype.c
@@ -56,6 +56,8 @@ test_guess (void)
g_free (res);
g_free (expected);
+ /* Sadly OSX just doesn't have as large and robust of a mime type database as Linux */
+#ifndef __APPLE__
res = g_content_type_guess ("foo", data, sizeof (data) - 1, &uncertain);
expected = g_content_type_from_mime_type ("text/plain");
g_assert_content_type_equals (expected, res);
@@ -63,8 +65,6 @@ test_guess (void)
g_free (res);
g_free (expected);
-/* Sadly OSX just doesn't have as large and robust of a mime type database as Linux */
-#ifndef __APPLE__
res = g_content_type_guess ("foo.desktop", data, sizeof (data) - 1, &uncertain);
expected = g_content_type_from_mime_type ("application/x-desktop");
g_assert_content_type_equals (expected, res);
@@ -110,6 +110,7 @@ test_guess (void)
g_assert (!uncertain);
g_free (res);
g_free (expected);
+#endif
res = g_content_type_guess (NULL, (guchar *)"%!PS-Adobe-2.0 EPSF-1.2", 23, &uncertain);
expected = g_content_type_from_mime_type ("image/x-eps");
@@ -117,7 +118,6 @@ test_guess (void)
g_assert (!uncertain);
g_free (res);
g_free (expected);
-#endif
}
static void
@@ -233,8 +233,12 @@ test_icon (void)
const gchar *const *names;
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+#ifdef __APPLE__
+ g_assert (g_strv_contains (names, "text-*"));
+#else
g_assert (g_strv_contains (names, "text-plain"));
g_assert (g_strv_contains (names, "text-x-generic"));
+#endif
}
g_object_unref (icon);
g_free (type);
@@ -248,7 +252,9 @@ test_icon (void)
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
g_assert (g_strv_contains (names, "application-rtf"));
+#ifndef __APPLE__
g_assert (g_strv_contains (names, "x-office-document"));
+#endif
}
g_object_unref (icon);
g_free (type);
@@ -269,10 +275,15 @@ test_symbolic_icon (void)
const gchar *const *names;
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
+#ifdef __APPLE__
+ g_assert (g_strv_contains (names, "text-*-symbolic"));
+ g_assert (g_strv_contains (names, "text-*"));
+#else
g_assert (g_strv_contains (names, "text-plain-symbolic"));
g_assert (g_strv_contains (names, "text-x-generic-symbolic"));
g_assert (g_strv_contains (names, "text-plain"));
g_assert (g_strv_contains (names, "text-x-generic"));
+#endif
}
g_object_unref (icon);
g_free (type);
@@ -286,9 +297,11 @@ test_symbolic_icon (void)
names = g_themed_icon_get_names (G_THEMED_ICON (icon));
g_assert (g_strv_contains (names, "application-rtf-symbolic"));
- g_assert (g_strv_contains (names, "x-office-document-symbolic"));
g_assert (g_strv_contains (names, "application-rtf"));
+#ifndef __APPLE__
+ g_assert (g_strv_contains (names, "x-office-document-symbolic"));
g_assert (g_strv_contains (names, "x-office-document"));
+#endif
}
g_object_unref (icon);
g_free (type);
@@ -334,8 +347,60 @@ test_type_is_a_special_case (void)
/* Everything but the inode type is application/octet-stream */
res = g_content_type_is_a ("inode/directory", "application/octet-stream");
g_assert_false (res);
+#ifndef __APPLE__
res = g_content_type_is_a ("anything", "application/octet-stream");
g_assert_true (res);
+#endif
+}
+
+static void
+test_guess_svg_from_data (void)
+{
+ const gchar svgfilecontent[] = "<svg xmlns=\"http://www.w3.org/2000/svg\"\
+ xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n\
+ <rect x=\"10\" y=\"10\" height=\"100\" width=\"100\"\n\
+ style=\"stroke:#ff0000; fill: #0000ff\"/>\n\
+</svg>\n";
+
+ gboolean uncertain = TRUE;
+ gchar *res = g_content_type_guess (NULL, (guchar *)svgfilecontent,
+ sizeof (svgfilecontent) - 1, &uncertain);
+#ifdef __APPLE__
+ g_assert_cmpstr (res, ==, "public.svg-image");
+#elif defined(G_OS_WIN32)
+ g_test_skip ("svg type detection from content is not implemented on WIN32");
+#else
+ g_assert_cmpstr (res, ==, "image/svg+xml");
+#endif
+ g_assert_false (uncertain);
+ g_free (res);
+}
+
+static void
+test_mime_from_content (void)
+{
+#ifdef __APPLE__
+ gchar *mime_type;
+ mime_type = g_content_type_get_mime_type ("com.microsoft.bmp");
+ g_assert_cmpstr (mime_type, ==, "image/bmp");
+ g_free (mime_type);
+ mime_type = g_content_type_get_mime_type ("com.compuserve.gif");
+ g_assert_cmpstr (mime_type, ==, "image/gif");
+ g_free (mime_type);
+ mime_type = g_content_type_get_mime_type ("public.png");
+ g_assert_cmpstr (mime_type, ==, "image/png");
+ g_free (mime_type);
+ mime_type = g_content_type_get_mime_type ("public.text");
+ g_assert_cmpstr (mime_type, ==, "text/*");
+ g_free (mime_type);
+ mime_type = g_content_type_get_mime_type ("public.svg-image");
+ g_assert_cmpstr (mime_type, ==, "image/svg+xml");
+ g_free (mime_type);
+#elif defined(G_OS_WIN32)
+ g_test_skip ("mime from content type test not implemented on WIN32");
+#else
+ g_test_skip ("mime from content type test not implemented on UNIX");
+#endif
}
int
@@ -346,6 +411,8 @@ main (int argc, char *argv[])
g_test_bug_base ("http://bugzilla.gnome.org/");
g_test_add_func ("/contenttype/guess", test_guess);
+ g_test_add_func ("/contenttype/guess_svg_from_data", test_guess_svg_from_data);
+ g_test_add_func ("/contenttype/mime_from_content", test_mime_from_content);
g_test_add_func ("/contenttype/unknown", test_unknown);
g_test_add_func ("/contenttype/subtype", test_subtype);
g_test_add_func ("/contenttype/list", test_list);
diff --git a/gio/tests/dbus-launch.c b/gio/tests/dbus-launch.c
index 5eeb1c0c0..90d8d069e 100644
--- a/gio/tests/dbus-launch.c
+++ b/gio/tests/dbus-launch.c
@@ -38,7 +38,7 @@ write_all (const void *ptr,
while (len > 0)
{
- ssize_t done = write (STDOUT_FILENO, p, len);
+ gssize done = write (STDOUT_FILENO, p, len);
int errsv = errno;
if (done == 0)
diff --git a/gio/tests/desktop-files/home/applications/epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop b/gio/tests/desktop-files/home/applications/epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop
index 97fe69dcc..83976e027 100644
--- a/gio/tests/desktop-files/home/applications/epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop
+++ b/gio/tests/desktop-files/home/applications/epiphany-weather-for-toronto-island-9c6a4e022b17686306243dada811d550d25eb1fb.desktop
@@ -1,6 +1,6 @@
[Desktop Entry]
Name=Weather for Toronto Island
-Exec=/bin/true
+Exec=true
StartupNotify=true
Terminal=false
Type=Application
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 779183791..cf2aae253 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -8,27 +8,47 @@
#endif
static void
-test_basic (void)
+test_basic_for_file (GFile *file,
+ const gchar *suffix)
{
- GFile *file;
gchar *s;
- file = g_file_new_for_path ("./some/directory/testfile");
-
s = g_file_get_basename (file);
g_assert_cmpstr (s, ==, "testfile");
g_free (s);
s = g_file_get_uri (file);
g_assert (g_str_has_prefix (s, "file://"));
- g_assert (g_str_has_suffix (s, "/some/directory/testfile"));
+ g_assert (g_str_has_suffix (s, suffix));
g_free (s);
g_assert (g_file_has_uri_scheme (file, "file"));
s = g_file_get_uri_scheme (file);
g_assert_cmpstr (s, ==, "file");
g_free (s);
+}
+
+static void
+test_basic (void)
+{
+ GFile *file;
+ file = g_file_new_for_path ("./some/directory/testfile");
+ test_basic_for_file (file, "/some/directory/testfile");
+ g_object_unref (file);
+}
+
+static void
+test_build_filename (void)
+{
+ GFile *file;
+
+ file = g_file_new_build_filename (".", "some", "directory", "testfile", NULL);
+ test_basic_for_file (file, "/some/directory/testfile");
+ g_object_unref (file);
+
+ file = g_file_new_build_filename ("testfile", NULL);
+ test_basic_for_file (file, "/testfile");
g_object_unref (file);
}
@@ -466,7 +486,7 @@ test_create_delete (gconstpointer d)
data->loop = g_main_loop_new (NULL, FALSE);
- data->timeout = g_timeout_add (5000, stop_timeout, NULL);
+ data->timeout = g_timeout_add (10000, stop_timeout, NULL);
g_file_create_async (data->file, 0, 0, NULL, created_cb, data);
@@ -1043,6 +1063,91 @@ test_measure_async (void)
measure_done, data);
}
+static void
+test_load_bytes (void)
+{
+ gchar filename[] = "g_file_load_bytes_XXXXXX";
+ GError *error = NULL;
+ GBytes *bytes;
+ GFile *file;
+ int len;
+ int fd;
+ int ret;
+
+ fd = g_mkstemp (filename);
+ g_assert_cmpint (fd, !=, -1);
+ len = strlen ("test_load_bytes");
+ ret = write (fd, "test_load_bytes", len);
+ g_assert_cmpint (ret, ==, len);
+ close (fd);
+
+ file = g_file_new_for_path (filename);
+ bytes = g_file_load_bytes (file, NULL, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (bytes != NULL);
+ g_assert_cmpint (len, ==, g_bytes_get_size (bytes));
+ g_assert_cmpstr ("test_load_bytes", ==, (gchar *)g_bytes_get_data (bytes, NULL));
+
+ g_file_delete (file, NULL, NULL);
+
+ g_bytes_unref (bytes);
+ g_object_unref (file);
+}
+
+typedef struct
+{
+ GMainLoop *main_loop;
+ GFile *file;
+ GBytes *bytes;
+} LoadBytesAsyncData;
+
+static void
+test_load_bytes_cb (GObject *object,
+ GAsyncResult *result,
+ gpointer user_data)
+{
+ GFile *file = G_FILE (object);
+ LoadBytesAsyncData *data = user_data;
+ GError *error = NULL;
+
+ data->bytes = g_file_load_bytes_finish (file, result, NULL, &error);
+ g_assert_no_error (error);
+ g_assert (data->bytes != NULL);
+
+ g_main_loop_quit (data->main_loop);
+}
+
+static void
+test_load_bytes_async (void)
+{
+ LoadBytesAsyncData data = { 0 };
+ gchar filename[] = "g_file_load_bytes_XXXXXX";
+ int len;
+ int fd;
+ int ret;
+
+ fd = g_mkstemp (filename);
+ g_assert_cmpint (fd, !=, -1);
+ len = strlen ("test_load_bytes_async");
+ ret = write (fd, "test_load_bytes_async", len);
+ g_assert_cmpint (ret, ==, len);
+ close (fd);
+
+ data.main_loop = g_main_loop_new (NULL, FALSE);
+ data.file = g_file_new_for_path (filename);
+
+ g_file_load_bytes_async (data.file, NULL, test_load_bytes_cb, &data);
+ g_main_loop_run (data.main_loop);
+
+ g_assert_cmpint (len, ==, g_bytes_get_size (data.bytes));
+ g_assert_cmpstr ("test_load_bytes_async", ==, (gchar *)g_bytes_get_data (data.bytes, NULL));
+
+ g_file_delete (data.file, NULL, NULL);
+ g_object_unref (data.file);
+ g_bytes_unref (data.bytes);
+ g_main_loop_unref (data.main_loop);
+}
+
int
main (int argc, char *argv[])
{
@@ -1051,6 +1156,7 @@ main (int argc, char *argv[])
g_test_bug_base ("http://bugzilla.gnome.org/");
g_test_add_func ("/file/basic", test_basic);
+ g_test_add_func ("/file/build-filename", test_build_filename);
g_test_add_func ("/file/parent", test_parent);
g_test_add_func ("/file/child", test_child);
g_test_add_func ("/file/type", test_type);
@@ -1068,6 +1174,8 @@ main (int argc, char *argv[])
#endif
g_test_add_func ("/file/measure", test_measure);
g_test_add_func ("/file/measure-async", test_measure_async);
+ g_test_add_func ("/file/load-bytes", test_load_bytes);
+ g_test_add_func ("/file/load-bytes-async", test_load_bytes_async);
return g_test_run ();
}
diff --git a/gio/tests/g-file-info-filesystem-readonly.c b/gio/tests/g-file-info-filesystem-readonly.c
new file mode 100644
index 000000000..9a185b081
--- /dev/null
+++ b/gio/tests/g-file-info-filesystem-readonly.c
@@ -0,0 +1,176 @@
+/* Testcase for bug in GIO function g_file_query_filesystem_info()
+ * Author: Nelson Benítez León
+ *
+ * This work is provided "as is"; redistribution and modification
+ * in whole or in part, in any medium, physical or electronic is
+ * permitted without restriction.
+ *
+ * This work 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.
+ *
+ * In no event shall the authors or contributors be liable for any
+ * direct, indirect, incidental, special, exemplary, or consequential
+ * damages (including, but not limited to, procurement of substitute
+ * goods or services; loss of use, data, or profits; or business
+ * interruption) however caused and on any theory of liability, whether
+ * in contract, strict liability, or tort (including negligence or
+ * otherwise) arising in any way out of the use of this software, even
+ * if advised of the possibility of such damage.
+ */
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+static void
+test_filesystem_readonly (gconstpointer with_mount_monitor)
+{
+ GFileInfo *file_info;
+ GFile *mounted_file;
+ GUnixMountMonitor *mount_monitor;
+ gchar *bindfs, *fusermount;
+ gchar *command_mount, *command_mount_ro, *command_umount;
+ gchar *curdir, *dir_to_mount, *dir_mountpoint;
+ gchar *file_in_mount, *file_in_mountpoint;
+
+ /* installed by package 'bindfs' in Fedora */
+ bindfs = g_find_program_in_path ("bindfs");
+
+ /* installed by package 'fuse' in Fedora */
+ fusermount = g_find_program_in_path ("fusermount");
+
+ if (bindfs == NULL || fusermount == NULL)
+ {
+ /* We need these because "mount --bind" requires root privileges */
+ g_test_skip ("'bindfs' and 'fusermount' commands are needed to run this test");
+ return;
+ }
+
+ curdir = g_get_current_dir ();
+ dir_to_mount = g_strdup_printf ("%s/dir_bindfs_to_mount", curdir);
+ file_in_mount = g_strdup_printf ("%s/example.txt", dir_to_mount);
+ dir_mountpoint = g_strdup_printf ("%s/dir_bindfs_mountpoint", curdir);
+
+ g_mkdir (dir_to_mount, 0777);
+ g_mkdir (dir_mountpoint, 0777);
+ if (! g_file_set_contents (file_in_mount, "Example", -1, NULL))
+ {
+ g_test_skip ("Failed to create file needed to proceed further with the test");
+ return;
+ }
+
+ if (with_mount_monitor)
+ {
+ 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) */
+ command_mount_ro = g_strdup_printf ("%s -n -o ro '%s' '%s'", bindfs, dir_to_mount, dir_mountpoint);
+ g_spawn_command_line_sync (command_mount_ro, NULL, NULL, NULL, NULL);
+
+ /* Let's check now, that the file is in indeed in a readonly filesystem */
+ file_in_mountpoint = g_strdup_printf ("%s/example.txt", dir_mountpoint);
+ mounted_file = g_file_new_for_path (file_in_mountpoint);
+
+ if (with_mount_monitor)
+ {
+ /* Let UnixMountMonitor process its 'mounts-changed'
+ * signal triggered by mount operation above */
+ while (g_main_context_iteration (NULL, FALSE));
+ }
+
+ file_info = g_file_query_filesystem_info (mounted_file,
+ G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, NULL, NULL);
+ if (! g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
+ {
+ g_test_skip ("Failed to create readonly file needed to proceed further with the test");
+ return;
+ }
+
+ /* Now we unmount, and mount again but this time rw (not readonly) */
+ command_umount = g_strdup_printf ("%s -u '%s'", fusermount, dir_mountpoint);
+ g_spawn_command_line_sync (command_umount, NULL, NULL, NULL, NULL);
+ command_mount = g_strdup_printf ("%s -n '%s' '%s'", bindfs, dir_to_mount, dir_mountpoint);
+ g_spawn_command_line_sync (command_mount, NULL, NULL, NULL, NULL);
+
+ if (with_mount_monitor)
+ {
+ /* Let UnixMountMonitor process its 'mounts-changed' signal
+ * triggered by mount/umount operations above */
+ while (g_main_context_iteration (NULL, FALSE));
+ }
+
+ /* Now let's test if GIO will report the new filesystem state */
+ g_clear_object (&file_info);
+ g_clear_object (&mounted_file);
+ mounted_file = g_file_new_for_path (file_in_mountpoint);
+ file_info = g_file_query_filesystem_info (mounted_file,
+ G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, NULL, NULL);
+
+ if (g_file_info_get_attribute_boolean (file_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
+ {
+ /* ¡¡ GIO still reports filesystem as being Readonly !!
+ * Let's check if that's true by trying to write to file */
+ GFileOutputStream *write_stream;
+ write_stream = g_file_append_to (mounted_file, G_FILE_CREATE_NONE, NULL, NULL);
+ if (write_stream != NULL)
+ {
+ /* The file has been opened for writing without error, so ¡¡ GIO IS WRONG !! */
+ g_object_unref (write_stream);
+ g_test_fail (); /* Marking test as FAILED */
+ }
+ }
+
+ /* Clean up */
+ if (with_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 */
+
+ g_remove (file_in_mount);
+ g_remove (dir_to_mount);
+ g_remove (dir_mountpoint);
+
+ g_free (bindfs);
+ g_free (fusermount);
+ g_free (curdir);
+ g_free (dir_to_mount);
+ g_free (dir_mountpoint);
+ g_free (command_mount);
+ g_free (command_mount_ro);
+ g_free (command_umount);
+ g_free (file_in_mount);
+ g_free (file_in_mountpoint);
+}
+
+int
+main (int argc, char *argv[])
+{
+ /* To avoid unnecessary D-Bus calls, see http://goo.gl/ir56j2 */
+ g_setenv ("GIO_USE_VFS", "local", FALSE);
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_bug_base ("http://bugzilla.gnome.org/");
+ g_test_bug ("787731");
+
+ g_test_add_data_func ("/g-file-info-filesystem-readonly/test-fs-ro",
+ GINT_TO_POINTER (FALSE), test_filesystem_readonly);
+
+ /* This second test is using a running GUnixMountMonitor, so the calls to:
+ * g_unix_mount_get(&time_read) - To fill the time_read parameter
+ * g_unix_mounts_changed_since()
+ *
+ * made from inside g_file_query_filesystem_info() will use the mount_poller_time
+ * from the monitoring of /proc/self/mountinfo , while in the previous test new
+ * created timestamps are returned from those g_unix_mount* functions. */
+ g_test_add_data_func ("/g-file-info-filesystem-readonly/test-fs-ro-with-mount-monitor",
+ GINT_TO_POINTER (TRUE), test_filesystem_readonly);
+
+ return g_test_run ();
+}
diff --git a/gio/tests/g-file-info.c b/gio/tests/g-file-info.c
index 7ed874a03..5b3def91c 100644
--- a/gio/tests/g-file-info.c
+++ b/gio/tests/g-file-info.c
@@ -20,10 +20,18 @@
* if advised of the possibility of such damage.
*/
+#include "config.h"
+
#include <glib/glib.h>
#include <gio/gio.h>
#include <stdlib.h>
#include <string.h>
+#ifdef G_OS_WIN32
+#include <stdio.h>
+#include <glib/gstdio.h>
+#include <Windows.h>
+#include <Shlobj.h>
+#endif
#define TEST_NAME "Prilis zlutoucky kun"
#define TEST_DISPLAY_NAME "UTF-8 p\xc5\x99\xc3\xadli\xc5\xa1 \xc5\xbelu\xc5\xa5ou\xc4\x8dk\xc3\xbd k\xc5\xaf\xc5\x88"
@@ -132,6 +140,362 @@ test_g_file_info (void)
g_object_unref (info_copy);
}
+#ifdef G_OS_WIN32
+static void
+test_internal_enhanced_stdio (void)
+{
+ char *p0, *p1, *ps;
+ gboolean try_sparse;
+ gchar *tmp_dir_root;
+ wchar_t *tmp_dir_root_w;
+ gchar *c;
+ DWORD fsflags;
+ FILE *f;
+ SYSTEMTIME st;
+ FILETIME ft;
+ HANDLE h;
+ GStatBuf statbuf_p0, statbuf_p1, statbuf_ps;
+ GFile *gf_p0, *gf_p1, *gf_ps;
+ GFileInfo *fi_p0, *fi_p1, *fi_ps;
+ guint64 size_p0, alsize_p0, size_ps, alsize_ps;
+ const gchar *id_p0;
+ const gchar *id_p1;
+ volatile guint64 time_p0;
+ gchar *tmp_dir;
+ wchar_t *programdata_dir_w;
+ wchar_t *users_dir_w;
+ static const GUID folder_id_programdata =
+ { 0x62AB5D82, 0xFDC1, 0x4DC3, { 0xA9, 0xDD, 0x07, 0x0D, 0x1D, 0x49, 0x5D, 0x97 } };
+ static const GUID folder_id_users =
+ { 0x0762D272, 0xC50A, 0x4BB0, { 0xA3, 0x82, 0x69, 0x7D, 0xCD, 0x72, 0x9B, 0x80 } };
+
+ programdata_dir_w = NULL;
+ SHGetKnownFolderPath (&folder_id_programdata, 0, NULL, &programdata_dir_w);
+
+ users_dir_w = NULL;
+ SHGetKnownFolderPath (&folder_id_users, 0, NULL, &users_dir_w);
+
+ if (programdata_dir_w != NULL && users_dir_w != NULL)
+ {
+ gchar *programdata;
+ gchar *users_dir;
+ gchar *allusers;
+ GFile *gf_programdata, *gf_allusers;
+ GFileInfo *fi_programdata, *fi_allusers, *fi_allusers_target;
+ GFileType ft_allusers;
+ GFileType ft_allusers_target;
+ GFileType ft_programdata;
+ gboolean allusers_is_symlink;
+ const gchar *id_allusers;
+ const gchar *id_allusers_target;
+ const gchar *id_programdata;
+ const gchar *allusers_target;
+
+ /* C:/ProgramData */
+ programdata = g_utf16_to_utf8 (programdata_dir_w, -1, NULL, NULL, NULL);
+ g_assert_nonnull (programdata);
+ /* C:/Users */
+ users_dir = g_utf16_to_utf8 (users_dir_w, -1, NULL, NULL, NULL);
+ g_assert_nonnull (users_dir);
+ /* "C:/Users/All Users" is a known directory symlink
+ * for "C:/ProgramData".
+ */
+ allusers = g_build_filename (users_dir, "All Users", NULL);
+ g_assert_nonnull (allusers);
+
+ /* We don't test g_stat() and g_lstat() on these directories,
+ * because it is pointless - there's no way to tell that these
+ * functions behave correctly in this case
+ * (st_ino is useless, so we can't tell apart g_stat() and g_lstat()
+ * results; st_mode is also useless as it does not support S_ISLNK;
+ * and these directories have no interesting properties other
+ * than [not] being symlinks).
+ */
+ gf_programdata = g_file_new_for_path (programdata);
+ gf_allusers = g_file_new_for_path (allusers);
+
+ fi_programdata = g_file_query_info (gf_programdata,
+ G_FILE_ATTRIBUTE_ID_FILE ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ fi_allusers_target = g_file_query_info (gf_allusers,
+ G_FILE_ATTRIBUTE_ID_FILE ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ fi_allusers = g_file_query_info (gf_allusers,
+ G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
+ G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
+ G_FILE_ATTRIBUTE_ID_FILE ","
+ G_FILE_ATTRIBUTE_STANDARD_TYPE,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ NULL, NULL);
+
+ g_assert (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE));
+ g_assert (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
+
+ g_assert (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE));
+ g_assert (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
+
+ g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE));
+ g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_TYPE));
+ g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
+ g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
+
+ ft_allusers = g_file_info_get_file_type (fi_allusers);
+ ft_allusers_target = g_file_info_get_file_type (fi_allusers_target);
+ ft_programdata = g_file_info_get_file_type (fi_programdata);
+
+ g_assert (ft_allusers == G_FILE_TYPE_SYMBOLIC_LINK);
+ g_assert (ft_allusers_target == G_FILE_TYPE_DIRECTORY);
+ g_assert (ft_programdata == G_FILE_TYPE_DIRECTORY);
+
+ allusers_is_symlink = g_file_info_get_attribute_boolean (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
+
+ g_assert_true (allusers_is_symlink);
+
+ id_allusers = g_file_info_get_attribute_string (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE);
+ id_allusers_target = g_file_info_get_attribute_string (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE);
+ id_programdata = g_file_info_get_attribute_string (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE);
+
+ g_assert_cmpstr (id_allusers_target, ==, id_programdata);
+ g_assert_cmpstr (id_allusers, !=, id_programdata);
+
+ allusers_target = g_file_info_get_symlink_target (fi_allusers);
+
+ g_assert_true (g_str_has_suffix (allusers_target, "ProgramData"));
+
+ g_object_unref (fi_allusers);
+ g_object_unref (fi_allusers_target);
+ g_object_unref (fi_programdata);
+ g_object_unref (gf_allusers);
+ g_object_unref (gf_programdata);
+
+ g_free (allusers);
+ g_free (users_dir);
+ g_free (programdata);
+ }
+
+ if (programdata_dir_w)
+ CoTaskMemFree (programdata_dir_w);
+
+ if (users_dir_w)
+ CoTaskMemFree (users_dir_w);
+
+ tmp_dir = g_dir_make_tmp ("glib_stdio_testXXXXXX", NULL);
+ g_assert_nonnull (tmp_dir);
+
+ /* Technically, this isn't necessary - we already assume NTFS, because of
+ * symlink support, and NTFS also supports sparse files. Still, given
+ * the amount of unusual I/O APIs called in this test, checking for
+ * sparse file support of the filesystem where temp directory is
+ * doesn't seem to be out of place.
+ */
+ try_sparse = FALSE;
+ tmp_dir_root = g_strdup (tmp_dir);
+ /* We need "C:\\" or "C:/", with a trailing [back]slash */
+ for (c = tmp_dir_root; c && c[0] && c[1]; c++)
+ if (c[0] == ':')
+ {
+ c[2] = '\0';
+ break;
+ }
+ tmp_dir_root_w = g_utf8_to_utf16 (tmp_dir_root, -1, NULL, NULL, NULL);
+ g_assert_nonnull (tmp_dir_root_w);
+ g_free (tmp_dir_root);
+ g_assert_true (GetVolumeInformationW (tmp_dir_root_w, NULL, 0, NULL, NULL, &fsflags, NULL, 0));
+ g_free (tmp_dir_root_w);
+ try_sparse = (fsflags & FILE_SUPPORTS_SPARSE_FILES) == FILE_SUPPORTS_SPARSE_FILES;
+
+ p0 = g_build_filename (tmp_dir, "zool", NULL);
+ p1 = g_build_filename (tmp_dir, "looz", NULL);
+ ps = g_build_filename (tmp_dir, "sparse", NULL);
+
+ if (try_sparse)
+ {
+ FILE_SET_SPARSE_BUFFER ssb;
+ FILE_ZERO_DATA_INFORMATION zdi;
+
+ g_remove (ps);
+
+ f = g_fopen (ps, "wb");
+ g_assert_nonnull (f);
+
+ h = (HANDLE) _get_osfhandle (fileno (f));
+ g_assert (h != INVALID_HANDLE_VALUE);
+
+ ssb.SetSparse = TRUE;
+ g_assert_true (DeviceIoControl (h,
+ FSCTL_SET_SPARSE,
+ &ssb, sizeof (ssb),
+ NULL, 0, NULL, NULL));
+
+ /* Make it a sparse file that starts with 4GBs of zeros */
+ zdi.FileOffset.QuadPart = 0;
+ zdi.BeyondFinalZero.QuadPart = 0xFFFFFFFFULL + 1;
+ g_assert_true (DeviceIoControl (h,
+ FSCTL_SET_ZERO_DATA,
+ &zdi, sizeof (zdi),
+ NULL, 0, NULL, NULL));
+
+ /* Let's not keep this seemingly 4GB monster around
+ * longer than we absolutely need to. Do all operations
+ * without assertions, then remove the file immediately.
+ */
+ _fseeki64 (f, 0xFFFFFFFFULL, SEEK_SET);
+ fprintf (f, "Hello 4GB World!");
+ fflush (f);
+ fclose (f);
+
+ memset (&statbuf_ps, 0, sizeof (statbuf_ps));
+
+ g_stat (ps, &statbuf_ps);
+
+ gf_ps = g_file_new_for_path (ps);
+
+ fi_ps = g_file_query_info (gf_ps,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ g_remove (ps);
+
+ g_assert (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ g_assert (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
+
+ size_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE);
+ alsize_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
+
+ /* allocated size should small (usually - size of the FS cluster,
+ * let's assume it's less than 1 gigabyte),
+ * size should be more than 4 gigabytes,
+ * st_size should not exceed its 0xFFFFFFFF 32-bit limit,
+ * and should be nonzero (this also detects a failed g_stat() earlier).
+ */
+ g_assert_cmpuint (alsize_ps, <, 0x40000000);
+ g_assert_cmpuint (size_ps, >, G_GUINT64_CONSTANT (0xFFFFFFFF));
+ g_assert_cmpuint (statbuf_ps.st_size, >, 0);
+ g_assert_cmpuint (statbuf_ps.st_size, <=, 0xFFFFFFFF);
+
+ g_object_unref (fi_ps);
+ g_object_unref (gf_ps);
+ }
+
+ /* Wa-a-ay past 02/07/2106 @ 6:28am (UTC),
+ * which is the date corresponding to 0xFFFFFFFF + 1.
+ * This is easier to check than Y2038 (0x80000000 + 1),
+ * since there's no need to worry about signedness this way.
+ */
+ st.wYear = 2106;
+ st.wMonth = 2;
+ st.wDay = 9;
+ st.wHour = 0;
+ st.wMinute = 0;
+ st.wSecond = 0;
+ st.wMilliseconds = 0;
+
+ g_assert_true (SystemTimeToFileTime (&st, &ft));
+
+ f = g_fopen (p0, "w");
+ g_assert_nonnull (f);
+
+ h = (HANDLE) _get_osfhandle (fileno (f));
+ g_assert (h != INVALID_HANDLE_VALUE);
+
+ fprintf (f, "1");
+ fflush (f);
+
+ g_assert_true (SetFileTime (h, &ft, &ft, &ft));
+
+ fclose (f);
+
+ f = g_fopen (p1, "w");
+ g_assert_nonnull (f);
+
+ fclose (f);
+
+ memset (&statbuf_p0, 0, sizeof (statbuf_p0));
+ memset (&statbuf_p1, 0, sizeof (statbuf_p1));
+
+ g_assert_cmpint (g_stat (p0, &statbuf_p0), ==, 0);
+ g_assert_cmpint (g_stat (p1, &statbuf_p1), ==, 0);
+
+ gf_p0 = g_file_new_for_path (p0);
+ gf_p1 = g_file_new_for_path (p1);
+
+ fi_p0 = g_file_query_info (gf_p0,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE ","
+ G_FILE_ATTRIBUTE_ID_FILE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ fi_p1 = g_file_query_info (gf_p1,
+ G_FILE_ATTRIBUTE_STANDARD_SIZE ","
+ G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE ","
+ G_FILE_ATTRIBUTE_ID_FILE ","
+ G_FILE_ATTRIBUTE_TIME_MODIFIED,
+ G_FILE_QUERY_INFO_NONE,
+ NULL, NULL);
+
+ g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
+ g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_ID_FILE));
+ g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED));
+
+ g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_SIZE));
+ g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
+ g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_ID_FILE));
+ g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_TIME_MODIFIED));
+
+ size_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE);
+ alsize_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
+
+ /* size should be 1, allocated size should be something else
+ * (could be 0 or the size of the FS cluster, but never 1).
+ */
+ g_assert_cmpuint (size_p0, ==, statbuf_p0.st_size);
+ g_assert_cmpuint (size_p0, ==, 1);
+ g_assert_cmpuint (alsize_p0, !=, size_p0);
+
+ id_p0 = g_file_info_get_attribute_string (fi_p0, G_FILE_ATTRIBUTE_ID_FILE);
+ id_p1 = g_file_info_get_attribute_string (fi_p1, G_FILE_ATTRIBUTE_ID_FILE);
+
+ /* st_ino from W32 stat() is useless for file identification.
+ * It will be either 0, or it will be the same for both files.
+ */
+ g_assert (statbuf_p0.st_ino == statbuf_p1.st_ino);
+ g_assert_cmpstr (id_p0, !=, id_p1);
+
+ time_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED);
+
+ /* Check that GFileInfo doesn't suffer from Y2106 problem.
+ * Don't check stat(), as its contents may vary depending on
+ * the host platform architecture
+ * (time fields are 32-bit on 32-bit Windows,
+ * and 64-bit on 64-bit Windows, usually),
+ * so it *can* pass this test in some cases.
+ */
+ g_assert (time_p0 > G_GUINT64_CONSTANT (0xFFFFFFFF));
+
+ g_object_unref (fi_p0);
+ g_object_unref (fi_p1);
+ g_object_unref (gf_p0);
+ g_object_unref (gf_p1);
+ g_remove (p0);
+ g_remove (p1);
+ g_free (p0);
+ g_free (p1);
+ g_rmdir (tmp_dir);
+}
+#endif
+
+
int
main (int argc,
char *argv[])
@@ -139,6 +503,9 @@ main (int argc,
g_test_init (&argc, &argv, NULL);
g_test_add_func ("/g-file-info/test_g_file_info", test_g_file_info);
+#ifdef G_OS_WIN32
+ g_test_add_func ("/g-file-info/internal-enhanced-stdio", test_internal_enhanced_stdio);
+#endif
return g_test_run();
}
diff --git a/gio/tests/gdbus-proxy.c b/gio/tests/gdbus-proxy.c
index fff1f48da..8a2c324a2 100644
--- a/gio/tests/gdbus-proxy.c
+++ b/gio/tests/gdbus-proxy.c
@@ -74,11 +74,15 @@ test_methods (GDBusProxy *proxy)
g_assert_cmpstr (error->message, ==, "Yo is not a proper greeting");
g_clear_error (&error);
- /* Check that we get a timeout if the method handling is taking longer than timeout */
+ /* Check that we get a timeout if the method handling is taking longer than
+ * timeout. We use such a long sleep because on slow machines, if the
+ * sleep isn't much longer than the timeout and we're doing a parallel
+ * build, there's no guarantee we'll be scheduled in the window between
+ * the timeout being hit and the sleep finishing. */
error = NULL;
result = g_dbus_proxy_call_sync (proxy,
"Sleep",
- g_variant_new ("(i)", 500 /* msec */),
+ g_variant_new ("(i)", 10000 /* msec */),
G_DBUS_CALL_FLAGS_NONE,
100 /* msec */,
NULL,
@@ -104,12 +108,14 @@ test_methods (GDBusProxy *proxy)
g_assert_cmpstr (g_variant_get_type_string (result), ==, "()");
g_variant_unref (result);
- /* now set the proxy-default timeout to 250 msec and try the 500 msec call - this should FAIL */
+ /* Now set the proxy-default timeout to 250 msec and try the 10000 msec
+ * call - this should FAIL. Again, we use such a long sleep because on slow
+ * machines there's no guarantee we'll be scheduled when we want to be. */
g_dbus_proxy_set_default_timeout (proxy, 250);
g_assert_cmpint (g_dbus_proxy_get_default_timeout (proxy), ==, 250);
result = g_dbus_proxy_call_sync (proxy,
"Sleep",
- g_variant_new ("(i)", 500 /* msec */),
+ g_variant_new ("(i)", 10000 /* msec */),
G_DBUS_CALL_FLAGS_NONE,
-1, /* use proxy default (e.g. 250 msec) */
NULL,
@@ -829,6 +835,8 @@ fail_test (gpointer user_data)
static void
test_async (void)
{
+ guint id;
+
g_dbus_proxy_new_for_bus (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_NONE,
NULL, /* GDBusInterfaceInfo */
@@ -842,8 +850,10 @@ test_async (void)
/* this is safe; testserver will exit once the bus goes away */
g_assert (g_spawn_command_line_async (g_test_get_filename (G_TEST_BUILT, "gdbus-testserver", NULL), NULL));
- g_timeout_add (10000, fail_test, NULL);
+ id = g_timeout_add (10000, fail_test, NULL);
g_main_loop_run (loop);
+
+ g_source_remove (id);
}
static void
@@ -889,6 +899,7 @@ test_wellknown_noauto (void)
{
GError *error = NULL;
GDBusProxy *proxy;
+ guint id;
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION,
G_DBUS_PROXY_FLAGS_DO_NOT_AUTO_START,
@@ -898,9 +909,10 @@ test_wellknown_noauto (void)
g_assert (proxy != NULL);
g_dbus_proxy_call (proxy, "method", NULL, G_DBUS_CALL_FLAGS_NONE, -1, NULL, check_error, NULL);
- g_timeout_add (10000, fail_test, NULL);
+ id = g_timeout_add (10000, fail_test, NULL);
g_main_loop_run (loop);
g_object_unref (proxy);
+ g_source_remove (id);
}
int
diff --git a/gio/tests/gmenumodel.c b/gio/tests/gmenumodel.c
index f18db77d6..a604f996f 100644
--- a/gio/tests/gmenumodel.c
+++ b/gio/tests/gmenumodel.c
@@ -2,33 +2,6 @@
#include "gdbus-sessionbus.h"
-static gboolean
-time_out (gpointer unused G_GNUC_UNUSED)
-{
- g_error ("Timed out");
- /* not reached */
- return FALSE;
-}
-
-static guint
-add_timeout (guint seconds)
-{
-#ifdef G_OS_UNIX
- /* Safety-catch against the main loop having blocked */
- alarm (seconds + 5);
-#endif
- return g_timeout_add_seconds (seconds, time_out, NULL);
-}
-
-static void
-cancel_timeout (guint timeout_id)
-{
-#ifdef G_OS_UNIX
- alarm (0);
-#endif
- g_source_remove (timeout_id);
-}
-
/* Markup printing {{{1 */
/* This used to be part of GLib, but it was removed before the stable
@@ -845,9 +818,7 @@ test_dbus_subscriptions (void)
GMainLoop *loop;
GError *error = NULL;
guint export_id;
- guint timeout_id;
- timeout_id = add_timeout (60);
loop = g_main_loop_new (NULL, FALSE);
bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, NULL);
@@ -868,42 +839,32 @@ test_dbus_subscriptions (void)
g_assert_cmpint (items_changed_count, ==, 0);
- /* We don't subscribe to change-notification until we look at the items */
g_timeout_add (100, stop_loop, loop);
g_main_loop_run (loop);
- /* Looking at the items triggers subscription */
g_menu_model_get_n_items (G_MENU_MODEL (proxy));
- while (items_changed_count < 1)
- g_main_context_iteration (NULL, TRUE);
+ g_timeout_add (100, stop_loop, loop);
+ g_main_loop_run (loop);
- /* We get all three items in one batch */
g_assert_cmpint (items_changed_count, ==, 1);
g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3);
- /* If we wait, we don't get any more */
g_timeout_add (100, stop_loop, loop);
g_main_loop_run (loop);
- g_assert_cmpint (items_changed_count, ==, 1);
- g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 3);
- /* Now we're subscribed, we get changes individually */
g_menu_append (menu, "item4", NULL);
g_menu_append (menu, "item5", NULL);
g_menu_append (menu, "item6", NULL);
g_menu_remove (menu, 0);
g_menu_remove (menu, 0);
- while (items_changed_count < 6)
- g_main_context_iteration (NULL, TRUE);
+ g_timeout_add (200, stop_loop, loop);
+ g_main_loop_run (loop);
g_assert_cmpint (items_changed_count, ==, 6);
g_assert_cmpint (g_menu_model_get_n_items (G_MENU_MODEL (proxy)), ==, 4);
-
- /* After destroying the proxy and waiting a bit, we don't get any more
- * items-changed signals */
g_object_unref (proxy);
g_timeout_add (100, stop_loop, loop);
@@ -922,7 +883,6 @@ test_dbus_subscriptions (void)
g_main_loop_unref (loop);
g_object_unref (bus);
- cancel_timeout (timeout_id);
}
static gpointer
diff --git a/gio/tests/gschema-compile.c b/gio/tests/gschema-compile.c
index 40a396d2f..65f656c52 100644
--- a/gio/tests/gschema-compile.c
+++ b/gio/tests/gschema-compile.c
@@ -86,6 +86,7 @@ static const SchemaTest tests[] = {
{ "enum", NULL, NULL },
{ "enum-with-aliases", NULL, NULL },
{ "enum-with-invalid-alias", NULL, "*“banger” is not in enumerated type*" },
+ { "enum-with-invalid-value", NULL, "*Invalid numeric value*" },
{ "enum-with-repeated-alias", NULL, "*<alias value='sausages'/> already specified*" },
{ "enum-with-repeated-nick", NULL, "*<value nick='spam'/> already specified*" },
{ "enum-with-repeated-value", NULL, "*value='1' already specified*" },
diff --git a/gio/tests/httpd.c b/gio/tests/httpd.c
index 41bc6c8b8..9bca6c96c 100644
--- a/gio/tests/httpd.c
+++ b/gio/tests/httpd.c
@@ -67,12 +67,19 @@ handler (GThreadedSocketService *service,
version = NULL;
tmp = strchr (escaped, ' ');
- if (tmp != NULL)
+ if (tmp == NULL)
{
- *tmp = 0;
- version = tmp + 1;
+ send_error (out, 400, "Bad Request");
+ goto out;
+ }
+ *tmp = 0;
+
+ version = tmp + 1;
+ if (!g_str_has_prefix (version, "HTTP/1."))
+ {
+ send_error(out, 505, "HTTP Version Not Supported");
+ goto out;
}
- version = version; /* To avoid -Wunused-but-set-variable */
query = strchr (escaped, '?');
if (query != NULL)
diff --git a/gio/tests/meson.build b/gio/tests/meson.build
index e149a4bb3..fb17cc407 100644
--- a/gio/tests/meson.build
+++ b/gio/tests/meson.build
@@ -113,7 +113,9 @@ if host_machine.system() != 'windows'
'socket-address',
'stream-rw_all',
'unix-fd',
+ 'unix-mounts',
'unix-streams',
+ 'g-file-info-filesystem-readonly',
'gschema-compile',
]
@@ -145,6 +147,7 @@ if host_machine.system() != 'windows'
input : ['test-codegen.xml'],
output : ['gdbus-test-codegen-generated.h',
'gdbus-test-codegen-generated.c'],
+ depend_files : gdbus_codegen_built_files,
command : [python, gdbus_codegen,
'--interface-prefix', 'org.project.',
'--output-directory', '@OUTDIR@',
diff --git a/gio/tests/resources.c b/gio/tests/resources.c
index b002325b8..8163aa141 100644
--- a/gio/tests/resources.c
+++ b/gio/tests/resources.c
@@ -134,6 +134,32 @@ test_resource (GResource *resource)
g_assert_no_error (error);
g_assert_cmpint (g_strv_length (children), ==, 2);
g_strfreev (children);
+
+ /* Test the preferred lookup where we have a trailing slash. */
+ children = g_resource_enumerate_children (resource,
+ "/a_prefix/",
+ G_RESOURCE_LOOKUP_FLAGS_NONE,
+ &error);
+ g_assert (children != NULL);
+ g_assert_no_error (error);
+ g_assert_cmpint (g_strv_length (children), ==, 2);
+ g_strfreev (children);
+
+ /* test with a path > 256 and no trailing slash to test the
+ * slow path of resources where we allocate a modified path.
+ */
+ children = g_resource_enumerate_children (resource,
+ "/not/here/not/here/not/here/not/here/not/here/not/here/not/here"
+ "/not/here/not/here/not/here/not/here/not/here/not/here/not/here"
+ "/not/here/not/here/not/here/not/here/not/here/not/here/not/here"
+ "/not/here/not/here/not/here/not/here/not/here/not/here/not/here"
+ "/not/here/not/here/not/here/not/here/not/here/not/here/not/here"
+ "/with/no/trailing/slash",
+ G_RESOURCE_LOOKUP_FLAGS_NONE,
+ &error);
+ g_assert (children == NULL);
+ g_assert_error (error, G_RESOURCE_ERROR, G_RESOURCE_ERROR_NOT_FOUND);
+ g_clear_error (&error);
}
static void
@@ -156,6 +182,49 @@ test_resource_file (void)
}
static void
+test_resource_file_path (void)
+{
+ static const struct {
+ const gchar *input;
+ const gchar *expected;
+ } test_uris[] = {
+ { "resource://", "resource:///" },
+ { "resource:///", "resource:///" },
+ { "resource://////", "resource:///" },
+ { "resource:///../../../", "resource:///" },
+ { "resource:///../../..", "resource:///" },
+ { "resource://abc", "resource:///abc" },
+ { "resource:///abc/", "resource:///abc" },
+ { "resource:/a/b/../c/", "resource:///a/c" },
+ { "resource://../a/b/../c/../", "resource:///a" },
+ { "resource://a/b/cc//bb//a///", "resource:///a/b/cc/bb/a" },
+ { "resource://././././", "resource:///" },
+ { "resource://././././../", "resource:///" },
+ { "resource://a/b/c/d.png", "resource:///a/b/c/d.png" },
+ { "resource://a/b/c/..png", "resource:///a/b/c/..png" },
+ { "resource://a/b/c/./png", "resource:///a/b/c/png" },
+ };
+ guint i;
+
+ for (i = 0; i < G_N_ELEMENTS (test_uris); i++)
+ {
+ GFile *file;
+ gchar *uri;
+
+ file = g_file_new_for_uri (test_uris[i].input);
+ g_assert (file != NULL);
+
+ uri = g_file_get_uri (file);
+ g_assert (uri != NULL);
+
+ g_assert_cmpstr (uri, ==, test_uris[i].expected);
+
+ g_object_unref (file);
+ g_free (uri);
+ }
+}
+
+static void
test_resource_data (void)
{
GResource *resource;
@@ -181,6 +250,36 @@ test_resource_data (void)
}
static void
+test_resource_data_unaligned (void)
+{
+ GResource *resource;
+ GError *error = NULL;
+ gboolean loaded_file;
+ char *content, *content_copy;
+ gsize content_size;
+ GBytes *data;
+
+ loaded_file = g_file_get_contents (g_test_get_filename (G_TEST_BUILT, "test.gresource", NULL),
+ &content, &content_size, NULL);
+ g_assert (loaded_file);
+
+ content_copy = g_new (char, content_size + 1);
+ memcpy (content_copy + 1, content, content_size);
+
+ data = g_bytes_new_with_free_func (content_copy + 1, content_size,
+ (GDestroyNotify) g_free, content_copy);
+ g_free (content);
+ resource = g_resource_new_from_data (data, &error);
+ g_bytes_unref (data);
+ g_assert (resource != NULL);
+ g_assert_no_error (error);
+
+ test_resource (resource);
+
+ g_resource_unref (resource);
+}
+
+static void
test_resource_registered (void)
{
GResource *resource;
@@ -643,7 +742,9 @@ main (int argc,
_g_test2_register_resource ();
g_test_add_func ("/resource/file", test_resource_file);
+ g_test_add_func ("/resource/file-path", test_resource_file_path);
g_test_add_func ("/resource/data", test_resource_data);
+ g_test_add_func ("/resource/data_unaligned", test_resource_data_unaligned);
g_test_add_func ("/resource/registered", test_resource_registered);
g_test_add_func ("/resource/manual", test_resource_manual);
g_test_add_func ("/resource/manual2", test_resource_manual2);
diff --git a/gio/tests/schema-tests/enum-with-invalid-value.gschema.xml b/gio/tests/schema-tests/enum-with-invalid-value.gschema.xml
new file mode 100644
index 000000000..02071e070
--- /dev/null
+++ b/gio/tests/schema-tests/enum-with-invalid-value.gschema.xml
@@ -0,0 +1,10 @@
+<schemalist>
+ <enum id='org.gtk.test.MyEnum'>
+ <value nick='nospam' value='*'/>
+ <value nick='spam' value='1'/>
+ <value nick='ham' value='2'/>
+ <value nick='eggs' value='3'/>
+ <value nick='bangers' value='4'/>
+ <value nick='mash' value='5'/>
+ </enum>
+</schemalist>
diff --git a/gio/tests/socket.c b/gio/tests/socket.c
index 4343dd537..0835a6655 100644
--- a/gio/tests/socket.c
+++ b/gio/tests/socket.c
@@ -1386,6 +1386,53 @@ test_unix_connection_ancillary_data (void)
* g_unix_connection_receive_credentials().
*/
}
+
+static gboolean
+postmortem_source_cb (GSocket *socket,
+ GIOCondition condition,
+ gpointer user_data)
+{
+ gboolean *been_here = user_data;
+
+ g_assert_cmpint (condition, ==, G_IO_NVAL);
+
+ *been_here = TRUE;
+ return FALSE;
+}
+
+static void
+test_source_postmortem (void)
+{
+ GMainContext *context;
+ GSocket *socket;
+ GSource *source;
+ GError *error = NULL;
+ gboolean callback_visited = FALSE;
+
+ socket = g_socket_new (G_SOCKET_FAMILY_UNIX, G_SOCKET_TYPE_STREAM, G_SOCKET_PROTOCOL_DEFAULT, &error);
+ g_assert_no_error (error);
+
+ context = g_main_context_new ();
+
+ source = g_socket_create_source (socket, G_IO_IN, NULL);
+ g_source_set_callback (source, (GSourceFunc) postmortem_source_cb,
+ &callback_visited, NULL);
+ g_source_attach (source, context);
+ g_source_unref (source);
+
+ g_socket_close (socket, &error);
+ g_assert_no_error (error);
+ g_object_unref (socket);
+
+ /* Test that, after a socket is closed, its source callback should be called
+ * exactly once. */
+ g_main_context_iteration (context, FALSE);
+ g_assert (callback_visited);
+ g_assert (!g_main_context_pending (context));
+
+ g_main_context_unref (context);
+}
+
#endif /* G_OS_UNIX */
static void
@@ -1643,6 +1690,7 @@ main (int argc,
g_test_add_func ("/socket/unix-from-fd", test_unix_from_fd);
g_test_add_func ("/socket/unix-connection", test_unix_connection);
g_test_add_func ("/socket/unix-connection-ancillary-data", test_unix_connection_ancillary_data);
+ g_test_add_func ("/socket/source-postmortem", test_source_postmortem);
#endif
g_test_add_func ("/socket/reuse/tcp", test_reuse_tcp);
g_test_add_func ("/socket/reuse/udp", test_reuse_udp);
diff --git a/gio/tests/unix-mounts.c b/gio/tests/unix-mounts.c
new file mode 100644
index 000000000..3d54047dc
--- /dev/null
+++ b/gio/tests/unix-mounts.c
@@ -0,0 +1,57 @@
+/* GLib testing framework examples and tests
+ *
+ * Copyright © 2017 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/>.
+ */
+
+#include <glib.h>
+
+#ifndef G_OS_UNIX
+#error This is a Unix-specific test
+#endif
+
+#include <errno.h>
+#include <locale.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+
+static void
+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"));
+}
+
+static void
+test_is_system_device_path (void)
+{
+ g_assert_true (g_unix_is_system_device_path ("devpts"));
+ g_assert_false (g_unix_is_system_device_path ("/"));
+}
+
+int
+main (int argc,
+ char *argv[])
+{
+ setlocale (LC_ALL, "");
+
+ g_test_init (&argc, &argv, NULL);
+
+ g_test_add_func ("/unix-mounts/is-system-fs-type", test_is_system_fs_type);
+ g_test_add_func ("/unix-mounts/is-system-device-path", test_is_system_device_path);
+
+ return g_test_run ();
+}