Index: libnautilus-private/nautilus-file-operations.c =================================================================== --- libnautilus-private/nautilus-file-operations.c (revision 14108) +++ libnautilus-private/nautilus-file-operations.c (working copy) @@ -3224,6 +3224,24 @@ } } +static gboolean +g_file_struct_contains (GFile *child, GFile *root) +{ + GFile *f; + + f = g_file_dup (child); + while (f) { + if (g_file_equal (f, root)) { + g_object_unref (f); + return TRUE; + } + f = g_file_get_parent (f); + } + + if (f) g_object_unref (f); + return FALSE; +} + /* Debuting files is non-NULL only for toplevel items */ static void copy_move_file (CopyMoveJob *copy_job, @@ -3264,6 +3282,41 @@ dest = get_target_file (src, dest_dir, same_fs); } + + /* Don't allow recursive move/copy into itself. + * (We would get a file system error if we proceeded but it is nicer to + * detect and report it at this level) */ + if (g_file_struct_contains (dest_dir, src)) { + if (job->skip_all_error) { + g_error_free (error); + goto out; + } + + /* the run_warning() frees all strings passed in automatically */ + primary = copy_job->is_move ? g_strdup (_("You cannot move a folder into itself.")) + : g_strdup (_("You cannot copy a folder into itself.")); + secondary = g_strdup (_("The destination folder is inside the source folder.")); + + response = run_warning (job, + primary, + secondary, + NULL, + GTK_STOCK_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; + } else if (response == 2) { /* skip */ + /* do nothing */ + } else { + g_assert_not_reached (); + } + + goto out; + } + retry: error = NULL; @@ -3791,6 +3844,41 @@ dest = get_target_file (src, dest_dir, same_fs); + + /* Don't allow recursive move/copy into itself. + * (We would get a file system error if we proceeded but it is nicer to + * detect and report it at this level) */ + if (g_file_struct_contains (dest_dir, src)) { + if (job->skip_all_error) { + g_error_free (error); + goto out; + } + + /* the run_warning() frees all strings passed in automatically */ + primary = move_job->is_move ? g_strdup (_("You cannot move a folder into itself.")) + : g_strdup (_("You cannot copy a folder into itself.")); + secondary = g_strdup (_("The destination folder is inside the source folder.")); + + response = run_warning (job, + primary, + secondary, + NULL, + GTK_STOCK_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; + } else if (response == 2) { /* skip */ + /* do nothing */ + } else { + g_assert_not_reached (); + } + + goto out; + } + retry: flags = G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_NO_FALLBACK_FOR_MOVE;