nautilus-3.6.3/libnautilus-private/nautilus-file-operations.c

Location Tool Test ID Function Issue
nautilus-file-operations.c:5223:32 clang-analyzer Access to field 'data' results in a dereference of a null pointer (loaded from variable 'files')*
nautilus-file-operations.c:5547:32 clang-analyzer Access to field 'data' results in a dereference of a null pointer (loaded from variable 'files')
nautilus-file-operations.c:5848:32 clang-analyzer Access to field 'data' results in a dereference of a null pointer (loaded from variable 'locations')*
   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*- */
   2 
   3 /* nautilus-file-operations.c - Nautilus 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., 59 Temple Place - Suite 330,
  22    Boston, MA 02111-1307, 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 
  39 #include "nautilus-file-operations.h"
  40 
  41 #include "nautilus-file-changes-queue.h"
  42 #include "nautilus-lib-self-check-functions.h"
  43 
  44 #include "nautilus-progress-info.h"
  45 
  46 #include <eel/eel-glib-extensions.h>
  47 #include <eel/eel-gtk-extensions.h>
  48 #include <eel/eel-stock-dialogs.h>
  49 #include <eel/eel-vfs-extensions.h>
  50 
  51 #include <glib/gi18n.h>
  52 #include <glib/gstdio.h>
  53 #include <gdk/gdk.h>
  54 #include <gtk/gtk.h>
  55 #include <gio/gio.h>
  56 #include <glib.h>
  57 #include "nautilus-file-changes-queue.h"
  58 #include "nautilus-file-private.h"
  59 #include "nautilus-desktop-icon-file.h"
  60 #include "nautilus-desktop-link-monitor.h"
  61 #include "nautilus-global-preferences.h"
  62 #include "nautilus-link.h"
  63 #include "nautilus-trash-monitor.h"
  64 #include "nautilus-file-utilities.h"
  65 #include "nautilus-file-conflict-dialog.h"
  66 #include "nautilus-file-undo-operations.h"
  67 #include "nautilus-file-undo-manager.h"
  68 
  69 /* TODO: TESTING!!! */
  70 
  71 typedef struct {
  72 	GIOSchedulerJob *io_job;	
  73 	GTimer *time;
  74 	GtkWindow *parent_window;
  75 	int screen_num;
  76 	int inhibit_cookie;
  77 	NautilusProgressInfo *progress;
  78 	GCancellable *cancellable;
  79 	GHashTable *skip_files;
  80 	GHashTable *skip_readdir_error;
  81 	NautilusFileUndoInfo *undo_info;
  82 	gboolean skip_all_error;
  83 	gboolean skip_all_conflict;
  84 	gboolean merge_all;
  85 	gboolean replace_all;
  86 	gboolean delete_all;
  87 } CommonJob;
  88 
  89 typedef struct {
  90 	CommonJob common;
  91 	gboolean is_move;
  92 	GList *files;
  93 	GFile *destination;
  94 	GFile *desktop_location;
  95 	GFile *fake_display_source;
  96 	GdkPoint *icon_positions;
  97 	int n_icon_positions;
  98 	GHashTable *debuting_files;
  99 	gchar *target_name;
 100 	NautilusCopyCallback  done_callback;
 101 	gpointer done_callback_data;
 102 } CopyMoveJob;
 103 
 104 typedef struct {
 105 	CommonJob common;
 106 	GList *files;
 107 	gboolean try_trash;
 108 	gboolean user_cancel;
 109 	NautilusDeleteCallback done_callback;
 110 	gpointer done_callback_data;
 111 } DeleteJob;
 112 
 113 typedef struct {
 114 	CommonJob common;
 115 	GFile *dest_dir;
 116 	char *filename;
 117 	gboolean make_dir;
 118 	GFile *src;
 119 	char *src_data;
 120 	int length;
 121 	GdkPoint position;
 122 	gboolean has_position;
 123 	GFile *created_file;
 124 	NautilusCreateCallback done_callback;
 125 	gpointer done_callback_data;
 126 } CreateJob;
 127 
 128 
 129 typedef struct {
 130 	CommonJob common;
 131 	GList *trash_dirs;
 132 	gboolean should_confirm;
 133 	NautilusOpCallback done_callback;
 134 	gpointer done_callback_data;
 135 } EmptyTrashJob;
 136 
 137 typedef struct {
 138 	CommonJob common;
 139 	GFile *file;
 140 	gboolean interactive;
 141 	NautilusOpCallback done_callback;
 142 	gpointer done_callback_data;
 143 } MarkTrustedJob;
 144 
 145 typedef struct {
 146 	CommonJob common;
 147 	GFile *file;
 148 	NautilusOpCallback done_callback;
 149 	gpointer done_callback_data;
 150 	guint32 file_permissions;
 151 	guint32 file_mask;
 152 	guint32 dir_permissions;
 153 	guint32 dir_mask;
 154 } SetPermissionsJob;
 155 
 156 typedef enum {
 157 	OP_KIND_COPY,
 158 	OP_KIND_MOVE,
 159 	OP_KIND_DELETE,
 160 	OP_KIND_TRASH
 161 } OpKind;
 162 
 163 typedef struct {
 164 	int num_files;
 165 	goffset num_bytes;
 166 	int num_files_since_progress;
 167 	OpKind op;
 168 } SourceInfo;
 169 
 170 typedef struct {
 171 	int num_files;
 172 	goffset num_bytes;
 173 	OpKind op;
 174 	guint64 last_report_time;
 175 	int last_reported_files_left;
 176 } TransferInfo;
 177 
 178 #define SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE 15
 179 #define NSEC_PER_MICROSEC 1000
 180 
 181 #define MAXIMUM_DISPLAYED_FILE_NAME_LENGTH 50
 182 
 183 #define IS_IO_ERROR(__error, KIND) (((__error)->domain == G_IO_ERROR && (__error)->code == G_IO_ERROR_ ## KIND))
 184 
 185 #define SKIP _("_Skip")
 186 #define SKIP_ALL _("S_kip All")
 187 #define RETRY _("_Retry")
 188 #define DELETE_ALL _("Delete _All")
 189 #define REPLACE _("_Replace")
 190 #define REPLACE_ALL _("Replace _All")
 191 #define MERGE _("_Merge")
 192 #define MERGE_ALL _("Merge _All")
 193 #define COPY_FORCE _("Copy _Anyway")
 194 
 195 static void
 196 mark_desktop_file_trusted (CommonJob *common,
 197 			   GCancellable *cancellable,
 198 			   GFile *file,
 199 			   gboolean interactive);
 200 
 201 static gboolean
 202 is_all_button_text (const char *button_text)
 203 {
 204 	g_assert (button_text != NULL);
 205 
 206 	return !strcmp (button_text, SKIP_ALL) ||
 207 	       !strcmp (button_text, REPLACE_ALL) ||
 208 	       !strcmp (button_text, DELETE_ALL) ||
 209 	       !strcmp (button_text, MERGE_ALL);
 210 }
 211 
 212 static void scan_sources (GList *files,
 213 			  SourceInfo *source_info,
 214 			  CommonJob *job,
 215 			  OpKind kind);
 216 
 217 
 218 static gboolean empty_trash_job (GIOSchedulerJob *io_job,
 219 				 GCancellable *cancellable,
 220 				 gpointer user_data);
 221 
 222 static char * query_fs_type (GFile *file,
 223 			     GCancellable *cancellable);
 224 
 225 /* keep in time with format_time()
 226  *
 227  * This counts and outputs the number of “time units”
 228  * formatted and displayed by format_time().
 229  * For instance, if format_time outputs “3 hours, 4 minutes”
 230  * it yields 7.
 231  */
 232 static int
 233 seconds_count_format_time_units (int seconds)
 234 {
 235 	int minutes;
 236 	int hours;
 237 
 238 	if (seconds < 0) {
 239 		/* Just to make sure... */
 240 		seconds = 0;
 241 	}
 242 
 243 	if (seconds < 60) {
 244 		/* seconds */
 245 		return seconds;
 246 	}
 247 
 248 	if (seconds < 60*60) {
 249 		/* minutes */
 250 		minutes = seconds / 60;
 251 		return minutes;
 252 	}
 253 
 254 	hours = seconds / (60*60);
 255 
 256 	if (seconds < 60*60*4) {
 257 		/* minutes + hours */
 258 		minutes = (seconds - hours * 60 * 60) / 60;
 259 		return minutes + hours;
 260 	}
 261 
 262 	return hours;
 263 }
 264 
 265 static char *
 266 format_time (int seconds)
 267 {
 268 	int minutes;
 269 	int hours;
 270 	char *res;
 271 
 272 	if (seconds < 0) {
 273 		/* Just to make sure... */
 274 		seconds = 0;
 275 	}
 276 	
 277 	if (seconds < 60) {
 278 		return g_strdup_printf (ngettext ("%'d second","%'d seconds", (int) seconds), (int) seconds);
 279 	}
 280 
 281 	if (seconds < 60*60) {
 282 		minutes = seconds / 60;
 283 		return g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes);
 284 	}
 285 
 286 	hours = seconds / (60*60);
 287 	
 288 	if (seconds < 60*60*4) {
 289 		char *h, *m;
 290 
 291 		minutes = (seconds - hours * 60 * 60) / 60;
 292 		
 293 		h = g_strdup_printf (ngettext ("%'d hour", "%'d hours", hours), hours);
 294 		m = g_strdup_printf (ngettext ("%'d minute", "%'d minutes", minutes), minutes);
 295 		res = g_strconcat (h, ", ", m, NULL);
 296 		g_free (h);
 297 		g_free (m);
 298 		return res;
 299 	}
 300 	
 301 	return g_strdup_printf (ngettext ("approximately %'d hour",
 302 					  "approximately %'d hours",
 303 					  hours), hours);
 304 }
 305 
 306 static char *
 307 shorten_utf8_string (const char *base, int reduce_by_num_bytes)
 308 {
 309 	int len;
 310 	char *ret;
 311 	const char *p;
 312 	
 313 	len = strlen (base);
 314 	len -= reduce_by_num_bytes;
 315 	
 316 	if (len <= 0) {
 317 		return NULL;
 318 	}
 319 
 320 	ret = g_new (char, len + 1);
 321 
 322 	p = base;
 323 	while (len) {
 324 		char *next;
 325 		next = g_utf8_next_char (p);
 326 		if (next - p > len || *next == '\0') {
 327 			break;
 328 		}
 329 		
 330 		len -= next - p;
 331 		p = next;
 332 	}
 333 	
 334 	if (p - base == 0) {
 335 		g_free (ret);
 336 		return NULL;
 337 	} else {
 338 		memcpy (ret, base, p - base);
 339 		ret[p - base] = '\0';
 340 		return ret;
 341 	}
 342 }
 343 
 344 /* Note that we have these two separate functions with separate format
 345  * strings for ease of localization.
 346  */
 347 
 348 static char *
 349 get_link_name (const char *name, int count, int max_length)
 350 {
 351 	const char *format;
 352 	char *result;
 353 	int unshortened_length;
 354 	gboolean use_count;
 355 	
 356 	g_assert (name != NULL);
 357 
 358 	if (count < 0) {
 359 		g_warning ("bad count in get_link_name");
 360 		count = 0;
 361 	}
 362 
 363 	if (count <= 2) {
 364 		/* Handle special cases for low numbers.
 365 		 * Perhaps for some locales we will need to add more.
 366 		 */
 367 		switch (count) {
 368 		default:
 369 			g_assert_not_reached ();
 370 			/* fall through */
 371 		case 0:
 372 			/* duplicate original file name */
 373 			format = "%s";
 374 			break;
 375 		case 1:
 376 			/* appended to new link file */
 377 			format = _("Link to %s");
 378 			break;
 379 		case 2:
 380 			/* appended to new link file */
 381 			format = _("Another link to %s");
 382 			break;
 383 		}
 384 
 385 		use_count = FALSE;
 386 	} else {
 387 		/* Handle special cases for the first few numbers of each ten.
 388 		 * For locales where getting this exactly right is difficult,
 389 		 * these can just be made all the same as the general case below.
 390 		 */
 391 		switch (count % 10) {
 392 		case 1:
 393 			/* Localizers: Feel free to leave out the "st" suffix
 394 			 * if there's no way to do that nicely for a
 395 			 * particular language.
 396 			 */
 397 			format = _("%'dst link to %s");
 398 			break;
 399 		case 2:
 400 			/* appended to new link file */
 401 			format = _("%'dnd link to %s");
 402 			break;
 403 		case 3:
 404 			/* appended to new link file */
 405 			format = _("%'drd link to %s");
 406 			break;
 407 		default:
 408 			/* appended to new link file */
 409 			format = _("%'dth link to %s");
 410 			break;
 411 		}
 412 
 413 		use_count = TRUE;
 414 	}
 415 
 416 	if (use_count)
 417 		result = g_strdup_printf (format, count, name);
 418 	else
 419 		result = g_strdup_printf (format, name);
 420 
 421 	if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) {
 422 		char *new_name;
 423 
 424 		new_name = shorten_utf8_string (name, unshortened_length - max_length);
 425 		if (new_name) {
 426 			g_free (result);
 427 
 428 			if (use_count)
 429 				result = g_strdup_printf (format, count, new_name);
 430 			else
 431 				result = g_strdup_printf (format, new_name);
 432 
 433 			g_assert (strlen (result) <= max_length);
 434 			g_free (new_name);
 435 		}
 436 	}
 437 
 438 	return result;
 439 }
 440 
 441 
 442 /* Localizers: 
 443  * Feel free to leave out the st, nd, rd and th suffix or
 444  * make some or all of them match.
 445  */
 446 
 447 /* localizers: tag used to detect the first copy of a file */
 448 static const char untranslated_copy_duplicate_tag[] = N_(" (copy)");
 449 /* localizers: tag used to detect the second copy of a file */
 450 static const char untranslated_another_copy_duplicate_tag[] = N_(" (another copy)");
 451 
 452 /* localizers: tag used to detect the x11th copy of a file */
 453 static const char untranslated_x11th_copy_duplicate_tag[] = N_("th copy)");
 454 /* localizers: tag used to detect the x12th copy of a file */
 455 static const char untranslated_x12th_copy_duplicate_tag[] = N_("th copy)");
 456 /* localizers: tag used to detect the x13th copy of a file */
 457 static const char untranslated_x13th_copy_duplicate_tag[] = N_("th copy)");
 458 
 459 /* localizers: tag used to detect the x1st copy of a file */
 460 static const char untranslated_st_copy_duplicate_tag[] = N_("st copy)");
 461 /* localizers: tag used to detect the x2nd copy of a file */
 462 static const char untranslated_nd_copy_duplicate_tag[] = N_("nd copy)");
 463 /* localizers: tag used to detect the x3rd copy of a file */
 464 static const char untranslated_rd_copy_duplicate_tag[] = N_("rd copy)");
 465 
 466 /* localizers: tag used to detect the xxth copy of a file */
 467 static const char untranslated_th_copy_duplicate_tag[] = N_("th copy)");
 468 
 469 #define COPY_DUPLICATE_TAG _(untranslated_copy_duplicate_tag)
 470 #define ANOTHER_COPY_DUPLICATE_TAG _(untranslated_another_copy_duplicate_tag)
 471 #define X11TH_COPY_DUPLICATE_TAG _(untranslated_x11th_copy_duplicate_tag)
 472 #define X12TH_COPY_DUPLICATE_TAG _(untranslated_x12th_copy_duplicate_tag)
 473 #define X13TH_COPY_DUPLICATE_TAG _(untranslated_x13th_copy_duplicate_tag)
 474 
 475 #define ST_COPY_DUPLICATE_TAG _(untranslated_st_copy_duplicate_tag)
 476 #define ND_COPY_DUPLICATE_TAG _(untranslated_nd_copy_duplicate_tag)
 477 #define RD_COPY_DUPLICATE_TAG _(untranslated_rd_copy_duplicate_tag)
 478 #define TH_COPY_DUPLICATE_TAG _(untranslated_th_copy_duplicate_tag)
 479 
 480 /* localizers: appended to first file copy */
 481 static const char untranslated_first_copy_duplicate_format[] = N_("%s (copy)%s");
 482 /* localizers: appended to second file copy */
 483 static const char untranslated_second_copy_duplicate_format[] = N_("%s (another copy)%s");
 484 
 485 /* localizers: appended to x11th file copy */
 486 static const char untranslated_x11th_copy_duplicate_format[] = N_("%s (%'dth copy)%s");
 487 /* localizers: appended to x12th file copy */
 488 static const char untranslated_x12th_copy_duplicate_format[] = N_("%s (%'dth copy)%s");
 489 /* localizers: appended to x13th file copy */
 490 static const char untranslated_x13th_copy_duplicate_format[] = N_("%s (%'dth copy)%s");
 491 
 492 /* localizers: if in your language there's no difference between 1st, 2nd, 3rd and nth
 493  * plurals, you can leave the st, nd, rd suffixes out and just make all the translated
 494  * strings look like "%s (copy %'d)%s".
 495  */
 496 
 497 /* localizers: appended to x1st file copy */
 498 static const char untranslated_st_copy_duplicate_format[] = N_("%s (%'dst copy)%s");
 499 /* localizers: appended to x2nd file copy */
 500 static const char untranslated_nd_copy_duplicate_format[] = N_("%s (%'dnd copy)%s");
 501 /* localizers: appended to x3rd file copy */
 502 static const char untranslated_rd_copy_duplicate_format[] = N_("%s (%'drd copy)%s");
 503 /* localizers: appended to xxth file copy */
 504 static const char untranslated_th_copy_duplicate_format[] = N_("%s (%'dth copy)%s");
 505 
 506 #define FIRST_COPY_DUPLICATE_FORMAT _(untranslated_first_copy_duplicate_format)
 507 #define SECOND_COPY_DUPLICATE_FORMAT _(untranslated_second_copy_duplicate_format)
 508 #define X11TH_COPY_DUPLICATE_FORMAT _(untranslated_x11th_copy_duplicate_format)
 509 #define X12TH_COPY_DUPLICATE_FORMAT _(untranslated_x12th_copy_duplicate_format)
 510 #define X13TH_COPY_DUPLICATE_FORMAT _(untranslated_x13th_copy_duplicate_format)
 511 
 512 #define ST_COPY_DUPLICATE_FORMAT _(untranslated_st_copy_duplicate_format)
 513 #define ND_COPY_DUPLICATE_FORMAT _(untranslated_nd_copy_duplicate_format)
 514 #define RD_COPY_DUPLICATE_FORMAT _(untranslated_rd_copy_duplicate_format)
 515 #define TH_COPY_DUPLICATE_FORMAT _(untranslated_th_copy_duplicate_format)
 516 
 517 static char *
 518 extract_string_until (const char *original, const char *until_substring)
 519 {
 520 	char *result;
 521 	
 522 	g_assert ((int) strlen (original) >= until_substring - original);
 523 	g_assert (until_substring - original >= 0);
 524 
 525 	result = g_malloc (until_substring - original + 1);
 526 	strncpy (result, original, until_substring - original);
 527 	result[until_substring - original] = '\0';
 528 	
 529 	return result;
 530 }
 531 
 532 /* Dismantle a file name, separating the base name, the file suffix and removing any
 533  * (xxxcopy), etc. string. Figure out the count that corresponds to the given
 534  * (xxxcopy) substring.
 535  */
 536 static void
 537 parse_previous_duplicate_name (const char *name,
 538 			       char **name_base,
 539 			       const char **suffix,
 540 			       int *count)
 541 {
 542 	const char *tag;
 543 
 544 	g_assert (name[0] != '\0');
 545 
 546 	*suffix = eel_filename_get_extension_offset (name);
 547 
 548 	if (*suffix == NULL || (*suffix)[1] == '\0') {
 549 		/* no suffix */
 550 		*suffix = "";
 551 	}
 552 
 553 	tag = strstr (name, COPY_DUPLICATE_TAG);
 554 	if (tag != NULL) {
 555 		if (tag > *suffix) {
 556 			/* handle case "foo. (copy)" */
 557 			*suffix = "";
 558 		}
 559 		*name_base = extract_string_until (name, tag);
 560 		*count = 1;
 561 		return;
 562 	}
 563 
 564 
 565 	tag = strstr (name, ANOTHER_COPY_DUPLICATE_TAG);
 566 	if (tag != NULL) {
 567 		if (tag > *suffix) {
 568 			/* handle case "foo. (another copy)" */
 569 			*suffix = "";
 570 		}
 571 		*name_base = extract_string_until (name, tag);
 572 		*count = 2;
 573 		return;
 574 	}
 575 
 576 
 577 	/* Check to see if we got one of st, nd, rd, th. */
 578 	tag = strstr (name, X11TH_COPY_DUPLICATE_TAG);
 579 
 580 	if (tag == NULL) {
 581 		tag = strstr (name, X12TH_COPY_DUPLICATE_TAG);
 582 	}
 583 	if (tag == NULL) {
 584 		tag = strstr (name, X13TH_COPY_DUPLICATE_TAG);
 585 	}
 586 
 587 	if (tag == NULL) {
 588 		tag = strstr (name, ST_COPY_DUPLICATE_TAG);
 589 	}
 590 	if (tag == NULL) {
 591 		tag = strstr (name, ND_COPY_DUPLICATE_TAG);
 592 	}
 593 	if (tag == NULL) {
 594 		tag = strstr (name, RD_COPY_DUPLICATE_TAG);
 595 	}
 596 	if (tag == NULL) {
 597 		tag = strstr (name, TH_COPY_DUPLICATE_TAG);
 598 	}
 599 
 600 	/* If we got one of st, nd, rd, th, fish out the duplicate number. */
 601 	if (tag != NULL) {
 602 		/* localizers: opening parentheses to match the "th copy)" string */
 603 		tag = strstr (name, _(" ("));
 604 		if (tag != NULL) {
 605 			if (tag > *suffix) {
 606 				/* handle case "foo. (22nd copy)" */
 607 				*suffix = "";
 608 			}
 609 			*name_base = extract_string_until (name, tag);
 610 			/* localizers: opening parentheses of the "th copy)" string */
 611 			if (sscanf (tag, _(" (%'d"), count) == 1) {
 612 				if (*count < 1 || *count > 1000000) {
 613 					/* keep the count within a reasonable range */
 614 					*count = 0;
 615 				}
 616 				return;
 617 			}
 618 			*count = 0;
 619 			return;
 620 		}
 621 	}
 622 
 623 	
 624 	*count = 0;
 625 	if (**suffix != '\0') {
 626 		*name_base = extract_string_until (name, *suffix);
 627 	} else {
 628 		*name_base = g_strdup (name);
 629 	}
 630 }
 631 
 632 static char *
 633 make_next_duplicate_name (const char *base, const char *suffix, int count, int max_length)
 634 {
 635 	const char *format;
 636 	char *result;
 637 	int unshortened_length;
 638 	gboolean use_count;
 639 
 640 	if (count < 1) {
 641 		g_warning ("bad count %d in get_duplicate_name", count);
 642 		count = 1;
 643 	}
 644 
 645 	if (count <= 2) {
 646 
 647 		/* Handle special cases for low numbers.
 648 		 * Perhaps for some locales we will need to add more.
 649 		 */
 650 		switch (count) {
 651 		default:
 652 			g_assert_not_reached ();
 653 			/* fall through */
 654 		case 1:
 655 			format = FIRST_COPY_DUPLICATE_FORMAT;
 656 			break;
 657 		case 2:
 658 			format = SECOND_COPY_DUPLICATE_FORMAT;
 659 			break;
 660 
 661 		}
 662 
 663 		use_count = FALSE;
 664 	} else {
 665 
 666 		/* Handle special cases for the first few numbers of each ten.
 667 		 * For locales where getting this exactly right is difficult,
 668 		 * these can just be made all the same as the general case below.
 669 		 */
 670 
 671 		/* Handle special cases for x11th - x20th.
 672 		 */
 673 		switch (count % 100) {
 674 		case 11:
 675 			format = X11TH_COPY_DUPLICATE_FORMAT;
 676 			break;
 677 		case 12:
 678 			format = X12TH_COPY_DUPLICATE_FORMAT;
 679 			break;
 680 		case 13:
 681 			format = X13TH_COPY_DUPLICATE_FORMAT;
 682 			break;
 683 		default:
 684 			format = NULL;
 685 			break;
 686 		}
 687 
 688 		if (format == NULL) {
 689 			switch (count % 10) {
 690 			case 1:
 691 				format = ST_COPY_DUPLICATE_FORMAT;
 692 				break;
 693 			case 2:
 694 				format = ND_COPY_DUPLICATE_FORMAT;
 695 				break;
 696 			case 3:
 697 				format = RD_COPY_DUPLICATE_FORMAT;
 698 				break;
 699 			default:
 700 				/* The general case. */
 701 				format = TH_COPY_DUPLICATE_FORMAT;
 702 				break;
 703 			}
 704 		}
 705 
 706 		use_count = TRUE;
 707 
 708 	}
 709 
 710 	if (use_count)
 711 		result = g_strdup_printf (format, base, count, suffix);
 712 	else
 713 		result = g_strdup_printf (format, base, suffix);
 714 
 715 	if (max_length > 0 && (unshortened_length = strlen (result)) > max_length) {
 716 		char *new_base;
 717 
 718 		new_base = shorten_utf8_string (base, unshortened_length - max_length);
 719 		if (new_base) {
 720 			g_free (result);
 721 
 722 			if (use_count)
 723 				result = g_strdup_printf (format, new_base, count, suffix);
 724 			else
 725 				result = g_strdup_printf (format, new_base, suffix);
 726 
 727 			g_assert (strlen (result) <= max_length);
 728 			g_free (new_base);
 729 		}
 730 	}
 731 
 732 	return result;
 733 }
 734 
 735 static char *
 736 get_duplicate_name (const char *name, int count_increment, int max_length)
 737 {
 738 	char *result;
 739 	char *name_base;
 740 	const char *suffix;
 741 	int count;
 742 
 743 	parse_previous_duplicate_name (name, &name_base, &suffix, &count);
 744 	result = make_next_duplicate_name (name_base, suffix, count + count_increment, max_length);
 745 
 746 	g_free (name_base);
 747 
 748 	return result;
 749 }
 750 
 751 static gboolean
 752 has_invalid_xml_char (char *str)
 753 {
 754 	gunichar c;
 755 
 756 	while (*str != 0) {
 757 		c = g_utf8_get_char (str);
 758 		/* characters XML permits */
 759 		if (!(c == 0x9 ||
 760 		      c == 0xA ||
 761 		      c == 0xD ||
 762 		      (c >= 0x20 && c <= 0xD7FF) ||
 763 		      (c >= 0xE000 && c <= 0xFFFD) ||
 764 		      (c >= 0x10000 && c <= 0x10FFFF))) {
 765 			return TRUE;
 766 		}
 767 		str = g_utf8_next_char (str);
 768 	}
 769 	return FALSE;
 770 }
 771 
 772 
 773 static char *
 774 custom_full_name_to_string (char *format, va_list va)
 775 {
 776 	GFile *file;
 777 	
 778 	file = va_arg (va, GFile *);
 779 	
 780 	return g_file_get_parse_name (file);
 781 }
 782 
 783 static void
 784 custom_full_name_skip (va_list *va)
 785 {
 786 	(void) va_arg (*va, GFile *);
 787 }
 788 
 789 static char *
 790 custom_basename_to_string (char *format, va_list va)
 791 {
 792 	GFile *file;
 793 	GFileInfo *info;
 794 	char *name, *basename, *tmp;
 795 
 796 	file = va_arg (va, GFile *);
 797 
 798 	info = g_file_query_info (file,
 799 				  G_FILE_ATTRIBUTE_STANDARD_DISPLAY_NAME,
 800 				  0,
 801 				  g_cancellable_get_current (),
 802 				  NULL);
 803 	
 804 	name = NULL;
 805 	if (info) {
 806 		name = g_strdup (g_file_info_get_display_name (info));
 807 		g_object_unref (info);
 808 	}
 809 	
 810 	if (name == NULL) {
 811 		basename = g_file_get_basename (file);
 812 		if (g_utf8_validate (basename, -1, NULL)) {
 813 			name = basename;
 814 		} else {
 815 			name = g_uri_escape_string (basename, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
 816 			g_free (basename);
 817 		}
 818 	}
 819 
 820 	/* Some chars can't be put in the markup we use for the dialogs... */
 821 	if (has_invalid_xml_char (name)) {
 822 		tmp = name;
 823 		name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
 824 		g_free (tmp);
 825 	}
 826 
 827 	/* Finally, if the string is too long, truncate it. */
 828 	if (name != NULL) {
 829 		tmp = name;
 830 		name = eel_str_middle_truncate (tmp, MAXIMUM_DISPLAYED_FILE_NAME_LENGTH);
 831 		g_free (tmp);
 832 	}
 833 
 834 	
 835 	return name;
 836 }
 837 
 838 static void
 839 custom_basename_skip (va_list *va)
 840 {
 841 	(void) va_arg (*va, GFile *);
 842 }
 843 
 844 
 845 static char *
 846 custom_size_to_string (char *format, va_list va)
 847 {
 848 	goffset size;
 849 
 850 	size = va_arg (va, goffset);
 851 	return g_format_size (size);
 852 }
 853 
 854 static void
 855 custom_size_skip (va_list *va)
 856 {
 857 	(void) va_arg (*va, goffset);
 858 }
 859 
 860 static char *
 861 custom_time_to_string (char *format, va_list va)
 862 {
 863 	int secs;
 864 
 865 	secs = va_arg (va, int);
 866 	return format_time (secs);
 867 }
 868 
 869 static void
 870 custom_time_skip (va_list *va)
 871 {
 872 	(void) va_arg (*va, int);
 873 }
 874 
 875 static char *
 876 custom_mount_to_string (char *format, va_list va)
 877 {
 878 	GMount *mount;
 879 
 880 	mount = va_arg (va, GMount *);
 881 	return g_mount_get_name (mount);
 882 }
 883 
 884 static void
 885 custom_mount_skip (va_list *va)
 886 {
 887 	(void) va_arg (*va, GMount *);
 888 }
 889 
 890 
 891 static EelPrintfHandler handlers[] = {
 892 	{ 'F', custom_full_name_to_string, custom_full_name_skip },
 893 	{ 'B', custom_basename_to_string, custom_basename_skip },
 894 	{ 'S', custom_size_to_string, custom_size_skip },
 895 	{ 'T', custom_time_to_string, custom_time_skip },
 896 	{ 'V', custom_mount_to_string, custom_mount_skip },
 897 	{ 0 }
 898 };
 899 
 900 
 901 static char *
 902 f (const char *format, ...) {
 903 	va_list va;
 904 	char *res;
 905 	
 906 	va_start (va, format);
 907 	res = eel_strdup_vprintf_with_custom (handlers, format, va);
 908 	va_end (va);
 909 
 910 	return res;
 911 }
 912 
 913 #define op_job_new(__type, parent_window) ((__type *)(init_common (sizeof(__type), parent_window)))
 914 
 915 static gpointer
 916 init_common (gsize job_size,
 917 	     GtkWindow *parent_window)
 918 {
 919 	CommonJob *common;
 920 	GdkScreen *screen;
 921 
 922 	common = g_malloc0 (job_size);
 923 
 924 	if (parent_window) {
 925 		common->parent_window = parent_window;
 926 		g_object_add_weak_pointer (G_OBJECT (common->parent_window),
 927 					   (gpointer *) &common->parent_window);
 928 
 929 	}
 930 	common->progress = nautilus_progress_info_new ();
 931 	common->cancellable = nautilus_progress_info_get_cancellable (common->progress);
 932 	common->time = g_timer_new ();
 933 	common->inhibit_cookie = -1;
 934 	common->screen_num = 0;
 935 	if (parent_window) {
 936 		screen = gtk_widget_get_screen (GTK_WIDGET (parent_window));
 937 		common->screen_num = gdk_screen_get_number (screen);
 938 	}
 939 	
 940 	return common;
 941 }
 942 
 943 static void
 944 finalize_common (CommonJob *common)
 945 {
 946 	nautilus_progress_info_finish (common->progress);
 947 
 948 	if (common->inhibit_cookie != -1) {
 949 		gtk_application_uninhibit (GTK_APPLICATION (g_application_get_default ()),
 950 					   common->inhibit_cookie);
 951 	}
 952 
 953 	common->inhibit_cookie = -1;
 954 	g_timer_destroy (common->time);
 955 
 956 	if (common->parent_window) {
 957 		g_object_remove_weak_pointer (G_OBJECT (common->parent_window),
 958 					      (gpointer *) &common->parent_window);
 959 	}
 960 
 961 	if (common->skip_files) {
 962 		g_hash_table_destroy (common->skip_files);
 963 	}
 964 	if (common->skip_readdir_error) {
 965 		g_hash_table_destroy (common->skip_readdir_error);
 966 	}
 967 
 968 	if (common->undo_info != NULL) {
 969 		nautilus_file_undo_manager_set_action (common->undo_info);
 970 		g_object_unref (common->undo_info);
 971 	}
 972 
 973 	g_object_unref (common->progress);
 974 	g_object_unref (common->cancellable);
 975 	g_free (common);
 976 }
 977 
 978 static void
 979 skip_file (CommonJob *common,
 980 	   GFile *file)
 981 {
 982 	if (common->skip_files == NULL) {
 983 		common->skip_files =
 984 			g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
 985 	}
 986 
 987 	g_hash_table_insert (common->skip_files, g_object_ref (file), file);
 988 }
 989 
 990 static void
 991 skip_readdir_error (CommonJob *common,
 992 		    GFile *dir)
 993 {
 994 	if (common->skip_readdir_error == NULL) {
 995 		common->skip_readdir_error =
 996 			g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
 997 	}
 998 
 999 	g_hash_table_insert (common->skip_readdir_error, g_object_ref (dir), dir);
1000 }
1001 
1002 static gboolean
1003 should_skip_file (CommonJob *common,
1004 		  GFile *file)
1005 {
1006 	if (common->skip_files != NULL) {
1007 		return g_hash_table_lookup (common->skip_files, file) != NULL;
1008 	}
1009 	return FALSE;
1010 }
1011 
1012 static gboolean
1013 should_skip_readdir_error (CommonJob *common,
1014 			   GFile *dir)
1015 {
1016 	if (common->skip_readdir_error != NULL) {
1017 		return g_hash_table_lookup (common->skip_readdir_error, dir) != NULL;
1018 	}
1019 	return FALSE;
1020 }
1021 
1022 static gboolean
1023 can_delete_without_confirm (GFile *file)
1024 {
1025 	if (g_file_has_uri_scheme (file, "burn") ||
1026 	    g_file_has_uri_scheme (file, "recent") ||
1027 	    g_file_has_uri_scheme (file, "x-nautilus-desktop")) {
1028 		return TRUE;
1029 	}
1030 
1031 	return FALSE;
1032 }
1033 
1034 static gboolean
1035 can_delete_files_without_confirm (GList *files)
1036 {
1037 	g_assert (files != NULL);
1038 
1039 	while (files != NULL) {
1040 		if (!can_delete_without_confirm (files->data)) {
1041 			return FALSE;
1042 		}
1043 
1044 		files = files->next;
1045 	}
1046 
1047 	return TRUE;
1048 }
1049 
1050 typedef struct {
1051 	GtkWindow **parent_window;
1052 	gboolean ignore_close_box;
1053 	GtkMessageType message_type;
1054 	const char *primary_text;
1055 	const char *secondary_text;
1056 	const char *details_text;
1057 	const char **button_titles;
1058 	gboolean show_all;
1059 	
1060 	int result;
1061 } RunSimpleDialogData;
1062 
1063 static gboolean
1064 do_run_simple_dialog (gpointer _data)
1065 {
1066 	RunSimpleDialogData *data = _data;
1067 	const char *button_title;
1068         GtkWidget *dialog;
1069 	int result;
1070 	int response_id;
1071 
1072 	/* Create the dialog. */
1073 	dialog = gtk_message_dialog_new (*data->parent_window,
1074 					 0,
1075 					 data->message_type,
1076 					 GTK_BUTTONS_NONE,
1077 					 NULL);
1078 
1079 	g_object_set (dialog,
1080 		      "text", data->primary_text,
1081 		      "secondary-text", data->secondary_text,
1082 		      NULL);
1083 
1084 	for (response_id = 0;
1085 	     data->button_titles[response_id] != NULL;
1086 	     response_id++) {
1087 		button_title = data->button_titles[response_id];
1088 		if (!data->show_all && is_all_button_text (button_title)) {
1089 			continue;
1090 		}
1091 
1092 		gtk_dialog_add_button (GTK_DIALOG (dialog), button_title, response_id);
1093 		gtk_dialog_set_default_response (GTK_DIALOG (dialog), response_id);
1094 	}
1095 
1096 	if (data->details_text) {
1097 		eel_gtk_message_dialog_set_details_label (GTK_MESSAGE_DIALOG (dialog),
1098 							  data->details_text);
1099 	}
1100 	
1101 	/* Run it. */
1102         result = gtk_dialog_run (GTK_DIALOG (dialog));
1103 	
1104 	while ((result == GTK_RESPONSE_NONE || result == GTK_RESPONSE_DELETE_EVENT) && data->ignore_close_box) {
1105 		result = gtk_dialog_run (GTK_DIALOG (dialog));
1106 	}
1107 	
1108 	gtk_widget_destroy (dialog);
1109 
1110 	data->result = result;
1111 	
1112 	return FALSE;
1113 }
1114 
1115 /* NOTE: This frees the primary / secondary strings, in order to
1116    avoid doing that everywhere. So, make sure they are strduped */
1117 
1118 static int
1119 run_simple_dialog_va (CommonJob *job,
1120 		      gboolean ignore_close_box,
1121 		      GtkMessageType message_type,
1122 		      char *primary_text,
1123 		      char *secondary_text,
1124 		      const char *details_text,
1125 		      gboolean show_all,
1126 		      va_list varargs)
1127 {
1128 	RunSimpleDialogData *data;
1129 	int res;
1130 	const char *button_title;
1131 	GPtrArray *ptr_array;
1132 
1133 	g_timer_stop (job->time);
1134 	
1135 	data = g_new0 (RunSimpleDialogData, 1);
1136 	data->parent_window = &job->parent_window;
1137 	data->ignore_close_box = ignore_close_box;
1138 	data->message_type = message_type;
1139 	data->primary_text = primary_text;
1140 	data->secondary_text = secondary_text;
1141 	data->details_text = details_text;
1142 	data->show_all = show_all;
1143 
1144 	ptr_array = g_ptr_array_new ();
1145 	while ((button_title = va_arg (varargs, const char *)) != NULL) {
1146 		g_ptr_array_add (ptr_array, (char *)button_title);
1147 	}
1148 	g_ptr_array_add (ptr_array, NULL);
1149 	data->button_titles = (const char **)g_ptr_array_free (ptr_array, FALSE);
1150 
1151 	nautilus_progress_info_pause (job->progress);
1152 	g_io_scheduler_job_send_to_mainloop (job->io_job,
1153 					     do_run_simple_dialog,
1154 					     data,
1155 					     NULL);
1156 	nautilus_progress_info_resume (job->progress);
1157 	res = data->result;
1158 
1159 	g_free (data->button_titles);
1160 	g_free (data);
1161 
1162 	g_timer_continue (job->time);
1163 
1164 	g_free (primary_text);
1165 	g_free (secondary_text);
1166 	
1167 	return res;
1168 }
1169 
1170 #if 0 /* Not used at the moment */
1171 static int
1172 run_simple_dialog (CommonJob *job,
1173 		   gboolean ignore_close_box,
1174 		   GtkMessageType message_type,
1175 		   char *primary_text,
1176 		   char *secondary_text,
1177 		   const char *details_text,
1178 		   ...)
1179 {
1180 	va_list varargs;
1181 	int res;
1182 
1183 	va_start (varargs, details_text);
1184 	res = run_simple_dialog_va (job,
1185 				    ignore_close_box,
1186 				    message_type,
1187 				    primary_text,
1188 				    secondary_text,
1189 				    details_text,
1190 				    varargs);
1191 	va_end (varargs);
1192 	return res;
1193 }
1194 #endif
1195 
1196 static int
1197 run_error (CommonJob *job,
1198 	   char *primary_text,
1199 	   char *secondary_text,
1200 	   const char *details_text,
1201 	   gboolean show_all,
1202 	   ...)
1203 {
1204 	va_list varargs;
1205 	int res;
1206 
1207 	va_start (varargs, show_all);
1208 	res = run_simple_dialog_va (job,
1209 				    FALSE,
1210 				    GTK_MESSAGE_ERROR,
1211 				    primary_text,
1212 				    secondary_text,
1213 				    details_text,
1214 				    show_all,
1215 				    varargs);
1216 	va_end (varargs);
1217 	return res;
1218 }
1219 
1220 static int
1221 run_warning (CommonJob *job,
1222 	     char *primary_text,
1223 	     char *secondary_text,
1224 	     const char *details_text,
1225 	     gboolean show_all,
1226 	     ...)
1227 {
1228 	va_list varargs;
1229 	int res;
1230 
1231 	va_start (varargs, show_all);
1232 	res = run_simple_dialog_va (job,
1233 				    FALSE,
1234 				    GTK_MESSAGE_WARNING,
1235 				    primary_text,
1236 				    secondary_text,
1237 				    details_text,
1238 				    show_all,
1239 				    varargs);
1240 	va_end (varargs);
1241 	return res;
1242 }
1243 
1244 static int
1245 run_question (CommonJob *job,
1246 	      char *primary_text,
1247 	      char *secondary_text,
1248 	      const char *details_text,
1249 	      gboolean show_all,
1250 	      ...)
1251 {
1252 	va_list varargs;
1253 	int res;
1254 
1255 	va_start (varargs, show_all);
1256 	res = run_simple_dialog_va (job,
1257 				    FALSE,
1258 				    GTK_MESSAGE_QUESTION,
1259 				    primary_text,
1260 				    secondary_text,
1261 				    details_text,
1262 				    show_all,
1263 				    varargs);
1264 	va_end (varargs);
1265 	return res;
1266 }
1267 
1268 static void
1269 inhibit_power_manager (CommonJob *job, const char *message)
1270 {
1271 	job->inhibit_cookie = gtk_application_inhibit (GTK_APPLICATION (g_application_get_default ()),
1272 						       GTK_WINDOW (job->parent_window),
1273 						       GTK_APPLICATION_INHIBIT_LOGOUT |
1274 						       GTK_APPLICATION_INHIBIT_SUSPEND,
1275 						       message);
1276 }
1277 
1278 static void
1279 abort_job (CommonJob *job)
1280 {
1281 	/* destroy the undo action data too */
1282 	g_clear_object (&job->undo_info);
1283 
1284 	g_cancellable_cancel (job->cancellable);
1285 }
1286 
1287 static gboolean
1288 job_aborted (CommonJob *job)
1289 {
1290 	return g_cancellable_is_cancelled (job->cancellable);
1291 }
1292 
1293 /* Since this happens on a thread we can't use the global prefs object */
1294 static gboolean
1295 should_confirm_trash (void)
1296 {
1297 	GSettings *prefs;
1298 	gboolean confirm_trash;
1299 
1300 	prefs = g_settings_new ("org.gnome.nautilus.preferences");
1301 	confirm_trash = g_settings_get_boolean (prefs, NAUTILUS_PREFERENCES_CONFIRM_TRASH);
1302 	g_object_unref (prefs);
1303 	return confirm_trash;
1304 }
1305 
1306 static gboolean
1307 confirm_delete_from_trash (CommonJob *job,
1308 			   GList *files)
1309 {
1310 	char *prompt;
1311 	int file_count;
1312 	int response;
1313 
1314 	/* Just Say Yes if the preference says not to confirm. */
1315 	if (!should_confirm_trash ()) {
1316 		return TRUE;
1317 	}
1318 
1319 	file_count = g_list_length (files);
1320 	g_assert (file_count > 0);
1321 	
1322 	if (file_count == 1) {
1323 		prompt = f (_("Are you sure you want to permanently delete “%B” "
1324 					    "from the trash?"), files->data);
1325 	} else {
1326 		prompt = f (ngettext("Are you sure you want to permanently delete "
1327 				     "the %'d selected item from the trash?",
1328 				     "Are you sure you want to permanently delete "
1329 				     "the %'d selected items from the trash?",
1330 				     file_count), 
1331 			    file_count);
1332 	}
1333 
1334 	response = run_warning (job,
1335 				prompt,
1336 				f (_("If you delete an item, it will be permanently lost.")),
1337 				NULL,
1338 				FALSE,
1339 				GTK_STOCK_CANCEL, GTK_STOCK_DELETE,
1340 				NULL);
1341 	
1342 	return (response == 1);
1343 }
1344 
1345 static gboolean
1346 confirm_empty_trash (CommonJob *job)
1347 {
1348 	char *prompt;
1349 	int response;
1350 
1351 	/* Just Say Yes if the preference says not to confirm. */
1352 	if (!should_confirm_trash ()) {
1353 		return TRUE;
1354 	}
1355 
1356 	prompt = f (_("Empty all items from Trash?"));
1357 
1358 	response = run_warning (job,
1359 				prompt,
1360 				f(_("All items in the Trash will be permanently deleted.")),
1361 				NULL,
1362 				FALSE,
1363 				GTK_STOCK_CANCEL, _("Empty _Trash"),
1364 				NULL);
1365 
1366 	return (response == 1);
1367 }
1368 
1369 static gboolean
1370 confirm_delete_directly (CommonJob *job,
1371 			 GList *files)
1372 {
1373 	char *prompt;
1374 	int file_count;
1375 	int response;
1376 
1377 	/* Just Say Yes if the preference says not to confirm. */
1378 	if (!should_confirm_trash ()) {
1379 		return TRUE;
1380 	}
1381 
1382 	file_count = g_list_length (files);
1383 	g_assert (file_count > 0);
1384 
1385 	if (can_delete_files_without_confirm (files)) {
1386 		return TRUE;
1387 	}
1388 
1389 	if (file_count == 1) {
1390 		prompt = f (_("Are you sure you want to permanently delete “%B”?"), 
1391 			    files->data);
1392 	} else {
1393 		prompt = f (ngettext("Are you sure you want to permanently delete "
1394 				     "the %'d selected item?",
1395 				     "Are you sure you want to permanently delete "
1396 				     "the %'d selected items?", file_count),
1397 			    file_count);
1398 	}
1399 	
1400 	response = run_warning (job, 
1401 				prompt,
1402 				f (_("If you delete an item, it will be permanently lost.")),
1403 				NULL,
1404 				FALSE,
1405 				GTK_STOCK_CANCEL, GTK_STOCK_DELETE,
1406 				NULL);
1407 
1408 	return response == 1;
1409 }
1410 
1411 static void
1412 report_delete_progress (CommonJob *job,
1413 			SourceInfo *source_info,
1414 			TransferInfo *transfer_info)
1415 {
1416 	int files_left;
1417 	double elapsed, transfer_rate;
1418 	int remaining_time;
1419 	gint64 now;
1420 	char *files_left_s;
1421 
1422 	now = g_get_monotonic_time ();
1423 	if (transfer_info->last_report_time != 0 &&
1424 	    ABS ((gint64)(transfer_info->last_report_time - now)) < 100 * NSEC_PER_MICROSEC) {
1425 		return;
1426 	}
1427 	transfer_info->last_report_time = now;
1428 	
1429 	files_left = source_info->num_files - transfer_info->num_files;
1430 
1431 	/* Races and whatnot could cause this to be negative... */
1432 	if (files_left < 0) {
1433 		files_left = 1;
1434 	}
1435 
1436 	files_left_s = f (ngettext ("%'d file left to delete",
1437 				    "%'d files left to delete",
1438 				    files_left),
1439 			  files_left);
1440 
1441 	nautilus_progress_info_take_status (job->progress,
1442 					    f (_("Deleting files")));
1443 
1444 	elapsed = g_timer_elapsed (job->time, NULL);
1445 	if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE) {
1446 
1447 		nautilus_progress_info_set_details (job->progress, files_left_s);
1448 	} else {
1449 		char *details, *time_left_s;
1450 		transfer_rate = transfer_info->num_files / elapsed;
1451 		remaining_time = files_left / transfer_rate;
1452 
1453 		/* To translators: %T will expand to a time like "2 minutes".
1454  		 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
1455  		 */
1456 		time_left_s = f (ngettext ("%T left",
1457 					   "%T left",
1458 					   seconds_count_format_time_units (remaining_time)),
1459 				 remaining_time);
1460 
1461 		details = g_strconcat (files_left_s, "\xE2\x80\x94", time_left_s, NULL);
1462 		nautilus_progress_info_take_details (job->progress, details);
1463 
1464 		g_free (time_left_s);
1465 	}
1466 
1467 	g_free (files_left_s);
1468 
1469 	if (source_info->num_files != 0) {
1470 		nautilus_progress_info_set_progress (job->progress, transfer_info->num_files, source_info->num_files);
1471 	}
1472 }
1473 
1474 static void delete_file (CommonJob *job, GFile *file,
1475 			 gboolean *skipped_file,
1476 			 SourceInfo *source_info,
1477 			 TransferInfo *transfer_info,
1478 			 gboolean toplevel);
1479 
1480 static void
1481 delete_dir (CommonJob *job, GFile *dir,
1482 	    gboolean *skipped_file,
1483 	    SourceInfo *source_info,
1484 	    TransferInfo *transfer_info,
1485 	    gboolean toplevel)
1486 {
1487 	GFileInfo *info;
1488 	GError *error;
1489 	GFile *file;
1490 	GFileEnumerator *enumerator;
1491 	char *primary, *secondary, *details;
1492 	int response;
1493 	gboolean skip_error;
1494 	gboolean local_skipped_file;
1495 
1496 	local_skipped_file = FALSE;
1497 	
1498 	skip_error = should_skip_readdir_error (job, dir);
1499  retry:
1500 	error = NULL;
1501 	enumerator = g_file_enumerate_children (dir,
1502 						G_FILE_ATTRIBUTE_STANDARD_NAME,
1503 						G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
1504 						job->cancellable,
1505 						&error);
1506 	if (enumerator) {
1507 		error = NULL;
1508 		
1509 		while (!job_aborted (job) &&
1510 		       (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
1511 			file = g_file_get_child (dir,
1512 						 g_file_info_get_name (info));
1513 			delete_file (job, file, &local_skipped_file, source_info, transfer_info, FALSE);
1514 			g_object_unref (file);
1515 			g_object_unref (info);
1516 		}
1517 		g_file_enumerator_close (enumerator, job->cancellable, NULL);
1518 		g_object_unref (enumerator);
1519 		
1520 		if (error && IS_IO_ERROR (error, CANCELLED)) {
1521 			g_error_free (error);
1522 		} else if (error) {
1523 			primary = f (_("Error while deleting."));
1524 			details = NULL;
1525 			
1526 			if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
1527 				secondary = f (_("Files in the folder “%B” cannot be deleted because you do "
1528 						 "not have permissions to see them."), dir);
1529 			} else {
1530 				secondary = f (_("There was an error getting information about the files in the folder “%B”."), dir);
1531 				details = error->message;
1532 			}
1533 			
1534 			response = run_warning (job,
1535 						primary,
1536 						secondary,
1537 						details,
1538 						FALSE,
1539 						GTK_STOCK_CANCEL, _("_Skip files"),
1540 						NULL);
1541 			
1542 			g_error_free (error);
1543 			
1544 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
1545 				abort_job (job);
1546 			} else if (response == 1) {
1547 				/* Skip: Do Nothing */
1548 				local_skipped_file = TRUE;
1549 			} else {
1550 				g_assert_not_reached ();
1551 			}
1552 		}
1553 		
1554 	} else if (IS_IO_ERROR (error, CANCELLED)) {
1555 		g_error_free (error);
1556 	} else {
1557 		primary = f (_("Error while deleting."));
1558 		details = NULL;
1559 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
1560 			secondary = f (_("The folder “%B” cannot be deleted because you do not have "
1561 					 "permissions to read it."), dir);
1562 		} else {
1563 			secondary = f (_("There was an error reading the folder “%B”."), dir);
1564 			details = error->message;
1565 		}
1566 		
1567 		response = run_warning (job,
1568 					primary,
1569 					secondary,
1570 					details,
1571 					FALSE,
1572 					GTK_STOCK_CANCEL, SKIP, RETRY,
1573 					NULL);
1574 
1575 		g_error_free (error);
1576 
1577 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
1578 			abort_job (job);
1579 		} else if (response == 1) {
1580 			/* Skip: Do Nothing  */
1581 			local_skipped_file = TRUE;
1582 		} else if (response == 2) {
1583 			goto retry;
1584 		} else {
1585 			g_assert_not_reached ();
1586 		}
1587 	}
1588 
1589 	if (!job_aborted (job) &&
1590 	    /* Don't delete dir if there was a skipped file */
1591 	    !local_skipped_file) {
1592 		if (!g_file_delete (dir, job->cancellable, &error)) {
1593 			if (job->skip_all_error) {
1594 				goto skip;
1595 			}
1596 			primary = f (_("Error while deleting."));
1597 			secondary = f (_("Could not remove the folder %B."), dir);
1598 			details = error->message;
1599 			
1600 			response = run_warning (job,
1601 						primary,
1602 						secondary,
1603 						details,
1604 						(source_info->num_files - transfer_info->num_files) > 1,
1605 						GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
1606 						NULL);
1607 			
1608 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
1609 				abort_job (job);
1610 			} else if (response == 1) { /* skip all */
1611 				job->skip_all_error = TRUE;
1612 				local_skipped_file = TRUE;
1613 			} else if (response == 2) { /* skip */
1614 				local_skipped_file = TRUE;
1615 			} else {
1616 				g_assert_not_reached ();
1617 			}
1618 			
1619 		skip:
1620 			g_error_free (error);
1621 		} else {
1622 			nautilus_file_changes_queue_file_removed (dir);
1623 			transfer_info->num_files ++;
1624 			report_delete_progress (job, source_info, transfer_info);
1625 			return;
1626 		}
1627 	}
1628 
1629 	if (local_skipped_file) {
1630 		*skipped_file = TRUE;
1631 	}
1632 }
1633 
1634 static void
1635 delete_file (CommonJob *job, GFile *file,
1636 	     gboolean *skipped_file,
1637 	     SourceInfo *source_info,
1638 	     TransferInfo *transfer_info,
1639 	     gboolean toplevel)
1640 {
1641 	GError *error;
1642 	char *primary, *secondary, *details;
1643 	int response;
1644 
1645 	if (should_skip_file (job, file)) {
1646 		*skipped_file = TRUE;
1647 		return;
1648 	}
1649 	
1650 	error = NULL;
1651 	if (g_file_delete (file, job->cancellable, &error)) {
1652 		nautilus_file_changes_queue_file_removed (file);
1653 		transfer_info->num_files ++;
1654 		report_delete_progress (job, source_info, transfer_info);
1655 		return;
1656 	}
1657 
1658 	if (IS_IO_ERROR (error, NOT_EMPTY)) {
1659 		g_error_free (error);
1660 		delete_dir (job, file,
1661 			    skipped_file,
1662 			    source_info, transfer_info,
1663 			    toplevel);
1664 		return;
1665 		
1666 	} else if (IS_IO_ERROR (error, CANCELLED)) {
1667 		g_error_free (error);
1668 		
1669 	} else {
1670 		if (job->skip_all_error) {
1671 			goto skip;
1672 		}
1673 		primary = f (_("Error while deleting."));
1674 		secondary = f (_("There was an error deleting %B."), file);
1675 		details = error->message;
1676 		
1677 		response = run_warning (job,
1678 					primary,
1679 					secondary,
1680 					details,
1681 					(source_info->num_files - transfer_info->num_files) > 1,
1682 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
1683 					NULL);
1684 
1685 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
1686 			abort_job (job);
1687 		} else if (response == 1) { /* skip all */
1688 			job->skip_all_error = TRUE;
1689 		} else if (response == 2) { /* skip */
1690 			/* do nothing */
1691 		} else {
1692 			g_assert_not_reached ();
1693 		}
1694 	skip:
1695 		g_error_free (error);
1696 	}
1697 	
1698 	*skipped_file = TRUE;
1699 }
1700 
1701 static void
1702 delete_files (CommonJob *job, GList *files, int *files_skipped)
1703 {
1704 	GList *l;
1705 	GFile *file;
1706 	SourceInfo source_info;
1707 	TransferInfo transfer_info;
1708 	gboolean skipped_file;
1709 	
1710 	if (job_aborted (job)) {
1711 		return;
1712 	}
1713 
1714 	scan_sources (files,
1715 		      &source_info,
1716 		      job,
1717 		      OP_KIND_DELETE);
1718 	if (job_aborted (job)) {
1719 		return;
1720 	}
1721 
1722 	g_timer_start (job->time);
1723 	
1724 	memset (&transfer_info, 0, sizeof (transfer_info));
1725 	report_delete_progress (job, &source_info, &transfer_info);
1726 	
1727 	for (l = files;
1728 	     l != NULL && !job_aborted (job);
1729 	     l = l->next) {
1730 		file = l->data;
1731 
1732 		skipped_file = FALSE;
1733 		delete_file (job, file,
1734 			     &skipped_file,
1735 			     &source_info, &transfer_info,
1736 			     TRUE);
1737 		if (skipped_file) {
1738 			(*files_skipped)++;
1739 		}
1740 	}
1741 }
1742 
1743 static void
1744 report_trash_progress (CommonJob *job,
1745 		       int files_trashed,
1746 		       int total_files)
1747 {
1748 	int files_left;
1749 	char *s;
1750 
1751 	files_left = total_files - files_trashed;
1752 
1753 	nautilus_progress_info_take_status (job->progress,
1754 					    f (_("Moving files to trash")));
1755 
1756 	s = f (ngettext ("%'d file left to trash",
1757 			 "%'d files left to trash",
1758 			 files_left),
1759 	       files_left);
1760 	nautilus_progress_info_take_details (job->progress, s);
1761 
1762 	if (total_files != 0) {
1763 		nautilus_progress_info_set_progress (job->progress, files_trashed, total_files);
1764 	}
1765 }
1766 
1767 
1768 static void
1769 trash_files (CommonJob *job, GList *files, int *files_skipped)
1770 {
1771 	GList *l;
1772 	GFile *file;
1773 	GList *to_delete;
1774 	GError *error;
1775 	int total_files, files_trashed;
1776 	char *primary, *secondary, *details;
1777 	int response;
1778 
1779 	if (job_aborted (job)) {
1780 		return;
1781 	}
1782 
1783 	total_files = g_list_length (files);
1784 	files_trashed = 0;
1785 
1786 	report_trash_progress (job, files_trashed, total_files);
1787 
1788 	to_delete = NULL;
1789 	for (l = files;
1790 	     l != NULL && !job_aborted (job);
1791 	     l = l->next) {
1792 		file = l->data;
1793 
1794 		error = NULL;
1795 
1796 		if (!g_file_trash (file, job->cancellable, &error)) {
1797 			if (job->skip_all_error) {
1798 				(*files_skipped)++;
1799 				goto skip;
1800 			}
1801 
1802 			if (job->delete_all) {
1803 				to_delete = g_list_prepend (to_delete, file);
1804 				goto skip;
1805 			}
1806 
1807 			/* Translators: %B is a file name */
1808 			primary = f (_("“%B” can't be put in the trash. Do you want to delete it immediately?"), file);
1809 			details = NULL;
1810 			secondary = NULL;
1811 			if (!IS_IO_ERROR (error, NOT_SUPPORTED)) {
1812 				details = error->message;
1813 			} else if (!g_file_is_native (file)) {
1814 				secondary = f (_("This remote location does not support sending items to the trash."));
1815 			}
1816 
1817 			response = run_question (job,
1818 						 primary,
1819 						 secondary,
1820 						 details,
1821 						 (total_files - files_trashed) > 1,
1822 						 GTK_STOCK_CANCEL, SKIP_ALL, SKIP, DELETE_ALL, GTK_STOCK_DELETE,
1823 						 NULL);
1824 
1825 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
1826 				((DeleteJob *) job)->user_cancel = TRUE;				
1827 				abort_job (job);
1828 			} else if (response == 1) { /* skip all */
1829 				(*files_skipped)++;
1830 				job->skip_all_error = TRUE;
1831 			} else if (response == 2) { /* skip */
1832 				(*files_skipped)++;
1833 			} else if (response == 3) { /* delete all */
1834 				to_delete = g_list_prepend (to_delete, file);
1835 				job->delete_all = TRUE;
1836 			} else if (response == 4) { /* delete */
1837 				to_delete = g_list_prepend (to_delete, file);
1838 			}
1839 
1840 		skip:
1841 			g_error_free (error);
1842 			total_files--;
1843 		} else {
1844 			nautilus_file_changes_queue_file_removed (file);
1845 
1846 			if (job->undo_info != NULL) {
1847 				nautilus_file_undo_info_trash_add_file (NAUTILUS_FILE_UNDO_INFO_TRASH (job->undo_info), file);
1848 			}
1849 
1850 			files_trashed++;
1851 			report_trash_progress (job, files_trashed, total_files);
1852 		}
1853 	}
1854 
1855 	if (to_delete) {
1856 		to_delete = g_list_reverse (to_delete);
1857 		delete_files (job, to_delete, files_skipped);
1858 		g_list_free (to_delete);
1859 	}
1860 }
1861 
1862 static gboolean
1863 delete_job_done (gpointer user_data)
1864 {
1865 	DeleteJob *job;
1866 	GHashTable *debuting_uris;
1867 
1868 	job = user_data;
1869 
1870 	g_list_free_full (job->files, g_object_unref);
1871 
1872 	if (job->done_callback) {
1873 		debuting_uris = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
1874 		job->done_callback (debuting_uris, job->user_cancel, job->done_callback_data);
1875 		g_hash_table_unref (debuting_uris);
1876 	}
1877 	
1878 	finalize_common ((CommonJob *)job);
1879 
1880 	nautilus_file_changes_consume_changes (TRUE);
1881 
1882 	return FALSE;
1883 }
1884 
1885 static gboolean
1886 delete_job (GIOSchedulerJob *io_job,
1887 	    GCancellable *cancellable,
1888 	    gpointer user_data)
1889 {
1890 	DeleteJob *job = user_data;
1891 	GList *to_trash_files;
1892 	GList *to_delete_files;
1893 	GList *l;
1894 	GFile *file;
1895 	gboolean confirmed;
1896 	CommonJob *common;
1897 	gboolean must_confirm_delete_in_trash;
1898 	gboolean must_confirm_delete;
1899 	int files_skipped;
1900 
1901 	common = (CommonJob *)job;
1902 	common->io_job = io_job;
1903 
1904 	nautilus_progress_info_start (job->common.progress);
1905 	
1906 	to_trash_files = NULL;
1907 	to_delete_files = NULL;
1908 
1909 	must_confirm_delete_in_trash = FALSE;
1910 	must_confirm_delete = FALSE;
1911 	files_skipped = 0;
1912 	
1913 	for (l = job->files; l != NULL; l = l->next) {
1914 		file = l->data;
1915 		
1916 		if (job->try_trash &&
1917 		    g_file_has_uri_scheme (file, "trash")) {
1918 			must_confirm_delete_in_trash = TRUE;
1919 			to_delete_files = g_list_prepend (to_delete_files, file);
1920 		} else if (can_delete_without_confirm (file)) {
1921 			to_delete_files = g_list_prepend (to_delete_files, file);
1922 		} else {
1923 			if (job->try_trash) {
1924 				to_trash_files = g_list_prepend (to_trash_files, file);
1925 			} else {
1926 				must_confirm_delete = TRUE;
1927 				to_delete_files = g_list_prepend (to_delete_files, file);
1928 			}
1929 		}
1930 	}
1931 	
1932 	if (to_delete_files != NULL) {
1933 		to_delete_files = g_list_reverse (to_delete_files);
1934 		confirmed = TRUE;
1935 		if (must_confirm_delete_in_trash) {
1936 			confirmed = confirm_delete_from_trash (common, to_delete_files);
1937 		} else if (must_confirm_delete) {
1938 			confirmed = confirm_delete_directly (common, to_delete_files);
1939 		}
1940 		if (confirmed) {
1941 			delete_files (common, to_delete_files, &files_skipped);
1942 		} else {
1943 			job->user_cancel = TRUE;
1944 		}
1945 	}
1946 	
1947 	if (to_trash_files != NULL) {
1948 		to_trash_files = g_list_reverse (to_trash_files);
1949 		
1950 		trash_files (common, to_trash_files, &files_skipped);
1951 	}
1952 	
1953 	g_list_free (to_trash_files);
1954 	g_list_free (to_delete_files);
1955 	
1956 	if (files_skipped == g_list_length (job->files)) {
1957 		/* User has skipped all files, report user cancel */
1958 		job->user_cancel = TRUE;
1959 	}
1960 
1961 	g_io_scheduler_job_send_to_mainloop_async (io_job,
1962 						   delete_job_done,
1963 						   job,
1964 						   NULL);
1965 
1966 	return FALSE;
1967 }
1968 
1969 static void
1970 trash_or_delete_internal (GList                  *files,
1971 			  GtkWindow              *parent_window,
1972 			  gboolean                try_trash,			  
1973 			  NautilusDeleteCallback  done_callback,
1974 			  gpointer                done_callback_data)
1975 {
1976 	DeleteJob *job;
1977 
1978 	/* TODO: special case desktop icon link files ... */
1979 
1980 	job = op_job_new (DeleteJob, parent_window);
1981 	job->files = eel_g_object_list_copy (files);
1982 	job->try_trash = try_trash;
1983 	job->user_cancel = FALSE;
1984 	job->done_callback = done_callback;
1985 	job->done_callback_data = done_callback_data;
1986 
1987 	if (try_trash) {
1988 		inhibit_power_manager ((CommonJob *)job, _("Trashing Files"));
1989 	} else {
1990 		inhibit_power_manager ((CommonJob *)job, _("Deleting Files"));
1991 	}
1992 	
1993 	if (try_trash && !nautilus_file_undo_manager_pop_flag ()) {
1994 		job->common.undo_info = nautilus_file_undo_info_trash_new (g_list_length (files));
1995 	}
1996 
1997 	g_io_scheduler_push_job (delete_job,
1998 			   job,
1999 			   NULL,
2000 			   0,
2001 			   NULL);
2002 }
2003 
2004 void
2005 nautilus_file_operations_trash_or_delete (GList                  *files,
2006 					  GtkWindow              *parent_window,
2007 					  NautilusDeleteCallback  done_callback,
2008 					  gpointer                done_callback_data)
2009 {
2010 	trash_or_delete_internal (files, parent_window,
2011 				  TRUE,
2012 				  done_callback,  done_callback_data);
2013 }
2014 
2015 void
2016 nautilus_file_operations_delete (GList                  *files, 
2017 				 GtkWindow              *parent_window,
2018 				 NautilusDeleteCallback  done_callback,
2019 				 gpointer                done_callback_data)
2020 {
2021 	trash_or_delete_internal (files, parent_window,
2022 				  FALSE,			  
2023 				  done_callback,  done_callback_data);
2024 }
2025 
2026 
2027 
2028 typedef struct {
2029 	gboolean eject;
2030 	GMount *mount;
2031 	GMountOperation *mount_operation;
2032 	GtkWindow *parent_window;
2033 	NautilusUnmountCallback callback;
2034 	gpointer callback_data;
2035 } UnmountData;
2036 
2037 static void
2038 unmount_data_free (UnmountData *data)
2039 {
2040 	if (data->parent_window) {
2041 		g_object_remove_weak_pointer (G_OBJECT (data->parent_window),
2042 					      (gpointer *) &data->parent_window);
2043 	}
2044 
2045 	g_clear_object (&data->mount_operation);
2046 	g_object_unref (data->mount);
2047 	g_free (data);
2048 }
2049 
2050 static void
2051 unmount_mount_callback (GObject *source_object,
2052 			GAsyncResult *res,
2053 			gpointer user_data)
2054 {
2055 	UnmountData *data = user_data;
2056 	GError *error;
2057 	char *primary;
2058 	gboolean unmounted;
2059 
2060 	error = NULL;
2061 	if (data->eject) {
2062 		unmounted = g_mount_eject_with_operation_finish (G_MOUNT (source_object),
2063 								 res, &error);
2064 	} else {
2065 		unmounted = g_mount_unmount_with_operation_finish (G_MOUNT (source_object),
2066 								   res, &error);
2067 	}
2068 	
2069 	if (! unmounted) {
2070 		if (error->code != G_IO_ERROR_FAILED_HANDLED) {
2071 			if (data->eject) {
2072 				primary = f (_("Unable to eject %V"), source_object);
2073 			} else {
2074 				primary = f (_("Unable to unmount %V"), source_object);
2075 			}
2076 			eel_show_error_dialog (primary,
2077 					       error->message,
2078 					       data->parent_window);
2079 			g_free (primary);
2080 		}
2081 	}
2082 
2083 	if (data->callback) {
2084 		data->callback (data->callback_data);
2085 	}
2086 
2087 	if (error != NULL) {
2088 		g_error_free (error);
2089 	}
2090 
2091 	unmount_data_free (data);
2092 }
2093 
2094 static void
2095 do_unmount (UnmountData *data)
2096 {
2097 	GMountOperation *mount_op;
2098 
2099 	if (data->mount_operation) {
2100 		mount_op = g_object_ref (data->mount_operation);
2101 	} else {
2102 		mount_op = gtk_mount_operation_new (data->parent_window);
2103 	}
2104 	if (data->eject) {
2105 		g_mount_eject_with_operation (data->mount,
2106 					      0,
2107 					      mount_op,
2108 					      NULL,
2109 					      unmount_mount_callback,
2110 					      data);
2111 	} else {
2112 		g_mount_unmount_with_operation (data->mount,
2113 						0,
2114 						mount_op,
2115 						NULL,
2116 						unmount_mount_callback,
2117 						data);
2118 	}
2119 	g_object_unref (mount_op);
2120 }
2121 
2122 static gboolean
2123 dir_has_files (GFile *dir)
2124 {
2125 	GFileEnumerator *enumerator;
2126 	gboolean res;
2127 	GFileInfo *file_info;
2128 
2129 	res = FALSE;
2130 	
2131 	enumerator = g_file_enumerate_children (dir,
2132 						G_FILE_ATTRIBUTE_STANDARD_NAME,
2133 						0,
2134 						NULL, NULL);
2135 	if (enumerator) {
2136 		file_info = g_file_enumerator_next_file (enumerator, NULL, NULL);
2137 		if (file_info != NULL) {
2138 			res = TRUE;
2139 			g_object_unref (file_info);
2140 		}
2141 		
2142 		g_file_enumerator_close (enumerator, NULL, NULL);
2143 		g_object_unref (enumerator);
2144 	}
2145 	
2146 
2147 	return res;
2148 }
2149 
2150 static GList *
2151 get_trash_dirs_for_mount (GMount *mount)
2152 {
2153 	GFile *root;
2154 	GFile *trash;
2155 	char *relpath;
2156 	GList *list;
2157 
2158 	root = g_mount_get_root (mount);
2159 	if (root == NULL) {
2160 		return NULL;
2161 	}
2162 
2163 	list = NULL;
2164 	
2165 	if (g_file_is_native (root)) {
2166 		relpath = g_strdup_printf (".Trash/%d", getuid ());
2167 		trash = g_file_resolve_relative_path (root, relpath);
2168 		g_free (relpath);
2169 
2170 		list = g_list_prepend (list, g_file_get_child (trash, "files"));
2171 		list = g_list_prepend (list, g_file_get_child (trash, "info"));
2172 		
2173 		g_object_unref (trash);
2174 		
2175 		relpath = g_strdup_printf (".Trash-%d", getuid ());
2176 		trash = g_file_get_child (root, relpath);
2177 		g_free (relpath);
2178 
2179 		list = g_list_prepend (list, g_file_get_child (trash, "files"));
2180 		list = g_list_prepend (list, g_file_get_child (trash, "info"));
2181 		
2182 		g_object_unref (trash);
2183 	}
2184 	
2185 	g_object_unref (root);
2186 	
2187 	return list;
2188 }
2189 
2190 static gboolean
2191 has_trash_files (GMount *mount)
2192 {
2193 	GList *dirs, *l;
2194 	GFile *dir;
2195 	gboolean res;
2196 
2197 	dirs = get_trash_dirs_for_mount (mount);
2198 
2199 	res = FALSE;
2200 
2201 	for (l = dirs; l != NULL; l = l->next) {
2202 		dir = l->data;
2203 
2204 		if (dir_has_files (dir)) {
2205 			res = TRUE;
2206 			break;
2207 		}
2208 	}
2209 
2210 	g_list_free_full (dirs, g_object_unref);
2211 	
2212 	return res;
2213 }
2214 
2215 
2216 static gint
2217 prompt_empty_trash (GtkWindow *parent_window)
2218 {
2219 	gint                    result;
2220 	GtkWidget               *dialog;
2221 	GdkScreen               *screen;
2222 
2223 	screen = NULL;
2224 	if (parent_window != NULL) {
2225 		screen = gtk_widget_get_screen (GTK_WIDGET (parent_window));
2226 	}
2227 
2228 	/* Do we need to be modal ? */
2229 	dialog = gtk_message_dialog_new (NULL, GTK_DIALOG_MODAL,
2230 					 GTK_MESSAGE_QUESTION, GTK_BUTTONS_NONE,
2231 					 _("Do you want to empty the trash before you unmount?"));
2232 	gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog),
2233 						  _("In order to regain the "
2234 						    "free space on this volume "
2235 						    "the trash must be emptied. "
2236 						    "All trashed items on the volume "
2237 						    "will be permanently lost."));
2238 	gtk_dialog_add_buttons (GTK_DIALOG (dialog), 
2239 	                        _("Do _not Empty Trash"), GTK_RESPONSE_REJECT, 
2240 	                        GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, 
2241 	                        _("Empty _Trash"), GTK_RESPONSE_ACCEPT, NULL);
2242 	gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
2243 	gtk_window_set_title (GTK_WINDOW (dialog), ""); /* as per HIG */
2244 	gtk_window_set_skip_taskbar_hint (GTK_WINDOW (dialog), TRUE);
2245 	if (screen) {
2246 		gtk_window_set_screen (GTK_WINDOW (dialog), screen);
2247 	}
2248 	atk_object_set_role (gtk_widget_get_accessible (dialog), ATK_ROLE_ALERT);
2249 	gtk_window_set_wmclass (GTK_WINDOW (dialog), "empty_trash",
2250 				"Nautilus");
2251 	
2252 	/* Make transient for the window group */
2253 	gtk_widget_realize (dialog);
2254 	if (screen != NULL) {
2255 		gdk_window_set_transient_for (gtk_widget_get_window (GTK_WIDGET (dialog)),
2256 				      		gdk_screen_get_root_window (screen));
2257 	}
2258 	
2259 	result = gtk_dialog_run (GTK_DIALOG (dialog));
2260 	gtk_widget_destroy (dialog);
2261 	return result;
2262 }
2263 
2264 static void
2265 empty_trash_for_unmount_done (gboolean success,
2266 			      gpointer user_data)
2267 {
2268 	UnmountData *data = user_data;
2269 	do_unmount (data);
2270 }
2271 
2272 void
2273 nautilus_file_operations_unmount_mount_full (GtkWindow                      *parent_window,
2274 					     GMount                         *mount,
2275 					     GMountOperation                *mount_operation,
2276 					     gboolean                        eject,
2277 					     gboolean                        check_trash,
2278 					     NautilusUnmountCallback         callback,
2279 					     gpointer                        callback_data)
2280 {
2281 	UnmountData *data;
2282 	int response;
2283 
2284 	data = g_new0 (UnmountData, 1);
2285 	data->callback = callback;
2286 	data->callback_data = callback_data;
2287 	if (parent_window) {
2288 		data->parent_window = parent_window;
2289 		g_object_add_weak_pointer (G_OBJECT (data->parent_window),
2290 					   (gpointer *) &data->parent_window);
2291 		
2292 	}
2293 	if (mount_operation) {
2294 		data->mount_operation = g_object_ref (mount_operation);
2295 	}
2296 	data->eject = eject;
2297 	data->mount = g_object_ref (mount);
2298 
2299 	if (check_trash && has_trash_files (mount)) {
2300 		response = prompt_empty_trash (parent_window);
2301 
2302 		if (response == GTK_RESPONSE_ACCEPT) {
2303 			EmptyTrashJob *job;
2304 			
2305 			job = op_job_new (EmptyTrashJob, parent_window);
2306 			job->should_confirm = FALSE;
2307 			job->trash_dirs = get_trash_dirs_for_mount (mount);
2308 			job->done_callback = empty_trash_for_unmount_done;
2309 			job->done_callback_data = data;
2310 			g_io_scheduler_push_job (empty_trash_job,
2311 					   job,
2312 					   NULL,
2313 					   0,
2314 					   NULL);
2315 			return;
2316 		} else if (response == GTK_RESPONSE_CANCEL) {
2317 			if (callback) {
2318 				callback (callback_data);
2319 			}
2320 
2321 			unmount_data_free (data);
2322 			return;
2323 		}
2324 	}
2325 	
2326 	do_unmount (data);
2327 }
2328 
2329 void
2330 nautilus_file_operations_unmount_mount (GtkWindow                      *parent_window,
2331 					GMount                         *mount,
2332 					gboolean                        eject,
2333 					gboolean                        check_trash)
2334 {
2335 	nautilus_file_operations_unmount_mount_full (parent_window, mount, NULL, eject,
2336 						     check_trash, NULL, NULL);
2337 }
2338 
2339 static void
2340 mount_callback_data_notify (gpointer data,
2341 			    GObject *object)
2342 {
2343 	GMountOperation *mount_op;
2344 
2345 	mount_op = G_MOUNT_OPERATION (data);
2346 	g_object_set_data (G_OBJECT (mount_op), "mount-callback", NULL);
2347 	g_object_set_data (G_OBJECT (mount_op), "mount-callback-data", NULL);
2348 }
2349 
2350 static void
2351 volume_mount_cb (GObject *source_object,
2352 		 GAsyncResult *res,
2353 		 gpointer user_data)
2354 {
2355 	NautilusMountCallback mount_callback;
2356 	GObject *mount_callback_data_object;
2357 	GMountOperation *mount_op = user_data;
2358 	GError *error;
2359 	char *primary;
2360 	char *name;
2361 	gboolean success;
2362 
2363 	success = TRUE;
2364 	error = NULL;
2365 	if (!g_volume_mount_finish (G_VOLUME (source_object), res, &error)) {
2366 		if (error->code != G_IO_ERROR_FAILED_HANDLED &&
2367                     error->code != G_IO_ERROR_ALREADY_MOUNTED) {
2368 			GtkWindow *parent;
2369 
2370 			parent = gtk_mount_operation_get_parent (GTK_MOUNT_OPERATION (mount_op));
2371 			name = g_volume_get_name (G_VOLUME (source_object));
2372 			primary = g_strdup_printf (_("Unable to access “%s”"), name);
2373 			g_free (name);
2374 			success = FALSE;
2375 			eel_show_error_dialog (primary,
2376 					       error->message,
2377 					       parent);
2378 			g_free (primary);
2379 		}
2380 		g_error_free (error);
2381 	}
2382 
2383 	mount_callback = (NautilusMountCallback)
2384 		g_object_get_data (G_OBJECT (mount_op), "mount-callback");
2385 	mount_callback_data_object =
2386 		g_object_get_data (G_OBJECT (mount_op), "mount-callback-data");
2387 
2388 	if (mount_callback != NULL) {
2389 		(* mount_callback) (G_VOLUME (source_object),
2390 				    success,
2391 				    mount_callback_data_object);
2392 
2393 	    	if (mount_callback_data_object != NULL) {
2394 			g_object_weak_unref (mount_callback_data_object,
2395 					     mount_callback_data_notify,
2396 					     mount_op);
2397 		}
2398 	}
2399 
2400 	g_object_unref (mount_op);
2401 }
2402 
2403 
2404 void
2405 nautilus_file_operations_mount_volume (GtkWindow *parent_window,
2406 				       GVolume *volume)
2407 {
2408 	nautilus_file_operations_mount_volume_full (parent_window, volume,
2409 						    NULL, NULL);
2410 }
2411 
2412 void
2413 nautilus_file_operations_mount_volume_full (GtkWindow *parent_window,
2414 					    GVolume *volume,
2415 					    NautilusMountCallback mount_callback,
2416 					    GObject *mount_callback_data_object)
2417 {
2418 	GMountOperation *mount_op;
2419 
2420 	mount_op = gtk_mount_operation_new (parent_window);
2421 	g_mount_operation_set_password_save (mount_op, G_PASSWORD_SAVE_FOR_SESSION);
2422 	g_object_set_data (G_OBJECT (mount_op),
2423 			   "mount-callback",
2424 			   mount_callback);
2425 
2426 	if (mount_callback != NULL &&
2427 	    mount_callback_data_object != NULL) {
2428 		g_object_weak_ref (mount_callback_data_object,
2429 				   mount_callback_data_notify,
2430 				   mount_op);
2431 	}
2432 	g_object_set_data (G_OBJECT (mount_op),
2433 			   "mount-callback-data",
2434 			   mount_callback_data_object);
2435 
2436 	g_volume_mount (volume, 0, mount_op, NULL, volume_mount_cb, mount_op);
2437 }
2438 
2439 static void
2440 report_count_progress (CommonJob *job,
2441 		       SourceInfo *source_info)
2442 {
2443 	char *s;
2444 
2445 	switch (source_info->op) {
2446 	default:
2447 	case OP_KIND_COPY:
2448 		s = f (ngettext("Preparing to copy %'d file (%S)",
2449 		                "Preparing to copy %'d files (%S)",
2450 		                source_info->num_files),
2451 		       source_info->num_files, source_info->num_bytes);
2452 		break;
2453 	case OP_KIND_MOVE:
2454 		s = f (ngettext("Preparing to move %'d file (%S)",
2455 		                "Preparing to move %'d files (%S)",
2456 		                source_info->num_files),
2457 		       source_info->num_files, source_info->num_bytes);
2458 		break;
2459 	case OP_KIND_DELETE:
2460 		s = f (ngettext("Preparing to delete %'d file (%S)",
2461 		                "Preparing to delete %'d files (%S)",
2462 		                source_info->num_files),
2463 		       source_info->num_files, source_info->num_bytes);
2464 		break;
2465 	case OP_KIND_TRASH:
2466 		s = f (ngettext("Preparing to trash %'d file",
2467 		                "Preparing to trash %'d files",
2468 		                source_info->num_files),
2469 		       source_info->num_files);
2470 		break;
2471 	} 
2472 
2473 	nautilus_progress_info_take_details (job->progress, s);
2474 	nautilus_progress_info_pulse_progress (job->progress);
2475 }
2476 
2477 static void
2478 count_file (GFileInfo *info,
2479 	    CommonJob *job,
2480 	    SourceInfo *source_info)
2481 {
2482 	source_info->num_files += 1;
2483 	source_info->num_bytes += g_file_info_get_size (info);
2484 
2485 	if (source_info->num_files_since_progress++ > 100) {
2486 		report_count_progress (job, source_info);
2487 		source_info->num_files_since_progress = 0;
2488 	}
2489 }
2490 
2491 static char *
2492 get_scan_primary (OpKind kind)
2493 {
2494 	switch (kind) {
2495 	default:
2496 	case OP_KIND_COPY:
2497 		return f (_("Error while copying."));
2498 	case OP_KIND_MOVE:
2499 		return f (_("Error while moving."));
2500 	case OP_KIND_DELETE:
2501 		return f (_("Error while deleting."));
2502 	case OP_KIND_TRASH:
2503 		return f (_("Error while moving files to trash."));
2504 	}
2505 }
2506 
2507 static void
2508 scan_dir (GFile *dir,
2509 	  SourceInfo *source_info,
2510 	  CommonJob *job,
2511 	  GQueue *dirs)
2512 {
2513 	GFileInfo *info;
2514 	GError *error;
2515 	GFile *subdir;
2516 	GFileEnumerator *enumerator;
2517 	char *primary, *secondary, *details;
2518 	int response;
2519 	SourceInfo saved_info;
2520 
2521 	saved_info = *source_info;
2522 
2523  retry:
2524 	error = NULL;
2525 	enumerator = g_file_enumerate_children (dir,
2526 						G_FILE_ATTRIBUTE_STANDARD_NAME","
2527 						G_FILE_ATTRIBUTE_STANDARD_TYPE","
2528 						G_FILE_ATTRIBUTE_STANDARD_SIZE,
2529 						G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2530 						job->cancellable,
2531 						&error);
2532 	if (enumerator) {
2533 		error = NULL;
2534 		while ((info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) {
2535 			count_file (info, job, source_info);
2536 
2537 			if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2538 				subdir = g_file_get_child (dir,
2539 							   g_file_info_get_name (info));
2540 				
2541 				/* Push to head, since we want depth-first */
2542 				g_queue_push_head (dirs, subdir);
2543 			}
2544 
2545 			g_object_unref (info);
2546 		}
2547 		g_file_enumerator_close (enumerator, job->cancellable, NULL);
2548 		g_object_unref (enumerator);
2549 		
2550 		if (error && IS_IO_ERROR (error, CANCELLED)) {
2551 			g_error_free (error);
2552 		} else if (error) {
2553 			primary = get_scan_primary (source_info->op);
2554 			details = NULL;
2555 			
2556 			if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
2557 				secondary = f (_("Files in the folder “%B” cannot be handled because you do "
2558 						 "not have permissions to see them."), dir);
2559 			} else {
2560 				secondary = f (_("There was an error getting information about the files in the folder “%B”."), dir);
2561 				details = error->message;
2562 			}
2563 			
2564 			response = run_warning (job,
2565 						primary,
2566 						secondary,
2567 						details,
2568 						FALSE,
2569 						GTK_STOCK_CANCEL, RETRY, SKIP,
2570 						NULL);
2571 
2572 			g_error_free (error);
2573 			
2574 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
2575 				abort_job (job);
2576 			} else if (response == 1) {
2577 				*source_info = saved_info;
2578 				goto retry;
2579 			} else if (response == 2) {
2580 				skip_readdir_error (job, dir);
2581 			} else {
2582 				g_assert_not_reached ();
2583 			}
2584 		}
2585 		
2586 	} else if (job->skip_all_error) {
2587 		g_error_free (error);
2588 		skip_file (job, dir);
2589 	} else if (IS_IO_ERROR (error, CANCELLED)) {
2590 		g_error_free (error);
2591 	} else {	
2592 		primary = get_scan_primary (source_info->op);
2593 		details = NULL;
2594 		
2595 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
2596 			secondary = f (_("The folder “%B” cannot be handled because you do not have "
2597 					 "permissions to read it."), dir);
2598 		} else {
2599 			secondary = f (_("There was an error reading the folder “%B”."), dir);
2600 			details = error->message;
2601 		}
2602 		/* set show_all to TRUE here, as we don't know how many
2603 		 * files we'll end up processing yet.
2604 		 */
2605 		response = run_warning (job,
2606 					primary,
2607 					secondary,
2608 					details,
2609 					TRUE,
2610 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP, RETRY,
2611 					NULL);
2612 		
2613 		g_error_free (error);
2614 
2615 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
2616 			abort_job (job);
2617 		} else if (response == 1 || response == 2) {
2618 			if (response == 1) {
2619 				job->skip_all_error = TRUE;
2620 			}
2621 			skip_file (job, dir);
2622 		} else if (response == 3) {
2623 			goto retry;
2624 		} else {
2625 			g_assert_not_reached ();
2626 		}
2627 	}
2628 }	
2629 
2630 static void
2631 scan_file (GFile *file,
2632 	   SourceInfo *source_info,
2633 	   CommonJob *job)
2634 {
2635 	GFileInfo *info;
2636 	GError *error;
2637 	GQueue *dirs;
2638 	GFile *dir;
2639 	char *primary;
2640 	char *secondary;
2641 	char *details;
2642 	int response;
2643 
2644 	dirs = g_queue_new ();
2645 	
2646  retry:
2647 	error = NULL;
2648 	info = g_file_query_info (file, 
2649 				  G_FILE_ATTRIBUTE_STANDARD_TYPE","
2650 				  G_FILE_ATTRIBUTE_STANDARD_SIZE,
2651 				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2652 				  job->cancellable,
2653 				  &error);
2654 
2655 	if (info) {
2656 		count_file (info, job, source_info);
2657 
2658 		if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) {
2659 			g_queue_push_head (dirs, g_object_ref (file));
2660 		}
2661 		
2662 		g_object_unref (info);
2663 	} else if (job->skip_all_error) {
2664 		g_error_free (error);
2665 		skip_file (job, file);
2666 	} else if (IS_IO_ERROR (error, CANCELLED)) {
2667 		g_error_free (error);
2668 	} else {
2669 		primary = get_scan_primary (source_info->op);
2670 		details = NULL;
2671 		
2672 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
2673 			secondary = f (_("The file “%B” cannot be handled because you do not have "
2674 					 "permissions to read it."), file);
2675 		} else {
2676 			secondary = f (_("There was an error getting information about “%B”."), file);
2677 			details = error->message;
2678 		}
2679 		/* set show_all to TRUE here, as we don't know how many
2680 		 * files we'll end up processing yet.
2681 		 */
2682 		response = run_warning (job,
2683 					primary,
2684 					secondary,
2685 					details,
2686 					TRUE,
2687 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP, RETRY,
2688 					NULL);
2689 		
2690 		g_error_free (error);
2691 
2692 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
2693 			abort_job (job);
2694 		} else if (response == 1 || response == 2) {
2695 			if (response == 1) {
2696 				job->skip_all_error = TRUE;
2697 			}
2698 			skip_file (job, file);
2699 		} else if (response == 3) {
2700 			goto retry;
2701 		} else {
2702 			g_assert_not_reached ();
2703 		}
2704 	}
2705 		
2706 	while (!job_aborted (job) && 
2707 	       (dir = g_queue_pop_head (dirs)) != NULL) {
2708 		scan_dir (dir, source_info, job, dirs);
2709 		g_object_unref (dir);
2710 	}
2711 
2712 	/* Free all from queue if we exited early */
2713 	g_queue_foreach (dirs, (GFunc)g_object_unref, NULL);
2714 	g_queue_free (dirs);
2715 }
2716 
2717 static void
2718 scan_sources (GList *files,
2719 	      SourceInfo *source_info,
2720 	      CommonJob *job,
2721 	      OpKind kind)
2722 {
2723 	GList *l;
2724 	GFile *file;
2725 
2726 	memset (source_info, 0, sizeof (SourceInfo));
2727 	source_info->op = kind;
2728 
2729 	report_count_progress (job, source_info);
2730 	
2731 	for (l = files; l != NULL && !job_aborted (job); l = l->next) {
2732 		file = l->data;
2733 
2734 		scan_file (file,
2735 			   source_info,
2736 			   job);
2737 	}
2738 
2739 	/* Make sure we report the final count */
2740 	report_count_progress (job, source_info);
2741 }
2742 
2743 static void
2744 verify_destination (CommonJob *job,
2745 		    GFile *dest,
2746 		    char **dest_fs_id,
2747 		    goffset required_size)
2748 {
2749 	GFileInfo *info, *fsinfo;
2750 	GError *error;
2751 	guint64 free_size;
2752 	guint64 size_difference;
2753 	char *primary, *secondary, *details;
2754 	int response;
2755 	GFileType file_type;
2756 	gboolean dest_is_symlink = FALSE;
2757 
2758 	if (dest_fs_id) {
2759 		*dest_fs_id = NULL;
2760 	}
2761 
2762  retry:
2763 	
2764 	error = NULL;
2765 	info = g_file_query_info (dest, 
2766 				  G_FILE_ATTRIBUTE_STANDARD_TYPE","
2767 				  G_FILE_ATTRIBUTE_ID_FILESYSTEM,
2768 				  dest_is_symlink ? G_FILE_QUERY_INFO_NONE : G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
2769 				  job->cancellable,
2770 				  &error);
2771 
2772 	if (info == NULL) {
2773 		if (IS_IO_ERROR (error, CANCELLED)) {
2774 			g_error_free (error);
2775 			return;
2776 		}
2777 		
2778 		primary = f (_("Error while copying to “%B”."), dest);
2779 		details = NULL;
2780 		
2781 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
2782 			secondary = f (_("You do not have permissions to access the destination folder."));
2783 		} else {
2784 			secondary = f (_("There was an error getting information about the destination."));
2785 			details = error->message;
2786 		}
2787 
2788 		response = run_error (job,
2789 				      primary,
2790 				      secondary,
2791 				      details,
2792 				      FALSE,
2793 				      GTK_STOCK_CANCEL, RETRY,
2794 				      NULL);
2795 		
2796 		g_error_free (error);
2797 
2798 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
2799 			abort_job (job);
2800 		} else if (response == 1) {
2801 			goto retry;
2802 		} else {
2803 			g_assert_not_reached ();
2804 		}
2805 
2806 		return;
2807 	}
2808 
2809 	file_type = g_file_info_get_file_type (info);
2810 	if (!dest_is_symlink && file_type == G_FILE_TYPE_SYMBOLIC_LINK) {
2811 		/* Record that destination is a symlink and do real stat() once again */
2812 		dest_is_symlink = TRUE;
2813 		g_object_unref (info);
2814 		goto retry;
2815 	}
2816 
2817 	if (dest_fs_id) {
2818 		*dest_fs_id =
2819 			g_strdup (g_file_info_get_attribute_string (info,
2820 								    G_FILE_ATTRIBUTE_ID_FILESYSTEM));
2821 	}
2822 	
2823 	g_object_unref (info);
2824 	
2825 	if (file_type != G_FILE_TYPE_DIRECTORY) {
2826 		primary = f (_("Error while copying to “%B”."), dest);
2827 		secondary = f (_("The destination is not a folder."));
2828 
2829 		run_error (job,
2830 			   primary,
2831 			   secondary,
2832 			   NULL,
2833 			   FALSE,
2834 			   GTK_STOCK_CANCEL,
2835 			   NULL);
2836 		
2837 		abort_job (job);
2838 		return;
2839 	}
2840 	
2841 	if (dest_is_symlink) {
2842 		/* We can't reliably statfs() destination if it's a symlink, thus not doing any further checks. */
2843 		return;
2844 	}
2845 	
2846 	fsinfo = g_file_query_filesystem_info (dest,
2847 					       G_FILE_ATTRIBUTE_FILESYSTEM_FREE","
2848 					       G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
2849 					       job->cancellable,
2850 					       NULL);
2851 	if (fsinfo == NULL) {
2852 		/* All sorts of things can go wrong getting the fs info (like not supported)
2853 		 * only check these things if the fs returns them
2854 		 */
2855 		return;
2856 	}
2857 	
2858 	if (required_size > 0 &&
2859 	    g_file_info_has_attribute (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) {
2860 		free_size = g_file_info_get_attribute_uint64 (fsinfo,
2861 							      G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
2862 		
2863 		if (free_size < required_size) {
2864 			size_difference = required_size - free_size;
2865 			primary = f (_("Error while copying to “%B”."), dest);
2866 			secondary = f (_("There is not enough space on the destination. Try to remove files to make space."));
2867 			
2868 			details = f (_("%S more space is required to copy to the destination."), size_difference);
2869 			
2870 			response = run_warning (job,
2871 						primary,
2872 						secondary,
2873 						details,
2874 						FALSE,
2875 						GTK_STOCK_CANCEL,
2876 						COPY_FORCE,
2877 						RETRY,
2878 						NULL);
2879 			
2880 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
2881 				abort_job (job);
2882 			} else if (response == 2) {
2883 				goto retry;
2884 			} else if (response == 1) {
2885 				/* We are forced to copy - just fall through ... */
2886 			} else {
2887 				g_assert_not_reached ();
2888 			}
2889 		}
2890 	}
2891 	
2892 	if (!job_aborted (job) &&
2893 	    g_file_info_get_attribute_boolean (fsinfo,
2894 					       G_FILE_ATTRIBUTE_FILESYSTEM_READONLY)) {
2895 		primary = f (_("Error while copying to “%B”."), dest);
2896 		secondary = f (_("The destination is read-only."));
2897 
2898 		run_error (job,
2899 			   primary,
2900 			   secondary,
2901 			   NULL,
2902 			   FALSE,
2903 			   GTK_STOCK_CANCEL,
2904 			   NULL);
2905 		
2906 		g_error_free (error);
2907 
2908 		abort_job (job);
2909 	}
2910 	
2911 	g_object_unref (fsinfo);
2912 }
2913 
2914 static void
2915 report_copy_progress (CopyMoveJob *copy_job,
2916 		      SourceInfo *source_info,
2917 		      TransferInfo *transfer_info)
2918 {
2919 	int files_left;
2920 	goffset total_size;
2921 	double elapsed, transfer_rate;
2922 	int remaining_time;
2923 	guint64 now;
2924 	CommonJob *job;
2925 	gboolean is_move;
2926 
2927 	job = (CommonJob *)copy_job;
2928 
2929 	is_move = copy_job->is_move;
2930 	
2931 	now = g_get_monotonic_time ();
2932 
2933 	if (transfer_info->last_report_time != 0 &&
2934 	    ABS ((gint64)(transfer_info->last_report_time - now)) < 100 * NSEC_PER_MICROSEC) {
2935 		return;
2936 	}
2937 	transfer_info->last_report_time = now;
2938 	
2939 	files_left = source_info->num_files - transfer_info->num_files;
2940 
2941 	/* Races and whatnot could cause this to be negative... */
2942 	if (files_left < 0) {
2943 		files_left = 1;
2944 	}
2945 
2946 	if (files_left != transfer_info->last_reported_files_left ||
2947 	    transfer_info->last_reported_files_left == 0) {
2948 		/* Avoid changing this unless files_left changed since last time */
2949 		transfer_info->last_reported_files_left = files_left;
2950 		
2951 		if (source_info->num_files == 1) {
2952 			if (copy_job->destination != NULL) {
2953 				nautilus_progress_info_take_status (job->progress,
2954 								    f (is_move ?
2955 								       _("Moving “%B” to “%B”"):
2956 								       _("Copying “%B” to “%B”"),
2957 								       copy_job->fake_display_source != NULL ?
2958 								       copy_job->fake_display_source :
2959 								       (GFile *)copy_job->files->data,
2960 								       copy_job->destination));
2961 			} else {
2962 				nautilus_progress_info_take_status (job->progress,
2963 								    f (_("Duplicating “%B”"),
2964 								       (GFile *)copy_job->files->data));
2965 			}
2966 		} else if (copy_job->files != NULL &&
2967 			   copy_job->files->next == NULL) {
2968 			if (copy_job->destination != NULL) {
2969 				nautilus_progress_info_take_status (job->progress,
2970 								    f (is_move ?
2971 								       _("Moving file %'d of %'d (in “%B”) to “%B”")
2972 								       :
2973 								       _("Copying file %'d of %'d (in “%B”) to “%B”"),
2974 								       transfer_info->num_files + 1,
2975 								       source_info->num_files,
2976 								       (GFile *)copy_job->files->data,
2977 								       copy_job->destination));
2978 			} else {
2979 				nautilus_progress_info_take_status (job->progress,
2980 								    f (_("Duplicating file %'d of %'d (in “%B”)"),
2981 								       transfer_info->num_files + 1,
2982 								       source_info->num_files,
2983 								       (GFile *)copy_job->files->data));
2984 			}
2985 		} else {
2986 			if (copy_job->destination != NULL) {
2987 				nautilus_progress_info_take_status (job->progress,
2988 								    f (is_move ?
2989 								       _("Moving file %'d of %'d to “%B”")
2990 								       :
2991 								       _ ("Copying file %'d of %'d to “%B”"),
2992 								       transfer_info->num_files + 1,
2993 								       source_info->num_files,
2994 								       copy_job->destination));
2995 			} else {
2996 				nautilus_progress_info_take_status (job->progress,
2997 								    f (_("Duplicating file %'d of %'d"),
2998 								       transfer_info->num_files + 1,
2999 								       source_info->num_files));
3000 			}
3001 		}
3002 	}
3003 	
3004 	total_size = MAX (source_info->num_bytes, transfer_info->num_bytes);
3005 	
3006 	elapsed = g_timer_elapsed (job->time, NULL);
3007 	transfer_rate = 0;
3008 	if (elapsed > 0) {
3009 		transfer_rate = transfer_info->num_bytes / elapsed;
3010 	}
3011 
3012 	if (elapsed < SECONDS_NEEDED_FOR_RELIABLE_TRANSFER_RATE &&
3013 	    transfer_rate > 0) {
3014 		char *s;
3015 		/* To translators: %S will expand to a size like "2 bytes" or "3 MB", so something like "4 kb of 4 MB" */		
3016 		s = f (_("%S of %S"), transfer_info->num_bytes, total_size);
3017 		nautilus_progress_info_take_details (job->progress, s);
3018 	} else {
3019 		char *s;
3020 		remaining_time = (total_size - transfer_info->num_bytes) / transfer_rate;
3021 
3022 		/* To translators: %S will expand to a size like "2 bytes" or "3 MB", %T to a time duration like
3023 		 * "2 minutes". So the whole thing will be something like "2 kb of 4 MB -- 2 hours left (4kb/sec)"
3024 		 *
3025 		 * The singular/plural form will be used depending on the remaining time (i.e. the %T argument).
3026 		 */		
3027 		s = f (ngettext ("%S of %S \xE2\x80\x94 %T left (%S/sec)",
3028 				 "%S of %S \xE2\x80\x94 %T left (%S/sec)",
3029 				 seconds_count_format_time_units (remaining_time)),
3030 		       transfer_info->num_bytes, total_size,
3031 		       remaining_time,
3032 		       (goffset)transfer_rate);
3033 		nautilus_progress_info_take_details (job->progress, s);
3034 	}
3035 
3036 	nautilus_progress_info_set_progress (job->progress, transfer_info->num_bytes, total_size);
3037 }
3038 
3039 static int
3040 get_max_name_length (GFile *file_dir)
3041 {
3042 	int max_length;
3043 	char *dir;
3044 	long max_path;
3045 	long max_name;
3046 
3047 	max_length = -1;
3048 
3049 	if (!g_file_has_uri_scheme (file_dir, "file"))
3050 		return max_length;
3051 
3052 	dir = g_file_get_path (file_dir);
3053 	if (!dir)
3054 		return max_length;
3055 
3056 	max_path = pathconf (dir, _PC_PATH_MAX);
3057 	max_name = pathconf (dir, _PC_NAME_MAX);
3058 
3059 	if (max_name == -1 && max_path == -1) {
3060 		max_length = -1;
3061 	} else if (max_name == -1 && max_path != -1) {
3062 		max_length = max_path - (strlen (dir) + 1);
3063 	} else if (max_name != -1 && max_path == -1) {
3064 		max_length = max_name;
3065 	} else {
3066 		int leftover;
3067 
3068 		leftover = max_path - (strlen (dir) + 1);
3069 
3070 		max_length = MIN (leftover, max_name);
3071 	}
3072 
3073 	g_free (dir);
3074 
3075 	return max_length;
3076 }
3077 
3078 #define FAT_FORBIDDEN_CHARACTERS "/:;*?\"<>"
3079 
3080 static gboolean
3081 str_replace (char *str,
3082 	     const char *chars_to_replace,
3083 	     char replacement)
3084 {
3085 	gboolean success;
3086 	int i;
3087 
3088 	success = FALSE;
3089 	for (i = 0; str[i] != '\0'; i++) {
3090 		if (strchr (chars_to_replace, str[i])) {
3091 			success = TRUE;
3092 			str[i] = replacement;
3093 		}
3094 	}
3095 
3096 	return success;
3097 }
3098 
3099 static gboolean
3100 make_file_name_valid_for_dest_fs (char *filename,
3101 				 const char *dest_fs_type)
3102 {
3103 	if (dest_fs_type != NULL && filename != NULL) {
3104 		if (!strcmp (dest_fs_type, "fat")  ||
3105 		    !strcmp (dest_fs_type, "vfat") ||
3106 		    !strcmp (dest_fs_type, "msdos") ||
3107 		    !strcmp (dest_fs_type, "msdosfs")) {
3108 			gboolean ret;
3109 			int i, old_len;
3110 
3111 			ret = str_replace (filename, FAT_FORBIDDEN_CHARACTERS, '_');
3112 
3113 			old_len = strlen (filename);
3114 			for (i = 0; i < old_len; i++) {
3115 				if (filename[i] != ' ') {
3116 					g_strchomp (filename);
3117 					ret |= (old_len != strlen (filename));
3118 					break;
3119 				}
3120 			}
3121 
3122 			return ret;
3123 		}
3124 	}
3125 
3126 	return FALSE;
3127 }
3128 
3129 static GFile *
3130 get_unique_target_file (GFile *src,
3131 			GFile *dest_dir,
3132 			gboolean same_fs,
3133 			const char *dest_fs_type,
3134 			int count)
3135 {
3136 	const char *editname, *end;
3137 	char *basename, *new_name;
3138 	GFileInfo *info;
3139 	GFile *dest;
3140 	int max_length;
3141 
3142 	max_length = get_max_name_length (dest_dir);
3143 	
3144 	dest = NULL;
3145 	info = g_file_query_info (src,
3146 				  G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME,
3147 				  0, NULL, NULL);
3148 	if (info != NULL) {
3149 		editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
3150 		
3151 		if (editname != NULL) {
3152 			new_name = get_duplicate_name (editname, count, max_length);
3153 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3154 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
3155 			g_free (new_name);
3156 		}
3157 		
3158 		g_object_unref (info);
3159 	}
3160 
3161 	if (dest == NULL) {
3162 		basename = g_file_get_basename (src);
3163 
3164 		if (g_utf8_validate (basename, -1, NULL)) {
3165 			new_name = get_duplicate_name (basename, count, max_length);
3166 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3167 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
3168 			g_free (new_name);
3169 		} 
3170 
3171 		if (dest == NULL) {
3172 			end = strrchr (basename, '.');
3173 			if (end != NULL) {
3174 				count += atoi (end + 1);
3175 			}
3176 			new_name = g_strdup_printf ("%s.%d", basename, count);
3177 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3178 			dest = g_file_get_child (dest_dir, new_name);
3179 			g_free (new_name);
3180 		}
3181 		
3182 		g_free (basename);
3183 	}
3184 
3185 	return dest;
3186 }
3187 
3188 static GFile *
3189 get_target_file_for_link (GFile *src,
3190 			  GFile *dest_dir,
3191 			  const char *dest_fs_type,
3192 			  int count)
3193 {
3194 	const char *editname;
3195 	char *basename, *new_name;
3196 	GFileInfo *info;
3197 	GFile *dest;
3198 	int max_length;
3199 
3200 	max_length = get_max_name_length (dest_dir);
3201 
3202 	dest = NULL;
3203 	info = g_file_query_info (src,
3204 				  G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME,
3205 				  0, NULL, NULL);
3206 	if (info != NULL) {
3207 		editname = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_EDIT_NAME);
3208 		
3209 		if (editname != NULL) {
3210 			new_name = get_link_name (editname, count, max_length);
3211 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3212 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
3213 			g_free (new_name);
3214 		}
3215 		
3216 		g_object_unref (info);
3217 	}
3218 
3219 	if (dest == NULL) {
3220 		basename = g_file_get_basename (src);
3221 		make_file_name_valid_for_dest_fs (basename, dest_fs_type);
3222 
3223 		if (g_utf8_validate (basename, -1, NULL)) {
3224 			new_name = get_link_name (basename, count, max_length);
3225 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3226 			dest = g_file_get_child_for_display_name (dest_dir, new_name, NULL);
3227 			g_free (new_name);
3228 		} 
3229 
3230 		if (dest == NULL) {
3231 			if (count == 1) {
3232 				new_name = g_strdup_printf ("%s.lnk", basename);
3233 			} else {
3234 				new_name = g_strdup_printf ("%s.lnk%d", basename, count);
3235 			}
3236 			make_file_name_valid_for_dest_fs (new_name, dest_fs_type);
3237 			dest = g_file_get_child (dest_dir, new_name);
3238 			g_free (new_name);
3239 		}
3240 		
3241 		g_free (basename);
3242 	}
3243 
3244 	return dest;
3245 }
3246 
3247 static GFile *
3248 get_target_file_with_custom_name (GFile *src,
3249 				  GFile *dest_dir,
3250 				  const char *dest_fs_type,
3251 				  gboolean same_fs,
3252 				  const gchar *custom_name)
3253 {
3254 	char *basename;
3255 	GFile *dest;
3256 	GFileInfo *info;
3257 	char *copyname;
3258 
3259 	dest = NULL;
3260 
3261 	if (custom_name != NULL) {
3262 		copyname = g_strdup (custom_name);
3263 		make_file_name_valid_for_dest_fs (copyname, dest_fs_type);
3264 		dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL);
3265 
3266 		g_free (copyname);
3267 	}
3268 
3269 	if (dest == NULL && !same_fs) {
3270 		info = g_file_query_info (src,
3271 					  G_FILE_ATTRIBUTE_STANDARD_COPY_NAME,
3272 					  0, NULL, NULL);
3273 		
3274 		if (info) {
3275 			copyname = g_strdup (g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_COPY_NAME));
3276 
3277 			if (copyname) {
3278 				make_file_name_valid_for_dest_fs (copyname, dest_fs_type);
3279 				dest = g_file_get_child_for_display_name (dest_dir, copyname, NULL);
3280 				g_free (copyname);
3281 			}
3282 			
3283 			g_object_unref (info);
3284 		}
3285 	}
3286 
3287 	if (dest == NULL) {
3288 		basename = g_file_get_basename (src);
3289 		make_file_name_valid_for_dest_fs (basename, dest_fs_type);
3290 		dest = g_file_get_child (dest_dir, basename);
3291 		g_free (basename);
3292 	}
3293 	
3294 	return dest;
3295 }
3296 
3297 static GFile *
3298 get_target_file (GFile *src,
3299 		 GFile *dest_dir,
3300 		 const char *dest_fs_type,
3301 		 gboolean same_fs)
3302 {
3303 	return get_target_file_with_custom_name (src, dest_dir, dest_fs_type, same_fs, NULL);
3304 }
3305 
3306 static gboolean
3307 has_fs_id (GFile *file, const char *fs_id)
3308 {
3309 	const char *id;
3310 	GFileInfo *info;
3311 	gboolean res;
3312 
3313 	res = FALSE;
3314 	info = g_file_query_info (file,
3315 				  G_FILE_ATTRIBUTE_ID_FILESYSTEM,
3316 				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3317 				  NULL, NULL);
3318 
3319 	if (info) {
3320 		id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM);
3321 		
3322 		if (id && strcmp (id, fs_id) == 0) {
3323 			res = TRUE;
3324 		}
3325 		
3326 		g_object_unref (info);
3327 	}
3328 	
3329 	return res;
3330 }
3331 
3332 static gboolean
3333 is_dir (GFile *file)
3334 {
3335 	GFileInfo *info;
3336 	gboolean res;
3337 
3338 	res = FALSE;
3339 	info = g_file_query_info (file,
3340 				  G_FILE_ATTRIBUTE_STANDARD_TYPE,
3341 				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3342 				  NULL, NULL);
3343 	if (info) {
3344 		res = g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY;
3345 		g_object_unref (info);
3346 	}
3347 	
3348 	return res;
3349 }
3350 
3351 static void copy_move_file (CopyMoveJob *job,
3352 			    GFile *src,
3353 			    GFile *dest_dir,
3354 			    gboolean same_fs,
3355 			    gboolean unique_names,
3356 			    char **dest_fs_type,
3357 			    SourceInfo *source_info,
3358 			    TransferInfo *transfer_info,
3359 			    GHashTable *debuting_files,
3360 			    GdkPoint *point,
3361 			    gboolean overwrite,
3362 			    gboolean *skipped_file,
3363 			    gboolean readonly_source_fs);
3364 
3365 typedef enum {
3366 	CREATE_DEST_DIR_RETRY,
3367 	CREATE_DEST_DIR_FAILED,
3368 	CREATE_DEST_DIR_SUCCESS
3369 } CreateDestDirResult;
3370 
3371 static CreateDestDirResult
3372 create_dest_dir (CommonJob *job,
3373 		 GFile *src,
3374 		 GFile **dest,
3375 		 gboolean same_fs,
3376 		 char **dest_fs_type)
3377 {
3378 	GError *error;
3379 	GFile *new_dest, *dest_dir;
3380 	char *primary, *secondary, *details;
3381 	int response;
3382 	gboolean handled_invalid_filename;
3383 
3384 	handled_invalid_filename = *dest_fs_type != NULL;
3385 
3386  retry:
3387 	/* First create the directory, then copy stuff to it before
3388 	   copying the attributes, because we need to be sure we can write to it */
3389 	
3390 	error = NULL;
3391 	if (!g_file_make_directory (*dest, job->cancellable, &error)) {
3392 		if (IS_IO_ERROR (error, CANCELLED)) {
3393 			g_error_free (error);
3394 			return CREATE_DEST_DIR_FAILED;
3395 		} else if (IS_IO_ERROR (error, INVALID_FILENAME) &&
3396 			   !handled_invalid_filename) {
3397 			handled_invalid_filename = TRUE;
3398 
3399 			g_assert (*dest_fs_type == NULL);
3400 
3401 			dest_dir = g_file_get_parent (*dest);
3402 
3403 			if (dest_dir != NULL) {
3404 				*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
3405 
3406 				new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
3407 				g_object_unref (dest_dir);
3408 
3409 				if (!g_file_equal (*dest, new_dest)) {
3410 					g_object_unref (*dest);
3411 					*dest = new_dest;
3412 					g_error_free (error);
3413 					return CREATE_DEST_DIR_RETRY;
3414 				} else {
3415 					g_object_unref (new_dest);
3416 				}
3417 			}
3418 		}
3419 
3420 		primary = f (_("Error while copying."));
3421 		details = NULL;
3422 		
3423 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
3424 			secondary = f (_("The folder “%B” cannot be copied because you do not have "
3425 					 "permissions to create it in the destination."), src);
3426 		} else {
3427 			secondary = f (_("There was an error creating the folder “%B”."), src);
3428 			details = error->message;
3429 		}
3430 		
3431 		response = run_warning (job,
3432 					primary,
3433 					secondary,
3434 					details,
3435 					FALSE,
3436 					GTK_STOCK_CANCEL, SKIP, RETRY,
3437 					NULL);
3438 
3439 		g_error_free (error);
3440 
3441 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3442 			abort_job (job);
3443 		} else if (response == 1) {
3444 			/* Skip: Do Nothing  */
3445 		} else if (response == 2) {
3446 			goto retry;
3447 		} else {
3448 			g_assert_not_reached ();
3449 		}
3450 		return CREATE_DEST_DIR_FAILED;
3451 	}
3452 	nautilus_file_changes_queue_file_added (*dest);
3453 
3454 	if (job->undo_info != NULL) {
3455 		nautilus_file_undo_info_ext_add_origin_target_pair (NAUTILUS_FILE_UNDO_INFO_EXT (job->undo_info),
3456 								    src, *dest);
3457 	}
3458 
3459 	return CREATE_DEST_DIR_SUCCESS;
3460 }
3461 
3462 /* a return value of FALSE means retry, i.e.
3463  * the destination has changed and the source
3464  * is expected to re-try the preceeding
3465  * g_file_move() or g_file_copy() call with
3466  * the new destination.
3467  */
3468 static gboolean
3469 copy_move_directory (CopyMoveJob *copy_job,
3470 		     GFile *src,
3471 		     GFile **dest,
3472 		     gboolean same_fs,
3473 		     gboolean create_dest,
3474 		     char **parent_dest_fs_type,
3475 		     SourceInfo *source_info,
3476 		     TransferInfo *transfer_info,
3477 		     GHashTable *debuting_files,
3478 		     gboolean *skipped_file,
3479 		     gboolean readonly_source_fs)
3480 {
3481 	GFileInfo *info;
3482 	GError *error;
3483 	GFile *src_file;
3484 	GFileEnumerator *enumerator;
3485 	char *primary, *secondary, *details;
3486 	char *dest_fs_type;
3487 	int response;
3488 	gboolean skip_error;
3489 	gboolean local_skipped_file;
3490 	CommonJob *job;
3491 	GFileCopyFlags flags;
3492 
3493 	job = (CommonJob *)copy_job;
3494 	
3495 	if (create_dest) {
3496 		switch (create_dest_dir (job, src, dest, same_fs, parent_dest_fs_type)) {
3497 			case CREATE_DEST_DIR_RETRY:
3498 				/* next time copy_move_directory() is called,
3499 				 * create_dest will be FALSE if a directory already
3500 				 * exists under the new name (i.e. WOULD_RECURSE)
3501 				 */
3502 				return FALSE;
3503 
3504 			case CREATE_DEST_DIR_FAILED:
3505 				*skipped_file = TRUE;
3506 				return TRUE;
3507 
3508 			case CREATE_DEST_DIR_SUCCESS:
3509 			default:
3510 				break;
3511 		}
3512 
3513 		if (debuting_files) {
3514 			g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (TRUE));
3515 		}
3516 
3517 	}
3518 
3519 	local_skipped_file = FALSE;
3520 	dest_fs_type = NULL;
3521 	
3522 	skip_error = should_skip_readdir_error (job, src);
3523  retry:
3524 	error = NULL;
3525 	enumerator = g_file_enumerate_children (src,
3526 						G_FILE_ATTRIBUTE_STANDARD_NAME,
3527 						G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3528 						job->cancellable,
3529 						&error);
3530 	if (enumerator) {
3531 		error = NULL;
3532 
3533 		while (!job_aborted (job) &&
3534 		       (info = g_file_enumerator_next_file (enumerator, job->cancellable, skip_error?NULL:&error)) != NULL) {
3535 			src_file = g_file_get_child (src,
3536 						     g_file_info_get_name (info));
3537 			copy_move_file (copy_job, src_file, *dest, same_fs, FALSE, &dest_fs_type,
3538 					source_info, transfer_info, NULL, NULL, FALSE, &local_skipped_file,
3539 					readonly_source_fs);
3540 			g_object_unref (src_file);
3541 			g_object_unref (info);
3542 		}
3543 		g_file_enumerator_close (enumerator, job->cancellable, NULL);
3544 		g_object_unref (enumerator);
3545 		
3546 		if (error && IS_IO_ERROR (error, CANCELLED)) {
3547 			g_error_free (error);
3548 		} else if (error) {
3549 			if (copy_job->is_move) {
3550 				primary = f (_("Error while moving."));
3551 			} else {
3552 				primary = f (_("Error while copying."));
3553 			}
3554 			details = NULL;
3555 			
3556 			if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
3557 				secondary = f (_("Files in the folder “%B” cannot be copied because you do "
3558 						 "not have permissions to see them."), src);
3559 			} else {
3560 				secondary = f (_("There was an error getting information about the files in the folder “%B”."), src);
3561 				details = error->message;
3562 			}
3563 			
3564 			response = run_warning (job,
3565 						primary,
3566 						secondary,
3567 						details,
3568 						FALSE,
3569 						GTK_STOCK_CANCEL, _("_Skip files"),
3570 						NULL);
3571 			
3572 			g_error_free (error);
3573 			
3574 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3575 				abort_job (job);
3576 			} else if (response == 1) {
3577 				/* Skip: Do Nothing */
3578 				local_skipped_file = TRUE;
3579 			} else {
3580 				g_assert_not_reached ();
3581 			}
3582 		}
3583 
3584 		/* Count the copied directory as a file */
3585 		transfer_info->num_files ++;
3586 		report_copy_progress (copy_job, source_info, transfer_info);
3587 
3588 		if (debuting_files) {
3589 			g_hash_table_replace (debuting_files, g_object_ref (*dest), GINT_TO_POINTER (create_dest));
3590 		}
3591 	} else if (IS_IO_ERROR (error, CANCELLED)) {
3592 		g_error_free (error);
3593 	} else {
3594 		if (copy_job->is_move) {
3595 			primary = f (_("Error while moving."));
3596 		} else {
3597 			primary = f (_("Error while copying."));
3598 		}
3599 		details = NULL;
3600 		
3601 		if (IS_IO_ERROR (error, PERMISSION_DENIED)) {
3602 			secondary = f (_("The folder “%B” cannot be copied because you do not have "
3603 					 "permissions to read it."), src);
3604 		} else {
3605 			secondary = f (_("There was an error reading the folder “%B”."), src);
3606 			details = error->message;
3607 		}
3608 		
3609 		response = run_warning (job,
3610 					primary,
3611 					secondary,
3612 					details,
3613 					FALSE,
3614 					GTK_STOCK_CANCEL, SKIP, RETRY,
3615 					NULL);
3616 
3617 		g_error_free (error);
3618 
3619 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3620 			abort_job (job);
3621 		} else if (response == 1) {
3622 			/* Skip: Do Nothing  */
3623 			local_skipped_file = TRUE;
3624 		} else if (response == 2) {
3625 			goto retry;
3626 		} else {
3627 			g_assert_not_reached ();
3628 		}
3629 	}
3630 
3631 	if (create_dest) {
3632 		flags = (readonly_source_fs) ? G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_TARGET_DEFAULT_PERMS 
3633 					     : G_FILE_COPY_NOFOLLOW_SYMLINKS;
3634 		/* Ignore errors here. Failure to copy metadata is not a hard error */
3635 		g_file_copy_attributes (src, *dest,
3636 					flags,
3637 					job->cancellable, NULL);
3638 	}
3639 
3640 	if (!job_aborted (job) && copy_job->is_move &&
3641 	    /* Don't delete source if there was a skipped file */
3642 	    !local_skipped_file) {
3643 		if (!g_file_delete (src, job->cancellable, &error)) {
3644 			if (job->skip_all_error) {
3645 				goto skip;
3646 			}
3647 			primary = f (_("Error while moving “%B”."), src);
3648 			secondary = f (_("Could not remove the source folder."));
3649 			details = error->message;
3650 			
3651 			response = run_warning (job,
3652 						primary,
3653 						secondary,
3654 						details,
3655 						(source_info->num_files - transfer_info->num_files) > 1,
3656 						GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
3657 						NULL);
3658 			
3659 			if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3660 				abort_job (job);
3661 			} else if (response == 1) { /* skip all */
3662 				job->skip_all_error = TRUE;
3663 				local_skipped_file = TRUE;
3664 			} else if (response == 2) { /* skip */
3665 				local_skipped_file = TRUE;
3666 			} else {
3667 				g_assert_not_reached ();
3668 			}
3669 			
3670 		skip:
3671 			g_error_free (error);
3672 		}
3673 	}
3674 
3675 	if (local_skipped_file) {
3676 		*skipped_file = TRUE;
3677 	}
3678 
3679 	g_free (dest_fs_type);
3680 	return TRUE;
3681 }
3682 
3683 static gboolean
3684 remove_target_recursively (CommonJob *job,
3685 			   GFile *src,
3686 			   GFile *toplevel_dest,
3687 			   GFile *file)
3688 {
3689 	GFileEnumerator *enumerator;
3690 	GError *error;
3691 	GFile *child;
3692 	gboolean stop;
3693 	char *primary, *secondary, *details;
3694 	int response;
3695 	GFileInfo *info;
3696 
3697 	stop = FALSE;
3698 	
3699 	error = NULL;
3700 	enumerator = g_file_enumerate_children (file,
3701 						G_FILE_ATTRIBUTE_STANDARD_NAME,
3702 						G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3703 						job->cancellable,
3704 						&error);
3705 	if (enumerator) {
3706 		error = NULL;
3707 		
3708 		while (!job_aborted (job) &&
3709 		       (info = g_file_enumerator_next_file (enumerator, job->cancellable, &error)) != NULL) {
3710 			child = g_file_get_child (file,
3711 						  g_file_info_get_name (info));
3712 			if (!remove_target_recursively (job, src, toplevel_dest, child)) {
3713 				stop = TRUE;
3714 				break;
3715 			}
3716 			g_object_unref (child);
3717 			g_object_unref (info);
3718 		}
3719 		g_file_enumerator_close (enumerator, job->cancellable, NULL);
3720 		g_object_unref (enumerator);
3721 		
3722 	} else if (IS_IO_ERROR (error, NOT_DIRECTORY)) {
3723 		/* Not a dir, continue */
3724 		g_error_free (error);
3725 		
3726 	} else if (IS_IO_ERROR (error, CANCELLED)) {
3727 		g_error_free (error);
3728 	} else {
3729 		if (job->skip_all_error) {
3730 			goto skip1;
3731 		}
3732 		
3733 		primary = f (_("Error while copying “%B”."), src);
3734 		secondary = f (_("Could not remove files from the already existing folder %F."), file);
3735 		details = error->message;
3736 
3737 		/* set show_all to TRUE here, as we don't know how many
3738 		 * files we'll end up processing yet.
3739 		 */
3740 		response = run_warning (job,
3741 					primary,
3742 					secondary,
3743 					details,
3744 					TRUE,
3745 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
3746 					NULL);
3747 		
3748 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3749 			abort_job (job);
3750 		} else if (response == 1) { /* skip all */
3751 			job->skip_all_error = TRUE;
3752 		} else if (response == 2) { /* skip */
3753 			/* do nothing */
3754 		} else {
3755 			g_assert_not_reached ();
3756 		}
3757 	skip1:
3758 		g_error_free (error);
3759 		
3760 		stop = TRUE;
3761 	}
3762 
3763 	if (stop) {
3764 		return FALSE;
3765 	}
3766 
3767 	error = NULL;
3768 	
3769 	if (!g_file_delete (file, job->cancellable, &error)) {
3770 		if (job->skip_all_error ||
3771 		    IS_IO_ERROR (error, CANCELLED)) {
3772 			goto skip2;
3773 		}
3774 		primary = f (_("Error while copying “%B”."), src);
3775 		secondary = f (_("Could not remove the already existing file %F."), file);
3776 		details = error->message;
3777 
3778 		/* set show_all to TRUE here, as we don't know how many
3779 		 * files we'll end up processing yet.
3780 		 */
3781 		response = run_warning (job,
3782 					primary,
3783 					secondary,
3784 					details,
3785 					TRUE,
3786 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
3787 					NULL);
3788 		
3789 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
3790 			abort_job (job);
3791 		} else if (response == 1) { /* skip all */
3792 			job->skip_all_error = TRUE;
3793 		} else if (response == 2) { /* skip */
3794 			/* do nothing */
3795 		} else {
3796 			g_assert_not_reached ();
3797 		}
3798 
3799 	skip2:
3800 		g_error_free (error);
3801 		
3802 		return FALSE;
3803 	}
3804 	nautilus_file_changes_queue_file_removed (file);
3805 	
3806 	return TRUE;
3807 	
3808 }
3809 
3810 typedef struct {
3811 	CopyMoveJob *job;
3812 	goffset last_size;
3813 	SourceInfo *source_info;
3814 	TransferInfo *transfer_info;
3815 } ProgressData;
3816 
3817 static void
3818 copy_file_progress_callback (goffset current_num_bytes,
3819 			     goffset total_num_bytes,
3820 			     gpointer user_data)
3821 {
3822 	ProgressData *pdata;
3823 	goffset new_size;
3824 
3825 	pdata = user_data;
3826 	
3827 	new_size = current_num_bytes - pdata->last_size;
3828 
3829 	if (new_size > 0) {
3830 		pdata->transfer_info->num_bytes += new_size;
3831 		pdata->last_size = current_num_bytes;
3832 		report_copy_progress (pdata->job,
3833 				      pdata->source_info,
3834 				      pdata->transfer_info);
3835 	}
3836 }
3837 
3838 static gboolean
3839 test_dir_is_parent (GFile *child, GFile *root)
3840 {
3841 	GFile *f, *tmp;
3842 	
3843 	f = g_file_dup (child);
3844 	while (f) {
3845 		if (g_file_equal (f, root)) {
3846 			g_object_unref (f);
3847 			return TRUE;
3848 		}
3849 		tmp = f;
3850 		f = g_file_get_parent (f);
3851 		g_object_unref (tmp);
3852 	}
3853 	if (f) {
3854 		g_object_unref (f);
3855 	}
3856 	return FALSE;
3857 }
3858 
3859 static char *
3860 query_fs_type (GFile *file,
3861 	       GCancellable *cancellable)
3862 {
3863 	GFileInfo *fsinfo;
3864 	char *ret;
3865 
3866 	ret = NULL;
3867 
3868 	fsinfo = g_file_query_filesystem_info (file,
3869 					       G_FILE_ATTRIBUTE_FILESYSTEM_TYPE,
3870 					       cancellable,
3871 					       NULL);
3872 	if (fsinfo != NULL) {
3873 		ret = g_strdup (g_file_info_get_attribute_string (fsinfo, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE));
3874 		g_object_unref (fsinfo);
3875 	}
3876 
3877 	if (ret == NULL) {
3878 		/* ensure that we don't attempt to query
3879 		 * the FS type for each file in a given
3880 		 * directory, if it can't be queried. */
3881 		ret = g_strdup ("");
3882 	}
3883 
3884 	return ret;
3885 }
3886 
3887 static gboolean
3888 is_trusted_desktop_file (GFile *file,
3889 			 GCancellable *cancellable)
3890 {
3891 	char *basename;
3892 	gboolean res;
3893 	GFileInfo *info;
3894 
3895 	/* Don't trust non-local files */
3896 	if (!g_file_is_native (file)) {
3897 		return FALSE;
3898 	}
3899 	
3900 	basename = g_file_get_basename (file);
3901 	if (!g_str_has_suffix (basename, ".desktop")) {
3902 		g_free (basename);
3903 		return FALSE;
3904 	}
3905 	g_free (basename);
3906 
3907 	info = g_file_query_info (file, 
3908 				  G_FILE_ATTRIBUTE_STANDARD_TYPE ","
3909 				  G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE,
3910 				  G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
3911 				  cancellable,
3912 				  NULL);
3913 
3914 	if (info == NULL) {
3915 		return FALSE;
3916 	}
3917 
3918 	res = FALSE;
3919 	
3920 	/* Weird file => not trusted,
3921 	   Already executable => no need to mark trusted */
3922 	if (g_file_info_get_file_type (info) == G_FILE_TYPE_REGULAR &&
3923 	    !g_file_info_get_attribute_boolean (info,
3924 						G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE) &&
3925 	    nautilus_is_in_system_dir (file)) {
3926 		res = TRUE;
3927 	}
3928 	g_object_unref (info);
3929 	
3930 	return res;
3931 }
3932 
3933 typedef struct {
3934 	int id;
3935 	char *new_name;
3936 	gboolean apply_to_all;
3937 } ConflictResponseData;
3938 
3939 typedef struct {
3940 	GFile *src;
3941 	GFile *dest;
3942 	GFile *dest_dir;
3943 	GtkWindow *parent;
3944 	ConflictResponseData *resp_data;
3945 } ConflictDialogData;
3946 
3947 static gboolean
3948 do_run_conflict_dialog (gpointer _data)
3949 {
3950 	ConflictDialogData *data = _data;
3951 	GtkWidget *dialog;
3952 	int response;
3953 
3954 	dialog = nautilus_file_conflict_dialog_new (data->parent,
3955 						    data->src,
3956 						    data->dest,
3957 						    data->dest_dir);
3958 	response = gtk_dialog_run (GTK_DIALOG (dialog));
3959 
3960 	if (response == CONFLICT_RESPONSE_RENAME) {
3961 		data->resp_data->new_name = 
3962 			nautilus_file_conflict_dialog_get_new_name (NAUTILUS_FILE_CONFLICT_DIALOG (dialog));
3963 	} else if (response != GTK_RESPONSE_CANCEL ||
3964 		   response != GTK_RESPONSE_NONE) {
3965 		   data->resp_data->apply_to_all =
3966 			   nautilus_file_conflict_dialog_get_apply_to_all 
3967 				(NAUTILUS_FILE_CONFLICT_DIALOG (dialog));
3968 	}
3969 
3970 	data->resp_data->id = response;
3971 
3972 	gtk_widget_destroy (dialog);
3973 
3974 	return FALSE;
3975 }
3976 
3977 static ConflictResponseData *
3978 run_conflict_dialog (CommonJob *job,
3979 		     GFile *src,
3980 		     GFile *dest,
3981 		     GFile *dest_dir)
3982 {
3983 	ConflictDialogData *data;
3984 	ConflictResponseData *resp_data;
3985 
3986 	g_timer_stop (job->time);
3987 
3988 	data = g_slice_new0 (ConflictDialogData);
3989 	data->parent = job->parent_window;
3990 	data->src = src;
3991 	data->dest = dest;
3992 	data->dest_dir = dest_dir;
3993 
3994 	resp_data = g_slice_new0 (ConflictResponseData);
3995 	resp_data->new_name = NULL;
3996 	data->resp_data = resp_data;
3997 
3998 	nautilus_progress_info_pause (job->progress);
3999 	g_io_scheduler_job_send_to_mainloop (job->io_job,
4000 					     do_run_conflict_dialog,
4001 					     data,
4002 					     NULL);
4003 	nautilus_progress_info_resume (job->progress);
4004 
4005 	g_slice_free (ConflictDialogData, data);
4006 
4007 	g_timer_continue (job->time);
4008 
4009 	return resp_data;
4010 }
4011 
4012 static void
4013 conflict_response_data_free (ConflictResponseData *data)
4014 {
4015 	g_free (data->new_name);
4016 	g_slice_free (ConflictResponseData, data);
4017 }
4018 
4019 static GFile *
4020 get_target_file_for_display_name (GFile *dir,
4021 				  const gchar *name)
4022 {
4023 	GFile *dest;
4024 
4025 	dest = NULL;
4026 	dest = g_file_get_child_for_display_name (dir, name, NULL);
4027 
4028 	if (dest == NULL) {
4029 		dest = g_file_get_child (dir, name);
4030 	}
4031 	
4032 	return dest;		
4033 }
4034 
4035 /* Debuting files is non-NULL only for toplevel items */
4036 static void
4037 copy_move_file (CopyMoveJob *copy_job,
4038 		GFile *src,
4039 		GFile *dest_dir,
4040 		gboolean same_fs,
4041 		gboolean unique_names,
4042 		char **dest_fs_type,
4043 		SourceInfo *source_info,
4044 		TransferInfo *transfer_info,
4045 		GHashTable *debuting_files,
4046 		GdkPoint *position,
4047 		gboolean overwrite,
4048 		gboolean *skipped_file,
4049 		gboolean readonly_source_fs)
4050 {
4051 	GFile *dest, *new_dest;
4052 	GError *error;
4053 	GFileCopyFlags flags;
4054 	char *primary, *secondary, *details;
4055 	int response;
4056 	ProgressData pdata;
4057 	gboolean would_recurse, is_merge;
4058 	CommonJob *job;
4059 	gboolean res;
4060 	int unique_name_nr;
4061 	gboolean handled_invalid_filename;
4062 
4063 	job = (CommonJob *)copy_job;
4064 	
4065 	if (should_skip_file (job, src)) {
4066 		*skipped_file = TRUE;
4067 		return;
4068 	}
4069 
4070 	unique_name_nr = 1;
4071 
4072 	/* another file in the same directory might have handled the invalid
4073 	 * filename condition for us
4074 	 */
4075 	handled_invalid_filename = *dest_fs_type != NULL;
4076 
4077 	if (unique_names) {
4078 		dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
4079 	} else if (copy_job->target_name != NULL) {
4080 		dest = get_target_file_with_custom_name (src, dest_dir, *dest_fs_type, same_fs,
4081 							 copy_job->target_name);
4082 	} else {
4083 		dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4084 	}
4085 
4086 	/* Don't allow recursive move/copy into itself.  
4087 	 * (We would get a file system error if we proceeded but it is nicer to 
4088 	 * detect and report it at this level) */
4089 	if (test_dir_is_parent (dest_dir, src)) {
4090 		if (job->skip_all_error) {
4091 			goto out;
4092 		}
4093 		
4094 		/*  the run_warning() frees all strings passed in automatically  */
4095 		primary = copy_job->is_move ? g_strdup (_("You cannot move a folder into itself."))
4096 					    : g_strdup (_("You cannot copy a folder into itself."));
4097 		secondary = g_strdup (_("The destination folder is inside the source folder."));
4098 		
4099 		response = run_warning (job,
4100 					primary,
4101 					secondary,
4102 					NULL,
4103 					(source_info->num_files - transfer_info->num_files) > 1,
4104 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4105 					NULL);
4106 
4107 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4108 			abort_job (job);
4109 		} else if (response == 1) { /* skip all */
4110 			job->skip_all_error = TRUE;
4111 		} else if (response == 2) { /* skip */
4112 			/* do nothing */
4113 		} else {
4114 			g_assert_not_reached ();
4115 		}
4116 
4117 		goto out;
4118 	}
4119 
4120 	/* Don't allow copying over the source or one of the parents of the source.
4121 	 */
4122 	if (test_dir_is_parent (src, dest)) {
4123 		if (job->skip_all_error) {
4124 			goto out;
4125 		}
4126 		
4127 		/*  the run_warning() frees all strings passed in automatically  */
4128 		primary = copy_job->is_move ? g_strdup (_("You cannot move a file over itself."))
4129 					    : g_strdup (_("You cannot copy a file over itself."));
4130 		secondary = g_strdup (_("The source file would be overwritten by the destination."));
4131 		
4132 		response = run_warning (job,
4133 					primary,
4134 					secondary,
4135 					NULL,
4136 					(source_info->num_files - transfer_info->num_files) > 1,
4137 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4138 					NULL);
4139 
4140 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4141 			abort_job (job);
4142 		} else if (response == 1) { /* skip all */
4143 			job->skip_all_error = TRUE;
4144 		} else if (response == 2) { /* skip */
4145 			/* do nothing */
4146 		} else {
4147 			g_assert_not_reached ();
4148 		}
4149 
4150 		goto out;
4151 	}
4152 
4153 	
4154  retry:
4155 	
4156 	error = NULL;
4157 	flags = G_FILE_COPY_NOFOLLOW_SYMLINKS;
4158 	if (overwrite) {
4159 		flags |= G_FILE_COPY_OVERWRITE;
4160 	}
4161 	if (readonly_source_fs) {
4162 		flags |= G_FILE_COPY_TARGET_DEFAULT_PERMS;
4163 	}
4164 
4165 	pdata.job = copy_job;
4166 	pdata.last_size = 0;
4167 	pdata.source_info = source_info;
4168 	pdata.transfer_info = transfer_info;
4169 
4170 	if (copy_job->is_move) {
4171 		res = g_file_move (src, dest,
4172 				   flags,
4173 				   job->cancellable,
4174 				   copy_file_progress_callback,
4175 				   &pdata,
4176 				   &error);
4177 	} else {
4178 		res = g_file_copy (src, dest,
4179 				   flags,
4180 				   job->cancellable,
4181 				   copy_file_progress_callback,
4182 				   &pdata,
4183 				   &error);
4184 	}
4185 	
4186 	if (res) {
4187 		transfer_info->num_files ++;
4188 		report_copy_progress (copy_job, source_info, transfer_info);
4189 
4190 		if (debuting_files) {
4191 			if (position) {
4192 				nautilus_file_changes_queue_schedule_position_set (dest, *position, job->screen_num);
4193 			} else {
4194 				nautilus_file_changes_queue_schedule_position_remove (dest);
4195 			}
4196 			
4197 			g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE));
4198 		}
4199 		if (copy_job->is_move) {
4200 			nautilus_file_changes_queue_file_moved (src, dest);
4201 		} else {
4202 			nautilus_file_changes_queue_file_added (dest);
4203 		}
4204 
4205 		/* If copying a trusted desktop file to the desktop,
4206 		   mark it as trusted. */
4207 		if (copy_job->desktop_location != NULL &&
4208 		    g_file_equal (copy_job->desktop_location, dest_dir) &&
4209 		    is_trusted_desktop_file (src, job->cancellable)) {
4210 			mark_desktop_file_trusted (job,
4211 						   job->cancellable,
4212 						   dest,
4213 						   FALSE);
4214 		}
4215 
4216 		if (job->undo_info != NULL) {
4217 			nautilus_file_undo_info_ext_add_origin_target_pair (NAUTILUS_FILE_UNDO_INFO_EXT (job->undo_info),
4218 									    src, dest);
4219 		}
4220 
4221 		g_object_unref (dest);
4222 		return;
4223 	}
4224 
4225 	if (!handled_invalid_filename &&
4226 	    IS_IO_ERROR (error, INVALID_FILENAME)) {
4227 		handled_invalid_filename = TRUE;
4228 
4229 		g_assert (*dest_fs_type == NULL);
4230 		*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
4231 
4232 		if (unique_names) {
4233 			new_dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr);
4234 		} else {
4235 			new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4236 		}
4237 
4238 		if (!g_file_equal (dest, new_dest)) {
4239 			g_object_unref (dest);
4240 			dest = new_dest;
4241 
4242 			g_error_free (error);
4243 			goto retry;
4244 		} else {
4245 			g_object_unref (new_dest);
4246 		}
4247 	}
4248 
4249 	/* Conflict */
4250 	if (!overwrite &&
4251 	    IS_IO_ERROR (error, EXISTS)) {
4252 		gboolean is_merge;
4253 		ConflictResponseData *response;
4254 
4255 		g_error_free (error);
4256 
4257 		if (unique_names) {
4258 			g_object_unref (dest);
4259 			dest = get_unique_target_file (src, dest_dir, same_fs, *dest_fs_type, unique_name_nr++);
4260 			goto retry;
4261 		}
4262 
4263 		is_merge = FALSE;
4264 
4265 		if (is_dir (dest) && is_dir (src)) {
4266 			is_merge = TRUE;
4267 		}
4268 
4269 		if ((is_merge && job->merge_all) ||
4270 		    (!is_merge && job->replace_all)) {
4271 			overwrite = TRUE;
4272 			goto retry;
4273 		}
4274 
4275 		if (job->skip_all_conflict) {
4276 			goto out;
4277 		}
4278 
4279 		response = run_conflict_dialog (job, src, dest, dest_dir);	
4280 
4281 		if (response->id == GTK_RESPONSE_CANCEL ||
4282 		    response->id == GTK_RESPONSE_DELETE_EVENT) {
4283 			conflict_response_data_free (response);
4284 			abort_job (job);
4285 		} else if (response->id == CONFLICT_RESPONSE_SKIP) {
4286 			if (response->apply_to_all) {
4287 				job->skip_all_conflict = TRUE;
4288 			}
4289 			conflict_response_data_free (response);
4290 		} else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
4291 			if (response->apply_to_all) {
4292 				if (is_merge) {
4293 					job->merge_all = TRUE;
4294 				} else {
4295 					job->replace_all = TRUE;
4296 				}
4297 			}
4298 			overwrite = TRUE;
4299 			conflict_response_data_free (response);
4300 			goto retry;
4301 		} else if (response->id == CONFLICT_RESPONSE_RENAME) {
4302 			g_object_unref (dest);
4303 			dest = get_target_file_for_display_name (dest_dir,
4304 								 response->new_name);
4305 			conflict_response_data_free (response);
4306 			goto retry;
4307 		} else {
4308 			g_assert_not_reached ();
4309 		}
4310 	}
4311 	
4312 	else if (overwrite &&
4313 		 IS_IO_ERROR (error, IS_DIRECTORY)) {
4314 
4315 		g_error_free (error);
4316 		
4317 		if (remove_target_recursively (job, src, dest, dest)) {
4318 			goto retry;
4319 		}
4320 	}
4321 	
4322 	/* Needs to recurse */
4323 	else if (IS_IO_ERROR (error, WOULD_RECURSE) ||
4324 		 IS_IO_ERROR (error, WOULD_MERGE)) {
4325 		is_merge = error->code == G_IO_ERROR_WOULD_MERGE;
4326 		would_recurse = error->code == G_IO_ERROR_WOULD_RECURSE;
4327 		g_error_free (error);
4328 
4329 		if (overwrite && would_recurse) {
4330 			error = NULL;
4331 			
4332 			/* Copying a dir onto file, first remove the file */
4333 			if (!g_file_delete (dest, job->cancellable, &error) &&
4334 			    !IS_IO_ERROR (error, NOT_FOUND)) {
4335 				if (job->skip_all_error) {
4336 					g_error_free (error);
4337 					goto out;
4338 				}
4339 				if (copy_job->is_move) {
4340 					primary = f (_("Error while moving “%B”."), src);
4341 				} else {
4342 					primary = f (_("Error while copying “%B”."), src);
4343 				}
4344 				secondary = f (_("Could not remove the already existing file with the same name in %F."), dest_dir);
4345 				details = error->message;
4346 
4347 				/* setting TRUE on show_all here, as we could have
4348 				 * another error on the same file later.
4349 				 */
4350 				response = run_warning (job,
4351 							primary,
4352 							secondary,
4353 							details,
4354 							TRUE,
4355 							GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4356 							NULL);
4357 				
4358 				g_error_free (error);
4359 				
4360 				if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4361 					abort_job (job);
4362 				} else if (response == 1) { /* skip all */
4363 					job->skip_all_error = TRUE;
4364 				} else if (response == 2) { /* skip */
4365 					/* do nothing */
4366 				} else {
4367 					g_assert_not_reached ();
4368 				}
4369 				goto out;
4370 				
4371 			}
4372 			if (error) {
4373 				g_error_free (error);
4374 				error = NULL;
4375 			}
4376 			nautilus_file_changes_queue_file_removed (dest);
4377 		}
4378 
4379 		if (is_merge) {
4380 			/* On merge we now write in the target directory, which may not
4381 			   be in the same directory as the source, even if the parent is
4382 			   (if the merged directory is a mountpoint). This could cause
4383 			   problems as we then don't transcode filenames.
4384 			   We just set same_fs to FALSE which is safe but a bit slower. */
4385 			same_fs = FALSE;
4386 		}
4387 		
4388 		if (!copy_move_directory (copy_job, src, &dest, same_fs,
4389 					  would_recurse, dest_fs_type,
4390 					  source_info, transfer_info,
4391 					  debuting_files, skipped_file,
4392 					  readonly_source_fs)) {
4393 			/* destination changed, since it was an invalid file name */
4394 			g_assert (*dest_fs_type != NULL);
4395 			handled_invalid_filename = TRUE;
4396 			goto retry;
4397 		}
4398 
4399 		g_object_unref (dest);
4400 		return;
4401 	}
4402 	
4403 	else if (IS_IO_ERROR (error, CANCELLED)) {
4404 		g_error_free (error);
4405 	}
4406 	
4407 	/* Other error */
4408 	else {
4409 		if (job->skip_all_error) {
4410 			g_error_free (error);
4411 			goto out;
4412 		}
4413 		primary = f (_("Error while copying “%B”."), src);
4414 		secondary = f (_("There was an error copying the file into %F."), dest_dir);
4415 		details = error->message;
4416 		
4417 		response = run_warning (job,
4418 					primary,
4419 					secondary,
4420 					details,
4421 					(source_info->num_files - transfer_info->num_files) > 1,
4422 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4423 					NULL);
4424 
4425 		g_error_free (error);
4426 		
4427 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4428 			abort_job (job);
4429 		} else if (response == 1) { /* skip all */
4430 			job->skip_all_error = TRUE;
4431 		} else if (response == 2) { /* skip */
4432 			/* do nothing */
4433 		} else {
4434 			g_assert_not_reached ();
4435 		}
4436 	}
4437  out:
4438 	*skipped_file = TRUE; /* Or aborted, but same-same */
4439 	g_object_unref (dest);
4440 }
4441 
4442 static void
4443 copy_files (CopyMoveJob *job,
4444 	    const char *dest_fs_id,
4445 	    SourceInfo *source_info,
4446 	    TransferInfo *transfer_info)
4447 {
4448 	CommonJob *common;
4449 	GList *l;
4450 	GFile *src;
4451 	gboolean same_fs;
4452 	int i;
4453 	GdkPoint *point;
4454 	gboolean skipped_file;
4455 	gboolean unique_names;
4456 	GFile *dest;
4457 	GFile *source_dir;
4458 	char *dest_fs_type;
4459 	GFileInfo *inf;
4460 	gboolean readonly_source_fs;
4461 
4462 	dest_fs_type = NULL;
4463 	readonly_source_fs = FALSE;
4464 
4465 	common = &job->common;
4466 
4467 	report_copy_progress (job, source_info, transfer_info);
4468 
4469 	/* Query the source dir, not the file because if its a symlink we'll follow it */
4470 	source_dir = g_file_get_parent ((GFile *) job->files->data);
4471 	if (source_dir) {
4472 		inf = g_file_query_filesystem_info (source_dir, "filesystem::readonly", NULL, NULL);
4473 		if (inf != NULL) {
4474 			readonly_source_fs = g_file_info_get_attribute_boolean (inf, "filesystem::readonly");
4475 			g_object_unref (inf);
4476 		}
4477 		g_object_unref (source_dir);
4478 	}
4479 
4480 	unique_names = (job->destination == NULL);
4481 	i = 0;
4482 	for (l = job->files;
4483 	     l != NULL && !job_aborted (common);
4484 	     l = l->next) {
4485 		src = l->data;
4486 
4487 		if (i < job->n_icon_positions) {
4488 			point = &job->icon_positions[i];
4489 		} else {
4490 			point = NULL;
4491 		}
4492 
4493 		
4494 		same_fs = FALSE;
4495 		if (dest_fs_id) {
4496 			same_fs = has_fs_id (src, dest_fs_id);
4497 		}
4498 
4499 		if (job->destination) {
4500 			dest = g_object_ref (job->destination);
4501 		} else {
4502 			dest = g_file_get_parent (src);
4503 			
4504 		}
4505 		if (dest) {
4506 			skipped_file = FALSE;
4507 			copy_move_file (job, src, dest,
4508 					same_fs, unique_names,
4509 					&dest_fs_type,
4510 					source_info, transfer_info,
4511 					job->debuting_files,
4512 					point, FALSE, &skipped_file,
4513 					readonly_source_fs);
4514 			g_object_unref (dest);
4515 		}
4516 		i++;
4517 	}
4518 
4519 	g_free (dest_fs_type);
4520 }
4521 
4522 static gboolean
4523 copy_job_done (gpointer user_data)
4524 {
4525 	CopyMoveJob *job;
4526 
4527 	job = user_data;
4528 	if (job->done_callback) {
4529 		job->done_callback (job->debuting_files, 
4530 				    !job_aborted ((CommonJob *) job),
4531 				    job->done_callback_data);
4532 	}
4533 
4534 	g_list_free_full (job->files, g_object_unref);
4535 	if (job->destination) {
4536 		g_object_unref (job->destination);
4537 	}
4538 	if (job->desktop_location) {
4539 		g_object_unref (job->desktop_location);
4540 	}
4541 	g_hash_table_unref (job->debuting_files);
4542 	g_free (job->icon_positions);
4543 	g_free (job->target_name);
4544 
4545 	g_clear_object (&job->fake_display_source);
4546 	
4547 	finalize_common ((CommonJob *)job);
4548 
4549 	nautilus_file_changes_consume_changes (TRUE);
4550 	return FALSE;
4551 }
4552 
4553 static gboolean
4554 copy_job (GIOSchedulerJob *io_job,
4555 	  GCancellable *cancellable,
4556 	  gpointer user_data)
4557 {
4558 	CopyMoveJob *job;
4559 	CommonJob *common;
4560 	SourceInfo source_info;
4561 	TransferInfo transfer_info;
4562 	char *dest_fs_id;
4563 	GFile *dest;
4564 
4565 	job = user_data;
4566 	common = &job->common;
4567 	common->io_job = io_job;
4568 
4569 	dest_fs_id = NULL;
4570 	
4571 	nautilus_progress_info_start (job->common.progress);
4572 	
4573 	scan_sources (job->files,
4574 		      &source_info,
4575 		      common,
4576 		      OP_KIND_COPY);
4577 	if (job_aborted (common)) {
4578 		goto aborted;
4579 	}
4580 
4581 	if (job->destination) {
4582 		dest = g_object_ref (job->destination);
4583 	} else {
4584 		/* Duplication, no dest,
4585 		 * use source for free size, etc
4586 		 */
4587 		dest = g_file_get_parent (job->files->data);
4588 	}
4589 	
4590 	verify_destination (&job->common,
4591 			    dest,
4592 			    &dest_fs_id,
4593 			    source_info.num_bytes);
4594 	g_object_unref (dest);
4595 	if (job_aborted (common)) {
4596 		goto aborted;
4597 	}
4598 
4599 	g_timer_start (job->common.time);
4600 	
4601 	memset (&transfer_info, 0, sizeof (transfer_info));
4602 	copy_files (job,
4603 		    dest_fs_id,
4604 		    &source_info, &transfer_info);
4605 
4606  aborted:
4607 	
4608 	g_free (dest_fs_id);
4609 	
4610 	g_io_scheduler_job_send_to_mainloop_async (io_job,
4611 						   copy_job_done,
4612 						   job,
4613 						   NULL);
4614 
4615 	return FALSE;
4616 }
4617 
4618 void
4619 nautilus_file_operations_copy_file (GFile *source_file,
4620 				    GFile *target_dir,
4621 				    const gchar *source_display_name,
4622 				    const gchar *new_name,
4623 				    GtkWindow *parent_window,
4624 				    NautilusCopyCallback done_callback,
4625 				    gpointer done_callback_data)
4626 {
4627 	CopyMoveJob *job;
4628 
4629 	job = op_job_new (CopyMoveJob, parent_window);
4630 	job->done_callback = done_callback;
4631 	job->done_callback_data = done_callback_data;
4632 	job->files = g_list_append (NULL, g_object_ref (source_file));
4633 	job->destination = g_object_ref (target_dir);
4634 	job->target_name = g_strdup (new_name);
4635 	job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
4636 
4637 	if (source_display_name != NULL) {
4638 		gchar *path;
4639 
4640 		path = g_build_filename ("/", source_display_name, NULL);
4641 		job->fake_display_source = g_file_new_for_path (path);
4642 
4643 		g_free (path);
4644 	}
4645 
4646 	inhibit_power_manager ((CommonJob *)job, _("Copying Files"));
4647 
4648 	g_io_scheduler_push_job (copy_job,
4649 			   job,
4650 			   NULL, /* destroy notify */
4651 			   0,
4652 			   job->common.cancellable);
4653 }
4654 
4655 void
4656 nautilus_file_operations_copy (GList *files,
4657 			       GArray *relative_item_points,
4658 			       GFile *target_dir,
4659 			       GtkWindow *parent_window,
4660 			       NautilusCopyCallback  done_callback,
4661 			       gpointer done_callback_data)
4662 {
4663 	CopyMoveJob *job;
4664 
4665 	job = op_job_new (CopyMoveJob, parent_window);
4666 	job->desktop_location = nautilus_get_desktop_location ();
4667 	job->done_callback = done_callback;
4668 	job->done_callback_data = done_callback_data;
4669 	job->files = eel_g_object_list_copy (files);
4670 	job->destination = g_object_ref (target_dir);
4671 	if (relative_item_points != NULL &&
4672 	    relative_item_points->len > 0) {
4673 		job->icon_positions =
4674 			g_memdup (relative_item_points->data,
4675 				  sizeof (GdkPoint) * relative_item_points->len);
4676 		job->n_icon_positions = relative_item_points->len;
4677 	}
4678 	job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
4679 
4680 	inhibit_power_manager ((CommonJob *)job, _("Copying Files"));
4681 
4682 	if (!nautilus_file_undo_manager_pop_flag ()) {
4683 		GFile* src_dir;
4684 
4685 		src_dir = g_file_get_parent (files->data);
4686 		job->common.undo_info = nautilus_file_undo_info_ext_new (NAUTILUS_FILE_UNDO_OP_COPY,
4687 									 g_list_length (files),
4688 									 src_dir, target_dir);
4689 
4690 		g_object_unref (src_dir);
4691 	}
4692 
4693 	g_io_scheduler_push_job (copy_job,
4694 			   job,
4695 			   NULL, /* destroy notify */
4696 			   0,
4697 			   job->common.cancellable);
4698 }
4699 
4700 static void
4701 report_move_progress (CopyMoveJob *move_job, int total, int left)
4702 {
4703 	CommonJob *job;
4704 
4705 	job = (CommonJob *)move_job;
4706 	
4707 	nautilus_progress_info_take_status (job->progress,
4708 					    f (_("Preparing to Move to “%B”"),
4709 					       move_job->destination));
4710 
4711 	nautilus_progress_info_take_details (job->progress,
4712 					     f (ngettext ("Preparing to move %'d file",
4713 							  "Preparing to move %'d files",
4714 							  left), left));
4715 
4716 	nautilus_progress_info_pulse_progress (job->progress);
4717 }
4718 
4719 typedef struct {
4720 	GFile *file;
4721 	gboolean overwrite;
4722 	gboolean has_position;
4723 	GdkPoint position;
4724 } MoveFileCopyFallback;
4725 
4726 static MoveFileCopyFallback *
4727 move_copy_file_callback_new (GFile *file,
4728 			     gboolean overwrite,
4729 			     GdkPoint *position)
4730 {
4731 	MoveFileCopyFallback *fallback;
4732 
4733 	fallback = g_new (MoveFileCopyFallback, 1);
4734 	fallback->file = file;
4735 	fallback->overwrite = overwrite;
4736 	if (position) {
4737 		fallback->has_position = TRUE;
4738 		fallback->position = *position;
4739 	} else {
4740 		fallback->has_position = FALSE;
4741 	}
4742 
4743 	return fallback;
4744 }
4745 
4746 static GList *
4747 get_files_from_fallbacks (GList *fallbacks)
4748 {
4749 	MoveFileCopyFallback *fallback;
4750 	GList *res, *l;
4751 
4752 	res = NULL;
4753 	for (l = fallbacks; l != NULL; l = l->next) {
4754 		fallback = l->data;
4755 		res = g_list_prepend (res, fallback->file);
4756 	}
4757 	return g_list_reverse (res);
4758 }
4759 
4760 static void
4761 move_file_prepare (CopyMoveJob *move_job,
4762 		   GFile *src,
4763 		   GFile *dest_dir,
4764 		   gboolean same_fs,
4765 		   char **dest_fs_type,
4766 		   GHashTable *debuting_files,
4767 		   GdkPoint *position,
4768 		   GList **fallback_files,
4769 		   int files_left)
4770 {
4771 	GFile *dest, *new_dest;
4772 	GError *error;
4773 	CommonJob *job;
4774 	gboolean overwrite;
4775 	char *primary, *secondary, *details;
4776 	int response;
4777 	GFileCopyFlags flags;
4778 	MoveFileCopyFallback *fallback;
4779 	gboolean handled_invalid_filename;
4780 
4781 	overwrite = FALSE;
4782 	handled_invalid_filename = *dest_fs_type != NULL;
4783 
4784 	job = (CommonJob *)move_job;
4785 	
4786 	dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4787 
4788 
4789 	/* Don't allow recursive move/copy into itself.  
4790 	 * (We would get a file system error if we proceeded but it is nicer to 
4791 	 * detect and report it at this level) */
4792 	if (test_dir_is_parent (dest_dir, src)) {
4793 		if (job->skip_all_error) {
4794 			goto out;
4795 		}
4796 		
4797 		/*  the run_warning() frees all strings passed in automatically  */
4798 		primary = move_job->is_move ? g_strdup (_("You cannot move a folder into itself."))
4799 					    : g_strdup (_("You cannot copy a folder into itself."));
4800 		secondary = g_strdup (_("The destination folder is inside the source folder."));
4801 		
4802 		response = run_warning (job,
4803 					primary,
4804 					secondary,
4805 					NULL,
4806 					files_left > 1,
4807 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4808 					NULL);
4809 		
4810 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4811 			abort_job (job);
4812 		} else if (response == 1) { /* skip all */
4813 			job->skip_all_error = TRUE;
4814 		} else if (response == 2) { /* skip */
4815 			/* do nothing */
4816 		} else {
4817 			g_assert_not_reached ();
4818 		}
4819 
4820 		goto out;
4821 	}
4822 
4823  retry:
4824 	
4825 	flags = G_FILE_COPY_NOFOLLOW_SYMLINKS | G_FILE_COPY_NO_FALLBACK_FOR_MOVE;
4826 	if (overwrite) {
4827 		flags |= G_FILE_COPY_OVERWRITE;
4828 	}
4829 	
4830 	error = NULL;
4831 	if (g_file_move (src, dest,
4832 			 flags,
4833 			 job->cancellable,
4834 			 NULL,
4835 			 NULL,
4836 			 &error)) {
4837 		
4838 		if (debuting_files) {
4839 			g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE));
4840 		}
4841 
4842 		nautilus_file_changes_queue_file_moved (src, dest);
4843 
4844 		if (position) {
4845 			nautilus_file_changes_queue_schedule_position_set (dest, *position, job->screen_num);
4846 		} else {
4847 			nautilus_file_changes_queue_schedule_position_remove (dest);
4848 		}
4849 
4850 		if (job->undo_info != NULL) {
4851 			nautilus_file_undo_info_ext_add_origin_target_pair (NAUTILUS_FILE_UNDO_INFO_EXT (job->undo_info),
4852 									    src, dest);
4853 		}
4854 
4855 		return;
4856 	}
4857 
4858 	if (IS_IO_ERROR (error, INVALID_FILENAME) &&
4859 	    !handled_invalid_filename) {
4860 		g_error_free (error);
4861 
4862 		handled_invalid_filename = TRUE;
4863 
4864 		g_assert (*dest_fs_type == NULL);
4865 		*dest_fs_type = query_fs_type (dest_dir, job->cancellable);
4866 
4867 		new_dest = get_target_file (src, dest_dir, *dest_fs_type, same_fs);
4868 		if (!g_file_equal (dest, new_dest)) {
4869 			g_object_unref (dest);
4870 			dest = new_dest;
4871 			goto retry;
4872 		} else {
4873 			g_object_unref (new_dest);
4874 		}
4875 	}
4876 
4877 	/* Conflict */
4878 	else if (!overwrite &&
4879 		 IS_IO_ERROR (error, EXISTS)) {
4880 		gboolean is_merge;
4881 		ConflictResponseData *response;
4882 		
4883 		g_error_free (error);
4884 
4885 		is_merge = FALSE;
4886 		if (is_dir (dest) && is_dir (src)) {
4887 			is_merge = TRUE;
4888 		}
4889 
4890 		if ((is_merge && job->merge_all) ||
4891 		    (!is_merge && job->replace_all)) {
4892 			overwrite = TRUE;
4893 			goto retry;
4894 		}
4895 
4896 		if (job->skip_all_conflict) {
4897 			goto out;
4898 		}
4899 
4900 		response = run_conflict_dialog (job, src, dest, dest_dir);
4901 
4902 		if (response->id == GTK_RESPONSE_CANCEL ||
4903 		    response->id == GTK_RESPONSE_DELETE_EVENT) {
4904 			conflict_response_data_free (response);	
4905 			abort_job (job);
4906 		} else if (response->id == CONFLICT_RESPONSE_SKIP) {
4907 			if (response->apply_to_all) {
4908 				job->skip_all_conflict = TRUE;
4909 			}
4910 			conflict_response_data_free (response);
4911 		} else if (response->id == CONFLICT_RESPONSE_REPLACE) { /* merge/replace */
4912 			if (response->apply_to_all) {
4913 				if (is_merge) {
4914 					job->merge_all = TRUE;
4915 				} else {
4916 					job->replace_all = TRUE;
4917 				}
4918 			}
4919 			overwrite = TRUE;
4920 			conflict_response_data_free (response);
4921 			goto retry;
4922 		} else if (response->id == CONFLICT_RESPONSE_RENAME) {
4923 			g_object_unref (dest);
4924 			dest = get_target_file_for_display_name (dest_dir,
4925 								 response->new_name);
4926 			conflict_response_data_free (response);
4927 			goto retry;
4928 		} else {
4929 			g_assert_not_reached ();
4930 		}
4931 	}
4932 
4933 	else if (IS_IO_ERROR (error, WOULD_RECURSE) ||
4934 		 IS_IO_ERROR (error, WOULD_MERGE) ||
4935 		 IS_IO_ERROR (error, NOT_SUPPORTED) ||
4936 		 (overwrite && IS_IO_ERROR (error, IS_DIRECTORY))) {
4937 		g_error_free (error);
4938 		
4939 		fallback = move_copy_file_callback_new (src,
4940 							overwrite, 
4941 							position);
4942 		*fallback_files = g_list_prepend (*fallback_files, fallback);
4943 	}
4944 	
4945 	else if (IS_IO_ERROR (error, CANCELLED)) {
4946 		g_error_free (error);
4947 	}
4948 	
4949 	/* Other error */
4950 	else {
4951 		if (job->skip_all_error) {
4952 			g_error_free (error);
4953 			goto out;
4954 		}
4955 		primary = f (_("Error while moving “%B”."), src);
4956 		secondary = f (_("There was an error moving the file into %F."), dest_dir);
4957 		details = error->message;
4958 		
4959 		response = run_warning (job,
4960 					primary,
4961 					secondary,
4962 					details,
4963 					files_left > 1,
4964 					GTK_STOCK_CANCEL, SKIP_ALL, SKIP,
4965 					NULL);
4966 
4967 		g_error_free (error);
4968 		
4969 		if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) {
4970 			abort_job (job);
4971 		} else if (response == 1) { /* skip all */
4972 			job->skip_all_error = TRUE;
4973 		} else if (response == 2) { /* skip */
4974 			/* do nothing */
4975 		} else {
4976 			g_assert_not_reached ();
4977 		}
4978 	}
4979 	
4980  out:
4981 	g_object_unref (dest);
4982 }
4983 
4984 static void
4985 move_files_prepare (CopyMoveJob *job,
4986 		    const char *dest_fs_id,
4987 		    char **dest_fs_type,
4988 		    GList **fallbacks)
4989 {
4990 	CommonJob *common;
4991 	GList *l;
4992 	GFile *src;
4993 	gboolean same_fs;
4994 	int i;
4995 	GdkPoint *point;
4996 	int total, left;
4997 
4998 	common = &job->common;
4999 
5000 	total = left = g_list_length (job->files);
5001 
5002 	report_move_progress (job, total, left);
5003 
5004 	i = 0;
5005 	for (l = job->files;
5006 	     l != NULL && !job_aborted (common);
5007 	     l = l->next) {
5008 		src = l->data;
5009 
5010 		if (i < job->n_icon_positions) {
5011 			point = &job->icon_positions[i];
5012 		} else {
5013 			point = NULL;
5014 		}
5015 
5016 		
5017 		same_fs = FALSE;
5018 		if (dest_fs_id) {
5019 			same_fs = has_fs_id (src, dest_fs_id);
5020 		}
5021 		
5022 		move_file_prepare (job, src, job->destination,
5023 				   same_fs, dest_fs_type,
5024 				   job->debuting_files,
5025 				   point,
5026 				   fallbacks,
5027 				   left);
5028 		report_move_progress (job, total, --left);
5029 		i++;
5030 	}
5031 
5032 	*fallbacks = g_list_reverse (*fallbacks);
5033 
5034 	
5035 }
5036 
5037 static void
5038 move_files (CopyMoveJob *job,
5039 	    GList *fallbacks,
5040 	    const char *dest_fs_id,
5041 	    char **dest_fs_type,
5042 	    SourceInfo *source_info,
5043 	    TransferInfo *transfer_info)
5044 {
5045 	CommonJob *common;
5046 	GList *l;
5047 	GFile *src;
5048 	gboolean same_fs;
5049 	int i;
5050 	GdkPoint *point;
5051 	gboolean skipped_file;
5052 	MoveFileCopyFallback *fallback;
5053 common = &job->common;
5054 
5055 	report_copy_progress (job, source_info, transfer_info);
5056 	
5057 	i = 0;
5058 	for (l = fallbacks;
5059 	     l != NULL && !job_aborted (common);
5060 	     l = l->next) {
5061 		fallback = l->data;
5062 		src = fallback->file;
5063 
5064 		if (fallback->has_position) {
5065 			point = &fallback->position;
5066 		} else {
5067 			point = NULL;
5068 		}
5069 		
5070 		same_fs = FALSE;
5071 		if (dest_fs_id) {
5072 			same_fs = has_fs_id (src, dest_fs_id);
5073 		}
5074 
5075 		/* Set overwrite to true, as the user has
5076 		   selected overwrite on all toplevel items */
5077 		skipped_file = FALSE;
5078 		copy_move_file (job, src, job->destination,
5079 				same_fs, FALSE, dest_fs_type,
5080 				source_info, transfer_info,
5081 				job->debuting_files,
5082 				point, fallback->overwrite, &skipped_file, FALSE);
5083 		i++;
5084 	}
5085 }
5086 
5087 
5088 static gboolean
5089 move_job_done (gpointer user_data)
5090 {
5091 	CopyMoveJob *job;
5092 
5093 	job = user_data;
5094 	if (job->done_callback) {
5095 		job->done_callback (job->debuting_files,
5096 				    !job_aborted ((CommonJob *) job),
5097 				    job->done_callback_data);
5098 	}
5099 
5100 	g_list_free_full (job->files, g_object_unref);
5101 	g_object_unref (job->destination);
5102 	g_hash_table_unref (job->debuting_files);
5103 	g_free (job->icon_positions);
5104 	
5105 	finalize_common ((CommonJob *)job);
5106 
5107 	nautilus_file_changes_consume_changes (TRUE);
5108 	return FALSE;
5109 }
5110 
5111 static gboolean
5112 move_job (GIOSchedulerJob *io_job,
5113 	  GCancellable *cancellable,
5114 	  gpointer user_data)
5115 {
5116 	CopyMoveJob *job;
5117 	CommonJob *common;
5118 	GList *fallbacks;
5119 	SourceInfo source_info;
5120 	TransferInfo transfer_info;
5121 	char *dest_fs_id;
5122 	char *dest_fs_type;
5123 	GList *fallback_files;
5124 
5125 	job = user_data;
5126 	common = &job->common;
5127 	common->io_job = io_job;
5128 
5129 	dest_fs_id = NULL;
5130 	dest_fs_type = NULL;
5131 
5132 	fallbacks = NULL;
5133 	
5134 	nautilus_progress_info_start (job->common.progress);
5135 	
5136 	verify_destination (&job->common,
5137 			    job->destination,
5138 			    &dest_fs_id,
5139 			    -1);
5140 	if (job_aborted (common)) {
5141 		goto aborted;
5142 	}
5143 
5144 	/* This moves all files that we can do without copy + delete */
5145 	move_files_prepare (job, dest_fs_id, &dest_fs_type, &fallbacks);
5146 	if (job_aborted (common)) {
5147 		goto aborted;
5148 	}
5149 
5150 	/* The rest we need to do deep copy + delete behind on,
5151 	   so scan for size */
5152 
5153 	fallback_files = get_files_from_fallbacks (fallbacks);
5154 	scan_sources (fallback_files,
5155 		      &source_info,
5156 		      common,
5157 		      OP_KIND_MOVE);
5158 	
5159 	g_list_free (fallback_files);
5160 	
5161 	if (job_aborted (common)) {
5162 		goto aborted;
5163 	}
5164 
5165 	verify_destination (&job->common,
5166 			    job->destination,
5167 			    NULL,
5168 			    source_info.num_bytes);
5169 	if (job_aborted (common)) {
5170 		goto aborted;
5171 	}
5172 
5173 	memset (&transfer_info, 0, sizeof (transfer_info));
5174 	move_files (job,
5175 		    fallbacks,
5176 		    dest_fs_id, &dest_fs_type,
5177 		    &source_info, &transfer_info);
5178 
5179  aborted:
5180 	g_list_free_full (fallbacks, g_free);
5181 
5182 	g_free (dest_fs_id);
5183 	g_free (dest_fs_type);
5184 	
5185 	g_io_scheduler_job_send_to_mainloop (io_job,
5186 					     move_job_done,
5187 					     job,
5188 					     NULL);
5189 
5190 	return FALSE;
5191 }
5192 
5193 void
5194 nautilus_file_operations_move (GList *files,
5195 			       GArray *relative_item_points,
5196 			       GFile *target_dir,
5197 			       GtkWindow *parent_window,
5198 			       NautilusCopyCallback  done_callback,
5199 			       gpointer done_callback_data)
5200 {
5201 	CopyMoveJob *job;
5202 
5203 	job = op_job_new (CopyMoveJob, parent_window);
5204 	job->is_move = TRUE;
5205 	job->done_callback = done_callback;
5206 	job->done_callback_data = done_callback_data;
5207 	job->files = eel_g_object_list_copy (files);
5208 	job->destination = g_object_ref (target_dir);
5209 	if (relative_item_points != NULL &&
5210 	    relative_item_points->len > 0) {
5211 		job->icon_positions =
5212 			g_memdup (relative_item_points->data,
5213 				  sizeof (GdkPoint) * relative_item_points->len);
5214 		job->n_icon_positions = relative_item_points->len;
5215 	}
5216 	job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL);
5217 
5218 	inhibit_power_manager ((CommonJob *)job, _("Moving Files"));
5219 
5220 	if (!nautilus_file_undo_manager_pop_flag ()) {
5221 		GFile* src_dir;
5222 
5223 		src_dir = g_file_get_parent (files->data);
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'files')

