<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.1//EN"
"http://www.w3.org/TR/xhtml11/DTD/xhtml11.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head><meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>[118872] trunk/dports/gnome/gnome-desktop</title>
</head>
<body>

<style type="text/css"><!--
#msg dl.meta { border: 1px #006 solid; background: #369; padding: 6px; color: #fff; }
#msg dl.meta dt { float: left; width: 6em; font-weight: bold; }
#msg dt:after { content:':';}
#msg dl, #msg dt, #msg ul, #msg li, #header, #footer, #logmsg { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt;  }
#msg dl a { font-weight: bold}
#msg dl a:link    { color:#fc3; }
#msg dl a:active  { color:#ff0; }
#msg dl a:visited { color:#cc6; }
h3 { font-family: verdana,arial,helvetica,sans-serif; font-size: 10pt; font-weight: bold; }
#msg pre { overflow: auto; background: #ffc; border: 1px #fa0 solid; padding: 6px; }
#logmsg { background: #ffc; border: 1px #fa0 solid; padding: 1em 1em 0 1em; }
#logmsg p, #logmsg pre, #logmsg blockquote { margin: 0 0 1em 0; }
#logmsg p, #logmsg li, #logmsg dt, #logmsg dd { line-height: 14pt; }
#logmsg h1, #logmsg h2, #logmsg h3, #logmsg h4, #logmsg h5, #logmsg h6 { margin: .5em 0; }
#logmsg h1:first-child, #logmsg h2:first-child, #logmsg h3:first-child, #logmsg h4:first-child, #logmsg h5:first-child, #logmsg h6:first-child { margin-top: 0; }
#logmsg ul, #logmsg ol { padding: 0; list-style-position: inside; margin: 0 0 0 1em; }
#logmsg ul { text-indent: -1em; padding-left: 1em; }#logmsg ol { text-indent: -1.5em; padding-left: 1.5em; }
#logmsg > ul, #logmsg > ol { margin: 0 0 1em 0; }
#logmsg pre { background: #eee; padding: 1em; }
#logmsg blockquote { border: 1px solid #fa0; border-left-width: 10px; padding: 1em 1em 0 1em; background: white;}
#logmsg dl { margin: 0; }
#logmsg dt { font-weight: bold; }
#logmsg dd { margin: 0; padding: 0 0 0.5em 0; }
#logmsg dd:before { content:'\00bb';}
#logmsg table { border-spacing: 0px; border-collapse: collapse; border-top: 4px solid #fa0; border-bottom: 1px solid #fa0; background: #fff; }
#logmsg table th { text-align: left; font-weight: normal; padding: 0.2em 0.5em; border-top: 1px dotted #fa0; }
#logmsg table td { text-align: right; border-top: 1px dotted #fa0; padding: 0.2em 0.5em; }
#logmsg table thead th { text-align: center; border-bottom: 1px solid #fa0; }
#logmsg table th.Corner { text-align: left; }
#logmsg hr { border: none 0; border-top: 2px dashed #fa0; height: 1px; }
#header, #footer { color: #fff; background: #636; border: 1px #300 solid; padding: 6px; }
#patch { width: 100%; }
#patch h4 {font-family: verdana,arial,helvetica,sans-serif;font-size:10pt;padding:8px;background:#369;color:#fff;margin:0;}
#patch .propset h4, #patch .binary h4 {margin:0;}
#patch pre {padding:0;line-height:1.2em;margin:0;}
#patch .diff {width:100%;background:#eee;padding: 0 0 10px 0;overflow:auto;}
#patch .propset .diff, #patch .binary .diff  {padding:10px 0;}
#patch span {display:block;padding:0 10px;}
#patch .modfile, #patch .addfile, #patch .delfile, #patch .propset, #patch .binary, #patch .copfile {border:1px solid #ccc;margin:10px 0;}
#patch ins {background:#dfd;text-decoration:none;display:block;padding:0 10px;}
#patch del {background:#fdd;text-decoration:none;display:block;padding:0 10px;}
#patch .lines, .info {color:#888;background:#fff;}
--></style>
<div id="msg">
<dl class="meta">
<dt>Revision</dt> <dd><a href="https://trac.macports.org/changeset/118872">118872</a></dd>
<dt>Author</dt> <dd>devans@macports.org</dd>
<dt>Date</dt> <dd>2014-04-13 16:00:41 -0700 (Sun, 13 Apr 2014)</dd>
</dl>

<h3>Log Message</h3>
<pre>gnome-desktop: update to version 3.12.0.</pre>

<h3>Modified Paths</h3>
<ul>
<li><a href="#trunkdportsgnomegnomedesktopPortfile">trunk/dports/gnome/gnome-desktop/Portfile</a></li>
<li><a href="#trunkdportsgnomegnomedesktopfilespatchgnomedesktopMakefileamdiff">trunk/dports/gnome/gnome-desktop/files/patch-gnome-desktop-Makefile.am.diff</a></li>
<li><a href="#trunkdportsgnomegnomedesktopfilespatchlibgnomedestktoplibgsystemdiff">trunk/dports/gnome/gnome-desktop/files/patch-libgnome-destktop-libgsystem.diff</a></li>
</ul>

<h3>Property Changed</h3>
<ul>
<li><a href="#trunkdportsgnomegnomedesktop">trunk/dports/gnome/gnome-desktop/</a></li>
</ul>

</div>
<div id="patch">
<h3>Diff</h3>
<a id="trunkdportsgnomegnomedesktop"></a>
<div class="propset"><h4>Property changes: trunk/dports/gnome/gnome-desktop</h4>
<pre class="diff"><span>
</span></pre></div>
<a id="svnmergeinfo"></a>
<div class="modfile"><h4>Modified: svn:mergeinfo</h4></div>
<span class="cx">   + /users/devans/GNOME-3/stable/dports/gnome/gnome-desktop:108269-118645
</span><span class="cx">/users/devans/GNOME-3/unstable/dports/gnome/gnome-desktop:116416-118152
</span><a id="trunkdportsgnomegnomedesktopPortfile"></a>
<div class="modfile"><h4>Modified: trunk/dports/gnome/gnome-desktop/Portfile (118871 => 118872)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/dports/gnome/gnome-desktop/Portfile        2014-04-13 22:41:36 UTC (rev 118871)
+++ trunk/dports/gnome/gnome-desktop/Portfile        2014-04-13 23:00:41 UTC (rev 118872)
</span><span class="lines">@@ -4,7 +4,7 @@
</span><span class="cx"> PortSystem      1.0
</span><span class="cx"> 
</span><span class="cx"> name            gnome-desktop
</span><del>-version         3.10.2
</del><ins>+version         3.12.0
</ins><span class="cx"> set branch      [join [lrange [split ${version} .] 0 1] .]
</span><span class="cx"> maintainers     devans openmaintainer
</span><span class="cx"> categories      gnome
</span><span class="lines">@@ -24,8 +24,8 @@
</span><span class="cx"> 
</span><span class="cx"> use_xz          yes
</span><span class="cx"> 
</span><del>-checksums       rmd160  9d59c58c497eafa75a5ae7a38edaa740c8c77726 \
-                sha256  d4f5944aea5f2a8c7c5dc0e738bf07f293dfff81ddc55a53d661370bf24e4632
</del><ins>+checksums       rmd160  5941991cde23e0baf92c34e3f87ac4c927e02992 \
+                sha256  dea684a14ce4e737ccbb90b3ef1b56d6e3db500cc4c11d488bce1bd4c7b87e81
</ins><span class="cx"> 
</span><span class="cx"> depends_build   port:pkgconfig \
</span><span class="cx">                 port:intltool \
</span><span class="lines">@@ -41,7 +41,7 @@
</span><span class="cx">                 port:xorg-libXext \
</span><span class="cx">                 port:xorg-libXrandr \
</span><span class="cx">                 port:xkeyboard-config \
</span><del>-                port:xorg-libxkbfile 
</del><ins>+                port:xorg-libxkbfile
</ins><span class="cx"> 
</span><span class="cx"> patchfiles      patch-gnome-desktop-Makefile.am.diff \
</span><span class="cx">                 patch-libgnome-destktop-libgsystem.diff
</span></span></pre></div>
<a id="trunkdportsgnomegnomedesktopfilespatchgnomedesktopMakefileamdiff"></a>
<div class="modfile"><h4>Modified: trunk/dports/gnome/gnome-desktop/files/patch-gnome-desktop-Makefile.am.diff (118871 => 118872)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/dports/gnome/gnome-desktop/files/patch-gnome-desktop-Makefile.am.diff        2014-04-13 22:41:36 UTC (rev 118871)
+++ trunk/dports/gnome/gnome-desktop/files/patch-gnome-desktop-Makefile.am.diff        2014-04-13 23:00:41 UTC (rev 118872)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><del>---- libgnome-desktop/Makefile.am.orig        2013-10-04 15:18:41.000000000 -0700
-+++ libgnome-desktop/Makefile.am        2013-11-26 14:58:19.000000000 -0800
-@@ -79,8 +79,7 @@
</del><ins>+--- libgnome-desktop/Makefile.am.orig        2014-01-15 13:04:02.000000000 -0800
++++ libgnome-desktop/Makefile.am        2014-01-24 16:42:17.000000000 -0800
+@@ -78,8 +78,7 @@
</ins><span class="cx">          $(XLIB_LIBS)                \
</span><span class="cx">          $(LIBM)                        \
</span><span class="cx">          $(GNOME_DESKTOP_LIBS)        \
</span></span></pre></div>
<a id="trunkdportsgnomegnomedesktopfilespatchlibgnomedestktoplibgsystemdiff"></a>
<div class="modfile"><h4>Modified: trunk/dports/gnome/gnome-desktop/files/patch-libgnome-destktop-libgsystem.diff (118871 => 118872)</h4>
<pre class="diff"><span>
<span class="info">--- trunk/dports/gnome/gnome-desktop/files/patch-libgnome-destktop-libgsystem.diff        2014-04-13 22:41:36 UTC (rev 118871)
+++ trunk/dports/gnome/gnome-desktop/files/patch-libgnome-destktop-libgsystem.diff        2014-04-13 23:00:41 UTC (rev 118872)
</span><span class="lines">@@ -1,6 +1,6 @@
</span><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/Makefile-libgsystem.am libgnome-desktop/libgsystem/Makefile-libgsystem.am
</span><del>---- libgnome-desktop/libgsystem.orig/Makefile-libgsystem.am        2013-10-04 15:18:43.000000000 -0700
-+++ libgnome-desktop/libgsystem/Makefile-libgsystem.am        2014-01-11 18:24:46.000000000 -0800
</del><ins>+--- libgnome-desktop/libgsystem.orig/Makefile-libgsystem.am        2014-01-15 13:06:25.000000000 -0800
++++ libgnome-desktop/libgsystem/Makefile-libgsystem.am        2014-01-24 17:02:13.000000000 -0800
</ins><span class="cx"> @@ -35,6 +35,8 @@
</span><span class="cx">          $(libgsystem_srcpath)/gsystem-subprocess.h \
</span><span class="cx">          $(libgsystem_srcpath)/gsystem-subprocess.c \
</span><span class="lines">@@ -11,11 +11,11 @@
</span><span class="cx">  
</span><span class="cx">  libgsystem_la_CFLAGS = $(AM_CFLAGS) $(libgsystem_cflags)
</span><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/gsystem-file-utils.c libgnome-desktop/libgsystem/gsystem-file-utils.c
</span><del>---- libgnome-desktop/libgsystem.orig/gsystem-file-utils.c        2013-10-04 15:18:43.000000000 -0700
-+++ libgnome-desktop/libgsystem/gsystem-file-utils.c        2014-01-11 18:24:46.000000000 -0800
-@@ -38,6 +38,10 @@
- #include &lt;limits.h&gt;
- #include &lt;dirent.h&gt;
</del><ins>+--- libgnome-desktop/libgsystem.orig/gsystem-file-utils.c        2014-01-15 13:06:25.000000000 -0800
++++ libgnome-desktop/libgsystem/gsystem-file-utils.c        2014-01-24 17:02:13.000000000 -0800
+@@ -41,6 +41,10 @@
+ #include &lt;attr/xattr.h&gt;
+ #endif
</ins><span class="cx">  
</span><span class="cx"> +#ifdef __APPLE__
</span><span class="cx"> +#include &quot;gsystem-osx-compat.h&quot;
</span><span class="lines">@@ -24,7 +24,7 @@
</span><span class="cx">  static int
</span><span class="cx">  close_nointr (int fd)
</span><span class="cx">  {
</span><del>-@@ -444,12 +448,28 @@
</del><ins>+@@ -454,12 +458,28 @@
</ins><span class="cx">                       GError       **error)
</span><span class="cx">  {
</span><span class="cx">    /* Linux specific probably */
</span><span class="lines">@@ -53,9 +53,1639 @@
</span><span class="cx">    return TRUE;
</span><span class="cx">  }
</span><span class="cx">  
</span><ins>+diff -urN libgnome-desktop/libgsystem.orig/gsystem-file-utils.c.orig libgnome-desktop/libgsystem/gsystem-file-utils.c.orig
+--- libgnome-desktop/libgsystem.orig/gsystem-file-utils.c.orig        1969-12-31 16:00:00.000000000 -0800
++++ libgnome-desktop/libgsystem/gsystem-file-utils.c.orig        2014-01-15 13:06:25.000000000 -0800
+@@ -0,0 +1,1626 @@
++/* -*- mode: C; c-file-style: &quot;gnu&quot;; indent-tabs-mode: nil; -*-
++ *
++ * Copyright (C) 2012 William Jon McCann &lt;mccann@redhat.com&gt;
++ * Copyright (C) 2012 Colin Walters &lt;walters@verbum.org&gt;
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * 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, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include &quot;config.h&quot;
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE
++#endif
++
++#include &lt;string.h&gt;
++
++#define _GSYSTEM_NO_LOCAL_ALLOC
++#include &quot;libgsystem.h&quot;
++#include &quot;gsystem-glib-compat.h&quot;
++#include &lt;glib/gstdio.h&gt;
++#include &lt;gio/gunixinputstream.h&gt;
++#include &lt;gio/gfiledescriptorbased.h&gt;
++#include &lt;gio/gunixoutputstream.h&gt;
++#include &lt;glib-unix.h&gt;
++#include &lt;limits.h&gt;
++#include &lt;dirent.h&gt;
++#ifdef GSYSTEM_CONFIG_XATTRS
++#include &lt;attr/xattr.h&gt;
++#endif
++
++static int
++close_nointr (int fd)
++{
++  int res;
++  /* Note this is NOT actually a retry loop.
++   * See: https://bugzilla.gnome.org/show_bug.cgi?id=682819
++   */
++  res = close (fd);
++  /* Just ignore EINTR...on Linux, retrying is wrong. */
++  if (res == EINTR)
++    res = 0;
++  return res;
++}
++
++static void
++close_nointr_noerror (int fd)
++{
++  (void) close_nointr (fd);
++}
++
++static int
++open_nointr (const char *path, int flags, mode_t mode)
++{
++  int res;
++  do
++    res = open (path, flags, mode);
++  while (G_UNLIKELY (res == -1 &amp;&amp; errno == EINTR));
++  return res;
++}
++
++static inline void
++_set_error_from_errno (GError **error)
++{
++  int errsv = errno;
++  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                       g_strerror (errsv));
++}
++
++/**
++ * gs_file_openat_noatime:
++ * @dfd: File descriptor for directory
++ * @name: Pathname, relative to @dfd
++ * @ret_fd: (out): Returned file descriptor
++ * @cancellable: Cancellable
++ * @error: Error
++ *
++ * Wrapper for openat() using %O_RDONLY with %O_NOATIME if available.
++ */
++gboolean
++gs_file_openat_noatime (int            dfd,
++                        const char    *name,
++                        int           *ret_fd,
++                        GCancellable  *cancellable,
++                        GError       **error)
++{
++  int fd;
++
++#ifdef O_NOATIME
++  do
++    fd = openat (dfd, name, O_RDONLY | O_NOATIME, 0);
++  while (G_UNLIKELY (fd == -1 &amp;&amp; errno == EINTR));
++  /* Only the owner or superuser may use O_NOATIME; so we may get
++   * EPERM.  EINVAL may happen if the kernel is really old...
++   */
++  if (fd == -1 &amp;&amp; (errno == EPERM || errno == EINVAL))
++#endif
++    do
++      fd = openat (dfd, name, O_RDONLY, 0);
++    while (G_UNLIKELY (fd == -1 &amp;&amp; errno == EINTR));
++  
++  if (fd == -1)
++    {
++      _set_error_from_errno (error);
++      return FALSE;
++    }
++  else
++    {
++      *ret_fd = fd;
++      return TRUE;
++    }
++}
++
++/**
++ * gs_file_read_noatime:
++ * @file: a #GFile
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Like g_file_read(), but try to avoid updating the file's
++ * access time.  This should be used by background scanning
++ * components such as search indexers, antivirus programs, etc.
++ *
++ * Returns: (transfer full): A new input stream, or %NULL on error
++ */
++GInputStream *
++gs_file_read_noatime (GFile         *file,
++                      GCancellable  *cancellable,
++                      GError       **error)
++{
++  const char *path = NULL;
++  int fd;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return NULL;
++
++  path = gs_file_get_path_cached (file);
++  if (path == NULL)
++    {
++      char *uri;
++      uri = g_file_get_uri (file);
++      g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_NOENT,
++                   &quot;%s has no associated path&quot;, uri);
++      g_free (uri);
++      return NULL;
++    }
++
++  if (!gs_file_openat_noatime (AT_FDCWD, path, &amp;fd, cancellable, error))
++    return NULL;
++
++  return g_unix_input_stream_new (fd, TRUE);
++}
++
++/**
++ * gs_stream_fstat:
++ * @stream: A stream containing a Unix file descriptor
++ * @stbuf: Memory location to write stat buffer
++ * @cancellable:
++ * @error:
++ *
++ * Some streams created via libgsystem are #GUnixInputStream; these do
++ * not support e.g. g_file_input_stream_query_info().  This function
++ * allows dropping to the raw unix fstat() call for these types of
++ * streams, while still conveniently wrapped with the normal GLib
++ * handling of @cancellable and @error.
++ */
++gboolean
++gs_stream_fstat (GFileDescriptorBased *stream,
++                 struct stat          *stbuf,
++                 GCancellable         *cancellable,
++                 GError              **error)
++{
++  gboolean ret = FALSE;
++  int fd;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    goto out;
++
++  fd = g_file_descriptor_based_get_fd (stream);
++
++  if (fstat (fd, stbuf) == -1)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++}
++
++/**
++ * gs_file_map_noatime: (skip)
++ * @file: a #GFile
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Like g_mapped_file_new(), but try to avoid updating the file's
++ * access time.  This should be used by background scanning
++ * components such as search indexers, antivirus programs, etc.
++ *
++ * Returns: (transfer full): A new mapped file, or %NULL on error
++ */
++GMappedFile *
++gs_file_map_noatime (GFile         *file,
++                     GCancellable  *cancellable,
++                     GError       **error)
++{
++  const char *path;
++  int fd;
++  GMappedFile *ret;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return NULL;
++
++  path = gs_file_get_path_cached (file);
++  if (path == NULL)
++    return NULL;
++
++  if (!gs_file_openat_noatime (AT_FDCWD, path, &amp;fd, cancellable, error))
++    return NULL;
++  
++  ret = g_mapped_file_new_from_fd (fd, FALSE, error);
++  close_nointr_noerror (fd); /* Ignore errors - we always want to close */
++
++  return ret;
++}
++
++#if GLIB_CHECK_VERSION(2,34,0)
++/**
++ * gs_file_map_readonly:
++ * @file: a #GFile
++ * @cancellable:
++ * @error:
++ *
++ * Return a #GBytes which references a readonly view of the contents of
++ * @file.  This function uses #GMappedFile internally.
++ *
++ * Returns: (transfer full): a newly referenced #GBytes
++ */
++GBytes *
++gs_file_map_readonly (GFile         *file,
++                      GCancellable  *cancellable,
++                      GError       **error)
++{
++  GMappedFile *mfile;
++  GBytes *ret;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return NULL;
++
++  mfile = g_mapped_file_new (gs_file_get_path_cached (file), FALSE, error);
++  if (!mfile)
++    return NULL;
++
++  ret = g_mapped_file_get_bytes (mfile);
++  g_mapped_file_unref (mfile);
++  return ret;
++}
++#endif
++
++/**
++ * gs_file_sync_data:
++ * @file: a #GFile
++ * @cancellable:
++ * @error:
++ *
++ * Wraps the UNIX fsync() function (or fdatasync(), if available), which
++ * ensures that the data in @file is on non-volatile storage.
++ */
++gboolean
++gs_file_sync_data (GFile          *file,
++                   GCancellable   *cancellable,
++                   GError        **error)
++{
++  gboolean ret = FALSE;
++  int res;
++  int fd = -1; 
++
++  if (!gs_file_openat_noatime (AT_FDCWD, gs_file_get_path_cached (file), &amp;fd,
++                               cancellable, error))
++    goto out;
++
++  do
++    {
++#ifdef __linux
++      res = fdatasync (fd);
++#else
++      res = fsync (fd);
++#endif
++    }
++  while (G_UNLIKELY (res != 0 &amp;&amp; errno == EINTR));
++  if (res != 0)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  res = close_nointr (fd);
++  if (res != 0)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++  fd = -1;
++  
++  ret = TRUE;
++ out:
++  if (fd != -1)
++    close_nointr_noerror (fd);
++  return ret;
++}
++
++/**
++ * gs_file_create:
++ * @file: Path to non-existent file
++ * @mode: Unix access permissions
++ * @out_stream: (out) (transfer full) (allow-none): Newly created output, or %NULL
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Like g_file_create(), except this function allows specifying the
++ * access mode.  This allows atomically creating private files.
++ */
++gboolean
++gs_file_create (GFile          *file,
++                int             mode,
++                GOutputStream **out_stream,
++                GCancellable   *cancellable,
++                GError        **error)
++{
++  gboolean ret = FALSE;
++  int fd;
++  GOutputStream *ret_stream = NULL;
++
++  fd = open_nointr (gs_file_get_path_cached (file), O_WRONLY | O_CREAT | O_EXCL, mode);
++  if (fd &lt; 0)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  if (fchmod (fd, mode) &lt; 0)
++    {
++      close (fd);
++      _set_error_from_errno (error);
++      goto out;
++    }
++  
++  ret_stream = g_unix_output_stream_new (fd, TRUE);
++  
++  ret = TRUE;
++  gs_transfer_out_value (out_stream, &amp;ret_stream);
++ out:
++  g_clear_object (&amp;ret_stream);
++  return ret;
++}
++
++static const char *
++get_default_tmp_prefix (void)
++{
++  static char *tmpprefix = NULL;
++
++  if (g_once_init_enter (&amp;tmpprefix))
++    {
++      const char *prgname = g_get_prgname ();
++      const char *p;
++      char *prefix;
++      char *iter;
++
++      if (prgname)
++        {
++          p = strrchr (prgname, '/');
++          if (p)
++            prgname = p + 1;
++        }
++      else
++        prgname = &quot;&quot;;
++          
++      prefix = g_strdup_printf (&quot;tmp-%s%u-&quot;, prgname, getuid ());
++      for (iter = prefix; *iter; iter++)
++        {
++          char c = *iter;
++          if (c == ' ')
++            *iter = '_';
++        }
++      
++      g_once_init_leave (&amp;tmpprefix, prefix);
++    }
++
++  return tmpprefix;
++}
++
++/**
++ * gs_fileutil_gen_tmp_name:
++ * @prefix: (allow-none): String prepended to the result
++ * @suffix: (allow-none): String suffixed to the result
++ *
++ * Generate a name suitable for use as a temporary file.  This
++ * function does no I/O; it is not guaranteed that a file with that
++ * name does not exist.
++ */
++char *
++gs_fileutil_gen_tmp_name (const char *prefix,
++                          const char *suffix)
++{
++  static const char table[] = &quot;ABCEDEFGHIJKLMNOPQRSTUVWXYZabcedefghijklmnopqrstuvwxyz0123456789&quot;;
++  GString *str = g_string_new (&quot;&quot;);
++  guint i;
++
++  if (!prefix)
++    prefix = get_default_tmp_prefix ();
++  if (!suffix)
++    suffix = &quot;tmp&quot;;
++
++  g_string_append (str, prefix);
++  for (i = 0; i &lt; 8; i++)
++    {
++      int offset = g_random_int_range (0, sizeof (table) - 1);
++      g_string_append_c (str, (guint8)table[offset]);
++    }
++  g_string_append_c (str, '.');
++  g_string_append (str, suffix);
++
++  return g_string_free (str, FALSE);
++}
++
++/**
++ * gs_file_open_dir_fd:
++ * @path: Directory name
++ * @out_fd: (out): File descriptor for directory
++ * @cancellable: Cancellable
++ * @error: Error
++ *
++ * On success, sets @out_fd to a file descriptor for the directory
++ * that can be used with UNIX functions such as openat().
++ */
++gboolean
++gs_file_open_dir_fd (GFile         *path,
++                     int           *out_fd,
++                     GCancellable  *cancellable,
++                     GError       **error)
++{
++  /* Linux specific probably */
++  *out_fd = open (gs_file_get_path_cached (path), O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC);
++  if (*out_fd == -1)
++    {
++      _set_error_from_errno (error);
++      return FALSE;
++    }
++  return TRUE;
++}
++
++/**
++ * gs_file_open_in_tmpdir_at:
++ * @tmpdir_fd: Directory to place temporary file
++ * @mode: Default mode (will be affected by umask)
++ * @out_name: (out) (transfer full): Newly created file name
++ * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
++ * @cancellable:
++ * @error:
++ *
++ * Like g_file_open_tmp(), except the file will be created in the
++ * provided @tmpdir, and allows specification of the Unix @mode, which
++ * means private files may be created.  Return values will be stored
++ * in @out_name, and optionally @out_stream.
++ */
++gboolean
++gs_file_open_in_tmpdir_at (int                tmpdir_fd,
++                           int                mode,
++                           char             **out_name,
++                           GOutputStream    **out_stream,
++                           GCancellable      *cancellable,
++                           GError           **error)
++{
++  gboolean ret = FALSE;
++  const int max_attempts = 128;
++  int i;
++  char *tmp_name = NULL;
++  int fd;
++
++  /* 128 attempts seems reasonable... */
++  for (i = 0; i &lt; max_attempts; i++)
++    {
++      g_free (tmp_name);
++      tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL);
++
++      do
++        fd = openat (tmpdir_fd, tmp_name, O_WRONLY | O_CREAT | O_EXCL, mode);
++      while (fd == -1 &amp;&amp; errno == EINTR);
++      if (fd &lt; 0 &amp;&amp; errno != EEXIST)
++        {
++          _set_error_from_errno (error);
++          goto out;
++        }
++      else if (fd != -1)
++        break;
++    }
++  if (i == max_attempts)
++    {
++      g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED,
++                   &quot;Exhausted attempts to open temporary file&quot;);
++      goto out;
++    }
++
++  ret = TRUE;
++  gs_transfer_out_value (out_name, &amp;tmp_name);
++  if (out_stream)
++    *out_stream = g_unix_output_stream_new (fd, TRUE);
++  else
++    (void) close (fd);
++ out:
++  g_free (tmp_name);
++  return ret;
++}
++
++/**
++ * gs_file_open_in_tmpdir:
++ * @tmpdir: Directory to place temporary file
++ * @mode: Default mode (will be affected by umask)
++ * @out_file: (out) (transfer full): Newly created file path
++ * @out_stream: (out) (transfer full) (allow-none): Newly created output stream
++ * @cancellable:
++ * @error:
++ *
++ * Like g_file_open_tmp(), except the file will be created in the
++ * provided @tmpdir, and allows specification of the Unix @mode, which
++ * means private files may be created.  Return values will be stored
++ * in @out_file, and optionally @out_stream.
++ */
++gboolean
++gs_file_open_in_tmpdir (GFile             *tmpdir,
++                        int                mode,
++                        GFile            **out_file,
++                        GOutputStream    **out_stream,
++                        GCancellable      *cancellable,
++                        GError           **error)
++{
++  gboolean ret = FALSE;
++  DIR *d = NULL;
++  int dfd = -1;
++  char *tmp_name = NULL;
++  GOutputStream *ret_stream = NULL;
++
++  d = opendir (gs_file_get_path_cached (tmpdir));
++  if (!d)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++  dfd = dirfd (d);
++
++  if (!gs_file_open_in_tmpdir_at (dfd, mode, &amp;tmp_name,
++                                  out_stream ? &amp;ret_stream : NULL,
++                                  cancellable, error))
++    goto out;
++ 
++  ret = TRUE;
++  *out_file = g_file_get_child (tmpdir, tmp_name);
++  gs_transfer_out_value (out_stream, &amp;ret_stream);
++ out:
++  if (d) (void) closedir (d);
++  g_clear_object (&amp;ret_stream);
++  g_free (tmp_name);
++  return ret;
++}
++
++static gboolean
++linkcopy_internal_attempt (GFile          *src,
++                          GFile          *dest,
++                          GFile          *dest_parent,
++                          GFileCopyFlags  flags,
++                          gboolean        sync_data,
++                          gboolean        enable_guestfs_fuse_workaround,
++                          gboolean       *out_try_again,
++                          GCancellable   *cancellable,
++                          GError        **error)
++{
++  gboolean ret = FALSE;
++  int res;
++  char *tmp_name = NULL;
++  GFile *tmp_dest = NULL;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    goto out;
++
++  tmp_name = gs_fileutil_gen_tmp_name (NULL, NULL);
++  tmp_dest = g_file_get_child (dest_parent, tmp_name);
++
++  res = link (gs_file_get_path_cached (src), gs_file_get_path_cached (tmp_dest));
++  if (res == -1)
++    {
++      if (errno == EEXIST)
++        {
++          /* Nothing, fall through */
++          *out_try_again = TRUE;
++          ret = TRUE;
++          goto out;
++        }
++      else if (errno == EXDEV || errno == EMLINK || errno == EPERM
++               || (enable_guestfs_fuse_workaround &amp;&amp; errno == ENOENT))
++        {
++          if (!g_file_copy (src, tmp_dest, flags,
++                            cancellable, NULL, NULL, error))
++            goto out;
++        }
++      else
++        {
++          _set_error_from_errno (error);
++          goto out;
++        }
++    }
++      
++  if (sync_data)
++    {
++      /* Now, we need to fsync */
++      if (!gs_file_sync_data (tmp_dest, cancellable, error))
++        goto out;
++    }
++
++  if (!gs_file_rename (tmp_dest, dest, cancellable, error))
++    goto out;
++
++  ret = TRUE;
++  *out_try_again = FALSE;
++ out:
++  g_clear_pointer (&amp;tmp_name, g_free);
++  g_clear_object (&amp;tmp_dest);
++  return ret;
++}
++
++static gboolean
++linkcopy_internal (GFile          *src,
++                   GFile          *dest,
++                   GFileCopyFlags  flags,
++                   gboolean        sync_data,
++                   GCancellable   *cancellable,
++                   GError        **error)
++{
++  gboolean ret = FALSE;
++  gboolean dest_exists;
++  int i;
++  gboolean enable_guestfs_fuse_workaround;
++  struct stat src_stat;
++  struct stat dest_stat;
++  GFile *dest_parent = NULL;
++
++  flags |= G_FILE_COPY_NOFOLLOW_SYMLINKS;
++
++  g_return_val_if_fail ((flags &amp; (G_FILE_COPY_BACKUP | G_FILE_COPY_TARGET_DEFAULT_PERMS)) == 0, FALSE);
++
++  dest_parent = g_file_get_parent (dest);
++
++  if (lstat (gs_file_get_path_cached (src), &amp;src_stat) == -1)
++    {
++      int errsv = errno;
++      g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errno),
++                           g_strerror (errsv));
++      goto out;
++    }
++
++  if (lstat (gs_file_get_path_cached (dest), &amp;dest_stat) == -1)
++    dest_exists = FALSE;
++  else
++    dest_exists = TRUE;
++  
++  if (((flags &amp; G_FILE_COPY_OVERWRITE) == 0) &amp;&amp; dest_exists)
++    {
++      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_EXISTS,
++                           &quot;File exists&quot;);
++      goto out;
++    }
++
++  /* Work around the behavior of link() where it's a no-op if src and
++   * dest are the same.
++   */
++  if (dest_exists &amp;&amp;
++      src_stat.st_dev == dest_stat.st_dev &amp;&amp;
++      src_stat.st_ino == dest_stat.st_ino)
++    {
++      ret = TRUE;
++      goto out;
++    }
++
++  enable_guestfs_fuse_workaround = getenv (&quot;LIBGSYSTEM_ENABLE_GUESTFS_FUSE_WORKAROUND&quot;) != NULL;
++
++  /* 128 attempts seems reasonable... */
++  for (i = 0; i &lt; 128; i++)
++    {
++      gboolean tryagain = FALSE;
++
++      if (!linkcopy_internal_attempt (src, dest, dest_parent,
++                                      flags, sync_data,
++                                      enable_guestfs_fuse_workaround,
++                                      &amp;tryagain,
++                                      cancellable, error))
++        goto out;
++
++      if (!tryagain)
++        break;
++    }
++
++  ret = TRUE;
++ out:
++  g_clear_object (&amp;dest_parent);
++  return ret;
++
++}
++
++/**
++ * gs_file_linkcopy:
++ * @src: Source file
++ * @dest: Destination file
++ * @flags: flags
++ * @cancellable:
++ * @error:
++ *
++ * First tries to use the UNIX link() call, but if the files are on
++ * separate devices, fall back to copying via g_file_copy().
++ *
++ * The given @flags have different semantics than those documented
++ * when hardlinking is used.  Specifically, both
++ * #G_FILE_COPY_TARGET_DEFAULT_PERMS and #G_FILE_COPY_BACKUP are not
++ * supported.  #G_FILE_COPY_NOFOLLOW_SYMLINKS treated as if it was
++ * always given - if you want to follow symbolic links, you will need
++ * to resolve them manually.
++ *
++ * Beware - do not use this function if @src may be modified, and it's
++ * undesirable for the changes to also be reflected in @dest.  The
++ * best use of this function is in the case where @src and @dest are
++ * read-only, or where @src is a temporary file, and you want to put
++ * it in the final place.
++ */
++gboolean
++gs_file_linkcopy (GFile          *src,
++                  GFile          *dest,
++                  GFileCopyFlags  flags,
++                  GCancellable   *cancellable,
++                  GError        **error)
++{
++  return linkcopy_internal (src, dest, flags, FALSE, cancellable, error);
++}
++
++/**
++ * gs_file_linkcopy_sync_data:
++ * @src: Source file
++ * @dest: Destination file
++ * @flags: flags
++ * @cancellable:
++ * @error:
++ *
++ * This function is similar to gs_file_linkcopy(), except it also uses
++ * gs_file_sync_data() to ensure that @dest is in stable storage
++ * before it is moved into place.
++ */
++gboolean
++gs_file_linkcopy_sync_data (GFile          *src,
++                            GFile          *dest,
++                            GFileCopyFlags  flags,
++                            GCancellable   *cancellable,
++                            GError        **error)
++{
++  return linkcopy_internal (src, dest, flags, TRUE, cancellable, error);
++}
++
++static char *
++gs_file_get_target_path (GFile *file)
++{
++  GFileInfo *info;
++  const char *target;
++  char *path;
++
++  info = g_file_query_info (file, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI, G_FILE_QUERY_INFO_NONE, NULL, NULL);
++  if (info == NULL)
++    return NULL;
++  target = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
++  path = g_filename_from_uri (target, NULL, NULL);
++  g_object_unref (info);
++
++  return path;
++}
++
++G_LOCK_DEFINE_STATIC (pathname_cache);
++
++/**
++ * gs_file_get_path_cached:
++ *
++ * Like g_file_get_path(), but returns a constant copy so callers
++ * don't need to free the result.
++ */
++const char *
++gs_file_get_path_cached (GFile *file)
++{
++  const char *path;
++  static GQuark _file_path_quark = 0;
++
++  if (G_UNLIKELY (_file_path_quark) == 0)
++    _file_path_quark = g_quark_from_static_string (&quot;gsystem-file-path&quot;);
++
++  G_LOCK (pathname_cache);
++
++  path = g_object_get_qdata ((GObject*)file, _file_path_quark);
++  if (!path)
++    {
++      if (g_file_has_uri_scheme (file, &quot;trash&quot;) ||
++          g_file_has_uri_scheme (file, &quot;recent&quot;))
++        path = gs_file_get_target_path (file);
++      else
++        path = g_file_get_path (file);
++      if (path == NULL)
++        {
++          G_UNLOCK (pathname_cache);
++          return NULL;
++        }
++      g_object_set_qdata_full ((GObject*)file, _file_path_quark, (char*)path, (GDestroyNotify)g_free);
++    }
++
++  G_UNLOCK (pathname_cache);
++
++  return path;
++}
++
++/**
++ * gs_file_get_basename_cached:
++ *
++ * Like g_file_get_basename(), but returns a constant copy so callers
++ * don't need to free the result.
++ */
++const char *
++gs_file_get_basename_cached (GFile *file)
++{
++  const char *name;
++  static GQuark _file_name_quark = 0;
++
++  if (G_UNLIKELY (_file_name_quark) == 0)
++    _file_name_quark = g_quark_from_static_string (&quot;gsystem-file-name&quot;);
++
++  G_LOCK (pathname_cache);
++
++  name = g_object_get_qdata ((GObject*)file, _file_name_quark);
++  if (!name)
++    {
++      name = g_file_get_basename (file);
++      g_object_set_qdata_full ((GObject*)file, _file_name_quark, (char*)name, (GDestroyNotify)g_free);
++    }
++
++  G_UNLOCK (pathname_cache);
++
++  return name;
++}
++
++/**
++ * gs_file_enumerator_iterate:
++ * @direnum: an open #GFileEnumerator
++ * @out_info: (out) (transfer none) (allow-none): Output location for the next #GFileInfo
++ * @out_child: (out) (transfer none) (allow-none): Output location for the next #GFile, or %NULL
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * This is a version of g_file_enumerator_next_file() that's easier to
++ * use correctly from C programs.  With g_file_enumerator_next_file(),
++ * the gboolean return value signifies &quot;end of iteration or error&quot;, which
++ * requires allocation of a temporary #GError.
++ *
++ * In contrast, with this function, a %FALSE return from
++ * gs_file_enumerator_iterate() &lt;emphasis&gt;always&lt;/emphasis&gt; means
++ * &quot;error&quot;.  End of iteration is signaled by @out_info being %NULL.
++ *
++ * Another crucial difference is that the references for @out_info and
++ * @out_child are owned by @direnum (they are cached as hidden
++ * properties).  You must not unref them in your own code.  This makes
++ * memory management significantly easier for C code in combination
++ * with loops.
++ *
++ * Finally, this function optionally allows retrieving a #GFile as
++ * well.
++ *
++ * The code pattern for correctly using gs_file_enumerator_iterate() from C
++ * is:
++ *
++ * |[
++ * direnum = g_file_enumerate_children (file, ...);
++ * while (TRUE)
++ *   {
++ *     GFileInfo *info;
++ *     if (!gs_file_enumerator_iterate (direnum, &amp;info, NULL, cancellable, error))
++ *       goto out;
++ *     if (!info)
++ *       break;
++ *     ... do stuff with &quot;info&quot;; do not unref it! ...
++ *   }
++ * 
++ * out:
++ *   g_object_unref (direnum); // Note: frees the last @info
++ * ]|
++ */
++gboolean
++gs_file_enumerator_iterate (GFileEnumerator  *direnum,
++                            GFileInfo       **out_info,
++                            GFile           **out_child,
++                            GCancellable     *cancellable,
++                            GError          **error)
++{
++  gboolean ret = FALSE;
++  GError *temp_error = NULL;
++
++  static GQuark cached_info_quark;
++  static GQuark cached_child_quark;
++  static gsize quarks_initialized;
++
++  g_return_val_if_fail (direnum != NULL, FALSE);
++  g_return_val_if_fail (out_info != NULL, FALSE);
++
++  if (g_once_init_enter (&amp;quarks_initialized))
++    {
++      cached_info_quark = g_quark_from_static_string (&quot;gsystem-cached-info&quot;);
++      cached_child_quark = g_quark_from_static_string (&quot;gsystem-cached-child&quot;);
++      g_once_init_leave (&amp;quarks_initialized, 1);
++    }
++
++  
++  *out_info = g_file_enumerator_next_file (direnum, cancellable, &amp;temp_error);
++  if (out_child)
++    *out_child = NULL;
++  if (temp_error != NULL)
++    {
++      g_propagate_error (error, temp_error);
++      goto out;
++    }
++  else if (*out_info != NULL)
++    {
++      g_object_set_qdata_full ((GObject*)direnum, cached_info_quark, *out_info, (GDestroyNotify)g_object_unref);
++      if (out_child != NULL)
++        {
++          const char *name = g_file_info_get_name (*out_info);
++          *out_child = g_file_get_child (g_file_enumerator_get_container (direnum), name);
++          g_object_set_qdata_full ((GObject*)direnum, cached_child_quark, *out_child, (GDestroyNotify)g_object_unref);
++        }
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++}
++
++/**
++ * gs_file_rename:
++ * @from: Current path
++ * @to: New path
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * This function wraps the raw Unix function rename().
++ *
++ * Returns: %TRUE on success, %FALSE on error
++ */
++gboolean
++gs_file_rename (GFile          *from,
++                GFile          *to,
++                GCancellable   *cancellable,
++                GError        **error)
++{
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return FALSE;
++
++  if (rename (gs_file_get_path_cached (from),
++              gs_file_get_path_cached (to)) &lt; 0)
++    {
++      _set_error_from_errno (error);
++      return FALSE;
++    }
++  return TRUE;
++}
++
++/**
++ * gs_file_unlink:
++ * @path: Path to file
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Like g_file_delete(), except this function does not follow Unix
++ * symbolic links, and will delete a symbolic link even if it's
++ * pointing to a nonexistent file.  In other words, this function
++ * merely wraps the raw Unix function unlink().
++ *
++ * Returns: %TRUE on success, %FALSE on error
++ */
++gboolean
++gs_file_unlink (GFile          *path,
++                GCancellable   *cancellable,
++                GError        **error)
++{
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return FALSE;
++
++  if (unlink (gs_file_get_path_cached (path)) &lt; 0)
++    {
++      _set_error_from_errno (error);
++      return FALSE;
++    }
++  return TRUE;
++}
++
++static gboolean
++chown_internal (GFile          *path,
++                gboolean        dereference_links,
++                guint32         owner,
++                guint32         group,
++                GCancellable   *cancellable,
++                GError        **error)
++{
++  gboolean ret = FALSE;
++  int res;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return FALSE;
++
++  do
++    if (dereference_links)
++      res = chown (gs_file_get_path_cached (path), owner, group);
++    else
++      res = lchown (gs_file_get_path_cached (path), owner, group);
++  while (G_UNLIKELY (res != 0 &amp;&amp; errno == EINTR));
++
++  if (res &lt; 0)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++}
++
++/**
++ * gs_file_chown:
++ * @path: Path to file
++ * @owner: UNIX owner
++ * @group: UNIX group
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Merely wraps UNIX chown().
++ *
++ * Returns: %TRUE on success, %FALSE on error
++ */
++gboolean
++gs_file_chown (GFile          *path,
++               guint32         owner,
++               guint32         group,
++               GCancellable   *cancellable,
++               GError        **error)
++{
++  return chown_internal (path, TRUE, owner, group, cancellable, error);
++}
++
++/**
++ * gs_file_lchown:
++ * @path: Path to file
++ * @owner: UNIX owner
++ * @group: UNIX group
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Merely wraps UNIX lchown().
++ *
++ * Returns: %TRUE on success, %FALSE on error
++ */
++gboolean
++gs_file_lchown (GFile          *path,
++                guint32         owner,
++                guint32         group,
++                GCancellable   *cancellable,
++                GError        **error)
++{
++  return chown_internal (path, FALSE, owner, group, cancellable, error);
++}
++
++/**
++ * gs_file_chmod:
++ * @path: Path to file
++ * @mode: UNIX mode
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Merely wraps UNIX chmod().
++ *
++ * Returns: %TRUE on success, %FALSE on error
++ */
++gboolean
++gs_file_chmod (GFile          *path,
++               guint           mode,
++               GCancellable   *cancellable,
++               GError        **error)
++{
++  gboolean ret = FALSE;
++  int res;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return FALSE;
++
++  do
++    res = chmod (gs_file_get_path_cached (path), mode);
++  while (G_UNLIKELY (res != 0 &amp;&amp; errno == EINTR));
++
++  if (res &lt; 0)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++}
++
++/**
++ * gs_file_ensure_directory:
++ * @dir: Path to create as directory
++ * @with_parents: Also create parent directories
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Like g_file_make_directory(), except does not throw an error if the
++ * directory already exists.
++ */
++gboolean
++gs_file_ensure_directory (GFile         *dir,
++                          gboolean       with_parents, 
++                          GCancellable  *cancellable,
++                          GError       **error)
++{
++  gboolean ret = FALSE;
++  GError *temp_error = NULL;
++  GFile *parent = NULL;
++
++  if (!g_file_make_directory (dir, cancellable, &amp;temp_error))
++    {
++      if (with_parents &amp;&amp;
++          g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND))
++        {
++          g_clear_error (&amp;temp_error);
++
++          parent = g_file_get_parent (dir);
++          if (parent)
++            {
++              if (!gs_file_ensure_directory (parent, TRUE, cancellable, error))
++                goto out;
++            }
++          if (!gs_file_ensure_directory (dir, FALSE, cancellable, error))
++            goto out;
++        }
++      else if (!g_error_matches (temp_error, G_IO_ERROR, G_IO_ERROR_EXISTS))
++        {
++          g_propagate_error (error, temp_error);
++          goto out;
++        }
++      else
++        g_clear_error (&amp;temp_error);
++    }
++
++  ret = TRUE;
++ out:
++  g_clear_object (&amp;parent);
++  return ret;
++}
++
++/**
++ * gs_file_ensure_directory_mode:
++ * @dir: Path to create as directory
++ * @mode: Create directory with these permissions
++ * @cancellable: a #GCancellable
++ * @error: a #GError
++ *
++ * Wraps UNIX mkdir() function with support for @cancellable, and
++ * uses @error instead of errno.
++ */
++gboolean
++gs_file_ensure_directory_mode (GFile         *dir,
++                               guint          mode,
++                               GCancellable  *cancellable,
++                               GError       **error)
++{
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    return FALSE;
++
++  if (mkdir (gs_file_get_path_cached (dir), mode) == -1 &amp;&amp; errno != EEXIST)
++    {
++      _set_error_from_errno (error);
++      return FALSE;
++    }
++  return TRUE;
++}
++
++/**
++ * gs_file_load_contents_utf8:
++ * @file: Path to file whose contents must be UTF-8
++ * @cancellable:
++ * @error:
++ *
++ * Like g_file_load_contents(), except validates the contents are
++ * UTF-8.
++ */
++gchar *
++gs_file_load_contents_utf8 (GFile         *file,
++                            GCancellable  *cancellable,
++                            GError       **error)
++{
++  gboolean ret = FALSE;
++  gsize len;
++  char *ret_contents = NULL;
++
++  if (!g_file_load_contents (file, cancellable, &amp;ret_contents, &amp;len,
++                             NULL, error))
++    goto out;
++  if (!g_utf8_validate (ret_contents, len, NULL))
++    {
++      g_set_error (error,
++                   G_IO_ERROR,
++                   G_IO_ERROR_INVALID_DATA,
++                   &quot;Invalid UTF-8&quot;);
++      goto out;
++    }
++
++  ret = TRUE;
++ out:
++  if (!ret)
++    {
++      g_free (ret_contents);
++      return NULL;
++    }
++  return ret_contents;
++}
++
++static int
++path_common_directory (char *one,
++                       char *two)
++{
++  int dir_index = 0;
++  int i = 0;
++
++  while (*one &amp;&amp; *two)
++    {
++      if (*one != *two)
++        break;
++      if (*one == '/')
++        dir_index = i + 1;
++
++      one++;
++      two++;
++      i++;
++    }
++
++  return dir_index;
++}
++
++/**
++ * gs_file_get_relpath:
++ * @one: The first #GFile
++ * @two: The second #GFile
++ *
++ * Like gs_file_get_relative_path(), but does not mandate that
++ * the two files have any parent in common. This function will
++ * instead insert &quot;../&quot; where appropriate.
++ *
++ * Returns: (transfer full): The relative path between the two.
++ */
++gchar *
++gs_file_get_relpath (GFile *one,
++                     GFile *two)
++{
++  gchar *simple_path;
++  gchar *one_path, *one_suffix;
++  gchar *two_path, *two_suffix;
++  GString *path;
++  int i;
++
++  simple_path = g_file_get_relative_path (one, two);
++  if (simple_path)
++    return simple_path;
++
++  one_path = g_file_get_path (one);
++  two_path = g_file_get_path (two);
++
++  i = path_common_directory (one_path, two_path);
++  one_suffix = one_path + i;
++  two_suffix = two_path + i;
++
++  path = g_string_new (&quot;&quot;);
++
++  /* For every leftover path segment one has, append &quot;../&quot; so
++   * that we reach the same directory. */
++  while (*one_suffix)
++    {
++      g_string_append (path, &quot;../&quot;);
++      one_suffix = strchr (one_suffix, '/');
++      if (one_suffix == NULL)
++        break;
++      one_suffix++;
++    }
++
++  /* And now append the leftover stuff on two's side. */
++  g_string_append (path, two_suffix);
++
++  g_free (one_path);
++  g_free (two_path);
++
++  return g_string_free (path, FALSE);
++}
++
++/**
++ * gs_file_realpath:
++ * @file: A #GFile
++ *
++ * Return a #GFile that contains the same path with symlinks
++ * followed. That is, it's a #GFile whose path is the result
++ * of calling realpath() on @file.
++ *
++ * Returns: (allow-none) (transfer full): A new #GFile or %NULL if @file is invalid
++ */
++GFile *
++gs_file_realpath (GFile *file)
++{
++  gchar *path;
++  gchar path_real[PATH_MAX];
++
++  path = g_file_get_path (file);
++
++  if (realpath ((const char *) path, path_real) == NULL)
++    {
++      g_free (path);
++      return NULL;
++    }
++
++  g_free (path);
++  return g_file_new_for_path (path_real);
++}
++
++#ifdef GSYSTEM_CONFIG_XATTRS
++static char *
++canonicalize_xattrs (char    *xattr_string,
++                     size_t   len)
++{
++  char *p;
++  GSList *xattrs = NULL;
++  GSList *iter;
++  GString *result;
++
++  result = g_string_new (0);
++
++  p = xattr_string;
++  while (p &lt; xattr_string+len)
++    {
++      xattrs = g_slist_prepend (xattrs, p);
++      p += strlen (p) + 1;
++    }
++
++  xattrs = g_slist_sort (xattrs, (GCompareFunc) strcmp);
++  for (iter = xattrs; iter; iter = iter-&gt;next) {
++    g_string_append (result, iter-&gt;data);
++    g_string_append_c (result, '\0');
++  }
++
++  g_slist_free (xattrs);
++  return g_string_free (result, FALSE);
++}
++
++static GVariant *
++variant_new_ay_bytes (GBytes *bytes)
++{
++  gsize size;
++  gconstpointer data;
++  data = g_bytes_get_data (bytes, &amp;size);
++  g_bytes_ref (bytes);
++  return g_variant_new_from_data (G_VARIANT_TYPE (&quot;ay&quot;), data, size,
++                                  TRUE, (GDestroyNotify)g_bytes_unref, bytes);
++}
++
++static gboolean
++read_xattr_name_array (const char *path,
++                       const char *xattrs,
++                       size_t      len,
++                       GVariantBuilder *builder,
++                       GError  **error)
++{
++  gboolean ret = FALSE;
++  const char *p;
++
++  p = xattrs;
++  while (p &lt; xattrs+len)
++    {
++      ssize_t bytes_read;
++      char *buf;
++      GBytes *bytes = NULL;
++
++      bytes_read = lgetxattr (path, p, NULL, 0);
++      if (bytes_read &lt; 0)
++        {
++          _set_error_from_errno (error);
++          g_prefix_error (error, &quot;lgetxattr (%s, %s) failed: &quot;, path, p);
++          goto out;
++        }
++      if (bytes_read == 0)
++        continue;
++
++      buf = g_malloc (bytes_read);
++      bytes = g_bytes_new_take (buf, bytes_read);
++      if (lgetxattr (path, p, buf, bytes_read) &lt; 0)
++        {
++          g_bytes_unref (bytes);
++          _set_error_from_errno (error);
++          g_prefix_error (error, &quot;lgetxattr (%s, %s) failed: &quot;, path, p);
++          goto out;
++        }
++      
++      g_variant_builder_add (builder, &quot;(@ay@ay)&quot;,
++                             g_variant_new_bytestring (p),
++                             variant_new_ay_bytes (bytes));
++
++      p = p + strlen (p) + 1;
++      g_bytes_unref (bytes);
++    }
++  
++  ret = TRUE;
++ out:
++  return ret;
++}
++
++#endif
++
++/**
++ * gs_file_get_all_xattrs:
++ * @f: a #GFile
++ * @out_xattrs: (out): A new #GVariant containing the extended attributes
++ * @cancellable: Cancellable
++ * @error: Error
++ *
++ * Read all extended attributes of @f in a canonical sorted order, and
++ * set @out_xattrs with the result.
++ *
++ * If the filesystem does not support extended attributes, @out_xattrs
++ * will have 0 elements, and this function will return successfully.
++ */
++gboolean
++gs_file_get_all_xattrs (GFile         *f,
++                        GVariant     **out_xattrs,
++                        GCancellable  *cancellable,
++                        GError       **error)
++{
++  gboolean ret = FALSE;
++  const char *path;
++  ssize_t bytes_read;
++  GVariant *ret_xattrs = NULL;
++  char *xattr_names = NULL;
++  char *xattr_names_canonical = NULL;
++  GVariantBuilder builder;
++  gboolean builder_initialized = FALSE;
++
++  path = gs_file_get_path_cached (f);
++
++  g_variant_builder_init (&amp;builder, G_VARIANT_TYPE (&quot;a(ayay)&quot;));
++  builder_initialized = TRUE;
++
++#ifdef GSYSTEM_CONFIG_XATTRS
++  bytes_read = llistxattr (path, NULL, 0);
++
++  if (bytes_read &lt; 0)
++    {
++      if (errno != ENOTSUP)
++        {
++          _set_error_from_errno (error);
++          g_prefix_error (error, &quot;llistxattr (%s) failed: &quot;, path);
++          goto out;
++        }
++    }
++  else if (bytes_read &gt; 0)
++    {
++      xattr_names = g_malloc (bytes_read);
++      if (llistxattr (path, xattr_names, bytes_read) &lt; 0)
++        {
++          _set_error_from_errno (error);
++          g_prefix_error (error, &quot;llistxattr (%s) failed: &quot;, path);
++          goto out;
++        }
++      xattr_names_canonical = canonicalize_xattrs (xattr_names, bytes_read);
++      
++      if (!read_xattr_name_array (path, xattr_names_canonical, bytes_read, &amp;builder, error))
++        goto out;
++    }
++
++#endif
++
++  ret_xattrs = g_variant_builder_end (&amp;builder);
++  g_variant_ref_sink (ret_xattrs);
++  
++  ret = TRUE;
++  gs_transfer_out_value (out_xattrs, &amp;ret_xattrs);
++ out:
++  g_clear_pointer (&amp;ret_xattrs, g_variant_unref);
++  g_clear_pointer (&amp;xattr_names, g_free);
++  g_clear_pointer (&amp;xattr_names_canonical, g_free);
++  if (!builder_initialized)
++    g_variant_builder_clear (&amp;builder);
++  return ret;
++}
++
++/**
++ * gs_fd_set_all_xattrs:
++ * @fd: File descriptor
++ * @xattrs: Extended attributes
++ * @cancellable: Cancellable
++ * @error: Error
++ *
++ * For each attribute in @xattrs, set its value on the file or
++ * directory referred to by @fd.  This function does not remove any
++ * attributes not in @xattrs.
++ */
++gboolean
++gs_fd_set_all_xattrs (int            fd,
++                      GVariant      *xattrs,
++                      GCancellable  *cancellable,
++                      GError       **error)
++{
++#ifdef GSYSTEM_CONFIG_XATTRS
++  gboolean ret = FALSE;
++  int i, n;
++
++  n = g_variant_n_children (xattrs);
++  for (i = 0; i &lt; n; i++)
++    {
++      const guint8* name;
++      const guint8* value_data;
++      GVariant *value = NULL;
++      gsize value_len;
++      int res;
++
++      g_variant_get_child (xattrs, i, &quot;(^&amp;ay@ay)&quot;,
++                           &amp;name, &amp;value);
++      value_data = g_variant_get_fixed_array (value, &amp;value_len, 1);
++      
++      do
++        res = fsetxattr (fd, (char*)name, (char*)value_data, value_len, 0);
++      while (G_UNLIKELY (res == -1 &amp;&amp; errno == EINTR));
++      g_variant_unref (value);
++      if (G_UNLIKELY (res == -1))
++        {
++          _set_error_from_errno (error);
++          goto out;
++        }
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++#else
++  return TRUE;
++#endif
++}
++
++/**
++ * gs_file_set_all_xattrs:
++ * @file: File descriptor
++ * @xattrs: Extended attributes
++ * @cancellable: Cancellable
++ * @error: Error
++ *
++ * For each attribute in @xattrs, set its value on the file or
++ * directory referred to by @file.  This function does not remove any
++ * attributes not in @xattrs.
++ */
++gboolean
++gs_file_set_all_xattrs (GFile         *file,
++                        GVariant      *xattrs,
++                        GCancellable  *cancellable,
++                        GError       **error)
++{
++#ifdef GSYSTEM_CONFIG_XATTRS
++  gboolean ret = FALSE;
++  const char *path;
++  int i, n;
++
++  path = gs_file_get_path_cached (file);
++
++  n = g_variant_n_children (xattrs);
++  for (i = 0; i &lt; n; i++)
++    {
++      const guint8* name;
++      GVariant *value;
++      const guint8* value_data;
++      gsize value_len;
++      gboolean loop_err;
++
++      g_variant_get_child (xattrs, i, &quot;(^&amp;ay@ay)&quot;,
++                           &amp;name, &amp;value);
++      value_data = g_variant_get_fixed_array (value, &amp;value_len, 1);
++      
++      loop_err = lsetxattr (path, (char*)name, (char*)value_data, value_len, 0) &lt; 0;
++      g_clear_pointer (&amp;value, (GDestroyNotify) g_variant_unref);
++      if (loop_err)
++        {
++          _set_error_from_errno (error);
++          g_prefix_error (error, &quot;lsetxattr (%s, %s) failed: &quot;, path, name);
++          goto out;
++        }
++    }
++
++  ret = TRUE;
++ out:
++  return ret;
++#else
++  return TRUE;
++#endif
++}
</ins><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/gsystem-osx-compat.c libgnome-desktop/libgsystem/gsystem-osx-compat.c
</span><span class="cx"> --- libgnome-desktop/libgsystem.orig/gsystem-osx-compat.c        1969-12-31 16:00:00.000000000 -0800
</span><del>-+++ libgnome-desktop/libgsystem/gsystem-osx-compat.c        2014-01-11 18:32:40.000000000 -0800
</del><ins>++++ libgnome-desktop/libgsystem/gsystem-osx-compat.c        2014-01-24 17:02:13.000000000 -0800
</ins><span class="cx"> @@ -0,0 +1,578 @@
</span><span class="cx"> +/*
</span><span class="cx"> + * Mac OS X compatibility functions
</span><span class="lines">@@ -637,7 +2267,7 @@
</span><span class="cx"> +
</span><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/gsystem-osx-compat.h libgnome-desktop/libgsystem/gsystem-osx-compat.h
</span><span class="cx"> --- libgnome-desktop/libgsystem.orig/gsystem-osx-compat.h        1969-12-31 16:00:00.000000000 -0800
</span><del>-+++ libgnome-desktop/libgsystem/gsystem-osx-compat.h        2014-01-11 18:24:46.000000000 -0800
</del><ins>++++ libgnome-desktop/libgsystem/gsystem-osx-compat.h        2014-01-24 17:02:13.000000000 -0800
</ins><span class="cx"> @@ -0,0 +1,52 @@
</span><span class="cx"> +/*
</span><span class="cx"> + * Mac OS X Compatibility
</span><span class="lines">@@ -692,8 +2322,8 @@
</span><span class="cx"> +
</span><span class="cx"> +DIR *fdopendir(int fd);
</span><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/gsystem-shutil.c libgnome-desktop/libgsystem/gsystem-shutil.c
</span><del>---- libgnome-desktop/libgsystem.orig/gsystem-shutil.c        2013-10-04 15:18:43.000000000 -0700
-+++ libgnome-desktop/libgsystem/gsystem-shutil.c        2014-01-11 18:24:46.000000000 -0800
</del><ins>+--- libgnome-desktop/libgsystem.orig/gsystem-shutil.c        2014-01-15 13:06:25.000000000 -0800
++++ libgnome-desktop/libgsystem/gsystem-shutil.c        2014-01-24 17:02:13.000000000 -0800
</ins><span class="cx"> @@ -33,6 +33,11 @@
</span><span class="cx">  #include &lt;dirent.h&gt;
</span><span class="cx">  #include &lt;fcntl.h&gt;
</span><span class="lines">@@ -706,7 +2336,7 @@
</span><span class="cx">  /* Taken from systemd/src/shared/util.h */
</span><span class="cx">  union dirent_storage {
</span><span class="cx">          struct dirent dent;
</span><del>-@@ -248,7 +253,11 @@
</del><ins>+@@ -299,7 +304,11 @@
</ins><span class="cx">        if (dent-&gt;d_type == DT_UNKNOWN)
</span><span class="cx">          {
</span><span class="cx">            struct stat stbuf;
</span><span class="lines">@@ -718,7 +2348,7 @@
</span><span class="cx">              {
</span><span class="cx">                int errsv = errno;
</span><span class="cx">                if (errsv == ENOENT)
</span><del>-@@ -271,6 +280,7 @@
</del><ins>+@@ -322,6 +331,7 @@
</ins><span class="cx">            
</span><span class="cx">        if (dent-&gt;d_type == DT_DIR)
</span><span class="cx">          {
</span><span class="lines">@@ -726,13 +2356,13 @@
</span><span class="cx">            int child_dfd = openat (dfd, dent-&gt;d_name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
</span><span class="cx">  
</span><span class="cx">            if (child_dfd == -1)
</span><del>-@@ -285,7 +295,31 @@
</del><ins>+@@ -336,7 +346,31 @@
</ins><span class="cx">                    goto out;
</span><span class="cx">                  }
</span><span class="cx">              }
</span><span class="cx"> +#else
</span><span class="cx"> +          int child_dfd = openat (dfd, dent-&gt;d_name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_NOFOLLOW);
</span><del>- 
</del><ins>++
</ins><span class="cx"> +          if (child_dfd == -1)
</span><span class="cx"> +            {
</span><span class="cx"> +              if (errno == ENOENT)
</span><span class="lines">@@ -745,7 +2375,7 @@
</span><span class="cx"> +                  goto out;
</span><span class="cx"> +                }
</span><span class="cx"> +            }
</span><del>-+
</del><ins>+ 
</ins><span class="cx"> +          int fc_error = fcntl(child_dfd, F_SETFD, FD_CLOEXEC);
</span><span class="cx"> +          
</span><span class="cx"> +          if (fc_error != 0)
</span><span class="lines">@@ -758,7 +2388,7 @@
</span><span class="cx">            child_dir = fdopendir (child_dfd);
</span><span class="cx">            if (!child_dir)
</span><span class="cx">              {
</span><del>-@@ -352,9 +386,9 @@
</del><ins>+@@ -403,9 +437,9 @@
</ins><span class="cx">    DIR *d = NULL;
</span><span class="cx">  
</span><span class="cx">    /* With O_NOFOLLOW first */
</span><span class="lines">@@ -769,7 +2399,7 @@
</span><span class="cx">    if (dfd == -1)
</span><span class="cx">      {
</span><span class="cx">        int errsv = errno;
</span><del>-@@ -374,7 +408,40 @@
</del><ins>+@@ -425,7 +459,40 @@
</ins><span class="cx">            goto out;
</span><span class="cx">          }
</span><span class="cx">      }
</span><span class="lines">@@ -811,9 +2441,472 @@
</span><span class="cx">      {
</span><span class="cx">        d = fdopendir (dfd);
</span><span class="cx">        if (!d)
</span><ins>+diff -urN libgnome-desktop/libgsystem.orig/gsystem-shutil.c.orig libgnome-desktop/libgsystem/gsystem-shutil.c.orig
+--- libgnome-desktop/libgsystem.orig/gsystem-shutil.c.orig        1969-12-31 16:00:00.000000000 -0800
++++ libgnome-desktop/libgsystem/gsystem-shutil.c.orig        2014-01-15 13:06:25.000000000 -0800
+@@ -0,0 +1,459 @@
++/* -*- mode: C; c-file-style: &quot;gnu&quot;; indent-tabs-mode: nil; -*-
++ *
++ * Copyright (C) 2012 William Jon McCann &lt;mccann@redhat.com&gt;
++ * Copyright (C) 2012 Colin Walters &lt;walters@verbum.org&gt;
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2 of the License, or (at your option) any later version.
++ *
++ * 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, write to the
++ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
++ * Boston, MA 02111-1307, USA.
++ */
++
++#include &quot;config.h&quot;
++
++#ifndef _GNU_SOURCE
++#define _GNU_SOURCE
++#endif
++
++#define _GSYSTEM_NO_LOCAL_ALLOC
++#include &quot;libgsystem.h&quot;
++#include &lt;glib-unix.h&gt;
++#include &lt;string.h&gt;
++#include &lt;sys/stat.h&gt;
++#include &lt;dirent.h&gt;
++#include &lt;fcntl.h&gt;
++
++/* Taken from systemd/src/shared/util.h */
++union dirent_storage {
++        struct dirent dent;
++        guint8 storage[offsetof(struct dirent, d_name) +
++                        ((NAME_MAX + 1 + sizeof(long)) &amp; ~(sizeof(long) - 1))];
++};
++
++static inline void
++_set_error_from_errno (GError **error)
++{
++  int errsv = errno;
++  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                       g_strerror (errsv));
++}
++
++static gboolean
++copy_xattrs_from_file_to_fd (GFile         *src,
++                             int            dest_fd,
++                             GCancellable  *cancellable,
++                             GError       **error)
++{
++  gboolean ret = FALSE;
++  GVariant *src_xattrs = NULL;
++
++  if (!gs_file_get_all_xattrs (src, &amp;src_xattrs, cancellable, error))
++    goto out;
++
++  if (src_xattrs)
++    {
++      if (!gs_fd_set_all_xattrs (dest_fd, src_xattrs, cancellable, error))
++        goto out;
++    }
++
++  ret = TRUE;
++ out:
++  g_clear_pointer (&amp;src_xattrs, g_variant_unref);
++  return ret;
++}
++
++typedef enum {
++  GS_CP_MODE_NONE,
++  GS_CP_MODE_HARDLINK,
++  GS_CP_MODE_COPY_ALL
++} GsCpMode;
++
++static gboolean
++cp_internal (GFile         *src,
++             GFile         *dest,
++             GsCpMode       mode,
++             GCancellable  *cancellable,
++             GError       **error)
++{
++  gboolean ret = FALSE;
++  GFileEnumerator *enumerator = NULL;
++  GFileInfo *src_info = NULL;
++  GFile *dest_child = NULL;
++  int dest_dfd = -1;
++  int r;
++
++  enumerator = g_file_enumerate_children (src, &quot;standard::type,standard::name,unix::uid,unix::gid,unix::mode&quot;,
++                                          G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
++                                          cancellable, error);
++  if (!enumerator)
++    goto out;
++
++  src_info = g_file_query_info (src, &quot;standard::name,unix::mode,unix::uid,unix::gid,&quot; \
++                                &quot;time::modified,time::modified-usec,time::access,time::access-usec&quot;,
++                                G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
++                                cancellable, error);
++  if (!src_info)
++    goto out;
++
++  do
++    r = mkdir (gs_file_get_path_cached (dest), 0755);
++  while (G_UNLIKELY (r == -1 &amp;&amp; errno == EINTR));
++  if (r == -1)
++    {
++      _set_error_from_errno (error);
++      goto out;
++    }
++
++  if (mode != GS_CP_MODE_NONE)
++    {
++      if (!gs_file_open_dir_fd (dest, &amp;dest_dfd,
++                                cancellable, error))
++        goto out;
++
++      do
++        r = fchown (dest_dfd,
++                    g_file_info_get_attribute_uint32 (src_info, &quot;unix::uid&quot;),
++                    g_file_info_get_attribute_uint32 (src_info, &quot;unix::gid&quot;));
++      while (G_UNLIKELY (r == -1 &amp;&amp; errno == EINTR));
++      if (r == -1)
++        {
++          _set_error_from_errno (error);
++          goto out;
++        }
++
++      do
++        r = fchmod (dest_dfd, g_file_info_get_attribute_uint32 (src_info, &quot;unix::mode&quot;));
++      while (G_UNLIKELY (r == -1 &amp;&amp; errno == EINTR));
++
++      if (!copy_xattrs_from_file_to_fd (src, dest_dfd, cancellable, error))
++        goto out;
++
++      if (dest_dfd != -1)
++        {
++          (void) close (dest_dfd);
++          dest_dfd = -1;
++        }
++    }
++
++  while (TRUE)
++    {
++      GFileInfo *file_info = NULL;
++      GFile *src_child = NULL;
++
++      if (!gs_file_enumerator_iterate (enumerator, &amp;file_info, &amp;src_child,
++                                       cancellable, error))
++        goto out;
++      if (!file_info)
++        break;
++
++      if (dest_child) g_object_unref (dest_child);
++      dest_child = g_file_get_child (dest, g_file_info_get_name (file_info));
++
++      if (g_file_info_get_file_type (file_info) == G_FILE_TYPE_DIRECTORY)
++        {
++          if (!cp_internal (src_child, dest_child, mode,
++                            cancellable, error))
++            goto out;
++        }
++      else
++        {
++          gboolean did_link = FALSE;
++          (void) unlink (gs_file_get_path_cached (dest_child));
++          if (mode == GS_CP_MODE_HARDLINK)
++            {
++              if (link (gs_file_get_path_cached (src_child), gs_file_get_path_cached (dest_child)) == -1)
++                {
++                  if (!(errno == EMLINK || errno == EXDEV))
++                    {
++                      int errsv = errno;
++                      g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                           g_strerror (errsv));
++                      goto out;
++                    }
++                  /* We failed to hardlink; fall back to copying all; this will
++                   * affect subsequent directory copies too.
++                   */
++                  mode = GS_CP_MODE_COPY_ALL;
++                }
++              else
++                did_link = TRUE;
++            }
++          if (!did_link)
++            {
++              GFileCopyFlags copyflags = G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS;
++              if (mode == GS_CP_MODE_COPY_ALL)
++                copyflags |= G_FILE_COPY_ALL_METADATA;
++              if (!g_file_copy (src_child, dest_child, copyflags,
++                                cancellable, NULL, NULL, error))
++                goto out;
++            }
++        }
++    }
++
++  ret = TRUE;
++ out:
++  if (dest_dfd != -1)
++    (void) close (dest_dfd);
++  g_clear_object (&amp;src_info);
++  g_clear_object (&amp;enumerator);
++  g_clear_object (&amp;dest_child);
++  return ret;
++}
++
++/**
++ * gs_shutil_cp_al_or_fallback:
++ * @src: Source path
++ * @dest: Destination path
++ * @cancellable:
++ * @error:
++ *
++ * Recursively copy path @src (which must be a directory) to the
++ * target @dest.  If possible, hardlinks are used; if a hardlink is
++ * not possible, a regular copy is created.  Any existing files are
++ * overwritten.
++ *
++ * Returns: %TRUE on success
++ */
++gboolean
++gs_shutil_cp_al_or_fallback (GFile         *src,
++                             GFile         *dest,
++                             GCancellable  *cancellable,
++                             GError       **error)
++{
++  return cp_internal (src, dest, GS_CP_MODE_HARDLINK,
++                      cancellable, error);
++}
++
++/**
++ * gs_shutil_cp_a:
++ * @src: Source path
++ * @dest: Destination path
++ * @cancellable:
++ * @error:
++ *
++ * Recursively copy path @src (which must be a directory) to the
++ * target @dest.  Any existing files are overwritten.
++ *
++ * Returns: %TRUE on success
++ */
++gboolean
++gs_shutil_cp_a (GFile         *src,
++                GFile         *dest,
++                GCancellable  *cancellable,
++                GError       **error)
++{
++  return cp_internal (src, dest, GS_CP_MODE_COPY_ALL,
++                      cancellable, error);
++}
++
++static unsigned char
++struct_stat_to_dt (struct stat *stbuf)
++{
++  if (S_ISDIR (stbuf-&gt;st_mode))
++    return DT_DIR;
++  if (S_ISREG (stbuf-&gt;st_mode))
++    return DT_REG;
++  if (S_ISCHR (stbuf-&gt;st_mode))
++    return DT_CHR;
++  if (S_ISBLK (stbuf-&gt;st_mode))
++    return DT_BLK;
++  if (S_ISFIFO (stbuf-&gt;st_mode))
++    return DT_FIFO;
++  if (S_ISLNK (stbuf-&gt;st_mode))
++    return DT_LNK;
++  if (S_ISSOCK (stbuf-&gt;st_mode))
++    return DT_SOCK;
++  return DT_UNKNOWN;
++}
++
++static gboolean
++gs_shutil_rm_rf_children (DIR                *dir,
++                          GCancellable       *cancellable,
++                          GError            **error)
++{
++  gboolean ret = FALSE;
++  int dfd;
++  DIR *child_dir = NULL;
++  struct dirent *dent;
++  union dirent_storage buf;
++
++  if (g_cancellable_set_error_if_cancelled (cancellable, error))
++    goto out;
++
++  dfd = dirfd (dir);
++
++  while (readdir_r (dir, &amp;buf.dent, &amp;dent) == 0)
++    {
++      if (dent == NULL)
++        break;
++      if (dent-&gt;d_type == DT_UNKNOWN)
++        {
++          struct stat stbuf;
++          if (fstatat (dfd, dent-&gt;d_name, &amp;stbuf, AT_SYMLINK_NOFOLLOW) == -1)
++            {
++              int errsv = errno;
++              if (errsv == ENOENT)
++                continue;
++              else
++                {
++                  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                       g_strerror (errsv));
++                  goto out;
++                }
++            }
++          dent-&gt;d_type = struct_stat_to_dt (&amp;stbuf);
++          /* Assume unknown types are just treated like regular files */
++          if (dent-&gt;d_type == DT_UNKNOWN)
++            dent-&gt;d_type = DT_REG;
++        }
++
++      if (strcmp (dent-&gt;d_name, &quot;.&quot;) == 0 || strcmp (dent-&gt;d_name, &quot;..&quot;) == 0)
++        continue;
++          
++      if (dent-&gt;d_type == DT_DIR)
++        {
++          int child_dfd = openat (dfd, dent-&gt;d_name, O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
++
++          if (child_dfd == -1)
++            {
++              if (errno == ENOENT)
++                continue;
++              else
++                {
++                  int errsv = errno;
++                  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                       g_strerror (errsv));
++                  goto out;
++                }
++            }
++
++          child_dir = fdopendir (child_dfd);
++          if (!child_dir)
++            {
++              int errsv = errno;
++              g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                   g_strerror (errsv));
++              goto out;
++            }
++
++          if (!gs_shutil_rm_rf_children (child_dir, cancellable, error))
++            goto out;
++
++          if (unlinkat (dfd, dent-&gt;d_name, AT_REMOVEDIR) == -1)
++            {
++              int errsv = errno;
++              g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                   g_strerror (errsv));
++              goto out;
++            }
++
++          (void) closedir (child_dir);
++          child_dir = NULL;
++        }
++      else
++        {
++          if (unlinkat (dfd, dent-&gt;d_name, 0) == -1)
++            {
++              int errsv = errno;
++              if (errno != ENOENT)
++                {
++                  g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                       g_strerror (errsv));
++                  goto out;
++                }
++            }
++        }
++    }
++  /* Ignore error result from readdir_r, that's what others
++   * seem to do =(
++   */
++
++  ret = TRUE;
++ out:
++  if (child_dir) (void) closedir (child_dir);
++  return ret;
++}
++
++/**
++ * gs_shutil_rm_rf:
++ * @path: A file or directory
++ * @cancellable:
++ * @error:
++ *
++ * Recursively delete the filename referenced by @path; it may be a
++ * file or directory.  No error is thrown if @path does not exist.
++ */
++gboolean
++gs_shutil_rm_rf (GFile        *path,
++                 GCancellable *cancellable,
++                 GError      **error)
++{
++  gboolean ret = FALSE;
++  int dfd = -1;
++  DIR *d = NULL;
++
++  /* With O_NOFOLLOW first */
++  dfd = openat (AT_FDCWD, gs_file_get_path_cached (path),
++                O_RDONLY | O_NONBLOCK | O_DIRECTORY | O_CLOEXEC | O_NOFOLLOW);
++
++  if (dfd == -1)
++    {
++      int errsv = errno;
++      if (errsv == ENOENT)
++        {
++          ;
++        }
++      else if (errsv == ENOTDIR || errsv == ELOOP)
++        {
++          if (!gs_file_unlink (path, cancellable, error))
++            goto out;
++        }
++      else
++        {
++          g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                               g_strerror (errsv));
++          goto out;
++        }
++    }
++  else
++    {
++      d = fdopendir (dfd);
++      if (!d)
++        {
++          int errsv = errno;
++          g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                               g_strerror (errsv));
++          goto out;
++        }
++
++      if (!gs_shutil_rm_rf_children (d, cancellable, error))
++        goto out;
++
++      if (rmdir (gs_file_get_path_cached (path)) == -1)
++        {
++          int errsv = errno;
++          if (errsv != ENOENT)
++            {
++              g_set_error_literal (error, G_IO_ERROR, g_io_error_from_errno (errsv),
++                                   g_strerror (errsv));
++              goto out;
++            }
++        }
++    }
++
++  ret = TRUE;
++ out:
++  if (d) (void) closedir (d);
++  return ret;
++}
++
</ins><span class="cx"> diff -urN libgnome-desktop/libgsystem.orig/gsystem-subprocess.c libgnome-desktop/libgsystem/gsystem-subprocess.c
</span><del>---- libgnome-desktop/libgsystem.orig/gsystem-subprocess.c        2013-10-04 15:18:43.000000000 -0700
-+++ libgnome-desktop/libgsystem/gsystem-subprocess.c        2014-01-11 18:24:46.000000000 -0800
</del><ins>+--- libgnome-desktop/libgsystem.orig/gsystem-subprocess.c        2014-01-15 13:06:25.000000000 -0800
++++ libgnome-desktop/libgsystem/gsystem-subprocess.c        2014-01-24 17:02:13.000000000 -0800
</ins><span class="cx"> @@ -259,7 +259,11 @@
</span><span class="cx">    gint my_fd;
</span><span class="cx">  
</span></span></pre>
</div>
</div>

</body>
</html>