File: | libbaul-private/baul-file-operations.c |
Warning: | line 2915, column 3 Value stored to 'response' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
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 | |
71 | typedef 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 | |
89 | typedef 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 | |
102 | typedef 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 | |
111 | typedef 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 | |
127 | typedef struct { |
128 | CommonJob common; |
129 | GList *trash_dirs; |
130 | gboolean should_confirm; |
131 | BaulOpCallback done_callback; |
132 | gpointer done_callback_data; |
133 | } EmptyTrashJob; |
134 | |
135 | typedef struct { |
136 | CommonJob common; |
137 | GFile *file; |
138 | gboolean interactive; |
139 | BaulOpCallback done_callback; |
140 | gpointer done_callback_data; |
141 | } MarkTrustedJob; |
142 | |
143 | typedef 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 | |
154 | typedef enum { |
155 | OP_KIND_COPY, |
156 | OP_KIND_MOVE, |
157 | OP_KIND_DELETE, |
158 | OP_KIND_TRASH |
159 | } OpKind; |
160 | |
161 | typedef struct { |
162 | int num_files; |
163 | goffset num_bytes; |
164 | int num_files_since_progress; |
165 | OpKind op; |
166 | } SourceInfo; |
167 | |
168 | typedef 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 | |
195 | NotifyNotification *unmount_notify; |
196 | |
197 | void |
198 | baul_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 | |
224 | static void |
225 | mark_desktop_file_trusted (CommonJob *common, |
226 | GCancellable *cancellable, |
227 | GFile *file, |
228 | gboolean interactive); |
229 | |
230 | static gboolean |
231 | is_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 | |
241 | static void scan_sources (GList *files, |
242 | SourceInfo *source_info, |
243 | CommonJob *job, |
244 | OpKind kind); |
245 | |
246 | |
247 | static gboolean empty_trash_job (GIOSchedulerJob *io_job, |
248 | GCancellable *cancellable, |
249 | gpointer user_data); |
250 | |
251 | static 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 | */ |
261 | static int |
262 | seconds_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 | |
294 | static char * |
295 | format_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 | |
335 | static char * |
336 | shorten_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 | |
377 | static char * |
378 | get_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 */ |
477 | static const char untranslated_copy_duplicate_tag[] = N_(" (copy)")(" (copy)"); |
478 | /* Translators: tag used to detect the second copy of a file */ |
479 | static 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 */ |
482 | static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)")("th copy)"); |
483 | /* Translators: tag used to detect the x12th copy of a file */ |
484 | static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)")("th copy)"); |
485 | /* Translators: tag used to detect the x13th copy of a file */ |
486 | static 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 */ |
489 | static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)")("st copy)"); |
490 | /* Translators: tag used to detect the x2nd copy of a file */ |
491 | static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)")("nd copy)"); |
492 | /* Translators: tag used to detect the x3rd copy of a file */ |
493 | static 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 */ |
496 | static 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 */ |
510 | static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s")("%s (copy)%s"); |
511 | /* Translators: appended to second file copy */ |
512 | static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s")("%s (another copy)%s"); |
513 | |
514 | /* Translators: appended to x11th file copy */ |
515 | static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s"); |
516 | /* Translators: appended to x12th file copy */ |
517 | static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%'dth copy)%s")("%s (%'dth copy)%s"); |
518 | /* Translators: appended to x13th file copy */ |
519 | static 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 */ |
527 | static const char untranslated_st_copy_duplicate_format[] = N_("%s (%'dst copy)%s")("%s (%'dst copy)%s"); |
528 | /* Translators: appended to x2nd file copy */ |
529 | static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%'dnd copy)%s")("%s (%'dnd copy)%s"); |
530 | /* Translators: appended to x3rd file copy */ |
531 | static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%'drd copy)%s")("%s (%'drd copy)%s"); |
532 | /* Translators: appended to xxth file copy */ |
533 | static 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 | |
546 | static char * |
547 | extract_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 | */ |
565 | static void |
566 | parse_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 | |
660 | static char * |
661 | make_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 | |
763 | static char * |
764 | get_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 | |
779 | static gboolean |
780 | has_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 | |
801 | static char * |
802 | custom_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 | |
811 | static void |
812 | custom_full_name_skip (va_list *va) |
813 | { |
814 | (void) va_arg (*va, GFile *)__builtin_va_arg(*va, GFile *); |
815 | } |
816 | |
817 | static char * |
818 | custom_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 | |
866 | static void |
867 | custom_basename_skip (va_list *va) |
868 | { |
869 | (void) va_arg (*va, GFile *)__builtin_va_arg(*va, GFile *); |
870 | } |
871 | |
872 | |
873 | static char * |
874 | custom_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 | |
886 | static void |
887 | custom_size_skip (va_list *va) |
888 | { |
889 | (void) va_arg (*va, goffset)__builtin_va_arg(*va, goffset); |
890 | } |
891 | |
892 | static char * |
893 | custom_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 | |
901 | static void |
902 | custom_time_skip (va_list *va) |
903 | { |
904 | (void) va_arg (*va, int)__builtin_va_arg(*va, int); |
905 | } |
906 | |
907 | static char * |
908 | custom_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 | |
916 | static void |
917 | custom_mount_skip (va_list *va) |
918 | { |
919 | (void) va_arg (*va, GMount *)__builtin_va_arg(*va, GMount *); |
920 | } |
921 | |
922 | |
923 | static 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 | |
933 | static char * |
934 | f (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 | |
947 | static gpointer |
948 | init_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 | |
983 | static void |
984 | finalize_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 | |
1010 | static void |
1011 | skip_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 | |
1022 | static void |
1023 | skip_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 | |
1034 | static gboolean |
1035 | should_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 | |
1045 | static gboolean |
1046 | should_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 | |
1055 | static gboolean |
1056 | can_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 | |
1066 | static gboolean |
1067 | can_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 | |
1082 | typedef 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 | |
1095 | static gboolean |
1096 | do_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 | |
1159 | static int |
1160 | run_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 */ |
1212 | static int |
1213 | run_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 | |
1237 | static int |
1238 | run_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 | |
1261 | static int |
1262 | run_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 | |
1285 | static int |
1286 | run_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 | |
1309 | static void |
1310 | inhibit_power_manager (CommonJob *job, const char *message) |
1311 | { |
1312 | job->inhibit_cookie = baul_inhibit_power_manager (message); |
1313 | } |
1314 | |
1315 | static void |
1316 | abort_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 */ |
1323 | static gboolean |
1324 | should_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 | |
1335 | static gboolean |
1336 | should_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 | |
1347 | static gboolean |
1348 | job_aborted (CommonJob *job) |
1349 | { |
1350 | return g_cancellable_is_cancelled (job->cancellable); |
1351 | } |
1352 | |
1353 | static gboolean |
1354 | confirm_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 | |
1392 | static gboolean |
1393 | confirm_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 | |
1416 | static gboolean |
1417 | confirm_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 | |
1458 | static gboolean |
1459 | confirm_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 | |
1500 | static void |
1501 | report_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 | |
1565 | static void delete_file (CommonJob *job, GFile *file, |
1566 | gboolean *skipped_file, |
1567 | SourceInfo *source_info, |
1568 | TransferInfo *transfer_info, |
1569 | gboolean toplevel); |
1570 | |
1571 | static void |
1572 | delete_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 | |
1725 | static void |
1726 | delete_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 | |
1792 | static void |
1793 | delete_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 | |
1834 | static void |
1835 | report_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 | |
1859 | static void |
1860 | trash_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 | |
1956 | static gboolean |
1957 | delete_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 | |
1980 | static gboolean |
1981 | delete_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 | |
2071 | static void |
2072 | trash_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 | |
2111 | void |
2112 | baul_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 | |
2122 | void |
2123 | baul_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 | |
2135 | typedef struct { |
2136 | gboolean eject; |
2137 | GMount *mount; |
2138 | CtkWindow *parent_window; |
2139 | BaulUnmountCallback callback; |
2140 | gpointer callback_data; |
2141 | } UnmountData; |
2142 | |
2143 | static void |
2144 | unmount_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 | |
2194 | static void |
2195 | do_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 | |
2221 | static gboolean |
2222 | dir_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 | |
2250 | static GList * |
2251 | get_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 | |
2291 | static gboolean |
2292 | has_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 | |
2317 | static gint |
2318 | prompt_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 | |
2369 | void |
2370 | baul_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 | |
2423 | void |
2424 | baul_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 | |
2433 | static void |
2434 | mount_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 | |
2444 | static void |
2445 | volume_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 | |
2492 | void |
2493 | baul_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 | |
2501 | void |
2502 | baul_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 | |
2531 | static void |
2532 | report_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 | |
2569 | static void |
2570 | count_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 | |
2583 | static char * |
2584 | get_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 | |
2599 | static void |
2600 | scan_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 | |
2723 | static void |
2724 | scan_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 | |
2811 | static void |
2812 | scan_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 | |
2837 | static void |
2838 | verify_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, |
Value stored to 'response' is never read | |
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 | |
2994 | static void |
2995 | report_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 | |
3125 | static int |
3126 | get_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 | |
3166 | static gboolean |
3167 | str_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 | |
3185 | static gboolean |
3186 | make_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 | |
3215 | static GFile * |
3216 | get_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 | |
3279 | static GFile * |
3280 | get_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 | |
3341 | static GFile * |
3342 | get_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 | |
3384 | static gboolean |
3385 | has_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 | |
3411 | static gboolean |
3412 | is_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 | |
3430 | static 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 | |
3445 | typedef enum { |
3446 | CREATE_DEST_DIR_RETRY, |
3447 | CREATE_DEST_DIR_FAILED, |
3448 | CREATE_DEST_DIR_SUCCESS |
3449 | } CreateDestDirResult; |
3450 | |
3451 | static CreateDestDirResult |
3452 | create_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 | */ |
3545 | static gboolean |
3546 | copy_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 | |
3771 | static gboolean |
3772 | remove_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 | |
3898 | typedef struct { |
3899 | CopyMoveJob *job; |
3900 | goffset last_size; |
3901 | SourceInfo *source_info; |
3902 | TransferInfo *transfer_info; |
3903 | } ProgressData; |
3904 | |
3905 | static void |
3906 | copy_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 | |
3926 | static gboolean |
3927 | test_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 | |
3945 | static char * |
3946 | query_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 | |
3973 | static gboolean |
3974 | is_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 | |
4019 | typedef struct { |
4020 | int id; |
4021 | char *new_name; |
4022 | gboolean apply_to_all; |
4023 | } ConflictResponseData; |
4024 | |
4025 | typedef struct { |
4026 | GFile *src; |
4027 | GFile *dest; |
4028 | GFile *dest_dir; |
4029 | CtkWindow *parent; |
4030 | ConflictResponseData *resp_data; |
4031 | } ConflictDialogData; |
4032 | |
4033 | static gboolean |
4034 | do_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 | |
4063 | static ConflictResponseData * |
4064 | run_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 | |
4098 | static void |
4099 | conflict_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 | |
4105 | static GFile * |
4106 | get_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 */ |
4122 | static void |
4123 | copy_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 | |
4539 | static void |
4540 | copy_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 | |
4624 | static gboolean |
4625 | copy_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 | |
4650 | static gboolean |
4651 | copy_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 | |
4715 | static gboolean |
4716 | contains_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 | |
4733 | void |
4734 | baul_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 | |
4777 | static void |
4778 | report_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 | |
4796 | typedef struct { |
4797 | GFile *file; |
4798 | gboolean overwrite; |
4799 | gboolean has_position; |
4800 | CdkPoint position; |
4801 | } MoveFileCopyFallback; |
4802 | |
4803 | static MoveFileCopyFallback * |
4804 | move_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 | |
4823 | static GList * |
4824 | get_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 | |
4837 | static void |
4838 | move_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 | |
5058 | static void |
5059 | move_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 | |
5118 | static void |
5119 | move_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 | |
5173 | static gboolean |
5174 | move_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 | |
5194 | static gboolean |
5195 | move_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 | |
5276 | void |
5277 | baul_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 | |
5324 | static void |
5325 | report_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 | |
5343 | static char * |
5344 | get_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 | |
5367 | static void |
5368 | link_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 | |
5507 | static gboolean |
5508 | link_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 | |
5528 | static gboolean |
5529 | link_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 | |
5596 | void |
5597 | baul_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 | |
5638 | void |
5639 | baul_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 | |
5678 | static gboolean |
5679 | set_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 | |
5695 | static void |
5696 | set_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 | |
5781 | static gboolean |
5782 | set_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 | |
5809 | void |
5810 | baul_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); |
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 | |
5845 | static GList * |
5846 | location_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 | |
5861 | typedef struct { |
5862 | BaulCopyCallback real_callback; |
5863 | gpointer real_data; |
5864 | } MoveTrashCBData; |
5865 | |
5866 | static void |
5867 | callback_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 | |
5876 | void |
5877 | baul_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 | |
5977 | static gboolean |
5978 | create_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 | |
6003 | static gboolean |
6004 | create_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 | |
6275 | void |
6276 | baul_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 | |
6313 | void |
6314 | baul_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 | |
6357 | void |
6358 | baul_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 | |
6402 | static void |
6403 | delete_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 | |
6446 | static gboolean |
6447 | empty_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 | |
6465 | static gboolean |
6466 | empty_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 | |
6501 | void |
6502 | baul_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 | |
6526 | static gboolean |
6527 | mark_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 | |
6543 | static void |
6544 | mark_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 | |
6703 | static gboolean |
6704 | mark_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 | |
6729 | void |
6730 | baul_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 | |
6753 | void |
6754 | baul_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 |