From 2edc4beaf99a0eb139005443a9ed9ebad1d4cf5f Mon Sep 17 00:00:00 2001 From: Hyunjee Kim Date: Tue, 3 Dec 2019 09:46:57 +0900 Subject: [PATCH] Imported Upstream version 2.55.0 --- NEWS | 173 +++- config.h.meson | 9 + config.h.win32.in | 253 +++--- configure.ac | 46 +- docs/reference/gio/Makefile.am | 5 +- docs/reference/gio/gio-docs.xml | 2 - docs/reference/gio/gio-sections.txt | 38 +- docs/reference/gio/meson.build | 58 +- docs/reference/glib/Makefile.am | 4 +- docs/reference/glib/glib-docs.xml | 4 + docs/reference/glib/glib-overrides.txt | 4 - docs/reference/glib/glib-sections.txt | 19 +- docs/reference/glib/meson.build | 57 +- docs/reference/gobject/Makefile.am | 5 +- docs/reference/gobject/glib-genmarshal.xml | 44 + docs/reference/gobject/glib-mkenums.xml | 180 +++- docs/reference/gobject/meson.build | 57 +- docs/reference/gobject/tut_gsignal.xml | 4 +- docs/reference/gobject/tut_gtype.xml | 2 +- gio/Makefile.am | 24 +- gio/completion/gsettings | 4 +- gio/data-to-c.pl | 37 - gio/data-to-c.py | 2 +- gio/gappinfo.c | 30 +- gio/gappinfo.h | 12 +- gio/gapplication.c | 7 +- gio/gapplicationcommandline.c | 12 +- gio/gasynchelper.c | 4 + gio/gasyncresult.c | 21 +- gio/gbufferedinputstream.c | 2 +- gio/gcancellable.c | 16 +- gio/gdbus-2.0/codegen/Makefile.am | 2 +- gio/gdbus-2.0/codegen/gdbus-codegen.in | 14 +- gio/gdbus-2.0/codegen/meson.build | 22 +- gio/gdbus-tool.c | 253 ++++-- gio/gdbusaddress.c | 6 +- gio/gdbusauth.c | 9 +- gio/gdbusauthmechanismsha1.c | 10 +- gio/gdbusconnection.c | 16 +- gio/gdbuserror.c | 2 +- gio/gdbusinterfaceskeleton.c | 2 +- gio/gdbusmessage.c | 14 +- gio/gdbusnamewatching.h | 2 +- gio/gdbusobjectmanagerclient.c | 18 +- gio/gdesktopappinfo.c | 80 +- gio/gdtlsconnection.c | 4 +- gio/gfile.c | 236 +++++- gio/gfile.h | 19 + gio/gfileenumerator.c | 2 +- gio/gioenums.h | 2 +- gio/giomodule.c | 4 +- gio/giotypes.h | 12 +- gio/glib-compile-resources.c | 8 + gio/glib-compile-schemas.c | 4 +- gio/glistmodel.c | 18 +- gio/glocalfile.c | 56 +- gio/glocalfileinfo.c | 121 +-- gio/glocalfileinfo.h | 5 +- gio/glocalfileoutputstream.c | 8 +- gio/gmount.c | 9 +- gio/gopenuriportal.c | 4 +- gio/gosxappinfo.c | 38 +- gio/gosxcontenttype.c | 103 ++- gio/goutputstream.c | 10 +- gio/gpollfilemonitor.c | 3 +- gio/gresource.c | 54 +- gio/gresourcefile.c | 125 +-- gio/gschema.dtd | 5 +- gio/gseekable.c | 12 +- gio/gsettings.c | 8 +- gio/gsettingsbackend.c | 4 +- gio/gsettingsschema.c | 17 +- gio/gsimpleasyncresult.c | 7 +- gio/gsocket.c | 483 ++++++++--- gio/gsocket.h | 12 + gio/gsocketlistener.h | 2 +- gio/gsubprocess.c | 2 +- gio/gsubprocesslauncher.c | 20 +- gio/gtask.c | 23 +- gio/gthreadedresolver.c | 4 +- gio/gtlsbackend.c | 30 +- gio/gtlsdatabase.c | 4 +- gio/gtlspassword.c | 4 +- gio/gunixmounts.c | 147 +++- gio/gunixmounts.h | 6 + gio/gvolume.c | 2 +- gio/gvolumemonitor.c | 5 +- gio/inotify/inotify-helper.c | 16 +- gio/inotify/inotify-path.c | 5 +- gio/kqueue/kqueue-helper.c | 4 +- gio/meson.build | 14 + gio/tests/Makefile.am | 28 +- gio/tests/appinfo.c | 83 +- gio/tests/contenttype.c | 75 +- gio/tests/dbus-launch.c | 2 +- ...c6a4e022b17686306243dada811d550d25eb1fb.desktop | 2 +- gio/tests/file.c | 120 ++- gio/tests/g-file-info-filesystem-readonly.c | 176 ++++ gio/tests/g-file-info.c | 367 ++++++++ gio/tests/gdbus-proxy.c | 24 +- gio/tests/gmenumodel.c | 48 +- gio/tests/gschema-compile.c | 1 + gio/tests/httpd.c | 15 +- gio/tests/meson.build | 3 + gio/tests/resources.c | 101 +++ .../enum-with-invalid-value.gschema.xml | 10 + gio/tests/socket.c | 48 ++ gio/tests/unix-mounts.c | 57 ++ glib-gettextize.in | 0 glib/Makefile.am | 2 + glib/docs.c | 14 +- glib/gbase64.c | 4 +- glib/gbookmarkfile.c | 2 +- glib/gbytes.c | 9 +- glib/gconvert.c | 13 +- glib/gconvert.h | 2 +- glib/gdataset.c | 71 +- glib/gdate.c | 29 + glib/gdate.h | 2 + glib/gdatetime.c | 337 ++++++++ glib/gdatetime.h | 4 + glib/genviron.c | 55 +- glib/gfileutils.c | 86 +- glib/gfileutils.h | 3 + glib/ghook.c | 2 +- glib/giochannel.c | 2 +- glib/giowin32.c | 4 +- glib/gkeyfile.c | 56 +- glib/glib-private.c | 7 + glib/glib-private.h | 18 + glib/glib-unix.c | 2 +- glib/glibconfig.h.win32.in | 109 ++- glib/gmacros.h | 8 +- glib/gmain.c | 121 ++- glib/gmain.h | 34 +- glib/gmem.c | 3 +- glib/gmessages.c | 84 +- glib/gmessages.h | 33 +- glib/goption.c | 4 +- glib/gpoll.c | 8 +- glib/gprintf.c | 14 + glib/gregex.c | 2 +- glib/gregex.h | 6 +- glib/gscanner.c | 2 +- glib/gshell.c | 14 +- glib/gslice.c | 18 +- glib/gslist.c | 92 +- glib/gspawn.c | 41 +- glib/gspawn.h | 2 +- glib/gstdio.c | 590 ++++++++++++- glib/gstdioprivate.h | 65 ++ glib/gstrfuncs.c | 32 +- glib/gstringchunk.c | 2 +- glib/gtester-report | 9 +- glib/gtester.c | 26 +- glib/gtestutils.c | 119 ++- glib/gtestutils.h | 18 +- glib/gthread-posix.c | 17 +- glib/gtypes.h | 4 +- glib/gunicode.h | 8 +- glib/gutf8.c | 2 +- glib/gutils.c | 178 ++-- glib/gutils.h | 3 +- glib/gvariant-parser.c | 2 + glib/gvariant.c | 2 +- glib/gversionmacros.h | 24 + glib/meson.build | 13 +- glib/pcre/pcre_compile.c | 2 +- glib/tests/array-test.c | 2 +- glib/tests/autoptr.c | 5 + glib/tests/bytes.c | 2 +- glib/tests/convert.c | 6 +- glib/tests/date.c | 27 + glib/tests/fileutils.c | 30 + glib/tests/gdatetime.c | 321 ++++++- glib/tests/slist.c | 73 ++ glib/tests/unix.c | 2 +- glib/tests/utf8-misc.c | 5 + glib/tests/utils.c | 27 + gmodule/gmodule-dl.c | 9 +- gmodule/gmodule-win32.c | 8 + gmodule/gmodule.c | 4 + gobject/Makefile.am | 1 + gobject/gboxed.c | 8 +- gobject/gclosure.c | 8 +- gobject/glib-genmarshal.in | 25 +- gobject/glib-mkenums.in | 39 +- gobject/gobject.c | 40 +- gobject/gparam.c | 4 +- gobject/gsignal.c | 4 +- gobject/gvalue.h | 2 + gobject/gvaluearray.c | 2 +- gobject/meson.build | 4 +- m4macros/glib-2.0.m4 | 5 +- m4macros/glib-gettext.m4 | 5 +- m4macros/glibtests.m4 | 3 + m4macros/gsettings.m4 | 3 + meson.build | 15 +- po/cs.po | 892 +++++++++++--------- po/de.po | 841 +++++++++++-------- po/es.po | 921 ++++++++++++--------- po/nb.po | 860 ++++++++++--------- po/sl.po | 300 ++++--- tests/assert-msg-test.gdb | 3 +- tests/timeloop-basic.c | 4 +- win32/gen_util_scripts.py | 1 - win32/setup.py | 1 - win32/vs10/glib-version-paths.props.in | 20 +- win32/vs9/glib-version-paths.vsprops.in | 22 +- 209 files changed, 8043 insertions(+), 3372 deletions(-) delete mode 100755 gio/data-to-c.pl mode change 100644 => 100755 gio/data-to-c.py mode change 100644 => 100755 gio/gdbus-2.0/codegen/gdbus-codegen.in create mode 100644 gio/tests/g-file-info-filesystem-readonly.c create mode 100644 gio/tests/schema-tests/enum-with-invalid-value.gschema.xml create mode 100644 gio/tests/unix-mounts.c mode change 100644 => 100755 glib-gettextize.in create mode 100644 glib/gstdioprivate.h diff --git a/NEWS b/NEWS index d2eaa94..d51be0b 100644 --- a/NEWS +++ b/NEWS @@ -1,61 +1,146 @@ -Overview of changes in GLib 2.54.3 +Overview of changes in GLib 2.55.0 ================================== -* Bugs fixed: +* New API: + - g_clear_handle_id, to simplify removing sources from the default mainloop + - g_file_load_bytes, to make it more convenient to load files into GBytes + +* Bugs fixed: + 330458 Sample code for the GLib Key-value parser + 483341 g_error and friends create warnings when not used in MSVC + 569375 g[u]intptr undocumented + 573251 documentation for g_seekable_truncate() needs some love + 629347 Missing annotations in GFile (was: Perf throws an exception in cur... + 630983 [PATCH] Type accuracy for result of strlen() in string utilities. + 632953 Clarify documentation of GValueTransform. + 636210 Document that pre-unmount is not guaranteed and backend-dependant + 656502 type information for GSettings::backend missing from .gir + 661442 Nautilus crashes when refreshing home folder after modifying ~/.co... + 668035 gtester-report broken with python 2.7.2 and glib 2.30.1 + 670139 gbytes.c:try_steal_and_unref nit + 677233 (transfer full) annotation not correct for g_closure_new_simple re... + 679347 glocalfile seems to leak 'fstype' + 679467 Mention translation in g_warning() documentation + 689323 Variable scoping in gunixmounts.c 691436 glib-mkenums output arch dependent - 761102 Increase performance for main loop - 776147 gio/glocalfilemonitor.c doesn't handle case G_FILE_MONITOR_EVENT_MOVE... + 695681 gsettings bash completion put error messages + 705331 AM_PATH_GLIB_2_0 macro fails with -Wstrict-prototypes -Werror + 706667 Fix permission denied error when installing from an nfs directory + 711809 gdbus-proxy: Fix erroneous timeout during following tests + 722256 gslist: Simplified node removal and got rid of some code duplication + 723655 Socket source is left in the poll after the socket is closed + 723743 g_child_watch_add() doesn't check for non-pids + 725014 g_settings_schema_source_ref should check for NULL pointer + 727346 docs: Escape some backslashes for markdown + 730296 gsignal: Fix a potential NULL pointer dereference + 731625 Improve test for darwin printf format-strings + 731705 gio/tests/desktop-app-info assumes /bin/true + 737278 Clarify relationship of g_application_quit() to hold count + 738176 Skip GSpawnChildSetupFunc closures in introspection + 740223 source_object for GAsyncResult should be nullable + 740791 gio: cannot specify the source when joining a multicast group (IGM... + 740826 glib doesn't know fuse filesystems + 742548 configure.ac: stay out of autoconf's namespace + 742997 Don't skip invalid enum values in schemas + 745723 -Wunused-but-set-variable work-around no longer sufficient + 749371 Use a GHashTable as a set when possible + 751738 Unused-variable warnings in glib/tests/autoptr.c + 752239 Missing dependency for python files in build file + 752240 Add DTLS support to GIO + 753459 GDateTime: Add conversion functions from/to ISO 8601 strings + 753521 g_subprocess_launcher_set_environ misses argument annotations + 754026 gfileutils: add some sanity checks + 756009 'const gchar* const *' gets incorrectly defaulted to utf8 + 756103 Skip g_base64_decode_step() in introspection + 756128 Fix up annotations in gconvert + 756430 g_rw_lock_reader_lock() can return without locking, or error + 756470 Fix up annotations in gdataset.c + 756588 Fix up annotations on data/qdata API of GObject + 760022 Memory leak in gvariant-parser.c + 760109 [PATCH] Invalid GDate can't be g_boxed_copy()'d + 760716 Fix documentation regarding + 765063 Update annotations for gio + 765552 Please set serial in .m4 files to prevent autoreconf failure on up... + 767215 GCC version number is interpreted as start of a list in docs for g... + 767239 Tautological comparisons in convert tests + 769674 some GIO tests' arbitrary timeouts are too short + 769846 gmessages: Add timestamp to g_log_writer_format_fields() + 770459 Tutorial article is slightly wrong + 773355 Incorrect documentation about stopping a signal emission from a hook + 774083 spelling mistakes in glib: charater + 776562 Add Intel C Compiler support for G_GNUC_BEGIN/END_IGNORE_DEPRECATI... + 777308 GModule win32: disable error dialog popup + 777310 gio/gasynchelper.c: fix cast from pointer to smaller int type on w... + 777956 gmessages: Update advice for G_LOG_DOMAIN 779182 xdg-open fails with gio open for some uris - 782057 Unit tests fail in run-assert-msg-test.sh - 785113 glib-mkenums Python port fixes - 788990 Include licensing information in output from glib-mkenums, glib-genma... + 779501 Type of GIConv given wrongly on web + 780202 introspection: Don't expose GValueArray.free + 780296 xdg-open/gnome-open doesn't work if service isn't started + 781598 gstdio.h should #include what it needs to work + 781867 various gvfsd-* wants to look in /boot/efi, causes unnecessary/ina... + 783210 build: Switch to sassc for generating style + 783270 Improve Visual Studio support for Meson builds + 783825 Suggest that asynchronous operations should invoke the callback in... + 786737 No g_variant_get() example for dicts + 786785 Commit #fe2a9887a8 breaks gdbus-codegen, cannot find its module so... + 787271 Make GListModel usable from G-I bindings + 787485 g_tls_backend_supports_dtls () returns true when the backend doesn't + 787551 Factor out some duplicated code in GParamSpec validation + 787581 tests: Add tests for g_slist_copy() and g_slist_copy_deep() + 787671 meson: Fix permissions of installed scripts + 787731 g_file_query_filesystem_info() wrongly reports "filesystem::readon... + 788138 glib-compile-resources: Fix leak of a GHashTable + 788180 G_FILE_ATTRIBUTE_ID_FILE is useless on W32 + 788270 gmodule - failed to load symbol on Android 64bit + 788368 Race condition in GDbusObjectManagerClient + 788384 gtypes: Fix signedness of __builtin_bswap() usage + 788385 gtestutils: Explicitly cast args to g_assertion_message_cmpnum() + 788401 PATCH: MacOS build cannot detect content type from content - xdgmi... + 788467 Fatal errors and warnings should be reported as TAP + 788488 GFile-based API for g_build_filename() + 788489 gmain: add g_clear_source API + 788561 Document how to integrate GTest into your project + 788594 gdbus-tool doesn’t handle non-message-bus connections correctly + 788705 Allow building GLib on older Linux platforms + 788766 fixed a doc-typo in socket_get_remote_address + 788772 meson installs gdb scripts incorrectly + 788863 Add more filename type annotations for strings which can contain f... + 788880 gunixmounts: Update list of virtual file systems to ignore + 788927 Expose better API for detecting ‘system’ mounts + 788936 Show mime type icons on OS X + 788948 Document Autotools best practices for genmarshal/mkenums + 788975 Meson + Visual Studio: Can't find zlib.h with subprojects/zlib + 788978 Document XML has a syntax error + 788989 Use subdir-objects with Autotools + 788990 Include licensing information in output from glib-mkenums, glib-ge... + 789087 gint and guint misrepresented as functions + 789170 GFormatSizeFlags should have a value for bits + 789245 g_settings_bind() not conforming to lifecycle specification + 789444 Fix handling of length in g_utf8_make_valid 789637 glib-mkenums: Fails when --ouput file does not exist - 789894 Text tool has color from previous line, when overwriting existing text + 789681 meson: Libmount support not built + 789723 [PATCH] gdbus-codegen: Call abspath() earlier + 789755 g_get_host_name: ensure return value is always UTF8 encoded + 789820 GPollFileMonitor is not cleaning up correctly + 790015 docs: Various linking and syntax fixes 790030 GResource/GVariant fails to load from non-pointer aligned memory 790093 gio-tool: fix inverted logic in monitor tool 790126 gengiotypefuncs.py is missing from tarballs - 790829 glib-genmarshal --body must not generate alias implementations - 790934 gtester doesn't handle skipped tests - 791235 Fix gschema.dtd regarding flags. - 791267 Make gschema.dtd usable. - 791296 gtester-report: fix range usage when running as python3 app - 791325 Gio handling of thumbnail:: attribute namespace causes inconsistent b... - 791334 gbinding.c:898: The target object of type GNetworkAddress has no prop... - 791337 Crash opening URIs with g_desktop_app_info_launch_uris_with_spawn() - 791720 Criticals in gio/xdp-dbus.h leading to crash under flatpak - 791744 gmenumodel test sometimes fails: assertion failed (items_changed_coun... - 791754 gdbus-peer test intermittently fails: assertion 'source->ref_count > ... - 791906 GSocketListenerClass.event has wrong signature - -* Translation updates: - Norwegian bokmål - - -Overview of changes in GLib 2.54.2 -================================== - -* Bugs fixed: - 780296 Fix a race in gio open + 790147 build: Drop data-to-c.pl in favour of data-to-c.py + 790157 gmessages: Give examples of G_DEBUG with gdb in the documentation + 790272 file: add g_file_load_bytes() + 790275 avoid temporary string allocations in g_resources_enumerate_children + 790310 speedup path canonicalization in GResourceFile * Translation updates: Catalan (Valencian) + Czech + German Nepali + Norwegian bokmål Slovak Slovenian - - -Overview of changes in GLib 2.54.1 -================================== - -* Bugs fixed: - 786737 No g_variant_get() example for dicts - 787551 Factor out some duplicated code in GParamSpec validation - 783270 Improve Visual Studio support for Meson builds - 783210 build: Switch to sassc for generating style - 781867 various gvfsd-* wants to look in /boot/efi, causes unnecessary/inappro... - -* Translation updates: - Slovenian + Spanish Overview of changes in GLib 2.54.0 diff --git a/config.h.meson b/config.h.meson index ac0b5e0..3f310b3 100644 --- a/config.h.meson +++ b/config.h.meson @@ -247,6 +247,9 @@ /* Define if libelf is available */ #mesondefine HAVE_LIBELF +/* Define if libmount is available */ +#mesondefine HAVE_LIBMOUNT + /* Define to 1 if you have the header file. */ #mesondefine HAVE_LINUX_MAGIC_H @@ -364,6 +367,9 @@ /* Define if you have the 'sig_atomic_t' type. */ #mesondefine HAVE_SIG_ATOMIC_T +/* Define if there is support for the ioctl request SIOCGIFADDR. */ +#mesondefine HAVE_SIOCGIFADDR + /* Define to 1 if you have the `snprintf' function. */ #mesondefine HAVE_SNPRINTF @@ -376,6 +382,9 @@ /* Define to 1 if you have the `statvfs' function. */ #mesondefine HAVE_STATVFS +/* Define to 1 if you have the `mkostemp' function. */ +#mesondefine HAVE_MKOSTEMP + /* Define to 1 if you have the header file. */ #mesondefine HAVE_STDDEF_H diff --git a/config.h.win32.in b/config.h.win32.in index 7bb9a13..b607cca 100644 --- a/config.h.win32.in +++ b/config.h.win32.in @@ -57,16 +57,16 @@ /* A 'va_copy' style function */ #if !defined (_MSC_VER) || (_MSC_VER >= 1800) -#define G_VA_COPY va_copy +# define G_VA_COPY va_copy #else /* _MSC_VER && _MSC_VER < 1800 */ /* #undef G_VA_COPY */ -#endif /* _MSC_VER */ +#endif /* 'va_lists' cannot be copies as values */ /* #undef G_VA_COPY_AS_ARRAY */ /* Define to 1 if you have `alloca', as a function or macro. */ -#define HAVE_ALLOCA 1 +/* #undef HAVE_ALLOCA */ /* Define to 1 if you have and it should be used (not on Ultrix). */ @@ -80,11 +80,11 @@ /* Define if you have a version of the snprintf function with semantics as specified by the ISO C99 standard. */ -/* #undef HAVE_C99_SNPRINTF */ +#undef HAVE_C99_SNPRINTF /* Define if you have a version of the vsnprintf function with semantics as specified by the ISO C99 standard. */ -/* #undef HAVE_C99_VSNPRINTF */ +#undef HAVE_C99_VSNPRINTF /* define to 1 if Carbon is available */ /* #undef HAVE_CARBON */ @@ -110,9 +110,9 @@ /* Define to 1 if you have the header file, and it defines `DIR'. */ #ifndef _MSC_VER -#define HAVE_DIRENT_H 1 +# define HAVE_DIRENT_H 1 #else -/* #undef HAVE_DIRENT_H */ +/* # undef HAVE_DIRENT_H */ #endif /* Define to 1 if you have the header file. */ @@ -196,52 +196,33 @@ /* Define to 1 if you have the `hasmntopt' function. */ /* #undef HAVE_HASMNTOPT */ -/* Target the Windows XP API */ -#ifndef _WIN32_WINNT -#define _WIN32_WINNT 0x0501 -#endif - -#if _WIN32_WINNT >= 0x0600 -/* if_indextoname() and if_nametoindex() are available on Windows Vista/Server - * 2008 or later, so we can make use of them when building agaist Vista/Server - * 2008 or later. - */ - /* Define to 1 if you have the `if_indextoname' function. */ #define HAVE_IF_INDEXTONAME 1 /* Define to 1 if you have the `if_nametoindex' function. */ #define HAVE_IF_NAMETOINDEX 1 -#endif - /* Define to 1 if you have the `inotify_init1' function. */ /* #undef HAVE_INOTIFY_INIT1 */ /* define to support printing 64-bit integers with format I64 */ -#define HAVE_INT64_AND_I64 1 +/* #undef HAVE_INT64_AND_I64 */ /* Define if you have the 'intmax_t' type in or . */ #if !defined (_MSC_VER) || (_MSC_VER >= 1600) -#define HAVE_INTMAX_T 1 -#else /* !_MSC_VER || _MSC_VER >= 1600 */ -/* #undef HAVE_INTMAX_T */ -#endif /* _MSC_VER < 1600 */ +# define HAVE_INTMAX_T 1 +#endif /* Define to 1 if you have the header file. */ #if !defined (_MSC_VER) || (_MSC_VER >= 1800) -#define HAVE_INTTYPES_H 1 -#else /* !_MSC_VER || _MSC_VER >= 1800 */ -/* #undef HAVE_INTTYPES_H */ -#endif /* _MSC_VER < 1800 */ +# define HAVE_INTTYPES_H 1 +#endif /* Define if exists, doesn't clash with , and declares uintmax_t. */ -#ifndef _MSC_VER -#define HAVE_INTTYPES_H_WITH_UINTMAX 1 -#else /* !_MSC_VER */ -/* #undef HAVE_INTTYPES_H_WITH_UINTMAX */ -#endif /* _MSC_VER */ +#if !defined (_MSC_VER) || (_MSC_VER >= 1800) +# define HAVE_INTTYPES_H_WITH_UINTMAX 1 +#endif /* Define if we have struct ip_mreqn */ /* #undef HAVE_IP_MREQN */ @@ -295,7 +276,7 @@ #define HAVE_LONG_LONG 1 /* define if system printf can print long long */ -#define HAVE_LONG_LONG_FORMAT 1 +/* #undef HAVE_LONG_LONG_FORMAT */ /* Define to 1 if you have the `lstat' function. */ /* #undef HAVE_LSTAT */ @@ -333,12 +314,6 @@ /* Define to 1 if you have the `newlocale' function. */ /* #undef HAVE_NEWLOCALE */ -/* Have non-POSIX function getgrgid_r */ -/* #undef HAVE_NONPOSIX_GETGRGID_R */ - -/* Have non-POSIX function getpwuid_r */ -/* #undef HAVE_NONPOSIX_GETPWUID_R */ - /* open option O_DIRECTORY */ /* #undef HAVE_OPEN_O_DIRECTORY */ @@ -348,12 +323,6 @@ /* Define to 1 if you have the `poll' function. */ /* #undef HAVE_POLL */ -/* Have POSIX function getgrgid_r */ -/* #undef HAVE_POSIX_GETGRGID_R */ - -/* Have POSIX function getpwuid_r */ -/* #undef HAVE_POSIX_GETPWUID_R */ - /* Define to 1 if you have the `posix_memalign' function. */ /* #undef HAVE_POSIX_MEMALIGN */ @@ -363,11 +332,17 @@ /* Have function pthread_attr_setstacksize */ /* #undef HAVE_PTHREAD_ATTR_SETSTACKSIZE */ +/* Have function pthread_cond_timedwait_relative_np */ +/* #undef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP */ + /* Have function pthread_condattr_setclock */ /* #undef HAVE_PTHREAD_CONDATTR_SETCLOCK */ -/* Have function pthread_cond_timedwait_relative_np */ -/* #undef HAVE_PTHREAD_COND_TIMEDWAIT_RELATIVE_NP */ +/* Have function pthread_setname_np without TID as argument */ +/* #undef HAVE_PTHREAD_SETNAME_NP_WITHOUT_TID */ + +/* Have function pthread_setname_np with TID as argument */ +/* #undef HAVE_PTHREAD_SETNAME_NP_WITH_TID */ /* Define to 1 if the system has the type `ptrdiff_t'. */ #define HAVE_PTRDIFF_T 1 @@ -375,6 +350,9 @@ /* Define to 1 if you have the `readlink' function. */ /* #undef HAVE_READLINK */ +/* Define to 1 if you have the `recvmmsg' function. */ +/* #undef HAVE_RECVMMSG */ + /* Define to 1 if you have the 'res_init' function. */ /* #undef HAVE_RES_INIT */ @@ -384,15 +362,12 @@ /* Define to 1 if libselinux is available */ /* #undef HAVE_SELINUX */ -/* Define to 1 if you have the `sendmmsg` function */ -/* #undef HAVE_SENDMMSG */ - -/* Define to 1 if you have the `recvmmsg` function */ -/* #undef HAVE_RECVMMSG */ - /* Define to 1 if you have the header file. */ /* #undef HAVE_SELINUX_SELINUX_H */ +/* Define to 1 if you have the `sendmmsg' function. */ +/* #undef HAVE_SENDMMSG */ + /* Define to 1 if you have the `setenv' function. */ /* #undef HAVE_SETENV */ @@ -403,14 +378,10 @@ #define HAVE_SIG_ATOMIC_T 1 /* Define to 1 if you have the `snprintf' function. */ -#if !defined (_MSC_VER) || (_MSC_VER >= 1900) #define HAVE_SNPRINTF 1 -#ifdef __DMC__ -#define snprintf _snprintf +#if defined (_MSC_VER) && (_MSC_VER < 1900) +# define snprintf _snprintf #endif -#else /* !_MSC_VER || _MSC_VER >= 1900 */ -/* #undef HAVE_SNPRINTF */ -#endif /* _MSC_VER < 1900 */ /* Define to 1 if you have the `splice' function. */ /* #undef HAVE_SPLICE */ @@ -421,60 +392,57 @@ /* Define to 1 if you have the `statvfs' function. */ /* #undef HAVE_STATVFS */ +/* Define to 1 if you have the header file. */ +#define HAVE_STDDEF_H 1 + /* Define to 1 if you have the header file. */ -#ifndef _MSC_VER -#define HAVE_STDINT_H 1 -#else /* _MSC_VER */ -#if (_MSC_VER >= 1600) /*VS 2010 ships with stdint.h*/ -#define HAVE_STDINT_H 1 -#else -/* #undef HAVE_STDINT_H */ +#if !defined (_MSC_VER) || (_MSC_VER >= 1600) +# define HAVE_STDINT_H 1 #endif -#endif /* _MSC_VER */ /* Define if exists, doesn't clash with , and declares uintmax_t. */ -#ifndef _MSC_VER -#define HAVE_STDINT_H_WITH_UINTMAX 1 -#else /* _MSC_VER */ -#if (_MSC_VER >= 1600) -#define HAVE_STDINT_H_WITH_UINTMAX 1 -#else -/* #undef HAVE_STDINT_H_WITH_UINTMAX */ +#if !defined (_MSC_VER) || (_MSC_VER >= 1600) +# define HAVE_STDINT_H_WITH_UINTMAX 1 #endif -#endif /* _MSC_VER */ + +/* Define to 1 if you have the header file. */ +#define HAVE_STDLIB_H 1 /* Define to 1 if you have the `stpcpy' function. */ /* #undef HAVE_STPCPY */ /* Define to 1 if you have the `strcasecmp' function. */ -#if defined(_MSC_VER) -#define strcasecmp _stricmp -#endif /* _MSC_VER uses _stricmp, which is identical to strcasecmp */ - -#if !defined(__DMC__) #define HAVE_STRCASECMP 1 -#endif /* _MSC_VER or __gcc__ */ +#ifdef _MSC_VER +# define strcasecmp _stricmp +#endif + +/* Define to 1 if you have the `strerror_r' function. */ +/* #undef HAVE_STRERROR_R */ + +/* Define if strerror_r returns char * */ +/* #undef STRERROR_R_CHAR_P */ /* Define to 1 if you have the header file. */ -#if !defined(_MSC_VER) && !defined(__DMC__) -#define HAVE_STRINGS_H 1 -#else /* _MSC_VER or __DMC__ */ -/* #undef HAVE_STRINGS_H */ -#endif /* _MSC_VER or __DMC__ */ +#ifndef _MSC_VER +# define HAVE_STRINGS_H 1 +#endif + +/* Define to 1 if you have the header file. */ +#define HAVE_STRING_H 1 /* Have functions strlcpy and strlcat */ /* #undef HAVE_STRLCPY */ /* Define to 1 if you have the `strncasecmp' function. */ -#if !defined(__DMC__) -#if defined(_MSC_VER) -#define strncasecmp _strnicmp -#endif /* _MSC_VER uses _strnicmp, which is identical to strncasecmp */ #define HAVE_STRNCASECMP 1 -#else /* __DMC__ */ -/* #undef HAVE_STRNCASECMP */ -#endif /* __DMC__ */ +#ifdef _MSC_VER +# define strncasecmp _strnicmp +#endif + +/* Define to 1 if you have the `strnlen' function. */ +#define HAVE_STRNLEN 1 /* Define to 1 if you have the `strsignal' function. */ /* #undef HAVE_STRSIGNAL */ @@ -539,7 +507,7 @@ /* Define to 1 if `st_mtim.tv_nsec' is a member of `struct stat'. */ /* #undef HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC */ -/* Define to 1 if `tm_gmtoff' is a a member of `struct tm'. */ +/* Define to 1 if `tm_gmtoff' is a member of `struct tm'. */ /* #undef HAVE_STRUCT_TM_TM_GMTOFF */ /* Define to 1 if `__tm_gmtoff' is a member of `struct tm'. */ @@ -581,14 +549,12 @@ /* #undef HAVE_SYS_NDIR_H */ /* Define to 1 if you have the header file. */ -#if !defined(_MSC_VER) && !defined(__DMC__) -#define HAVE_SYS_PARAM_H 1 -#else /* _MSC_VER or __DMC__ */ -/* #undef HAVE_SYS_PARAM_H */ -#endif /* _MSC_VER or __DMC__ */ +#ifndef _MSC_VER +# define HAVE_SYS_PARAM_H 1 +#endif -/* Define to 1 if you have the header file. */ -/* #undef HAVE_SYS_PRCTL_H */ +/* Define to 1 if you have the header file. */ +/* #undef HAVE_SYS_POLL_H */ /* Define to 1 if you have the header file. */ /* #undef HAVE_SYS_RESOURCE_H */ @@ -613,10 +579,8 @@ /* Define to 1 if you have the header file. */ #ifndef _MSC_VER -#define HAVE_SYS_TIME_H 1 -#else /* _MSC_VER */ -/* #undef HAVE_SYS_TIME_H */ -#endif /* _MSC_VER */ +# define HAVE_SYS_TIME_H 1 +#endif /* Define to 1 if you have the header file. */ #define HAVE_SYS_TYPES_H 1 @@ -664,24 +628,15 @@ /* #undef HAVE_VALLOC */ /* Define to 1 if you have the header file. */ -#if !defined(_MSC_VER) && !defined(__DMC__) -#define HAVE_VALUES_H 1 -#else /* _MSC_VER or __DMC__ */ -/* #undef HAVE_VALUES_H */ -#endif /* _MSC_VER or __DMC__ */ +#ifdef _MSC_VER +# define HAVE_VALUES_H 1 +#endif /* Define to 1 if you have the `vasprintf' function. */ #define HAVE_VASPRINTF 1 /* Define to 1 if you have the `vsnprintf' function. */ -#if !defined (_MSC_VER) || (_MSC_VER >= 1500) #define HAVE_VSNPRINTF 1 -#ifdef __DMC__ -#define vsnprintf _vsnprintf -#endif -#else /* !_MSC_VER || _MSC_VER >= 1500 */ -/* #undef HAVE_VSNPRINTF */ -#endif /* _MSC_VER < 1500 */ /* Define if you have the 'wchar_t' type. */ #define HAVE_WCHAR_T 1 @@ -707,9 +662,8 @@ /* Define to 1 if you have the `_NSGetEnviron' function. */ /* #undef HAVE__NSGETENVIRON */ -/* Define to the sub-directory in which libtool stores uninstalled libraries. - */ -#define LT_OBJDIR ".libs/" +/* Define to the sub-directory where libtool stores uninstalled libraries. */ +#define LT_OBJDIR "" /* Do we cache iconv descriptors */ /* #undef NEED_ICONV_CACHE */ @@ -754,28 +708,24 @@ #define SIZEOF_SHORT 2 /* The size of `size_t', as computed by sizeof. */ -#if (defined(_M_X64) || defined(_M_AMD64)) +#ifdef _WIN64 # define SIZEOF_SIZE_T 8 #else # define SIZEOF_SIZE_T 4 #endif /* The size of `ssize_t', as computed by sizeof. */ -#if (defined(_M_X64) || defined(_M_AMD64)) +#ifdef _WIN64 # define SIZEOF_SSIZE_T 8 #else # define SIZEOF_SSIZE_T 4 #endif /* The size of `void *', as computed by sizeof. */ -#ifdef _MSC_VER -#if (defined(_M_X64) || defined(_M_AMD64)) -#define SIZEOF_VOID_P 8 -#elif (defined(_M_IX86)) -#define SIZEOF_VOID_P 4 -#endif +#ifdef _WIN64 +# define SIZEOF_VOID_P 8 #else -#define SIZEOF_VOID_P 4 +# define SIZEOF_VOID_P 4 #endif /* The size of `__int64', as computed by sizeof. */ @@ -818,27 +768,27 @@ /* Enable extensions on AIX 3, Interix. */ #ifndef _ALL_SOURCE -/* # undef _ALL_SOURCE */ +/* #undef _ALL_SOURCE */ #endif /* Enable GNU extensions on systems that have them. */ #ifndef _GNU_SOURCE -/* # undef _GNU_SOURCE */ +#define _GNU_SOURCE 1 #endif /* Enable threading extensions on Solaris. */ #ifndef _POSIX_PTHREAD_SEMANTICS -/* # undef _POSIX_PTHREAD_SEMANTICS */ +/* #undef _POSIX_PTHREAD_SEMANTICS */ #endif /* Enable extensions on HP NonStop. */ #ifndef _TANDEM_SOURCE -/* # undef _TANDEM_SOURCE */ +/* #undef _TANDEM_SOURCE */ #endif /* Enable general extensions on Solaris. */ #ifndef __EXTENSIONS__ -/* # undef __EXTENSIONS__ */ +#define __EXTENSIONS__ 1 #endif /* using the system-supplied PCRE library */ -/* This is defined in the *_PCRE MSVC project configs */ +/* This is determined in the MSVC projects */ /* #undef USE_SYSTEM_PCRE */ /* Define WORDS_BIGENDIAN to 1 if your processor stores words with the most @@ -849,13 +799,13 @@ # endif #else # ifndef WORDS_BIGENDIAN -/* # undef WORDS_BIGENDIAN */ +# undef WORDS_BIGENDIAN # endif #endif /* Enable large inode numbers on Mac OS X 10.5. */ #ifndef _DARWIN_USE_64_BIT_INODE -/* # define _DARWIN_USE_64_BIT_INODE 1 */ +# define _DARWIN_USE_64_BIT_INODE 1 #endif /* Number of bits in a file offset, on hosts where this is settable. */ @@ -863,23 +813,16 @@ /* defines how to decorate public symbols while building */ #ifdef _MSC_VER -#define _GLIB_EXTERN __declspec (dllexport) extern +# define _GLIB_EXTERN __declspec (dllexport) extern #else -#define _GLIB_EXTERN __attribute__((visibility("default"))) __declspec (dllexport) extern +# define _GLIB_EXTERN __attribute__((visibility("default"))) __declspec (dllexport) extern #endif /* Define for large files, on AIX-style hosts. */ /* #undef _LARGE_FILES */ -/* Define to 1 if on MINIX. */ -/* #undef _MINIX */ - -/* Define to 2 if the system does not provide POSIX.1 features except with - this defined. */ -/* #undef _POSIX_1_SOURCE */ - -/* Define to 1 if you need to in order for `stat' and other things to work. */ -/* #undef _POSIX_SOURCE */ +/* Target the Windows 7 API */ +#define _WIN32_WINNT 0x0601 /* Needed to get declarations for msg_control and msg_controllen on Solaris */ /* #undef _XOPEN_SOURCE */ @@ -888,7 +831,7 @@ /* #undef _XOPEN_SOURCE_EXTENDED */ /* Needed to get declarations for msg_control and msg_controllen on Solaris */ -/* #undef __EXTENSIONS__ */ +#define __EXTENSIONS__ 1 /* compiler supports atomic operations */ /* #undef __GCC_HAVE_SYNC_COMPARE_AND_SWAP_4 */ @@ -904,3 +847,11 @@ /* Define to `unsigned int' if does not define. */ /* #undef size_t */ + +#define EXEEXT ".exe" + +/* #undef MAJOR_IN_MKDEV */ +/* #undef MAJOR_IN_SYSMACROS */ +/* #undef HAVE_RTLD_LAZY */ +/* #undef HAVE_RTLD_NOW */ +/* #undef HAVE_RTLD_GLOBAL */ diff --git a/configure.ac b/configure.ac index 0457c90..5cbff19 100644 --- a/configure.ac +++ b/configure.ac @@ -30,9 +30,9 @@ m4_define(glib_configure_ac) # on the unstable (ie master), interface age = 0 m4_define([glib_major_version], [2]) -m4_define([glib_minor_version], [54]) -m4_define([glib_micro_version], [3]) -m4_define([glib_interface_age], [3]) +m4_define([glib_minor_version], [55]) +m4_define([glib_micro_version], [0]) +m4_define([glib_interface_age], [0]) m4_define([glib_binary_age], [m4_eval(100 * glib_minor_version + glib_micro_version)]) m4_define([glib_version], @@ -63,7 +63,7 @@ AC_CONFIG_MACRO_DIR([m4macros]) # Save this value here, since automake will set cflags later cflags_set=${CFLAGS:+set} -AM_INIT_AUTOMAKE([1.11 -Wno-portability no-define no-dist-gzip dist-xz tar-ustar]) +AM_INIT_AUTOMAKE([1.13.3 -Wno-portability no-define no-dist-gzip dist-xz tar-ustar subdir-objects]) AM_MAINTAINER_MODE([enable]) # Support silent build rules. Disable @@ -144,7 +144,7 @@ case "$host" in ;; esac - AC_DEFINE([_WIN32_WINNT], [0x0501], [Target the Windows XP API]) + AC_DEFINE([_WIN32_WINNT], [0x0601], [Target the Windows 7 API]) ;; *) glib_native_win32=no @@ -369,16 +369,6 @@ if test "x$enable_rebuilds" = "xyes" && \ fi AC_SUBST(REBUILD) -# Need full path to Perl for glib-mkenums -# -if test "x$PERL" != x ; then - AC_PATH_PROG(PERL_PATH, [$PERL]) -fi -if test "x$PERL_PATH" = x ; then - PERL_PATH="/usr/bin/env perl" -fi -AC_SUBST(PERL_PATH) - # option to specify python interpreter to use; this just sets $PYTHON, so that # we will fallback to reading $PYTHON if --with-python is not given, and # python.m4 will get the expected input @@ -700,7 +690,7 @@ AM_CONDITIONAL(HAVE_SUNSTUDIO_VISIBILITY, [test x$g_have_sunstudio_visibility = # check for bytesex stuff AC_C_BIGENDIAN if test x$ac_cv_c_bigendian = xuniversal ; then - AC_MSG_ERROR([Universal builds not supported: see https://bugs.gnome.org/742548]) + AC_MSG_ERROR([Universal builds not supported: see https://bugzilla.gnome.org/show_bug.cgi?id=742548]) fi @@ -890,7 +880,7 @@ int main () AC_MSG_RESULT($glib_ssize_type) # Check for some functions -AC_CHECK_FUNCS(lstat strsignal vsnprintf stpcpy strcasecmp strncasecmp poll vasprintf setenv unsetenv getc_unlocked readlink symlink fdwalk) +AC_CHECK_FUNCS(lstat strsignal vsnprintf stpcpy strcasecmp strncasecmp poll vasprintf setenv unsetenv getc_unlocked readlink symlink fdwalk mkostemp) AC_CHECK_FUNCS(lchmod lchown fchmod fchown utimes getresuid) AC_CHECK_FUNCS(getmntent_r setmntent endmntent hasmntopt getfsstat getvfsstat fallocate) case $host_os in aix*) ac_cv_func_splice=no ;; esac # AIX splice() is something else @@ -961,6 +951,22 @@ fi AC_CHECK_FUNCS(endservent if_nametoindex if_indextoname sendmmsg recvmmsg) +AC_MSG_CHECKING([for SIOCGIFADDR]) +AC_COMPILE_IFELSE([AC_LANG_PROGRAM( + [[ + #include + #include + ]], + [[ + struct ifreq ifr; + ioctl(0, SIOCGIFADDR, &ifr); + ]])], [ + AC_MSG_RESULT(yes) + AC_DEFINE(HAVE_SIOCGIFADDR, 1, [SIOCGIFADDR is available]) + ], [ + AC_MSG_RESULT(no) +]) + AS_IF([test $glib_native_win32 = yes], [ # in the Windows SDK and in mingw-w64 has wrappers for # inline workarounds for getaddrinfo, getnameinfo and freeaddrinfo if @@ -1754,8 +1760,10 @@ AS_IF([ test $have_libmount = maybe ], [ glib_save_LIBS=$LIBS AC_CHECK_HEADER([libmount/libmount.h], [:], [have_libmount=no]) - # Check for a recent enough libmount - AC_CHECK_LIB([mount], [mnt_unref_table], [:], [have_libmount=no]) + # We used to check for mnt_unref_table(), but now for compat with + # e.g. RHEL7 just use mnt_free_table(). Let's keep this check + # anyways. + AC_CHECK_LIB([mount], [mnt_free_table], [:], [have_libmount=no]) LIBS=$glib_save_LIBS if test $have_libmount != no; then diff --git a/docs/reference/gio/Makefile.am b/docs/reference/gio/Makefile.am index 5741a3e..e04ab68 100644 --- a/docs/reference/gio/Makefile.am +++ b/docs/reference/gio/Makefile.am @@ -7,8 +7,9 @@ DOC_MODULE=gio DOC_MAIN_SGML_FILE=gio-docs.xml # Extra options to supply to gtkdoc-scan -SCAN_OPTIONS=--deprecated-guards="G_DISABLE_DEPRECATED" \ - --ignore-decorators="G_GNUC_WARN_UNUSED_RESULT" +SCAN_OPTIONS = \ + --deprecated-guards="G_DISABLE_DEPRECATED" \ + --ignore-decorators="GLIB_VAR|G_GNUC_INTERNAL|G_GNUC_WARN_UNUSED_RESULT|GLIB_AVAILABLE_IN_ALL|GLIB_AVAILABLE_IN_2_26|GLIB_AVAILABLE_IN_2_28|GLIB_AVAILABLE_IN_2_30|GLIB_AVAILABLE_IN_2_32|GLIB_AVAILABLE_IN_2_34|GLIB_AVAILABLE_IN_2_36|GLIB_AVAILABLE_IN_2_38|GLIB_AVAILABLE_IN_2_40|GLIB_AVAILABLE_IN_2_42|GLIB_AVAILABLE_IN_2_44|GLIB_AVAILABLE_IN_2_46|GLIB_AVAILABLE_IN_2_48|GLIB_AVAILABLE_IN_2_50|GLIB_AVAILABLE_IN_2_52|GLIB_AVAILABLE_IN_2_54|GLIB_AVAILABLE_IN_2_56|GLIB_DEPRECATED_IN_2_26|GLIB_DEPRECATED_IN_2_26_FOR|GLIB_DEPRECATED_IN_2_28|GLIB_DEPRECATED_IN_2_28_FOR|GLIB_DEPRECATED_IN_2_30|GLIB_DEPRECATED_IN_2_30_FOR|GLIB_DEPRECATED_IN_2_32|GLIB_DEPRECATED_IN_2_32_FOR|GLIB_DEPRECATED_IN_2_34|GLIB_DEPRECATED_IN_2_34_FOR|GLIB_DEPRECATED_IN_2_36|GLIB_DEPRECATED_IN_2_36_FOR|GLIB_DEPRECATED_IN_2_38|GLIB_DEPRECATED_IN_2_38_FOR|GLIB_DEPRECATED_IN_2_40|GLIB_DEPRECATED_IN_2_40_FOR|GLIB_DEPRECATED_IN_2_42|GLIB_DEPRECATED_IN_2_42_FOR|GLIB_DEPRECATED_IN_2_44|GLIB_DEPRECATED_IN_2_44_FOR|GLIB_DEPRECATED_IN_2_46|GLIB_DEPRECATED_IN_2_46_FOR|GLIB_DEPRECATED_IN_2_48|GLIB_DEPRECATED_IN_2_48_FOR|GLIB_DEPRECATED_IN_2_50|GLIB_DEPRECATED_IN_2_50_FOR|GLIB_DEPRECATED_IN_2_52|GLIB_DEPRECATED_IN_2_52_FOR|GLIB_DEPRECATED_IN_2_54|GLIB_DEPRECATED_IN_2_54_FOR|GLIB_DEPRECATED_IN_2_56|GLIB_DEPRECATED_IN_2_56_FOR" # The directory containing the source code. Relative to $(srcdir) DOC_SOURCE_DIR =$(top_srcdir)/gio $(top_builddir)/gio diff --git a/docs/reference/gio/gio-docs.xml b/docs/reference/gio/gio-docs.xml index 6abd0ea..bc23bf9 100644 --- a/docs/reference/gio/gio-docs.xml +++ b/docs/reference/gio/gio-docs.xml @@ -167,8 +167,6 @@ - - diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt index 780d249..e0472f7 100644 --- a/docs/reference/gio/gio-sections.txt +++ b/docs/reference/gio/gio-sections.txt @@ -85,6 +85,7 @@ g_file_new_for_commandline_arg g_file_new_for_commandline_arg_and_cwd g_file_new_tmp g_file_parse_name +g_file_new_build_filename g_file_dup g_file_hash g_file_equal @@ -183,6 +184,9 @@ g_file_mount_enclosing_volume_finish g_file_monitor_directory g_file_monitor_file g_file_monitor +g_file_load_bytes +g_file_load_bytes_async +g_file_load_bytes_finish g_file_load_contents g_file_load_contents_async g_file_load_contents_finish @@ -1571,6 +1575,8 @@ g_unix_mount_monitor_get g_unix_mount_monitor_new g_unix_mount_monitor_set_rate_limit g_unix_is_mount_path_system_internal +g_unix_is_system_fs_type +g_unix_is_system_device_path GUnixMountMonitorClass G_UNIX_MOUNT_MONITOR @@ -1931,40 +1937,26 @@ GSocketConnectableIface g_socket_connectable_enumerate g_socket_connectable_proxy_enumerate g_socket_connectable_to_string + +GSocketAddressEnumerator +g_socket_address_enumerator_next +g_socket_address_enumerator_next_async +g_socket_address_enumerator_next_finish + +GProxyAddressEnumerator G_IS_SOCKET_CONNECTABLE G_SOCKET_CONNECTABLE G_SOCKET_CONNECTABLE_GET_IFACE G_TYPE_SOCKET_CONNECTABLE - -g_socket_connectable_get_type - - -
-gsocketaddressenumerator -GSocketAddressEnumerator -GSocketAddressEnumerator GSocketAddressEnumeratorClass -g_socket_address_enumerator_next -g_socket_address_enumerator_next_async -g_socket_address_enumerator_next_finish - G_IS_SOCKET_ADDRESS_ENUMERATOR G_IS_SOCKET_ADDRESS_ENUMERATOR_CLASS G_SOCKET_ADDRESS_ENUMERATOR G_SOCKET_ADDRESS_ENUMERATOR_CLASS G_SOCKET_ADDRESS_ENUMERATOR_GET_CLASS G_TYPE_SOCKET_ADDRESS_ENUMERATOR - -g_socket_address_enumerator_get_type -
- -
-gproxyaddressenumerator -GProxyAddressEnumerator -GProxyAddressEnumerator GProxyAddressEnumeratorClass - G_IS_PROXY_ADDRESS_ENUMERATOR G_IS_PROXY_ADDRESS_ENUMERATOR_CLASS G_PROXY_ADDRESS_ENUMERATOR @@ -1974,6 +1966,8 @@ G_TYPE_PROXY_ADDRESS_ENUMERATOR GProxyAddressEnumeratorPrivate g_proxy_address_enumerator_get_type +g_socket_address_enumerator_get_type +g_socket_connectable_get_type
@@ -2107,6 +2101,8 @@ g_socket_get_credentials g_socket_join_multicast_group g_socket_leave_multicast_group +g_socket_join_multicast_group_ssm +g_socket_leave_multicast_group_ssm g_socket_get_multicast_loopback g_socket_set_multicast_loopback g_socket_get_multicast_ttl diff --git a/docs/reference/gio/meson.build b/docs/reference/gio/meson.build index 7f04677..e6b1386 100644 --- a/docs/reference/gio/meson.build +++ b/docs/reference/gio/meson.build @@ -82,6 +82,62 @@ if get_option('with-docs') != 'no' 'thumbnail-verify.h', 'xdp-dbus.h', ] + + ignore_decorators = [ + 'GLIB_VAR', + 'G_GNUC_INTERNAL', + 'G_GNUC_WARN_UNUSED_RESULT', + 'GLIB_AVAILABLE_IN_ALL', + 'GLIB_AVAILABLE_IN_2_26', + 'GLIB_AVAILABLE_IN_2_28', + 'GLIB_AVAILABLE_IN_2_30', + 'GLIB_AVAILABLE_IN_2_32', + 'GLIB_AVAILABLE_IN_2_34', + 'GLIB_AVAILABLE_IN_2_36', + 'GLIB_AVAILABLE_IN_2_38', + 'GLIB_AVAILABLE_IN_2_40', + 'GLIB_AVAILABLE_IN_2_42', + 'GLIB_AVAILABLE_IN_2_44', + 'GLIB_AVAILABLE_IN_2_46', + 'GLIB_AVAILABLE_IN_2_48', + 'GLIB_AVAILABLE_IN_2_50', + 'GLIB_AVAILABLE_IN_2_52', + 'GLIB_AVAILABLE_IN_2_54', + 'GLIB_AVAILABLE_IN_2_56', + 'GLIB_DEPRECATED_IN_2_26', + 'GLIB_DEPRECATED_IN_2_26_FOR', + 'GLIB_DEPRECATED_IN_2_28', + 'GLIB_DEPRECATED_IN_2_28_FOR', + 'GLIB_DEPRECATED_IN_2_30', + 'GLIB_DEPRECATED_IN_2_30_FOR', + 'GLIB_DEPRECATED_IN_2_32', + 'GLIB_DEPRECATED_IN_2_32_FOR', + 'GLIB_DEPRECATED_IN_2_34', + 'GLIB_DEPRECATED_IN_2_34_FOR', + 'GLIB_DEPRECATED_IN_2_36', + 'GLIB_DEPRECATED_IN_2_36_FOR', + 'GLIB_DEPRECATED_IN_2_38', + 'GLIB_DEPRECATED_IN_2_38_FOR', + 'GLIB_DEPRECATED_IN_2_40', + 'GLIB_DEPRECATED_IN_2_40_FOR', + 'GLIB_DEPRECATED_IN_2_42', + 'GLIB_DEPRECATED_IN_2_42_FOR', + 'GLIB_DEPRECATED_IN_2_44', + 'GLIB_DEPRECATED_IN_2_44_FOR', + 'GLIB_DEPRECATED_IN_2_46', + 'GLIB_DEPRECATED_IN_2_46_FOR', + 'GLIB_DEPRECATED_IN_2_48', + 'GLIB_DEPRECATED_IN_2_48_FOR', + 'GLIB_DEPRECATED_IN_2_50', + 'GLIB_DEPRECATED_IN_2_50_FOR', + 'GLIB_DEPRECATED_IN_2_52', + 'GLIB_DEPRECATED_IN_2_52_FOR', + 'GLIB_DEPRECATED_IN_2_54', + 'GLIB_DEPRECATED_IN_2_54_FOR', + 'GLIB_DEPRECATED_IN_2_56', + 'GLIB_DEPRECATED_IN_2_56_FOR', + ] + # FIXME: More win32 headers were added to fix building gio-scan # FIXME: ExampleAnimal docs aren't built @@ -105,7 +161,7 @@ if get_option('with-docs') != 'no' scan_args : [ '--rebuild-types', '--deprecated-guards=G_DISABLE_DEPRECATED', - '--ignore-decorators=G_GNUC_WARN_UNUSED_RESULT', + '--ignore-decorators=' + '|'.join(ignore_decorators), '--ignore-headers=' + ' '.join(ignore_headers), ], content_files : [ diff --git a/docs/reference/glib/Makefile.am b/docs/reference/glib/Makefile.am index 8dbb069..44536cf 100644 --- a/docs/reference/glib/Makefile.am +++ b/docs/reference/glib/Makefile.am @@ -14,7 +14,9 @@ DOC_SOURCE_DIR = \ $(top_builddir)/glib $(top_builddir)/gmodule # Extra options to supply to gtkdoc-scan -SCAN_OPTIONS=--deprecated-guards="G_DISABLE_DEPRECATED" --ignore-decorators="GLIB_VAR|G_GNUC_WARN_UNUSED_RESULT" +SCAN_OPTIONS = \ + --deprecated-guards="G_DISABLE_DEPRECATED" \ + --ignore-decorators="GLIB_VAR|G_GNUC_INTERNAL|G_GNUC_WARN_UNUSED_RESULT|GLIB_AVAILABLE_IN_ALL|GLIB_AVAILABLE_IN_2_26|GLIB_AVAILABLE_IN_2_28|GLIB_AVAILABLE_IN_2_30|GLIB_AVAILABLE_IN_2_32|GLIB_AVAILABLE_IN_2_34|GLIB_AVAILABLE_IN_2_36|GLIB_AVAILABLE_IN_2_38|GLIB_AVAILABLE_IN_2_40|GLIB_AVAILABLE_IN_2_42|GLIB_AVAILABLE_IN_2_44|GLIB_AVAILABLE_IN_2_46|GLIB_AVAILABLE_IN_2_48|GLIB_AVAILABLE_IN_2_50|GLIB_AVAILABLE_IN_2_52|GLIB_AVAILABLE_IN_2_54|GLIB_AVAILABLE_IN_2_56|GLIB_DEPRECATED_IN_2_26|GLIB_DEPRECATED_IN_2_26_FOR|GLIB_DEPRECATED_IN_2_28|GLIB_DEPRECATED_IN_2_28_FOR|GLIB_DEPRECATED_IN_2_30|GLIB_DEPRECATED_IN_2_30_FOR|GLIB_DEPRECATED_IN_2_32|GLIB_DEPRECATED_IN_2_32_FOR|GLIB_DEPRECATED_IN_2_34|GLIB_DEPRECATED_IN_2_34_FOR|GLIB_DEPRECATED_IN_2_36|GLIB_DEPRECATED_IN_2_36_FOR|GLIB_DEPRECATED_IN_2_38|GLIB_DEPRECATED_IN_2_38_FOR|GLIB_DEPRECATED_IN_2_40|GLIB_DEPRECATED_IN_2_40_FOR|GLIB_DEPRECATED_IN_2_42|GLIB_DEPRECATED_IN_2_42_FOR|GLIB_DEPRECATED_IN_2_44|GLIB_DEPRECATED_IN_2_44_FOR|GLIB_DEPRECATED_IN_2_46|GLIB_DEPRECATED_IN_2_46_FOR|GLIB_DEPRECATED_IN_2_48|GLIB_DEPRECATED_IN_2_48_FOR|GLIB_DEPRECATED_IN_2_50|GLIB_DEPRECATED_IN_2_50_FOR|GLIB_DEPRECATED_IN_2_52|GLIB_DEPRECATED_IN_2_52_FOR|GLIB_DEPRECATED_IN_2_54|GLIB_DEPRECATED_IN_2_54_FOR|GLIB_DEPRECATED_IN_2_56|GLIB_DEPRECATED_IN_2_56_FOR" # Extra options to supply to gtkdoc-mkdb MKDB_OPTIONS=--output-format=xml --name-space=g diff --git a/docs/reference/glib/glib-docs.xml b/docs/reference/glib/glib-docs.xml index 93639b1..a0716c1 100644 --- a/docs/reference/glib/glib-docs.xml +++ b/docs/reference/glib/glib-docs.xml @@ -252,6 +252,10 @@ Index of new symbols in 2.54 + + Index of new symbols in 2.56 + + diff --git a/docs/reference/glib/glib-overrides.txt b/docs/reference/glib/glib-overrides.txt index b2774c0..991fcf2 100644 --- a/docs/reference/glib/glib-overrides.txt +++ b/docs/reference/glib/glib-overrides.txt @@ -288,10 +288,6 @@ gint *atomic gint *atomic - -GIConv - - G_VA_COPY #define G_VA_COPY(ap1,ap2) diff --git a/docs/reference/glib/glib-sections.txt b/docs/reference/glib/glib-sections.txt index e09d4d3..1aaaf60 100644 --- a/docs/reference/glib/glib-sections.txt +++ b/docs/reference/glib/glib-sections.txt @@ -129,6 +129,9 @@ GLIB_VERSION_2_44 GLIB_VERSION_2_46 GLIB_VERSION_2_48 GLIB_VERSION_2_50 +GLIB_VERSION_2_52 +GLIB_VERSION_2_54 +GLIB_VERSION_2_56 GLIB_VERSION_MIN_REQUIRED GLIB_VERSION_MAX_ALLOWED GLIB_DISABLE_DEPRECATION_WARNINGS @@ -149,6 +152,9 @@ GLIB_AVAILABLE_IN_2_44 GLIB_AVAILABLE_IN_2_46 GLIB_AVAILABLE_IN_2_48 GLIB_AVAILABLE_IN_2_50 +GLIB_AVAILABLE_IN_2_52 +GLIB_AVAILABLE_IN_2_54 +GLIB_AVAILABLE_IN_2_56 GLIB_DEPRECATED_IN_2_26 GLIB_DEPRECATED_IN_2_26_FOR GLIB_DEPRECATED_IN_2_28 @@ -175,6 +181,12 @@ GLIB_DEPRECATED_IN_2_48 GLIB_DEPRECATED_IN_2_48_FOR GLIB_DEPRECATED_IN_2_50 GLIB_DEPRECATED_IN_2_50_FOR +GLIB_DEPRECATED_IN_2_52 +GLIB_DEPRECATED_IN_2_52_FOR +GLIB_DEPRECATED_IN_2_54 +GLIB_DEPRECATED_IN_2_54_FOR +GLIB_DEPRECATED_IN_2_56 +GLIB_DEPRECATED_IN_2_56_FOR GLIB_VERSION_CUR_STABLE GLIB_VERSION_PREV_STABLE
@@ -621,6 +633,8 @@ g_source_get_current_time g_source_remove g_source_remove_by_funcs_user_data g_source_remove_by_user_data +GClearHandleFunc +g_clear_handle_id GLIB_HAVE_ALLOCA_H @@ -1324,7 +1338,7 @@ g_option_error_quark
File Utilities fileutils -glib.h,glib/gstdio.h +glib.h,glib/gstdio.h,fcntl.h,sys/types.h,sys/stat.h GFileError G_FILE_ERROR GFileTest @@ -1551,6 +1565,7 @@ g_date_new_dmy g_date_new_julian g_date_clear g_date_free +g_date_copy g_date_set_day @@ -1667,6 +1682,7 @@ g_date_time_new_from_unix_utc g_date_time_new_from_timeval_local g_date_time_new_from_timeval_utc +g_date_time_new_from_iso8601 g_date_time_new @@ -1837,6 +1853,7 @@ g_path_get_basename g_path_get_dirname g_build_filename g_build_filenamev +g_build_filename_valist g_build_path g_build_pathv diff --git a/docs/reference/glib/meson.build b/docs/reference/glib/meson.build index 3babb3e..271574d 100644 --- a/docs/reference/glib/meson.build +++ b/docs/reference/glib/meson.build @@ -36,6 +36,61 @@ if get_option('with-docs') != 'no' 'valgrind.h', ] + ignore_decorators = [ + 'GLIB_VAR', + 'G_GNUC_INTERNAL', + 'G_GNUC_WARN_UNUSED_RESULT', + 'GLIB_AVAILABLE_IN_ALL', + 'GLIB_AVAILABLE_IN_2_26', + 'GLIB_AVAILABLE_IN_2_28', + 'GLIB_AVAILABLE_IN_2_30', + 'GLIB_AVAILABLE_IN_2_32', + 'GLIB_AVAILABLE_IN_2_34', + 'GLIB_AVAILABLE_IN_2_36', + 'GLIB_AVAILABLE_IN_2_38', + 'GLIB_AVAILABLE_IN_2_40', + 'GLIB_AVAILABLE_IN_2_42', + 'GLIB_AVAILABLE_IN_2_44', + 'GLIB_AVAILABLE_IN_2_46', + 'GLIB_AVAILABLE_IN_2_48', + 'GLIB_AVAILABLE_IN_2_50', + 'GLIB_AVAILABLE_IN_2_52', + 'GLIB_AVAILABLE_IN_2_54', + 'GLIB_AVAILABLE_IN_2_56', + 'GLIB_DEPRECATED_IN_2_26', + 'GLIB_DEPRECATED_IN_2_26_FOR', + 'GLIB_DEPRECATED_IN_2_28', + 'GLIB_DEPRECATED_IN_2_28_FOR', + 'GLIB_DEPRECATED_IN_2_30', + 'GLIB_DEPRECATED_IN_2_30_FOR', + 'GLIB_DEPRECATED_IN_2_32', + 'GLIB_DEPRECATED_IN_2_32_FOR', + 'GLIB_DEPRECATED_IN_2_34', + 'GLIB_DEPRECATED_IN_2_34_FOR', + 'GLIB_DEPRECATED_IN_2_36', + 'GLIB_DEPRECATED_IN_2_36_FOR', + 'GLIB_DEPRECATED_IN_2_38', + 'GLIB_DEPRECATED_IN_2_38_FOR', + 'GLIB_DEPRECATED_IN_2_40', + 'GLIB_DEPRECATED_IN_2_40_FOR', + 'GLIB_DEPRECATED_IN_2_42', + 'GLIB_DEPRECATED_IN_2_42_FOR', + 'GLIB_DEPRECATED_IN_2_44', + 'GLIB_DEPRECATED_IN_2_44_FOR', + 'GLIB_DEPRECATED_IN_2_46', + 'GLIB_DEPRECATED_IN_2_46_FOR', + 'GLIB_DEPRECATED_IN_2_48', + 'GLIB_DEPRECATED_IN_2_48_FOR', + 'GLIB_DEPRECATED_IN_2_50', + 'GLIB_DEPRECATED_IN_2_50_FOR', + 'GLIB_DEPRECATED_IN_2_52', + 'GLIB_DEPRECATED_IN_2_52_FOR', + 'GLIB_DEPRECATED_IN_2_54', + 'GLIB_DEPRECATED_IN_2_54_FOR', + 'GLIB_DEPRECATED_IN_2_56', + 'GLIB_DEPRECATED_IN_2_56_FOR', + ] + docpath = join_paths(glib_datadir, 'gtk-doc', 'html') version_conf = configuration_data() version_conf.set('GLIB_VERSION', meson.project_version()) @@ -54,7 +109,7 @@ if get_option('with-docs') != 'no' scan_args : [ '--rebuild-types', '--deprecated-guards=G_DISABLE_DEPRECATED', - '--ignore-decorators=GLIB_VAR|G_GNUC_WARN_UNUSED_RESULT', + '--ignore-decorators=' + '|'.join(ignore_decorators), '--ignore-headers=' + ' '.join(ignore_headers), ], content_files : [ diff --git a/docs/reference/gobject/Makefile.am b/docs/reference/gobject/Makefile.am index 50b239b..430ab6d 100644 --- a/docs/reference/gobject/Makefile.am +++ b/docs/reference/gobject/Makefile.am @@ -12,8 +12,9 @@ DOC_MAIN_SGML_FILE=gobject-docs.xml DOC_SOURCE_DIR =$(top_srcdir)/gobject $(top_builddir)/gobject # Extra options to supply to gtkdoc-scan -SCAN_OPTIONS=--deprecated-guards="G_DISABLE_DEPRECATED" \ - --ignore-decorators="G_GNUC_INTERNAL|G_GNUC_WARN_UNUSED_RESULT" +SCAN_OPTIONS = \ + --deprecated-guards="G_DISABLE_DEPRECATED" \ + --ignore-decorators="GLIB_VAR|G_GNUC_INTERNAL|G_GNUC_WARN_UNUSED_RESULT|GLIB_AVAILABLE_IN_ALL|GLIB_AVAILABLE_IN_2_26|GLIB_AVAILABLE_IN_2_28|GLIB_AVAILABLE_IN_2_30|GLIB_AVAILABLE_IN_2_32|GLIB_AVAILABLE_IN_2_34|GLIB_AVAILABLE_IN_2_36|GLIB_AVAILABLE_IN_2_38|GLIB_AVAILABLE_IN_2_40|GLIB_AVAILABLE_IN_2_42|GLIB_AVAILABLE_IN_2_44|GLIB_AVAILABLE_IN_2_46|GLIB_AVAILABLE_IN_2_48|GLIB_AVAILABLE_IN_2_50|GLIB_AVAILABLE_IN_2_52|GLIB_AVAILABLE_IN_2_54|GLIB_AVAILABLE_IN_2_56|GLIB_DEPRECATED_IN_2_26|GLIB_DEPRECATED_IN_2_26_FOR|GLIB_DEPRECATED_IN_2_28|GLIB_DEPRECATED_IN_2_28_FOR|GLIB_DEPRECATED_IN_2_30|GLIB_DEPRECATED_IN_2_30_FOR|GLIB_DEPRECATED_IN_2_32|GLIB_DEPRECATED_IN_2_32_FOR|GLIB_DEPRECATED_IN_2_34|GLIB_DEPRECATED_IN_2_34_FOR|GLIB_DEPRECATED_IN_2_36|GLIB_DEPRECATED_IN_2_36_FOR|GLIB_DEPRECATED_IN_2_38|GLIB_DEPRECATED_IN_2_38_FOR|GLIB_DEPRECATED_IN_2_40|GLIB_DEPRECATED_IN_2_40_FOR|GLIB_DEPRECATED_IN_2_42|GLIB_DEPRECATED_IN_2_42_FOR|GLIB_DEPRECATED_IN_2_44|GLIB_DEPRECATED_IN_2_44_FOR|GLIB_DEPRECATED_IN_2_46|GLIB_DEPRECATED_IN_2_46_FOR|GLIB_DEPRECATED_IN_2_48|GLIB_DEPRECATED_IN_2_48_FOR|GLIB_DEPRECATED_IN_2_50|GLIB_DEPRECATED_IN_2_50_FOR|GLIB_DEPRECATED_IN_2_52|GLIB_DEPRECATED_IN_2_52_FOR|GLIB_DEPRECATED_IN_2_54|GLIB_DEPRECATED_IN_2_54_FOR|GLIB_DEPRECATED_IN_2_56|GLIB_DEPRECATED_IN_2_56_FOR" # Extra options to supply to gtkdoc-mkdb MKDB_OPTIONS=--output-format=xml --name-space=g diff --git a/docs/reference/gobject/glib-genmarshal.xml b/docs/reference/gobject/glib-genmarshal.xml index 61cfe77..bf72ba7 100644 --- a/docs/reference/gobject/glib-genmarshal.xml +++ b/docs/reference/gobject/glib-genmarshal.xml @@ -411,6 +411,50 @@ debugging information. This option is mutually exclusive with the +Using glib-genmarshal with Autotools + +In order to use glib-genmarshal in your project when using +Autotools as the build system, you will first need to modify your +configure.ac file to ensure you find the appropriate +command using pkg-config, similarly as to how you discover +the compiler and linker flags for GLib. + + +PKG_PROG_PKG_CONFIG([0.28]) + +PKG_CHECK_VAR([GLIB_GENMARSHAL], [glib-2.0], [glib_genmarshal]) + + +In your Makefile.am file you will typically need very +simple rules to generate the C files needed for the build. + + +marshal.h: marshal.list + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --header \ + --output=$@ \ + $< + +marshal.c: marshal.list marshal.h + $(AM_V_GEN)$(GLIB_GENMARSHAL) \ + --include-header=marshal.h \ + --body \ + --output=$@ \ + $< + +BUILT_SOURCES += marshal.h marshal.c +CLEANFILES += marshal.h marshal.c +EXTRA_DIST += marshal.list + + +In the example above, the first rule generates the header file and depends on +a marshal.list file in order to regenerate the result in +case the marshallers list is updated. The second rule generates the source file +for the same marshal.list, and includes the file generated +by the header rule. + + + Example To generate marshallers for the following callback functions: diff --git a/docs/reference/gobject/glib-mkenums.xml b/docs/reference/gobject/glib-mkenums.xml index 1dabe60..545857f 100644 --- a/docs/reference/gobject/glib-mkenums.xml +++ b/docs/reference/gobject/glib-mkenums.xml @@ -208,30 +208,54 @@ typedef enum /*< flags,prefix=PREFIX >*/ TEXT -Put out TEXT prior to processing input files. +Emits TEXT prior to processing input files. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be prepended to the template's file-header section. TEXT -Put out TEXT everytime a new input file +Emits TEXT every time a new input file is being processed. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be appended to the template's file-production section. TEXT -Put out TEXT after all input files have been +Emits TEXT after all input files have been processed. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be appended to the template's file-tail section. TEXT -Put out TEXT everytime an enum is encountered +Emits TEXT everytime an enum is encountered in the input files. @@ -239,23 +263,47 @@ in the input files. TEXT -Put out TEXT before iterating over the set of +Emits TEXT before iterating over the set of values of an enum. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be prepended to the template's value-header section. TEXT -Put out TEXT for every value of an enum. +Emits TEXT for every value of an enum. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be appended to the template's value-production section. TEXT -Put out TEXT after iterating over all values +Emits TEXT after iterating over all values of an enum. + + +You can specify this option multiple times, and the TEXT +will be concatenated. + + +When used along with a template file, TEXT +will be appended to the template's value-tail section. @@ -332,6 +380,124 @@ Write output to FILE instead of stdout. +Using glib-mkenums with Autotools + +In order to use glib-mkenums in your project when using +Autotools as the build system, you will first need to modify your +configure.ac file to ensure you find the appropriate +command using pkg-config, similarly as to how you discover +the compiler and linker flags for GLib. + + +PKG_PROG_PKG_CONFIG([0.28]) + +PKG_CHECK_VAR([GLIB_MKENUMS], [glib-2.0], [glib_mkenums]) + + +In your Makefile.am file you will typically use rules +like these: + + +# A list of headers to inspect +project_headers = \ + project-foo.h \ + project-bar.h \ + project-baz.h + +enum-types.h: $(project_headers) enum-types.h.in + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template=enum-types.h.in \ + --output=$@ \ + $(project_headers) + +enum-types.c: $(project_headers) enum-types.c.in enum-types.h + $(AM_V_GEN)$(GLIB_MKENUMS) \ + --template=enum-types.c.in \ + --output=$@ \ + $(project_headers) + +BUILT_SOURCES += enum-types.h enum-types.c +CLEANFILES += enum-types.h enum-types.c +EXTRA_DIST += enum-types.h.in enum-types.c.in + + +In the example above, we have a variable called project_headers +where we reference all header files we want to inspect for generating enumeration +GTypes. In the enum-types.h rule we use glib-mkenums +with a template called enum-types.h.in in order to generate the +header file; a header template file will typically look like this: + + +/*** BEGIN file-header ***/ +#pragma once + +/* Include the main project header */ +#include "project.h" + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void) G_GNUC_CONST; +#define @ENUMPREFIX@_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ +G_END_DECLS +/*** END file-tail ***/ + + +The enum-types.c rule is similar to the rule for the +header file, but will use a different enum-types.c.in template +file, similar to this: + + +/*** BEGIN file-header ***/ +#include "config.h" +#include "enum-types.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_@type@_type_id__volatile; + + if (g_once_init_enter (&g_define_type_id__volatile)) + { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + + GType g_@type@_type_id = + g_@type@_register_static (g_intern_static_string ("@EnumName@"), values); + + g_once_init_leave (&g_@type@_type_id__volatile, g_@type@_type_id); + } + return g_@type@_type_id__volatile; +} + +/*** END value-tail ***/ + + + See also diff --git a/docs/reference/gobject/meson.build b/docs/reference/gobject/meson.build index 1025e17..5a7aa47 100644 --- a/docs/reference/gobject/meson.build +++ b/docs/reference/gobject/meson.build @@ -8,6 +8,61 @@ if get_option('with-docs') != 'no' 'gtype-private.h' ] + ignore_decorators = [ + 'GLIB_VAR', + 'G_GNUC_INTERNAL', + 'G_GNUC_WARN_UNUSED_RESULT', + 'GLIB_AVAILABLE_IN_ALL', + 'GLIB_AVAILABLE_IN_2_26', + 'GLIB_AVAILABLE_IN_2_28', + 'GLIB_AVAILABLE_IN_2_30', + 'GLIB_AVAILABLE_IN_2_32', + 'GLIB_AVAILABLE_IN_2_34', + 'GLIB_AVAILABLE_IN_2_36', + 'GLIB_AVAILABLE_IN_2_38', + 'GLIB_AVAILABLE_IN_2_40', + 'GLIB_AVAILABLE_IN_2_42', + 'GLIB_AVAILABLE_IN_2_44', + 'GLIB_AVAILABLE_IN_2_46', + 'GLIB_AVAILABLE_IN_2_48', + 'GLIB_AVAILABLE_IN_2_50', + 'GLIB_AVAILABLE_IN_2_52', + 'GLIB_AVAILABLE_IN_2_54', + 'GLIB_AVAILABLE_IN_2_56', + 'GLIB_DEPRECATED_IN_2_26', + 'GLIB_DEPRECATED_IN_2_26_FOR', + 'GLIB_DEPRECATED_IN_2_28', + 'GLIB_DEPRECATED_IN_2_28_FOR', + 'GLIB_DEPRECATED_IN_2_30', + 'GLIB_DEPRECATED_IN_2_30_FOR', + 'GLIB_DEPRECATED_IN_2_32', + 'GLIB_DEPRECATED_IN_2_32_FOR', + 'GLIB_DEPRECATED_IN_2_34', + 'GLIB_DEPRECATED_IN_2_34_FOR', + 'GLIB_DEPRECATED_IN_2_36', + 'GLIB_DEPRECATED_IN_2_36_FOR', + 'GLIB_DEPRECATED_IN_2_38', + 'GLIB_DEPRECATED_IN_2_38_FOR', + 'GLIB_DEPRECATED_IN_2_40', + 'GLIB_DEPRECATED_IN_2_40_FOR', + 'GLIB_DEPRECATED_IN_2_42', + 'GLIB_DEPRECATED_IN_2_42_FOR', + 'GLIB_DEPRECATED_IN_2_44', + 'GLIB_DEPRECATED_IN_2_44_FOR', + 'GLIB_DEPRECATED_IN_2_46', + 'GLIB_DEPRECATED_IN_2_46_FOR', + 'GLIB_DEPRECATED_IN_2_48', + 'GLIB_DEPRECATED_IN_2_48_FOR', + 'GLIB_DEPRECATED_IN_2_50', + 'GLIB_DEPRECATED_IN_2_50_FOR', + 'GLIB_DEPRECATED_IN_2_52', + 'GLIB_DEPRECATED_IN_2_52_FOR', + 'GLIB_DEPRECATED_IN_2_54', + 'GLIB_DEPRECATED_IN_2_54_FOR', + 'GLIB_DEPRECATED_IN_2_56', + 'GLIB_DEPRECATED_IN_2_56_FOR', + ] + docpath = join_paths(glib_datadir, 'gtk-doc', 'html') version_conf = configuration_data() version_conf.set('GLIB_VERSION', meson.project_version()) @@ -26,7 +81,7 @@ if get_option('with-docs') != 'no' src_dir : 'gobject', scan_args : [ '--deprecated-guards=G_DISABLE_DEPRECATED', - '--ignore-decorators=G_GNUC_INTERNAL|G_GNUC_WARN_UNUSED_RESULT', + '--ignore-decorators=' + '|'.join(ignore_decorators), '--ignore-headers=' + ' '.join(ignore_headers), ], content_files : [ diff --git a/docs/reference/gobject/tut_gsignal.xml b/docs/reference/gobject/tut_gsignal.xml index f990ab8..4ed4211 100644 --- a/docs/reference/gobject/tut_gsignal.xml +++ b/docs/reference/gobject/tut_gsignal.xml @@ -390,8 +390,8 @@ void g_signal_emitv (const GValue *instance_and_params, - If, at any point during emission (except in RUN_CLEANUP state), one of the - closures or emission hook stops the signal emission with + If, at any point during emission (except in RUN_CLEANUP or + EMISSION_HOOK state), one of the closures stops the signal emission with g_signal_stop_emission, emission jumps to RUN_CLEANUP state. diff --git a/docs/reference/gobject/tut_gtype.xml b/docs/reference/gobject/tut_gtype.xml index 126eac3..a1c6005 100644 --- a/docs/reference/gobject/tut_gtype.xml +++ b/docs/reference/gobject/tut_gtype.xml @@ -677,7 +677,7 @@ viewer_editable_save (ViewerEditable *self, g_return_if_fail (VIEWER_IS_EDITABLE (self)); g_return_if_fail (error == NULL || *error == NULL); - iface = VIEWER_EDITABLE_GET_INTERFACE (self); + iface = VIEWER_EDITABLE_GET_IFACE (self); g_return_if_fail (iface->save != NULL); iface->save (self); } diff --git a/gio/Makefile.am b/gio/Makefile.am index b2db995..0cfda50 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 0316e29..22b2ac3 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 28c1d71..0000000 --- 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 . -# -# Author: Kalev Lember - - -if (@ARGV != 2) { - die "Usage: data-to-c.pl \n"; -} - -$file = $ARGV[0]; - -open (FILE, $file) || die "Cannot open $file: $!\n"; - -printf ("const char %s[] = \"", $ARGV[1]); -while (my $line = ) { - 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 old mode 100644 new mode 100755 index 7a8d8a8..f226220 --- 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 b0c03dd..646b8ef 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 may not 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 may not 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 18f0126..4889be9 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 0ee6ca6..9d880fc 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 b3a99e0..d6c5c45 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 fc2464a..41bbb2a 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 fafda9a..b96f1ee 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 f70ccb0..f5090d0 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 dced16e..d833bcf 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 b3fb2c2..b4e500c 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 old mode 100644 new mode 100755 index 8050981..67d3675 --- 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 0e9ffbd..54a86b0 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 fb285f1..77863a2 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 6fb3d2a..faee800 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 e46e622..1a0ada5 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 a51430c..47cef78 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 b56c5a8..421e9ea 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 c41c203..95949ea 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 4dd17af..4c82bd0 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 e80794f..7dd458d 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 d803ecb..491e21e 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 17a515a..08c94d5 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 fa52f84..cb5ec48 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 67a038d..cbcb720 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 8a78e95..812b148 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 1efbfa0..1717665 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 3e4db13..d96a798 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 bedc81b..c6ee8c4 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 6937932..4047695 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 67c9cc7..738e517 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 a92fefd..8a1a07d 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 b8de090..2dc8c71 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 c2491be..2b943a8 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 d417c49..e484a31 100644 --- a/gio/glocalfile.c +++ b/gio/glocalfile.c @@ -62,11 +62,11 @@ #include "gunixmounts.h" #include "gioerror.h" #include +#include #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 f46d4d6..fad80d3 100644 --- a/gio/glocalfileinfo.c +++ b/gio/glocalfileinfo.c @@ -53,6 +53,7 @@ #endif /* HAVE_XATTR */ #include +#include #include #include #include @@ -60,9 +61,10 @@ #ifdef G_OS_UNIX #include #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 f036288..a231c24 100644 --- a/gio/glocalfileinfo.h +++ b/gio/glocalfileinfo.h @@ -23,6 +23,7 @@ #include #include +#include #include #include @@ -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 7600571..57d2d5d 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 #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 3d74b85..0169ea5 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 247ed8c..51a72df 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 b24b6ff..463b2da 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 485f5bf..3474775 100644 --- a/gio/gosxcontenttype.c +++ b/gio/gosxcontenttype.c @@ -25,6 +25,12 @@ #include +#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 c59eb67..6372fd9 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 da7f1c5..411e003 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 ed0e474..8ead26b 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 739c6e2..429e9ef 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 8cd552d..00e3a16 100644 --- a/gio/gschema.dtd +++ b/gio/gschema.dtd @@ -1,4 +1,4 @@ - + @@ -47,8 +47,7 @@ - + diff --git a/gio/gseekable.c b/gio/gseekable.c index 26159d0..5237e7f 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 45b10dd..7b0b6a1 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 0d5df0f..edc4ff4 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 bc7a4ac..4e12243 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 7883463..c6ddd97 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 ba90be5..567b480 100644 --- a/gio/gsocket.c +++ b/gio/gsocket.c @@ -44,6 +44,10 @@ # include #endif +#ifdef HAVE_SIOCGIFADDR +#include +#endif + #ifdef HAVE_SYS_FILIO_H # include #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 613c8dd..a65cbc2 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 e5185c2..687fab3 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 8525f3b..18de30e 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 5cdec4d..12a5e44 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 7eb0185..814ba94 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: * |[ @@ -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: * |[ @@ -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 7fa266a..7941d95 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 a78d84b..80af6ad 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 424d9c1..5a77b56 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 27364b1..1e437a7 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 8e32b4f..fc37129 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 853b161..04d6b07 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 67a70a9..f97ce4c 100644 --- a/gio/gvolume.c +++ b/gio/gvolume.c @@ -633,7 +633,7 @@ g_volume_enumerate_identifiers (GVolume *volume) * then the expression * |[ * (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 cc8d917..cb22f89 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 d64e34d..dce57e5 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 f0528f4..5110dff 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 e7d583c..d4e66cd 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 3252636..4a10d49 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 + #include + 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 acc1da4..a553958 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 2e69da0..1902053 100644 --- a/gio/tests/appinfo.c +++ b/gio/tests/appinfo.c @@ -7,8 +7,9 @@ #include 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 1acbd77..2424b8e 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[] = "\n\ + \n\ +\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 5eeb1c0..90d8d06 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 97fe69d..83976e0 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 7791837..cf2aae2 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 0000000..9a185b0 --- /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 +#include +#include +#include + +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 7ed874a..5b3def9 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 #include #include #include +#ifdef G_OS_WIN32 +#include +#include +#include +#include +#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 fff1f48..8a2c324 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 f18db77..a604f99 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 40a396d..65f656c 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, "* already specified*" }, { "enum-with-repeated-nick", NULL, "* already specified*" }, { "enum-with-repeated-value", NULL, "*value='1' already specified*" }, diff --git a/gio/tests/httpd.c b/gio/tests/httpd.c index 41bc6c8..9bca6c9 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 e149a4b..fb17cc4 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 b002325..8163aa1 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 0000000..02071e0 --- /dev/null +++ b/gio/tests/schema-tests/enum-with-invalid-value.gschema.xml @@ -0,0 +1,10 @@ + + + + + + + + + + diff --git a/gio/tests/socket.c b/gio/tests/socket.c index 4343dd5..0835a66 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 0000000..3d54047 --- /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 . + */ + +#include + +#ifndef G_OS_UNIX +#error This is a Unix-specific test +#endif + +#include +#include +#include +#include +#include + +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 (); +} diff --git a/glib-gettextize.in b/glib-gettextize.in old mode 100644 new mode 100755 diff --git a/glib/Makefile.am b/glib/Makefile.am index 5478edb..8da549c 100644 --- a/glib/Makefile.am +++ b/glib/Makefile.am @@ -161,6 +161,7 @@ libglib_2_0_la_SOURCES = \ gslice.c \ gslist.c \ gstdio.c \ + gstdioprivate.h \ gstrfuncs.c \ gstring.c \ gstringchunk.c \ @@ -478,6 +479,7 @@ dist-hook: $(BUILT_EXTRA_DIST) $(top_builddir)/win32/vs9/glib.vcproj $(top_build gdbdir = $(datadir)/glib-2.0/gdb dist_gdb_DATA = glib_gdb.py +all-local: libglib-gdb.py libglib-gdb.py: libglib-gdb.py.in $(AM_V_GEN) $(SED) -e "s|\@datadir\@|$(datadir)|" $(srcdir)/libglib-gdb.py.in > $(builddir)/libglib-gdb.py diff --git a/glib/docs.c b/glib/docs.c index da23623..d6ac4b3 100644 --- a/glib/docs.c +++ b/glib/docs.c @@ -32,18 +32,20 @@ * and portability * * GLib defines a number of commonly used types, which can be divided - * into 4 groups: + * into several groups: * - New types which are not part of standard C (but are defined in - * various C standard library header files) - #gboolean, #gsize, - * #gssize, #goffset, #gintptr, #guintptr. + * various C standard library header files) — #gboolean, #gssize. * - Integer types which are guaranteed to be the same size across - * all platforms - #gint8, #guint8, #gint16, #guint16, #gint32, + * all platforms — #gint8, #guint8, #gint16, #guint16, #gint32, * #guint32, #gint64, #guint64. * - Types which are easier to use than their standard C counterparts - * #gpointer, #gconstpointer, #guchar, #guint, #gushort, #gulong. * - Types which correspond exactly to standard C types, but are - * included for completeness - #gchar, #gint, #gshort, #glong, + * included for completeness — #gchar, #gint, #gshort, #glong, * #gfloat, #gdouble. + * - Types which correspond exactly to standard C99 types, but are available + * to use even if your compiler does not support C99 — #gsize, #goffset, + * #gintptr, #guintptr. * * GLib also defines macros for the limits of some of the standard * integer and floating point types, as well as macros for suitable @@ -1997,6 +1999,8 @@ /** * G_GNUC_CHECK_VERSION: + * @major: major version to check against + * @minor: minor version to check against * * Expands to a a check for a compiler with __GNUC__ defined and a version * greater than or equal to the major and minor numbers provided. For example, diff --git a/glib/gbase64.c b/glib/gbase64.c index 651840e..7d8b20d 100644 --- a/glib/gbase64.c +++ b/glib/gbase64.c @@ -298,10 +298,10 @@ static const unsigned char mime_base64_rank[256] = { }; /** - * g_base64_decode_step: + * g_base64_decode_step: (skip) * @in: (array length=len) (element-type guint8): binary input data * @len: max length of @in data to decode - * @out: (out) (array) (element-type guint8): output buffer + * @out: (out caller-allocates) (array) (element-type guint8): output buffer * @state: (inout): Saved state between steps, initialize to 0 * @save: (inout): Saved state between steps, initialize to 0 * diff --git a/glib/gbookmarkfile.c b/glib/gbookmarkfile.c index 7d7da03..596e370 100644 --- a/glib/gbookmarkfile.c +++ b/glib/gbookmarkfile.c @@ -1566,7 +1566,7 @@ G_DEFINE_QUARK (g-bookmark-file-error-quark, g_bookmark_file_error) ********************/ /** - * g_bookmark_file_new: + * g_bookmark_file_new: (constructor) * * Creates a new empty #GBookmarkFile object. * diff --git a/glib/gbytes.c b/glib/gbytes.c index a68b17d..747c41b 100644 --- a/glib/gbytes.c +++ b/glib/gbytes.c @@ -99,7 +99,7 @@ g_bytes_new (gconstpointer data, /** * g_bytes_new_take: * @data: (transfer full) (array length=size) (element-type guint8) (nullable): - the data to be used for the bytes + * the data to be used for the bytes * @size: the size of @data * * Creates a new #GBytes from @data. @@ -130,7 +130,7 @@ g_bytes_new_take (gpointer data, /** * g_bytes_new_static: (skip) * @data: (transfer full) (array length=size) (element-type guint8) (nullable): - the data to be used for the bytes + * the data to be used for the bytes * @size: the size of @data * * Creates a new #GBytes from static data. @@ -152,7 +152,7 @@ g_bytes_new_static (gconstpointer data, /** * g_bytes_new_with_free_func: (skip) * @data: (array length=size) (element-type guint8) (nullable): - the data to be used for the bytes + * the data to be used for the bytes * @size: the size of @data * @free_func: the function to call to release the data * @user_data: data to pass to @free_func @@ -407,7 +407,8 @@ try_steal_and_unref (GBytes *bytes, { gpointer result; - if (bytes->free_func != free_func || bytes->data == NULL) + if (bytes->free_func != free_func || bytes->data == NULL || + bytes->user_data != bytes->data) return NULL; /* Are we the only reference? */ diff --git a/glib/gconvert.c b/glib/gconvert.c index 64fd981..194b2fc 100644 --- a/glib/gconvert.c +++ b/glib/gconvert.c @@ -128,7 +128,6 @@ * ## Checklist for Application Writers * * This section is a practical summary of the detailed - * things to do to make sure your applications process file * name encodings correctly. * @@ -202,7 +201,7 @@ try_to_aliases (const char **to_aliases, } /** - * g_iconv_open: + * g_iconv_open: (skip) * @to_codeset: destination codeset * @from_codeset: source codeset * @@ -251,7 +250,7 @@ g_iconv_open (const gchar *to_codeset, } /** - * g_iconv: + * g_iconv: (skip) * @converter: conversion descriptor from g_iconv_open() * @inbuf: bytes to convert * @inbytes_left: inout parameter, bytes remaining to convert in @inbuf @@ -280,7 +279,7 @@ g_iconv (GIConv converter, } /** - * g_iconv_close: + * g_iconv_close: (skip) * @converter: a conversion descriptor from g_iconv_open() * * Same as the standard UNIX routine iconv_close(), but @@ -340,7 +339,7 @@ close_converter (GIConv cd) } /** - * g_convert_with_iconv: + * g_convert_with_iconv: (skip) * @str: the string to convert * @len: the length of the string in bytes, or -1 if the string is * nul-terminated (Note that some encodings may allow nul @@ -583,8 +582,8 @@ g_convert (const gchar *str, * @fallback: UTF-8 string to use in place of character not * present in the target encoding. (The string must be * representable in the target encoding). - If %NULL, characters not in the target encoding will - be represented as Unicode escapes \uxxxx or \Uxxxxyyyy. + * If %NULL, characters not in the target encoding will + * be represented as Unicode escapes \uxxxx or \Uxxxxyyyy. * @bytes_read: location to store the number of bytes in the * input string that were successfully converted, or %NULL. * Even if the conversion was successful, this may be diff --git a/glib/gconvert.h b/glib/gconvert.h index ab6ab4f..f064e41 100644 --- a/glib/gconvert.h +++ b/glib/gconvert.h @@ -69,7 +69,7 @@ GLIB_AVAILABLE_IN_ALL GQuark g_convert_error_quark (void); /** - * GIConv: + * GIConv: (skip) * * The GIConv struct wraps an iconv() conversion descriptor. It contains * private data and should only be accessed using the following functions. diff --git a/glib/gdataset.c b/glib/gdataset.c index 28ec0c0..ae36e9e 100644 --- a/glib/gdataset.c +++ b/glib/gdataset.c @@ -243,7 +243,7 @@ g_datalist_clear_i (GData **datalist) } /** - * g_datalist_clear: + * g_datalist_clear: (skip) * @datalist: a datalist. * * Frees all the data elements of the datalist. @@ -486,7 +486,7 @@ g_data_set_internal (GData **datalist, } /** - * g_dataset_id_set_data_full: + * g_dataset_id_set_data_full: (skip) * @dataset_location: (not nullable): the location identifying the dataset. * @key_id: the #GQuark id to identify the data element. * @data: the data element. @@ -501,7 +501,7 @@ g_data_set_internal (GData **datalist, * is called. **/ /** - * g_dataset_set_data_full: + * g_dataset_set_data_full: (skip) * @l: the location identifying the dataset. * @k: the string to identify the data element. * @d: the data element. @@ -585,12 +585,12 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, } /** - * g_datalist_id_set_data_full: + * g_datalist_id_set_data_full: (skip) * @datalist: a datalist. * @key_id: the #GQuark to identify the data element. * @data: (nullable): the data element or %NULL to remove any previous element * corresponding to @key_id. - * @destroy_func: the function to call when the data element is + * @destroy_func: (nullable): the function to call when the data element is * removed. This function will be called with the data * element and can be used to free any memory allocated * for it. If @data is %NULL, then @destroy_func must @@ -602,13 +602,13 @@ g_dataset_id_set_data_full (gconstpointer dataset_location, * function is called. **/ /** - * g_datalist_set_data_full: + * g_datalist_set_data_full: (skip) * @dl: a datalist. * @k: the string to identify the data element. * @d: (nullable): the data element, or %NULL to remove any previous element * corresponding to @k. - * @f: the function to call when the data element is removed. This - * function will be called with the data element and can be used to + * @f: (nullable): the function to call when the data element is removed. + * This function will be called with the data element and can be used to * free any memory allocated for it. If @d is %NULL, then @f must * also be %NULL. * @@ -671,17 +671,18 @@ g_datalist_id_set_data_full (GData **datalist, } /** - * g_dataset_id_remove_no_notify: + * g_dataset_id_remove_no_notify: (skip) * @dataset_location: (not nullable): the location identifying the dataset. * @key_id: the #GQuark ID identifying the data element. * * Removes an element, without calling its destroy notification * function. * - * Returns: the data previously stored at @key_id, or %NULL if none. + * Returns: (nullable): the data previously stored at @key_id, + * or %NULL if none. **/ /** - * g_dataset_remove_no_notify: + * g_dataset_remove_no_notify: (skip) * @l: the location identifying the dataset. * @k: the string identifying the data element. * @@ -710,17 +711,18 @@ g_dataset_id_remove_no_notify (gconstpointer dataset_location, } /** - * g_datalist_id_remove_no_notify: + * g_datalist_id_remove_no_notify: (skip) * @datalist: a datalist. * @key_id: the #GQuark identifying a data element. * * Removes an element, without calling its destroy notification * function. * - * Returns: the data previously stored at @key_id, or %NULL if none. + * Returns: (nullable): the data previously stored at @key_id, + * or %NULL if none. **/ /** - * g_datalist_remove_no_notify: + * g_datalist_remove_no_notify: (skip) * @dl: a datalist. * @k: the string identifying the data element. * @@ -747,8 +749,8 @@ g_datalist_id_remove_no_notify (GData **datalist, * * Gets the data element corresponding to a #GQuark. * - * Returns: the data element corresponding to the #GQuark, or %NULL if - * it is not found. + * Returns: (transfer none) (nullable): the data element corresponding to + * the #GQuark, or %NULL if it is not found. **/ /** * g_dataset_get_data: @@ -757,8 +759,8 @@ g_datalist_id_remove_no_notify (GData **datalist, * * Gets the data element corresponding to a string. * - * Returns: the data element corresponding to the string, or %NULL if - * it is not found. + * Returns: (transfer none) (nullable): the data element corresponding to + * the string, or %NULL if it is not found. **/ gpointer g_dataset_id_get_data (gconstpointer dataset_location, @@ -789,7 +791,8 @@ g_dataset_id_get_data (gconstpointer dataset_location, * * Retrieves the data element corresponding to @key_id. * - * Returns: the data element, or %NULL if it is not found. + * Returns: (transfer none) (nullable): the data element, or %NULL if + * it is not found. */ gpointer g_datalist_id_get_data (GData **datalist, @@ -801,7 +804,8 @@ g_datalist_id_get_data (GData **datalist, /** * GDuplicateFunc: * @data: the data to duplicate - * @user_data: user data that was specified in g_datalist_id_dup_data() + * @user_data: (closure): user data that was specified in + * g_datalist_id_dup_data() * * The type of functions that are used to 'duplicate' an object. * What this means depends on the context, it could just be @@ -812,11 +816,11 @@ g_datalist_id_get_data (GData **datalist, */ /** - * g_datalist_id_dup_data: + * g_datalist_id_dup_data: (skip) * @datalist: location of a datalist * @key_id: the #GQuark identifying a data element - * @dup_func: (nullable): function to duplicate the old value - * @user_data: (nullable): passed as user_data to @dup_func + * @dup_func: (nullable) (scope call): function to duplicate the old value + * @user_data: (closure): passed as user_data to @dup_func * * This is a variant of g_datalist_id_get_data() which * returns a 'duplicate' of the value. @dup_func defines the @@ -832,7 +836,7 @@ g_datalist_id_get_data (GData **datalist, * This function can be useful to avoid races when multiple * threads are using the same datalist and the same key. * - * Returns: the result of calling @dup_func on the value + * Returns: (nullable): the result of calling @dup_func on the value * associated with @key_id in @datalist, or %NULL if not set. * If @dup_func is %NULL, the value is returned unmodified. * @@ -879,13 +883,13 @@ g_datalist_id_dup_data (GData **datalist, } /** - * g_datalist_id_replace_data: + * g_datalist_id_replace_data: (skip) * @datalist: location of a datalist * @key_id: the #GQuark identifying a data element * @oldval: (nullable): the old value to compare against * @newval: (nullable): the new value to replace it with * @destroy: (nullable): destroy notify for the new value - * @old_destroy: (nullable): destroy notify for the existing value + * @old_destroy: (out) (optional): destroy notify for the existing value * * Compares the member that is associated with @key_id in * @datalist to @oldval, and if they are the same, replace @@ -1006,7 +1010,8 @@ g_datalist_id_replace_data (GData **datalist, * Gets a data element, using its string identifier. This is slower than * g_datalist_id_get_data() because it compares strings. * - * Returns: the data element, or %NULL if it is not found. + * Returns: (transfer none) (nullable): the data element, or %NULL if it + * is not found. **/ gpointer g_datalist_get_data (GData **datalist, @@ -1045,7 +1050,7 @@ g_datalist_get_data (GData **datalist, * GDataForeachFunc: * @key_id: the #GQuark id to identifying the data element. * @data: the data element. - * @user_data: user data passed to g_dataset_foreach(). + * @user_data: (closure): user data passed to g_dataset_foreach(). * * Specifies the type of function passed to g_dataset_foreach(). It is * called with each #GQuark id and associated data element, together @@ -1055,8 +1060,8 @@ g_datalist_get_data (GData **datalist, /** * g_dataset_foreach: * @dataset_location: (not nullable): the location identifying the dataset. - * @func: the function to call for each data element. - * @user_data: user data to pass to the function. + * @func: (scope call): the function to call for each data element. + * @user_data: (closure): user data to pass to the function. * * Calls the given function for each data element which is associated * with the given location. Note that this function is NOT thread-safe. @@ -1090,8 +1095,8 @@ g_dataset_foreach (gconstpointer dataset_location, /** * g_datalist_foreach: * @datalist: a datalist. - * @func: the function to call for each data element. - * @user_data: user data to pass to the function. + * @func: (scope call): the function to call for each data element. + * @user_data: (closure): user data to pass to the function. * * Calls the given function for each data element of the datalist. The * function is called with each data element's #GQuark id and data, @@ -1143,7 +1148,7 @@ g_datalist_foreach (GData **datalist, } /** - * g_datalist_init: + * g_datalist_init: (skip) * @datalist: a pointer to a pointer to a datalist. * * Resets the datalist to %NULL. It does not free any memory or call diff --git a/glib/gdate.c b/glib/gdate.c index 1519cf0..58cb75c 100644 --- a/glib/gdate.c +++ b/glib/gdate.c @@ -343,6 +343,35 @@ g_date_free (GDate *date) } /** + * g_date_copy: + * @date: a #GDate to copy + * + * Copies a GDate to a newly-allocated GDate. If the input was invalid + * (as determined by g_date_valid()), the invalid state will be copied + * as is into the new object. + * + * Returns: (transfer full): a newly-allocated #GDate initialized from @date + * + * Since: 2.56 + */ +GDate * +g_date_copy (const GDate *date) +{ + GDate *res; + g_return_val_if_fail (date != NULL, NULL); + + if (g_date_valid (date)) + res = g_date_new_julian (g_date_get_julian (date)); + else + { + res = g_date_new (); + *res = *date; + } + + return res; +} + +/** * g_date_valid: * @date: a #GDate to check * diff --git a/glib/gdate.h b/glib/gdate.h index bc7e931..63feb35 100644 --- a/glib/gdate.h +++ b/glib/gdate.h @@ -127,6 +127,8 @@ GLIB_AVAILABLE_IN_ALL GDate* g_date_new_julian (guint32 julian_day); GLIB_AVAILABLE_IN_ALL void g_date_free (GDate *date); +GLIB_AVAILABLE_IN_2_56 +GDate* g_date_copy (const GDate *date); /* check g_date_valid() after doing an operation that might fail, like * _parse. Almost all g_date operations are undefined on invalid diff --git a/glib/gdatetime.c b/glib/gdatetime.c index c78bc4c..e1c7260 100644 --- a/glib/gdatetime.c +++ b/glib/gdatetime.c @@ -22,6 +22,7 @@ * Thiago Santos * Emmanuele Bassi * Ryan Lortie + * Robert Ancell */ /* Algorithms within this file are based on the Calendar FAQ by @@ -902,6 +903,342 @@ g_date_time_new_from_timeval_utc (const GTimeVal *tv) return datetime; } +/* Parse integers in the form d (week days), dd (hours etc), ddd (ordinal days) or dddd (years) */ +static gboolean +get_iso8601_int (const gchar *text, gsize length, gint *value) +{ + gint i, v = 0; + + if (length < 1 || length > 4) + return FALSE; + + for (i = 0; i < length; i++) + { + const gchar c = text[i]; + if (c < '0' || c > '9') + return FALSE; + v = v * 10 + (c - '0'); + } + + *value = v; + return TRUE; +} + +/* Parse seconds in the form ss or ss.sss (variable length decimal) */ +static gboolean +get_iso8601_seconds (const gchar *text, gsize length, gdouble *value) +{ + gint i; + gdouble multiplier = 0.1, v = 0; + + if (length < 2) + return FALSE; + + for (i = 0; i < 2; i++) + { + const gchar c = text[i]; + if (c < '0' || c > '9') + return FALSE; + v = v * 10 + (c - '0'); + } + + if (length > 2 && !(text[i] == '.' || text[i] == ',')) + return FALSE; + i++; + if (i == length) + return FALSE; + + for (; i < length; i++) + { + const gchar c = text[i]; + if (c < '0' || c > '9') + return FALSE; + v += (c - '0') * multiplier; + multiplier *= 0.1; + } + + *value = v; + return TRUE; +} + +static GDateTime * +g_date_time_new_ordinal (GTimeZone *tz, gint year, gint ordinal_day, gint hour, gint minute, gdouble seconds) +{ + GDateTime *dt; + + if (ordinal_day < 1 || ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365)) + return NULL; + + dt = g_date_time_new (tz, year, 1, 1, hour, minute, seconds); + dt->days += ordinal_day - 1; + + return dt; +} + +static GDateTime * +g_date_time_new_week (GTimeZone *tz, gint year, gint week, gint week_day, gint hour, gint minute, gdouble seconds) +{ + gint64 p; + gint max_week, jan4_week_day, ordinal_day; + GDateTime *dt; + + p = (year * 365 + (year / 4) - (year / 100) + (year / 400)) % 7; + max_week = p == 4 ? 53 : 52; + + if (week < 1 || week > max_week || week_day < 1 || week_day > 7) + return NULL; + + dt = g_date_time_new (tz, year, 1, 4, 0, 0, 0); + g_date_time_get_week_number (dt, NULL, &jan4_week_day, NULL); + ordinal_day = (week * 7) + week_day - (jan4_week_day + 3); + if (ordinal_day < 0) + { + year--; + ordinal_day += GREGORIAN_LEAP (year) ? 366 : 365; + } + else if (ordinal_day > (GREGORIAN_LEAP (year) ? 366 : 365)) + { + ordinal_day -= (GREGORIAN_LEAP (year) ? 366 : 365); + year++; + } + + return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds); +} + +static GDateTime * +parse_iso8601_date (const gchar *text, gsize length, + gint hour, gint minute, gdouble seconds, GTimeZone *tz) +{ + /* YYYY-MM-DD */ + if (length == 10 && text[4] == '-' && text[7] == '-') + { + int year, month, day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 5, 2, &month) || + !get_iso8601_int (text + 8, 2, &day)) + return NULL; + return g_date_time_new (tz, year, month, day, hour, minute, seconds); + } + /* YYYY-DDD */ + else if (length == 8 && text[4] == '-') + { + gint year, ordinal_day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 5, 3, &ordinal_day)) + return NULL; + return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds); + } + /* YYYY-Www-D */ + else if (length == 10 && text[4] == '-' && text[5] == 'W' && text[8] == '-') + { + gint year, week, week_day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 6, 2, &week) || + !get_iso8601_int (text + 9, 1, &week_day)) + return NULL; + return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds); + } + /* YYYYWwwD */ + else if (length == 8 && text[4] == 'W') + { + gint year, week, week_day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 5, 2, &week) || + !get_iso8601_int (text + 7, 1, &week_day)) + return NULL; + return g_date_time_new_week (tz, year, week, week_day, hour, minute, seconds); + } + /* YYYYMMDD */ + else if (length == 8) + { + int year, month, day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 4, 2, &month) || + !get_iso8601_int (text + 6, 2, &day)) + return NULL; + return g_date_time_new (tz, year, month, day, hour, minute, seconds); + } + /* YYYYDDD */ + else if (length == 7) + { + gint year, ordinal_day; + if (!get_iso8601_int (text, 4, &year) || + !get_iso8601_int (text + 4, 3, &ordinal_day)) + return NULL; + return g_date_time_new_ordinal (tz, year, ordinal_day, hour, minute, seconds); + } + else + return FALSE; +} + +static GTimeZone * +parse_iso8601_timezone (const gchar *text, gsize length, gssize *tz_offset) +{ + gint i, tz_length, offset_sign = 1, offset_hours, offset_minutes; + GTimeZone *tz; + + /* UTC uses Z suffix */ + if (length > 0 && text[length - 1] == 'Z') + { + *tz_offset = length - 1; + return g_time_zone_new_utc (); + } + + /* Look for '+' or '-' of offset */ + for (i = length - 1; i >= 0; i--) + if (text[i] == '+' || text[i] == '-') + { + offset_sign = text[i] == '-' ? -1 : 1; + break; + } + if (i < 0) + return NULL; + tz_length = length - i; + + /* +hh:mm or -hh:mm */ + if (tz_length == 6 && text[i+3] == ':') + { + if (!get_iso8601_int (text + i + 1, 2, &offset_hours) || + !get_iso8601_int (text + i + 4, 2, &offset_minutes)) + return NULL; + } + /* +hhmm or -hhmm */ + else if (tz_length == 5) + { + if (!get_iso8601_int (text + i + 1, 2, &offset_hours) || + !get_iso8601_int (text + i + 3, 2, &offset_minutes)) + return NULL; + } + /* +hh or -hh */ + else if (tz_length == 3) + { + if (!get_iso8601_int (text + i + 1, 2, &offset_hours)) + return NULL; + offset_minutes = 0; + } + else + return NULL; + + *tz_offset = i; + tz = g_time_zone_new (text + i); + + /* Double-check that the GTimeZone matches our interpretation of the timezone. + * Failure would indicate a bug either here of in the GTimeZone code. */ + g_assert (g_time_zone_get_offset (tz, 0) == offset_sign * (offset_hours * 3600 + offset_minutes * 60)); + + return tz; +} + +static gboolean +parse_iso8601_time (const gchar *text, gsize length, + gint *hour, gint *minute, gdouble *seconds, GTimeZone **tz) +{ + gssize tz_offset = -1; + + /* Check for timezone suffix */ + *tz = parse_iso8601_timezone (text, length, &tz_offset); + if (tz_offset >= 0) + length = tz_offset; + + /* hh:mm:ss(.sss) */ + if (length >= 8 && text[2] == ':' && text[5] == ':') + { + return get_iso8601_int (text, 2, hour) && + get_iso8601_int (text + 3, 2, minute) && + get_iso8601_seconds (text + 6, length - 6, seconds); + } + /* hhmmss(.sss) */ + else if (length >= 6) + { + return get_iso8601_int (text, 2, hour) && + get_iso8601_int (text + 2, 2, minute) && + get_iso8601_seconds (text + 4, length - 4, seconds); + } + else + return FALSE; +} + +/** + * g_date_time_new_from_iso8601: + * @text: an ISO 8601 formatted time string. + * @default_tz: (nullable): a #GTimeZone to use if the text doesn't contain a + * timezone, or %NULL. + * + * Creates a #GDateTime corresponding to the given + * [ISO 8601 formatted string](https://en.wikipedia.org/wiki/ISO_8601) + * @text. ISO 8601 strings of the form