mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
gio: Expose g_file_build_attribute_list_for_copy
Expose a function that prepares an attribute query string to be passed to g_file_query_info() to get a list of attributes normally copied with the file. This function is used by the implementation of g_file_copy_attributes, and it's useful if one needs to split g_file_copy_attributes into two stages, for example, when nautilus does a recursive move of a directory. When files are moved from the source directory, its modification time changes. To preserve the mtime on the destination directory, it has to be queried before moving files and set after doing it, hence these two stages. Signed-off-by: Maxim Mikityanskiy <maxtram95@gmail.com>
This commit is contained in:
parent
5017de6567
commit
094eca7076
@ -199,6 +199,7 @@ g_file_replace_contents
|
|||||||
g_file_replace_contents_async
|
g_file_replace_contents_async
|
||||||
g_file_replace_contents_bytes_async
|
g_file_replace_contents_bytes_async
|
||||||
g_file_replace_contents_finish
|
g_file_replace_contents_finish
|
||||||
|
g_file_build_attribute_list_for_copy
|
||||||
g_file_copy_attributes
|
g_file_copy_attributes
|
||||||
g_file_create_readwrite
|
g_file_create_readwrite
|
||||||
g_file_create_readwrite_async
|
g_file_create_readwrite_async
|
||||||
|
113
gio/gfile.c
113
gio/gfile.c
@ -2695,14 +2695,36 @@ should_copy (GFileAttributeInfo *info,
|
|||||||
return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE;
|
return info->flags & G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static gboolean
|
/**
|
||||||
build_attribute_list_for_copy (GFile *file,
|
* g_file_build_attribute_list_for_copy:
|
||||||
GFileCopyFlags flags,
|
* @file: a #GFile to copy attributes to
|
||||||
char **out_attributes,
|
* @flags: a set of #GFileCopyFlags
|
||||||
GCancellable *cancellable,
|
* @cancellable: (nullable): optional #GCancellable object,
|
||||||
GError **error)
|
* %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;
|
GFileAttributeInfoList *attributes = NULL, *namespaces = NULL;
|
||||||
GString *s = NULL;
|
GString *s = NULL;
|
||||||
gboolean first;
|
gboolean first;
|
||||||
@ -2710,6 +2732,10 @@ build_attribute_list_for_copy (GFile *file,
|
|||||||
gboolean copy_all_attributes;
|
gboolean copy_all_attributes;
|
||||||
gboolean skip_perms;
|
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;
|
copy_all_attributes = flags & G_FILE_COPY_ALL_METADATA;
|
||||||
skip_perms = (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) != 0;
|
skip_perms = (flags & G_FILE_COPY_TARGET_DEFAULT_PERMS) != 0;
|
||||||
|
|
||||||
@ -2763,8 +2789,7 @@ build_attribute_list_for_copy (GFile *file,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ret = TRUE;
|
ret = g_string_free (s, FALSE);
|
||||||
*out_attributes = g_string_free (s, FALSE);
|
|
||||||
s = NULL;
|
s = NULL;
|
||||||
out:
|
out:
|
||||||
if (s)
|
if (s)
|
||||||
@ -2810,8 +2835,9 @@ g_file_copy_attributes (GFile *source,
|
|||||||
GFileInfo *info;
|
GFileInfo *info;
|
||||||
gboolean source_nofollow_symlinks;
|
gboolean source_nofollow_symlinks;
|
||||||
|
|
||||||
if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
|
attrs_to_read = g_file_build_attribute_list_for_copy (destination, flags,
|
||||||
cancellable, error))
|
cancellable, error);
|
||||||
|
if (!attrs_to_read)
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
source_nofollow_symlinks = flags & G_FILE_COPY_NOFOLLOW_SYMLINKS;
|
source_nofollow_symlinks = flags & G_FILE_COPY_NOFOLLOW_SYMLINKS;
|
||||||
@ -3157,6 +3183,7 @@ file_copy_fallback (GFile *source,
|
|||||||
char *attrs_to_read;
|
char *attrs_to_read;
|
||||||
gboolean do_set_attributes = FALSE;
|
gboolean do_set_attributes = FALSE;
|
||||||
GFileCreateFlags create_flags;
|
GFileCreateFlags create_flags;
|
||||||
|
GError *tmp_error = NULL;
|
||||||
|
|
||||||
/* need to know the file type */
|
/* need to know the file type */
|
||||||
info = g_file_query_info (source,
|
info = g_file_query_info (source,
|
||||||
@ -3198,47 +3225,43 @@ file_copy_fallback (GFile *source,
|
|||||||
goto out;
|
goto out;
|
||||||
in = G_INPUT_STREAM (file_in);
|
in = G_INPUT_STREAM (file_in);
|
||||||
|
|
||||||
if (!build_attribute_list_for_copy (destination, flags, &attrs_to_read,
|
attrs_to_read = g_file_build_attribute_list_for_copy (destination, flags,
|
||||||
cancellable, error))
|
cancellable, error);
|
||||||
|
if (!attrs_to_read)
|
||||||
goto out;
|
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;
|
/* Not all gvfs backends implement query_info_on_read(), we
|
||||||
|
* can just fall back to the pathname again.
|
||||||
/* Ok, ditch the previous lightweight info (on Unix we just
|
* https://bugzilla.gnome.org/706254
|
||||||
* called lstat()); at this point we gather all the information
|
|
||||||
* we need about the source from the opened file descriptor.
|
|
||||||
*/
|
*/
|
||||||
g_object_unref (info);
|
if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
||||||
|
|
||||||
info = g_file_input_stream_query_info (file_in, attrs_to_read,
|
|
||||||
cancellable, &tmp_error);
|
|
||||||
if (!info)
|
|
||||||
{
|
{
|
||||||
/* Not all gvfs backends implement query_info_on_read(), we
|
g_clear_error (&tmp_error);
|
||||||
* can just fall back to the pathname again.
|
info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||||
* https://bugzilla.gnome.org/706254
|
cancellable, error);
|
||||||
*/
|
}
|
||||||
if (g_error_matches (tmp_error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED))
|
else
|
||||||
{
|
{
|
||||||
g_clear_error (&tmp_error);
|
g_free (attrs_to_read);
|
||||||
info = g_file_query_info (source, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
g_propagate_error (error, tmp_error);
|
||||||
cancellable, error);
|
goto out;
|
||||||
}
|
|
||||||
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
|
/* In the local file path, we pass down the source info which
|
||||||
* includes things like unix::mode, to ensure that the target file
|
* includes things like unix::mode, to ensure that the target file
|
||||||
|
@ -1094,6 +1094,12 @@ gboolean g_file_eject_mountable_with_operation_finish (GFile
|
|||||||
GAsyncResult *result,
|
GAsyncResult *result,
|
||||||
GError **error);
|
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
|
GLIB_AVAILABLE_IN_ALL
|
||||||
gboolean g_file_copy_attributes (GFile *source,
|
gboolean g_file_copy_attributes (GFile *source,
|
||||||
GFile *destination,
|
GFile *destination,
|
||||||
|
@ -1780,6 +1780,79 @@ test_writev_async_all_too_big_vectors (void)
|
|||||||
g_object_unref (file);
|
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
|
int
|
||||||
main (int argc, char *argv[])
|
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-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-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/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 ();
|
return g_test_run ();
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user