diff options
author | Ernestas Kulik <ernestask@gnome.org> | 2017-07-24 12:55:31 +0300 |
---|---|---|
committer | Ernestas Kulik <ernestask@gnome.org> | 2017-08-28 19:49:54 +0300 |
commit | 1349a35c54dabe8db63af99898962b65e6566c10 (patch) | |
tree | 52609affafbb33dbf05a50c8cdb6cab0dc38850e | |
parent | ee3bcfb234510b3665ffb82a8514c8200891eb44 (diff) | |
download | nautilus-1349a35c54dabe8db63af99898962b65e6566c10.tar.gz |
file-operations: fail when overwriting directory with file
GIO documentation (and therefore code) mandates that copies and moves of
files over directories should fail, but Nautilus has support for such
(possibly dangerous) operations even to this day. This commit works with
the assumption that whatever backend happens to be used, it will fail as
expected and not overwrite the directory.
https://bugzilla.gnome.org/show_bug.cgi?id=773671
-rw-r--r-- | src/nautilus-file-operations.c | 143 |
1 files changed, 30 insertions, 113 deletions
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c index 3cb9335f4..02dabf587 100644 --- a/src/nautilus-file-operations.c +++ b/src/nautilus-file-operations.c @@ -4322,21 +4322,13 @@ has_fs_id (GFile *file, static gboolean is_dir (GFile *file) { - GFileInfo *info; - gboolean res; + GFileType file_type; - res = FALSE; - info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_TYPE, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, NULL); - if (info) - { - res = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY; - g_object_unref (info); - } + file_type = g_file_query_file_type (file, + G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, + NULL); - return res; + return file_type == G_FILE_TYPE_DIRECTORY; } static GFile * @@ -4883,80 +4875,6 @@ typedef struct GFile *source; } DeleteExistingFileData; -static void -existing_file_removed_callback (GFile *file, - GError *error, - gpointer callback_data) -{ - DeleteExistingFileData *data = callback_data; - CommonJob *job; - GFile *source; - GFileType file_type; - char *primary; - char *secondary; - char *details = NULL; - int response; - g_autofree gchar *basename = NULL; - g_autofree gchar *filename = NULL; - - job = data->job; - source = data->source; - - if (error == NULL) - { - nautilus_file_changes_queue_file_removed (file); - - return; - } - - if (job_aborted (job) || job->skip_all_error) - { - return; - } - - basename = get_basename (source); - primary = g_strdup_printf (_("Error while copying ā%sā."), basename); - - file_type = g_file_query_file_type (file, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - job->cancellable); - - filename = g_file_get_parse_name (file); - if (file_type == G_FILE_TYPE_DIRECTORY) - { - secondary = g_strdup_printf (_("Could not remove the already existing folder %s."), - filename); - } - else - { - secondary = g_strdup_printf (_("Could not remove the already existing file %s."), - filename); - } - - details = error->message; - - /* set show_all to TRUE here, as we don't know how many - * files we'll end up processing yet. - */ - response = run_warning (job, - primary, - secondary, - details, - TRUE, - CANCEL, SKIP_ALL, SKIP, - NULL); - - if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) - { - abort_job (job); - } - else if (response == 1) - { - /* skip all */ - job->skip_all_error = TRUE; - } -} - typedef struct { CopyMoveJob *job; @@ -5411,9 +5329,14 @@ retry: if (!overwrite && IS_IO_ERROR (error, EXISTS)) { + gboolean source_is_directory; + gboolean destination_is_directory; gboolean is_merge; FileConflictResponse *response; + source_is_directory = is_dir (src); + destination_is_directory = is_dir (dest); + g_error_free (error); if (unique_names) @@ -5425,10 +5348,16 @@ retry: is_merge = FALSE; - if (is_dir (dest) && is_dir (src)) + if (source_is_directory && destination_is_directory) { is_merge = TRUE; } + else if (!source_is_directory && destination_is_directory) + { + /* Any sane backend will fail with G_IO_ERROR_IS_DIRECTORY. */ + overwrite = TRUE; + goto retry; + } if ((is_merge && job->merge_all) || (!is_merge && job->replace_all)) @@ -5488,28 +5417,6 @@ retry: g_assert_not_reached (); } } - else if (overwrite && - IS_IO_ERROR (error, IS_DIRECTORY)) - { - gboolean existing_file_deleted; - DeleteExistingFileData data; - - g_error_free (error); - - data.job = job; - data.source = src; - - existing_file_deleted = - delete_file_recursively (dest, - job->cancellable, - existing_file_removed_callback, - &data); - - if (existing_file_deleted) - { - goto retry; - } - } /* Needs to recurse */ else if (IS_IO_ERROR (error, WOULD_RECURSE) || IS_IO_ERROR (error, WOULD_MERGE)) @@ -6154,16 +6061,27 @@ retry: else if (!overwrite && IS_IO_ERROR (error, EXISTS)) { + gboolean source_is_directory; + gboolean destination_is_directory; gboolean is_merge; FileConflictResponse *response; + source_is_directory = is_dir (src); + destination_is_directory = is_dir (dest); + g_error_free (error); is_merge = FALSE; - if (is_dir (dest) && is_dir (src)) + if (source_is_directory && destination_is_directory) { is_merge = TRUE; } + else if (!source_is_directory && destination_is_directory) + { + /* Any sane backend will fail with G_IO_ERROR_IS_DIRECTORY. */ + overwrite = TRUE; + goto retry; + } if ((is_merge && job->merge_all) || (!is_merge && job->replace_all)) @@ -6225,8 +6143,7 @@ retry: } else if (IS_IO_ERROR (error, WOULD_RECURSE) || IS_IO_ERROR (error, WOULD_MERGE) || - IS_IO_ERROR (error, NOT_SUPPORTED) || - (overwrite && IS_IO_ERROR (error, IS_DIRECTORY))) + IS_IO_ERROR (error, NOT_SUPPORTED)) { g_error_free (error); |