Bug Summary

File:libbaul-private/baul-file-operations.c
Warning:line 5839, column 32
This statement is never executed

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name baul-file-operations.c -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -fmath-errno -ffp-contract=on -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/rootdir/libbaul-private -fcoverage-compilation-dir=/rootdir/libbaul-private -resource-dir /usr/lib/llvm-19/lib/clang/19 -D HAVE_CONFIG_H -I . -I .. -I .. -I .. -I /usr/include/glib-2.0 -I /usr/lib/x86_64-linux-gnu/glib-2.0/include -I /usr/include/sysprof-6 -I /usr/include/cafe-desktop-2.0 -I /usr/include/ctk-3.0 -I /usr/include/pango-1.0 -I /usr/include/harfbuzz -I /usr/include/freetype2 -I /usr/include/libpng16 -I /usr/include/libmount -I /usr/include/blkid -I /usr/include/fribidi -I /usr/include/cairo -I /usr/include/pixman-1 -I /usr/include/gdk-pixbuf-2.0 -I /usr/include/x86_64-linux-gnu -I /usr/include/webp -I /usr/include/gio-unix-2.0 -I /usr/include/atk-1.0 -I /usr/include/at-spi2-atk/2.0 -I /usr/include/at-spi-2.0 -I /usr/include/dbus-1.0 -I /usr/lib/x86_64-linux-gnu/dbus-1.0/include -I /usr/include/startup-notification-1.0 -I /usr/include/dconf -I /usr/include/cail-3.0 -I /usr/include/libxml2 -D G_DISABLE_DEPRECATED -D GDK_PIXBUF_DISABLE_DEPRECATED -D DATADIR="/usr/share" -D SYSCONFDIR="/usr/etc" -D BAUL_DATADIR="/usr/share/baul" -D BAUL_EXTENSIONDIR="/usr/lib/baul/extensions-2.0" -D PIC -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -ferror-limit 19 -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -analyzer-checker deadcode.DeadStores -analyzer-checker alpha.deadcode.UnreachableCode -analyzer-checker alpha.core.CastSize -analyzer-checker alpha.core.CastToStruct -analyzer-checker alpha.core.IdenticalExpr -analyzer-checker alpha.security.ArrayBoundV2 -analyzer-checker alpha.security.MallocOverflow -analyzer-checker alpha.security.ReturnPtrRange -analyzer-checker alpha.unix.SimpleStream -analyzer-checker alpha.unix.cstring.BufferOverlap -analyzer-checker alpha.unix.cstring.NotNullTerminated -analyzer-checker alpha.unix.cstring.OutOfBounds -analyzer-checker alpha.core.FixedAddr -analyzer-output=html -faddrsig -D__GCC_HAVE_DWARF2_CFI_ASM=1 -o /rootdir/html-report/2025-01-24-094037-27604-1 -x c baul-file-operations.c
1/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
2
3/* baul-file-operations.c - Baul file operations.
4
5 Copyright (C) 1999, 2000 Free Software Foundation
6 Copyright (C) 2000, 2001 Eazel, Inc.
7 Copyright (C) 2007 Red Hat, Inc.
8
9 This program is free software; you can redistribute it and/or
10 modify it under the terms of the GNU General Public License as
11 published by the Free Software Foundation; either version 2 of the
12 License, or (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 General Public License for more details.
18
19 You should have received a copy of the GNU General Public
20 License along with this program; if not, write to the
21 Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
22 Boston, MA 02110-1301, USA.
23
24 Authors: Alexander Larsson <alexl@redhat.com>
25 Ettore Perazzoli <ettore@gnu.org>
26 Pavel Cisler <pavel@eazel.com>
27 */
28
29#include <config.h>
30#include <string.h>
31#include <stdio.h>
32#include <stdarg.h>
33#include <locale.h>
34#include <math.h>
35#include <unistd.h>
36#include <sys/types.h>
37#include <stdlib.h>
38#include <glib/gi18n.h>
39#include <glib/gstdio.h>
40#include <cdk/cdk.h>
41#include <cdk/cdkx.h>
42#include <ctk/ctk.h>
43#include <gio/gio.h>
44#include <glib.h>
45#include <libnotify/notify.h>
46
47#include <eel/eel-glib-extensions.h>
48#include <eel/eel-ctk-extensions.h>
49#include <eel/eel-stock-dialogs.h>
50#include <eel/eel-vfs-extensions.h>
51
52#include "baul-file-operations.h"
53#include "baul-debug-log.h"
54#include "baul-file-changes-queue.h"
55#include "baul-lib-self-check-functions.h"
56#include "baul-progress-info.h"
57#include "baul-file-changes-queue.h"
58#include "baul-file-private.h"
59#include "baul-desktop-icon-file.h"
60#include "baul-desktop-link-monitor.h"
61#include "baul-global-preferences.h"
62#include "baul-link.h"
63#include "baul-autorun.h"
64#include "baul-trash-monitor.h"
65#include "baul-file-utilities.h"
66#include "baul-file-conflict-dialog.h"
67#include "baul-undostack-manager.h"
68
69/* TODO: TESTING!!! */
70
71typedef struct {
72 GIOSchedulerJob *io_job;
73 GTimer *time;
74 CtkWindow *parent_window;
75 int screen_num;
76 int inhibit_cookie;
77 BaulProgressInfo *progress;
78 GCancellable *cancellable;
79 GHashTable *skip_files;
80 GHashTable *skip_readdir_error;
81 gboolean skip_all_error;
82 gboolean skip_all_conflict;
83 gboolean merge_all;
84 gboolean replace_all;
85 gboolean delete_all;
86 BaulUndoStackActionData* undo_redo_data;
87} CommonJob;
88
89typedef struct {
90 CommonJob common;
91 gboolean is_move;
92 GList *files;
93 GFile *destination;
94 GFile *desktop_location;
95 CdkPoint *icon_positions;
96 int n_icon_positions;
97 GHashTable *debuting_files;
98 BaulCopyCallback done_callback;
99 gpointer done_callback_data;
100} CopyMoveJob;
101
102typedef struct {
103 CommonJob common;
104 GList *files;
105 gboolean try_trash;
106 gboolean user_cancel;
107 BaulDeleteCallback done_callback;
108 gpointer done_callback_data;
109} DeleteJob;
110
111typedef struct {
112 CommonJob common;
113 GFile *dest_dir;
114 char *filename;
115 gboolean make_dir;
116 GFile *src;
117 char *src_data;
118 int length;
119 CdkPoint position;
120 gboolean has_position;
121 GFile *created_file;
122 BaulCreateCallback done_callback;
123 gpointer done_callback_data;
124} CreateJob;
125
126
127typedef struct {
128 CommonJob common;
129 GList *trash_dirs;
130 gboolean should_confirm;
131 BaulOpCallback done_callback;
132 gpointer done_callback_data;
133} EmptyTrashJob;
134
135typedef struct {
136 CommonJob common;
137 GFile *file;
138 gboolean interactive;
139 BaulOpCallback done_callback;
140 gpointer done_callback_data;
141} MarkTrustedJob;
142
143typedef struct {
144 CommonJob common;
145 GFile *file;
146 BaulOpCallback done_callback;
147 gpointer done_callback_data;
148 guint32 file_permissions;
149 guint32 file_mask;
150 guint32 dir_permissions;
151 guint32 dir_mask;
152} SetPermissionsJob;
153
154typedef enum {
155 OP_KIND_COPY,
156 OP_KIND_MOVE,
157 OP_KIND_DELETE,
158 OP_KIND_TRASH
159} OpKind;
160
161typedef struct {
162 int num_files;
163 goffset num_bytes;
164 int num_files_since_progress;
165 OpKind op;
166} SourceInfo;
167
168typedef struct {
169 int num_files;
170 goffset num_bytes;
171 OpKind op;
172 guint64 last_report_time;
173 int last_reported_files_left;
174} TransferInfo;
175
176#define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE15 15
177#define NSEC_PER_MICROSEC1000 1000
178
179#define MAXIMUM_DISPLAYED_FILE_NAME_LENGTH50 50
180
181#define IS_IO_ERROR(__error, KIND)(((__error)->domain == g_io_error_quark() && (__error
)->code == G_IO_ERROR_KIND))
(((__error)->domain == G_IO_ERRORg_io_error_quark() && (__error)->code == G_IO_ERROR_ ## KIND))
182
183#define CANCELgettext ("_Cancel") _("_Cancel")gettext ("_Cancel")
184#define SKIPgettext ("_Skip") _("_Skip")gettext ("_Skip")
185#define SKIP_ALLgettext ("S_kip All") _("S_kip All")gettext ("S_kip All")
186#define RETRYgettext ("_Retry") _("_Retry")gettext ("_Retry")
187#define DELETEgettext ("_Delete") _("_Delete")gettext ("_Delete")
188#define DELETE_ALLgettext ("Delete _All") _("Delete _All")gettext ("Delete _All")
189#define REPLACEgettext ("_Replace") _("_Replace")gettext ("_Replace")
190#define REPLACE_ALLgettext ("Replace _All") _("Replace _All")gettext ("Replace _All")
191#define MERGEgettext ("_Merge") _("_Merge")gettext ("_Merge")
192#define MERGE_ALLgettext ("Merge _All") _("Merge _All")gettext ("Merge _All")
193#define COPY_FORCEgettext ("Copy _Anyway") _("Copy _Anyway")gettext ("Copy _Anyway")
194
195NotifyNotification *unmount_notify;
196
197void
198baul_application_notify_unmount_show (const gchar *message)
199{
200 gchar **strings;
201 strings = g_strsplit (message, "\n", 0);
202
203 if (!g_settings_get_boolean (baul_preferences, BAUL_PREFERENCES_SHOW_NOTIFICATIONS"show-notifications")) return;
204
205 if (unmount_notify == NULL((void*)0)) {
206 unmount_notify =
207 notify_notification_new (strings[0], strings[1],
208 "media-removable");
209
210 notify_notification_set_hint (unmount_notify,
211 "transient", g_variant_new_boolean (TRUE(!(0))));
212 notify_notification_set_urgency (unmount_notify,
213 NOTIFY_URGENCY_CRITICAL);
214 } else {
215 notify_notification_update (unmount_notify,
216 strings[0], strings[1],
217 "media-removable");
218 }
219
220 notify_notification_show (unmount_notify, NULL((void*)0));
221 g_strfreev (strings);
222}
223
224static void
225mark_desktop_file_trusted (CommonJob *common,
226 GCancellable *cancellable,
227 GFile *file,
228 gboolean interactive);
229
230static gboolean
231is_all_button_text (const char *button_text)
232{
233 g_assert (button_text != NULL)do { if (button_text != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 233, ((const char*)
(__func__)), "button_text != NULL"); } while (0)
;
234
235 return !strcmp (button_text, SKIP_ALLgettext ("S_kip All")) ||
236 !strcmp (button_text, REPLACE_ALLgettext ("Replace _All")) ||
237 !strcmp (button_text, DELETE_ALLgettext ("Delete _All")) ||
238 !strcmp (button_text, MERGE_ALLgettext ("Merge _All"));
239}
240
241static void scan_sources (GList *files,
242 SourceInfo *source_info,
243 CommonJob *job,
244 OpKind kind);
245
246
247static gboolean empty_trash_job (GIOSchedulerJob *io_job,
248 GCancellable *cancellable,
249 gpointer user_data);
250
251static char * query_fs_type (GFile *file,
252 GCancellable *cancellable);
253
254/* keep in time with format_time()
255 *
256 * This counts and outputs the number of “time units”
257 * formatted and displayed by format_time().
258 * For instance, if format_time outputs “3 hours, 4 minutes”
259 * it yields 7.
260 */
261static int
262seconds_count_format_time_units (int seconds)
263{
264 int minutes;
265 int hours;
266
267 if (seconds < 0) {
268 /* Just to make sure... */
269 seconds = 0;
270 }
271
272 if (seconds < 60) {
273 /* seconds */
274 return seconds;
275 }
276
277 if (seconds < 60*60) {
278 /* minutes */
279 minutes = seconds / 60;
280 return minutes;
281 }
282
283 hours = seconds / (60*60);
284
285 if (seconds < 60*60*4) {
286 /* minutes + hours */
287 minutes = (seconds - hours * 60 * 60) / 60;
288 return minutes + hours;
289 }
290
291 return hours;
292}
293
294static char *
295format_time (int seconds)
296{
297 int minutes;
298 int hours;
299
300 if (seconds < 0) {
301 /* Just to make sure... */
302 seconds = 0;
303 }
304
305 if (seconds < 60) {
306 return g_strdup_printf (ngettext ("%'d second","%'d seconds", (int) seconds), (int) seconds);
307 }
308
309 if (seconds < 60*60) {
310 minutes = seconds / 60;
311 return g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes);
312 }
313
314 hours = seconds / (60*60);
315
316 if (seconds < 60*60*4) {
317 char *h, *m;
318 char *res;
319
320 minutes = (seconds - hours * 60 * 60) / 60;
321
322 h = g_strdup_printf (ngettext ("%'d hour", "%'d hours", hours), hours);
323 m = g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes);
324 res = g_strconcat (h, ", ", m, NULL((void*)0));
325 g_free (h);
326 g_free (m);
327 return res;
328 }
329
330 return g_strdup_printf (ngettext ("approximately %'d hour",
331 "approximately %'d hours",
332 hours), hours);
333}
334
335static char *
336shorten_utf8_string (const char *base, int reduce_by_num_bytes)
337{
338 int len;
339 char *ret;
340 const char *p;
341
342 len = strlen (base);
343 len -= reduce_by_num_bytes;
344
345 if (len <= 0) {
346 return NULL((void*)0);
347 }
348
349 ret = g_new (char, len + 1)((char *) g_malloc_n ((len + 1), sizeof (char)));
350
351 p = base;
352 while (len) {
353 char *next;
354 next = g_utf8_next_char (p)((p) + g_utf8_skip[*(const guchar *)(p)]);
355 if (next - p > len || *next == '\0') {
356 break;
357 }
358
359 len -= next - p;
360 p = next;
361 }
362
363 if (p - base == 0) {
364 g_free (ret);
365 return NULL((void*)0);
366 } else {
367 memcpy (ret, base, p - base);
368 ret[p - base] = '\0';
369 return ret;
370 }
371}
372
373/* Note that we have these two separate functions with separate format
374 * strings for ease of localization.
375 */
376
377static char *
378get_link_name (const char *name, int count, int max_length)
379{
380 const char *format;
381 char *result;
382 int unshortened_length;
383 gboolean use_count;
384
385 g_assert (name != NULL)do { if (name != ((void*)0)) ; else g_assertion_message_expr (
((gchar*) 0), "baul-file-operations.c", 385, ((const char*) (
__func__)), "name != NULL"); } while (0)
;
386
387 if (count < 0) {
388 g_warning ("bad count in get_link_name");
389 count = 0;
390 }
391
392 if (count <= 2) {
393 /* Handle special cases for low numbers.
394 * Perhaps for some locales we will need to add more.
395 */
396 switch (count) {
397 default:
398 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 398, ((const char*) (__func__)), ((void*)0)); } while (0)
;
399 /* fall through */
400 case 0:
401 /* duplicate original file name */
402 format = "%s";
403 break;
404 case 1:
405 /* appended to new link file */
406 format = _("Link to %s")gettext ("Link to %s");
407 break;
408 case 2:
409 /* appended to new link file */
410 format = _("Another link to %s")gettext ("Another link to %s");
411 break;
412 }
413
414 use_count = FALSE(0);
415 } else {
416 /* Handle special cases for the first few numbers of each ten.
417 * For locales where getting this exactly right is difficult,
418 * these can just be made all the same as the general case below.
419 */
420 switch (count % 10) {
421 case 1:
422 /* Translators: Feel free to leave out the "st" suffix
423 * if there's no way to do that nicely for a
424 * particular language.
425 */
426 format = _("%'dst link to %s")gettext ("%'dst link to %s");
427 break;
428 case 2:
429 /* appended to new link file */
430 format = _("%'dnd link to %s")gettext ("%'dnd link to %s");
431 break;
432 case 3:
433 /* appended to new link file */
434 format = _("%'drd link to %s")gettext ("%'drd link to %s");
435 break;
436 default:
437 /* appended to new link file */
438 format = _("%'dth link to %s")gettext ("%'dth link to %s");
439 break;
440 }
441
442 use_count = TRUE(!(0));
443 }
444
445 if (use_count)
446 result = g_strdup_printf (format, count, name);
447 else
448 result = g_strdup_printf (format, name);
449
450 if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) {
451 char *new_name;
452
453 new_name = shorten_utf8_string (name, unshortened_length - max_length);
454 if (new_name) {
455 g_free (result);
456
457 if (use_count)
458 result = g_strdup_printf (format, count, new_name);
459 else
460 result = g_strdup_printf (format, new_name);
461
462 g_assert (strlen (result) <= max_length)do { if (strlen (result) <= max_length) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 462, ((const char*)
(__func__)), "strlen (result) <= max_length"); } while (0
)
;
463 g_free (new_name);
464 }
465 }
466
467 return result;
468}
469
470
471/* Translators:
472 * Feel free to leave out the st, nd, rd and th suffix or
473 * make some or all of them match.
474 */
475
476/* Translators: tag used to detect the first copy of a file */
477static const char untranslated_copy_duplicate_tag[] = N_(" (copy)")(" (copy)");
478/* Translators: tag used to detect the second copy of a file */
479static const char untranslated_another_copy_duplicate_tag[] = N_(" (another copy)")(" (another copy)");
480
481/* Translators: tag used to detect the x11th copy of a file */
482static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)")("th copy)");
483/* Translators: tag used to detect the x12th copy of a file */
484static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)")("th copy)");
485/* Translators: tag used to detect the x13th copy of a file */
486static const char untranslated_x13th_copy_duplicate_tag[] = N_("th copy)")("th copy)");
487
488/* Translators: tag used to detect the x1st copy of a file */
489static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)")("st copy)");
490/* Translators: tag used to detect the x2nd copy of a file */
491static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)")("nd copy)");
492/* Translators: tag used to detect the x3rd copy of a file */
493static const char untranslated_rd_copy_duplicate_tag[] = N_("rd copy)")("rd copy)");
494
495/* Translators: tag used to detect the xxth copy of a file */
496static const char untranslated_th_copy_duplicate_tag[] = N_("th copy)")("th copy)");
497
498#define COPY_DUPLICATE_TAGgettext (untranslated_copy_duplicate_tag) _(untranslated_copy_duplicate_tag)gettext (untranslated_copy_duplicate_tag)
499#define ANOTHER_COPY_DUPLICATE_TAGgettext (untranslated_another_copy_duplicate_tag) _(untranslated_another_copy_duplicate_tag)gettext (untranslated_another_copy_duplicate_tag)
500#define X11TH_COPY_DUPLICATE_TAGgettext (untranslated_x11th_copy_duplicate_tag) _(untranslated_x11th_copy_duplicate_tag)gettext (untranslated_x11th_copy_duplicate_tag)
501#define X12TH_COPY_DUPLICATE_TAGgettext (untranslated_x12th_copy_duplicate_tag) _(untranslated_x12th_copy_duplicate_tag)gettext (untranslated_x12th_copy_duplicate_tag)
502#define X13TH_COPY_DUPLICATE_TAGgettext (untranslated_x13th_copy_duplicate_tag) _(untranslated_x13th_copy_duplicate_tag)gettext (untranslated_x13th_copy_duplicate_tag)
503
504#define ST_COPY_DUPLICATE_TAGgettext (untranslated_st_copy_duplicate_tag) _(untranslated_st_copy_duplicate_tag)gettext (untranslated_st_copy_duplicate_tag)
505#define ND_COPY_DUPLICATE_TAGgettext (untranslated_nd_copy_duplicate_tag) _(untranslated_nd_copy_duplicate_tag)gettext (untranslated_nd_copy_duplicate_tag)
506#define RD_COPY_DUPLICATE_TAGgettext (untranslated_rd_copy_duplicate_tag) _(untranslated_rd_copy_duplicate_tag)gettext (untranslated_rd_copy_duplicate_tag)
507#define TH_COPY_DUPLICATE_TAGgettext (untranslated_th_copy_duplicate_tag) _(untranslated_th_copy_duplicate_tag)gettext (untranslated_th_copy_duplicate_tag)
508
509/* Translators: appended to first file copy */
510static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s")("%s (copy)%s");
511/* Translators: appended to second file copy */
512static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s")("%s (another copy)%s");
513
514/* Translators: appended to x11th file copy */
515static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s");
516/* Translators: appended to x12th file copy */
517static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s");
518/* Translators: appended to x13th file copy */
519static const char untranslated_x13th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s");
520
521/* Translators: if in your language there's no difference between 1st, 2nd, 3rd and nth
522 * plurals, you can leave the st, nd, rd suffixes out and just make all the translated
523 * strings look like "%s (copy %'d)%s".
524 */
525
526/* Translators: appended to x1st file copy */
527static const char untranslated_st_copy_duplicate_format[] = N_("%s (%'dst copy)%s")("%s (%'dst copy)%s");
528/* Translators: appended to x2nd file copy */
529static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%'dnd copy)%s")("%s (%'dnd copy)%s");
530/* Translators: appended to x3rd file copy */
531static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%'drd copy)%s")("%s (%'drd copy)%s");
532/* Translators: appended to xxth file copy */
533static const char untranslated_th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s");
534
535#define FIRST_COPY_DUPLICATE_FORMATgettext (untranslated_first_copy_duplicate_format) _(untranslated_first_copy_duplicate_format)gettext (untranslated_first_copy_duplicate_format)
536#define SECOND_COPY_DUPLICATE_FORMATgettext (untranslated_second_copy_duplicate_format) _(untranslated_second_copy_duplicate_format)gettext (untranslated_second_copy_duplicate_format)
537#define X11TH_COPY_DUPLICATE_FORMATgettext (untranslated_x11th_copy_duplicate_format) _(untranslated_x11th_copy_duplicate_format)gettext (untranslated_x11th_copy_duplicate_format)
538#define X12TH_COPY_DUPLICATE_FORMATgettext (untranslated_x12th_copy_duplicate_format) _(untranslated_x12th_copy_duplicate_format)gettext (untranslated_x12th_copy_duplicate_format)
539#define X13TH_COPY_DUPLICATE_FORMATgettext (untranslated_x13th_copy_duplicate_format) _(untranslated_x13th_copy_duplicate_format)gettext (untranslated_x13th_copy_duplicate_format)
540
541#define ST_COPY_DUPLICATE_FORMATgettext (untranslated_st_copy_duplicate_format) _(untranslated_st_copy_duplicate_format)gettext (untranslated_st_copy_duplicate_format)
542#define ND_COPY_DUPLICATE_FORMATgettext (untranslated_nd_copy_duplicate_format) _(untranslated_nd_copy_duplicate_format)gettext (untranslated_nd_copy_duplicate_format)
543#define RD_COPY_DUPLICATE_FORMATgettext (untranslated_rd_copy_duplicate_format) _(untranslated_rd_copy_duplicate_format)gettext (untranslated_rd_copy_duplicate_format)
544#define TH_COPY_DUPLICATE_FORMATgettext (untranslated_th_copy_duplicate_format) _(untranslated_th_copy_duplicate_format)gettext (untranslated_th_copy_duplicate_format)
545
546static char *
547extract_string_until (const char *original, const char *until_substring)
548{
549 char *result;
550
551 g_assert ((int) strlen (original) >= until_substring - original)do { if ((int) strlen (original) >= until_substring - original
) ; else g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 551, ((const char*) (__func__)), "(int) strlen (original) >= until_substring - original"
); } while (0)
;
552 g_assert (until_substring - original >= 0)do { if (until_substring - original >= 0) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 552, ((const char*)
(__func__)), "until_substring - original >= 0"); } while (
0)
;
553
554 result = g_malloc (until_substring - original + 1);
555 strncpy (result, original, until_substring - original);
556 result[until_substring - original] = '\0';
557
558 return result;
559}
560
561/* Dismantle a file name, separating the base name, the file suffix and removing any
562 * (xxxcopy), etc. string. Figure out the count that corresponds to the given
563 * (xxxcopy) substring.
564 */
565static void
566parse_previous_duplicate_name (const char *name,
567 char **name_base,
568 const char **suffix,
569 int *count)
570{
571 const char *tag;
572
573 g_assert (name[0] != '\0')do { if (name[0] != '\0') ; else g_assertion_message_expr (((
gchar*) 0), "baul-file-operations.c", 573, ((const char*) (__func__
)), "name[0] != '\\0'"); } while (0)
;
574
575 *suffix = strchr (name + 1, '.');
576 if (*suffix == NULL((void*)0) || (*suffix)[1] == '\0') {
577 /* no suffix */
578 *suffix = "";
579 }
580
581 tag = strstr (name, COPY_DUPLICATE_TAGgettext (untranslated_copy_duplicate_tag));
582 if (tag != NULL((void*)0)) {
583 if (tag > *suffix) {
584 /* handle case "foo. (copy)" */
585 *suffix = "";
586 }
587 *name_base = extract_string_until (name, tag);
588 *count = 1;
589 return;
590 }
591
592
593 tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAGgettext (untranslated_another_copy_duplicate_tag));
594 if (tag != NULL((void*)0)) {
595 if (tag > *suffix) {
596 /* handle case "foo. (another copy)" */
597 *suffix = "";
598 }
599 *name_base = extract_string_until (name, tag);
600 *count = 2;
601 return;
602 }
603
604
605 /* Check to see if we got one of st, nd, rd, th. */
606 tag = strstr (name, X11TH_COPY_DUPLICATE_TAGgettext (untranslated_x11th_copy_duplicate_tag));
607
608 if (tag == NULL((void*)0)) {
609 tag = strstr (name, X12TH_COPY_DUPLICATE_TAGgettext (untranslated_x12th_copy_duplicate_tag));
610 }
611 if (tag == NULL((void*)0)) {
612 tag = strstr (name, X13TH_COPY_DUPLICATE_TAGgettext (untranslated_x13th_copy_duplicate_tag));
613 }
614
615 if (tag == NULL((void*)0)) {
616 tag = strstr (name, ST_COPY_DUPLICATE_TAGgettext (untranslated_st_copy_duplicate_tag));
617 }
618 if (tag == NULL((void*)0)) {
619 tag = strstr (name, ND_COPY_DUPLICATE_TAGgettext (untranslated_nd_copy_duplicate_tag));
620 }
621 if (tag == NULL((void*)0)) {
622 tag = strstr (name, RD_COPY_DUPLICATE_TAGgettext (untranslated_rd_copy_duplicate_tag));
623 }
624 if (tag == NULL((void*)0)) {
625 tag = strstr (name, TH_COPY_DUPLICATE_TAGgettext (untranslated_th_copy_duplicate_tag));
626 }
627
628 /* If we got one of st, nd, rd, th, fish out the duplicate number. */
629 if (tag != NULL((void*)0)) {
630 /* Translators: opening parentheses to match the "th copy)" string */
631 tag = strstr (name, _(" (")gettext (" ("));
632 if (tag != NULL((void*)0)) {
633 if (tag > *suffix) {
634 /* handle case "foo. (22nd copy)" */
635 *suffix = "";
636 }
637 *name_base = extract_string_until (name, tag);
638 /* Translators: opening parentheses of the "th copy)" string */
639 if (sscanf (tag, _(" (%'d")gettext (" (%'d"), count) == 1) {
640 if (*count < 1 || *count > 1000000) {
641 /* keep the count within a reasonable range */
642 *count = 0;
643 }
644 return;
645 }
646 *count = 0;
647 return;
648 }
649 }
650
651
652 *count = 0;
653 if (**suffix != '\0') {
654 *name_base = extract_string_until (name, *suffix);
655 } else {
656 *name_base = g_strdup (name)g_strdup_inline (name);
657 }
658}
659
660static char *
661make_next_duplicate_name (const char *base, const char *suffix, int count, int max_length)
662{
663 const char *format;
664 char *result;
665 int unshortened_length;
666 gboolean use_count;
667
668 if (count < 1) {
669 g_warning ("bad count %d in get_duplicate_name", count);
670 count = 1;
671 }
672
673 if (count <= 2) {
674
675 /* Handle special cases for low numbers.
676 * Perhaps for some locales we will need to add more.
677 */
678 switch (count) {
679 default:
680 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 680, ((const char*) (__func__)), ((void*)0)); } while (0)
;
681 /* fall through */
682 case 1:
683 format = FIRST_COPY_DUPLICATE_FORMATgettext (untranslated_first_copy_duplicate_format);
684 break;
685 case 2:
686 format = SECOND_COPY_DUPLICATE_FORMATgettext (untranslated_second_copy_duplicate_format);
687 break;
688
689 }
690
691 use_count = FALSE(0);
692 } else {
693
694 /* Handle special cases for the first few numbers of each ten.
695 * For locales where getting this exactly right is difficult,
696 * these can just be made all the same as the general case below.
697 */
698
699 /* Handle special cases for x11th - x20th.
700 */
701 switch (count % 100) {
702 case 11:
703 format = X11TH_COPY_DUPLICATE_FORMATgettext (untranslated_x11th_copy_duplicate_format);
704 break;
705 case 12:
706 format = X12TH_COPY_DUPLICATE_FORMATgettext (untranslated_x12th_copy_duplicate_format);
707 break;
708 case 13:
709 format = X13TH_COPY_DUPLICATE_FORMATgettext (untranslated_x13th_copy_duplicate_format);
710 break;
711 default:
712 format = NULL((void*)0);
713 break;
714 }
715
716 if (format == NULL((void*)0)) {
717 switch (count % 10) {
718 case 1:
719 format = ST_COPY_DUPLICATE_FORMATgettext (untranslated_st_copy_duplicate_format);
720 break;
721 case 2:
722 format = ND_COPY_DUPLICATE_FORMATgettext (untranslated_nd_copy_duplicate_format);
723 break;
724 case 3:
725 format = RD_COPY_DUPLICATE_FORMATgettext (untranslated_rd_copy_duplicate_format);
726 break;
727 default:
728 /* The general case. */
729 format = TH_COPY_DUPLICATE_FORMATgettext (untranslated_th_copy_duplicate_format);
730 break;
731 }
732 }
733
734 use_count = TRUE(!(0));
735
736 }
737
738 if (use_count)
739 result = g_strdup_printf (format, base, count, suffix);
740 else
741 result = g_strdup_printf (format, base, suffix);
742
743 if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) {
744 char *new_base;
745
746 new_base = shorten_utf8_string (base, unshortened_length - max_length);
747 if (new_base) {
748 g_free (result);
749
750 if (use_count)
751 result = g_strdup_printf (format, new_base, count, suffix);
752 else
753 result = g_strdup_printf (format, new_base, suffix);
754
755 g_assert (strlen (result) <= max_length)do { if (strlen (result) <= max_length) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 755, ((const char*)
(__func__)), "strlen (result) <= max_length"); } while (0
)
;
756 g_free (new_base);
757 }
758 }
759
760 return result;
761}
762
763static char *
764get_duplicate_name (const char *name, int count_increment, int max_length)
765{
766 char *result;
767 char *name_base;
768 const char *suffix;
769 int count;
770
771 parse_previous_duplicate_name (name, &name_base, &suffix, &count);
772 result = make_next_duplicate_name (name_base, suffix, count + count_increment, max_length);
773
774 g_free (name_base);
775
776 return result;
777}
778
779static gboolean
780has_invalid_xml_char (char *str)
781{
782 gunichar c;
783
784 while (*str != 0) {
785 c = g_utf8_get_char (str);
786 /* characters XML permits */
787 if (!(c == 0x9 ||
788 c == 0xA ||
789 c == 0xD ||
790 (c >= 0x20 && c <= 0xD7FF) ||
791 (c >= 0xE000 && c <= 0xFFFD) ||
792 (c >= 0x10000 && c <= 0x10FFFF))) {
793 return TRUE(!(0));
794 }
795 str = g_utf8_next_char (str)((str) + g_utf8_skip[*(const guchar *)(str)]);
796 }
797 return FALSE(0);
798}
799
800
801static char *
802custom_full_name_to_string (char *format G_GNUC_UNUSED__attribute__ ((__unused__)),
803 va_list va)
804{
805 GFile *file;
806
807 file = va_arg (va, GFile *)__builtin_va_arg(va, GFile *);
808
809 return g_file_get_parse_name (file);
810}
811
812static void
813custom_full_name_skip (va_list *va)
814{
815 (void) va_arg (*va, GFile *)__builtin_va_arg(*va, GFile *);
816}
817
818static char *
819custom_basename_to_string (char *format G_GNUC_UNUSED__attribute__ ((__unused__)),
820 va_list va)
821{
822 GFile *file;
823 GFileInfo *info;
824 char *name, *basename, *tmp;
825
826 file = va_arg (va, GFile *)__builtin_va_arg(va, GFile *);
827
828 info = g_file_query_info (file,
829 G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME"standard::display-name",
830 0,
831 g_cancellable_get_current (),
832 NULL((void*)0));
833
834 name = NULL((void*)0);
835 if (info) {
836 name = g_strdup (g_file_info_get_display_name (info))g_strdup_inline (g_file_info_get_display_name (info));
837 g_object_unref (info);
838 }
839
840 if (name == NULL((void*)0)) {
841 basename = g_file_get_basename (file);
842 if (g_utf8_validate (basename, -1, NULL((void*)0))) {
843 name = basename;
844 } else {
845 name = g_uri_escape_string (basename, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH"!$&'()*+,;=" ":@" "/", TRUE(!(0)));
846 g_free (basename);
847 }
848 }
849
850 /* Some chars can't be put in the markup we use for the dialogs... */
851 if (has_invalid_xml_char (name)) {
852 tmp = name;
853 name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH"!$&'()*+,;=" ":@" "/", TRUE(!(0)));
854 g_free (tmp);
855 }
856
857 /* Finally, if the string is too long, truncate it. */
858 if (name != NULL((void*)0)) {
859 tmp = name;
860 name = eel_str_middle_truncate (tmp, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH50);
861 g_free (tmp);
862 }
863
864
865 return name;
866}
867
868static void
869custom_basename_skip (va_list *va)
870{
871 (void) va_arg (*va, GFile *)__builtin_va_arg(*va, GFile *);
872}
873
874
875static char *
876custom_size_to_string (char *format G_GNUC_UNUSED__attribute__ ((__unused__)),
877 va_list va)
878{
879 goffset size;
880
881 size = va_arg (va, goffset)__builtin_va_arg(va, goffset);
882
883 if (g_settings_get_boolean (baul_preferences, BAUL_PREFERENCES_USE_IEC_UNITS"use-iec-units"))
884 return g_format_size_full (size, G_FORMAT_SIZE_IEC_UNITS);
885 else
886 return g_format_size(size);
887}
888
889static void
890custom_size_skip (va_list *va)
891{
892 (void) va_arg (*va, goffset)__builtin_va_arg(*va, goffset);
893}
894
895static char *
896custom_time_to_string (char *format G_GNUC_UNUSED__attribute__ ((__unused__)),
897 va_list va)
898{
899 int secs;
900
901 secs = va_arg (va, int)__builtin_va_arg(va, int);
902 return format_time (secs);
903}
904
905static void
906custom_time_skip (va_list *va)
907{
908 (void) va_arg (*va, int)__builtin_va_arg(*va, int);
909}
910
911static char *
912custom_mount_to_string (char *format G_GNUC_UNUSED__attribute__ ((__unused__)),
913 va_list va)
914{
915 GMount *mount;
916
917 mount = va_arg (va, GMount *)__builtin_va_arg(va, GMount *);
918 return g_mount_get_name (mount);
919}
920
921static void
922custom_mount_skip (va_list *va)
923{
924 (void) va_arg (*va, GMount *)__builtin_va_arg(*va, GMount *);
925}
926
927
928static EelPrintfHandler handlers[] = {
929 { 'F', custom_full_name_to_string, custom_full_name_skip },
930 { 'B', custom_basename_to_string, custom_basename_skip },
931 { 'S', custom_size_to_string, custom_size_skip },
932 { 'T', custom_time_to_string, custom_time_skip },
933 { 'V', custom_mount_to_string, custom_mount_skip },
934 { 0 }
935};
936
937
938static char *
939f (const char *format, ...) {
940 va_list va;
941 char *res;
942
943 va_start (va, format)__builtin_va_start(va, format);
944 res = eel_strdup_vprintf_with_custom (handlers, format, va);
945 va_end (va)__builtin_va_end(va);
946
947 return res;
948}
949
950#define op_job_new(__type, parent_window, should_start, can_pause)((__type *)(init_common (sizeof(__type), parent_window, should_start
, can_pause)))
((__type *)(init_common (sizeof(__type), parent_window, should_start, can_pause)))
951
952static gpointer
953init_common (gsize job_size,
954 CtkWindow *parent_window,
955 gboolean should_start, gboolean can_pause)
956{
957 CommonJob *common;
958
959 /* expected warning with Clang static analyzer: *
960 * "Cast a region whose size is not a multiple of the destination type size" *
961 * *
962 * It is expected for job_size to be larger than sizeof(CommonJob) no matter *
963 * what Clang analyzer reports: we're allocating the whole structure for a job *
964 * (e.g. a TrashJob), but only initializing the common part of it (CommonJob) *
965 * which is a subset of all "real" job structures, structures that all start *
966 * with a CommonJob, and that thus can be used as such. */
967 common = g_malloc0 (job_size);
968
969 if (parent_window) {
970 common->parent_window = parent_window;
971 eel_add_weak_pointer (&common->parent_window);
972 }
973 common->progress = baul_progress_info_new (should_start, can_pause);
974 common->cancellable = baul_progress_info_get_cancellable (common->progress);
975 common->time = g_timer_new ();
976 common->inhibit_cookie = -1;
977 common->screen_num = 0;
978 if (parent_window) {
979 CdkScreen *screen;
980
981 screen = ctk_widget_get_screen (CTK_WIDGET (parent_window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((parent_window)), ((ctk_widget_get_type ()))))))
);
982 common->screen_num = cdk_x11_screen_get_screen_number (screen);
983 }
984
985 return common;
986}
987
988static void
989finalize_common (CommonJob *common)
990{
991 baul_progress_info_finish (common->progress);
992
993 if (common->inhibit_cookie != -1) {
994 baul_uninhibit_power_manager (common->inhibit_cookie);
995 }
996
997 common->inhibit_cookie = -1;
998 g_timer_destroy (common->time);
999 eel_remove_weak_pointer (&common->parent_window);
1000 if (common->skip_files) {
1001 g_hash_table_destroy (common->skip_files);
1002 }
1003 if (common->skip_readdir_error) {
1004 g_hash_table_destroy (common->skip_readdir_error);
1005 }
1006 // Start UNDO-REDO
1007 baul_undostack_manager_add_action (baul_undostack_manager_instance(),
1008 common->undo_redo_data);
1009 // End UNDO-REDO
1010 g_object_unref (common->progress);
1011 g_object_unref (common->cancellable);
1012 g_free (common);
1013}
1014
1015static void
1016skip_file (CommonJob *common,
1017 GFile *file)
1018{
1019 if (common->skip_files == NULL((void*)0)) {
1020 common->skip_files =
1021 g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
1022 }
1023
1024 g_hash_table_insert (common->skip_files, g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file)), file);
1025}
1026
1027static void
1028skip_readdir_error (CommonJob *common,
1029 GFile *dir)
1030{
1031 if (common->skip_readdir_error == NULL((void*)0)) {
1032 common->skip_readdir_error =
1033 g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
1034 }
1035
1036 g_hash_table_insert (common->skip_readdir_error, g_object_ref (dir)((__typeof__ (dir)) (g_object_ref) (dir)), dir);
1037}
1038
1039static gboolean
1040should_skip_file (CommonJob *common,
1041 GFile *file)
1042{
1043 if (common->skip_files != NULL((void*)0)) {
1044 return g_hash_table_lookup (common->skip_files, file) != NULL((void*)0);
1045 }
1046
1047 return FALSE(0);
1048}
1049
1050static gboolean
1051should_skip_readdir_error (CommonJob *common,
1052 GFile *dir)
1053{
1054 if (common->skip_readdir_error != NULL((void*)0)) {
1055 return g_hash_table_lookup (common->skip_readdir_error, dir) != NULL((void*)0);
1056 }
1057 return FALSE(0);
1058}
1059
1060static gboolean
1061can_delete_without_confirm (GFile *file)
1062{
1063 if (g_file_has_uri_scheme (file, "burn") ||
1064 g_file_has_uri_scheme (file, "x-baul-desktop")) {
1065 return TRUE(!(0));
1066 }
1067
1068 return FALSE(0);
1069}
1070
1071static gboolean
1072can_delete_files_without_confirm (GList *files)
1073{
1074 g_assert (files != NULL)do { if (files != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 1074, ((const char*
) (__func__)), "files != NULL"); } while (0)
;
1075
1076 while (files != NULL((void*)0)) {
1077 if (!can_delete_without_confirm (files->data)) {
1078 return FALSE(0);
1079 }
1080
1081 files = files->next;
1082 }
1083
1084 return TRUE(!(0));
1085}
1086
1087typedef struct {
1088 CtkWindow **parent_window;
1089 gboolean ignore_close_box;
1090 CtkMessageType message_type;
1091 const char *primary_text;
1092 const char *secondary_text;
1093 const char *details_text;
1094 const char **button_titles;
1095 gboolean show_all;
1096
1097 int result;
1098} RunSimpleDialogData;
1099
1100static gboolean
1101do_run_simple_dialog (gpointer _data)
1102{
1103 RunSimpleDialogData *data = _data;
1104 CtkWidget *dialog;
1105 int result;
1106 int response_id;
1107
1108 /* Create the dialog. */
1109 dialog = ctk_message_dialog_new (*data->parent_window,
1110 0,
1111 data->message_type,
1112 CTK_BUTTONS_NONE,
1113 NULL((void*)0));
1114
1115 g_object_set (dialog,
1116 "text", data->primary_text,
1117 "secondary-text", data->secondary_text,
1118 NULL((void*)0));
1119
1120 for (response_id = 0;
1121 data->button_titles[response_id] != NULL((void*)0);
1122 response_id++) {
1123 const char *button_title;
1124
1125 button_title = data->button_titles[response_id];
1126 if (!data->show_all && is_all_button_text (button_title)) {
1127 continue;
1128 }
1129
1130 if (g_strcmp0 (button_title, CANCELgettext ("_Cancel")) == 0)
1131 eel_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
, button_title, "process-stop", response_id);
1132 else if (g_strcmp0 (button_title, DELETEgettext ("_Delete")) == 0)
1133 eel_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
, button_title, "edit-delete", response_id);
1134 else
1135 ctk_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
, button_title, response_id);
1136
1137 ctk_dialog_set_default_response (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
, response_id);
1138 }
1139
1140 if (data->details_text) {
1141 eel_ctk_message_dialog_set_details_label (CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ())
)))))
,
1142 data->details_text);
1143 }
1144
1145 /* Run it. */
1146 ctk_widget_show (dialog);
1147 result = ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
1148
1149 while ((result == CTK_RESPONSE_NONE || result == CTK_RESPONSE_DELETE_EVENT) && data->ignore_close_box) {
1150 ctk_widget_show (CTK_WIDGET (dialog)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_widget_get_type ()))))))
);
1151 result = ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
1152 }
1153
1154 ctk_widget_destroy (dialog);
1155
1156 data->result = result;
1157
1158 return FALSE(0);
1159}
1160
1161/* NOTE: This frees the primary / secondary strings, in order to
1162 avoid doing that everywhere. So, make sure they are strduped */
1163
1164static int
1165run_simple_dialog_va (CommonJob *job,
1166 gboolean ignore_close_box,
1167 CtkMessageType message_type,
1168 char *primary_text,
1169 char *secondary_text,
1170 const char *details_text,
1171 gboolean show_all,
1172 va_list varargs)
1173{
1174 RunSimpleDialogData *data;
1175 int res;
1176 const char *button_title;
1177 GPtrArray *ptr_array;
1178
1179 g_timer_stop (job->time);
1180
1181 data = g_new0 (RunSimpleDialogData, 1)((RunSimpleDialogData *) g_malloc0_n ((1), sizeof (RunSimpleDialogData
)))
;
1182 data->parent_window = &job->parent_window;
1183 data->ignore_close_box = ignore_close_box;
1184 data->message_type = message_type;
1185 data->primary_text = primary_text;
1186 data->secondary_text = secondary_text;
1187 data->details_text = details_text;
1188 data->show_all = show_all;
1189
1190 ptr_array = g_ptr_array_new ();
1191 while ((button_title = va_arg (varargs, const char *)__builtin_va_arg(varargs, const char *)) != NULL((void*)0)) {
1192 g_ptr_array_add (ptr_array, (char *)button_title);
1193 }
1194 g_ptr_array_add (ptr_array, NULL((void*)0));
1195 data->button_titles = (const char **)g_ptr_array_free (ptr_array, FALSE(0));
1196
1197 baul_progress_info_pause (job->progress);
1198 g_io_scheduler_job_send_to_mainloop (job->io_job,
1199 do_run_simple_dialog,
1200 data,
1201 NULL((void*)0));
1202 baul_progress_info_resume (job->progress);
1203 res = data->result;
1204
1205 g_free (data->button_titles);
1206 g_free (data);
1207
1208 g_timer_continue (job->time);
1209
1210 g_free (primary_text);
1211 g_free (secondary_text);
1212
1213 return res;
1214}
1215
1216#if 0 /* Not used at the moment */
1217static int
1218run_simple_dialog (CommonJob *job,
1219 gboolean ignore_close_box,
1220 CtkMessageType message_type,
1221 char *primary_text,
1222 char *secondary_text,
1223 const char *details_text,
1224 ...)
1225{
1226 va_list varargs;
1227 int res;
1228
1229 va_start (varargs, details_text)__builtin_va_start(varargs, details_text);
1230 res = run_simple_dialog_va (job,
1231 ignore_close_box,
1232 message_type,
1233 primary_text,
1234 secondary_text,
1235 details_text,
1236 varargs);
1237 va_end (varargs)__builtin_va_end(varargs);
1238 return res;
1239}
1240#endif
1241
1242static int
1243run_error (CommonJob *job,
1244 char *primary_text,
1245 char *secondary_text,
1246 const char *details_text,
1247 gboolean show_all,
1248 ...)
1249{
1250 va_list varargs;
1251 int res;
1252
1253 va_start (varargs, show_all)__builtin_va_start(varargs, show_all);
1254 res = run_simple_dialog_va (job,
1255 FALSE(0),
1256 CTK_MESSAGE_ERROR,
1257 primary_text,
1258 secondary_text,
1259 details_text,
1260 show_all,
1261 varargs);
1262 va_end (varargs)__builtin_va_end(varargs);
1263 return res;
1264}
1265
1266static int
1267run_warning (CommonJob *job,
1268 char *primary_text,
1269 char *secondary_text,
1270 const char *details_text,
1271 gboolean show_all,
1272 ...)
1273{
1274 va_list varargs;
1275 int res;
1276
1277 va_start (varargs, show_all)__builtin_va_start(varargs, show_all);
1278 res = run_simple_dialog_va (job,
1279 FALSE(0),
1280 CTK_MESSAGE_WARNING,
1281 primary_text,
1282 secondary_text,
1283 details_text,
1284 show_all,
1285 varargs);
1286 va_end (varargs)__builtin_va_end(varargs);
1287 return res;
1288}
1289
1290static int
1291run_question (CommonJob *job,
1292 char *primary_text,
1293 char *secondary_text,
1294 const char *details_text,
1295 gboolean show_all,
1296 ...)
1297{
1298 va_list varargs;
1299 int res;
1300
1301 va_start (varargs, show_all)__builtin_va_start(varargs, show_all);
1302 res = run_simple_dialog_va (job,
1303 FALSE(0),
1304 CTK_MESSAGE_QUESTION,
1305 primary_text,
1306 secondary_text,
1307 details_text,
1308 show_all,
1309 varargs);
1310 va_end (varargs)__builtin_va_end(varargs);
1311 return res;
1312}
1313
1314static void
1315inhibit_power_manager (CommonJob *job, const char *message)
1316{
1317 job->inhibit_cookie = baul_inhibit_power_manager (message);
1318}
1319
1320static void
1321abort_job (CommonJob *job)
1322{
1323 g_cancellable_cancel (job->cancellable);
1324
1325}
1326
1327/* Since this happens on a thread we can't use the global prefs object */
1328static gboolean
1329should_confirm_trash (void)
1330{
1331 GSettings *prefs;
1332 gboolean confirm_trash;
1333
1334 prefs = g_settings_new ("org.cafe.baul.preferences");
1335 confirm_trash = g_settings_get_boolean (prefs, BAUL_PREFERENCES_CONFIRM_TRASH"confirm-trash");
1336 g_object_unref (prefs);
1337 return confirm_trash;
1338}
1339
1340static gboolean
1341should_confirm_move_to_trash (void)
1342{
1343 GSettings *prefs;
1344 gboolean confirm_trash;
1345
1346 prefs = g_settings_new ("org.cafe.baul.preferences");
1347 confirm_trash = g_settings_get_boolean (prefs, BAUL_PREFERENCES_CONFIRM_MOVE_TO_TRASH"confirm-move-to-trash");
1348 g_object_unref (prefs);
1349 return confirm_trash;
1350}
1351
1352static gboolean
1353job_aborted (CommonJob *job)
1354{
1355 return g_cancellable_is_cancelled (job->cancellable);
1356}
1357
1358static gboolean
1359confirm_delete_from_trash (CommonJob *job,
1360 GList *files)
1361{
1362 char *prompt;
1363 int file_count;
1364 int response;
1365
1366 /* Just Say Yes if the preference says not to confirm. */
1367 if (!should_confirm_trash ()) {
1368 return TRUE(!(0));
1369 }
1370
1371 file_count = g_list_length (files);
1372 g_assert (file_count > 0)do { if (file_count > 0) ; else g_assertion_message_expr (
((gchar*) 0), "baul-file-operations.c", 1372, ((const char*) (
__func__)), "file_count > 0"); } while (0)
;
1373
1374 if (file_count == 1) {
1375 prompt = f (_("Are you sure you want to permanently delete \"%B\" "gettext ("Are you sure you want to permanently delete \"%B\" "
"from the trash?")
1376 "from the trash?")gettext ("Are you sure you want to permanently delete \"%B\" "
"from the trash?")
, files->data);
1377 } else {
1378 prompt = f (ngettext("Are you sure you want to permanently delete "
1379 "the %'d selected item from the trash?",
1380 "Are you sure you want to permanently delete "
1381 "the %'d selected items from the trash?",
1382 file_count),
1383 file_count);
1384 }
1385
1386 response = run_warning (job,
1387 prompt,
1388 f (_("If you delete an item, it will be permanently lost.")gettext ("If you delete an item, it will be permanently lost."
)
),
1389 NULL((void*)0),
1390 FALSE(0),
1391 CANCELgettext ("_Cancel"), DELETEgettext ("_Delete"),
1392 NULL((void*)0));
1393
1394 return (response == 1);
1395}
1396
1397static gboolean
1398confirm_empty_trash (CommonJob *job)
1399{
1400 char *prompt;
1401 int response;
1402
1403 /* Just Say Yes if the preference says not to confirm. */
1404 if (!should_confirm_trash ()) {
1405 return TRUE(!(0));
1406 }
1407
1408 prompt = f (_("Empty all items from Trash?")gettext ("Empty all items from Trash?"));
1409
1410 response = run_warning (job,
1411 prompt,
1412 f(_("All items in the Trash will be permanently deleted.")gettext ("All items in the Trash will be permanently deleted."
)
),
1413 NULL((void*)0),
1414 FALSE(0),
1415 CANCELgettext ("_Cancel"), _("Empty _Trash")gettext ("Empty _Trash"),
1416 NULL((void*)0));
1417
1418 return (response == 1);
1419}
1420
1421static gboolean
1422confirm_delete_directly (CommonJob *job,
1423 GList *files)
1424{
1425 char *prompt;
1426 int file_count;
1427 int response;
1428
1429 /* Just Say Yes if the preference says not to confirm. */
1430 if (!should_confirm_trash ()) {
1431 return TRUE(!(0));
1432 }
1433
1434 file_count = g_list_length (files);
1435 g_assert (file_count > 0)do { if (file_count > 0) ; else g_assertion_message_expr (
((gchar*) 0), "baul-file-operations.c", 1435, ((const char*) (
__func__)), "file_count > 0"); } while (0)
;
1436
1437 if (can_delete_files_without_confirm (files)) {
1438 return TRUE(!(0));
1439 }
1440
1441 if (file_count == 1) {
1442 prompt = f (_("Are you sure you want to permanently delete \"%B\"?")gettext ("Are you sure you want to permanently delete \"%B\"?"
)
,
1443 files->data);
1444 } else {
1445 prompt = f (ngettext("Are you sure you want to permanently delete "
1446 "the %'d selected item?",
1447 "Are you sure you want to permanently delete "
1448 "the %'d selected items?", file_count),
1449 file_count);
1450 }
1451
1452 response = run_warning (job,
1453 prompt,
1454 f (_("If you delete an item, it will be permanently lost.")gettext ("If you delete an item, it will be permanently lost."
)
),
1455 NULL((void*)0),
1456 FALSE(0),
1457 CANCELgettext ("_Cancel"), DELETEgettext ("_Delete"),
1458 NULL((void*)0));
1459
1460 return response == 1;
1461}
1462
1463static gboolean
1464confirm_trash (CommonJob *job,
1465 GList *files)
1466{
1467 char *prompt;
1468 int file_count;
1469 int response;
1470
1471 /* Just Say Yes if the preference says not to confirm. */
1472 if (!should_confirm_move_to_trash ()) {
1473 return TRUE(!(0));
1474 }
1475
1476 file_count = g_list_length (files);
1477 g_assert (file_count > 0)do { if (file_count > 0) ; else g_assertion_message_expr (
((gchar*) 0), "baul-file-operations.c", 1477, ((const char*) (
__func__)), "file_count > 0"); } while (0)
;
1478
1479 if (can_delete_files_without_confirm (files)) {
1480 return TRUE(!(0));
1481 }
1482
1483 if (file_count == 1) {
1484 prompt = f (_("Are you sure you want to trash \"%B\"?")gettext ("Are you sure you want to trash \"%B\"?"),
1485 files->data);
1486 } else {
1487 prompt = f (ngettext("Are you sure you want to trash "
1488 "the %'d selected item?",
1489 "Are you sure you want to trash "
1490 "the %'d selected items?", file_count),
1491 file_count);
1492 }
1493
1494 response = run_warning (job,
1495 prompt,
1496 f (_("Items moved to the trash may be recovered until the trash is emptied.")gettext ("Items moved to the trash may be recovered until the trash is emptied."
)
),
1497 NULL((void*)0),
1498 FALSE(0),
1499 CANCELgettext ("_Cancel"), _("Move to _Trash")gettext ("Move to _Trash"),
1500 NULL((void*)0));
1501
1502 return response == 1;
1503}
1504
1505static void
1506report_delete_progress (CommonJob *job,
1507 SourceInfo *source_info,
1508 TransferInfo *transfer_info)
1509{
1510 int files_left;
1511 double elapsed;
1512 gint64 now;
1513 char *files_left_s;
1514
1515 now = g_get_monotonic_time ();
1516 if (transfer_info->last_report_time != 0 &&
1517 ABS ((gint64)(transfer_info->last_report_time - now))((((gint64)(transfer_info->last_report_time - now)) < 0
) ? -((gint64)(transfer_info->last_report_time - now)) : (
(gint64)(transfer_info->last_report_time - now)))
< 100 * NSEC_PER_MICROSEC1000) {
1518 return;
1519 }
1520 transfer_info->last_report_time = now;
1521
1522 files_left = source_info->num_files - transfer_info->num_files;
1523
1524 /* Races and whatnot could cause this to be negative... */
1525 if (files_left < 0) {
1526 files_left = 1;
1527 }
1528
1529 files_left_s = f (ngettext ("%'d file left to delete",
1530 "%'d files left to delete",
1531 files_left),
1532 files_left);
1533
1534 baul_progress_info_take_status (job->progress,
1535 f (_("Deleting files")gettext ("Deleting files")));
1536
1537 elapsed = g_timer_elapsed (job->time, NULL((void*)0));
1538 if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE15) {
1539
1540 baul_progress_info_set_details (job->progress, files_left_s);
1541 } else {
1542 char *details, *time_left_s;
1543 int remaining_time;
1544 double transfer_rate;
1545
1546 transfer_rate = transfer_info->num_files / elapsed;
1547 remaining_time = files_left / transfer_rate;
1548
1549 /* Translators: %T will expand to a time like "2 minutes".
1550 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
1551 */
1552 time_left_s = f (ngettext ("%T left",
1553 "%T left",
1554 seconds_count_format_time_units (remaining_time)),
1555 remaining_time);
1556
1557 details = g_strconcat (files_left_s, "\xE2\x80\x94", time_left_s, NULL((void*)0));
1558 baul_progress_info_take_details (job->progress, details);
1559
1560 g_free (time_left_s);
1561 }
1562
1563 g_free (files_left_s);
1564
1565 if (source_info->num_files != 0) {
1566 baul_progress_info_set_progress (job->progress, transfer_info->num_files, source_info->num_files);
1567 }
1568}
1569
1570static void delete_file (CommonJob *job, GFile *file,
1571 gboolean *skipped_file,
1572 SourceInfo *source_info,
1573 TransferInfo *transfer_info,
1574 gboolean toplevel);
1575
1576static void
1577delete_dir (CommonJob *job,
1578 GFile *dir,
1579 gboolean *skipped_file,
1580 SourceInfo *source_info,
1581 TransferInfo *transfer_info,
1582 gboolean toplevel G_GNUC_UNUSED__attribute__ ((__unused__)))
1583{
1584 GFileInfo *info;
1585 GError *error;
1586 GFile *file;
1587 GFileEnumerator *enumerator;
1588 char *primary, *secondary, *details;
1589 int response;
1590 gboolean skip_error;
1591 gboolean local_skipped_file;
1592
1593 local_skipped_file = FALSE(0);
1594
1595 skip_error = should_skip_readdir_error (job, dir);
1596 retry:
1597 error = NULL((void*)0);
1598 enumerator = g_file_enumerate_children (dir,
1599 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name",
1600 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1601 job->cancellable,
1602 &error);
1603 if (enumerator) {
1604 error = NULL((void*)0);
1605
1606 while (!job_aborted (job) &&
1607 (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL((void*)0):&error)) != NULL((void*)0)) {
1608 file = g_file_get_child (dir,
1609 g_file_info_get_name (info));
1610 delete_file (job, file, &local_skipped_file, source_info, transfer_info, FALSE(0));
1611 g_object_unref (file);
1612 g_object_unref (info);
1613 }
1614 g_file_enumerator_close (enumerator, job->cancellable, NULL((void*)0));
1615 g_object_unref (enumerator);
1616
1617 if (error && IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
1618 g_error_free (error);
1619 } else if (error) {
1620 primary = f (_("Error while deleting.")gettext ("Error while deleting."));
1621 details = NULL((void*)0);
1622
1623 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
1624 secondary = f (_("Files in the folder \"%B\" cannot be deleted because you do "gettext ("Files in the folder \"%B\" cannot be deleted because you do "
"not have permissions to see them.")
1625 "not have permissions to see them.")gettext ("Files in the folder \"%B\" cannot be deleted because you do "
"not have permissions to see them.")
, dir);
1626 } else {
1627 secondary = f (_("There was an error getting information about the files in the folder \"%B\".")gettext ("There was an error getting information about the files in the folder \"%B\"."
)
, dir);
1628 details = error->message;
1629 }
1630
1631 response = run_warning (job,
1632 primary,
1633 secondary,
1634 details,
1635 FALSE(0),
1636 CANCELgettext ("_Cancel"), _("_Skip files")gettext ("_Skip files"),
1637 NULL((void*)0));
1638
1639 g_error_free (error);
1640
1641 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
1642 abort_job (job);
1643 } else if (response == 1) {
1644 /* Skip: Do Nothing */
1645 local_skipped_file = TRUE(!(0));
1646 } else {
1647 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 1647, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1648 }
1649 }
1650
1651 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
1652 g_error_free (error);
1653 } else {
1654 primary = f (_("Error while deleting.")gettext ("Error while deleting."));
1655 details = NULL((void*)0);
1656 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
1657 secondary = f (_("The folder \"%B\" cannot be deleted because you do not have "gettext ("The folder \"%B\" cannot be deleted because you do not have "
"permissions to read it.")
1658 "permissions to read it.")gettext ("The folder \"%B\" cannot be deleted because you do not have "
"permissions to read it.")
, dir);
1659 } else {
1660 secondary = f (_("There was an error reading the folder \"%B\".")gettext ("There was an error reading the folder \"%B\"."), dir);
1661 details = error->message;
1662 }
1663
1664 response = run_warning (job,
1665 primary,
1666 secondary,
1667 details,
1668 FALSE(0),
1669 CANCELgettext ("_Cancel"), SKIPgettext ("_Skip"), RETRYgettext ("_Retry"),
1670 NULL((void*)0));
1671
1672 g_error_free (error);
1673
1674 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
1675 abort_job (job);
1676 } else if (response == 1) {
1677 /* Skip: Do Nothing */
1678 local_skipped_file = TRUE(!(0));
1679 } else if (response == 2) {
1680 goto retry;
1681 } else {
1682 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 1682, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1683 }
1684 }
1685
1686 if (!job_aborted (job) &&
1687 /* Don't delete dir if there was a skipped file */
1688 !local_skipped_file) {
1689 if (!g_file_delete (dir, job->cancellable, &error)) {
1690 if (job->skip_all_error) {
1691 goto skip;
1692 }
1693 primary = f (_("Error while deleting.")gettext ("Error while deleting."));
1694 secondary = f (_("Could not remove the folder %B.")gettext ("Could not remove the folder %B."), dir);
1695 details = error->message;
1696
1697 response = run_warning (job,
1698 primary,
1699 secondary,
1700 details,
1701 (source_info->num_files - transfer_info->num_files) > 1,
1702 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
1703 NULL((void*)0));
1704
1705 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
1706 abort_job (job);
1707 } else if (response == 1) { /* skip all */
1708 job->skip_all_error = TRUE(!(0));
1709 local_skipped_file = TRUE(!(0));
1710 } else if (response == 2) { /* skip */
1711 local_skipped_file = TRUE(!(0));
1712 } else {
1713 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 1713, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1714 }
1715
1716 skip:
1717 g_error_free (error);
1718 } else {
1719 baul_file_changes_queue_file_removed (dir);
1720 transfer_info->num_files ++;
1721 report_delete_progress (job, source_info, transfer_info);
1722 return;
1723 }
1724 }
1725
1726 if (local_skipped_file) {
1727 *skipped_file = TRUE(!(0));
1728 }
1729}
1730
1731static void
1732delete_file (CommonJob *job, GFile *file,
1733 gboolean *skipped_file,
1734 SourceInfo *source_info,
1735 TransferInfo *transfer_info,
1736 gboolean toplevel)
1737{
1738 GError *error;
1739 char *primary, *secondary, *details;
1740 int response;
1741
1742 if (should_skip_file (job, file)) {
1743 *skipped_file = TRUE(!(0));
1744 return;
1745 }
1746
1747 error = NULL((void*)0);
1748 if (g_file_delete (file, job->cancellable, &error)) {
1749 baul_file_changes_queue_file_removed (file);
1750 transfer_info->num_files ++;
1751 report_delete_progress (job, source_info, transfer_info);
1752 return;
1753 }
1754
1755 if (IS_IO_ERROR (error, NOT_EMPTY)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_EMPTY))
) {
1756 g_error_free (error);
1757 delete_dir (job, file,
1758 skipped_file,
1759 source_info, transfer_info,
1760 toplevel);
1761 return;
1762
1763 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
1764 g_error_free (error);
1765
1766 } else {
1767 if (job->skip_all_error) {
1768 goto skip;
1769 }
1770 primary = f (_("Error while deleting.")gettext ("Error while deleting."));
1771 secondary = f (_("There was an error deleting %B.")gettext ("There was an error deleting %B."), file);
1772 details = error->message;
1773
1774 response = run_warning (job,
1775 primary,
1776 secondary,
1777 details,
1778 (source_info->num_files - transfer_info->num_files) > 1,
1779 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
1780 NULL((void*)0));
1781
1782 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
1783 abort_job (job);
1784 } else if (response == 1) { /* skip all */
1785 job->skip_all_error = TRUE(!(0));
1786 } else if (response == 2) { /* skip */
1787 /* do nothing */
1788 } else {
1789 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 1789, ((const char*) (__func__)), ((void*)0)); } while (0)
;
1790 }
1791 skip:
1792 g_error_free (error);
1793 }
1794
1795 *skipped_file = TRUE(!(0));
1796}
1797
1798static void
1799delete_files (CommonJob *job, GList *files, int *files_skipped)
1800{
1801 GList *l;
1802 SourceInfo source_info;
1803 TransferInfo transfer_info;
1804 gboolean skipped_file;
1805 GFile *file = NULL((void*)0);
1806
1807 if (job_aborted (job)) {
1808 return;
1809 }
1810
1811 scan_sources (files,
1812 &source_info,
1813 job,
1814 OP_KIND_DELETE);
1815 if (job_aborted (job)) {
1816 return;
1817 }
1818
1819 g_timer_start (job->time);
1820
1821 memset (&transfer_info, 0, sizeof (transfer_info));
1822 report_delete_progress (job, &source_info, &transfer_info);
1823
1824 for (l = files;
1825 l != NULL((void*)0) && !job_aborted (job);
1826 l = l->next) {
1827 file = l->data;
1828
1829 skipped_file = FALSE(0);
1830 delete_file (job, file,
1831 &skipped_file,
1832 &source_info, &transfer_info,
1833 TRUE(!(0)));
1834 if (skipped_file) {
1835 (*files_skipped)++;
1836 }
1837 }
1838}
1839
1840static void
1841report_trash_progress (CommonJob *job,
1842 int files_trashed,
1843 int total_files)
1844{
1845 int files_left;
1846 char *s;
1847
1848 files_left = total_files - files_trashed;
1849
1850 baul_progress_info_take_status (job->progress,
1851 f (_("Moving files to trash")gettext ("Moving files to trash")));
1852
1853 s = f (ngettext ("%'d file left to trash",
1854 "%'d files left to trash",
1855 files_left),
1856 files_left);
1857 baul_progress_info_take_details (job->progress, s);
1858
1859 if (total_files != 0) {
1860 baul_progress_info_set_progress (job->progress, files_trashed, total_files);
1861 }
1862}
1863
1864
1865static void
1866trash_files (CommonJob *job, GList *files, int *files_skipped)
1867{
1868 GList *l;
1869 GFile *file;
1870 GList *to_delete;
1871 GError *error;
1872 int total_files, files_trashed;
1873 char *primary, *secondary, *details;
1874 int response;
1875
1876 guint64 mtime;
1877
1878 if (job_aborted (job)) {
1879 return;
1880 }
1881
1882 total_files = g_list_length (files);
1883 files_trashed = 0;
1884
1885 report_trash_progress (job, files_trashed, total_files);
1886
1887 to_delete = NULL((void*)0);
1888 for (l = files;
1889 l != NULL((void*)0) && !job_aborted (job);
1890 l = l->next) {
1891 baul_progress_info_get_ready (job->progress);
1892
1893 file = l->data;
1894
1895 error = NULL((void*)0);
1896
1897 mtime = baul_undostack_manager_get_file_modification_time (file);
1898
1899 if (!g_file_trash (file, job->cancellable, &error)) {
1900 if (job->skip_all_error) {
1901 (*files_skipped)++;
1902 goto skip;
1903 }
1904
1905 if (job->delete_all) {
1906 to_delete = g_list_prepend (to_delete, file);
1907 goto skip;
1908 }
1909
1910 primary = f (_("Cannot move file to trash, do you want to delete immediately?")gettext ("Cannot move file to trash, do you want to delete immediately?"
)
);
1911 secondary = f (_("The file \"%B\" cannot be moved to the trash.")gettext ("The file \"%B\" cannot be moved to the trash."), file);
1912 details = NULL((void*)0);
1913 if (!IS_IO_ERROR (error, NOT_SUPPORTED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_SUPPORTED))
) {
1914 details = error->message;
1915 }
1916
1917 response = run_question (job,
1918 primary,
1919 secondary,
1920 details,
1921 (total_files - files_trashed) > 1,
1922 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"), DELETE_ALLgettext ("Delete _All"), DELETEgettext ("_Delete"),
1923 NULL((void*)0));
1924
1925 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
1926 ((DeleteJob *) job)->user_cancel = TRUE(!(0));
1927 abort_job (job);
1928 } else if (response == 1) { /* skip all */
1929 (*files_skipped)++;
1930 job->skip_all_error = TRUE(!(0));
1931 } else if (response == 2) { /* skip */
1932 (*files_skipped)++;
1933 } else if (response == 3) { /* delete all */
1934 to_delete = g_list_prepend (to_delete, file);
1935 job->delete_all = TRUE(!(0));
1936 } else if (response == 4) { /* delete */
1937 to_delete = g_list_prepend (to_delete, file);
1938 }
1939
1940 skip:
1941 g_error_free (error);
1942 total_files--;
1943 } else {
1944 baul_file_changes_queue_file_removed (file);
1945
1946 // Start UNDO-REDO
1947 baul_undostack_manager_data_add_trashed_file (job->undo_redo_data, file, mtime);
1948 // End UNDO-REDO
1949
1950 files_trashed++;
1951 report_trash_progress (job, files_trashed, total_files);
1952 }
1953 }
1954
1955 if (to_delete) {
1956 to_delete = g_list_reverse (to_delete);
1957 delete_files (job, to_delete, files_skipped);
1958 g_list_free (to_delete);
1959 }
1960}
1961
1962static gboolean
1963delete_job_done (gpointer user_data)
1964{
1965 DeleteJob *job;
1966
1967 job = user_data;
1968
1969 g_list_free_full (job->files, g_object_unref);
1970
1971 if (job->done_callback) {
1972 GHashTable *debuting_uris;
1973
1974 debuting_uris = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
1975 job->done_callback (debuting_uris, job->user_cancel, job->done_callback_data);
1976 g_hash_table_unref (debuting_uris);
1977 }
1978
1979 finalize_common ((CommonJob *)job);
1980
1981 baul_file_changes_consume_changes (TRUE(!(0)));
1982
1983 return FALSE(0);
1984}
1985
1986static gboolean
1987delete_job (GIOSchedulerJob *io_job,
1988 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
1989 gpointer user_data)
1990{
1991 DeleteJob *job = user_data;
1992 GList *to_trash_files;
1993 GList *to_delete_files;
1994 GList *l;
1995 gboolean confirmed;
1996 CommonJob *common;
1997 gboolean must_confirm_delete_in_trash;
1998 gboolean must_confirm_delete;
1999 gboolean must_confirm_trash;
2000 int files_skipped;
2001 GFile *file = NULL((void*)0);
2002
2003 common = (CommonJob *)job;
2004 common->io_job = io_job;
2005
2006 baul_progress_info_start (job->common.progress);
2007
2008 to_trash_files = NULL((void*)0);
2009 to_delete_files = NULL((void*)0);
2010
2011 must_confirm_delete_in_trash = FALSE(0);
2012 must_confirm_delete = FALSE(0);
2013 must_confirm_trash = FALSE(0);
2014 files_skipped = 0;
2015
2016 for (l = job->files; l != NULL((void*)0); l = l->next) {
2017 file = l->data;
2018
2019 if (job->try_trash &&
2020 g_file_has_uri_scheme (file, "trash")) {
2021 must_confirm_delete_in_trash = TRUE(!(0));
2022 to_delete_files = g_list_prepend (to_delete_files, file);
2023 } else if (can_delete_without_confirm (file)) {
2024 to_delete_files = g_list_prepend (to_delete_files, file);
2025 } else {
2026 if (job->try_trash) {
2027 must_confirm_trash = TRUE(!(0));
2028 to_trash_files = g_list_prepend (to_trash_files, file);
2029 } else {
2030 must_confirm_delete = TRUE(!(0));
2031 to_delete_files = g_list_prepend (to_delete_files, file);
2032 }
2033 }
2034 }
2035
2036 if (to_delete_files != NULL((void*)0)) {
2037 to_delete_files = g_list_reverse (to_delete_files);
2038 confirmed = TRUE(!(0));
2039 if (must_confirm_delete_in_trash) {
2040 confirmed = confirm_delete_from_trash (common, to_delete_files);
2041 } else if (must_confirm_delete) {
2042 confirmed = confirm_delete_directly (common, to_delete_files);
2043 }
2044 if (confirmed) {
2045 delete_files (common, to_delete_files, &files_skipped);
2046 } else {
2047 job->user_cancel = TRUE(!(0));
2048 }
2049 }
2050
2051 if (to_trash_files != NULL((void*)0)) {
2052 to_trash_files = g_list_reverse (to_trash_files);
2053
2054 if (! must_confirm_trash || confirm_trash (common, to_trash_files)) {
2055 trash_files (common, to_trash_files, &files_skipped);
2056 } else {
2057 job->user_cancel = TRUE(!(0));
2058 }
2059 }
2060
2061 g_list_free (to_trash_files);
2062 g_list_free (to_delete_files);
2063
2064 if (files_skipped == g_list_length (job->files)) {
2065 /* User has skipped all files, report user cancel */
2066 job->user_cancel = TRUE(!(0));
2067 }
2068
2069 g_io_scheduler_job_send_to_mainloop_async (io_job,
2070 delete_job_done,
2071 job,
2072 NULL((void*)0));
2073
2074 return FALSE(0);
2075}
2076
2077static void
2078trash_or_delete_internal (GList *files,
2079 CtkWindow *parent_window,
2080 gboolean try_trash,
2081 BaulDeleteCallback done_callback,
2082 gpointer done_callback_data)
2083{
2084 DeleteJob *job;
2085
2086 /* TODO: special case desktop icon link files ... */
2087
2088 job = op_job_new (DeleteJob, parent_window, TRUE, FALSE)((DeleteJob *)(init_common (sizeof(DeleteJob), parent_window,
(!(0)), (0))))
;
2089 job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL((void*)0));
2090 job->try_trash = try_trash;
2091 job->user_cancel = FALSE(0);
2092 job->done_callback = done_callback;
2093 job->done_callback_data = done_callback_data;
2094
2095 if (try_trash) {
2096 inhibit_power_manager ((CommonJob *)job, _("Trashing Files")gettext ("Trashing Files"));
2097 } else {
2098 inhibit_power_manager ((CommonJob *)job, _("Deleting Files")gettext ("Deleting Files"));
2099 }
2100 // Start UNDO-REDO
2101 // FIXME: Disabled, because of missing mechanism to restore a file from trash in a clean way
2102 // see https://www.mail-archive.com/nautilus-list@gnome.org/msg04664.html
2103 if (try_trash && !baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
2104 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_MOVETOTRASH, g_list_length(files));
2105 GFile* src_dir = g_file_get_parent (files->data);
2106 baul_undostack_manager_data_set_src_dir (job->common.undo_redo_data, src_dir);
2107 }
2108 // End UNDO-REDO
2109
2110 g_io_scheduler_push_job (delete_job,
2111 job,
2112 NULL((void*)0),
2113 0,
2114 NULL((void*)0));
2115}
2116
2117void
2118baul_file_operations_trash_or_delete (GList *files,
2119 CtkWindow *parent_window,
2120 BaulDeleteCallback done_callback,
2121 gpointer done_callback_data)
2122{
2123 trash_or_delete_internal (files, parent_window,
2124 TRUE(!(0)),
2125 done_callback, done_callback_data);
2126}
2127
2128void
2129baul_file_operations_delete (GList *files,
2130 CtkWindow *parent_window,
2131 BaulDeleteCallback done_callback,
2132 gpointer done_callback_data)
2133{
2134 trash_or_delete_internal (files, parent_window,
2135 FALSE(0),
2136 done_callback, done_callback_data);
2137}
2138
2139
2140
2141typedef struct {
2142 gboolean eject;
2143 GMount *mount;
2144 CtkWindow *parent_window;
2145 BaulUnmountCallback callback;
2146 gpointer callback_data;
2147} UnmountData;
2148
2149static void
2150unmount_mount_callback (GObject *source_object,
2151 GAsyncResult *res,
2152 gpointer user_data)
2153{
2154 UnmountData *data = user_data;
2155 GError *error;
2156 gboolean unmounted;
2157
2158 error = NULL((void*)0);
2159 if (data->eject) {
2160 unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object)((((GMount*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_mount_get_type ()))))))
,
2161 res, &error);
2162 if ((!error) || (unmounted == TRUE(!(0)))){
2163 baul_application_notify_unmount_show (_("It is now safe to remove the drive")gettext ("It is now safe to remove the drive"));
2164 }
2165
2166 } else {
2167 unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object)((((GMount*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_mount_get_type ()))))))
,
2168 res, &error);
2169 }
2170
2171 if (! unmounted) {
2172 if (error && error->code != G_IO_ERROR_FAILED_HANDLED) {
2173 char *primary;
2174
2175 if (data->eject) {
2176 primary = f (_("Unable to eject %V")gettext ("Unable to eject %V"), source_object);
2177 } else {
2178 primary = f (_("Unable to unmount %V")gettext ("Unable to unmount %V"), source_object);
2179 }
2180 eel_show_error_dialog (primary,
2181 error->message,
2182 data->parent_window);
2183 g_free (primary);
2184 }
2185 }
2186
2187 if (data->callback) {
2188 data->callback (data->callback_data);
2189 }
2190
2191 if (error != NULL((void*)0)) {
2192 g_error_free (error);
2193 }
2194
2195 eel_remove_weak_pointer (&data->parent_window);
2196 g_object_unref (data->mount);
2197 g_free (data);
2198}
2199
2200static void
2201do_unmount (UnmountData *data)
2202{
2203 GMountOperation *mount_op;
2204
2205 mount_op = ctk_mount_operation_new (data->parent_window);
2206 if (data->eject) {
2207 g_mount_eject_with_operation (data->mount,
2208 0,
2209 mount_op,
2210 NULL((void*)0),
2211 unmount_mount_callback,
2212 data);
2213
2214 baul_application_notify_unmount_show (_("Writing data to the drive -- do not unplug")gettext ("Writing data to the drive -- do not unplug"));
2215
2216 } else {
2217 g_mount_unmount_with_operation (data->mount,
2218 0,
2219 mount_op,
2220 NULL((void*)0),
2221 unmount_mount_callback,
2222 data);
2223 }
2224 g_object_unref (mount_op);
2225}
2226
2227static gboolean
2228dir_has_files (GFile *dir)
2229{
2230 GFileEnumerator *enumerator;
2231 gboolean res;
2232
2233 res = FALSE(0);
2234
2235 enumerator = g_file_enumerate_children (dir,
2236 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name",
2237 0,
2238 NULL((void*)0), NULL((void*)0));
2239 if (enumerator) {
2240 GFileInfo *file_info;
2241
2242 file_info = g_file_enumerator_next_file (enumerator, NULL((void*)0), NULL((void*)0));
2243 if (file_info != NULL((void*)0)) {
2244 res = TRUE(!(0));
2245 g_object_unref (file_info);
2246 }
2247
2248 g_file_enumerator_close (enumerator, NULL((void*)0), NULL((void*)0));
2249 g_object_unref (enumerator);
2250 }
2251
2252
2253 return res;
2254}
2255
2256static GList *
2257get_trash_dirs_for_mount (GMount *mount)
2258{
2259 GFile *root;
2260 GList *list;
2261
2262 root = g_mount_get_root (mount);
2263 if (root == NULL((void*)0)) {
2264 return NULL((void*)0);
2265 }
2266
2267 list = NULL((void*)0);
2268
2269 if (g_file_is_native (root)) {
2270 GFile *trash;
2271 char *relpath;
2272
2273 relpath = g_strdup_printf (".Trash/%d", getuid ());
2274 trash = g_file_resolve_relative_path (root, relpath);
2275 g_free (relpath);
2276
2277 list = g_list_prepend (list, g_file_get_child (trash, "files"));
2278 list = g_list_prepend (list, g_file_get_child (trash, "info"));
2279
2280 g_object_unref (trash);
2281
2282 relpath = g_strdup_printf (".Trash-%d", getuid ());
2283 trash = g_file_get_child (root, relpath);
2284 g_free (relpath);
2285
2286 list = g_list_prepend (list, g_file_get_child (trash, "files"));
2287 list = g_list_prepend (list, g_file_get_child (trash, "info"));
2288
2289 g_object_unref (trash);
2290 }
2291
2292 g_object_unref (root);
2293
2294 return list;
2295}
2296
2297static gboolean
2298has_trash_files (GMount *mount)
2299{
2300 gboolean res;
2301 GList *dirs, *l;
2302 GFile *dir = NULL((void*)0);
2303
2304 dirs = get_trash_dirs_for_mount (mount);
2305
2306 res = FALSE(0);
2307
2308 for (l = dirs; l != NULL((void*)0); l = l->next) {
2309 dir = l->data;
2310
2311 if (dir_has_files (dir)) {
2312 res = TRUE(!(0));
2313 break;
2314 }
2315 }
2316
2317 g_list_free_full (dirs, g_object_unref);
2318
2319 return res;
2320}
2321
2322
2323static gint
2324prompt_empty_trash (CtkWindow *parent_window)
2325{
2326 gint result;
2327 CtkWidget *dialog;
2328 CdkScreen *screen;
2329
2330 screen = NULL((void*)0);
2331 if (parent_window != NULL((void*)0)) {
2332 screen = ctk_widget_get_screen (CTK_WIDGET (parent_window)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((parent_window)), ((ctk_widget_get_type ()))))))
);
2333 }
2334
2335 /* Do we need to be modal ? */
2336 dialog = ctk_message_dialog_new (NULL((void*)0), CTK_DIALOG_MODAL,
2337 CTK_MESSAGE_QUESTION, CTK_BUTTONS_NONE,
2338 _("Do you want to empty the trash before you unmount?")gettext ("Do you want to empty the trash before you unmount?"
)
);
2339 ctk_message_dialog_format_secondary_text (CTK_MESSAGE_DIALOG (dialog)((((CtkMessageDialog*) (void *) g_type_check_instance_cast ((
GTypeInstance*) ((dialog)), ((ctk_message_dialog_get_type ())
)))))
,
2340 _("In order to regain the "gettext ("In order to regain the " "free space on this volume "
"the trash must be emptied. " "All trashed items on the volume "
"will be permanently lost.")
2341 "free space on this volume "gettext ("In order to regain the " "free space on this volume "
"the trash must be emptied. " "All trashed items on the volume "
"will be permanently lost.")
2342 "the trash must be emptied. "gettext ("In order to regain the " "free space on this volume "
"the trash must be emptied. " "All trashed items on the volume "
"will be permanently lost.")
2343 "All trashed items on the volume "gettext ("In order to regain the " "free space on this volume "
"the trash must be emptied. " "All trashed items on the volume "
"will be permanently lost.")
2344 "will be permanently lost.")gettext ("In order to regain the " "free space on this volume "
"the trash must be emptied. " "All trashed items on the volume "
"will be permanently lost.")
);
2345
2346 ctk_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
,
2347 _("Do _not Empty Trash")gettext ("Do _not Empty Trash"), CTK_RESPONSE_REJECT);
2348
2349 eel_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
,
2350 CANCELgettext ("_Cancel"), "process-stop", CTK_RESPONSE_CANCEL);
2351
2352 ctk_dialog_add_button (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
,
2353 _("Empty _Trash")gettext ("Empty _Trash"), CTK_RESPONSE_ACCEPT);
2354
2355 ctk_dialog_set_default_response (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
, CTK_RESPONSE_ACCEPT);
2356 ctk_window_set_title (CTK_WINDOW (dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_window_get_type ()))))))
, ""); /* as per HIG */
2357 ctk_window_set_skip_taskbar_hint (CTK_WINDOW (dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_window_get_type ()))))))
, TRUE(!(0)));
2358 if (screen) {
2359 ctk_window_set_screen (CTK_WINDOW (dialog)((((CtkWindow*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_window_get_type ()))))))
, screen);
2360 }
2361 atk_object_set_role (ctk_widget_get_accessible (dialog), ATK_ROLE_ALERT);
2362
2363 /* Make transient for the window group */
2364 ctk_widget_realize (dialog);
2365 if (screen != NULL((void*)0)) {
2366 cdk_window_set_transient_for (ctk_widget_get_window (CTK_WIDGET (dialog)((((CtkWidget*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_widget_get_type ()))))))
),
2367 cdk_screen_get_root_window (screen));
2368 }
2369
2370 result = ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
2371 ctk_widget_destroy (dialog);
2372 return result;
2373}
2374
2375void
2376baul_file_operations_unmount_mount_full (CtkWindow *parent_window,
2377 GMount *mount,
2378 gboolean eject,
2379 gboolean check_trash,
2380 BaulUnmountCallback callback,
2381 gpointer callback_data)
2382{
2383 UnmountData *data;
2384
2385 data = g_new0 (UnmountData, 1)((UnmountData *) g_malloc0_n ((1), sizeof (UnmountData)));
2386 data->callback = callback;
2387 data->callback_data = callback_data;
2388 if (parent_window) {
2389 data->parent_window = parent_window;
2390 eel_add_weak_pointer (&data->parent_window);
2391
2392 }
2393 data->eject = eject;
2394 data->mount = g_object_ref (mount)((__typeof__ (mount)) (g_object_ref) (mount));
2395
2396 if (check_trash && has_trash_files (mount)) {
2397 int response;
2398
2399 response = prompt_empty_trash (parent_window);
2400
2401 if (response == CTK_RESPONSE_ACCEPT) {
2402 EmptyTrashJob *job;
2403
2404 job = op_job_new (EmptyTrashJob, parent_window, TRUE, FALSE)((EmptyTrashJob *)(init_common (sizeof(EmptyTrashJob), parent_window
, (!(0)), (0))))
;
2405 job->should_confirm = FALSE(0);
2406 job->trash_dirs = get_trash_dirs_for_mount (mount);
2407 job->done_callback = (BaulOpCallback)do_unmount;
2408 job->done_callback_data = data;
2409 g_io_scheduler_push_job (empty_trash_job,
2410 job,
2411 NULL((void*)0),
2412 0,
2413 NULL((void*)0));
2414 return;
2415 } else if (response == CTK_RESPONSE_CANCEL) {
2416 if (callback) {
2417 callback (callback_data);
2418 }
2419 eel_remove_weak_pointer (&data->parent_window);
2420 g_object_unref (data->mount);
2421 g_free (data);
2422 return;
2423 }
2424 }
2425
2426 do_unmount (data);
2427}
2428
2429void
2430baul_file_operations_unmount_mount (CtkWindow *parent_window,
2431 GMount *mount,
2432 gboolean eject,
2433 gboolean check_trash)
2434{
2435 baul_file_operations_unmount_mount_full (parent_window, mount, eject,
2436 check_trash, NULL((void*)0), NULL((void*)0));
2437}
2438
2439static void
2440mount_callback_data_notify (gpointer data,
2441 GObject *object G_GNUC_UNUSED__attribute__ ((__unused__)))
2442{
2443 GMountOperation *mount_op;
2444
2445 mount_op = G_MOUNT_OPERATION (data)((((GMountOperation*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((data)), ((g_mount_operation_get_type ()))))))
;
2446 g_object_set_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
, "mount-callback", NULL((void*)0));
2447 g_object_set_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
, "mount-callback-data", NULL((void*)0));
2448}
2449
2450static void
2451volume_mount_cb (GObject *source_object,
2452 GAsyncResult *res,
2453 gpointer user_data)
2454{
2455 BaulMountCallback mount_callback;
2456 GObject *mount_callback_data_object;
2457 GMountOperation *mount_op = user_data;
2458 GError *error;
2459
2460 error = NULL((void*)0);
2461 baul_allow_autorun_for_volume_finish (G_VOLUME (source_object)((((GVolume*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_volume_get_type ()))))))
);
2462 if (!g_volume_mount_finish (G_VOLUME (source_object)((((GVolume*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_volume_get_type ()))))))
, res, &error)) {
2463 if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2464 char *name;
2465 char *primary;
2466
2467 name = g_volume_get_name (G_VOLUME (source_object)((((GVolume*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_volume_get_type ()))))))
);
2468 primary = g_strdup_printf (_("Unable to mount %s")gettext ("Unable to mount %s"), name);
2469 g_free (name);
2470 eel_show_error_dialog (primary,
2471 error->message,
2472 NULL((void*)0));
2473 g_free (primary);
2474 }
2475 g_error_free (error);
2476 }
2477
2478 mount_callback = (BaulMountCallback)
2479 g_object_get_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
, "mount-callback");
2480 mount_callback_data_object =
2481 g_object_get_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
, "mount-callback-data");
2482
2483 if (mount_callback != NULL((void*)0)) {
2484 (* mount_callback) (G_VOLUME (source_object)((((GVolume*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((source_object)), ((g_volume_get_type ()))))))
,
2485 mount_callback_data_object);
2486
2487 if (mount_callback_data_object != NULL((void*)0)) {
2488 g_object_weak_unref (mount_callback_data_object,
2489 mount_callback_data_notify,
2490 mount_op);
2491 }
2492 }
2493
2494 g_object_unref (mount_op);
2495}
2496
2497
2498void
2499baul_file_operations_mount_volume (CtkWindow *parent_window,
2500 GVolume *volume,
2501 gboolean allow_autorun)
2502{
2503 baul_file_operations_mount_volume_full (parent_window, volume,
2504 allow_autorun, NULL((void*)0), NULL((void*)0));
2505}
2506
2507void
2508baul_file_operations_mount_volume_full (CtkWindow *parent_window,
2509 GVolume *volume,
2510 gboolean allow_autorun,
2511 BaulMountCallback mount_callback,
2512 GObject *mount_callback_data_object)
2513{
2514 GMountOperation *mount_op;
2515
2516 mount_op = ctk_mount_operation_new (parent_window);
2517 g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
2518 g_object_set_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
,
2519 "mount-callback",
2520 mount_callback);
2521
2522 if (mount_callback != NULL((void*)0) &&
2523 mount_callback_data_object != NULL((void*)0)) {
2524 g_object_weak_ref (mount_callback_data_object,
2525 mount_callback_data_notify,
2526 mount_op);
2527 }
2528 g_object_set_data (G_OBJECT (mount_op)((((GObject*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((mount_op)), (((GType) ((20) << (2))))))))
,
2529 "mount-callback-data",
2530 mount_callback_data_object);
2531
2532 if (allow_autorun)
2533 baul_allow_autorun_for_volume (volume);
2534 g_volume_mount (volume, 0, mount_op, NULL((void*)0), volume_mount_cb, mount_op);
2535}
2536
2537static void
2538report_count_progress (CommonJob *job,
2539 SourceInfo *source_info)
2540{
2541 char *s;
2542
2543 switch (source_info->op) {
2544 default:
2545 case OP_KIND_COPY:
2546 s = f (ngettext("Preparing to copy %'d file (%S)",
2547 "Preparing to copy %'d files (%S)",
2548 source_info->num_files),
2549 source_info->num_files, source_info->num_bytes);
2550 break;
2551 case OP_KIND_MOVE:
2552 s = f (ngettext("Preparing to move %'d file (%S)",
2553 "Preparing to move %'d files (%S)",
2554 source_info->num_files),
2555 source_info->num_files, source_info->num_bytes);
2556 break;
2557 case OP_KIND_DELETE:
2558 s = f (ngettext("Preparing to delete %'d file (%S)",
2559 "Preparing to delete %'d files (%S)",
2560 source_info->num_files),
2561 source_info->num_files, source_info->num_bytes);
2562 break;
2563 case OP_KIND_TRASH:
2564 s = f (ngettext("Preparing to trash %'d file",
2565 "Preparing to trash %'d files",
2566 source_info->num_files),
2567 source_info->num_files);
2568 break;
2569 }
2570
2571 baul_progress_info_take_details (job->progress, s);
2572 baul_progress_info_pulse_progress (job->progress);
2573}
2574
2575static void
2576count_file (GFileInfo *info,
2577 CommonJob *job,
2578 SourceInfo *source_info)
2579{
2580 source_info->num_files += 1;
2581 source_info->num_bytes += g_file_info_get_size (info);
2582
2583 if (source_info->num_files_since_progress++ > 100) {
2584 report_count_progress (job, source_info);
2585 source_info->num_files_since_progress = 0;
2586 }
2587}
2588
2589static char *
2590get_scan_primary (OpKind kind)
2591{
2592 switch (kind) {
2593 default:
2594 case OP_KIND_COPY:
2595 return f (_("Error while copying.")gettext ("Error while copying."));
2596 case OP_KIND_MOVE:
2597 return f (_("Error while moving.")gettext ("Error while moving."));
2598 case OP_KIND_DELETE:
2599 return f (_("Error while deleting.")gettext ("Error while deleting."));
2600 case OP_KIND_TRASH:
2601 return f (_("Error while moving files to trash.")gettext ("Error while moving files to trash."));
2602 }
2603}
2604
2605static void
2606scan_dir (GFile *dir,
2607 SourceInfo *source_info,
2608 CommonJob *job,
2609 GQueue *dirs)
2610{
2611 GFileInfo *info;
2612 GError *error;
2613 GFile *subdir;
2614 GFileEnumerator *enumerator;
2615 char *primary, *secondary, *details;
2616 int response;
2617 SourceInfo saved_info;
2618
2619 saved_info = *source_info;
2620
2621 retry:
2622 error = NULL((void*)0);
2623 enumerator = g_file_enumerate_children (dir,
2624 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name"","
2625 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
2626 G_FILE_ATTRIBUTE_STANDARD_SIZE"standard::size"","
2627 G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE"standard::allocated-size",
2628 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2629 job->cancellable,
2630 &error);
2631 if (enumerator) {
2632 error = NULL((void*)0);
2633 while ((info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL((void*)0)) {
2634 count_file (info, job, source_info);
2635
2636 if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2637 subdir = g_file_get_child (dir,
2638 g_file_info_get_name (info));
2639
2640 /* Push to head, since we want depth-first */
2641 g_queue_push_head (dirs, subdir);
2642 }
2643
2644 g_object_unref (info);
2645 }
2646 g_file_enumerator_close (enumerator, job->cancellable, NULL((void*)0));
2647 g_object_unref (enumerator);
2648
2649 if (error && IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
2650 g_error_free (error);
2651 } else if (error) {
2652 primary = get_scan_primary (source_info->op);
2653 details = NULL((void*)0);
2654
2655 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
2656 secondary = f (_("Files in the folder \"%B\" cannot be handled because you do "gettext ("Files in the folder \"%B\" cannot be handled because you do "
"not have permissions to see them.")
2657 "not have permissions to see them.")gettext ("Files in the folder \"%B\" cannot be handled because you do "
"not have permissions to see them.")
, dir);
2658 } else {
2659 secondary = f (_("There was an error getting information about the files in the folder \"%B\".")gettext ("There was an error getting information about the files in the folder \"%B\"."
)
, dir);
2660 details = error->message;
2661 }
2662
2663 response = run_warning (job,
2664 primary,
2665 secondary,
2666 details,
2667 FALSE(0),
2668 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"), SKIPgettext ("_Skip"),
2669 NULL((void*)0));
2670
2671 g_error_free (error);
2672
2673 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
2674 abort_job (job);
2675 } else if (response == 1) {
2676 *source_info = saved_info;
2677 goto retry;
2678 } else if (response == 2) {
2679 skip_readdir_error (job, dir);
2680 } else {
2681 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 2681, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2682 }
2683 }
2684
2685 } else if (job->skip_all_error) {
2686 g_error_free (error);
2687 skip_file (job, dir);
2688 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
2689 g_error_free (error);
2690 } else {
2691 primary = get_scan_primary (source_info->op);
2692 details = NULL((void*)0);
2693
2694 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
2695 secondary = f (_("The folder \"%B\" cannot be handled because you do not have "gettext ("The folder \"%B\" cannot be handled because you do not have "
"permissions to read it.")
2696 "permissions to read it.")gettext ("The folder \"%B\" cannot be handled because you do not have "
"permissions to read it.")
, dir);
2697 } else {
2698 secondary = f (_("There was an error reading the folder \"%B\".")gettext ("There was an error reading the folder \"%B\"."), dir);
2699 details = error->message;
2700 }
2701 /* set show_all to TRUE here, as we don't know how many
2702 * files we'll end up processing yet.
2703 */
2704 response = run_warning (job,
2705 primary,
2706 secondary,
2707 details,
2708 TRUE(!(0)),
2709 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"), RETRYgettext ("_Retry"),
2710 NULL((void*)0));
2711
2712 g_error_free (error);
2713
2714 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
2715 abort_job (job);
2716 } else if (response == 1 || response == 2) {
2717 if (response == 1) {
2718 job->skip_all_error = TRUE(!(0));
2719 }
2720 skip_file (job, dir);
2721 } else if (response == 3) {
2722 goto retry;
2723 } else {
2724 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 2724, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2725 }
2726 }
2727}
2728
2729static void
2730scan_file (GFile *file,
2731 SourceInfo *source_info,
2732 CommonJob *job)
2733{
2734 GFileInfo *info;
2735 GError *error;
2736 GQueue *dirs;
2737 GFile *dir;
2738 char *primary;
2739 char *secondary;
2740 char *details;
2741 int response;
2742
2743 dirs = g_queue_new ();
2744
2745 retry:
2746 error = NULL((void*)0);
2747 info = g_file_query_info (file,
2748 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
2749 G_FILE_ATTRIBUTE_STANDARD_SIZE"standard::size"","
2750 G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE"standard::allocated-size",
2751 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2752 job->cancellable,
2753 &error);
2754
2755 if (info) {
2756 count_file (info, job, source_info);
2757
2758 if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2759 g_queue_push_head (dirs, g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file)));
2760 }
2761
2762 g_object_unref (info);
2763 } else if (job->skip_all_error) {
2764 g_error_free (error);
2765 skip_file (job, file);
2766 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
2767 g_error_free (error);
2768 } else {
2769 primary = get_scan_primary (source_info->op);
2770 details = NULL((void*)0);
2771
2772 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
2773 secondary = f (_("The file \"%B\" cannot be handled because you do not have "gettext ("The file \"%B\" cannot be handled because you do not have "
"permissions to read it.")
2774 "permissions to read it.")gettext ("The file \"%B\" cannot be handled because you do not have "
"permissions to read it.")
, file);
2775 } else {
2776 secondary = f (_("There was an error getting information about \"%B\".")gettext ("There was an error getting information about \"%B\"."
)
, file);
2777 details = error->message;
2778 }
2779 /* set show_all to TRUE here, as we don't know how many
2780 * files we'll end up processing yet.
2781 */
2782 response = run_warning (job,
2783 primary,
2784 secondary,
2785 details,
2786 TRUE(!(0)),
2787 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"), RETRYgettext ("_Retry"),
2788 NULL((void*)0));
2789
2790 g_error_free (error);
2791
2792 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
2793 abort_job (job);
2794 } else if (response == 1 || response == 2) {
2795 if (response == 1) {
2796 job->skip_all_error = TRUE(!(0));
2797 }
2798 skip_file (job, file);
2799 } else if (response == 3) {
2800 goto retry;
2801 } else {
2802 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 2802, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2803 }
2804 }
2805
2806 while (!job_aborted (job) &&
2807 (dir = g_queue_pop_head (dirs)) != NULL((void*)0)) {
2808 scan_dir (dir, source_info, job, dirs);
2809 g_object_unref (dir);
2810 }
2811
2812 /* Free all from queue if we exited early */
2813 g_queue_foreach (dirs, (GFunc)g_object_unref, NULL((void*)0));
2814 g_queue_free (dirs);
2815}
2816
2817static void
2818scan_sources (GList *files,
2819 SourceInfo *source_info,
2820 CommonJob *job,
2821 OpKind kind)
2822{
2823 GList *l;
2824 GFile *file = NULL((void*)0);
2825
2826 memset (source_info, 0, sizeof (SourceInfo));
2827 source_info->op = kind;
2828
2829 report_count_progress (job, source_info);
2830
2831 for (l = files; l != NULL((void*)0) && !job_aborted (job); l = l->next) {
2832 file = l->data;
2833
2834 scan_file (file,
2835 source_info,
2836 job);
2837 }
2838
2839 /* Make sure we report the final count */
2840 report_count_progress (job, source_info);
2841}
2842
2843static void
2844verify_destination (CommonJob *job,
2845 GFile *dest,
2846 char **dest_fs_id,
2847 goffset required_size)
2848{
2849 GFileInfo *info, *fsinfo;
2850 GError *error;
2851 guint64 free_size;
2852 char *primary, *secondary, *details;
2853 int response;
2854 GFileType file_type;
2855
2856 if (dest_fs_id) {
2857 *dest_fs_id = NULL((void*)0);
2858 }
2859
2860 retry:
2861
2862 error = NULL((void*)0);
2863 info = g_file_query_info (dest,
2864 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
2865 G_FILE_ATTRIBUTE_ID_FILESYSTEM"id::filesystem",
2866 0,
2867 job->cancellable,
2868 &error);
2869
2870 if (info == NULL((void*)0)) {
2871 if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
2872 g_error_free (error);
2873 return;
2874 }
2875
2876 primary = f (_("Error while copying to \"%B\".")gettext ("Error while copying to \"%B\"."), dest);
2877 details = NULL((void*)0);
2878
2879 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
2880 secondary = f (_("You do not have permissions to access the destination folder.")gettext ("You do not have permissions to access the destination folder."
)
);
2881 } else {
2882 secondary = f (_("There was an error getting information about the destination.")gettext ("There was an error getting information about the destination."
)
);
2883 details = error->message;
2884 }
2885
2886 response = run_error (job,
2887 primary,
2888 secondary,
2889 details,
2890 FALSE(0),
2891 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"),
2892 NULL((void*)0));
2893
2894 g_error_free (error);
2895
2896 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
2897 abort_job (job);
2898 } else if (response == 1) {
2899 goto retry;
2900 } else {
2901 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 2901, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2902 }
2903
2904 return;
2905 }
2906
2907 file_type = g_file_info_get_file_type (info);
2908
2909 if (dest_fs_id) {
2910 *dest_fs_id =
2911 g_strdup (g_file_info_get_attribute_string (info,g_strdup_inline (g_file_info_get_attribute_string (info, "id::filesystem"
))
2912 G_FILE_ATTRIBUTE_ID_FILESYSTEM))g_strdup_inline (g_file_info_get_attribute_string (info, "id::filesystem"
))
;
2913 }
2914
2915 g_object_unref (info);
2916
2917 if (file_type != G_FILE_TYPE_DIRECTORY) {
2918 primary = f (_("Error while copying to \"%B\".")gettext ("Error while copying to \"%B\"."), dest);
2919 secondary = f (_("The destination is not a folder.")gettext ("The destination is not a folder."));
2920
2921 response = run_error (job,
2922 primary,
2923 secondary,
2924 NULL((void*)0),
2925 FALSE(0),
2926 CANCELgettext ("_Cancel"),
2927 NULL((void*)0));
2928
2929 abort_job (job);
2930 return;
2931 }
2932
2933 fsinfo = g_file_query_filesystem_info (dest,
2934 G_FILE_ATTRIBUTE_FILESYSTEM_FREE"filesystem::free"","
2935 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY"filesystem::readonly",
2936 job->cancellable,
2937 NULL((void*)0));
2938 if (fsinfo == NULL((void*)0)) {
2939 /* All sorts of things can go wrong getting the fs info (like not supported)
2940 * only check these things if the fs returns them
2941 */
2942 return;
2943 }
2944
2945 if (required_size > 0 &&
2946 g_file_info_has_attribute (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_FREE"filesystem::free")) {
2947 free_size = g_file_info_get_attribute_uint64 (fsinfo,
2948 G_FILE_ATTRIBUTE_FILESYSTEM_FREE"filesystem::free");
2949
2950 if (free_size < required_size) {
2951 primary = f (_("Error while copying to \"%B\".")gettext ("Error while copying to \"%B\"."), dest);
2952 secondary = f(_("There is not enough space on the destination. Try to remove files to make space.")gettext ("There is not enough space on the destination. Try to remove files to make space."
)
);
2953
2954 details = f (_("There is %S available, but %S is required.")gettext ("There is %S available, but %S is required."), free_size, required_size);
2955
2956 response = run_warning (job,
2957 primary,
2958 secondary,
2959 details,
2960 FALSE(0),
2961 CANCELgettext ("_Cancel"),
2962 COPY_FORCEgettext ("Copy _Anyway"),
2963 RETRYgettext ("_Retry"),
2964 NULL((void*)0));
2965
2966 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
2967 abort_job (job);
2968 } else if (response == 2) {
2969 goto retry;
2970 } else if (response == 1) {
2971 /* We are forced to copy - just fall through ... */
2972 } else {
2973 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 2973, ((const char*) (__func__)), ((void*)0)); } while (0)
;
2974 }
2975 }
2976 }
2977
2978 if (!job_aborted (job) &&
2979 g_file_info_get_attribute_boolean (fsinfo,
2980 G_FILE_ATTRIBUTE_FILESYSTEM_READONLY"filesystem::readonly")) {
2981 primary = f (_("Error while copying to \"%B\".")gettext ("Error while copying to \"%B\"."), dest);
2982 secondary = f (_("The destination is read-only.")gettext ("The destination is read-only."));
2983
2984 response = run_error (job,
2985 primary,
2986 secondary,
2987 NULL((void*)0),
2988 FALSE(0),
2989 CANCELgettext ("_Cancel"),
2990 NULL((void*)0));
2991
2992 g_error_free (error);
2993
2994 abort_job (job);
2995 }
2996
2997 g_object_unref (fsinfo);
2998}
2999
3000static void
3001report_copy_progress (CopyMoveJob *copy_job,
3002 SourceInfo *source_info,
3003 TransferInfo *transfer_info)
3004{
3005 int files_left;
3006 goffset total_size;
3007 double elapsed, transfer_rate;
3008 guint64 now;
3009 CommonJob *job;
3010 gboolean is_move;
3011
3012 job = (CommonJob *)copy_job;
3013
3014 is_move = copy_job->is_move;
3015
3016 now = g_get_monotonic_time ();
3017
3018 if (transfer_info->last_report_time != 0 &&
3019 ABS ((gint64)(transfer_info->last_report_time - now))((((gint64)(transfer_info->last_report_time - now)) < 0
) ? -((gint64)(transfer_info->last_report_time - now)) : (
(gint64)(transfer_info->last_report_time - now)))
< 100 * NSEC_PER_MICROSEC1000) {
3020 return;
3021 }
3022 transfer_info->last_report_time = now;
3023
3024 files_left = source_info->num_files - transfer_info->num_files;
3025
3026 /* Races and whatnot could cause this to be negative... */
3027 if (files_left < 0) {
3028 files_left = 1;
3029 }
3030
3031 if (files_left != transfer_info->last_reported_files_left ||
3032 transfer_info->last_reported_files_left == 0) {
3033 /* Avoid changing this unless files_left changed since last time */
3034 transfer_info->last_reported_files_left = files_left;
3035
3036 if (source_info->num_files == 1) {
3037 if (copy_job->destination != NULL((void*)0)) {
3038 baul_progress_info_take_status (job->progress,
3039 f (is_move ?
3040 _("Moving \"%B\" to \"%B\"")gettext ("Moving \"%B\" to \"%B\""):
3041 _("Copying \"%B\" to \"%B\"")gettext ("Copying \"%B\" to \"%B\""),
3042 (GFile *)copy_job->files->data,
3043 copy_job->destination));
3044 } else {
3045 baul_progress_info_take_status (job->progress,
3046 f (_("Duplicating \"%B\"")gettext ("Duplicating \"%B\""),
3047 (GFile *)copy_job->files->data));
3048 }
3049 } else if (copy_job->files != NULL((void*)0) &&
3050 copy_job->files->next == NULL((void*)0)) {
3051 if (copy_job->destination != NULL((void*)0)) {
3052 baul_progress_info_take_status (job->progress,
3053 f (is_move?
3054 ngettext ("Moving %'d file (in \"%B\") to \"%B\"",
3055 "Moving %'d files (in \"%B\") to \"%B\"",
3056 files_left)
3057 :
3058 ngettext ("Copying %'d file (in \"%B\") to \"%B\"",
3059 "Copying %'d files (in \"%B\") to \"%B\"",
3060 files_left),
3061 files_left,
3062 (GFile *)copy_job->files->data,
3063 copy_job->destination));
3064 } else {
3065 baul_progress_info_take_status (job->progress,
3066 f (ngettext ("Duplicating %'d file (in \"%B\")",
3067 "Duplicating %'d files (in \"%B\")",
3068 files_left),
3069 files_left,
3070 (GFile *)copy_job->files->data));
3071 }
3072 } else {
3073 if (copy_job->destination != NULL((void*)0)) {
3074 baul_progress_info_take_status (job->progress,
3075 f (is_move?
3076 ngettext ("Moving %'d file to \"%B\"",
3077 "Moving %'d files to \"%B\"",
3078 files_left)
3079 :
3080 ngettext ("Copying %'d file to \"%B\"",
3081 "Copying %'d files to \"%B\"",
3082 files_left),
3083 files_left, copy_job->destination));
3084 } else {
3085 baul_progress_info_take_status (job->progress,
3086 f (ngettext ("Duplicating %'d file",
3087 "Duplicating %'d files",
3088 files_left),
3089 files_left));
3090 }
3091 }
3092 }
3093
3094 total_size = MAX (source_info->num_bytes, transfer_info->num_bytes)(((source_info->num_bytes) > (transfer_info->num_bytes
)) ? (source_info->num_bytes) : (transfer_info->num_bytes
))
;
3095
3096 elapsed = g_timer_elapsed (job->time, NULL((void*)0));
3097 transfer_rate = 0;
3098 if (elapsed > 0) {
3099 transfer_rate = transfer_info->num_bytes / elapsed;
3100 }
3101
3102 if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE15 &&
3103 transfer_rate > 0) {
3104 char *s;
3105 /* Translators: %S will expand to a size like "2 bytes" or "3 MB", so something like "4 kb of 4 MB" */
3106 s = f (_("%S of %S")gettext ("%S of %S"), transfer_info->num_bytes, total_size);
3107 baul_progress_info_take_details (job->progress, s);
3108 } else {
3109 int remaining_time;
3110 char *s;
3111
3112 remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
3113
3114 /* Translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration like
3115 * "2 minutes". So the whole thing will be something like "2 kb of 4 MB -- 2 hours left (4kb/sec)"
3116 *
3117 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
3118 */
3119 s = f (ngettext ("%S of %S \xE2\x80\x94 %T left (%S/sec)",
3120 "%S of %S \xE2\x80\x94 %T left (%S/sec)",
3121 seconds_count_format_time_units (remaining_time)),
3122 transfer_info->num_bytes, total_size,
3123 remaining_time,
3124 (goffset)transfer_rate);
3125 baul_progress_info_take_details (job->progress, s);
3126 }
3127
3128 baul_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size);
3129}
3130
3131static int
3132get_max_name_length (GFile *file_dir)
3133{
3134 int max_length;
3135 char *dir;
3136 long max_path;
3137 long max_name;
3138
3139 max_length = -1;
3140
3141 if (!g_file_has_uri_scheme (file_dir, "file"))
3142 return max_length;
3143
3144 dir = g_file_get_path (file_dir);
3145 if (!dir)
3146 return max_length;
3147
3148 max_path = pathconf (dir, _PC_PATH_MAX_PC_PATH_MAX);
3149 max_name = pathconf (dir, _PC_NAME_MAX_PC_NAME_MAX);
3150
3151 if (max_name == -1 && max_path == -1) {
3152 max_length = -1;
3153 } else if (max_name == -1 && max_path != -1) {
3154 max_length = max_path - (strlen (dir) + 1);
3155 } else if (max_name != -1 && max_path == -1) {
3156 max_length = max_name;
3157 } else {
3158 int leftover;
3159
3160 leftover = max_path - (strlen (dir) + 1);
3161
3162 max_length = MIN (leftover, max_name)(((leftover) < (max_name)) ? (leftover) : (max_name));
3163 }
3164
3165 g_free (dir);
3166
3167 return max_length;
3168}
3169
3170#define FAT_FORBIDDEN_CHARACTERS"/:;*?\"<>" "/:;*?\"<>"
3171
3172static gboolean
3173str_replace (char *str,
3174 const char *chars_to_replace,
3175 char replacement)
3176{
3177 gboolean success;
3178 int i;
3179
3180 success = FALSE(0);
3181 for (i = 0; str[i] != '\0'; i++) {
3182 if (strchr (chars_to_replace, str[i])) {
3183 success = TRUE(!(0));
3184 str[i] = replacement;
3185 }
3186 }
3187
3188 return success;
3189}
3190
3191static gboolean
3192make_file_name_valid_for_dest_fs (char *filename,
3193 const char *dest_fs_type)
3194{
3195 if (dest_fs_type != NULL((void*)0) && filename != NULL((void*)0)) {
3196 if (!strcmp (dest_fs_type, "fat") ||
3197 !strcmp (dest_fs_type, "vfat") ||
3198 !strcmp (dest_fs_type, "msdos") ||
3199 !strcmp (dest_fs_type, "msdosfs")) {
3200 gboolean ret;
3201 int i, old_len;
3202
3203 ret = str_replace (filename, FAT_FORBIDDEN_CHARACTERS"/:;*?\"<>", '_');
3204
3205 old_len = strlen (filename);
3206 for (i = 0; i < old_len; i++) {
3207 if (filename[i] != ' ') {
3208 g_strchomp (filename);
3209 ret |= (old_len != strlen (filename));
3210 break;
3211 }
3212 }
3213
3214 return ret;
3215 }
3216 }
3217
3218 return FALSE(0);
3219}
3220
3221static GFile *
3222get_unique_target_file (GFile *src,
3223 GFile *dest_dir,
3224 gboolean same_fs G_GNUC_UNUSED__attribute__ ((__unused__)),
3225 const char *dest_fs_type,
3226 int count)
3227{
3228 char *new_name;
3229 GFileInfo *info;
3230 GFile *dest;
3231 int max_length;
3232
3233 max_length = get_max_name_length (dest_dir);
3234
3235 dest = NULL((void*)0);
3236 info = g_file_query_info (src,
3237 G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME"standard::edit-name",
3238 0, NULL((void*)0), NULL((void*)0));
3239 if (info != NULL((void*)0)) {
3240 const char *editname;
3241
3242 editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME"standard::edit-name");
3243
3244 if (editname != NULL((void*)0)) {
3245 new_name = get_duplicate_name (editname, count, max_length);
3246 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3247 dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL((void*)0));
3248 g_free (new_name);
3249 }
3250
3251 g_object_unref (info);
3252 }
3253
3254 if (dest == NULL((void*)0)) {
3255 char *basename;
3256
3257 basename = g_file_get_basename (src);
3258
3259 if (g_utf8_validate (basename, -1, NULL((void*)0))) {
3260 new_name = get_duplicate_name (basename, count, max_length);
3261 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3262 dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL((void*)0));
3263 g_free (new_name);
3264 }
3265
3266 if (dest == NULL((void*)0)) {
3267 const char *end;
3268
3269 end = strrchr (basename, '.');
3270 if (end != NULL((void*)0)) {
3271 count += atoi (end + 1);
3272 }
3273 new_name = g_strdup_printf ("%s.%d", basename, count);
3274 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3275 dest = g_file_get_child (dest_dir, new_name);
3276 g_free (new_name);
3277 }
3278
3279 g_free (basename);
3280 }
3281
3282 return dest;
3283}
3284
3285static GFile *
3286get_target_file_for_link (GFile *src,
3287 GFile *dest_dir,
3288 const char *dest_fs_type,
3289 int count)
3290{
3291 char *new_name;
3292 GFileInfo *info;
3293 GFile *dest;
3294 int max_length;
3295
3296 max_length = get_max_name_length (dest_dir);
3297
3298 dest = NULL((void*)0);
3299 info = g_file_query_info (src,
3300 G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME"standard::edit-name",
3301 0, NULL((void*)0), NULL((void*)0));
3302 if (info != NULL((void*)0)) {
3303 const char *editname;
3304
3305 editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME"standard::edit-name");
3306
3307 if (editname != NULL((void*)0)) {
3308 new_name = get_link_name (editname, count, max_length);
3309 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3310 dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL((void*)0));
3311 g_free (new_name);
3312 }
3313
3314 g_object_unref (info);
3315 }
3316
3317 if (dest == NULL((void*)0)) {
3318 char *basename;
3319
3320 basename = g_file_get_basename (src);
3321 make_file_name_valid_for_dest_fs (basename, dest_fs_type);
3322
3323 if (g_utf8_validate (basename, -1, NULL((void*)0))) {
3324 new_name = get_link_name (basename, count, max_length);
3325 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3326 dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL((void*)0));
3327 g_free (new_name);
3328 }
3329
3330 if (dest == NULL((void*)0)) {
3331 if (count == 1) {
3332 new_name = g_strdup_printf ("%s.lnk", basename);
3333 } else {
3334 new_name = g_strdup_printf ("%s.lnk%d", basename, count);
3335 }
3336 make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3337 dest = g_file_get_child (dest_dir, new_name);
3338 g_free (new_name);
3339 }
3340
3341 g_free (basename);
3342 }
3343
3344 return dest;
3345}
3346
3347static GFile *
3348get_target_file (GFile *src,
3349 GFile *dest_dir,
3350 const char *dest_fs_type,
3351 gboolean same_fs)
3352{
3353 GFile *dest;
3354
3355 dest = NULL((void*)0);
3356 if (!same_fs) {
3357 GFileInfo *info;
3358
3359 info = g_file_query_info (src,
3360 G_FILE_ATTRIBUTE_STANDARD_COPY_NAME"standard::copy-name",
3361 0, NULL((void*)0), NULL((void*)0));
3362
3363 if (info) {
3364 char *copyname;
3365
3366 copyname = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME))g_strdup_inline (g_file_info_get_attribute_string (info, "standard::copy-name"
))
;
3367
3368 if (copyname) {
3369 make_file_name_valid_for_dest_fs (copyname, dest_fs_type);
3370 dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL((void*)0));
3371 g_free (copyname);
3372 }
3373
3374 g_object_unref (info);
3375 }
3376 }
3377
3378 if (dest == NULL((void*)0)) {
3379 char *basename;
3380
3381 basename = g_file_get_basename (src);
3382 make_file_name_valid_for_dest_fs (basename, dest_fs_type);
3383 dest = g_file_get_child (dest_dir, basename);
3384 g_free (basename);
3385 }
3386
3387 return dest;
3388}
3389
3390static gboolean
3391has_fs_id (GFile *file, const char *fs_id)
3392{
3393 GFileInfo *info;
3394 gboolean res;
3395
3396 res = FALSE(0);
3397 info = g_file_query_info (file,
3398 G_FILE_ATTRIBUTE_ID_FILESYSTEM"id::filesystem",
3399 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3400 NULL((void*)0), NULL((void*)0));
3401
3402 if (info) {
3403 const char *id;
3404
3405 id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM"id::filesystem");
3406
3407 if (id && strcmp (id, fs_id) == 0) {
3408 res = TRUE(!(0));
3409 }
3410
3411 g_object_unref (info);
3412 }
3413
3414 return res;
3415}
3416
3417static gboolean
3418is_dir (GFile *file)
3419{
3420 GFileInfo *info;
3421 gboolean res;
3422
3423 res = FALSE(0);
3424 info = g_file_query_info (file,
3425 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
3426 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3427 NULL((void*)0), NULL((void*)0));
3428 if (info) {
3429 res = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
3430 g_object_unref (info);
3431 }
3432
3433 return res;
3434}
3435
3436static void copy_move_file (CopyMoveJob *job,
3437 GFile *src,
3438 GFile *dest_dir,
3439 gboolean same_fs,
3440 gboolean unique_names,
3441 char **dest_fs_type,
3442 SourceInfo *source_info,
3443 TransferInfo *transfer_info,
3444 GHashTable *debuting_files,
3445 CdkPoint *point,
3446 gboolean overwrite,
3447 gboolean *skipped_file,
3448 gboolean readonly_source_fs,
3449 gboolean last_item);
3450
3451typedef enum {
3452 CREATE_DEST_DIR_RETRY,
3453 CREATE_DEST_DIR_FAILED,
3454 CREATE_DEST_DIR_SUCCESS
3455} CreateDestDirResult;
3456
3457static CreateDestDirResult
3458create_dest_dir (CommonJob *job,
3459 GFile *src,
3460 GFile **dest,
3461 gboolean same_fs,
3462 char **dest_fs_type)
3463{
3464 GError *error;
3465 GFile *new_dest, *dest_dir;
3466 char *primary, *secondary, *details;
3467 int response;
3468 gboolean handled_invalid_filename;
3469
3470 handled_invalid_filename = *dest_fs_type != NULL((void*)0);
3471
3472 retry:
3473 /* First create the directory, then copy stuff to it before
3474 copying the attributes, because we need to be sure we can write to it */
3475
3476 error = NULL((void*)0);
3477 if (!g_file_make_directory (*dest, job->cancellable, &error)) {
3478 if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
3479 g_error_free (error);
3480 return CREATE_DEST_DIR_FAILED;
3481 } else if (IS_IO_ERROR (error, INVALID_FILENAME)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_INVALID_FILENAME))
&&
3482 !handled_invalid_filename) {
3483 handled_invalid_filename = TRUE(!(0));
3484
3485 g_assert (*dest_fs_type == NULL)do { if (*dest_fs_type == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 3485, ((const char*
) (__func__)), "*dest_fs_type == NULL"); } while (0)
;
3486
3487 dest_dir = g_file_get_parent (*dest);
3488
3489 if (dest_dir != NULL((void*)0)) {
3490 *dest_fs_type = query_fs_type (dest_dir, job->cancellable);
3491
3492 new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
3493 g_object_unref (dest_dir);
3494
3495 if (!g_file_equal (*dest, new_dest)) {
3496 g_object_unref (*dest);
3497 *dest = new_dest;
3498 g_error_free (error);
3499 return CREATE_DEST_DIR_RETRY;
3500 } else {
3501 g_object_unref (new_dest);
3502 }
3503 }
3504 }
3505
3506 primary = f (_("Error while copying.")gettext ("Error while copying."));
3507 details = NULL((void*)0);
3508
3509 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
3510 secondary = f (_("The folder \"%B\" cannot be copied because you do not have "gettext ("The folder \"%B\" cannot be copied because you do not have "
"permissions to create it in the destination.")
3511 "permissions to create it in the destination.")gettext ("The folder \"%B\" cannot be copied because you do not have "
"permissions to create it in the destination.")
, src);
3512 } else {
3513 secondary = f (_("There was an error creating the folder \"%B\".")gettext ("There was an error creating the folder \"%B\"."), src);
3514 details = error->message;
3515 }
3516
3517 response = run_warning (job,
3518 primary,
3519 secondary,
3520 details,
3521 FALSE(0),
3522 CANCELgettext ("_Cancel"), SKIPgettext ("_Skip"), RETRYgettext ("_Retry"),
3523 NULL((void*)0));
3524
3525 g_error_free (error);
3526
3527 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3528 abort_job (job);
3529 } else if (response == 1) {
3530 /* Skip: Do Nothing */
3531 } else if (response == 2) {
3532 goto retry;
3533 } else {
3534 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3534, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3535 }
3536 return CREATE_DEST_DIR_FAILED;
3537 }
3538 // Start UNDO-REDO
3539 baul_undostack_manager_data_add_origin_target_pair (job->undo_redo_data, src, *dest);
3540 // End UNDO-REDO
3541 baul_file_changes_queue_file_added (*dest);
3542 return CREATE_DEST_DIR_SUCCESS;
3543}
3544
3545/* a return value of FALSE means retry, i.e.
3546 * the destination has changed and the source
3547 * is expected to re-try the preceeding
3548 * g_file_move() or g_file_copy() call with
3549 * the new destination.
3550 */
3551static gboolean
3552copy_move_directory (CopyMoveJob *copy_job,
3553 GFile *src,
3554 GFile **dest,
3555 gboolean same_fs,
3556 gboolean create_dest,
3557 char **parent_dest_fs_type,
3558 SourceInfo *source_info,
3559 TransferInfo *transfer_info,
3560 GHashTable *debuting_files,
3561 gboolean *skipped_file,
3562 gboolean readonly_source_fs,
3563 gboolean last_item_above)
3564{
3565 GFileInfo *info, *nextinfo;
3566 GError *error;
3567 GFile *src_file;
3568 GFileEnumerator *enumerator;
3569 char *primary, *secondary, *details;
3570 char *dest_fs_type;
3571 int response;
3572 gboolean skip_error;
3573 gboolean local_skipped_file;
3574 CommonJob *job;
3575 GFileCopyFlags flags;
3576 gboolean last_item;
3577
3578 job = (CommonJob *)copy_job;
3579
3580 if (create_dest) {
3581 switch (create_dest_dir (job, src, dest, same_fs, parent_dest_fs_type)) {
3582 case CREATE_DEST_DIR_RETRY:
3583 /* next time copy_move_directory() is called,
3584 * create_dest will be FALSE if a directory already
3585 * exists under the new name (i.e. WOULD_RECURSE)
3586 */
3587 return FALSE(0);
3588
3589 case CREATE_DEST_DIR_FAILED:
3590 *skipped_file = TRUE(!(0));
3591 return TRUE(!(0));
3592
3593 case CREATE_DEST_DIR_SUCCESS:
3594 default:
3595 break;
3596 }
3597
3598 if (debuting_files) {
3599 g_hash_table_replace (debuting_files, g_object_ref (*dest)((__typeof__ (*dest)) (g_object_ref) (*dest)), GINT_TO_POINTER (TRUE)((gpointer) (glong) ((!(0)))));
3600 }
3601
3602 }
3603
3604 local_skipped_file = FALSE(0);
3605 dest_fs_type = NULL((void*)0);
3606
3607 skip_error = should_skip_readdir_error (job, src);
3608 retry:
3609 error = NULL((void*)0);
3610 enumerator = g_file_enumerate_children (src,
3611 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name",
3612 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3613 job->cancellable,
3614 &error);
3615 if (enumerator) {
3616 error = NULL((void*)0);
3617
3618 nextinfo = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL((void*)0):&error);
3619 while (!job_aborted (job) &&
3620 (info = nextinfo) != NULL((void*)0)) {
3621 baul_progress_info_get_ready (job->progress);
3622
3623 nextinfo = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL((void*)0):&error);
3624 src_file = g_file_get_child (src,
3625 g_file_info_get_name (info));
3626
3627 last_item = (last_item_above) && (!nextinfo);
3628 copy_move_file (copy_job, src_file, *dest, same_fs, FALSE(0), &dest_fs_type,
3629 source_info, transfer_info, NULL((void*)0), NULL((void*)0), FALSE(0), &local_skipped_file,
3630 readonly_source_fs, last_item);
3631 g_object_unref (src_file);
3632 g_object_unref (info);
3633 }
3634 if (nextinfo)
3635 g_object_unref (nextinfo);
3636
3637 g_file_enumerator_close (enumerator, job->cancellable, NULL((void*)0));
3638 g_object_unref (enumerator);
3639
3640 if (error && IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
3641 g_error_free (error);
3642 } else if (error) {
3643 if (copy_job->is_move) {
3644 primary = f (_("Error while moving.")gettext ("Error while moving."));
3645 } else {
3646 primary = f (_("Error while copying.")gettext ("Error while copying."));
3647 }
3648 details = NULL((void*)0);
3649
3650 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
3651 secondary = f (_("Files in the folder \"%B\" cannot be copied because you do "gettext ("Files in the folder \"%B\" cannot be copied because you do "
"not have permissions to see them.")
3652 "not have permissions to see them.")gettext ("Files in the folder \"%B\" cannot be copied because you do "
"not have permissions to see them.")
, src);
3653 } else {
3654 secondary = f (_("There was an error getting information about the files in the folder \"%B\".")gettext ("There was an error getting information about the files in the folder \"%B\"."
)
, src);
3655 details = error->message;
3656 }
3657
3658 response = run_warning (job,
3659 primary,
3660 secondary,
3661 details,
3662 FALSE(0),
3663 CANCELgettext ("_Cancel"), _("_Skip files")gettext ("_Skip files"),
3664 NULL((void*)0));
3665
3666 g_error_free (error);
3667
3668 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3669 abort_job (job);
3670 } else if (response == 1) {
3671 /* Skip: Do Nothing */
3672 local_skipped_file = TRUE(!(0));
3673 } else {
3674 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3674, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3675 }
3676 }
3677
3678 /* Count the copied directory as a file */
3679 transfer_info->num_files ++;
3680 report_copy_progress (copy_job, source_info, transfer_info);
3681
3682 if (debuting_files) {
3683 g_hash_table_replace (debuting_files, g_object_ref (*dest)((__typeof__ (*dest)) (g_object_ref) (*dest)), GINT_TO_POINTER (create_dest)((gpointer) (glong) (create_dest)));
3684 }
3685 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
3686 g_error_free (error);
3687 } else {
3688 if (copy_job->is_move) {
3689 primary = f (_("Error while moving.")gettext ("Error while moving."));
3690 } else {
3691 primary = f (_("Error while copying.")gettext ("Error while copying."));
3692 }
3693 details = NULL((void*)0);
3694
3695 if (IS_IO_ERROR (error, PERMISSION_DENIED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_PERMISSION_DENIED))
) {
3696 secondary = f (_("The folder \"%B\" cannot be copied because you do not have "gettext ("The folder \"%B\" cannot be copied because you do not have "
"permissions to read it.")
3697 "permissions to read it.")gettext ("The folder \"%B\" cannot be copied because you do not have "
"permissions to read it.")
, src);
3698 } else {
3699 secondary = f (_("There was an error reading the folder \"%B\".")gettext ("There was an error reading the folder \"%B\"."), src);
3700 details = error->message;
3701 }
3702
3703 response = run_warning (job,
3704 primary,
3705 secondary,
3706 details,
3707 FALSE(0),
3708 CANCELgettext ("_Cancel"), SKIPgettext ("_Skip"), RETRYgettext ("_Retry"),
3709 NULL((void*)0));
3710
3711 g_error_free (error);
3712
3713 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3714 abort_job (job);
3715 } else if (response == 1) {
3716 /* Skip: Do Nothing */
3717 local_skipped_file = TRUE(!(0));
3718 } else if (response == 2) {
3719 goto retry;
3720 } else {
3721 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3721, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3722 }
3723 }
3724
3725 if (create_dest) {
3726 flags = (readonly_source_fs) ? G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_PERMS
3727 : G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_ALL_METADATA;
3728 /* Ignore errors here. Failure to copy metadata is not a hard error */
3729 g_file_copy_attributes (src, *dest,
3730 flags,
3731 job->cancellable, NULL((void*)0));
3732 }
3733
3734 if (!job_aborted (job) && copy_job->is_move &&
3735 /* Don't delete source if there was a skipped file */
3736 !local_skipped_file) {
3737 if (!g_file_delete (src, job->cancellable, &error)) {
3738 if (job->skip_all_error) {
3739 goto skip;
3740 }
3741 primary = f (_("Error while moving \"%B\".")gettext ("Error while moving \"%B\"."), src);
3742 secondary = f (_("Could not remove the source folder.")gettext ("Could not remove the source folder."));
3743 details = error->message;
3744
3745 response = run_warning (job,
3746 primary,
3747 secondary,
3748 details,
3749 (source_info->num_files - transfer_info->num_files) > 1,
3750 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
3751 NULL((void*)0));
3752
3753 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3754 abort_job (job);
3755 } else if (response == 1) { /* skip all */
3756 job->skip_all_error = TRUE(!(0));
3757 local_skipped_file = TRUE(!(0));
3758 } else if (response == 2) { /* skip */
3759 local_skipped_file = TRUE(!(0));
3760 } else {
3761 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3761, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3762 }
3763
3764 skip:
3765 g_error_free (error);
3766 }
3767 }
3768
3769 if (local_skipped_file) {
3770 *skipped_file = TRUE(!(0));
3771 }
3772
3773 g_free (dest_fs_type);
3774 return TRUE(!(0));
3775}
3776
3777static gboolean
3778remove_target_recursively (CommonJob *job,
3779 GFile *src,
3780 GFile *toplevel_dest,
3781 GFile *file)
3782{
3783 GFileEnumerator *enumerator;
3784 GError *error;
3785 GFile *child;
3786 gboolean stop;
3787 char *primary, *secondary, *details;
3788 int response;
3789 GFileInfo *info;
3790
3791 stop = FALSE(0);
3792
3793 error = NULL((void*)0);
3794 enumerator = g_file_enumerate_children (file,
3795 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name",
3796 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3797 job->cancellable,
3798 &error);
3799 if (enumerator) {
3800 error = NULL((void*)0);
3801
3802 while (!job_aborted (job) &&
3803 (info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL((void*)0)) {
3804 child = g_file_get_child (file,
3805 g_file_info_get_name (info));
3806 if (!remove_target_recursively (job, src, toplevel_dest, child)) {
3807 stop = TRUE(!(0));
3808 break;
3809 }
3810 g_object_unref (child);
3811 g_object_unref (info);
3812 }
3813 g_file_enumerator_close (enumerator, job->cancellable, NULL((void*)0));
3814 g_object_unref (enumerator);
3815
3816 } else if (IS_IO_ERROR (error, NOT_DIRECTORY)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_DIRECTORY))
) {
3817 /* Not a dir, continue */
3818 g_error_free (error);
3819
3820 } else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
3821 g_error_free (error);
3822 } else {
3823 if (job->skip_all_error) {
3824 goto skip1;
3825 }
3826
3827 primary = f (_("Error while copying \"%B\".")gettext ("Error while copying \"%B\"."), src);
3828 secondary = f (_("Could not remove files from the already existing folder %F.")gettext ("Could not remove files from the already existing folder %F."
)
, file);
3829 details = error->message;
3830
3831 /* set show_all to TRUE here, as we don't know how many
3832 * files we'll end up processing yet.
3833 */
3834 response = run_warning (job,
3835 primary,
3836 secondary,
3837 details,
3838 TRUE(!(0)),
3839 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
3840 NULL((void*)0));
3841
3842 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3843 abort_job (job);
3844 } else if (response == 1) { /* skip all */
3845 job->skip_all_error = TRUE(!(0));
3846 } else if (response == 2) { /* skip */
3847 /* do nothing */
3848 } else {
3849 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3849, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3850 }
3851 skip1:
3852 g_error_free (error);
3853
3854 stop = TRUE(!(0));
3855 }
3856
3857 if (stop) {
3858 return FALSE(0);
3859 }
3860
3861 error = NULL((void*)0);
3862
3863 if (!g_file_delete (file, job->cancellable, &error)) {
3864 if (job->skip_all_error ||
3865 IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
3866 goto skip2;
3867 }
3868 primary = f (_("Error while copying \"%B\".")gettext ("Error while copying \"%B\"."), src);
3869 secondary = f (_("Could not remove the already existing file %F.")gettext ("Could not remove the already existing file %F."), file);
3870 details = error->message;
3871
3872 /* set show_all to TRUE here, as we don't know how many
3873 * files we'll end up processing yet.
3874 */
3875 response = run_warning (job,
3876 primary,
3877 secondary,
3878 details,
3879 TRUE(!(0)),
3880 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
3881 NULL((void*)0));
3882
3883 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
3884 abort_job (job);
3885 } else if (response == 1) { /* skip all */
3886 job->skip_all_error = TRUE(!(0));
3887 } else if (response == 2) { /* skip */
3888 /* do nothing */
3889 } else {
3890 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 3890, ((const char*) (__func__)), ((void*)0)); } while (0)
;
3891 }
3892
3893 skip2:
3894 g_error_free (error);
3895
3896 return FALSE(0);
3897 }
3898 baul_file_changes_queue_file_removed (file);
3899
3900 return TRUE(!(0));
3901
3902}
3903
3904typedef struct {
3905 CopyMoveJob *job;
3906 goffset last_size;
3907 SourceInfo *source_info;
3908 TransferInfo *transfer_info;
3909} ProgressData;
3910
3911static void
3912copy_file_progress_callback (goffset current_num_bytes,
3913 goffset total_num_bytes G_GNUC_UNUSED__attribute__ ((__unused__)),
3914 gpointer user_data)
3915{
3916 ProgressData *pdata;
3917 goffset new_size;
3918
3919 pdata = user_data;
3920
3921 new_size = current_num_bytes - pdata->last_size;
3922
3923 if (new_size > 0) {
3924 pdata->transfer_info->num_bytes += new_size;
3925 pdata->last_size = current_num_bytes;
3926 report_copy_progress (pdata->job,
3927 pdata->source_info,
3928 pdata->transfer_info);
3929 }
3930}
3931
3932static gboolean
3933test_dir_is_parent (GFile *child, GFile *root)
3934{
3935 GFile *f;
3936
3937 f = g_file_dup (child);
3938 while (f) {
3939 if (g_file_equal (f, root)) {
3940 g_object_unref (f);
3941 return TRUE(!(0));
3942 }
3943 f = g_file_get_parent (f);
3944 }
3945 if (f) {
3946 g_object_unref (f);
3947 }
3948 return FALSE(0);
3949}
3950
3951static char *
3952query_fs_type (GFile *file,
3953 GCancellable *cancellable)
3954{
3955 GFileInfo *fsinfo;
3956 char *ret;
3957
3958 ret = NULL((void*)0);
3959
3960 fsinfo = g_file_query_filesystem_info (file,
3961 G_FILE_ATTRIBUTE_FILESYSTEM_TYPE"filesystem::type",
3962 cancellable,
3963 NULL((void*)0));
3964 if (fsinfo != NULL((void*)0)) {
3965 ret = g_strdup (g_file_info_get_attribute_string (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))g_strdup_inline (g_file_info_get_attribute_string (fsinfo, "filesystem::type"
))
;
3966 g_object_unref (fsinfo);
3967 }
3968
3969 if (ret == NULL((void*)0)) {
3970 /* ensure that we don't attempt to query
3971 * the FS type for each file in a given
3972 * directory, if it can't be queried. */
3973 ret = g_strdup ("")g_strdup_inline ("");
3974 }
3975
3976 return ret;
3977}
3978
3979static gboolean
3980is_trusted_desktop_file (GFile *file,
3981 GCancellable *cancellable)
3982{
3983 char *basename;
3984 gboolean res;
3985 GFileInfo *info;
3986
3987 /* Don't trust non-local files */
3988 if (!g_file_is_native (file)) {
3989 return FALSE(0);
3990 }
3991
3992 basename = g_file_get_basename (file);
3993 if (!g_str_has_suffix (basename, ".desktop")(__builtin_constant_p (".desktop")? __extension__ ({ const char
* const __str = (basename); const char * const __suffix = (".desktop"
); gboolean __result = (0); if (__str == ((void*)0) || __suffix
== ((void*)0)) __result = (g_str_has_suffix) (__str, __suffix
); else { const size_t __str_len = strlen (((__str) + !(__str
))); const size_t __suffix_len = strlen (((__suffix) + !(__suffix
))); if (__str_len >= __suffix_len) __result = memcmp (__str
+ __str_len - __suffix_len, ((__suffix) + !(__suffix)), __suffix_len
) == 0; } __result; }) : (g_str_has_suffix) (basename, ".desktop"
) )
) {
3994 g_free (basename);
3995 return FALSE(0);
3996 }
3997 g_free (basename);
3998
3999 info = g_file_query_info (file,
4000 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type" ","
4001 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE"access::can-execute",
4002 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
4003 cancellable,
4004 NULL((void*)0));
4005
4006 if (info == NULL((void*)0)) {
4007 return FALSE(0);
4008 }
4009
4010 res = FALSE(0);
4011
4012 /* Weird file => not trusted,
4013 Already executable => no need to mark trusted */
4014 if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR &&
4015 !g_file_info_get_attribute_boolean (info,
4016 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE"access::can-execute") &&
4017 baul_is_in_system_dir (file)) {
4018 res = TRUE(!(0));
4019 }
4020 g_object_unref (info);
4021
4022 return res;
4023}
4024
4025typedef struct {
4026 int id;
4027 char *new_name;
4028 gboolean apply_to_all;
4029} ConflictResponseData;
4030
4031typedef struct {
4032 GFile *src;
4033 GFile *dest;
4034 GFile *dest_dir;
4035 CtkWindow *parent;
4036 ConflictResponseData *resp_data;
4037} ConflictDialogData;
4038
4039static gboolean
4040do_run_conflict_dialog (gpointer _data)
4041{
4042 ConflictDialogData *data = _data;
4043 CtkWidget *dialog;
4044 int response;
4045
4046 dialog = baul_file_conflict_dialog_new (data->parent,
4047 data->src,
4048 data->dest,
4049 data->dest_dir);
4050 response = ctk_dialog_run (CTK_DIALOG (dialog)((((CtkDialog*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((dialog)), ((ctk_dialog_get_type ()))))))
);
4051
4052 if (response == CONFLICT_RESPONSE_RENAME) {
4053 data->resp_data->new_name =
4054 baul_file_conflict_dialog_get_new_name (BAUL_FILE_CONFLICT_DIALOG (dialog)((((BaulFileConflictDialog*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dialog)), ((baul_file_conflict_dialog_get_type
()))))))
);
4055 } else if (response != CTK_RESPONSE_CANCEL ||
4056 response != CTK_RESPONSE_NONE) {
4057 data->resp_data->apply_to_all =
4058 baul_file_conflict_dialog_get_apply_to_all
4059 (BAUL_FILE_CONFLICT_DIALOG (dialog)((((BaulFileConflictDialog*) (void *) g_type_check_instance_cast
((GTypeInstance*) ((dialog)), ((baul_file_conflict_dialog_get_type
()))))))
);
4060 }
4061
4062 data->resp_data->id = response;
4063
4064 ctk_widget_destroy (dialog);
4065
4066 return FALSE(0);
4067}
4068
4069static ConflictResponseData *
4070run_conflict_dialog (CommonJob *job,
4071 GFile *src,
4072 GFile *dest,
4073 GFile *dest_dir)
4074{
4075 ConflictDialogData *data;
4076 ConflictResponseData *resp_data;
4077
4078 g_timer_stop (job->time);
4079
4080 data = g_slice_new0 (ConflictDialogData)((ConflictDialogData*) g_slice_alloc0 (sizeof (ConflictDialogData
)))
;
4081 data->parent = job->parent_window;
4082 data->src = src;
4083 data->dest = dest;
4084 data->dest_dir = dest_dir;
4085
4086 resp_data = g_slice_new0 (ConflictResponseData)((ConflictResponseData*) g_slice_alloc0 (sizeof (ConflictResponseData
)))
;
4087 resp_data->new_name = NULL((void*)0);
4088 data->resp_data = resp_data;
4089
4090 baul_progress_info_pause (job->progress);
4091 g_io_scheduler_job_send_to_mainloop (job->io_job,
4092 do_run_conflict_dialog,
4093 data,
4094 NULL((void*)0));
4095 baul_progress_info_resume (job->progress);
4096
4097 g_slice_free (ConflictDialogData, data)do { if (1) g_slice_free1 (sizeof (ConflictDialogData), (data
)); else (void) ((ConflictDialogData*) 0 == (data)); } while (
0)
;
4098
4099 g_timer_continue (job->time);
4100
4101 return resp_data;
4102}
4103
4104static void
4105conflict_response_data_free (ConflictResponseData *data)
4106{
4107 g_free (data->new_name);
4108 g_slice_free (ConflictResponseData, data)do { if (1) g_slice_free1 (sizeof (ConflictResponseData), (data
)); else (void) ((ConflictResponseData*) 0 == (data)); } while
(0)
;
4109}
4110
4111static GFile *
4112get_target_file_for_display_name (GFile *dir,
4113 char *name)
4114{
4115 GFile *dest;
4116
4117 dest = NULL((void*)0);
4118 dest = g_file_get_child_for_display_name (dir, name, NULL((void*)0));
4119
4120 if (dest == NULL((void*)0)) {
4121 dest = g_file_get_child (dir, name);
4122 }
4123
4124 return dest;
4125}
4126
4127/* Debuting files is non-NULL only for toplevel items */
4128static void
4129copy_move_file (CopyMoveJob *copy_job,
4130 GFile *src,
4131 GFile *dest_dir,
4132 gboolean same_fs,
4133 gboolean unique_names,
4134 char **dest_fs_type,
4135 SourceInfo *source_info,
4136 TransferInfo *transfer_info,
4137 GHashTable *debuting_files,
4138 CdkPoint *position,
4139 gboolean overwrite,
4140 gboolean *skipped_file,
4141 gboolean readonly_source_fs,
4142 gboolean last_item)
4143{
4144 GFile *dest, *new_dest;
4145 GError *error;
4146 GFileCopyFlags flags;
4147 char *primary, *secondary, *details;
4148 int response;
4149 ProgressData pdata;
4150 gboolean would_recurse, is_merge;
4151 CommonJob *job;
4152 gboolean res;
4153 int unique_name_nr;
4154 gboolean handled_invalid_filename;
4155
4156 job = (CommonJob *)copy_job;
4157
4158 if (should_skip_file (job, src)) {
4159 *skipped_file = TRUE(!(0));
4160 return;
4161 }
4162
4163 unique_name_nr = 1;
4164
4165 // TODO: Here we should get the previous file name UNDO
4166
4167 /* another file in the same directory might have handled the invalid
4168 * filename condition for us
4169 */
4170 handled_invalid_filename = *dest_fs_type != NULL((void*)0);
4171
4172 if (unique_names) {
4173 dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
4174 } else {
4175 dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4176 }
4177
4178
4179 /* Don't allow recursive move/copy into itself.
4180 * (We would get a file system error if we proceeded but it is nicer to
4181 * detect and report it at this level) */
4182 if (test_dir_is_parent (dest_dir, src)) {
4183 if (job->skip_all_error) {
4184 goto out;
4185 }
4186
4187 /* the run_warning() frees all strings passed in automatically */
4188 primary = copy_job->is_move ? g_strdup (_("You cannot move a folder into itself."))g_strdup_inline (gettext ("You cannot move a folder into itself."
))
4189 : g_strdup (_("You cannot copy a folder into itself."))g_strdup_inline (gettext ("You cannot copy a folder into itself."
))
;
4190 secondary = g_strdup (_("The destination folder is inside the source folder."))g_strdup_inline (gettext ("The destination folder is inside the source folder."
))
;
4191
4192 response = run_warning (job,
4193 primary,
4194 secondary,
4195 NULL((void*)0),
4196 (source_info->num_files - transfer_info->num_files) > 1,
4197 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
4198 NULL((void*)0));
4199
4200 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
4201 abort_job (job);
4202 } else if (response == 1) { /* skip all */
4203 job->skip_all_error = TRUE(!(0));
4204 } else if (response == 2) { /* skip */
4205 /* do nothing */
4206 } else {
4207 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4207, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4208 }
4209
4210 goto out;
4211 }
4212
4213 /* Don't allow copying over the source or one of the parents of the source.
4214 */
4215 if (test_dir_is_parent (src, dest)) {
4216 if (job->skip_all_error) {
4217 goto out;
4218 }
4219
4220 /* the run_warning() frees all strings passed in automatically */
4221 primary = copy_job->is_move ? g_strdup (_("You cannot move a file over itself."))g_strdup_inline (gettext ("You cannot move a file over itself."
))
4222 : g_strdup (_("You cannot copy a file over itself."))g_strdup_inline (gettext ("You cannot copy a file over itself."
))
;
4223 secondary = g_strdup (_("The source file would be overwritten by the destination."))g_strdup_inline (gettext ("The source file would be overwritten by the destination."
))
;
4224
4225 response = run_warning (job,
4226 primary,
4227 secondary,
4228 NULL((void*)0),
4229 (source_info->num_files - transfer_info->num_files) > 1,
4230 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
4231 NULL((void*)0));
4232
4233 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
4234 abort_job (job);
4235 } else if (response == 1) { /* skip all */
4236 job->skip_all_error = TRUE(!(0));
4237 } else if (response == 2) { /* skip */
4238 /* do nothing */
4239 } else {
4240 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4240, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4241 }
4242
4243 goto out;
4244 }
4245
4246
4247 retry:
4248 error = NULL((void*)0);
4249 flags = G_FILE_COPY_NOFOLLOW_SYMLINKS;
4250 if (overwrite) {
4251 flags |= G_FILE_COPY_OVERWRITE;
4252 }
4253 if (readonly_source_fs) {
4254 flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS;
4255 }
4256
4257 pdata.job = copy_job;
4258 pdata.last_size = 0;
4259 pdata.source_info = source_info;
4260 pdata.transfer_info = transfer_info;
4261
4262 if (!is_dir(src) && last_item)
4263 /* this is the last file for this operation, cannot pause anymore */
4264 baul_progress_info_disable_pause (job->progress);
4265
4266 if (copy_job->is_move) {
4267 res = g_file_move (src, dest,
4268 flags,
4269 job->cancellable,
4270 copy_file_progress_callback,
4271 &pdata,
4272 &error);
4273 } else {
4274 res = g_file_copy (src, dest,
4275 flags,
4276 job->cancellable,
4277 copy_file_progress_callback,
4278 &pdata,
4279 &error);
4280 }
4281
4282 if (res) {
4283 if (!copy_job->is_move) {
4284 /* Ignore errors here. Failure to copy metadata is not a hard error */
4285 g_file_copy_attributes (src, dest,
4286 flags | G_FILE_COPY_ALL_METADATA,
4287 job->cancellable, NULL((void*)0));
4288 }
4289
4290 transfer_info->num_files ++;
4291 report_copy_progress (copy_job, source_info, transfer_info);
4292
4293 if (debuting_files) {
4294 if (position) {
4295 baul_file_changes_queue_schedule_position_set (dest, *position, job->screen_num);
4296 } else {
4297 baul_file_changes_queue_schedule_position_remove (dest);
4298 }
4299
4300 g_hash_table_replace (debuting_files, g_object_ref (dest)((__typeof__ (dest)) (g_object_ref) (dest)), GINT_TO_POINTER (TRUE)((gpointer) (glong) ((!(0)))));
4301 }
4302 if (copy_job->is_move) {
4303 baul_file_changes_queue_file_moved (src, dest);
4304 } else {
4305 baul_file_changes_queue_file_added (dest);
4306 }
4307
4308 /* If copying a trusted desktop file to the desktop,
4309 mark it as trusted. */
4310 if (copy_job->desktop_location != NULL((void*)0) &&
4311 g_file_equal (copy_job->desktop_location, dest_dir) &&
4312 is_trusted_desktop_file (src, job->cancellable)) {
4313 mark_desktop_file_trusted (job,
4314 job->cancellable,
4315 dest,
4316 FALSE(0));
4317 }
4318
4319 // Start UNDO-REDO
4320 baul_undostack_manager_data_add_origin_target_pair (job->undo_redo_data, src, dest);
4321 // End UNDO-REDO
4322
4323 g_object_unref (dest);
4324 return;
4325 }
4326
4327 if (!handled_invalid_filename &&
4328 IS_IO_ERROR (error, INVALID_FILENAME)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_INVALID_FILENAME))
) {
4329 handled_invalid_filename = TRUE(!(0));
4330
4331 g_assert (*dest_fs_type == NULL)do { if (*dest_fs_type == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 4331, ((const char*
) (__func__)), "*dest_fs_type == NULL"); } while (0)
;
4332 *dest_fs_type = query_fs_type (dest_dir, job->cancellable);
4333
4334 if (unique_names) {
4335 new_dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr);
4336 } else {
4337 new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4338 }
4339
4340 if (!g_file_equal (dest, new_dest)) {
4341 g_object_unref (dest);
4342 dest = new_dest;
4343
4344 g_error_free (error);
4345 goto retry;
4346 } else {
4347 g_object_unref (new_dest);
4348 }
4349 }
4350
4351 /* Conflict */
4352 if (!overwrite &&
4353 IS_IO_ERROR (error, EXISTS)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_EXISTS))
) {
4354 gboolean is_merge;
4355 ConflictResponseData *response;
4356
4357 g_error_free (error);
4358
4359 if (unique_names) {
4360 g_object_unref (dest);
4361 dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
4362 goto retry;
4363 }
4364
4365 is_merge = FALSE(0);
4366
4367 if (is_dir (dest) && is_dir (src)) {
4368 is_merge = TRUE(!(0));
4369 }
4370
4371 if ((is_merge && job->merge_all) ||
4372 (!is_merge && job->replace_all)) {
4373 overwrite = TRUE(!(0));
4374 goto retry;
4375 }
4376
4377 if (job->skip_all_conflict) {
4378 goto out;
4379 }
4380
4381 response = run_conflict_dialog (job, src, dest, dest_dir);
4382
4383 if (response->id == CTK_RESPONSE_CANCEL ||
4384 response->id == CTK_RESPONSE_DELETE_EVENT) {
4385 conflict_response_data_free (response);
4386 abort_job (job);
4387 } else if (response->id == CONFLICT_RESPONSE_SKIP) {
4388 if (response->apply_to_all) {
4389 job->skip_all_conflict = TRUE(!(0));
4390 }
4391 conflict_response_data_free (response);
4392 } else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
4393 if (response->apply_to_all) {
4394 if (is_merge) {
4395 job->merge_all = TRUE(!(0));
4396 } else {
4397 job->replace_all = TRUE(!(0));
4398 }
4399 }
4400 overwrite = TRUE(!(0));
4401 conflict_response_data_free (response);
4402 goto retry;
4403 } else if (response->id == CONFLICT_RESPONSE_RENAME) {
4404 g_object_unref (dest);
4405 dest = get_target_file_for_display_name (dest_dir,
4406 response->new_name);
4407 conflict_response_data_free (response);
4408 goto retry;
4409 } else {
4410 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4410, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4411 }
4412 }
4413
4414 else if (overwrite &&
4415 IS_IO_ERROR (error, IS_DIRECTORY)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_IS_DIRECTORY))
) {
4416
4417 g_error_free (error);
4418
4419 if (remove_target_recursively (job, src, dest, dest)) {
4420 goto retry;
4421 }
4422 }
4423
4424 /* Needs to recurse */
4425 else if (IS_IO_ERROR (error, WOULD_RECURSE)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_WOULD_RECURSE))
||
4426 IS_IO_ERROR (error, WOULD_MERGE)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_WOULD_MERGE))
) {
4427 is_merge = error->code == G_IO_ERROR_WOULD_MERGE;
4428 would_recurse = error->code == G_IO_ERROR_WOULD_RECURSE;
4429 g_error_free (error);
4430
4431 if (overwrite && would_recurse) {
4432 error = NULL((void*)0);
4433
4434 /* Copying a dir onto file, first remove the file */
4435 if (!g_file_delete (dest, job->cancellable, &error) &&
4436 !IS_IO_ERROR (error, NOT_FOUND)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_FOUND))
) {
4437 if (job->skip_all_error) {
4438 g_error_free (error);
4439 goto out;
4440 }
4441 if (copy_job->is_move) {
4442 primary = f (_("Error while moving \"%B\".")gettext ("Error while moving \"%B\"."), src);
4443 } else {
4444 primary = f (_("Error while copying \"%B\".")gettext ("Error while copying \"%B\"."), src);
4445 }
4446 secondary = f (_("Could not remove the already existing file with the same name in %F.")gettext ("Could not remove the already existing file with the same name in %F."
)
, dest_dir);
4447 details = error->message;
4448
4449 /* setting TRUE on show_all here, as we could have
4450 * another error on the same file later.
4451 */
4452 response = run_warning (job,
4453 primary,
4454 secondary,
4455 details,
4456 TRUE(!(0)),
4457 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
4458 NULL((void*)0));
4459
4460 g_error_free (error);
4461
4462 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
4463 abort_job (job);
4464 } else if (response == 1) { /* skip all */
4465 job->skip_all_error = TRUE(!(0));
4466 } else if (response == 2) { /* skip */
4467 /* do nothing */
4468 } else {
4469 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4469, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4470 }
4471 goto out;
4472
4473 }
4474 if (error) {
4475 g_error_free (error);
4476 error = NULL((void*)0);
4477 }
4478 baul_file_changes_queue_file_removed (dest);
4479 }
4480
4481 if (is_merge) {
4482 /* On merge we now write in the target directory, which may not
4483 be in the same directory as the source, even if the parent is
4484 (if the merged directory is a mountpoint). This could cause
4485 problems as we then don't transcode filenames.
4486 We just set same_fs to FALSE which is safe but a bit slower. */
4487 same_fs = FALSE(0);
4488 }
4489
4490 if (!copy_move_directory (copy_job, src, &dest, same_fs,
4491 would_recurse, dest_fs_type,
4492 source_info, transfer_info,
4493 debuting_files, skipped_file,
4494 readonly_source_fs,
4495 last_item)) {
4496 /* destination changed, since it was an invalid file name */
4497 g_assert (*dest_fs_type != NULL)do { if (*dest_fs_type != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 4497, ((const char*
) (__func__)), "*dest_fs_type != NULL"); } while (0)
;
4498 handled_invalid_filename = TRUE(!(0));
4499 goto retry;
4500 }
4501
4502 g_object_unref (dest);
4503 return;
4504 }
4505
4506 else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
4507 g_error_free (error);
4508 }
4509
4510 /* Other error */
4511 else {
4512 if (job->skip_all_error) {
4513 g_error_free (error);
4514 goto out;
4515 }
4516 primary = f (_("Error while copying \"%B\".")gettext ("Error while copying \"%B\"."), src);
4517 secondary = f (_("There was an error copying the file into %F.")gettext ("There was an error copying the file into %F."), dest_dir);
4518 details = error->message;
4519
4520 response = run_warning (job,
4521 primary,
4522 secondary,
4523 details,
4524 (source_info->num_files - transfer_info->num_files) > 1,
4525 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
4526 NULL((void*)0));
4527
4528 g_error_free (error);
4529
4530 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
4531 abort_job (job);
4532 } else if (response == 1) { /* skip all */
4533 job->skip_all_error = TRUE(!(0));
4534 } else if (response == 2) { /* skip */
4535 /* do nothing */
4536 } else {
4537 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4537, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4538 }
4539 }
4540 out:
4541 *skipped_file = TRUE(!(0)); /* Or aborted, but same-same */
4542 g_object_unref (dest);
4543}
4544
4545static void
4546copy_files (CopyMoveJob *job,
4547 const char *dest_fs_id,
4548 SourceInfo *source_info,
4549 TransferInfo *transfer_info)
4550{
4551 CommonJob *common;
4552 GList *l;
4553 gboolean same_fs;
4554 int i;
4555 CdkPoint *point;
4556 gboolean skipped_file;
4557 gboolean unique_names;
4558 GFile *dest;
4559 GFile *source_dir;
4560 char *dest_fs_type;
4561 gboolean readonly_source_fs;
4562 GFile *src = NULL((void*)0);
4563
4564 dest_fs_type = NULL((void*)0);
4565 readonly_source_fs = FALSE(0);
4566
4567 common = &job->common;
4568
4569 report_copy_progress (job, source_info, transfer_info);
4570
4571 /* Query the source dir, not the file because if its a symlink we'll follow it */
4572 source_dir = g_file_get_parent ((GFile *) job->files->data);
4573 if (source_dir) {
4574 GFileInfo *inf;
4575
4576 inf = g_file_query_filesystem_info (source_dir, "filesystem::readonly", NULL((void*)0), NULL((void*)0));
4577 if (inf != NULL((void*)0)) {
4578 readonly_source_fs = g_file_info_get_attribute_boolean (inf, "filesystem::readonly");
4579 g_object_unref (inf);
4580 }
4581 g_object_unref (source_dir);
4582 }
4583
4584 unique_names = (job->destination == NULL((void*)0));
4585 i = 0;
4586 for (l = job->files;
4587 l != NULL((void*)0) && !job_aborted (common);
4588 l = l->next) {
4589 baul_progress_info_get_ready (common->progress);
4590
4591 src = l->data;
4592
4593 if (i < job->n_icon_positions) {
4594 point = &job->icon_positions[i];
4595 } else {
4596 point = NULL((void*)0);
4597 }
4598
4599
4600 same_fs = FALSE(0);
4601 if (dest_fs_id) {
4602 same_fs = has_fs_id (src, dest_fs_id);
4603 }
4604
4605 if (job->destination) {
4606 dest = g_object_ref (job->destination)((__typeof__ (job->destination)) (g_object_ref) (job->destination
))
;
4607 } else {
4608 dest = g_file_get_parent (src);
4609
4610 }
4611 if (dest) {
4612 skipped_file = FALSE(0);
4613
4614 copy_move_file (job, src, dest,
4615 same_fs, unique_names,
4616 &dest_fs_type,
4617 source_info, transfer_info,
4618 job->debuting_files,
4619 point, FALSE(0), &skipped_file,
4620 readonly_source_fs,
4621 !l->next);
4622 g_object_unref (dest);
4623 }
4624 i++;
4625 }
4626
4627 g_free (dest_fs_type);
4628}
4629
4630static gboolean
4631copy_job_done (gpointer user_data)
4632{
4633 CopyMoveJob *job;
4634
4635 job = user_data;
4636 if (job->done_callback) {
4637 job->done_callback (job->debuting_files, job->done_callback_data);
4638 }
4639
4640 g_list_free_full (job->files, g_object_unref);
4641 if (job->destination) {
4642 g_object_unref (job->destination);
4643 }
4644 if (job->desktop_location) {
4645 g_object_unref (job->desktop_location);
4646 }
4647 g_hash_table_unref (job->debuting_files);
4648 g_free (job->icon_positions);
4649
4650 finalize_common ((CommonJob *)job);
4651
4652 baul_file_changes_consume_changes (TRUE(!(0)));
4653 return FALSE(0);
4654}
4655
4656static gboolean
4657copy_job (GIOSchedulerJob *io_job,
4658 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
4659 gpointer user_data)
4660{
4661 CopyMoveJob *job;
4662 CommonJob *common;
4663 SourceInfo source_info;
4664 TransferInfo transfer_info;
4665 char *dest_fs_id;
4666 GFile *dest;
4667
4668 job = user_data;
4669 common = &job->common;
4670 common->io_job = io_job;
4671
4672 dest_fs_id = NULL((void*)0);
4673
4674 baul_progress_info_start (job->common.progress);
4675
4676 scan_sources (job->files,
4677 &source_info,
4678 common,
4679 OP_KIND_COPY);
4680 if (job_aborted (common)) {
4681 goto aborted;
4682 }
4683
4684 if (job->destination) {
4685 dest = g_object_ref (job->destination)((__typeof__ (job->destination)) (g_object_ref) (job->destination
))
;
4686 } else {
4687 /* Duplication, no dest,
4688 * use source for free size, etc
4689 */
4690 dest = g_file_get_parent (job->files->data);
4691 }
4692
4693 verify_destination (&job->common,
4694 dest,
4695 &dest_fs_id,
4696 source_info.num_bytes);
4697 g_object_unref (dest);
4698 if (job_aborted (common)) {
4699 goto aborted;
4700 }
4701
4702 g_timer_start (job->common.time);
4703
4704 memset (&transfer_info, 0, sizeof (transfer_info));
4705 copy_files (job,
4706 dest_fs_id,
4707 &source_info, &transfer_info);
4708
4709 aborted:
4710
4711 g_free (dest_fs_id);
4712
4713 g_io_scheduler_job_send_to_mainloop_async (io_job,
4714 copy_job_done,
4715 job,
4716 NULL((void*)0));
4717
4718 return FALSE(0);
4719}
4720
4721static gboolean
4722contains_multiple_items (GList *files)
4723{
4724 GFile *first;
4725
4726 if (g_list_length (files) > 1) {
4727 return TRUE(!(0));
4728 } else {
4729 if (files) {
4730 first = files->data;
4731 if (is_dir (first))
4732 return TRUE(!(0));
4733 }
4734 }
4735
4736 return FALSE(0);
4737}
4738
4739void
4740baul_file_operations_copy (GList *files,
4741 GArray *relative_item_points,
4742 GFile *target_dir,
4743 CtkWindow *parent_window,
4744 BaulCopyCallback done_callback,
4745 gpointer done_callback_data)
4746{
4747 CopyMoveJob *job;
4748
4749 job = op_job_new (CopyMoveJob, parent_window, FALSE, contains_multiple_items (files))((CopyMoveJob *)(init_common (sizeof(CopyMoveJob), parent_window
, (0), contains_multiple_items (files))))
;
4750 job->desktop_location = baul_get_desktop_location ();
4751 job->done_callback = done_callback;
4752 job->done_callback_data = done_callback_data;
4753 job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL((void*)0));
4754 job->destination = g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
4755 if (relative_item_points != NULL((void*)0) &&
4756 relative_item_points->len > 0) {
4757 job->icon_positions =
4758 g_memdup2 (relative_item_points->data,
4759 sizeof (CdkPoint) * relative_item_points->len);
4760 job->n_icon_positions = relative_item_points->len;
4761 }
4762 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
4763
4764 inhibit_power_manager ((CommonJob *)job, _("Copying Files")gettext ("Copying Files"));
4765
4766 // Start UNDO-REDO
4767 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
4768 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_COPY, g_list_length(files));
4769 GFile* src_dir = g_file_get_parent (files->data);
4770 baul_undostack_manager_data_set_src_dir (job->common.undo_redo_data, src_dir);
4771 g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
4772 baul_undostack_manager_data_set_dest_dir (job->common.undo_redo_data, target_dir);
4773 }
4774 // End UNDO-REDO
4775
4776 g_io_scheduler_push_job (copy_job,
4777 job,
4778 NULL((void*)0), /* destroy notify */
4779 0,
4780 job->common.cancellable);
4781}
4782
4783static void
4784report_move_progress (CopyMoveJob *move_job,
4785 int total G_GNUC_UNUSED__attribute__ ((__unused__)),
4786 int left)
4787{
4788 CommonJob *job;
4789
4790 job = (CommonJob *)move_job;
4791
4792 baul_progress_info_take_status (job->progress,
4793 f (_("Preparing to Move to \"%B\"")gettext ("Preparing to Move to \"%B\""),
4794 move_job->destination));
4795
4796 baul_progress_info_take_details (job->progress,
4797 f (ngettext ("Preparing to move %'d file",
4798 "Preparing to move %'d files",
4799 left), left));
4800
4801 baul_progress_info_pulse_progress (job->progress);
4802}
4803
4804typedef struct {
4805 GFile *file;
4806 gboolean overwrite;
4807 gboolean has_position;
4808 CdkPoint position;
4809} MoveFileCopyFallback;
4810
4811static MoveFileCopyFallback *
4812move_copy_file_callback_new (GFile *file,
4813 gboolean overwrite,
4814 CdkPoint *position)
4815{
4816 MoveFileCopyFallback *fallback;
4817
4818 fallback = g_new (MoveFileCopyFallback, 1)((MoveFileCopyFallback *) g_malloc_n ((1), sizeof (MoveFileCopyFallback
)))
;
4819 fallback->file = file;
4820 fallback->overwrite = overwrite;
4821 if (position) {
4822 fallback->has_position = TRUE(!(0));
4823 fallback->position = *position;
4824 } else {
4825 fallback->has_position = FALSE(0);
4826 }
4827
4828 return fallback;
4829}
4830
4831static GList *
4832get_files_from_fallbacks (GList *fallbacks)
4833{
4834 GList *res, *l;
4835 MoveFileCopyFallback *fallback = NULL((void*)0);
4836
4837 res = NULL((void*)0);
4838 for (l = fallbacks; l != NULL((void*)0); l = l->next) {
4839 fallback = l->data;
4840 res = g_list_prepend (res, fallback->file);
4841 }
4842 return g_list_reverse (res);
4843}
4844
4845static void
4846move_file_prepare (CopyMoveJob *move_job,
4847 GFile *src,
4848 GFile *dest_dir,
4849 gboolean same_fs,
4850 char **dest_fs_type,
4851 GHashTable *debuting_files,
4852 CdkPoint *position,
4853 GList **fallback_files,
4854 int files_left)
4855{
4856 GFile *dest, *new_dest;
4857 GError *error;
4858 CommonJob *job;
4859 gboolean overwrite;
4860 char *primary, *secondary, *details;
4861 int response;
4862 GFileCopyFlags flags;
4863 MoveFileCopyFallback *fallback;
4864 gboolean handled_invalid_filename;
4865
4866 overwrite = FALSE(0);
4867 handled_invalid_filename = *dest_fs_type != NULL((void*)0);
4868
4869 job = (CommonJob *)move_job;
4870
4871 dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4872
4873
4874 /* Don't allow recursive move/copy into itself.
4875 * (We would get a file system error if we proceeded but it is nicer to
4876 * detect and report it at this level) */
4877 if (test_dir_is_parent (dest_dir, src)) {
4878 if (job->skip_all_error) {
4879 goto out;
4880 }
4881
4882 /* the run_warning() frees all strings passed in automatically */
4883 primary = move_job->is_move ? g_strdup (_("You cannot move a folder into itself."))g_strdup_inline (gettext ("You cannot move a folder into itself."
))
4884 : g_strdup (_("You cannot copy a folder into itself."))g_strdup_inline (gettext ("You cannot copy a folder into itself."
))
;
4885 secondary = g_strdup (_("The destination folder is inside the source folder."))g_strdup_inline (gettext ("The destination folder is inside the source folder."
))
;
4886
4887 response = run_warning (job,
4888 primary,
4889 secondary,
4890 NULL((void*)0),
4891 files_left > 1,
4892 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
4893 NULL((void*)0));
4894
4895 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
4896 abort_job (job);
4897 } else if (response == 1) { /* skip all */
4898 job->skip_all_error = TRUE(!(0));
4899 } else if (response == 2) { /* skip */
4900 /* do nothing */
4901 } else {
4902 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 4902, ((const char*) (__func__)), ((void*)0)); } while (0)
;
4903 }
4904
4905 goto out;
4906 }
4907
4908 retry:
4909 baul_progress_info_get_ready (job->progress);
4910
4911 flags = G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_NO_FALLBACK_FOR_MOVE;
4912 if (overwrite) {
4913 flags |= G_FILE_COPY_OVERWRITE;
4914 }
4915
4916 error = NULL((void*)0);
4917 if (g_file_move (src, dest,
4918 flags,
4919 job->cancellable,
4920 NULL((void*)0),
4921 NULL((void*)0),
4922 &error)) {
4923
4924 if (debuting_files) {
4925 g_hash_table_replace (debuting_files, g_object_ref (dest)((__typeof__ (dest)) (g_object_ref) (dest)), GINT_TO_POINTER (TRUE)((gpointer) (glong) ((!(0)))));
4926 }
4927
4928 baul_file_changes_queue_file_moved (src, dest);
4929
4930 if (position) {
4931 baul_file_changes_queue_schedule_position_set (dest, *position, job->screen_num);
4932 } else {
4933 baul_file_changes_queue_schedule_position_remove (dest);
4934 }
4935
4936 // Start UNDO-REDO
4937 baul_undostack_manager_data_add_origin_target_pair (job->undo_redo_data, src, dest);
4938 // End UNDO-REDO
4939
4940 return;
4941 }
4942
4943 if (IS_IO_ERROR (error, INVALID_FILENAME)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_INVALID_FILENAME))
&&
4944 !handled_invalid_filename) {
4945 handled_invalid_filename = TRUE(!(0));
4946
4947 g_assert (*dest_fs_type == NULL)do { if (*dest_fs_type == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 4947, ((const char*
) (__func__)), "*dest_fs_type == NULL"); } while (0)
;
4948 *dest_fs_type = query_fs_type (dest_dir, job->cancellable);
4949
4950 new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4951 if (!g_file_equal (dest, new_dest)) {
4952 g_object_unref (dest);
4953 dest = new_dest;
4954 goto retry;
4955 } else {
4956 g_object_unref (new_dest);
4957 }
4958 }
4959
4960 /* Conflict */
4961 else if (!overwrite &&
4962 IS_IO_ERROR (error, EXISTS)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_EXISTS))
) {
4963 gboolean is_merge;
4964 ConflictResponseData *response;
4965
4966 g_error_free (error);
4967
4968 is_merge = FALSE(0);
4969 if (is_dir (dest) && is_dir (src)) {
4970 is_merge = TRUE(!(0));
4971 }
4972
4973 if ((is_merge && job->merge_all) ||
4974 (!is_merge && job->replace_all)) {
4975 overwrite = TRUE(!(0));
4976 goto retry;
4977 }
4978
4979 if (job->skip_all_conflict) {
4980 goto out;
4981 }
4982
4983 response = run_conflict_dialog (job, src, dest, dest_dir);
4984
4985 if (response->id == CTK_RESPONSE_CANCEL ||
4986 response->id == CTK_RESPONSE_DELETE_EVENT) {
4987 conflict_response_data_free (response);
4988 abort_job (job);
4989 } else if (response->id == CONFLICT_RESPONSE_SKIP) {
4990 if (response->apply_to_all) {
4991 job->skip_all_conflict = TRUE(!(0));
4992 }
4993 conflict_response_data_free (response);
4994 } else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
4995 if (response->apply_to_all) {
4996 if (is_merge) {
4997 job->merge_all = TRUE(!(0));
4998 } else {
4999 job->replace_all = TRUE(!(0));
5000 }
5001 }
5002 overwrite = TRUE(!(0));
5003 conflict_response_data_free (response);
5004 goto retry;
5005 } else if (response->id == CONFLICT_RESPONSE_RENAME) {
5006 g_object_unref (dest);
5007 dest = get_target_file_for_display_name (dest_dir,
5008 response->new_name);
5009 conflict_response_data_free (response);
5010 goto retry;
5011 } else {
5012 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 5012, ((const char*) (__func__)), ((void*)0)); } while (0)
;
5013 }
5014 }
5015
5016 else if (IS_IO_ERROR (error, WOULD_RECURSE)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_WOULD_RECURSE))
||
5017 IS_IO_ERROR (error, WOULD_MERGE)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_WOULD_MERGE))
||
5018 IS_IO_ERROR (error, NOT_SUPPORTED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_SUPPORTED))
||
5019 (overwrite && IS_IO_ERROR (error, IS_DIRECTORY)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_IS_DIRECTORY))
)) {
5020 g_error_free (error);
5021
5022 fallback = move_copy_file_callback_new (src,
5023 overwrite,
5024 position);
5025 *fallback_files = g_list_prepend (*fallback_files, fallback);
5026 }
5027
5028 else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
5029 g_error_free (error);
5030 }
5031
5032 /* Other error */
5033 else {
5034 if (job->skip_all_error) {
5035 goto out;
5036 }
5037 primary = f (_("Error while moving \"%B\".")gettext ("Error while moving \"%B\"."), src);
5038 secondary = f (_("There was an error moving the file into %F.")gettext ("There was an error moving the file into %F."), dest_dir);
5039 details = error->message;
5040
5041 response = run_warning (job,
5042 primary,
5043 secondary,
5044 details,
5045 files_left > 1,
5046 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
5047 NULL((void*)0));
5048
5049 g_error_free (error);
5050
5051 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
5052 abort_job (job);
5053 } else if (response == 1) { /* skip all */
5054 job->skip_all_error = TRUE(!(0));
5055 } else if (response == 2) { /* skip */
5056 /* do nothing */
5057 } else {
5058 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 5058, ((const char*) (__func__)), ((void*)0)); } while (0)
;
5059 }
5060 }
5061
5062 out:
5063 g_object_unref (dest);
5064}
5065
5066static void
5067move_files_prepare (CopyMoveJob *job,
5068 const char *dest_fs_id,
5069 char **dest_fs_type,
5070 GList **fallbacks)
5071{
5072 CommonJob *common;
5073 GList *l;
5074 gboolean same_fs;
5075 gboolean last_item;
5076 int i;
5077 CdkPoint *point;
5078 int total, left;
5079 GFile *src = NULL((void*)0);
5080
5081 common = &job->common;
5082
5083 total = left = g_list_length (job->files);
5084
5085 baul_progress_info_get_ready (common->progress);
5086 report_move_progress (job, total, left);
5087
5088 i = 0;
5089 for (l = job->files;
5090 l != NULL((void*)0) && !job_aborted (common);
5091 l = l->next) {
5092 src = l->data;
5093
5094 last_item = (!l->next) && (!is_dir(src)) && (!(*fallbacks));
5095 if (last_item)
5096 /* this is the last file and there are no fallbacks to process, cannot pause anymore */
5097 baul_progress_info_disable_pause (common->progress);
5098
5099 if (i < job->n_icon_positions) {
5100 point = &job->icon_positions[i];
5101 } else {
5102 point = NULL((void*)0);
5103 }
5104
5105
5106 same_fs = FALSE(0);
5107 if (dest_fs_id) {
5108 same_fs = has_fs_id (src, dest_fs_id);
5109 }
5110
5111 move_file_prepare (job, src, job->destination,
5112 same_fs, dest_fs_type,
5113 job->debuting_files,
5114 point,
5115 fallbacks,
5116 left);
5117 report_move_progress (job, total, --left);
5118 i++;
5119 }
5120
5121 *fallbacks = g_list_reverse (*fallbacks);
5122
5123
5124}
5125
5126static void
5127move_files (CopyMoveJob *job,
5128 GList *fallbacks,
5129 const char *dest_fs_id,
5130 char **dest_fs_type,
5131 SourceInfo *source_info,
5132 TransferInfo *transfer_info)
5133{
5134 CommonJob *common;
5135 GList *l;
5136 gboolean same_fs;
5137 int i;
5138 CdkPoint *point;
5139 gboolean skipped_file;
5140 MoveFileCopyFallback *fallback;
5141 GFile *src = NULL((void*)0);
5142
5143 common = &job->common;
5144
5145 report_copy_progress (job, source_info, transfer_info);
5146
5147 i = 0;
5148 for (l = fallbacks;
5149 l != NULL((void*)0) && !job_aborted (common);
5150 l = l->next) {
5151 baul_progress_info_get_ready (common->progress);
5152
5153 fallback = l->data;
5154 src = fallback->file;
5155
5156 if (fallback->has_position) {
5157 point = &fallback->position;
5158 } else {
5159 point = NULL((void*)0);
5160 }
5161
5162 same_fs = FALSE(0);
5163 if (dest_fs_id) {
5164 same_fs = has_fs_id (src, dest_fs_id);
5165 }
5166
5167 /* Set overwrite to true, as the user has
5168 selected overwrite on all toplevel items */
5169 skipped_file = FALSE(0);
5170 copy_move_file (job, src, job->destination,
5171 same_fs, FALSE(0), dest_fs_type,
5172 source_info, transfer_info,
5173 job->debuting_files,
5174 point, fallback->overwrite, &skipped_file, FALSE(0),
5175 !l->next);
5176 i++;
5177 }
5178}
5179
5180
5181static gboolean
5182move_job_done (gpointer user_data)
5183{
5184 CopyMoveJob *job;
5185
5186 job = user_data;
5187 if (job->done_callback) {
5188 job->done_callback (job->debuting_files, job->done_callback_data);
5189 }
5190
5191 g_list_free_full (job->files, g_object_unref);
5192 g_object_unref (job->destination);
5193 g_hash_table_unref (job->debuting_files);
5194 g_free (job->icon_positions);
5195
5196 finalize_common ((CommonJob *)job);
5197
5198 baul_file_changes_consume_changes (TRUE(!(0)));
5199 return FALSE(0);
5200}
5201
5202static gboolean
5203move_job (GIOSchedulerJob *io_job,
5204 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
5205 gpointer user_data)
5206{
5207 CopyMoveJob *job;
5208 CommonJob *common;
5209 GList *fallbacks;
5210 SourceInfo source_info;
5211 TransferInfo transfer_info;
5212 char *dest_fs_id;
5213 char *dest_fs_type;
5214 GList *fallback_files;
5215
5216 job = user_data;
5217 common = &job->common;
5218 common->io_job = io_job;
5219
5220 dest_fs_id = NULL((void*)0);
5221 dest_fs_type = NULL((void*)0);
5222
5223 fallbacks = NULL((void*)0);
5224
5225 baul_progress_info_start (job->common.progress);
5226
5227 verify_destination (&job->common,
5228 job->destination,
5229 &dest_fs_id,
5230 -1);
5231 if (job_aborted (common)) {
5232 goto aborted;
5233 }
5234
5235 /* This moves all files that we can do without copy + delete */
5236 move_files_prepare (job, dest_fs_id, &dest_fs_type, &fallbacks);
5237 if (job_aborted (common)) {
5238 goto aborted;
5239 }
5240
5241 /* The rest we need to do deep copy + delete behind on,
5242 so scan for size */
5243
5244 fallback_files = get_files_from_fallbacks (fallbacks);
5245 scan_sources (fallback_files,
5246 &source_info,
5247 common,
5248 OP_KIND_MOVE);
5249
5250 g_list_free (fallback_files);
5251
5252 if (job_aborted (common)) {
5253 goto aborted;
5254 }
5255
5256 verify_destination (&job->common,
5257 job->destination,
5258 NULL((void*)0),
5259 source_info.num_bytes);
5260 if (job_aborted (common)) {
5261 goto aborted;
5262 }
5263
5264 memset (&transfer_info, 0, sizeof (transfer_info));
5265 move_files (job,
5266 fallbacks,
5267 dest_fs_id, &dest_fs_type,
5268 &source_info, &transfer_info);
5269
5270 aborted:
5271 g_list_free_full (fallbacks, g_free);
5272
5273 g_free (dest_fs_id);
5274 g_free (dest_fs_type);
5275
5276 g_io_scheduler_job_send_to_mainloop (io_job,
5277 move_job_done,
5278 job,
5279 NULL((void*)0));
5280
5281 return FALSE(0);
5282}
5283
5284void
5285baul_file_operations_move (GList *files,
5286 GArray *relative_item_points,
5287 GFile *target_dir,
5288 CtkWindow *parent_window,
5289 BaulCopyCallback done_callback,
5290 gpointer done_callback_data)
5291{
5292 CopyMoveJob *job;
5293
5294 job = op_job_new (CopyMoveJob, parent_window, FALSE, contains_multiple_items (files))((CopyMoveJob *)(init_common (sizeof(CopyMoveJob), parent_window
, (0), contains_multiple_items (files))))
;
5295 job->is_move = TRUE(!(0));
5296 job->done_callback = done_callback;
5297 job->done_callback_data = done_callback_data;
5298 job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL((void*)0));
5299 job->destination = g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
5300 if (relative_item_points != NULL((void*)0) &&
5301 relative_item_points->len > 0) {
5302 job->icon_positions =
5303 g_memdup2 (relative_item_points->data,
5304 sizeof (CdkPoint) * relative_item_points->len);
5305 job->n_icon_positions = relative_item_points->len;
5306 }
5307 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
5308
5309 inhibit_power_manager ((CommonJob *)job, _("Moving Files")gettext ("Moving Files"));
5310
5311 // Start UNDO-REDO
5312 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
5313 if (g_file_has_uri_scheme (g_list_first(files)->data, "trash")) {
5314 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_RESTOREFROMTRASH, g_list_length(files));
5315 } else {
5316 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_MOVE, g_list_length(files));
5317 }
5318 GFile* src_dir = g_file_get_parent (files->data);
5319 baul_undostack_manager_data_set_src_dir (job->common.undo_redo_data, src_dir);
5320 g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
5321 baul_undostack_manager_data_set_dest_dir (job->common.undo_redo_data, target_dir);
5322 }
5323 // End UNDO-REDO
5324
5325 g_io_scheduler_push_job (move_job,
5326 job,
5327 NULL((void*)0), /* destroy notify */
5328 0,
5329 job->common.cancellable);
5330}
5331
5332static void
5333report_link_progress (CopyMoveJob *link_job, int total, int left)
5334{
5335 CommonJob *job;
5336
5337 job = (CommonJob *)link_job;
5338
5339 baul_progress_info_take_status (job->progress,
5340 f (_("Creating links in \"%B\"")gettext ("Creating links in \"%B\""),
5341 link_job->destination));
5342
5343 baul_progress_info_take_details (job->progress,
5344 f (ngettext ("Making link to %'d file",
5345 "Making links to %'d files",
5346 left), left));
5347
5348 baul_progress_info_set_progress (job->progress, left, total);
5349}
5350
5351static char *
5352get_abs_path_for_symlink (GFile *file)
5353{
5354 GFile *root, *parent;
5355 char *relative, *abs;
5356
5357 if (g_file_is_native (file)) {
5358 return g_file_get_path (file);
5359 }
5360
5361 root = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
5362 while ((parent = g_file_get_parent (root)) != NULL((void*)0)) {
5363 g_object_unref (root);
5364 root = parent;
5365 }
5366
5367 relative = g_file_get_relative_path (root, file);
5368 g_object_unref (root);
5369 abs = g_strconcat ("/", relative, NULL((void*)0));
5370 g_free (relative);
5371 return abs;
5372}
5373
5374
5375static void
5376link_file (CopyMoveJob *job,
5377 GFile *src, GFile *dest_dir,
5378 char **dest_fs_type,
5379 GHashTable *debuting_files,
5380 CdkPoint *position,
5381 int files_left)
5382{
5383 GFile *src_dir, *dest, *new_dest;
5384 int count;
5385 char *path;
5386 gboolean not_local;
5387 GError *error;
5388 CommonJob *common;
5389 char *primary, *secondary, *details;
5390 int response;
5391 gboolean handled_invalid_filename;
5392
5393 common = (CommonJob *)job;
5394
5395 count = 0;
5396
5397 src_dir = g_file_get_parent (src);
5398 if (g_file_equal (src_dir, dest_dir)) {
5399 count = 1;
5400 }
5401 g_object_unref (src_dir);
5402
5403 handled_invalid_filename = *dest_fs_type != NULL((void*)0);
5404
5405 dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count);
5406
5407 retry:
5408 error = NULL((void*)0);
5409 not_local = FALSE(0);
5410
5411 path = get_abs_path_for_symlink (src);
5412 if (path == NULL((void*)0)) {
5413 not_local = TRUE(!(0));
5414 } else if (g_file_make_symbolic_link (dest,
5415 path,
5416 common->cancellable,
5417 &error)) {
5418 // Start UNDO-REDO
5419 baul_undostack_manager_data_add_origin_target_pair (common->undo_redo_data, src, dest);
5420 // End UNDO-REDO
5421 g_free (path);
5422 if (debuting_files) {
5423 g_hash_table_replace (debuting_files, g_object_ref (dest)((__typeof__ (dest)) (g_object_ref) (dest)), GINT_TO_POINTER (TRUE)((gpointer) (glong) ((!(0)))));
5424 }
5425
5426 baul_file_changes_queue_file_added (dest);
5427 if (position) {
5428 baul_file_changes_queue_schedule_position_set (dest, *position, common->screen_num);
5429 } else {
5430 baul_file_changes_queue_schedule_position_remove (dest);
5431 }
5432
5433 g_object_unref (dest);
5434
5435 return;
5436 }
5437 g_free (path);
5438
5439 if (error != NULL((void*)0) &&
5440 IS_IO_ERROR (error, INVALID_FILENAME)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_INVALID_FILENAME))
&&
5441 !handled_invalid_filename) {
5442 handled_invalid_filename = TRUE(!(0));
5443
5444 g_assert (*dest_fs_type == NULL)do { if (*dest_fs_type == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 5444, ((const char*
) (__func__)), "*dest_fs_type == NULL"); } while (0)
;
5445 *dest_fs_type = query_fs_type (dest_dir, common->cancellable);
5446
5447 new_dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count);
5448
5449 if (!g_file_equal (dest, new_dest)) {
5450 g_object_unref (dest);
5451 dest = new_dest;
5452 g_error_free (error);
5453
5454 goto retry;
5455 } else {
5456 g_object_unref (new_dest);
5457 }
5458 }
5459 /* Conflict */
5460 if (error != NULL((void*)0) && IS_IO_ERROR (error, EXISTS)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_EXISTS))
) {
5461 g_object_unref (dest);
5462 dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count++);
5463 g_error_free (error);
5464 goto retry;
5465 }
5466
5467 else if (error != NULL((void*)0) && IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
5468 g_error_free (error);
5469 }
5470
5471 /* Other error */
5472 else {
5473 if (common->skip_all_error) {
5474 goto out;
5475 }
5476 primary = f (_("Error while creating link to %B.")gettext ("Error while creating link to %B."), src);
5477 if (not_local) {
5478 secondary = f (_("Symbolic links only supported for local files")gettext ("Symbolic links only supported for local files"));
5479 details = NULL((void*)0);
5480 } else if (error != NULL((void*)0) && IS_IO_ERROR (error, NOT_SUPPORTED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_NOT_SUPPORTED))
) {
5481 secondary = f (_("The target doesn't support symbolic links.")gettext ("The target doesn't support symbolic links."));
5482 details = NULL((void*)0);
5483 } else {
5484 secondary = f (_("There was an error creating the symlink in %F.")gettext ("There was an error creating the symlink in %F."), dest_dir);
5485 details = error ? error->message : NULL((void*)0);
5486 }
5487
5488 response = run_warning (common,
5489 primary,
5490 secondary,
5491 details,
5492 files_left > 1,
5493 CANCELgettext ("_Cancel"), SKIP_ALLgettext ("S_kip All"), SKIPgettext ("_Skip"),
5494 NULL((void*)0));
5495
5496 if (error) {
5497 g_error_free (error);
5498 }
5499
5500 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
5501 abort_job (common);
5502 } else if (response == 1) { /* skip all */
5503 common->skip_all_error = TRUE(!(0));
5504 } else if (response == 2) { /* skip */
5505 /* do nothing */
5506 } else {
5507 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 5507, ((const char*) (__func__)), ((void*)0)); } while (0)
;
5508 }
5509 }
5510
5511 out:
5512 g_object_unref (dest);
5513}
5514
5515static gboolean
5516link_job_done (gpointer user_data)
5517{
5518 CopyMoveJob *job;
5519
5520 job = user_data;
5521 if (job->done_callback) {
5522 job->done_callback (job->debuting_files, job->done_callback_data);
5523 }
5524
5525 g_list_free_full (job->files, g_object_unref);
5526 g_object_unref (job->destination);
5527 g_hash_table_unref (job->debuting_files);
5528 g_free (job->icon_positions);
5529
5530 finalize_common ((CommonJob *)job);
5531
5532 baul_file_changes_consume_changes (TRUE(!(0)));
5533 return FALSE(0);
5534}
5535
5536static gboolean
5537link_job (GIOSchedulerJob *io_job,
5538 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
5539 gpointer user_data)
5540{
5541 CopyMoveJob *job;
5542 CommonJob *common;
5543 GFile *src;
5544 CdkPoint *point;
5545 char *dest_fs_type;
5546 int total, left;
5547 int i;
5548 GList *l;
5549
5550 job = user_data;
5551 common = &job->common;
5552 common->io_job = io_job;
5553
5554 dest_fs_type = NULL((void*)0);
5555
5556 baul_progress_info_start (job->common.progress);
5557
5558 verify_destination (&job->common,
5559 job->destination,
5560 NULL((void*)0),
5561 -1);
5562 if (job_aborted (common)) {
5563 goto aborted;
5564 }
5565
5566 total = left = g_list_length (job->files);
5567
5568 report_link_progress (job, total, left);
5569
5570 i = 0;
5571 for (l = job->files;
5572 l != NULL((void*)0) && !job_aborted (common);
5573 l = l->next) {
5574 baul_progress_info_get_ready (common->progress);
5575
5576 src = l->data;
5577
5578 if (i < job->n_icon_positions) {
5579 point = &job->icon_positions[i];
5580 } else {
5581 point = NULL((void*)0);
5582 }
5583
5584
5585 link_file (job, src, job->destination,
5586 &dest_fs_type, job->debuting_files,
5587 point, left);
5588 report_link_progress (job, total, --left);
5589 i++;
5590
5591 }
5592
5593 aborted:
5594 g_free (dest_fs_type);
5595
5596 g_io_scheduler_job_send_to_mainloop (io_job,
5597 link_job_done,
5598 job,
5599 NULL((void*)0));
5600
5601 return FALSE(0);
5602}
5603
5604void
5605baul_file_operations_link (GList *files,
5606 GArray *relative_item_points,
5607 GFile *target_dir,
5608 CtkWindow *parent_window,
5609 BaulCopyCallback done_callback,
5610 gpointer done_callback_data)
5611{
5612 CopyMoveJob *job;
5613
5614 job = op_job_new (CopyMoveJob, parent_window, TRUE, FALSE)((CopyMoveJob *)(init_common (sizeof(CopyMoveJob), parent_window
, (!(0)), (0))))
;
5615 job->done_callback = done_callback;
5616 job->done_callback_data = done_callback_data;
5617 job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL((void*)0));
5618 job->destination = g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
5619 if (relative_item_points != NULL((void*)0) &&
5620 relative_item_points->len > 0) {
5621 job->icon_positions =
5622 g_memdup2 (relative_item_points->data,
5623 sizeof (CdkPoint) * relative_item_points->len);
5624 job->n_icon_positions = relative_item_points->len;
5625 }
5626 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
5627
5628 // Start UNDO-REDO
5629 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
5630 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_CREATELINK, g_list_length(files));
5631 GFile* src_dir = g_file_get_parent (files->data);
5632 baul_undostack_manager_data_set_src_dir (job->common.undo_redo_data, src_dir);
5633 g_object_ref (target_dir)((__typeof__ (target_dir)) (g_object_ref) (target_dir));
5634 baul_undostack_manager_data_set_dest_dir (job->common.undo_redo_data, target_dir);
5635 }
5636 // End UNDO-REDO
5637
5638 g_io_scheduler_push_job (link_job,
5639 job,
5640 NULL((void*)0), /* destroy notify */
5641 0,
5642 job->common.cancellable);
5643}
5644
5645
5646void
5647baul_file_operations_duplicate (GList *files,
5648 GArray *relative_item_points,
5649 CtkWindow *parent_window,
5650 BaulCopyCallback done_callback,
5651 gpointer done_callback_data)
5652{
5653 CopyMoveJob *job;
5654
5655 job = op_job_new (CopyMoveJob, parent_window, FALSE, contains_multiple_items (files))((CopyMoveJob *)(init_common (sizeof(CopyMoveJob), parent_window
, (0), contains_multiple_items (files))))
;
5656 job->done_callback = done_callback;
5657 job->done_callback_data = done_callback_data;
5658 job->files = g_list_copy_deep (files, (GCopyFunc) g_object_ref, NULL((void*)0));
5659 job->destination = NULL((void*)0);
5660 if (relative_item_points != NULL((void*)0) &&
5661 relative_item_points->len > 0) {
5662 job->icon_positions =
5663 g_memdup2 (relative_item_points->data,
5664 sizeof (CdkPoint) * relative_item_points->len);
5665 job->n_icon_positions = relative_item_points->len;
5666 }
5667 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL((void*)0));
5668
5669 // Start UNDO-REDO
5670 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
5671 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_DUPLICATE, g_list_length(files));
5672 GFile* src_dir = g_file_get_parent (files->data);
5673 baul_undostack_manager_data_set_src_dir (job->common.undo_redo_data, src_dir);
5674 g_object_ref (src_dir)((__typeof__ (src_dir)) (g_object_ref) (src_dir));
5675 baul_undostack_manager_data_set_dest_dir (job->common.undo_redo_data, src_dir);
5676 }
5677 // End UNDO-REDO
5678
5679 g_io_scheduler_push_job (copy_job,
5680 job,
5681 NULL((void*)0), /* destroy notify */
5682 0,
5683 job->common.cancellable);
5684}
5685
5686static gboolean
5687set_permissions_job_done (gpointer user_data)
5688{
5689 SetPermissionsJob *job;
5690
5691 job = user_data;
5692
5693 g_object_unref (job->file);
5694
5695 if (job->done_callback) {
5696 job->done_callback (job->done_callback_data);
5697 }
5698
5699 finalize_common ((CommonJob *)job);
5700 return FALSE(0);
5701}
5702
5703static void
5704set_permissions_file (SetPermissionsJob *job,
5705 GFile *file,
5706 GFileInfo *info)
5707{
5708 CommonJob *common;
5709 gboolean free_info;
5710 guint32 current;
5711 guint32 value;
5712 guint32 mask;
5713
5714 common = (CommonJob *)job;
5715
5716 baul_progress_info_pulse_progress (common->progress);
5717
5718 baul_progress_info_get_ready (common->progress);
5719
5720 free_info = FALSE(0);
5721 if (info == NULL((void*)0)) {
5722 free_info = TRUE(!(0));
5723 info = g_file_query_info (file,
5724 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
5725 G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
5726 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
5727 common->cancellable,
5728 NULL((void*)0));
5729 /* Ignore errors */
5730 if (info == NULL((void*)0)) {
5731 return;
5732 }
5733 }
5734
5735 if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
5736 value = job->dir_permissions;
5737 mask = job->dir_mask;
5738 } else {
5739 value = job->file_permissions;
5740 mask = job->file_mask;
5741 }
5742
5743
5744 if (!job_aborted (common) &&
5745 g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode")) {
5746 current = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode");
5747 // Start UNDO-REDO
5748 baul_undostack_manager_data_add_file_permissions(common->undo_redo_data, file, current);
5749 // End UNDO-REDO
5750 current = (current & ~mask) | value;
5751
5752 g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
5753 current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
5754 common->cancellable, NULL((void*)0));
5755 }
5756
5757 if (!job_aborted (common) && g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
5758 GFileEnumerator *enumerator;
5759
5760 enumerator = g_file_enumerate_children (file,
5761 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name"","
5762 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
5763 G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
5764 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
5765 common->cancellable,
5766 NULL((void*)0));
5767 if (enumerator) {
5768 GFile *child = NULL((void*)0);
5769 GFileInfo *child_info = NULL((void*)0);
5770
5771 while (!job_aborted (common) &&
5772 (child_info = g_file_enumerator_next_file (enumerator, common->cancellable, NULL((void*)0))) != NULL((void*)0)) {
5773 child = g_file_get_child (file,
5774 g_file_info_get_name (child_info));
5775 set_permissions_file (job, child, child_info);
5776 g_object_unref (child);
5777 g_object_unref (child_info);
5778 }
5779 g_file_enumerator_close (enumerator, common->cancellable, NULL((void*)0));
5780 g_object_unref (enumerator);
5781 }
5782 }
5783 if (free_info) {
5784 g_object_unref (info);
5785 }
5786}
5787
5788
5789static gboolean
5790set_permissions_job (GIOSchedulerJob *io_job,
5791 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
5792 gpointer user_data)
5793{
5794 SetPermissionsJob *job = user_data;
5795 CommonJob *common;
5796
5797 common = (CommonJob *)job;
5798 common->io_job = io_job;
5799
5800 baul_progress_info_set_status (common->progress,
5801 _("Setting permissions")gettext ("Setting permissions"));
5802
5803 baul_progress_info_start (job->common.progress);
5804
5805 set_permissions_file (job, job->file, NULL((void*)0));
5806
5807 g_io_scheduler_job_send_to_mainloop_async (io_job,
5808 set_permissions_job_done,
5809 job,
5810 NULL((void*)0));
5811
5812 return FALSE(0);
5813}
5814
5815
5816
5817void
5818baul_file_set_permissions_recursive (const char *directory,
5819 guint32 file_permissions,
5820 guint32 file_mask,
5821 guint32 dir_permissions,
5822 guint32 dir_mask,
5823 BaulOpCallback callback,
5824 gpointer callback_data)
5825{
5826 SetPermissionsJob *job;
5827
5828 job = op_job_new (SetPermissionsJob, NULL, TRUE, FALSE)((SetPermissionsJob *)(init_common (sizeof(SetPermissionsJob)
, ((void*)0), (!(0)), (0))))
;
5829 job->file = g_file_new_for_uri (directory);
5830 job->file_permissions = file_permissions;
5831 job->file_mask = file_mask;
5832 job->dir_permissions = dir_permissions;
5833 job->dir_mask = dir_mask;
5834 job->done_callback = callback;
5835 job->done_callback_data = callback_data;
5836
5837 // Start UNDO-REDO
5838 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
5839 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_RECURSIVESETPERMISSIONS, 1);
This statement is never executed
5840 g_object_ref (job->file)((__typeof__ (job->file)) (g_object_ref) (job->file));
5841 baul_undostack_manager_data_set_dest_dir (job->common.undo_redo_data, job->file);
5842 baul_undostack_manager_data_set_recursive_permissions(job->common.undo_redo_data, file_permissions, file_mask, dir_permissions, dir_mask);
5843 }
5844 // End UNDO-REDO
5845
5846 g_io_scheduler_push_job (set_permissions_job,
5847 job,
5848 NULL((void*)0),
5849 0,
5850 NULL((void*)0));
5851}
5852
5853static GList *
5854location_list_from_uri_list (const GList *uris)
5855{
5856 const GList *l;
5857 GList *files;
5858 GFile *f = NULL((void*)0);
5859
5860 files = NULL((void*)0);
5861 for (l = uris; l != NULL((void*)0); l = l->next) {
5862 f = g_file_new_for_uri (l->data);
5863 files = g_list_prepend (files, f);
5864 }
5865
5866 return g_list_reverse (files);
5867}
5868
5869typedef struct {
5870 BaulCopyCallback real_callback;
5871 gpointer real_data;
5872} MoveTrashCBData;
5873
5874static void
5875callback_for_move_to_trash (GHashTable *debuting_uris,
5876 gboolean user_cancelled G_GNUC_UNUSED__attribute__ ((__unused__)),
5877 MoveTrashCBData *data)
5878{
5879 if (data->real_callback)
5880 data->real_callback (debuting_uris, data->real_data);
5881 g_slice_free (MoveTrashCBData, data)do { if (1) g_slice_free1 (sizeof (MoveTrashCBData), (data));
else (void) ((MoveTrashCBData*) 0 == (data)); } while (0)
;
5882}
5883
5884void
5885baul_file_operations_copy_move (const GList *item_uris,
5886 GArray *relative_item_points,
5887 const char *target_dir,
5888 CdkDragAction copy_action,
5889 CtkWidget *parent_view,
5890 BaulCopyCallback done_callback,
5891 gpointer done_callback_data)
5892{
5893 GList *locations;
5894 GList *p;
5895 GFile *dest;
5896 CtkWindow *parent_window;
5897 gboolean target_is_mapping;
5898 gboolean have_nonmapping_source;
5899
5900 dest = NULL((void*)0);
5901 target_is_mapping = FALSE(0);
5902 have_nonmapping_source = FALSE(0);
5903
5904 if (target_dir) {
5905 dest = g_file_new_for_uri (target_dir);
5906 if (g_file_has_uri_scheme (dest, "burn")) {
5907 target_is_mapping = TRUE(!(0));
5908 }
5909 }
5910
5911 locations = location_list_from_uri_list (item_uris);
5912
5913 for (p = location_list_from_uri_list (item_uris); p != NULL((void*)0); p = p->next) {
5914 if (!g_file_has_uri_scheme ((GFile* )p->data, "burn")) {
5915 have_nonmapping_source = TRUE(!(0));
5916 }
5917 }
5918
5919 if (target_is_mapping && have_nonmapping_source && copy_action == CDK_ACTION_MOVE) {
5920 /* never move to "burn:///", but fall back to copy.
5921 * This is a workaround, because otherwise the source files would be removed.
5922 */
5923 copy_action = CDK_ACTION_COPY;
5924 }
5925
5926 parent_window = NULL((void*)0);
5927 if (parent_view) {
5928 parent_window = (CtkWindow *)ctk_widget_get_ancestor (parent_view, CTK_TYPE_WINDOW(ctk_window_get_type ()));
5929 }
5930
5931 if (copy_action == CDK_ACTION_COPY) {
5932 GFile *src_dir;
5933
5934 src_dir = g_file_get_parent (locations->data);
5935 if (target_dir == NULL((void*)0) ||
5936 (src_dir != NULL((void*)0) &&
5937 g_file_equal (src_dir, dest))) {
5938 baul_file_operations_duplicate (locations,
5939 relative_item_points,
5940 parent_window,
5941 done_callback, done_callback_data);
5942 } else {
5943 baul_file_operations_copy (locations,
5944 relative_item_points,
5945 dest,
5946 parent_window,
5947 done_callback, done_callback_data);
5948 }
5949 if (src_dir) {
5950 g_object_unref (src_dir);
5951 }
5952
5953 } else if (copy_action == CDK_ACTION_MOVE) {
5954 if (g_file_has_uri_scheme (dest, "trash")) {
5955 MoveTrashCBData *cb_data;
5956
5957 cb_data = g_slice_new0 (MoveTrashCBData)((MoveTrashCBData*) g_slice_alloc0 (sizeof (MoveTrashCBData))
)
;
5958 cb_data->real_callback = done_callback;
5959 cb_data->real_data = done_callback_data;
5960 baul_file_operations_trash_or_delete (locations,
5961 parent_window,
5962 (BaulDeleteCallback) callback_for_move_to_trash,
5963 cb_data);
5964 } else {
5965 baul_file_operations_move (locations,
5966 relative_item_points,
5967 dest,
5968 parent_window,
5969 done_callback, done_callback_data);
5970 }
5971 } else {
5972 baul_file_operations_link (locations,
5973 relative_item_points,
5974 dest,
5975 parent_window,
5976 done_callback, done_callback_data);
5977 }
5978
5979 g_list_free_full (locations, g_object_unref);
5980 if (dest) {
5981 g_object_unref (dest);
5982 }
5983}
5984
5985static gboolean
5986create_job_done (gpointer user_data)
5987{
5988 CreateJob *job;
5989
5990 job = user_data;
5991 if (job->done_callback) {
5992 job->done_callback (job->created_file, job->done_callback_data);
5993 }
5994
5995 g_object_unref (job->dest_dir);
5996 if (job->src) {
5997 g_object_unref (job->src);
5998 }
5999 g_free (job->src_data);
6000 g_free (job->filename);
6001 if (job->created_file) {
6002 g_object_unref (job->created_file);
6003 }
6004
6005 finalize_common ((CommonJob *)job);
6006
6007 baul_file_changes_consume_changes (TRUE(!(0)));
6008 return FALSE(0);
6009}
6010
6011static gboolean
6012create_job (GIOSchedulerJob *io_job,
6013 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
6014 gpointer user_data)
6015{
6016 CreateJob *job;
6017 CommonJob *common;
6018 int count;
6019 GFile *dest;
6020 char *filename, *filename2, *new_filename;
6021 char *dest_fs_type;
6022 GError *error;
6023 gboolean res;
6024 gboolean filename_is_utf8;
6025 char *primary, *secondary, *details;
6026 int response;
6027 char *data;
6028 int length;
6029 GFileOutputStream *out;
6030 gboolean handled_invalid_filename;
6031 int max_length;
6032
6033 job = user_data;
6034 common = &job->common;
6035 common->io_job = io_job;
6036
6037 baul_progress_info_start (job->common.progress);
6038
6039 handled_invalid_filename = FALSE(0);
6040
6041 dest_fs_type = NULL((void*)0);
6042 filename = NULL((void*)0);
6043 dest = NULL((void*)0);
6044
6045 max_length = get_max_name_length (job->dest_dir);
6046
6047 verify_destination (common,
6048 job->dest_dir,
6049 NULL((void*)0), -1);
6050 if (job_aborted (common)) {
6051 goto aborted;
6052 }
6053
6054 filename = g_strdup (job->filename)g_strdup_inline (job->filename);
6055 filename_is_utf8 = FALSE(0);
6056 if (filename) {
6057 filename_is_utf8 = g_utf8_validate (filename, -1, NULL((void*)0));
6058 }
6059 if (filename == NULL((void*)0)) {
6060 if (job->make_dir) {
6061 /* Translators: the initial name of a new folder */
6062 filename = g_strdup (_("untitled folder"))g_strdup_inline (gettext ("untitled folder"));
6063 filename_is_utf8 = TRUE(!(0)); /* Pass in utf8 */
6064 } else {
6065 if (job->src != NULL((void*)0)) {
6066 filename = g_file_get_basename (job->src);
6067 }
6068 if (filename == NULL((void*)0)) {
6069 /* Translators: the initial name of a new empty file */
6070 filename = g_strdup (_("new file"))g_strdup_inline (gettext ("new file"));
6071 filename_is_utf8 = TRUE(!(0)); /* Pass in utf8 */
6072 }
6073 }
6074 }
6075
6076 make_file_name_valid_for_dest_fs (filename, dest_fs_type);
6077 if (filename_is_utf8) {
6078 dest = g_file_get_child_for_display_name (job->dest_dir, filename, NULL((void*)0));
6079 }
6080 if (dest == NULL((void*)0)) {
6081 dest = g_file_get_child (job->dest_dir, filename);
6082 }
6083 count = 1;
6084
6085 retry:
6086 baul_progress_info_get_ready (common->progress);
6087
6088 error = NULL((void*)0);
6089 if (job->make_dir) {
6090 res = g_file_make_directory (dest,
6091 common->cancellable,
6092 &error);
6093 // Start UNDO-REDO
6094 if (res) {
6095 baul_undostack_manager_data_set_create_data(common->undo_redo_data,
6096 g_file_get_uri(dest),
6097 NULL((void*)0));
6098 }
6099 // End UNDO-REDO
6100 } else {
6101 if (job->src) {
6102 res = g_file_copy (job->src,
6103 dest,
6104 G_FILE_COPY_NONE,
6105 common->cancellable,
6106 NULL((void*)0), NULL((void*)0),
6107 &error);
6108 // Start UNDO-REDO
6109 if (res) {
6110 baul_undostack_manager_data_set_create_data(common->undo_redo_data,
6111 g_file_get_uri(dest),
6112 g_file_get_uri(job->src));
6113 }
6114 // End UNDO-REDO
6115 } else {
6116 data = "";
6117 length = 0;
6118 if (job->src_data) {
6119 data = job->src_data;
6120 length = job->length;
6121 }
6122
6123 out = g_file_create (dest,
6124 G_FILE_CREATE_NONE,
6125 common->cancellable,
6126 &error);
6127 if (out) {
6128 res = g_output_stream_write_all (G_OUTPUT_STREAM (out)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((out)), ((g_output_stream_get_type ()))))))
,
6129 data, length,
6130 NULL((void*)0),
6131 common->cancellable,
6132 &error);
6133 if (res) {
6134 res = g_output_stream_close (G_OUTPUT_STREAM (out)((((GOutputStream*) (void *) g_type_check_instance_cast ((GTypeInstance
*) ((out)), ((g_output_stream_get_type ()))))))
,
6135 common->cancellable,
6136 &error);
6137 // Start UNDO-REDO
6138 if (res) {
6139 baul_undostack_manager_data_set_create_data(common->undo_redo_data,
6140 g_file_get_uri(dest),
6141 g_strdup(data)g_strdup_inline (data));
6142 }
6143 // End UNDO-REDO
6144 }
6145
6146 /* This will close if the write failed and we didn't close */
6147 g_object_unref (out);
6148 } else {
6149 res = FALSE(0);
6150 }
6151 }
6152 }
6153
6154 if (res) {
6155 job->created_file = g_object_ref (dest)((__typeof__ (dest)) (g_object_ref) (dest));
6156 baul_file_changes_queue_file_added (dest);
6157 if (job->has_position) {
6158 baul_file_changes_queue_schedule_position_set (dest, job->position, common->screen_num);
6159 } else {
6160 baul_file_changes_queue_schedule_position_remove (dest);
6161 }
6162 } else {
6163 g_assert (error != NULL)do { if (error != ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 6163, ((const char*
) (__func__)), "error != NULL"); } while (0)
;
6164
6165 if (IS_IO_ERROR (error, INVALID_FILENAME)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_INVALID_FILENAME))
&&
6166 !handled_invalid_filename) {
6167 handled_invalid_filename = TRUE(!(0));
6168
6169 g_assert (dest_fs_type == NULL)do { if (dest_fs_type == ((void*)0)) ; else g_assertion_message_expr
(((gchar*) 0), "baul-file-operations.c", 6169, ((const char*
) (__func__)), "dest_fs_type == NULL"); } while (0)
;
6170 dest_fs_type = query_fs_type (job->dest_dir, common->cancellable);
6171
6172 g_object_unref (dest);
6173
6174 if (count == 1) {
6175 new_filename = g_strdup (filename)g_strdup_inline (filename);
6176 } else if (job->make_dir) {
6177 filename2 = g_strdup_printf ("%s %d", filename, count);
6178
6179 new_filename = NULL((void*)0);
6180 if (max_length > 0 && strlen (filename2) > max_length) {
6181 new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length);
6182 }
6183
6184 if (new_filename == NULL((void*)0)) {
6185 new_filename = g_strdup (filename2)g_strdup_inline (filename2);
6186 }
6187
6188 g_free (filename2);
6189 } else {
6190 new_filename = get_duplicate_name (filename, count, max_length);
6191 }
6192
6193 if (make_file_name_valid_for_dest_fs (new_filename, dest_fs_type)) {
6194 g_object_unref (dest);
6195
6196 if (filename_is_utf8) {
6197 dest = g_file_get_child_for_display_name (job->dest_dir, new_filename, NULL((void*)0));
6198 }
6199 if (dest == NULL((void*)0)) {
6200 dest = g_file_get_child (job->dest_dir, new_filename);
6201 }
6202
6203 g_free (new_filename);
6204 g_error_free (error);
6205 goto retry;
6206 }
6207 g_free (new_filename);
6208 } else if (IS_IO_ERROR (error, EXISTS)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_EXISTS))
) {
6209 g_object_unref (dest);
6210 dest = NULL((void*)0);
6211 if (job->make_dir) {
6212 filename2 = g_strdup_printf ("%s %d", filename, ++count);
6213 if (max_length > 0 && strlen (filename2) > max_length) {
6214 new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length);
6215 if (new_filename != NULL((void*)0)) {
6216 g_free (filename2);
6217 filename2 = new_filename;
6218 }
6219 }
6220 } else {
6221 filename2 = get_duplicate_name (filename, count++, max_length);
6222 }
6223 make_file_name_valid_for_dest_fs (filename2, dest_fs_type);
6224 if (filename_is_utf8) {
6225 dest = g_file_get_child_for_display_name (job->dest_dir, filename2, NULL((void*)0));
6226 }
6227 if (dest == NULL((void*)0)) {
6228 dest = g_file_get_child (job->dest_dir, filename2);
6229 }
6230 g_free (filename2);
6231 g_error_free (error);
6232 goto retry;
6233 }
6234
6235 else if (IS_IO_ERROR (error, CANCELLED)(((error)->domain == g_io_error_quark() && (error)
->code == G_IO_ERROR_CANCELLED))
) {
6236 g_error_free (error);
6237 }
6238
6239 /* Other error */
6240 else {
6241 if (job->make_dir) {
6242 primary = f (_("Error while creating directory %B.")gettext ("Error while creating directory %B."), dest);
6243 } else {
6244 primary = f (_("Error while creating file %B.")gettext ("Error while creating file %B."), dest);
6245 }
6246 secondary = f (_("There was an error creating the directory in %F.")gettext ("There was an error creating the directory in %F."), job->dest_dir);
6247 details = error->message;
6248
6249 response = run_warning (common,
6250 primary,
6251 secondary,
6252 details,
6253 FALSE(0),
6254 CANCELgettext ("_Cancel"), SKIPgettext ("_Skip"),
6255 NULL((void*)0));
6256
6257 g_error_free (error);
6258
6259 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
6260 abort_job (common);
6261 } else if (response == 1) { /* skip */
6262 /* do nothing */
6263 } else {
6264 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 6264, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6265 }
6266 }
6267 }
6268
6269 aborted:
6270 if (dest) {
6271 g_object_unref (dest);
6272 }
6273 g_free (filename);
6274 g_free (dest_fs_type);
6275 g_io_scheduler_job_send_to_mainloop_async (io_job,
6276 create_job_done,
6277 job,
6278 NULL((void*)0));
6279
6280 return FALSE(0);
6281}
6282
6283void
6284baul_file_operations_new_folder (CtkWidget *parent_view,
6285 CdkPoint *target_point,
6286 const char *parent_dir,
6287 BaulCreateCallback done_callback,
6288 gpointer done_callback_data)
6289{
6290 CreateJob *job;
6291 CtkWindow *parent_window;
6292
6293 parent_window = NULL((void*)0);
6294 if (parent_view) {
6295 parent_window = (CtkWindow *)ctk_widget_get_ancestor (parent_view, CTK_TYPE_WINDOW(ctk_window_get_type ()));
6296 }
6297
6298 job = op_job_new (CreateJob, parent_window, TRUE, FALSE)((CreateJob *)(init_common (sizeof(CreateJob), parent_window,
(!(0)), (0))))
;
6299 job->done_callback = done_callback;
6300 job->done_callback_data = done_callback_data;
6301 job->dest_dir = g_file_new_for_uri (parent_dir);
6302 job->make_dir = TRUE(!(0));
6303 if (target_point != NULL((void*)0)) {
6304 job->position = *target_point;
6305 job->has_position = TRUE(!(0));
6306 }
6307
6308 // Start UNDO-REDO
6309 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
6310 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_CREATEFOLDER, 1);
6311 }
6312 // End UNDO-REDO
6313
6314 g_io_scheduler_push_job (create_job,
6315 job,
6316 NULL((void*)0), /* destroy notify */
6317 0,
6318 job->common.cancellable);
6319}
6320
6321void
6322baul_file_operations_new_file_from_template (CtkWidget *parent_view,
6323 CdkPoint *target_point,
6324 const char *parent_dir,
6325 const char *target_filename,
6326 const char *template_uri,
6327 BaulCreateCallback done_callback,
6328 gpointer done_callback_data)
6329{
6330 CreateJob *job;
6331 CtkWindow *parent_window;
6332
6333 parent_window = NULL((void*)0);
6334 if (parent_view) {
6335 parent_window = (CtkWindow *)ctk_widget_get_ancestor (parent_view, CTK_TYPE_WINDOW(ctk_window_get_type ()));
6336 }
6337
6338 job = op_job_new (CreateJob, parent_window, TRUE, FALSE)((CreateJob *)(init_common (sizeof(CreateJob), parent_window,
(!(0)), (0))))
;
6339 job->done_callback = done_callback;
6340 job->done_callback_data = done_callback_data;
6341 job->dest_dir = g_file_new_for_uri (parent_dir);
6342 if (target_point != NULL((void*)0)) {
6343 job->position = *target_point;
6344 job->has_position = TRUE(!(0));
6345 }
6346 job->filename = g_strdup (target_filename)g_strdup_inline (target_filename);
6347
6348 if (template_uri) {
6349 job->src = g_file_new_for_uri (template_uri);
6350 }
6351
6352 // Start UNDO-REDO
6353 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
6354 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_CREATEFILEFROMTEMPLATE, 1);
6355 }
6356 // End UNDO-REDO
6357
6358 g_io_scheduler_push_job (create_job,
6359 job,
6360 NULL((void*)0), /* destroy notify */
6361 0,
6362 job->common.cancellable);
6363}
6364
6365void
6366baul_file_operations_new_file (CtkWidget *parent_view,
6367 CdkPoint *target_point,
6368 const char *parent_dir,
6369 const char *target_filename,
6370 const char *initial_contents,
6371 int length,
6372 BaulCreateCallback done_callback,
6373 gpointer done_callback_data)
6374{
6375 CreateJob *job;
6376 CtkWindow *parent_window;
6377
6378 parent_window = NULL((void*)0);
6379 if (parent_view) {
6380 parent_window = (CtkWindow *)ctk_widget_get_ancestor (parent_view, CTK_TYPE_WINDOW(ctk_window_get_type ()));
6381 }
6382
6383 job = op_job_new (CreateJob, parent_window, TRUE, FALSE)((CreateJob *)(init_common (sizeof(CreateJob), parent_window,
(!(0)), (0))))
;
6384 job->done_callback = done_callback;
6385 job->done_callback_data = done_callback_data;
6386 job->dest_dir = g_file_new_for_uri (parent_dir);
6387 if (target_point != NULL((void*)0)) {
6388 job->position = *target_point;
6389 job->has_position = TRUE(!(0));
6390 }
6391 job->src_data = g_memdup2 (initial_contents, length);
6392 job->length = length;
6393 job->filename = g_strdup (target_filename)g_strdup_inline (target_filename);
6394
6395 // Start UNDO-REDO
6396 if (!baul_undostack_manager_is_undo_redo(baul_undostack_manager_instance())) {
6397 job->common.undo_redo_data = baul_undostack_manager_data_new (BAUL_UNDOSTACK_CREATEEMPTYFILE, 1);
6398 }
6399 // End UNDO-REDO
6400
6401 g_io_scheduler_push_job (create_job,
6402 job,
6403 NULL((void*)0), /* destroy notify */
6404 0,
6405 job->common.cancellable);
6406}
6407
6408
6409
6410static void
6411delete_trash_file (CommonJob *job,
6412 GFile *file,
6413 gboolean del_file,
6414 gboolean del_children)
6415{
6416 baul_progress_info_get_ready (job->progress);
6417
6418 if (job_aborted (job)) {
6419 return;
6420 }
6421
6422 if (del_children) {
6423 GFileEnumerator *enumerator;
6424
6425 enumerator = g_file_enumerate_children (file,
6426 G_FILE_ATTRIBUTE_STANDARD_NAME"standard::name" ","
6427 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type",
6428 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
6429 job->cancellable,
6430 NULL((void*)0));
6431 if (enumerator) {
6432 GFileInfo *info = NULL((void*)0);
6433 GFile *child = NULL((void*)0);
6434
6435 while (!job_aborted (job) &&
6436 (info = g_file_enumerator_next_file (enumerator, job->cancellable, NULL((void*)0))) != NULL((void*)0)) {
6437 child = g_file_get_child (file,
6438 g_file_info_get_name (info));
6439 delete_trash_file (job, child, TRUE(!(0)),
6440 g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY);
6441 g_object_unref (child);
6442 g_object_unref (info);
6443 }
6444 g_file_enumerator_close (enumerator, job->cancellable, NULL((void*)0));
6445 g_object_unref (enumerator);
6446 }
6447 }
6448
6449 if (!job_aborted (job) && del_file) {
6450 g_file_delete (file, job->cancellable, NULL((void*)0));
6451 }
6452}
6453
6454static gboolean
6455empty_trash_job_done (gpointer user_data)
6456{
6457 EmptyTrashJob *job;
6458
6459 job = user_data;
6460
6461 g_list_free_full (job->trash_dirs, g_object_unref);
6462
6463 if (job->done_callback) {
6464 job->done_callback (job->done_callback_data);
6465 }
6466
6467 baul_undostack_manager_trash_has_emptied(baul_undostack_manager_instance());
6468
6469 finalize_common ((CommonJob *)job);
6470 return FALSE(0);
6471}
6472
6473static gboolean
6474empty_trash_job (GIOSchedulerJob *io_job,
6475 GCancellable *cancellable G_GNUC_UNUSED__attribute__ ((__unused__)),
6476 gpointer user_data)
6477{
6478 EmptyTrashJob *job = user_data;
6479 CommonJob *common;
6480 GList *l;
6481 gboolean confirmed;
6482
6483 common = (CommonJob *)job;
6484 common->io_job = io_job;
6485
6486 baul_progress_info_start (job->common.progress);
6487
6488 if (job->should_confirm) {
6489 confirmed = confirm_empty_trash (common);
6490 } else {
6491 confirmed = TRUE(!(0));
6492 }
6493 if (confirmed) {
6494 for (l = job->trash_dirs;
6495 l != NULL((void*)0) && !job_aborted (common);
6496 l = l->next) {
6497 delete_trash_file (common, l->data, FALSE(0), TRUE(!(0)));
6498 }
6499 }
6500
6501 g_io_scheduler_job_send_to_mainloop_async (io_job,
6502 empty_trash_job_done,
6503 job,
6504 NULL((void*)0));
6505
6506 return FALSE(0);
6507}
6508
6509void
6510baul_file_operations_empty_trash (CtkWidget *parent_view)
6511{
6512 EmptyTrashJob *job;
6513 CtkWindow *parent_window;
6514
6515 parent_window = NULL((void*)0);
6516 if (parent_view) {
6517 parent_window = (CtkWindow *)ctk_widget_get_ancestor (parent_view, CTK_TYPE_WINDOW(ctk_window_get_type ()));
6518 }
6519
6520 job = op_job_new (EmptyTrashJob, parent_window, TRUE, FALSE)((EmptyTrashJob *)(init_common (sizeof(EmptyTrashJob), parent_window
, (!(0)), (0))))
;
6521 job->trash_dirs = g_list_prepend (job->trash_dirs,
6522 g_file_new_for_uri ("trash:"));
6523 job->should_confirm = TRUE(!(0));
6524
6525 inhibit_power_manager ((CommonJob *)job, _("Emptying Trash")gettext ("Emptying Trash"));
6526
6527 g_io_scheduler_push_job (empty_trash_job,
6528 job,
6529 NULL((void*)0),
6530 0,
6531 NULL((void*)0));
6532}
6533
6534static gboolean
6535mark_trusted_job_done (gpointer user_data)
6536{
6537 MarkTrustedJob *job = user_data;
6538
6539 g_object_unref (job->file);
6540
6541 if (job->done_callback) {
6542 job->done_callback (job->done_callback_data);
6543 }
6544
6545 finalize_common ((CommonJob *)job);
6546 return FALSE(0);
6547}
6548
6549#define TRUSTED_SHEBANG"#!/usr/bin/env xdg-open\n" "#!/usr/bin/env xdg-open\n"
6550
6551static void
6552mark_desktop_file_trusted (CommonJob *common,
6553 GCancellable *cancellable,
6554 GFile *file,
6555 gboolean interactive)
6556{
6557 char *contents, *new_contents;
6558 gsize length, new_length;
6559 GError *error;
6560 guint32 current_perms, new_perms;
6561 int response;
6562 GFileInfo *info;
6563
6564 retry:
6565 baul_progress_info_get_ready (common->progress);
6566
6567 error = NULL((void*)0);
6568 if (!g_file_load_contents (file,
6569 cancellable,
6570 &contents, &length,
6571 NULL((void*)0), &error)) {
6572 if (interactive) {
6573 response = run_error (common,
6574 g_strdup (_("Unable to mark launcher trusted (executable)"))g_strdup_inline (gettext ("Unable to mark launcher trusted (executable)"
))
,
6575 error->message,
6576 NULL((void*)0),
6577 FALSE(0),
6578 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"),
6579 NULL((void*)0));
6580 } else {
6581 response = 0;
6582 }
6583
6584
6585 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
6586 abort_job (common);
6587 } else if (response == 1) {
6588 goto retry;
6589 } else {
6590 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 6590, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6591 }
6592
6593 goto out;
6594 }
6595
6596 if (!g_str_has_prefix (contents, "#!")(__builtin_constant_p ("#!")? __extension__ ({ const char * const
__str = (contents); const char * const __prefix = ("#!"); gboolean
__result = (0); if (__str == ((void*)0) || __prefix == ((void
*)0)) __result = (g_str_has_prefix) (__str, __prefix); else {
const size_t __str_len = strlen (((__str) + !(__str))); const
size_t __prefix_len = strlen (((__prefix) + !(__prefix))); if
(__str_len >= __prefix_len) __result = memcmp (((__str) +
!(__str)), ((__prefix) + !(__prefix)), __prefix_len) == 0; }
__result; }) : (g_str_has_prefix) (contents, "#!") )
) {
6597 new_length = length + strlen (TRUSTED_SHEBANG"#!/usr/bin/env xdg-open\n") + 1;
6598 new_contents = g_malloc0 (new_length);
6599
6600 g_strlcpy (new_contents, TRUSTED_SHEBANG"#!/usr/bin/env xdg-open\n", new_length);
6601 memcpy (new_contents + strlen (TRUSTED_SHEBANG"#!/usr/bin/env xdg-open\n"),
6602 contents, length);
6603
6604 if (!g_file_replace_contents (file,
6605 new_contents,
6606 new_length,
6607 NULL((void*)0),
6608 FALSE(0), 0,
6609 NULL((void*)0), cancellable, &error)) {
6610 g_free (contents);
6611 g_free (new_contents);
6612
6613 if (interactive) {
6614 response = run_error (common,
6615 g_strdup (_("Unable to mark launcher trusted (executable)"))g_strdup_inline (gettext ("Unable to mark launcher trusted (executable)"
))
,
6616 error->message,
6617 NULL((void*)0),
6618 FALSE(0),
6619 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"),
6620 NULL((void*)0));
6621 } else {
6622 response = 0;
6623 }
6624
6625 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
6626 abort_job (common);
6627 } else if (response == 1) {
6628 goto retry;
6629 } else {
6630 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 6630, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6631 }
6632
6633 goto out;
6634 }
6635 g_free (new_contents);
6636
6637 }
6638 g_free (contents);
6639
6640 info = g_file_query_info (file,
6641 G_FILE_ATTRIBUTE_STANDARD_TYPE"standard::type"","
6642 G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
6643 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
6644 common->cancellable,
6645 &error);
6646
6647 if (info == NULL((void*)0)) {
6648 if (interactive) {
6649 response = run_error (common,
6650 g_strdup (_("Unable to mark launcher trusted (executable)"))g_strdup_inline (gettext ("Unable to mark launcher trusted (executable)"
))
,
6651 error->message,
6652 NULL((void*)0),
6653 FALSE(0),
6654 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"),
6655 NULL((void*)0));
6656 } else {
6657 response = 0;
6658 }
6659
6660 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
6661 abort_job (common);
6662 } else if (response == 1) {
6663 goto retry;
6664 } else {
6665 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 6665, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6666 }
6667
6668 goto out;
6669 }
6670
6671
6672 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode")) {
6673 current_perms = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode");
6674 new_perms = current_perms | S_IXGRP(0100 >> 3) | S_IXUSR0100 | S_IXOTH((0100 >> 3) >> 3);
6675
6676 if ((current_perms != new_perms) &&
6677 !g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE"unix::mode",
6678 new_perms, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
6679 common->cancellable, &error))
6680 {
6681 g_object_unref (info);
6682
6683 if (interactive) {
6684 response = run_error (common,
6685 g_strdup (_("Unable to mark launcher trusted (executable)"))g_strdup_inline (gettext ("Unable to mark launcher trusted (executable)"
))
,
6686 error->message,
6687 NULL((void*)0),
6688 FALSE(0),
6689 CANCELgettext ("_Cancel"), RETRYgettext ("_Retry"),
6690 NULL((void*)0));
6691 } else {
6692 response = 0;
6693 }
6694
6695 if (response == 0 || response == CTK_RESPONSE_DELETE_EVENT) {
6696 abort_job (common);
6697 } else if (response == 1) {
6698 goto retry;
6699 } else {
6700 g_assert_not_reached ()do { g_assertion_message_expr (((gchar*) 0), "baul-file-operations.c"
, 6700, ((const char*) (__func__)), ((void*)0)); } while (0)
;
6701 }
6702
6703 goto out;
6704 }
6705 }
6706 g_object_unref (info);
6707 out:
6708 ;
6709}
6710
6711static gboolean
6712mark_trusted_job (GIOSchedulerJob *io_job,
6713 GCancellable *cancellable,
6714 gpointer user_data)
6715{
6716 MarkTrustedJob *job = user_data;
6717 CommonJob *common;
6718
6719 common = (CommonJob *)job;
6720 common->io_job = io_job;
6721
6722 baul_progress_info_start (job->common.progress);
6723
6724 mark_desktop_file_trusted (common,
6725 cancellable,
6726 job->file,
6727 job->interactive);
6728
6729 g_io_scheduler_job_send_to_mainloop_async (io_job,
6730 mark_trusted_job_done,
6731 job,
6732 NULL((void*)0));
6733
6734 return FALSE(0);
6735}
6736
6737void
6738baul_file_mark_desktop_file_trusted (GFile *file,
6739 CtkWindow *parent_window,
6740 gboolean interactive,
6741 BaulOpCallback done_callback,
6742 gpointer done_callback_data)
6743{
6744 MarkTrustedJob *job;
6745
6746 job = op_job_new (MarkTrustedJob, parent_window, TRUE, FALSE)((MarkTrustedJob *)(init_common (sizeof(MarkTrustedJob), parent_window
, (!(0)), (0))))
;
6747 job->file = g_object_ref (file)((__typeof__ (file)) (g_object_ref) (file));
6748 job->interactive = interactive;
6749 job->done_callback = done_callback;
6750 job->done_callback_data = done_callback_data;
6751
6752 g_io_scheduler_push_job (mark_trusted_job,
6753 job,
6754 NULL((void*)0),
6755 0,
6756 NULL((void*)0));
6757}
6758
6759#if !defined (BAUL_OMIT_SELF_CHECK)
6760
6761void
6762baul_self_check_file_operations (void)
6763{
6764 setlocale (LC_MESSAGES5, "C");
6765
6766
6767 /* test the next duplicate name generator */
6768 EEL_CHECK_STRING_RESULT (get_duplicate_name (" (copy)", 1, -1), " (another copy)")do { eel_before_check ("get_duplicate_name (\" (copy)\", 1, -1)"
, "baul-file-operations.c", 6768); eel_check_string_result (get_duplicate_name
(" (copy)", 1, -1), " (another copy)"); } while (0)
;
6769 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo", 1, -1), "foo (copy)")do { eel_before_check ("get_duplicate_name (\"foo\", 1, -1)",
"baul-file-operations.c", 6769); eel_check_string_result (get_duplicate_name
("foo", 1, -1), "foo (copy)"); } while (0)
;
6770 EEL_CHECK_STRING_RESULT (get_duplicate_name (".bashrc", 1, -1), ".bashrc (copy)")do { eel_before_check ("get_duplicate_name (\".bashrc\", 1, -1)"
, "baul-file-operations.c", 6770); eel_check_string_result (get_duplicate_name
(".bashrc", 1, -1), ".bashrc (copy)"); } while (0)
;
6771 EEL_CHECK_STRING_RESULT (get_duplicate_name (".foo.txt", 1, -1), ".foo (copy).txt")do { eel_before_check ("get_duplicate_name (\".foo.txt\", 1, -1)"
, "baul-file-operations.c", 6771); eel_check_string_result (get_duplicate_name
(".foo.txt", 1, -1), ".foo (copy).txt"); } while (0)
;
6772 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo", 1, -1), "foo foo (copy)")do { eel_before_check ("get_duplicate_name (\"foo foo\", 1, -1)"
, "baul-file-operations.c", 6772); eel_check_string_result (get_duplicate_name
("foo foo", 1, -1), "foo foo (copy)"); } while (0)
;
6773 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo.txt", 1, -1), "foo (copy).txt")do { eel_before_check ("get_duplicate_name (\"foo.txt\", 1, -1)"
, "baul-file-operations.c", 6773); eel_check_string_result (get_duplicate_name
("foo.txt", 1, -1), "foo (copy).txt"); } while (0)
;
6774 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt", 1, -1), "foo foo (copy).txt")do { eel_before_check ("get_duplicate_name (\"foo foo.txt\", 1, -1)"
, "baul-file-operations.c", 6774); eel_check_string_result (get_duplicate_name
("foo foo.txt", 1, -1), "foo foo (copy).txt"); } while (0)
;
6775 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt txt", 1, -1), "foo foo (copy).txt txt")do { eel_before_check ("get_duplicate_name (\"foo foo.txt txt\", 1, -1)"
, "baul-file-operations.c", 6775); eel_check_string_result (get_duplicate_name
("foo foo.txt txt", 1, -1), "foo foo (copy).txt txt"); } while
(0)
;
6776 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...txt", 1, -1), "foo (copy)...txt")do { eel_before_check ("get_duplicate_name (\"foo...txt\", 1, -1)"
, "baul-file-operations.c", 6776); eel_check_string_result (get_duplicate_name
("foo...txt", 1, -1), "foo (copy)...txt"); } while (0)
;
6777 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...", 1, -1), "foo (copy)...")do { eel_before_check ("get_duplicate_name (\"foo...\", 1, -1)"
, "baul-file-operations.c", 6777); eel_check_string_result (get_duplicate_name
("foo...", 1, -1), "foo (copy)..."); } while (0)
;
6778 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo. (copy)", 1, -1), "foo. (another copy)")do { eel_before_check ("get_duplicate_name (\"foo. (copy)\", 1, -1)"
, "baul-file-operations.c", 6778); eel_check_string_result (get_duplicate_name
("foo. (copy)", 1, -1), "foo. (another copy)"); } while (0)
;
6779 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy)", 1, -1), "foo (another copy)")do { eel_before_check ("get_duplicate_name (\"foo (copy)\", 1, -1)"
, "baul-file-operations.c", 6779); eel_check_string_result (get_duplicate_name
("foo (copy)", 1, -1), "foo (another copy)"); } while (0)
;
6780 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy).txt", 1, -1), "foo (another copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (copy).txt\", 1, -1)"
, "baul-file-operations.c", 6780); eel_check_string_result (get_duplicate_name
("foo (copy).txt", 1, -1), "foo (another copy).txt"); } while
(0)
;
6781 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy)", 1, -1), "foo (3rd copy)")do { eel_before_check ("get_duplicate_name (\"foo (another copy)\", 1, -1)"
, "baul-file-operations.c", 6781); eel_check_string_result (get_duplicate_name
("foo (another copy)", 1, -1), "foo (3rd copy)"); } while (0
)
;
6782 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy).txt", 1, -1), "foo (3rd copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (another copy).txt\", 1, -1)"
, "baul-file-operations.c", 6782); eel_check_string_result (get_duplicate_name
("foo (another copy).txt", 1, -1), "foo (3rd copy).txt"); } while
(0)
;
6783 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (another copy).txt", 1, -1), "foo foo (3rd copy).txt")do { eel_before_check ("get_duplicate_name (\"foo foo (another copy).txt\", 1, -1)"
, "baul-file-operations.c", 6783); eel_check_string_result (get_duplicate_name
("foo foo (another copy).txt", 1, -1), "foo foo (3rd copy).txt"
); } while (0)
;
6784 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy)", 1, -1), "foo (14th copy)")do { eel_before_check ("get_duplicate_name (\"foo (13th copy)\", 1, -1)"
, "baul-file-operations.c", 6784); eel_check_string_result (get_duplicate_name
("foo (13th copy)", 1, -1), "foo (14th copy)"); } while (0)
;
6785 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy).txt", 1, -1), "foo (14th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (13th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6785); eel_check_string_result (get_duplicate_name
("foo (13th copy).txt", 1, -1), "foo (14th copy).txt"); } while
(0)
;
6786 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy)", 1, -1), "foo (22nd copy)")do { eel_before_check ("get_duplicate_name (\"foo (21st copy)\", 1, -1)"
, "baul-file-operations.c", 6786); eel_check_string_result (get_duplicate_name
("foo (21st copy)", 1, -1), "foo (22nd copy)"); } while (0)
;
6787 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy).txt", 1, -1), "foo (22nd copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (21st copy).txt\", 1, -1)"
, "baul-file-operations.c", 6787); eel_check_string_result (get_duplicate_name
("foo (21st copy).txt", 1, -1), "foo (22nd copy).txt"); } while
(0)
;
6788 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy)", 1, -1), "foo (23rd copy)")do { eel_before_check ("get_duplicate_name (\"foo (22nd copy)\", 1, -1)"
, "baul-file-operations.c", 6788); eel_check_string_result (get_duplicate_name
("foo (22nd copy)", 1, -1), "foo (23rd copy)"); } while (0)
;
6789 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy).txt", 1, -1), "foo (23rd copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (22nd copy).txt\", 1, -1)"
, "baul-file-operations.c", 6789); eel_check_string_result (get_duplicate_name
("foo (22nd copy).txt", 1, -1), "foo (23rd copy).txt"); } while
(0)
;
6790 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy)", 1, -1), "foo (24th copy)")do { eel_before_check ("get_duplicate_name (\"foo (23rd copy)\", 1, -1)"
, "baul-file-operations.c", 6790); eel_check_string_result (get_duplicate_name
("foo (23rd copy)", 1, -1), "foo (24th copy)"); } while (0)
;
6791 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy).txt", 1, -1), "foo (24th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (23rd copy).txt\", 1, -1)"
, "baul-file-operations.c", 6791); eel_check_string_result (get_duplicate_name
("foo (23rd copy).txt", 1, -1), "foo (24th copy).txt"); } while
(0)
;
6792 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy)", 1, -1), "foo (25th copy)")do { eel_before_check ("get_duplicate_name (\"foo (24th copy)\", 1, -1)"
, "baul-file-operations.c", 6792); eel_check_string_result (get_duplicate_name
("foo (24th copy)", 1, -1), "foo (25th copy)"); } while (0)
;
6793 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy).txt", 1, -1), "foo (25th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (24th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6793); eel_check_string_result (get_duplicate_name
("foo (24th copy).txt", 1, -1), "foo (25th copy).txt"); } while
(0)
;
6794 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy)", 1, -1), "foo foo (25th copy)")do { eel_before_check ("get_duplicate_name (\"foo foo (24th copy)\", 1, -1)"
, "baul-file-operations.c", 6794); eel_check_string_result (get_duplicate_name
("foo foo (24th copy)", 1, -1), "foo foo (25th copy)"); } while
(0)
;
6795 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy).txt", 1, -1), "foo foo (25th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo foo (24th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6795); eel_check_string_result (get_duplicate_name
("foo foo (24th copy).txt", 1, -1), "foo foo (25th copy).txt"
); } while (0)
;
6796 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (100000000000000th copy).txt", 1, -1), "foo foo (copy).txt")do { eel_before_check ("get_duplicate_name (\"foo foo (100000000000000th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6796); eel_check_string_result (get_duplicate_name
("foo foo (100000000000000th copy).txt", 1, -1), "foo foo (copy).txt"
); } while (0)
;
6797 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy)", 1, -1), "foo (11th copy)")do { eel_before_check ("get_duplicate_name (\"foo (10th copy)\", 1, -1)"
, "baul-file-operations.c", 6797); eel_check_string_result (get_duplicate_name
("foo (10th copy)", 1, -1), "foo (11th copy)"); } while (0)
;
6798 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy).txt", 1, -1), "foo (11th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (10th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6798); eel_check_string_result (get_duplicate_name
("foo (10th copy).txt", 1, -1), "foo (11th copy).txt"); } while
(0)
;
6799 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy)", 1, -1), "foo (12th copy)")do { eel_before_check ("get_duplicate_name (\"foo (11th copy)\", 1, -1)"
, "baul-file-operations.c", 6799); eel_check_string_result (get_duplicate_name
("foo (11th copy)", 1, -1), "foo (12th copy)"); } while (0)
;
6800 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy).txt", 1, -1), "foo (12th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (11th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6800); eel_check_string_result (get_duplicate_name
("foo (11th copy).txt", 1, -1), "foo (12th copy).txt"); } while
(0)
;
6801 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy)", 1, -1), "foo (13th copy)")do { eel_before_check ("get_duplicate_name (\"foo (12th copy)\", 1, -1)"
, "baul-file-operations.c", 6801); eel_check_string_result (get_duplicate_name
("foo (12th copy)", 1, -1), "foo (13th copy)"); } while (0)
;
6802 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy).txt", 1, -1), "foo (13th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (12th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6802); eel_check_string_result (get_duplicate_name
("foo (12th copy).txt", 1, -1), "foo (13th copy).txt"); } while
(0)
;
6803 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy)", 1, -1), "foo (111th copy)")do { eel_before_check ("get_duplicate_name (\"foo (110th copy)\", 1, -1)"
, "baul-file-operations.c", 6803); eel_check_string_result (get_duplicate_name
("foo (110th copy)", 1, -1), "foo (111th copy)"); } while (0
)
;
6804 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy).txt", 1, -1), "foo (111th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (110th copy).txt\", 1, -1)"
, "baul-file-operations.c", 6804); eel_check_string_result (get_duplicate_name
("foo (110th copy).txt", 1, -1), "foo (111th copy).txt"); } while
(0)
;
6805 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy)", 1, -1), "foo (123rd copy)")do { eel_before_check ("get_duplicate_name (\"foo (122nd copy)\", 1, -1)"
, "baul-file-operations.c", 6805); eel_check_string_result (get_duplicate_name
("foo (122nd copy)", 1, -1), "foo (123rd copy)"); } while (0
)
;
6806 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy).txt", 1, -1), "foo (123rd copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (122nd copy).txt\", 1, -1)"
, "baul-file-operations.c", 6806); eel_check_string_result (get_duplicate_name
("foo (122nd copy).txt", 1, -1), "foo (123rd copy).txt"); } while
(0)
;
6807 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy)", 1, -1), "foo (124th copy)")do { eel_before_check ("get_duplicate_name (\"foo (123rd copy)\", 1, -1)"
, "baul-file-operations.c", 6807); eel_check_string_result (get_duplicate_name
("foo (123rd copy)", 1, -1), "foo (124th copy)"); } while (0
)
;
6808 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy).txt", 1, -1), "foo (124th copy).txt")do { eel_before_check ("get_duplicate_name (\"foo (123rd copy).txt\", 1, -1)"
, "baul-file-operations.c", 6808); eel_check_string_result (get_duplicate_name
("foo (123rd copy).txt", 1, -1), "foo (124th copy).txt"); } while
(0)
;
6809
6810 setlocale (LC_MESSAGES5, "");
6811}
6812
6813#endif