Commit 978571d8 authored by Colin Walters's avatar Colin Walters Committed by Allison Karlitskaya

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 166766a8.

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
parent ef2aa88a
......@@ -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;
......
......@@ -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 ();
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment