diff options
author | Maxim Mikityanskiy <maxtram95@gmail.com> | 2020-08-16 17:56:03 +0300 |
---|---|---|
committer | Maxim Mikityanskiy <maxtram95@gmail.com> | 2021-01-09 16:33:49 +0200 |
commit | f29b4839187c0ab18dd2cf1fd99c7cb734cab8ff (patch) | |
tree | c2d38dc9f19d0e152e1088a4070b002897391b29 | |
parent | 96b466877071a1e458e1597338fc5cb3e712af52 (diff) | |
download | nautilus-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.build | 2 | ||||
-rw-r--r-- | src/nautilus-file-operations.c | 32 |
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 && |