[glib] g_file_copy(): Ensure G_FILE_COPY_OVERWRITE preserves permissions



commit 978571d854922d12050e17d618e747ebdb4ff0a8
Author: Colin Walters <walters verbum org>
Date:   Sun Mar 17 18:33:59 2013 -0400

    g_file_copy(): Ensure G_FILE_COPY_OVERWRITE preserves permissions
    
    We need to close the stream *before* applying the file modes, because
    g_file_replace() allocates a temporary file.  At the moment we're
    applying the modes to the extant file, then immediately rename()ing
    over it with the default perms.
    
    This regressed with commit 166766a89fcd173dcd6ffda11f902029928f7f28.
    
    The real fix here is to have g_file_create_with_info() so that we can
    atomically create a file with the permissions we want.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=696014

 gio/gfile.c      |   15 +++++++------
 gio/tests/file.c |   59 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+), 7 deletions(-)
---
diff --git a/gio/gfile.c b/gio/gfile.c
index 6d281e6..277f7b0 100644
--- a/gio/gfile.c
+++ b/gio/gfile.c
@@ -3106,7 +3106,7 @@ file_copy_fallback (GFile                  *source,
     }
 
 #endif
-  
+
   /* A plain read/write loop */
   if (!copy_stream_with_progress (in, out, source, cancellable,
                                   progress_callback, progress_callback_data,
@@ -3115,11 +3115,6 @@ file_copy_fallback (GFile                  *source,
 
   ret = TRUE;
  out:
-  /* Ignore errors here. Failure to copy metadata is not a hard error */
-  if (ret)
-    (void) g_file_copy_attributes (source, destination,
-                                   flags, cancellable, NULL);
-
   if (in)
     {
       /* Don't care about errors in source here */
@@ -3134,7 +3129,13 @@ file_copy_fallback (GFile                  *source,
         ret = FALSE;
       g_object_unref (out);
     }
-  
+
+  /* Ignore errors here. Failure to copy metadata is not a hard error */
+  if (ret)
+    (void) g_file_copy_attributes (source, destination,
+                                   flags, cancellable, NULL);
+
+
   g_clear_object (&info);
 
   return ret;
diff --git a/gio/tests/file.c b/gio/tests/file.c
index 7106d89..bca461a 100644
--- a/gio/tests/file.c
+++ b/gio/tests/file.c
@@ -3,6 +3,9 @@
 #include <stdlib.h>
 #include <gio/gio.h>
 #include <gio/gfiledescriptorbased.h>
+#ifdef G_OS_UNIX
+#include <sys/stat.h>
+#endif
 
 static void
 test_basic (void)
@@ -727,6 +730,59 @@ test_async_delete (void)
   g_object_unref (file);
 }
 
+#ifdef G_OS_UNIX
+static void
+test_copy_preserve_mode (void)
+{
+  GFile *tmpfile;
+  GFile *dest_tmpfile;
+  GFileInfo *dest_info;
+  GFileIOStream *iostream;
+  GError *local_error = NULL;
+  GError **error = &local_error;
+  guint32 romode = S_IFREG | 0600;
+  guint32 dest_mode;
+
+  tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
+                            &iostream, error);
+  g_assert_no_error (local_error);
+  g_io_stream_close ((GIOStream*)iostream, NULL, error);
+  g_assert_no_error (local_error);
+  g_clear_object (&iostream);
+
+  g_file_set_attribute (tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, G_FILE_ATTRIBUTE_TYPE_UINT32,
+                        &romode, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                        NULL, error);
+  g_assert_no_error (local_error);
+
+  dest_tmpfile = g_file_new_tmp ("tmp-copy-preserve-modeXXXXXX",
+                                 &iostream, error);
+  g_assert_no_error (local_error);
+  g_io_stream_close ((GIOStream*)iostream, NULL, error);
+  g_assert_no_error (local_error);
+  g_clear_object (&iostream);
+
+  g_file_copy (tmpfile, dest_tmpfile, G_FILE_COPY_OVERWRITE | G_FILE_COPY_NOFOLLOW_SYMLINKS | 
G_FILE_COPY_ALL_METADATA,
+               NULL, NULL, NULL, error);
+  g_assert_no_error (local_error);
+
+  dest_info = g_file_query_info (dest_tmpfile, G_FILE_ATTRIBUTE_UNIX_MODE, 
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+                                 NULL, error);
+  g_assert_no_error (local_error);
+
+  dest_mode = g_file_info_get_attribute_uint32 (dest_info, G_FILE_ATTRIBUTE_UNIX_MODE);
+  
+  g_assert_cmpint (dest_mode, ==, romode);
+
+  (void) g_file_delete (tmpfile, NULL, NULL);
+  (void) g_file_delete (dest_tmpfile, NULL, NULL);
+  
+  g_clear_object (&tmpfile);
+  g_clear_object (&dest_tmpfile);
+  g_clear_object (&dest_info);
+}
+#endif
+
 int
 main (int argc, char *argv[])
 {
@@ -746,6 +802,9 @@ main (int argc, char *argv[])
   g_test_add_func ("/file/replace-load", test_replace_load);
   g_test_add_func ("/file/replace-cancel", test_replace_cancel);
   g_test_add_func ("/file/async-delete", test_async_delete);
+#ifdef G_OS_UNIX
+  g_test_add_func ("/file/copy-preserve-mode", test_copy_preserve_mode);
+#endif
 
   return g_test_run ();
 }


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]