summaryrefslogtreecommitdiff
path: root/src/nautilus-file-operations.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nautilus-file-operations.c')
-rw-r--r--src/nautilus-file-operations.c563
1 files changed, 223 insertions, 340 deletions
diff --git a/src/nautilus-file-operations.c b/src/nautilus-file-operations.c
index 8ec8f064d..26d07044b 100644
--- a/src/nautilus-file-operations.c
+++ b/src/nautilus-file-operations.c
@@ -1604,229 +1604,150 @@ report_delete_progress (CommonJob *job,
}
}
-static void delete_file (CommonJob *job, GFile *file,
- gboolean *skipped_file,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- gboolean toplevel);
+typedef void (*DeleteCallback) (GFile *file,
+ GError *error,
+ gpointer callback_data);
-static void
-delete_dir (CommonJob *job, GFile *dir,
- gboolean *skipped_file,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- gboolean toplevel)
+static gboolean
+delete_file_recursively (GFile *file,
+ GCancellable *cancellable,
+ DeleteCallback callback,
+ gpointer callback_data)
{
- GFileInfo *info;
- GError *error;
- GFile *file;
- GFileEnumerator *enumerator;
- char *primary, *secondary, *details;
- int response;
- gboolean skip_error;
- gboolean local_skipped_file;
+ gboolean success;
+ g_autoptr (GError) error = NULL;
- local_skipped_file = FALSE;
-
- skip_error = should_skip_readdir_error (job, dir);
- retry:
- error = NULL;
- enumerator = g_file_enumerate_children (dir,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- job->cancellable,
- &error);
- if (enumerator) {
- error = NULL;
-
- while (!job_aborted (job) &&
- (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
- file = g_file_get_child (dir,
- g_file_info_get_name (info));
- delete_file (job, file, &local_skipped_file, source_info, transfer_info, FALSE);
- g_object_unref (file);
- g_object_unref (info);
- }
- g_file_enumerator_close (enumerator, job->cancellable, NULL);
- g_object_unref (enumerator);
-
- if (error && IS_IO_ERROR (error, CANCELLED)) {
- g_error_free (error);
- } else if (error) {
- primary = f (_("Error while deleting."));
- details = NULL;
-
- if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
- secondary = f (_("Files in the folder “%B” cannot be deleted because you do "
- "not have permissions to see them."), dir);
- } else {
- secondary = f (_("There was an error getting information about the files in the folder “%B”."), dir);
- details = error->message;
- }
-
- response = run_warning (job,
- primary,
- secondary,
- details,
- FALSE,
- CANCEL, _("_Skip files"),
- NULL);
-
- g_error_free (error);
-
- if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
- abort_job (job);
- } else if (response == 1) {
- /* Skip: Do Nothing */
- local_skipped_file = TRUE;
- } else {
- g_assert_not_reached ();
- }
- }
-
- } else if (IS_IO_ERROR (error, CANCELLED)) {
- g_error_free (error);
- } else {
- primary = f (_("Error while deleting."));
- details = NULL;
- if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
- secondary = f (_("The folder “%B” cannot be deleted because you do not have "
- "permissions to read it."), dir);
- } else {
- secondary = f (_("There was an error reading the folder “%B”."), dir);
- details = error->message;
- }
-
- response = run_warning (job,
- primary,
- secondary,
- details,
- FALSE,
- CANCEL, SKIP, RETRY,
- NULL);
+ do {
+ g_autoptr (GFileEnumerator) enumerator = NULL;
- g_error_free (error);
+ success = g_file_delete (file, cancellable, &error);
+ if (success ||
+ !g_error_matches (error, G_IO_ERROR, G_IO_ERROR_NOT_EMPTY)) {
+ break;
+ }
- if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
- abort_job (job);
- } else if (response == 1) {
- /* Skip: Do Nothing */
- local_skipped_file = TRUE;
- } else if (response == 2) {
- goto retry;
- } else {
- g_assert_not_reached ();
- }
- }
+ g_clear_error (&error);
- if (!job_aborted (job) &&
- /* Don't delete dir if there was a skipped file */
- !local_skipped_file) {
- if (!g_file_delete (dir, job->cancellable, &error)) {
- if (job->skip_all_error) {
- goto skip;
- }
- primary = f (_("Error while deleting."));
- secondary = f (_("Could not remove the folder %B."), dir);
- details = error->message;
+ enumerator = g_file_enumerate_children (file,
+ G_FILE_ATTRIBUTE_STANDARD_NAME,
+ G_FILE_QUERY_INFO_NONE,
+ cancellable, &error);
- response = run_cancel_or_skip_warning (job,
- primary,
- secondary,
- details,
- source_info->num_files,
- source_info->num_files - transfer_info->num_files);
-
- if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
- abort_job (job);
- } else if (response == 1) { /* skip all */
- job->skip_all_error = TRUE;
- local_skipped_file = TRUE;
- } else if (response == 2) { /* skip */
- local_skipped_file = TRUE;
- } else {
- g_assert_not_reached ();
- }
-
- skip:
- g_error_free (error);
- } else {
- nautilus_file_changes_queue_file_removed (dir);
- transfer_info->num_files ++;
- report_delete_progress (job, source_info, transfer_info);
- return;
- }
- }
+ if (enumerator) {
+ GFileInfo *info;
- if (local_skipped_file) {
- *skipped_file = TRUE;
- }
+ success = TRUE;
+
+ info = g_file_enumerator_next_file (enumerator,
+ cancellable,
+ &error);
+
+ while (info != NULL) {
+ g_autoptr (GFile) child;
+
+ child = g_file_enumerator_get_child (enumerator, info);
+
+ success = success && delete_file_recursively (child,
+ cancellable,
+ callback,
+ callback_data);
+
+ g_object_unref (info);
+
+ info = g_file_enumerator_next_file (enumerator,
+ cancellable,
+ &error);
+ }
+ }
+
+ if (error != NULL) {
+ success = FALSE;
+ }
+ } while (success);
+
+ if (callback) {
+ callback (file, error, callback_data);
+ }
+
+ return success;
}
+typedef struct {
+ CommonJob *job;
+ SourceInfo *source_info;
+ TransferInfo *transfer_info;
+} DeleteData;
+
static void
-delete_file (CommonJob *job, GFile *file,
- gboolean *skipped_file,
- SourceInfo *source_info,
- TransferInfo *transfer_info,
- gboolean toplevel)
-{
- GError *error;
- char *primary, *secondary, *details;
- int response;
+file_deleted_callback (GFile *file,
+ GError *error,
+ gpointer callback_data)
+{
+ DeleteData *data = callback_data;
+ CommonJob *job;
+ SourceInfo *source_info;
+ TransferInfo *transfer_info;
+ GFileType file_type;
+ char *primary;
+ char *secondary;
+ char *details = NULL;
+ int response;
+
+ job = data->job;
+ source_info = data->source_info;
+ transfer_info = data->transfer_info;
+
+ data->transfer_info->num_files++;
+
+ if (error == NULL) {
+ nautilus_file_changes_queue_file_removed (file);
+ report_delete_progress (data->job, data->source_info, data->transfer_info);
- if (should_skip_file (job, file)) {
- *skipped_file = TRUE;
- return;
- }
-
- error = NULL;
- if (g_file_delete (file, job->cancellable, &error)) {
- nautilus_file_changes_queue_file_removed (file);
- transfer_info->num_files ++;
- report_delete_progress (job, source_info, transfer_info);
- return;
- }
+ return;
+ }
- if (IS_IO_ERROR (error, NOT_EMPTY)) {
- g_error_free (error);
- delete_dir (job, file,
- skipped_file,
- source_info, transfer_info,
- toplevel);
- return;
-
- } else if (IS_IO_ERROR (error, CANCELLED)) {
- g_error_free (error);
-
- } else {
- if (job->skip_all_error) {
- goto skip;
- }
- primary = f (_("Error while deleting."));
- secondary = f (_("There was an error deleting %B."), file);
- details = error->message;
-
- response = run_cancel_or_skip_warning (job,
- primary,
- secondary,
- details,
- source_info->num_files,
- source_info->num_files - transfer_info->num_files);
+ if (job_aborted (job) ||
+ job->skip_all_error ||
+ should_skip_file (job, file) ||
+ should_skip_readdir_error (job, file)) {
+ return;
+ }
- 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 ();
- }
- skip:
- g_error_free (error);
- }
-
- *skipped_file = TRUE;
+ primary = f (_("Error while deleting."));
+
+ file_type = g_file_query_file_type (file,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ job->cancellable);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ secondary = IS_IO_ERROR (error, PERMISSION_DENIED) ?
+ f (_("There was an error deleting the folder “%B”."),
+ file) :
+ f (_("You do not have sufficient permissions to delete the folder “%B”."),
+ file);
+ } else {
+ secondary = IS_IO_ERROR (error, PERMISSION_DENIED) ?
+ f (_("There was an error deleting the file “%B”."),
+ file) :
+ f (_("You do not have sufficient permissions to delete the file “%B”."),
+ file);
+ }
+
+ details = error->message;
+
+ response = run_cancel_or_skip_warning (job,
+ primary,
+ secondary,
+ details,
+ source_info->num_files,
+ source_info->num_files - transfer_info->num_files);
+
+ if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
+ abort_job (job);
+ } else if (response == 1) {
+ /* skip all */
+ job->skip_all_error = TRUE;
+ }
}
static void
@@ -1836,7 +1757,7 @@ delete_files (CommonJob *job, GList *files, int *files_skipped)
GFile *file;
SourceInfo source_info;
TransferInfo transfer_info;
- gboolean skipped_file;
+ DeleteData data;
if (job_aborted (job)) {
return;
@@ -1854,20 +1775,30 @@ delete_files (CommonJob *job, GList *files, int *files_skipped)
memset (&transfer_info, 0, sizeof (transfer_info));
report_delete_progress (job, &source_info, &transfer_info);
+
+ data.job = job;
+ data.source_info = &source_info;
+ data.transfer_info = &transfer_info;
for (l = files;
l != NULL && !job_aborted (job);
l = l->next) {
+ gboolean success;
+
file = l->data;
- skipped_file = FALSE;
- delete_file (job, file,
- &skipped_file,
- &source_info, &transfer_info,
- TRUE);
- if (skipped_file) {
- (*files_skipped)++;
- }
+ if (should_skip_file (job, file)) {
+ (*files_skipped)++;
+ continue;
+ }
+
+ success = delete_file_recursively (file, job->cancellable,
+ file_deleted_callback,
+ &data);
+
+ if (!success) {
+ (*files_skipped)++;
+ }
}
}
@@ -4138,131 +4069,72 @@ copy_move_directory (CopyMoveJob *copy_job,
return TRUE;
}
-static gboolean
-remove_target_recursively (CommonJob *job,
- GFile *src,
- GFile *toplevel_dest,
- GFile *file)
+
+typedef struct {
+ CommonJob *job;
+ GFile *source;
+} DeleteExistingFileData;
+
+static void
+existing_file_removed_callback (GFile *file,
+ GError *error,
+ gpointer callback_data)
{
- GFileEnumerator *enumerator;
- GError *error;
- GFile *child;
- gboolean stop;
- char *primary, *secondary, *details;
- int response;
- GFileInfo *info;
+ DeleteExistingFileData *data = callback_data;
+ CommonJob *job;
+ GFile *source;
+ GFileType file_type;
+ char *primary;
+ char *secondary;
+ char *details = NULL;
+ int response;
- stop = FALSE;
-
- error = NULL;
- enumerator = g_file_enumerate_children (file,
- G_FILE_ATTRIBUTE_STANDARD_NAME,
- G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
- job->cancellable,
- &error);
- if (enumerator) {
- error = NULL;
-
- while (!job_aborted (job) &&
- (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 (child);
- g_object_unref (info);
- }
- g_file_enumerator_close (enumerator, job->cancellable, NULL);
- g_object_unref (enumerator);
-
- } else if (IS_IO_ERROR (error, NOT_DIRECTORY)) {
- /* Not a dir, continue */
- g_error_free (error);
-
- } else if (IS_IO_ERROR (error, CANCELLED)) {
- g_error_free (error);
- } else {
- if (job->skip_all_error) {
- goto skip1;
- }
-
- primary = f (_("Error while copying “%B”."), src);
- secondary = f (_("Could not remove files from the already existing folder %F."), file);
- details = error->message;
+ job = data->job;
+ source = data->source;
- /* 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;
- } else if (response == 2) { /* skip */
- /* do nothing */
- } else {
- g_assert_not_reached ();
- }
- skip1:
- g_error_free (error);
-
- stop = TRUE;
- }
+ if (error == NULL) {
+ nautilus_file_changes_queue_file_removed (file);
- if (stop) {
- return FALSE;
- }
+ return;
+ }
- error = NULL;
-
- if (!g_file_delete (file, job->cancellable, &error)) {
- if (job->skip_all_error ||
- IS_IO_ERROR (error, CANCELLED)) {
- goto skip2;
- }
- primary = f (_("Error while copying “%B”."), src);
- secondary = f (_("Could not remove the already existing file %F."), file);
- details = error->message;
+ if (job_aborted (job) || job->skip_all_error) {
+ return;
+ }
- /* 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;
- } else if (response == 2) { /* skip */
- /* do nothing */
- } else {
- g_assert_not_reached ();
- }
+ primary = f (_("Error while copying “%B”."), source);
- skip2:
- g_error_free (error);
-
- return FALSE;
- }
- nautilus_file_changes_queue_file_removed (file);
-
- return TRUE;
-
+ file_type = g_file_query_file_type (file,
+ G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
+ job->cancellable);
+
+ if (file_type == G_FILE_TYPE_DIRECTORY) {
+ secondary = f (_("Could not remove the already existing folder %F."),
+ file);
+ } else {
+ secondary = f (_("Could not remove the already existing file %F."),
+ file);
+ }
+
+ 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 {
@@ -4806,12 +4678,23 @@ copy_move_file (CopyMoveJob *copy_job,
else if (overwrite &&
IS_IO_ERROR (error, IS_DIRECTORY)) {
+ gboolean existing_file_deleted;
+ DeleteExistingFileData data;
g_error_free (error);
-
- if (remove_target_recursively (job, src, dest, dest)) {
- goto retry;
- }
+
+ 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 */