From b2e28aa5c8c8bde943ed2bc00d2e380549959a67 Mon Sep 17 00:00:00 2001
From: Colin Walters <walters@verbum.org>
Date: Thu, 23 Jun 2016 08:42:53 -0400
Subject: GFile: Add g_file_peek_path()

This is a variant of g_file_get_path() which returns a const string to
the caller, rather than transferring ownership.

I've been carrying `gs_file_get_path_cached()` in libgsystem and it
has seen a lot of use in the ostree and flatpak codebases.  There are
probably others too.

I think language bindings like Python/Gjs could also use this to avoid
an extra malloc (i.e. we could transparently replace
`g_file_get_path()` with `g_file_peek_path()`.

(Originally by Colin Walters. Tweaked by Philip Withnall to update to
2.56, change the function name and drop the locking.)

https://bugzilla.gnome.org/show_bug.cgi?id=767976
---
 docs/reference/gio/gio-sections.txt |   1 +
 gio/gfile.c                         | 101 ++++++++++++++++++++++++++++++++++++
 gio/gfile.h                         |   2 +
 gio/tests/file.c                    |   8 +--
 4 files changed, 109 insertions(+), 3 deletions(-)

diff --git a/docs/reference/gio/gio-sections.txt b/docs/reference/gio/gio-sections.txt
index 0996a9e..36fe798 100644
--- a/docs/reference/gio/gio-sections.txt
+++ b/docs/reference/gio/gio-sections.txt
@@ -87,6 +87,7 @@ g_file_hash
 g_file_equal
 g_file_get_basename
 g_file_get_path
+g_file_peek_path
 g_file_get_uri
 g_file_get_parse_name
 g_file_get_parent
diff --git a/gio/gfile.c b/gio/gfile.c
index 9fcfef4..9395863 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -534,6 +534,107 @@ g_file_get_path (GFile *file)
   return (* iface->get_path) (file);
 }
 
