summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2007-11-21 15:45:14 +0000
committerAlexander Larsson <alexl@src.gnome.org>2007-11-21 15:45:14 +0000
commit9181da817c98aa5e15705b7312c6ea187c600445 (patch)
treedc34f7b42b3f1388b224c70d60495f5b94d19781
parent5097c6293993cbe644e24df684b85f15e086ad70 (diff)
downloadnautilus-9181da817c98aa5e15705b7312c6ea187c600445.tar.gz
Handle deleting a directory when overwriting it with a file.
2007-11-21 Alexander Larsson <alexl@redhat.com> * libnautilus-private/nautilus-file-operations.c: Handle deleting a directory when overwriting it with a file. svn path=/branches/gio-branch/; revision=13436
-rw-r--r--ChangeLog6
-rw-r--r--libnautilus-private/nautilus-file-operations.c136
2 files changed, 138 insertions, 4 deletions
diff --git a/ChangeLog b/ChangeLog
index 1efaffde6..c7bb847c8 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,12 @@
2007-11-21 Alexander Larsson <alexl@redhat.com>
* libnautilus-private/nautilus-file-operations.c:
+ Handle deleting a directory when overwriting it with a
+ file.
+
+2007-11-21 Alexander Larsson <alexl@redhat.com>
+
+ * libnautilus-private/nautilus-file-operations.c:
Handle errors in remove destination
2007-11-21 Alexander Larsson <alexl@redhat.com>
diff --git a/libnautilus-private/nautilus-file-operations.c b/libnautilus-private/nautilus-file-operations.c
index 35236f35a..b5a55ba30 100644
--- a/libnautilus-private/nautilus-file-operations.c
+++ b/libnautilus-private/nautilus-file-operations.c
@@ -4956,6 +4956,127 @@ copy_directory (CommonJob *job,
}
}
+static gboolean
+remove_target_recursively (CommonJob *job,
+ GFile *src,
+ GFile *toplevel_dest,
+ GFile *file)
+{
+ GFileEnumerator *enumerator;
+ GError *error;
+ GFile *child;
+ gboolean stop;
+ char *primary, *secondary, *details;
+ int response;
+ GFileInfo *info;
+
+ stop = FALSE;
+
+ error = NULL;
+ enumerator = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STD_NAME,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ job->cancellable,
+ &error);
+ if (enumerator) {
+ error = NULL;
+
+ while (!job->aborted &&
+ (info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) {
+ child = g_file_get_child (file,
+ g_file_info_get_name (info));
+ if (!remove_target_recursively (job, src, toplevel_dest, child)) {
+ stop = TRUE;
+ break;
+ }
+ g_object_unref (info);
+ }
+ g_file_enumerator_close (enumerator, job->cancellable, NULL);
+
+ } else if (error->domain == G_IO_ERROR &&
+ error->code == G_IO_ERROR_NOT_DIRECTORY) {
+ /* Not a dir, continue */
+ g_error_free (error);
+
+ } else {
+ if (job->skip_all_error) {
+ goto skip1;
+ }
+
+ primary = strdup_with_name (_("Error while copying \"%s\"."), src, job->cancellable);
+ secondary = strdup_with_full_name (_("Couldn't remove files from the already folder %s."), file);
+ details = error->message;
+
+ response = run_simple_dialog (job,
+ FALSE,
+ GTK_MESSAGE_WARNING,
+ primary,
+ secondary,
+ details,
+ GTK_STOCK_CANCEL, _("S_kip All"), _("_Skip"),
+ NULL);
+ g_free (primary);
+ g_free (secondary);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ job->aborted = TRUE;
+ } else if (response == 1) { /* skip all */
+ job->skip_all_error = TRUE;
+ } else if (response == 2) { /* skip */
+ /* do nothing */
+ } else {
+ g_assert_not_reached ();
+ }
+ skip1:
+ g_error_free (error);
+
+ stop = TRUE;
+ }
+
+ if (stop) {
+ return FALSE;
+ }
+
+ error = NULL;
+
+ if (!g_file_delete (file, job->cancellable, &error)) {
+ if (job->skip_all_error) {
+ goto skip2;
+ }
+ primary = strdup_with_name (_("Error while copying \"%s\"."), src, job->cancellable);
+ secondary = strdup_with_full_name (_("Couldn't remove the already existing file %s."), file);
+ details = error->message;
+
+ response = run_simple_dialog (job,
+ FALSE,
+ GTK_MESSAGE_WARNING,
+ primary,
+ secondary,
+ details,
+ GTK_STOCK_CANCEL, _("S_kip All"), _("_Skip"),
+ NULL);
+ g_free (primary);
+ g_free (secondary);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ job->aborted = TRUE;
+ } else if (response == 1) { /* skip all */
+ job->skip_all_error = TRUE;
+ } else if (response == 2) { /* skip */
+ /* do nothing */
+ } else {
+ g_assert_not_reached ();
+ }
+
+ skip2:
+ g_error_free (error);
+
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
typedef struct {
CommonJob *job;
@@ -5000,6 +5121,7 @@ copy_file (CommonJob *job,
char *primary, *secondary, *details;
int response;
ProgressData pdata;
+ gboolean would_recurse;
if (should_skip_file (job, src)) {
return;
@@ -5119,21 +5241,27 @@ copy_file (CommonJob *job,
g_assert_not_reached ();
}
}
-#if 0 /* TODO */
+
else if (overwrite &&
error->domain == G_IO_ERROR &&
error->code == G_IO_ERROR_IS_DIRECTORY) {
- /* TODO: Recursively delete dest, then retry */
+
+ g_error_free (error);
+ if (remove_target_recursively (job, src, dest, dest)) {
+ goto retry;
+ }
}
-#endif
/* Needs to recurse */
else if (error->domain == G_IO_ERROR &&
(error->code == G_IO_ERROR_WOULD_RECURSE ||
error->code == G_IO_ERROR_WOULD_MERGE)) {
- if (overwrite && error->code == G_IO_ERROR_WOULD_RECURSE) {
+ would_recurse = error->code == G_IO_ERROR_WOULD_RECURSE;
+ g_error_free (error);
+
+ if (overwrite && would_recurse) {
error = NULL;
/* Copying a dir onto file, first remove the file */