Bug Summary

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