Merge branch 'master' into 'master'

gio: Expose g_file_query_info_for_copy()

Closes gvfs#346

See merge request GNOME/glib!1449
This commit is contained in:
Philip Withnall 2020-10-06 09:55:19 +00:00
commit 3573a2d32d
4 changed files with 149 additions and 45 deletions

View File

@ -199,6 +199,7 @@ g_file_replace_contents
g_file_replace_contents_async
g_file_replace_contents_bytes_async
g_file_replace_contents_finish
g_file_build_attribute_list_for_copy
g_file_copy_attributes
g_file_create_readwrite
g_file_create_readwrite_async

View File

@ -2695,14 +2695,36 @@ should_copy (GFileAttributeInfo *info,
return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE;
}
static gboolean
build_attribute_list_for_copy (GFile *file,
GFileCopyFlags flags,
char **out_attributes,
GCancellable *cancellable,
GError **error)
/**
* g_file_build_attribute_list_for_copy:
* @file: a #GFile to copy attributes to
* @flags: a set of #GFileCopyFlags
* @cancellable: (nullable): optional #GCancellable object,
* %NULL to ignore
* @error: a #GError, %NULL to ignore
*
* Prepares the file attribute query string for copying to @file.
*
* This function prepares an attribute query string to be
* passed to g_file_query_info() to get a list of attributes
* normally copied with the file (see g_file_copy_attributes()
* for the detailed description). This function is used by the
* implementation of g_file_copy_attributes() and is useful
* when one needs to query and set the attributes in two
* stages (e.g., for recursive move of a directory).
*
* Returns: an attribute query string for g_file_query_info(),
* or %NULL if an error occurs.
*
* Since: 2.68
*/
char *
g_file_build_attribute_list_for_copy (GFile *file,
GFileCopyFlags flags,
GCancellable *cancellable,
GError **error)
{
gboolean ret = FALSE;
char *ret = NULL;
GFileAttributeInfoList *attributes = NULL, *namespaces = NULL;
GString *s = NULL;
gboolean first;
@ -2710,6 +2732,10 @@ build_attribute_list_for_copy (GFile *file,
gboolean copy_all_attributes;
gboolean skip_perms;
g_return_val_if_fail (G_IS_FILE (file), NULL);
g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), NULL);
g_return_val_if_fail (error == NULL || *error == NULL, NULL);
copy_all_attributes = flags & G_FILE_COPY_ALL_METADATA;
skip_perms = (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) != 0;
@ -2763,8 +2789,7 @@ build_attribute_list_for_copy (GFile *file,
}
}
ret = TRUE;
*out_attributes = g_string_free (s, FALSE);
ret = g_string_free (s, FALSE);
s = NULL;
out:
if (s)
@ -2810,8 +2835,9 @@ g_file_copy_attributes (GFile *source,
GFileInfo *info;
gboolean source_nofollow_symlinks;
if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
cancellable, error))
attrs_to_read = g_file_build_attribute_list_for_copy (destination, flags,
cancellable, error);
if (!attrs_to_read)
return FALSE;
source_nofollow_symlinks = flags & G_FILE_COPY_NOFOLLOW_SYMLINKS;
@ -3157,6 +3183,7 @@ file_copy_fallback (GFile *source,
char *attrs_to_read;
gboolean do_set_attributes = FALSE;
GFileCreateFlags create_flags;
GError *tmp_error = NULL;
/* need to know the file type */
info = g_file_query_info (source,
@ -3198,47 +3225,43 @@ file_copy_fallback (GFile *source,
goto out;
in = G_INPUT_STREAM (file_in);
if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
cancellable, error))
attrs_to_read = g_file_build_attribute_list_for_copy (destination, flags,
cancellable, error);
if (!attrs_to_read)
goto out;
if (attrs_to_read != NULL)
/* Ok, ditch the previous lightweight info (on Unix we just
* called lstat()); at this point we gather all the information
* we need about the source from the opened file descriptor.
*/
g_object_unref (info);
info = g_file_input_stream_query_info (file_in, attrs_to_read,
cancellable, &tmp_error);
if (!info)
{
GError *tmp_error = NULL;
/* Ok, ditch the previous lightweight info (on Unix we just
* called lstat()); at this point we gather all the information
* we need about the source from the opened file descriptor.
/* Not all gvfs backends implement query_info_on_read(), we
* can just fall back to the pathname again.
* https://bugzilla.gnome.org/706254
*/
g_object_unref (info);
info = g_file_input_stream_query_info (file_in, attrs_to_read,
cancellable, &tmp_error);
if (!info)
if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
{
/* Not all gvfs backends implement query_info_on_read(), we
* can just fall back to the pathname again.
* https://bugzilla.gnome.org/706254
*/
if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
{
g_clear_error (&tmp_error);
info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
}
else
{
g_free (attrs_to_read);
g_propagate_error (error, tmp_error);
goto out;
}
g_clear_error (&tmp_error);
info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
cancellable, error);
}
else
{
g_free (attrs_to_read);
g_propagate_error (error, tmp_error);
goto out;
}
g_free (attrs_to_read);
if (!info)
goto out;
do_set_attributes = TRUE;
}
g_free (attrs_to_read);
if (!info)
goto out;
do_set_attributes = TRUE;
/* In the local file path, we pass down the source info which
* includes things like unix::mode, to ensure that the target file

View File

@ -1094,6 +1094,12 @@ gboolean g_file_eject_mountable_with_operation_finish (GFile
GAsyncResult *result,
GError **error);
GLIB_AVAILABLE_IN_2_68
char * g_file_build_attribute_list_for_copy (GFile *file,
GFileCopyFlags flags,
GCancellable *cancellable,
GError **error);
GLIB_AVAILABLE_IN_ALL
gboolean g_file_copy_attributes (GFile *source,
GFile *destination,

View File

@ -1780,6 +1780,79 @@ test_writev_async_all_too_big_vectors (void)
g_object_unref (file);
}
static void
test_build_attribute_list_for_copy (void)
{
GFile *tmpfile;
GFileIOStream *iostream;
GError *error = NULL;
const GFileCopyFlags test_flags[] =
{
G_FILE_COPY_NONE,
G_FILE_COPY_TARGET_DEFAULT_PERMS,
G_FILE_COPY_ALL_METADATA,
G_FILE_COPY_ALL_METADATA | G_FILE_COPY_TARGET_DEFAULT_PERMS,
};
gsize i;
char *attrs;
gchar *attrs_with_commas;
tmpfile = g_file_new_tmp ("tmp-build-attribute-list-for-copyXXXXXX",
&iostream, &error);
g_assert_no_error (error);
g_io_stream_close ((GIOStream*)iostream, NULL, &error);
g_assert_no_error (error);
g_clear_object (&iostream);
for (i = 0; i < G_N_ELEMENTS (test_flags); i++)
{
GFileCopyFlags flags = test_flags[i];
attrs = g_file_build_attribute_list_for_copy (tmpfile, flags, NULL, &error);
g_test_message ("Attributes for copy: %s", attrs);
g_assert_no_error (error);
g_assert_nonnull (attrs);
attrs_with_commas = g_strconcat (",", attrs, ",", NULL);
g_free (attrs);
/* See g_local_file_class_init for reference. */
if (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS)
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
else
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_MODE ","));
#ifdef G_OS_UNIX
if (flags & G_FILE_COPY_ALL_METADATA)
{
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
}
else
{
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_UID ","));
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_UNIX_GID ","));
}
#endif
#ifdef HAVE_UTIMES
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED ","));
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC ","));
if (flags & G_FILE_COPY_ALL_METADATA)
{
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
g_assert_nonnull (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
}
else
{
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS ","));
g_assert_null (g_strstr_len (attrs_with_commas, -1, "," G_FILE_ATTRIBUTE_TIME_ACCESS_USEC ","));
}
#endif
g_free (attrs_with_commas);
}
(void) g_file_delete (tmpfile, NULL, NULL);
g_clear_object (&tmpfile);
}
int
main (int argc, char *argv[])
{
@ -1817,6 +1890,7 @@ main (int argc, char *argv[])
g_test_add_func ("/file/writev/async_all-no-vectors", test_writev_async_all_no_vectors);
g_test_add_func ("/file/writev/async_all-to-big-vectors", test_writev_async_all_too_big_vectors);
g_test_add_func ("/file/writev/async_all-cancellation", test_writev_async_all_cancellation);
g_test_add_func ("/file/build-attribute-list-for-copy", test_build_attribute_list_for_copy);
return g_test_run ();
}