+/* Original commit introducing this in libgsystem:
+ *
+ *  fileutil: Handle recent: and trash: URIs
+ *
+ *  The gs_file_get_path_cached() was rather brittle in its handling
+ *  of URIs. It would assert() when a GFile didn't have a backing path
+ *  (such as when handling trash: or recent: URIs), and didn't know
+ *  how to get the target URI for those items either.
+ *
+ *  Make sure that we do not assert() when a backing path cannot be
+ *  found, and handle recent: and trash: URIs.
+ *
+ *  https://bugzilla.gnome.org/show_bug.cgi?id=708435
+ */
+static char *
+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;
+}
+
+static const char *
+file_peek_path_generic (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 ("gio-file-path");
+
+  /* We need to be careful about threading, as two threads calling
+   * g_file_peek_path() on the same file could race: both would see
+   * (g_object_get_qdata(…) == NULL) to begin with, both would generate and add
+   * the path, but the second thread to add it would end up freeing the path
+   * set by the first thread. The first thread would still return the pointer
+   * to that freed path, though, resulting an a read-after-free. Handle that
+   * with a compare-and-swap loop. The g_object_*_qdata() functions are atomic. */
+
+  while (TRUE)
+    {
+      gchar *new_path = NULL;
+
+      path = g_object_get_qdata ((GObject*)file, _file_path_quark);
+
+      if (path != NULL)
+        break;
+
+      if (g_file_has_uri_scheme (file, "trash") ||
+          g_file_has_uri_scheme (file, "recent"))
+        new_path = file_get_target_path (file);
+      else
+        new_path = g_file_get_path (file);
+      if (new_path == NULL)
+        return NULL;
+
+      /* By passing NULL here, we ensure we never replace existing data: */
+      if (g_object_replace_qdata ((GObject *) file, _file_path_quark,
+                                  NULL, (gpointer) new_path,
+                                  (GDestroyNotify) g_free, NULL))
+        break;
+      else
+        g_free (new_path);
+    }
+
+  return path;
+}
+
+/**
+ * g_file_peek_path:
+ * @file: input #GFile
+ *
+ * Exactly like g_file_get_path(), but caches the result via
+ * g_object_set_qdata_full().  This is useful for example in C
+ * applications which mix `g_file_*` APIs with native ones.  It
+ * also avoids an extra duplicated string when possible, so will be
+ * generally more efficient.
+ *
+ * This call does no blocking I/O.
+ *
+ * Returns: (type filename) (nullable): string containing the #GFile's path,
+ *     or %NULL if no such path exists. The returned string is owned by @file.
+ * Since: 2.56
+ */
+const char *
+g_file_peek_path (GFile *file)
+{
+  if (G_IS_LOCAL_FILE (file))
+    return _g_local_file_get_filename ((GLocalFile *) file);
+  return file_peek_path_generic (file);
+}
+
 /**
  * g_file_get_uri:
  * @file: input #GFile
diff --git a/gio/gfile.h b/gio/gfile.h
index 394c643..e007bff 100644
--- a/gio/gfile.h
+++ b/gio/gfile.h
@@ -616,6 +616,8 @@ GLIB_AVAILABLE_IN_ALL
 char *                  g_file_get_basename               (GFile                      *file);
 GLIB_AVAILABLE_IN_ALL
 char *                  g_file_get_path                   (GFile                      *file);
+GLIB_AVAILABLE_IN_2_38
+const char *            g_file_peek_path                  (GFile                      *file);
 GLIB_AVAILABLE_IN_ALL
 char *                  g_file_get_uri                    (GFile                      *file);
 GLIB_AVAILABLE_IN_ALL
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 9d819f3..c3ee4be 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -149,9 +149,12 @@ monitor_changed (GFileMonitor      *monitor,
 {
   CreateDeleteData *data = user_data;
   gchar *path;
+  const gchar *peeked_path;
 
   path = g_file_get_path (file);
+  peeked_path = g_file_peek_path (file);
   g_assert_cmpstr (data->monitor_path, ==, path);
+  g_assert_cmpstr (path, ==, peeked_path);
   g_free (path);
 
   if (event_type == G_FILE_MONITOR_EVENT_CREATED)
@@ -599,7 +602,7 @@ static void
 test_replace_load (void)
 {
   ReplaceLoadData *data;
-  gchar *path;
+  const gchar *path;
   GFileIOStream *iostream;
 
   data = g_new0 (ReplaceLoadData, 1);
@@ -611,7 +614,7 @@ test_replace_load (void)
   g_assert (data->file != NULL);
   g_object_unref (iostream);
 
-  path = g_file_get_path (data->file);
+  path = g_file_peek_path (data->file);
   remove (path);
 
   g_assert (!g_file_query_exists (data->file, NULL));
@@ -633,7 +636,6 @@ test_replace_load (void)
   g_main_loop_unref (data->loop);
   g_object_unref (data->file);
   g_free (data);
-  free (path);
 }
 
 static void
-- 
2.16.4


From e869eccd1e0351f493af7e9f735a747fd169725a Mon Sep 17 00:00:00 2001
From: Matthias Clasen <mclasen@redhat.com>
Date: Tue, 22 Jan 2019 13:26:31 -0500
Subject: keyfile settings: Use tighter permissions

When creating directories, create them with 700 permissions,
instead of 777.

Closes: #1658
---
 gio/gkeyfilesettingsbackend.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/gio/gkeyfilesettingsbackend.c b/gio/gkeyfilesettingsbackend.c
index 6601eba..16fe048 100644
--- a/gio/gkeyfilesettingsbackend.c
+++ b/gio/gkeyfilesettingsbackend.c
@@ -91,7 +91,8 @@ g_keyfile_settings_backend_keyfile_write (GKeyfileSettingsBackend *kfsb)
 
   contents = g_key_file_to_data (kfsb->keyfile, &length, NULL);
   g_file_replace_contents (kfsb->file, contents, length, NULL, FALSE,
-                           G_FILE_CREATE_REPLACE_DESTINATION,
+                           G_FILE_CREATE_REPLACE_DESTINATION |
+                           G_FILE_CREATE_PRIVATE,
                            NULL, NULL, NULL);
 
   compute_checksum (kfsb->digest, contents, length);
@@ -638,7 +639,7 @@ g_keyfile_settings_backend_new (const gchar *filename,
 
   kfsb->file = g_file_new_for_path (filename);
   kfsb->dir = g_file_get_parent (kfsb->file);
-  g_file_make_directory_with_parents (kfsb->dir, NULL, NULL);
+  g_mkdir_with_parents (g_file_peek_path (kfsb->dir), 0700);
 
   kfsb->file_monitor = g_file_monitor_file (kfsb->file, 0, NULL, NULL);
   kfsb->dir_monitor = g_file_monitor_file (kfsb->dir, 0, NULL, NULL);
-- 
2.16.4

