[nautilus] file-operations: fail when overwriting directory with file



commit 1349a35c54dabe8db63af99898962b65e6566c10
Author: Ernestas Kulik <ernestask gnome org>
Date:   Mon Jul 24 12:55:31 2017 +0300

    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

 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 3cb9335..02dabf5 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);
 


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]