summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMaxim Mikityanskiy <maxtram95@gmail.com>2020-08-16 17:56:03 +0300
committerMaxim Mikityanskiy <maxtram95@gmail.com>2021-01-09 16:33:49 +0200
commitf29b4839187c0ab18dd2cf1fd99c7cb734cab8ff (patch)
treec2d38dc9f19d0e152e1088a4070b002897391b29
parent96b466877071a1e458e1597338fc5cb3e712af52 (diff)
downloadnautilus-f29b4839187c0ab18dd2cf1fd99c7cb734cab8ff.tar.gz
file-operations: Preserve mtime of non-empty directories on move
Nautilus follows this algorithm when copying or moving directories: 1. Create the destination directory. 2. Copy/move the old directory contents recursively. 3. g_file_copy_attributes from the old directory to the new. 4. Delete the old directory. The issue is that when moving a non-empty directory, step 2 leads to modification of the old directory's mtime, so g_file_copy_attributes copies the attributes that were already lost at that point. This commit fixes it by splitting g_file_copy_attributes into two steps. It depends on glib!1449. Closes: gvfs#471 Signed-off-by: Maxim Mikityanskiy <maxtram95@gmail.com>
-rw-r--r--meson.build2
-rw-r--r--src/nautilus-file-operations.c32
2 files changed, 27 insertions, 7 deletions
diff --git a/meson.build b/meson.build
index a5413d54c..3d9aaa340 100644
--- a/meson.build
+++ b/meson.build
@@ -93,7 +93,7 @@ pkgconfig = import('pkgconfig')
################
# Dependencies #
################
-glib_ver = '>= 2.62.0'
+glib_ver = '>= 2.67.1'
libgd = subproject(
'libgd',
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 3adf3b54c..43ed33941 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -4762,6 +4762,7 @@ copy_move_directory (CopyMoveJob *copy_job,
gboolean *skipped_file,
gboolean readonly_source_fs)
{
+ g_autoptr (GFileInfo) src_info = NULL;
GFileInfo *info;
GError *error;
GFile *src_file;
@@ -4778,6 +4779,8 @@ copy_move_directory (CopyMoveJob *copy_job,
if (create_dest)
{
+ g_autofree char *attrs_to_read = NULL;
+
switch (create_dest_dir (job, src, dest, same_fs, parent_dest_fs_type))
{
case CREATE_DEST_DIR_RETRY:
@@ -4806,6 +4809,23 @@ copy_move_directory (CopyMoveJob *copy_job,
{
g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (TRUE));
}
+
+ flags = G_FILE_COPY_NOFOLLOW_SYMLINKS;
+ if (readonly_source_fs)
+ {
+ flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS;
+ }
+ if (copy_job->is_move)
+ {
+ flags |= G_FILE_COPY_ALL_METADATA;
+ }
+
+ /* Ignore errors here. Failure to copy metadata is not a hard error */
+ attrs_to_read = g_file_build_attribute_list_for_copy (*dest, flags, job->cancellable, NULL);
+ if (attrs_to_read != NULL)
+ {
+ src_info = g_file_query_info (src, attrs_to_read, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, job->cancellable, NULL);
+ }
}
local_skipped_file = FALSE;
@@ -4971,14 +4991,14 @@ retry:
}
}
- if (create_dest)
+ if (src_info != NULL)
{
- flags = (readonly_source_fs) ? G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_PERMS
- : G_FILE_COPY_NOFOLLOW_SYMLINKS;
/* Ignore errors here. Failure to copy metadata is not a hard error */
- g_file_copy_attributes (src, *dest,
- flags,
- job->cancellable, NULL);
+ g_file_set_attributes_from_info (*dest,
+ src_info,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ job->cancellable,
+ NULL);
}
if (!job_aborted (job) && copy_job->is_move &&