Possibly related backtrace: 2a2c08219faa5f80a13ebe5a4b1d55d11a493f82 MatchResult(frame_number=1, dist=0)

Possibly related backtrace: 248a2415ad56492f05b0e5efc5d90732be58e935 MatchResult(frame_number=1, dist=0)

Possibly related backtrace: 260c1ab3ca4f7554ba914fdc1daa20edbea74d6d MatchResult(frame_number=1, dist=0)

(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

5224 5225 if (g_file_has_uri_scheme (g_list_first (files)->data, "trash")) { 5226 job->common.undo_info = nautilus_file_undo_info_ext_new (NAUTILUS_FILE_UNDO_OP_RESTORE_FROM_TRASH, 5227 g_list_length (files), 5228 src_dir, target_dir); 5229 } else { 5230 job->common.undo_info = nautilus_file_undo_info_ext_new (NAUTILUS_FILE_UNDO_OP_MOVE, 5231 g_list_length (files), 5232 src_dir, target_dir); 5233 } 5234 5235 g_object_unref (src_dir); 5236 } 5237 5238 g_io_scheduler_push_job (move_job, 5239 job, 5240 NULL, /* destroy notify */ 5241 0, 5242 job->common.cancellable); 5243 } 5244 5245 static void 5246 report_link_progress (CopyMoveJob *link_job, int total, int left) 5247 { 5248 CommonJob *job; 5249 5250 job = (CommonJob *)link_job; 5251 5252 nautilus_progress_info_take_status (job->progress, 5253 f (_("Creating links in “%B”"), 5254 link_job->destination)); 5255 5256 nautilus_progress_info_take_details (job->progress, 5257 f (ngettext ("Making link to %'d file", 5258 "Making links to %'d files", 5259 left), left)); 5260 5261 nautilus_progress_info_set_progress (job->progress, left, total); 5262 } 5263 5264 static char * 5265 get_abs_path_for_symlink (GFile *file, GFile *destination) 5266 { 5267 GFile *root, *parent; 5268 char *relative, *abs; 5269 5270 if (g_file_is_native (file) || g_file_is_native (destination)) { 5271 return g_file_get_path (file); 5272 } 5273 5274 root = g_object_ref (file); 5275 while ((parent = g_file_get_parent (root)) != NULL) { 5276 g_object_unref (root); 5277 root = parent; 5278 } 5279 5280 relative = g_file_get_relative_path (root, file); 5281 g_object_unref (root); 5282 abs = g_strconcat ("/", relative, NULL); 5283 g_free (relative); 5284 return abs; 5285 } 5286 5287 5288 static void 5289 link_file (CopyMoveJob *job, 5290 GFile *src, GFile *dest_dir, 5291 char **dest_fs_type, 5292 GHashTable *debuting_files, 5293 GdkPoint *position, 5294 int files_left) 5295 { 5296 GFile *src_dir, *dest, *new_dest; 5297 int count; 5298 char *path; 5299 gboolean not_local; 5300 GError *error; 5301 CommonJob *common; 5302 char *primary, *secondary, *details; 5303 int response; 5304 gboolean handled_invalid_filename; 5305 5306 common = (CommonJob *)job; 5307 5308 count = 0; 5309 5310 src_dir = g_file_get_parent (src); 5311 if (g_file_equal (src_dir, dest_dir)) { 5312 count = 1; 5313 } 5314 g_object_unref (src_dir); 5315 5316 handled_invalid_filename = *dest_fs_type != NULL; 5317 5318 dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count); 5319 5320 retry: 5321 error = NULL; 5322 not_local = FALSE; 5323 5324 path = get_abs_path_for_symlink (src, dest); 5325 if (path == NULL) { 5326 not_local = TRUE; 5327 } else if (g_file_make_symbolic_link (dest, 5328 path, 5329 common->cancellable, 5330 &error)) { 5331 5332 if (common->undo_info != NULL) { 5333 nautilus_file_undo_info_ext_add_origin_target_pair (NAUTILUS_FILE_UNDO_INFO_EXT (common->undo_info), 5334 src, dest); 5335 } 5336 5337 g_free (path); 5338 if (debuting_files) { 5339 g_hash_table_replace (debuting_files, g_object_ref (dest), GINT_TO_POINTER (TRUE)); 5340 } 5341 5342 nautilus_file_changes_queue_file_added (dest); 5343 if (position) { 5344 nautilus_file_changes_queue_schedule_position_set (dest, *position, common->screen_num); 5345 } else { 5346 nautilus_file_changes_queue_schedule_position_remove (dest); 5347 } 5348 5349 g_object_unref (dest); 5350 5351 return; 5352 } 5353 g_free (path); 5354 5355 if (error != NULL && 5356 IS_IO_ERROR (error, INVALID_FILENAME) && 5357 !handled_invalid_filename) { 5358 handled_invalid_filename = TRUE; 5359 5360 g_assert (*dest_fs_type == NULL); 5361 *dest_fs_type = query_fs_type (dest_dir, common->cancellable); 5362 5363 new_dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count); 5364 5365 if (!g_file_equal (dest, new_dest)) { 5366 g_object_unref (dest); 5367 dest = new_dest; 5368 g_error_free (error); 5369 5370 goto retry; 5371 } else { 5372 g_object_unref (new_dest); 5373 } 5374 } 5375 /* Conflict */ 5376 if (error != NULL && IS_IO_ERROR (error, EXISTS)) { 5377 g_object_unref (dest); 5378 dest = get_target_file_for_link (src, dest_dir, *dest_fs_type, count++); 5379 g_error_free (error); 5380 goto retry; 5381 } 5382 5383 else if (error != NULL && IS_IO_ERROR (error, CANCELLED)) { 5384 g_error_free (error); 5385 } 5386 5387 /* Other error */ 5388 else if (error != NULL) { 5389 if (common->skip_all_error) { 5390 goto out; 5391 } 5392 primary = f (_("Error while creating link to %B."), src); 5393 if (not_local) { 5394 secondary = f (_("Symbolic links only supported for local files")); 5395 details = NULL; 5396 } else if (IS_IO_ERROR (error, NOT_SUPPORTED)) { 5397 secondary = f (_("The target doesn't support symbolic links.")); 5398 details = NULL; 5399 } else { 5400 secondary = f (_("There was an error creating the symlink in %F."), dest_dir); 5401 details = error->message; 5402 } 5403 5404 response = run_warning (common, 5405 primary, 5406 secondary, 5407 details, 5408 files_left > 1, 5409 GTK_STOCK_CANCEL, SKIP_ALL, SKIP, 5410 NULL); 5411 5412 if (error) { 5413 g_error_free (error); 5414 } 5415 5416 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 5417 abort_job (common); 5418 } else if (response == 1) { /* skip all */ 5419 common->skip_all_error = TRUE; 5420 } else if (response == 2) { /* skip */ 5421 /* do nothing */ 5422 } else { 5423 g_assert_not_reached (); 5424 } 5425 } 5426 5427 out: 5428 g_object_unref (dest); 5429 } 5430 5431 static gboolean 5432 link_job_done (gpointer user_data) 5433 { 5434 CopyMoveJob *job; 5435 5436 job = user_data; 5437 if (job->done_callback) { 5438 job->done_callback (job->debuting_files, 5439 !job_aborted ((CommonJob *) job), 5440 job->done_callback_data); 5441 } 5442 5443 g_list_free_full (job->files, g_object_unref); 5444 g_object_unref (job->destination); 5445 g_hash_table_unref (job->debuting_files); 5446 g_free (job->icon_positions); 5447 5448 finalize_common ((CommonJob *)job); 5449 5450 nautilus_file_changes_consume_changes (TRUE); 5451 return FALSE; 5452 } 5453 5454 static gboolean 5455 link_job (GIOSchedulerJob *io_job, 5456 GCancellable *cancellable, 5457 gpointer user_data) 5458 { 5459 CopyMoveJob *job; 5460 CommonJob *common; 5461 GFile *src; 5462 GdkPoint *point; 5463 char *dest_fs_type; 5464 int total, left; 5465 int i; 5466 GList *l; 5467 5468 job = user_data; 5469 common = &job->common; 5470 common->io_job = io_job; 5471 5472 dest_fs_type = NULL; 5473 5474 nautilus_progress_info_start (job->common.progress); 5475 5476 verify_destination (&job->common, 5477 job->destination, 5478 NULL, 5479 -1); 5480 if (job_aborted (common)) { 5481 goto aborted; 5482 } 5483 5484 total = left = g_list_length (job->files); 5485 5486 report_link_progress (job, total, left); 5487 5488 i = 0; 5489 for (l = job->files; 5490 l != NULL && !job_aborted (common); 5491 l = l->next) { 5492 src = l->data; 5493 5494 if (i < job->n_icon_positions) { 5495 point = &job->icon_positions[i]; 5496 } else { 5497 point = NULL; 5498 } 5499 5500 5501 link_file (job, src, job->destination, 5502 &dest_fs_type, job->debuting_files, 5503 point, left); 5504 report_link_progress (job, total, --left); 5505 i++; 5506 5507 } 5508 5509 aborted: 5510 g_free (dest_fs_type); 5511 5512 g_io_scheduler_job_send_to_mainloop (io_job, 5513 link_job_done, 5514 job, 5515 NULL); 5516 5517 return FALSE; 5518 } 5519 5520 void 5521 nautilus_file_operations_link (GList *files, 5522 GArray *relative_item_points, 5523 GFile *target_dir, 5524 GtkWindow *parent_window, 5525 NautilusCopyCallback done_callback, 5526 gpointer done_callback_data) 5527 { 5528 CopyMoveJob *job; 5529 5530 job = op_job_new (CopyMoveJob, parent_window); 5531 job->done_callback = done_callback; 5532 job->done_callback_data = done_callback_data; 5533 job->files = eel_g_object_list_copy (files); 5534 job->destination = g_object_ref (target_dir); 5535 if (relative_item_points != NULL && 5536 relative_item_points->len > 0) { 5537 job->icon_positions = 5538 g_memdup (relative_item_points->data, 5539 sizeof (GdkPoint) * relative_item_points->len); 5540 job->n_icon_positions = relative_item_points->len; 5541 } 5542 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); 5543 5544 if (!nautilus_file_undo_manager_pop_flag ()) { 5545 GFile* src_dir; 5546 5547 src_dir = g_file_get_parent (files->data);
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'files')
(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

5548 job->common.undo_info = nautilus_file_undo_info_ext_new (NAUTILUS_FILE_UNDO_OP_CREATE_LINK, 5549 g_list_length (files), 5550 src_dir, target_dir); 5551 g_object_unref (src_dir); 5552 } 5553 5554 g_io_scheduler_push_job (link_job, 5555 job, 5556 NULL, /* destroy notify */ 5557 0, 5558 job->common.cancellable); 5559 } 5560 5561 5562 void 5563 nautilus_file_operations_duplicate (GList *files, 5564 GArray *relative_item_points, 5565 GtkWindow *parent_window, 5566 NautilusCopyCallback done_callback, 5567 gpointer done_callback_data) 5568 { 5569 CopyMoveJob *job; 5570 5571 job = op_job_new (CopyMoveJob, parent_window); 5572 job->done_callback = done_callback; 5573 job->done_callback_data = done_callback_data; 5574 job->files = eel_g_object_list_copy (files); 5575 job->destination = NULL; 5576 if (relative_item_points != NULL && 5577 relative_item_points->len > 0) { 5578 job->icon_positions = 5579 g_memdup (relative_item_points->data, 5580 sizeof (GdkPoint) * relative_item_points->len); 5581 job->n_icon_positions = relative_item_points->len; 5582 } 5583 job->debuting_files = g_hash_table_new_full (g_file_hash, (GEqualFunc)g_file_equal, g_object_unref, NULL); 5584 5585 if (!nautilus_file_undo_manager_pop_flag ()) { 5586 GFile* src_dir; 5587 5588 src_dir = g_file_get_parent (files->data); 5589 job->common.undo_info = 5590 nautilus_file_undo_info_ext_new (NAUTILUS_FILE_UNDO_OP_DUPLICATE, 5591 g_list_length (files), 5592 src_dir, src_dir); 5593 g_object_unref (src_dir); 5594 } 5595 5596 g_io_scheduler_push_job (copy_job, 5597 job, 5598 NULL, /* destroy notify */ 5599 0, 5600 job->common.cancellable); 5601 } 5602 5603 static gboolean 5604 set_permissions_job_done (gpointer user_data) 5605 { 5606 SetPermissionsJob *job; 5607 5608 job = user_data; 5609 5610 g_object_unref (job->file); 5611 5612 if (job->done_callback) { 5613 job->done_callback (!job_aborted ((CommonJob *) job), 5614 job->done_callback_data); 5615 } 5616 5617 finalize_common ((CommonJob *)job); 5618 return FALSE; 5619 } 5620 5621 static void 5622 set_permissions_file (SetPermissionsJob *job, 5623 GFile *file, 5624 GFileInfo *info) 5625 { 5626 CommonJob *common; 5627 GFileInfo *child_info; 5628 gboolean free_info; 5629 guint32 current; 5630 guint32 value; 5631 guint32 mask; 5632 GFileEnumerator *enumerator; 5633 GFile *child; 5634 5635 common = (CommonJob *)job; 5636 5637 nautilus_progress_info_pulse_progress (common->progress); 5638 5639 free_info = FALSE; 5640 if (info == NULL) { 5641 free_info = TRUE; 5642 info = g_file_query_info (file, 5643 G_FILE_ATTRIBUTE_STANDARD_TYPE"," 5644 G_FILE_ATTRIBUTE_UNIX_MODE, 5645 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 5646 common->cancellable, 5647 NULL); 5648 /* Ignore errors */ 5649 if (info == NULL) { 5650 return; 5651 } 5652 } 5653 5654 if (g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { 5655 value = job->dir_permissions; 5656 mask = job->dir_mask; 5657 } else { 5658 value = job->file_permissions; 5659 mask = job->file_mask; 5660 } 5661 5662 5663 if (!job_aborted (common) && 5664 g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE)) { 5665 current = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE); 5666 5667 if (common->undo_info != NULL) { 5668 nautilus_file_undo_info_rec_permissions_add_file (NAUTILUS_FILE_UNDO_INFO_REC_PERMISSIONS (common->undo_info), 5669 file, current); 5670 } 5671 5672 current = (current & ~mask) | value; 5673 5674 g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE, 5675 current, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 5676 common->cancellable, NULL); 5677 } 5678 5679 if (!job_aborted (common) && 5680 g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY) { 5681 enumerator = g_file_enumerate_children (file, 5682 G_FILE_ATTRIBUTE_STANDARD_NAME"," 5683 G_FILE_ATTRIBUTE_STANDARD_TYPE"," 5684 G_FILE_ATTRIBUTE_UNIX_MODE, 5685 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 5686 common->cancellable, 5687 NULL); 5688 if (enumerator) { 5689 while (!job_aborted (common) && 5690 (child_info = g_file_enumerator_next_file (enumerator, common->cancellable, NULL)) != NULL) { 5691 child = g_file_get_child (file, 5692 g_file_info_get_name (child_info)); 5693 set_permissions_file (job, child, child_info); 5694 g_object_unref (child); 5695 g_object_unref (child_info); 5696 } 5697 g_file_enumerator_close (enumerator, common->cancellable, NULL); 5698 g_object_unref (enumerator); 5699 } 5700 } 5701 if (free_info) { 5702 g_object_unref (info); 5703 } 5704 } 5705 5706 5707 static gboolean 5708 set_permissions_job (GIOSchedulerJob *io_job, 5709 GCancellable *cancellable, 5710 gpointer user_data) 5711 { 5712 SetPermissionsJob *job = user_data; 5713 CommonJob *common; 5714 5715 common = (CommonJob *)job; 5716 common->io_job = io_job; 5717 5718 nautilus_progress_info_set_status (common->progress, 5719 _("Setting permissions")); 5720 5721 nautilus_progress_info_start (job->common.progress); 5722 5723 set_permissions_file (job, job->file, NULL); 5724 5725 g_io_scheduler_job_send_to_mainloop_async (io_job, 5726 set_permissions_job_done, 5727 job, 5728 NULL); 5729 5730 return FALSE; 5731 } 5732 5733 5734 5735 void 5736 nautilus_file_set_permissions_recursive (const char *directory, 5737 guint32 file_permissions, 5738 guint32 file_mask, 5739 guint32 dir_permissions, 5740 guint32 dir_mask, 5741 NautilusOpCallback callback, 5742 gpointer callback_data) 5743 { 5744 SetPermissionsJob *job; 5745 5746 job = op_job_new (SetPermissionsJob, NULL); 5747 job->file = g_file_new_for_uri (directory); 5748 job->file_permissions = file_permissions; 5749 job->file_mask = file_mask; 5750 job->dir_permissions = dir_permissions; 5751 job->dir_mask = dir_mask; 5752 job->done_callback = callback; 5753 job->done_callback_data = callback_data; 5754 5755 if (!nautilus_file_undo_manager_pop_flag ()) { 5756 job->common.undo_info = 5757 nautilus_file_undo_info_rec_permissions_new (job->file, 5758 file_permissions, file_mask, 5759 dir_permissions, dir_mask); 5760 } 5761 5762 g_io_scheduler_push_job (set_permissions_job, 5763 job, 5764 NULL, 5765 0, 5766 NULL); 5767 } 5768 5769 static GList * 5770 location_list_from_uri_list (const GList *uris) 5771 { 5772 const GList *l; 5773 GList *files; 5774 GFile *f; 5775 5776 files = NULL; 5777 for (l = uris; l != NULL; l = l->next) { 5778 f = g_file_new_for_uri (l->data); 5779 files = g_list_prepend (files, f); 5780 } 5781 5782 return g_list_reverse (files); 5783 } 5784 5785 typedef struct { 5786 NautilusCopyCallback real_callback; 5787 gpointer real_data; 5788 } MoveTrashCBData; 5789 5790 static void 5791 callback_for_move_to_trash (GHashTable *debuting_uris, 5792 gboolean user_cancelled, 5793 MoveTrashCBData *data) 5794 { 5795 if (data->real_callback) 5796 data->real_callback (debuting_uris, !user_cancelled, data->real_data); 5797 g_slice_free (MoveTrashCBData, data); 5798 } 5799 5800 void 5801 nautilus_file_operations_copy_move (const GList *item_uris, 5802 GArray *relative_item_points, 5803 const char *target_dir, 5804 GdkDragAction copy_action, 5805 GtkWidget *parent_view, 5806 NautilusCopyCallback done_callback, 5807 gpointer done_callback_data) 5808 { 5809 GList *locations; 5810 GList *p; 5811 GFile *dest, *src_dir; 5812 GtkWindow *parent_window; 5813 gboolean target_is_mapping; 5814 gboolean have_nonmapping_source; 5815 5816 dest = NULL; 5817 target_is_mapping = FALSE; 5818 have_nonmapping_source = FALSE; 5819 5820 if (target_dir) { 5821 dest = g_file_new_for_uri (target_dir); 5822 if (g_file_has_uri_scheme (dest, "burn")) { 5823 target_is_mapping = TRUE; 5824 } 5825 } 5826 5827 locations = location_list_from_uri_list (item_uris); 5828 5829 for (p = locations; p != NULL; p = p->next) { 5830 if (!g_file_has_uri_scheme ((GFile* )p->data, "burn")) { 5831 have_nonmapping_source = TRUE; 5832 } 5833 } 5834 5835 if (target_is_mapping && have_nonmapping_source && copy_action == GDK_ACTION_MOVE) { 5836 /* never move to "burn:///", but fall back to copy. 5837 * This is a workaround, because otherwise the source files would be removed. 5838 */ 5839 copy_action = GDK_ACTION_COPY; 5840 } 5841 5842 parent_window = NULL; 5843 if (parent_view) { 5844 parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); 5845 } 5846 5847 if (copy_action == GDK_ACTION_COPY) { 5848 src_dir = g_file_get_parent (locations->data);
Access to field 'data' results in a dereference of a null pointer (loaded from variable 'locations')

Possibly related backtrace: eea39b8c6dde0dd1f59b69f3003b0370e488eced MatchResult(frame_number=1, dist=0)

Possibly related backtrace: 048839ce381ca4262c25bd0aef4f48b66024e1dc MatchResult(frame_number=1, dist=0)

Possibly related backtrace: ed7137125d7d9d67abb802a0420da284fe56dd02 MatchResult(frame_number=1, dist=0)

Possibly related backtrace: ff1539257de06347cc753b30a5f21f2dd9d512c9 MatchResult(frame_number=1, dist=0)

(emitted by clang-analyzer)

TODO: a detailed trace is available in the data model (not yet rendered in this report)

5849 if (target_dir == NULL || 5850 (src_dir != NULL && 5851 g_file_equal (src_dir, dest))) { 5852 5853 nautilus_file_operations_duplicate (locations, 5854 relative_item_points, 5855 parent_window, 5856 done_callback, done_callback_data); 5857 } else { 5858 nautilus_file_operations_copy (locations, 5859 relative_item_points, 5860 dest, 5861 parent_window, 5862 done_callback, done_callback_data); 5863 } 5864 if (src_dir) { 5865 g_object_unref (src_dir); 5866 } 5867 5868 } else if (copy_action == GDK_ACTION_MOVE) { 5869 if (g_file_has_uri_scheme (dest, "trash")) { 5870 MoveTrashCBData *cb_data; 5871 5872 cb_data = g_slice_new0 (MoveTrashCBData); 5873 cb_data->real_callback = done_callback; 5874 cb_data->real_data = done_callback_data; 5875 5876 nautilus_file_operations_trash_or_delete (locations, 5877 parent_window, 5878 (NautilusDeleteCallback) callback_for_move_to_trash, 5879 cb_data); 5880 } else { 5881 5882 nautilus_file_operations_move (locations, 5883 relative_item_points, 5884 dest, 5885 parent_window, 5886 done_callback, done_callback_data); 5887 } 5888 } else { 5889 5890 nautilus_file_operations_link (locations, 5891 relative_item_points, 5892 dest, 5893 parent_window, 5894 done_callback, done_callback_data); 5895 } 5896 5897 g_list_free_full (locations, g_object_unref); 5898 if (dest) { 5899 g_object_unref (dest); 5900 } 5901 } 5902 5903 static gboolean 5904 create_job_done (gpointer user_data) 5905 { 5906 CreateJob *job; 5907 5908 job = user_data; 5909 if (job->done_callback) { 5910 job->done_callback (job->created_file, 5911 !job_aborted ((CommonJob *) job), 5912 job->done_callback_data); 5913 } 5914 5915 g_object_unref (job->dest_dir); 5916 if (job->src) { 5917 g_object_unref (job->src); 5918 } 5919 g_free (job->src_data); 5920 g_free (job->filename); 5921 if (job->created_file) { 5922 g_object_unref (job->created_file); 5923 } 5924 5925 finalize_common ((CommonJob *)job); 5926 5927 nautilus_file_changes_consume_changes (TRUE); 5928 return FALSE; 5929 } 5930 5931 static gboolean 5932 create_job (GIOSchedulerJob *io_job, 5933 GCancellable *cancellable, 5934 gpointer user_data) 5935 { 5936 CreateJob *job; 5937 CommonJob *common; 5938 int count; 5939 GFile *dest; 5940 char *basename; 5941 char *filename, *filename2, *new_filename; 5942 char *filename_base, *suffix; 5943 char *dest_fs_type; 5944 GError *error; 5945 gboolean res; 5946 gboolean filename_is_utf8; 5947 char *primary, *secondary, *details; 5948 int response; 5949 char *data; 5950 int length; 5951 GFileOutputStream *out; 5952 gboolean handled_invalid_filename; 5953 int max_length, offset; 5954 5955 job = user_data; 5956 common = &job->common; 5957 common->io_job = io_job; 5958 5959 nautilus_progress_info_start (job->common.progress); 5960 5961 handled_invalid_filename = FALSE; 5962 5963 dest_fs_type = NULL; 5964 filename = NULL; 5965 dest = NULL; 5966 5967 max_length = get_max_name_length (job->dest_dir); 5968 5969 verify_destination (common, 5970 job->dest_dir, 5971 NULL, -1); 5972 if (job_aborted (common)) { 5973 goto aborted; 5974 } 5975 5976 filename = g_strdup (job->filename); 5977 filename_is_utf8 = FALSE; 5978 if (filename) { 5979 filename_is_utf8 = g_utf8_validate (filename, -1, NULL); 5980 } 5981 if (filename == NULL) { 5982 if (job->make_dir) { 5983 /* localizers: the initial name of a new folder */ 5984 filename = g_strdup (_("Untitled Folder")); 5985 filename_is_utf8 = TRUE; /* Pass in utf8 */ 5986 } else { 5987 if (job->src != NULL) { 5988 basename = g_file_get_basename (job->src); 5989 /* localizers: the initial name of a new template document */ 5990 filename = g_strdup_printf (_("Untitled %s"), basename); 5991 5992 g_free (basename); 5993 } 5994 if (filename == NULL) { 5995 /* localizers: the initial name of a new empty document */ 5996 filename = g_strdup (_("Untitled Document")); 5997 filename_is_utf8 = TRUE; /* Pass in utf8 */ 5998 } 5999 } 6000 } 6001 6002 make_file_name_valid_for_dest_fs (filename, dest_fs_type); 6003 if (filename_is_utf8) { 6004 dest = g_file_get_child_for_display_name (job->dest_dir, filename, NULL); 6005 } 6006 if (dest == NULL) { 6007 dest = g_file_get_child (job->dest_dir, filename); 6008 } 6009 count = 1; 6010 6011 retry: 6012 6013 error = NULL; 6014 if (job->make_dir) { 6015 res = g_file_make_directory (dest, 6016 common->cancellable, 6017 &error); 6018 6019 if (res && common->undo_info != NULL) { 6020 nautilus_file_undo_info_create_set_data (NAUTILUS_FILE_UNDO_INFO_CREATE (common->undo_info), 6021 dest, NULL, 0); 6022 } 6023 6024 } else { 6025 if (job->src) { 6026 res = g_file_copy (job->src, 6027 dest, 6028 G_FILE_COPY_NONE, 6029 common->cancellable, 6030 NULL, NULL, 6031 &error); 6032 6033 if (res && common->undo_info != NULL) { 6034 gchar *uri; 6035 6036 uri = g_file_get_uri (job->src); 6037 nautilus_file_undo_info_create_set_data (NAUTILUS_FILE_UNDO_INFO_CREATE (common->undo_info), 6038 dest, uri, 0); 6039 6040 g_free (uri); 6041 } 6042 6043 } else { 6044 data = ""; 6045 length = 0; 6046 if (job->src_data) { 6047 data = job->src_data; 6048 length = job->length; 6049 } 6050 6051 out = g_file_create (dest, 6052 G_FILE_CREATE_NONE, 6053 common->cancellable, 6054 &error); 6055 if (out) { 6056 res = g_output_stream_write_all (G_OUTPUT_STREAM (out), 6057 data, length, 6058 NULL, 6059 common->cancellable, 6060 &error); 6061 if (res) { 6062 res = g_output_stream_close (G_OUTPUT_STREAM (out), 6063 common->cancellable, 6064 &error); 6065 6066 if (res && common->undo_info != NULL) { 6067 nautilus_file_undo_info_create_set_data (NAUTILUS_FILE_UNDO_INFO_CREATE (common->undo_info), 6068 dest, data, length); 6069 } 6070 } 6071 6072 /* This will close if the write failed and we didn't close */ 6073 g_object_unref (out); 6074 } else { 6075 res = FALSE; 6076 } 6077 } 6078 } 6079 6080 if (res) { 6081 job->created_file = g_object_ref (dest); 6082 nautilus_file_changes_queue_file_added (dest); 6083 if (job->has_position) { 6084 nautilus_file_changes_queue_schedule_position_set (dest, job->position, common->screen_num); 6085 } else { 6086 nautilus_file_changes_queue_schedule_position_remove (dest); 6087 } 6088 } else { 6089 g_assert (error != NULL); 6090 6091 if (IS_IO_ERROR (error, INVALID_FILENAME) && 6092 !handled_invalid_filename) { 6093 handled_invalid_filename = TRUE; 6094 6095 g_assert (dest_fs_type == NULL); 6096 dest_fs_type = query_fs_type (job->dest_dir, common->cancellable); 6097 6098 g_object_unref (dest); 6099 6100 if (count == 1) { 6101 new_filename = g_strdup (filename); 6102 } else { 6103 filename_base = eel_filename_strip_extension (filename); 6104 offset = strlen (filename_base); 6105 suffix = g_strdup (filename + offset); 6106 6107 filename2 = g_strdup_printf ("%s %d%s", filename_base, count, suffix); 6108 6109 new_filename = NULL; 6110 if (max_length > 0 && strlen (filename2) > max_length) { 6111 new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length); 6112 } 6113 6114 if (new_filename == NULL) { 6115 new_filename = g_strdup (filename2); 6116 } 6117 6118 g_free (filename2); 6119 g_free (suffix); 6120 } 6121 6122 if (make_file_name_valid_for_dest_fs (new_filename, dest_fs_type)) { 6123 g_object_unref (dest); 6124 6125 if (filename_is_utf8) { 6126 dest = g_file_get_child_for_display_name (job->dest_dir, new_filename, NULL); 6127 } 6128 if (dest == NULL) { 6129 dest = g_file_get_child (job->dest_dir, new_filename); 6130 } 6131 6132 g_free (new_filename); 6133 g_error_free (error); 6134 goto retry; 6135 } 6136 g_free (new_filename); 6137 } else if (IS_IO_ERROR (error, EXISTS)) { 6138 g_object_unref (dest); 6139 dest = NULL; 6140 filename_base = eel_filename_strip_extension (filename); 6141 offset = strlen (filename_base); 6142 suffix = g_strdup (filename + offset); 6143 6144 filename2 = g_strdup_printf ("%s %d%s", filename_base, ++count, suffix); 6145 6146 if (max_length > 0 && strlen (filename2) > max_length) { 6147 new_filename = shorten_utf8_string (filename2, strlen (filename2) - max_length); 6148 if (new_filename != NULL) { 6149 g_free (filename2); 6150 filename2 = new_filename; 6151 } 6152 } 6153 6154 make_file_name_valid_for_dest_fs (filename2, dest_fs_type); 6155 if (filename_is_utf8) { 6156 dest = g_file_get_child_for_display_name (job->dest_dir, filename2, NULL); 6157 } 6158 if (dest == NULL) { 6159 dest = g_file_get_child (job->dest_dir, filename2); 6160 } 6161 g_free (filename2); 6162 g_free (suffix); 6163 g_error_free (error); 6164 goto retry; 6165 } 6166 6167 else if (IS_IO_ERROR (error, CANCELLED)) { 6168 g_error_free (error); 6169 } 6170 6171 /* Other error */ 6172 else { 6173 if (job->make_dir) { 6174 primary = f (_("Error while creating directory %B."), dest); 6175 } else { 6176 primary = f (_("Error while creating file %B."), dest); 6177 } 6178 secondary = f (_("There was an error creating the directory in %F."), job->dest_dir); 6179 details = error->message; 6180 6181 response = run_warning (common, 6182 primary, 6183 secondary, 6184 details, 6185 FALSE, 6186 GTK_STOCK_CANCEL, SKIP, 6187 NULL); 6188 6189 g_error_free (error); 6190 6191 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 6192 abort_job (common); 6193 } else if (response == 1) { /* skip */ 6194 /* do nothing */ 6195 } else { 6196 g_assert_not_reached (); 6197 } 6198 } 6199 } 6200 6201 aborted: 6202 if (dest) { 6203 g_object_unref (dest); 6204 } 6205 g_free (filename); 6206 g_free (dest_fs_type); 6207 g_io_scheduler_job_send_to_mainloop_async (io_job, 6208 create_job_done, 6209 job, 6210 NULL); 6211 6212 return FALSE; 6213 } 6214 6215 void 6216 nautilus_file_operations_new_folder (GtkWidget *parent_view, 6217 GdkPoint *target_point, 6218 const char *parent_dir, 6219 NautilusCreateCallback done_callback, 6220 gpointer done_callback_data) 6221 { 6222 CreateJob *job; 6223 GtkWindow *parent_window; 6224 6225 parent_window = NULL; 6226 if (parent_view) { 6227 parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); 6228 } 6229 6230 job = op_job_new (CreateJob, parent_window); 6231 job->done_callback = done_callback; 6232 job->done_callback_data = done_callback_data; 6233 job->dest_dir = g_file_new_for_uri (parent_dir); 6234 job->make_dir = TRUE; 6235 if (target_point != NULL) { 6236 job->position = *target_point; 6237 job->has_position = TRUE; 6238 } 6239 6240 if (!nautilus_file_undo_manager_pop_flag ()) { 6241 job->common.undo_info = nautilus_file_undo_info_create_new (NAUTILUS_FILE_UNDO_OP_CREATE_FOLDER); 6242 } 6243 6244 g_io_scheduler_push_job (create_job, 6245 job, 6246 NULL, /* destroy notify */ 6247 0, 6248 job->common.cancellable); 6249 } 6250 6251 void 6252 nautilus_file_operations_new_file_from_template (GtkWidget *parent_view, 6253 GdkPoint *target_point, 6254 const char *parent_dir, 6255 const char *target_filename, 6256 const char *template_uri, 6257 NautilusCreateCallback done_callback, 6258 gpointer done_callback_data) 6259 { 6260 CreateJob *job; 6261 GtkWindow *parent_window; 6262 6263 parent_window = NULL; 6264 if (parent_view) { 6265 parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); 6266 } 6267 6268 job = op_job_new (CreateJob, parent_window); 6269 job->done_callback = done_callback; 6270 job->done_callback_data = done_callback_data; 6271 job->dest_dir = g_file_new_for_uri (parent_dir); 6272 if (target_point != NULL) { 6273 job->position = *target_point; 6274 job->has_position = TRUE; 6275 } 6276 job->filename = g_strdup (target_filename); 6277 6278 if (template_uri) { 6279 job->src = g_file_new_for_uri (template_uri); 6280 } 6281 6282 if (!nautilus_file_undo_manager_pop_flag ()) { 6283 job->common.undo_info = nautilus_file_undo_info_create_new (NAUTILUS_FILE_UNDO_OP_CREATE_FILE_FROM_TEMPLATE); 6284 } 6285 6286 g_io_scheduler_push_job (create_job, 6287 job, 6288 NULL, /* destroy notify */ 6289 0, 6290 job->common.cancellable); 6291 } 6292 6293 void 6294 nautilus_file_operations_new_file (GtkWidget *parent_view, 6295 GdkPoint *target_point, 6296 const char *parent_dir, 6297 const char *target_filename, 6298 const char *initial_contents, 6299 int length, 6300 NautilusCreateCallback done_callback, 6301 gpointer done_callback_data) 6302 { 6303 CreateJob *job; 6304 GtkWindow *parent_window; 6305 6306 parent_window = NULL; 6307 if (parent_view) { 6308 parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); 6309 } 6310 6311 job = op_job_new (CreateJob, parent_window); 6312 job->done_callback = done_callback; 6313 job->done_callback_data = done_callback_data; 6314 job->dest_dir = g_file_new_for_uri (parent_dir); 6315 if (target_point != NULL) { 6316 job->position = *target_point; 6317 job->has_position = TRUE; 6318 } 6319 job->src_data = g_memdup (initial_contents, length); 6320 job->length = length; 6321 job->filename = g_strdup (target_filename); 6322 6323 if (!nautilus_file_undo_manager_pop_flag ()) { 6324 job->common.undo_info = nautilus_file_undo_info_create_new (NAUTILUS_FILE_UNDO_OP_CREATE_EMPTY_FILE); 6325 } 6326 6327 g_io_scheduler_push_job (create_job, 6328 job, 6329 NULL, /* destroy notify */ 6330 0, 6331 job->common.cancellable); 6332 } 6333 6334 6335 6336 static void 6337 delete_trash_file (CommonJob *job, 6338 GFile *file, 6339 gboolean del_file, 6340 gboolean del_children) 6341 { 6342 GFileInfo *info; 6343 GFile *child; 6344 GFileEnumerator *enumerator; 6345 6346 if (job_aborted (job)) { 6347 return; 6348 } 6349 6350 if (del_children) { 6351 enumerator = g_file_enumerate_children (file, 6352 G_FILE_ATTRIBUTE_STANDARD_NAME "," 6353 G_FILE_ATTRIBUTE_STANDARD_TYPE, 6354 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 6355 job->cancellable, 6356 NULL); 6357 if (enumerator) { 6358 while (!job_aborted (job) && 6359 (info = g_file_enumerator_next_file (enumerator, job->cancellable, NULL)) != NULL) { 6360 child = g_file_get_child (file, 6361 g_file_info_get_name (info)); 6362 delete_trash_file (job, child, TRUE, 6363 g_file_info_get_file_type (info) == G_FILE_TYPE_DIRECTORY); 6364 g_object_unref (child); 6365 g_object_unref (info); 6366 } 6367 g_file_enumerator_close (enumerator, job->cancellable, NULL); 6368 g_object_unref (enumerator); 6369 } 6370 } 6371 6372 if (!job_aborted (job) && del_file) { 6373 g_file_delete (file, job->cancellable, NULL); 6374 } 6375 } 6376 6377 static gboolean 6378 empty_trash_job_done (gpointer user_data) 6379 { 6380 EmptyTrashJob *job; 6381 6382 job = user_data; 6383 6384 g_list_free_full (job->trash_dirs, g_object_unref); 6385 6386 if (job->done_callback) { 6387 job->done_callback (!job_aborted ((CommonJob *) job), 6388 job->done_callback_data); 6389 } 6390 6391 finalize_common ((CommonJob *)job); 6392 return FALSE; 6393 } 6394 6395 static gboolean 6396 empty_trash_job (GIOSchedulerJob *io_job, 6397 GCancellable *cancellable, 6398 gpointer user_data) 6399 { 6400 EmptyTrashJob *job = user_data; 6401 CommonJob *common; 6402 GList *l; 6403 gboolean confirmed; 6404 6405 common = (CommonJob *)job; 6406 common->io_job = io_job; 6407 6408 nautilus_progress_info_start (job->common.progress); 6409 6410 if (job->should_confirm) { 6411 confirmed = confirm_empty_trash (common); 6412 } else { 6413 confirmed = TRUE; 6414 } 6415 if (confirmed) { 6416 for (l = job->trash_dirs; 6417 l != NULL && !job_aborted (common); 6418 l = l->next) { 6419 delete_trash_file (common, l->data, FALSE, TRUE); 6420 } 6421 } 6422 6423 g_io_scheduler_job_send_to_mainloop_async (io_job, 6424 empty_trash_job_done, 6425 job, 6426 NULL); 6427 6428 return FALSE; 6429 } 6430 6431 void 6432 nautilus_file_operations_empty_trash (GtkWidget *parent_view) 6433 { 6434 EmptyTrashJob *job; 6435 GtkWindow *parent_window; 6436 6437 parent_window = NULL; 6438 if (parent_view) { 6439 parent_window = (GtkWindow *)gtk_widget_get_ancestor (parent_view, GTK_TYPE_WINDOW); 6440 } 6441 6442 job = op_job_new (EmptyTrashJob, parent_window); 6443 job->trash_dirs = g_list_prepend (job->trash_dirs, 6444 g_file_new_for_uri ("trash:")); 6445 job->should_confirm = TRUE; 6446 6447 inhibit_power_manager ((CommonJob *)job, _("Emptying Trash")); 6448 6449 g_io_scheduler_push_job (empty_trash_job, 6450 job, 6451 NULL, 6452 0, 6453 NULL); 6454 } 6455 6456 static gboolean 6457 mark_trusted_job_done (gpointer user_data) 6458 { 6459 MarkTrustedJob *job = user_data; 6460 6461 g_object_unref (job->file); 6462 6463 if (job->done_callback) { 6464 job->done_callback (!job_aborted ((CommonJob *) job), 6465 job->done_callback_data); 6466 } 6467 6468 finalize_common ((CommonJob *)job); 6469 return FALSE; 6470 } 6471 6472 #define TRUSTED_SHEBANG "#!/usr/bin/env xdg-open\n" 6473 6474 static void 6475 mark_desktop_file_trusted (CommonJob *common, 6476 GCancellable *cancellable, 6477 GFile *file, 6478 gboolean interactive) 6479 { 6480 char *contents, *new_contents; 6481 gsize length, new_length; 6482 GError *error; 6483 guint32 current_perms, new_perms; 6484 int response; 6485 GFileInfo *info; 6486 6487 retry: 6488 error = NULL; 6489 if (!g_file_load_contents (file, 6490 cancellable, 6491 &contents, &length, 6492 NULL, &error)) { 6493 if (interactive) { 6494 response = run_error (common, 6495 g_strdup (_("Unable to mark launcher trusted (executable)")), 6496 error->message, 6497 NULL, 6498 FALSE, 6499 GTK_STOCK_CANCEL, RETRY, 6500 NULL); 6501 } else { 6502 response = 0; 6503 } 6504 6505 6506 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 6507 abort_job (common); 6508 } else if (response == 1) { 6509 goto retry; 6510 } else { 6511 g_assert_not_reached (); 6512 } 6513 6514 goto out; 6515 } 6516 6517 if (!g_str_has_prefix (contents, "#!")) { 6518 new_length = length + strlen (TRUSTED_SHEBANG); 6519 new_contents = g_malloc (new_length); 6520 6521 strcpy (new_contents, TRUSTED_SHEBANG); 6522 memcpy (new_contents + strlen (TRUSTED_SHEBANG), 6523 contents, length); 6524 6525 if (!g_file_replace_contents (file, 6526 new_contents, 6527 new_length, 6528 NULL, 6529 FALSE, 0, 6530 NULL, cancellable, &error)) { 6531 g_free (contents); 6532 g_free (new_contents); 6533 6534 if (interactive) { 6535 response = run_error (common, 6536 g_strdup (_("Unable to mark launcher trusted (executable)")), 6537 error->message, 6538 NULL, 6539 FALSE, 6540 GTK_STOCK_CANCEL, RETRY, 6541 NULL); 6542 } else { 6543 response = 0; 6544 } 6545 6546 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 6547 abort_job (common); 6548 } else if (response == 1) { 6549 goto retry; 6550 } else { 6551 g_assert_not_reached (); 6552 } 6553 6554 goto out; 6555 } 6556 g_free (new_contents); 6557 6558 } 6559 g_free (contents); 6560 6561 info = g_file_query_info (file, 6562 G_FILE_ATTRIBUTE_STANDARD_TYPE"," 6563 G_FILE_ATTRIBUTE_UNIX_MODE, 6564 G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 6565 common->cancellable, 6566 &error); 6567 6568 if (info == NULL) { 6569 if (interactive) { 6570 response = run_error (common, 6571 g_strdup (_("Unable to mark launcher trusted (executable)")), 6572 error->message, 6573 NULL, 6574 FALSE, 6575 GTK_STOCK_CANCEL, RETRY, 6576 NULL); 6577 } else { 6578 response = 0; 6579 } 6580 6581 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 6582 abort_job (common); 6583 } else if (response == 1) { 6584 goto retry; 6585 } else { 6586 g_assert_not_reached (); 6587 } 6588 6589 goto out; 6590 } 6591 6592 6593 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE)) { 6594 current_perms = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE); 6595 new_perms = current_perms | S_IXGRP | S_IXUSR | S_IXOTH; 6596 6597 if ((current_perms != new_perms) && 6598 !g_file_set_attribute_uint32 (file, G_FILE_ATTRIBUTE_UNIX_MODE, 6599 new_perms, G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, 6600 common->cancellable, &error)) 6601 { 6602 g_object_unref (info); 6603 6604 if (interactive) { 6605 response = run_error (common, 6606 g_strdup (_("Unable to mark launcher trusted (executable)")), 6607 error->message, 6608 NULL, 6609 FALSE, 6610 GTK_STOCK_CANCEL, RETRY, 6611 NULL); 6612 } else { 6613 response = 0; 6614 } 6615 6616 if (response == 0 || response == GTK_RESPONSE_DELETE_EVENT) { 6617 abort_job (common); 6618 } else if (response == 1) { 6619 goto retry; 6620 } else { 6621 g_assert_not_reached (); 6622 } 6623 6624 goto out; 6625 } 6626 } 6627 g_object_unref (info); 6628 out: 6629 ; 6630 } 6631 6632 static gboolean 6633 mark_trusted_job (GIOSchedulerJob *io_job, 6634 GCancellable *cancellable, 6635 gpointer user_data) 6636 { 6637 MarkTrustedJob *job = user_data; 6638 CommonJob *common; 6639 6640 common = (CommonJob *)job; 6641 common->io_job = io_job; 6642 6643 nautilus_progress_info_start (job->common.progress); 6644 6645 mark_desktop_file_trusted (common, 6646 cancellable, 6647 job->file, 6648 job->interactive); 6649 6650 g_io_scheduler_job_send_to_mainloop_async (io_job, 6651 mark_trusted_job_done, 6652 job, 6653 NULL); 6654 6655 return FALSE; 6656 } 6657 6658 void 6659 nautilus_file_mark_desktop_file_trusted (GFile *file, 6660 GtkWindow *parent_window, 6661 gboolean interactive, 6662 NautilusOpCallback done_callback, 6663 gpointer done_callback_data) 6664 { 6665 MarkTrustedJob *job; 6666 6667 job = op_job_new (MarkTrustedJob, parent_window); 6668 job->file = g_object_ref (file); 6669 job->interactive = interactive; 6670 job->done_callback = done_callback; 6671 job->done_callback_data = done_callback_data; 6672 6673 g_io_scheduler_push_job (mark_trusted_job, 6674 job, 6675 NULL, 6676 0, 6677 NULL); 6678 } 6679 6680 #if !defined (NAUTILUS_OMIT_SELF_CHECK) 6681 6682 void 6683 nautilus_self_check_file_operations (void) 6684 { 6685 setlocale (LC_MESSAGES, "C"); 6686 6687 6688 /* test the next duplicate name generator */ 6689 EEL_CHECK_STRING_RESULT (get_duplicate_name (" (copy)", 1, -1), " (another copy)"); 6690 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo", 1, -1), "foo (copy)"); 6691 EEL_CHECK_STRING_RESULT (get_duplicate_name (".bashrc", 1, -1), ".bashrc (copy)"); 6692 EEL_CHECK_STRING_RESULT (get_duplicate_name (".foo.txt", 1, -1), ".foo (copy).txt"); 6693 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo", 1, -1), "foo foo (copy)"); 6694 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo.txt", 1, -1), "foo (copy).txt"); 6695 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt", 1, -1), "foo foo (copy).txt"); 6696 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo.txt txt", 1, -1), "foo foo (copy).txt txt"); 6697 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...txt", 1, -1), "foo.. (copy).txt"); 6698 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo...", 1, -1), "foo... (copy)"); 6699 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo. (copy)", 1, -1), "foo. (another copy)"); 6700 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy)", 1, -1), "foo (another copy)"); 6701 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (copy).txt", 1, -1), "foo (another copy).txt"); 6702 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy)", 1, -1), "foo (3rd copy)"); 6703 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (another copy).txt", 1, -1), "foo (3rd copy).txt"); 6704 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (another copy).txt", 1, -1), "foo foo (3rd copy).txt"); 6705 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy)", 1, -1), "foo (14th copy)"); 6706 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (13th copy).txt", 1, -1), "foo (14th copy).txt"); 6707 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy)", 1, -1), "foo (22nd copy)"); 6708 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (21st copy).txt", 1, -1), "foo (22nd copy).txt"); 6709 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy)", 1, -1), "foo (23rd copy)"); 6710 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (22nd copy).txt", 1, -1), "foo (23rd copy).txt"); 6711 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy)", 1, -1), "foo (24th copy)"); 6712 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (23rd copy).txt", 1, -1), "foo (24th copy).txt"); 6713 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy)", 1, -1), "foo (25th copy)"); 6714 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (24th copy).txt", 1, -1), "foo (25th copy).txt"); 6715 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy)", 1, -1), "foo foo (25th copy)"); 6716 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (24th copy).txt", 1, -1), "foo foo (25th copy).txt"); 6717 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo foo (100000000000000th copy).txt", 1, -1), "foo foo (copy).txt"); 6718 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy)", 1, -1), "foo (11th copy)"); 6719 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (10th copy).txt", 1, -1), "foo (11th copy).txt"); 6720 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy)", 1, -1), "foo (12th copy)"); 6721 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (11th copy).txt", 1, -1), "foo (12th copy).txt"); 6722 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy)", 1, -1), "foo (13th copy)"); 6723 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (12th copy).txt", 1, -1), "foo (13th copy).txt"); 6724 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy)", 1, -1), "foo (111th copy)"); 6725 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (110th copy).txt", 1, -1), "foo (111th copy).txt"); 6726 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy)", 1, -1), "foo (123rd copy)"); 6727 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (122nd copy).txt", 1, -1), "foo (123rd copy).txt"); 6728 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy)", 1, -1), "foo (124th copy)"); 6729 EEL_CHECK_STRING_RESULT (get_duplicate_name ("foo (123rd copy).txt", 1, -1), "foo (124th copy).txt"); 6730 6731 setlocale (LC_MESSAGES, ""); 6732 } 6733 6734 #endif