diff --git a/libcore/FileOperations/CommonJob.vala b/libcore/FileOperations/CommonJob.vala index 0aec44179..8c21c5ab6 100644 --- a/libcore/FileOperations/CommonJob.vala +++ b/libcore/FileOperations/CommonJob.vala @@ -23,20 +23,24 @@ public class Files.FileOperations.CommonJob { [Compact] [CCode (cname = "SourceInfo")] protected class SourceInfo { - [CCode (has_target = false, cname = "CountProgressCallback")] - internal delegate void CountProgressCallback (Files.FileOperations.CommonJob job, Files.FileOperations.CommonJob.SourceInfo info); - internal int num_files; - internal size_t num_bytes; + internal int64 num_bytes; internal int num_files_since_progress; - internal weak CountProgressCallback count_callback; + + public SourceInfo copy () { + return new SourceInfo () { + num_files = this.num_files, + num_bytes = this.num_bytes, + num_files_since_progress = this.num_files_since_progress, + }; + } } [Compact] [CCode (cname = "TransferInfo")] protected class TransferInfo { internal int num_files; - internal size_t num_bytes; + internal int64 num_bytes; internal uint64 last_report_time; internal int last_reported_files_left; } @@ -67,6 +71,15 @@ public class Files.FileOperations.CommonJob { } } + protected virtual unowned string get_scan_primary () { + GLib.warn_if_reached (); + return _("Error while copying."); + } + + protected virtual void report_count_progress (CommonJob.SourceInfo source_info) { + GLib.warn_if_reached (); + } + protected void inhibit_power_manager (string message) { weak Gtk.Application app = (Gtk.Application) GLib.Application.get_default (); inhibit_cookie = app.inhibit ( @@ -257,6 +270,181 @@ public class Files.FileOperations.CommonJob { } } + private void count_file (GLib.FileInfo info, SourceInfo source_info) { + source_info.num_files += 1; + source_info.num_bytes += info.get_size (); + if (source_info.num_files_since_progress++ > 100) { + report_count_progress (source_info); + source_info.num_files_since_progress = 0; + } + } + + private void scan_dir (GLib.File dir, SourceInfo source_info, GLib.Queue dirs) { + var saved_source_info = source_info.copy (); + GLib.FileEnumerator? enumerator = null; + try { + enumerator = dir.enumerate_children (GLib.FileAttribute.STANDARD_NAME + "," + + GLib.FileAttribute.STANDARD_TYPE + "," + + GLib.FileAttribute.STANDARD_SIZE, + GLib.FileQueryInfoFlags.NOFOLLOW_SYMLINKS, + cancellable); + } catch (Error e) { + if (e is GLib.IOError.CANCELLED) { + // Do nothing + } else { + var dir_basename = FileUtils.custom_basename_from_file (dir); + unowned string primary = get_scan_primary (); + string secondary; + string? details = null; + if (e is GLib.IOError.PERMISSION_DENIED) { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("The folder \"%s\" cannot be handled because you do not have permissions to read it.").printf (dir_basename); + } else { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("There was an error reading the folder \"%s\".").printf (dir_basename); + details = e.message; + } + + var response = run_warning (primary, secondary, details, false, CANCEL, RETRY, SKIP); + + if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) { + abort_job (); + } else if (response == 1) { + source_info.num_files = saved_source_info.num_files, + source_info.num_bytes = saved_source_info.num_bytes, + source_info.num_files_since_progress = saved_source_info.num_files_since_progress, + scan_dir (dir, source_info, dirs); + } else if (response == 2) { + skip_readdir_error (dir); + } else { + GLib.assert_not_reached (); + } + } + + return; + } + + try { + unowned GLib.FileInfo? info = null; + unowned GLib.File? child = null; + while (enumerator.iterate (out info, out child, cancellable)) { + count_file (info, source_info); + if (info.get_file_type () == FileType.DIRECTORY) { + /* Push to head, since we want depth-first */ + dirs.push_head (child); + } + } + } catch (Error e) { + if (e is GLib.IOError.CANCELLED) { + // Do nothing + } else { + var dir_basename = FileUtils.custom_basename_from_file (dir); + unowned string primary = get_scan_primary (); + string secondary; + string? details = null; + if (e is GLib.IOError.PERMISSION_DENIED) { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("Files in the folder \"%s\" cannot be handled because you do not have permissions to see them.").printf (dir_basename); + } else { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("There was an error getting information about the files in the folder \"%s\".").printf (dir_basename); + details = e.message; + } + + var response = run_warning (primary, secondary, details, false, CANCEL, SKIP_ALL, SKIP, RETRY); + + if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) { + abort_job (); + } else if (response == 1) { + source_info = saved_source_info; + scan_dir (dir, source_info, dirs); + } else if (response == 2) { + skip_readdir_error (dir); + } else { + GLib.assert_not_reached (); + } + } + } + } + + private void scan_file (GLib.File file, SourceInfo source_info, GLib.Queue dirs = new GLib.Queue ()) { + try { + var info = file.query_info (GLib.FileAttribute.STANDARD_TYPE + "," + GLib.FileAttribute.STANDARD_SIZE, NOFOLLOW_SYMLINKS, cancellable); + count_file (info, source_info); + if (info.get_file_type () == GLib.FileType.DIRECTORY) { + dirs.push_head (file); + } + } catch (Error e) { + if (skip_all_error) { + skip_file (file); + } else if (e is GLib.IOError.CANCELLED) { + // Do nothing + } else { + var file_basename = FileUtils.custom_basename_from_file (file); + unowned string? primary = get_scan_primary (); + string secondary; + string? details = null; + + if (e is GLib.IOError.PERMISSION_DENIED) { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("The file \"%s\" cannot be handled because you do not have permissions to read it.").printf (file_basename); + } else { + /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed + /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) + secondary = _("There was an error getting information about \"%s\".").printf (file_basename); + details = e.message; + } + + /* set show_all to TRUE here, as we don't know how many + * files we'll end up processing yet. + */ + var response = run_warning (primary, secondary, details, true, CANCEL, SKIP_ALL, SKIP, RETRY); + + if (response == 0 || response == Gtk.ResponseType.DELETE_EVENT) { + abort_job (); + } else if (response == 1 || response == 2) { + if (response == 1) { + skip_all_error = true; + } + + skip_file (file); + } else if (response == 3) { + scan_file (file, source_info, dirs); + } else { + GLib.assert_not_reached (); + } + } + } + + GLib.File? dir = null; + while (!aborted () && (dir = dirs.pop_head ()) != null) { + scan_dir (dir, source_info, dirs); + } + } + + protected SourceInfo scan_sources (GLib.List files) { + var source_info = new SourceInfo (); + + report_count_progress (source_info); + foreach (var file in files) { + if (aborted ()) { + return source_info; + } + + scan_file (file, source_info); + } + + /* Make sure we report the final count */ + report_count_progress (source_info); + return source_info; + } + + private int run_simple_dialog_va (Gtk.MessageType message_type, owned string primary_text, owned string secondary_text, diff --git a/libcore/FileOperations/CopyMoveJob.vala b/libcore/FileOperations/CopyMoveJob.vala index 508c49cd8..217982332 100644 --- a/libcore/FileOperations/CopyMoveJob.vala +++ b/libcore/FileOperations/CopyMoveJob.vala @@ -43,7 +43,15 @@ public class Files.FileOperations.CopyMoveJob : CommonJob { is_move = true; } - protected void report_copy_move_count_progress (CommonJob.SourceInfo source_info) { + protected override unowned string get_scan_primary () { + if (is_move) { + return _("Error while moving."); + } else { + return _("Error while copying."); + } + } + + protected override void report_count_progress (CommonJob.SourceInfo source_info) { string s; string num_bytes_format = GLib.format_size (source_info.num_bytes); @@ -190,7 +198,7 @@ public class Files.FileOperations.CopyMoveJob : CommonJob { progress.take_status ((owned) s); } - var total_size = size_t.max (source_info.num_bytes, transfer_info.num_bytes); + var total_size = int64.max (source_info.num_bytes, transfer_info.num_bytes); double elapsed = time.elapsed (); double transfer_rate = 0; diff --git a/libcore/FileOperations/DeleteJob.vala b/libcore/FileOperations/DeleteJob.vala index 0d8bab997..f834f50b1 100644 --- a/libcore/FileOperations/DeleteJob.vala +++ b/libcore/FileOperations/DeleteJob.vala @@ -39,6 +39,10 @@ public class Files.FileOperations.DeleteJob : CommonJob { this.user_cancel = false; } + protected override unowned string get_scan_primary () { + return _("Error while deleting."); + } + protected bool confirm_delete_from_trash (GLib.List to_delete_files) { string prompt; @@ -131,7 +135,7 @@ public class Files.FileOperations.DeleteJob : CommonJob { } } - protected void report_delete_count_progress (CommonJob.SourceInfo source_info) { + protected override void report_count_progress (CommonJob.SourceInfo source_info) { /// TRANSLATORS: %'d is a placeholder for a number. It must not be translated or removed. /// %s is a placeholder for a size like "2 bytes" or "3 MB". It must not be translated or removed. /// So this represents something like "Preparing to delete 100 files (200 MB)" diff --git a/libcore/marlin-file-operations.c b/libcore/marlin-file-operations.c index 6610499ce..495fb4ae9 100644 --- a/libcore/marlin-file-operations.c +++ b/libcore/marlin-file-operations.c @@ -49,11 +49,6 @@ #define IS_IO_ERROR(__error, KIND) (((__error)->domain == G_IO_ERROR && (__error)->code == G_IO_ERROR_ ## KIND)) -static void scan_sources (GList *files, - SourceInfo *source_info, - CountProgressCallback count_callback, - FilesFileOperationsCommonJob *job); - static char * query_fs_type (GFile *file, GCancellable *cancellable); @@ -324,7 +319,7 @@ delete_files (FilesFileOperationsDeleteJob *del_job, GList *files, int *files_sk { GList *l; GFile *file; - SourceInfo source_info; + SourceInfo *source_info; TransferInfo transfer_info; gboolean skipped_file; FilesFileOperationsCommonJob *job = MARLIN_FILE_OPERATIONS_COMMON_JOB (del_job); @@ -333,18 +328,16 @@ delete_files (FilesFileOperationsDeleteJob *del_job, GList *files, int *files_sk return; } - scan_sources (files, - &source_info, - (CountProgressCallback) marlin_file_operations_delete_job_report_delete_count_progress, - job); + source_info = marlin_file_operations_common_job_scan_sources (job, files); if (marlin_file_operations_common_job_aborted (job)) { + g_clear_pointer (&source_info, marlin_file_operations_common_job_source_info_free); return; } g_timer_start (job->time); memset (&transfer_info, 0, sizeof (transfer_info)); - marlin_file_operations_delete_job_report_delete_progress (del_job, &source_info, &transfer_info); + marlin_file_operations_delete_job_report_delete_progress (del_job, source_info, &transfer_info); for (l = files; l != NULL && !marlin_file_operations_common_job_aborted (job); @@ -354,13 +347,15 @@ delete_files (FilesFileOperationsDeleteJob *del_job, GList *files, int *files_sk skipped_file = FALSE; delete_file (del_job, file, &skipped_file, - &source_info, &transfer_info, + source_info, &transfer_info, TRUE); if (skipped_file) { (*files_skipped)++; } } + g_clear_pointer (&source_info, marlin_file_operations_common_job_source_info_free); + PFSoundManager *sm; sm = pf_sound_manager_get_instance (); /* returns unowned instance - no need to unref */ pf_sound_manager_play_delete_sound (sm); @@ -669,301 +664,6 @@ marlin_file_operations_delete_finish (GAsyncResult *result, return g_task_propagate_boolean (G_TASK (result), error); } -static void -count_file (GFileInfo *info, - FilesFileOperationsCommonJob *job, - SourceInfo *source_info) -{ - source_info->num_files += 1; - source_info->num_bytes += g_file_info_get_size (info); - - if (source_info->num_files_since_progress++ > 100) { - source_info->count_callback (job, source_info); - source_info->num_files_since_progress = 0; - } -} - -static char * -get_scan_primary (FilesFileOperationsCommonJob *job) -{ - g_assert (MARLIN_FILE_OPERATIONS_IS_COMMON_JOB (job)); - - if (MARLIN_FILE_OPERATIONS_IS_DELETE_JOB (job)) { - return g_strdup (_("Error while deleting.")); - } else if (MARLIN_FILE_OPERATIONS_IS_COPY_MOVE_JOB (job)) { - FilesFileOperationsCopyMoveJob *move_job = MARLIN_FILE_OPERATIONS_COPY_MOVE_JOB (job); - if (move_job->is_move) { - return g_strdup (_("Error while moving.")); - } else { - return g_strdup (_("Error while copying.")); - } - } else { - g_warn_if_reached (); - return g_strdup (_("Error while copying.")); - } -} - -static void -scan_dir (GFile *dir, - SourceInfo *source_info, - FilesFileOperationsCommonJob *job, - GQueue *dirs) -{ - GFileInfo *info; - GError *error; - GFile *subdir; - GFileEnumerator *enumerator; - char *primary, *secondary, *details; - int response; - SourceInfo saved_info; - - saved_info = *source_info; - -retry: - error = NULL; - enumerator = g_file_enumerate_children (dir, - G_FILE_ATTRIBUTE_STANDARD_NAME"," - G_FILE_ATTRIBUTE_STANDARD_TYPE"," - G_FILE_ATTRIBUTE_STANDARD_SIZE, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - job->cancellable, - &error); - if (enumerator) { - error = NULL; - while ((info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) { - count_file (info, job, source_info); - - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { - subdir = g_file_get_child (dir, - g_file_info_get_name (info)); - - /* Push to head, since we want depth-first */ - g_queue_push_head (dirs, subdir); - } - - 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) { - gchar *dir_basename = files_file_utils_custom_basename_from_file (dir); - primary = get_scan_primary (job); - details = NULL; - - if (IS_IO_ERROR (error, PERMISSION_DENIED)) { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("Files in the folder \"%s\" cannot be handled because you do " - "not have permissions to see them."), dir_basename); - } else { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("There was an error getting information about the files in the folder \"%s\"."), dir_basename); - details = error->message; - } - - g_free (dir_basename); - response = marlin_file_operations_common_job_run_warning ( - job, - primary, - secondary, - details, - FALSE, - CANCEL, RETRY, SKIP, - NULL); - - g_error_free (error); - - if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { - marlin_file_operations_common_job_abort_job (job); - } else if (response == 1) { - *source_info = saved_info; - goto retry; - } else if (response == 2) { - marlin_file_operations_common_job_skip_readdir_error (job, dir); - } else { - g_assert_not_reached (); - } - } - - } else if (job->skip_all_error) { - g_error_free (error); - marlin_file_operations_common_job_skip_file (job, dir); - } else if (IS_IO_ERROR (error, CANCELLED)) { - g_error_free (error); - } else { - gchar *dir_basename = files_file_utils_custom_basename_from_file (dir); - primary = get_scan_primary (job); - details = NULL; - - if (IS_IO_ERROR (error, PERMISSION_DENIED)) { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("The folder \"%s\" cannot be handled because you do not have " - "permissions to read it."), dir_basename); - } else { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("There was an error reading the folder \"%s\"."), dir_basename); - details = error->message; - } - - g_free (dir_basename); - /* set show_all to TRUE here, as we don't know how many - * files we'll end up processing yet. - */ - response = marlin_file_operations_common_job_run_warning ( - job, - primary, - secondary, - details, - TRUE, - CANCEL, SKIP_ALL, SKIP, RETRY, - NULL); - - g_error_free (error); - - if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { - marlin_file_operations_common_job_abort_job (job); - } else if (response == 1 || response == 2) { - if (response == 1) { - job->skip_all_error = TRUE; - } - marlin_file_operations_common_job_skip_file (job, dir); - } else if (response == 3) { - goto retry; - } else { - g_assert_not_reached (); - } - } -} - -static void -scan_file (GFile *file, - SourceInfo *source_info, - FilesFileOperationsCommonJob *job) -{ - GFileInfo *info; - GError *error; - GQueue *dirs; - GFile *dir; - char *primary; - char *secondary; - char *details; - int response; - - dirs = g_queue_new (); -retry: - error = NULL; - info = NULL; - - if (G_IS_FILE (file)) { - info = g_file_query_info (file, - G_FILE_ATTRIBUTE_STANDARD_TYPE"," - G_FILE_ATTRIBUTE_STANDARD_SIZE, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - job->cancellable, - &error); - } - - if (info) { - count_file (info, job, source_info); - - if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { - g_queue_push_head (dirs, g_object_ref (file)); - } - - g_object_unref (info); - } else if (job->skip_all_error) { - g_error_free (error); - marlin_file_operations_common_job_skip_file (job, file); - } else if (IS_IO_ERROR (error, CANCELLED)) { - g_error_free (error); - } else { - gchar *file_basename = files_file_utils_custom_basename_from_file (file); - primary = get_scan_primary (job); - details = NULL; - - if (IS_IO_ERROR (error, PERMISSION_DENIED)) { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("The file \"%s\" cannot be handled because you do not have " - "permissions to read it."), file_basename); - } else { - /// TRANSLATORS: '\"%s\"' is a placeholder for the quoted basename of a file. It may change position but must not be translated or removed - /// '\"' is an escaped quoted mark. This may be replaced with another suitable character (escaped if necessary) - secondary = g_strdup_printf (_("There was an error getting information about \"%s\"."), file_basename); - details = error->message; - } - - g_free (file_basename); - /* set show_all to TRUE here, as we don't know how many - * files we'll end up processing yet. - */ - response = marlin_file_operations_common_job_run_warning ( - job, - primary, - secondary, - details, - TRUE, - CANCEL, SKIP_ALL, SKIP, RETRY, - NULL); - - g_error_free (error); - - if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { - marlin_file_operations_common_job_abort_job (job); - } else if (response == 1 || response == 2) { - if (response == 1) { - job->skip_all_error = TRUE; - } - marlin_file_operations_common_job_skip_file (job, file); - } else if (response == 3) { - goto retry; - } else { - g_assert_not_reached (); - } - } - - while (!marlin_file_operations_common_job_aborted (job) && - (dir = g_queue_pop_head (dirs)) != NULL) { - scan_dir (dir, source_info, job, dirs); - g_object_unref (dir); - } - - /* Free all from queue if we exited early */ - g_queue_foreach (dirs, (GFunc)g_object_unref, NULL); - g_queue_free (dirs); -} - -static void -scan_sources (GList *files, - SourceInfo *source_info, - CountProgressCallback count_callback, - FilesFileOperationsCommonJob *job) -{ - GList *l; - GFile *file; - - memset (source_info, 0, sizeof (SourceInfo)); - source_info->count_callback = count_callback; - source_info->count_callback (job, source_info); - - for (l = files; l != NULL && !marlin_file_operations_common_job_aborted (job); l = l->next) { - file = l->data; - - scan_file (file, - source_info, - job); - } - - /* Make sure we report the final count */ - source_info->count_callback (job, source_info); -} - static GFile * get_unique_target_file (GFile *src, GFile *dest_dir, @@ -2341,16 +2041,13 @@ copy_job (GTask *task, { FilesFileOperationsCopyMoveJob *job = task_data; FilesFileOperationsCommonJob *common = MARLIN_FILE_OPERATIONS_COMMON_JOB (job); - SourceInfo source_info; + SourceInfo *source_info; TransferInfo transfer_info; char *dest_fs_id = NULL; GFile *dest; pf_progress_info_start (common->progress); - scan_sources (job->files, - &source_info, - (CountProgressCallback) marlin_file_operations_copy_move_job_report_copy_move_count_progress, - common); + source_info = marlin_file_operations_common_job_scan_sources (common, job->files); if (marlin_file_operations_common_job_aborted (common)) { goto aborted; } @@ -2367,7 +2064,7 @@ copy_job (GTask *task, marlin_file_operations_common_job_verify_destination (common, dest, &dest_fs_id, - source_info.num_bytes); + source_info->num_bytes); g_object_unref (dest); if (marlin_file_operations_common_job_aborted (common)) { goto aborted; @@ -2378,10 +2075,10 @@ copy_job (GTask *task, memset (&transfer_info, 0, sizeof (transfer_info)); copy_files (job, dest_fs_id, - &source_info, &transfer_info); + source_info, &transfer_info); aborted: - + g_clear_pointer (&source_info, marlin_file_operations_common_job_source_info_free); g_free (dest_fs_id); g_task_return_boolean (task, TRUE); @@ -2783,7 +2480,7 @@ move_job (GTask *task, FilesFileOperationsCopyMoveJob *job = task_data; FilesFileOperationsCommonJob *common = MARLIN_FILE_OPERATIONS_COMMON_JOB (job); GList *fallbacks = NULL; - SourceInfo source_info; + SourceInfo *source_info; TransferInfo transfer_info; char *dest_fs_id = NULL; char *dest_fs_type = NULL; @@ -2808,10 +2505,7 @@ move_job (GTask *task, so scan for size */ fallback_files = get_files_from_fallbacks (fallbacks); - scan_sources (fallback_files, - &source_info, - (CountProgressCallback) marlin_file_operations_copy_move_job_report_copy_move_count_progress, - common); + source_info = marlin_file_operations_common_job_scan_sources (common, fallback_files); g_list_free (fallback_files); @@ -2822,7 +2516,7 @@ move_job (GTask *task, marlin_file_operations_common_job_verify_destination (common, job->destination, NULL, - source_info.num_bytes); + source_info->num_bytes); if (marlin_file_operations_common_job_aborted (common)) { goto aborted; } @@ -2831,9 +2525,10 @@ move_job (GTask *task, move_files (job, fallbacks, dest_fs_id, &dest_fs_type, - &source_info, &transfer_info); + source_info, &transfer_info); aborted: + g_clear_pointer (&source_info, marlin_file_operations_common_job_source_info_free); g_list_free_full (fallbacks, g_free); g_free (dest_fs_id);