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

No issues found

   1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
   2 
   3    nautilus-file.c: Nautilus file model.
   4  
   5    Copyright (C) 1999, 2000, 2001 Eazel, Inc.
   6   
   7    This program is free software; you can redistribute it and/or
   8    modify it under the terms of the GNU General Public License as
   9    published by the Free Software Foundation; either version 2 of the
  10    License, or (at your option) any later version.
  11   
  12    This program is distributed in the hope that it will be useful,
  13    but WITHOUT ANY WARRANTY; without even the implied warranty of
  14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  15    General Public License for more details.
  16   
  17    You should have received a copy of the GNU General Public
  18    License along with this program; if not, write to the
  19    Free Software Foundation, Inc., 59 Temple Place - Suite 330,
  20    Boston, MA 02111-1307, USA.
  21   
  22    Author: Darin Adler <darin@bentspoon.com>
  23 */
  24 
  25 #include <config.h>
  26 #include "nautilus-file.h"
  27 
  28 #include "nautilus-directory-notify.h"
  29 #include "nautilus-directory-private.h"
  30 #include "nautilus-signaller.h"
  31 #include "nautilus-desktop-directory.h"
  32 #include "nautilus-desktop-directory-file.h"
  33 #include "nautilus-desktop-icon-file.h"
  34 #include "nautilus-file-attributes.h"
  35 #include "nautilus-file-private.h"
  36 #include "nautilus-file-operations.h"
  37 #include "nautilus-file-utilities.h"
  38 #include "nautilus-global-preferences.h"
  39 #include "nautilus-lib-self-check-functions.h"
  40 #include "nautilus-link.h"
  41 #include "nautilus-metadata.h"
  42 #include "nautilus-module.h"
  43 #include "nautilus-search-directory.h"
  44 #include "nautilus-search-directory-file.h"
  45 #include "nautilus-thumbnails.h"
  46 #include "nautilus-ui-utilities.h"
  47 #include "nautilus-vfs-file.h"
  48 #include "nautilus-file-undo-operations.h"
  49 #include "nautilus-file-undo-manager.h"
  50 #include <eel/eel-debug.h>
  51 #include <eel/eel-glib-extensions.h>
  52 #include <eel/eel-gtk-extensions.h>
  53 #include <eel/eel-vfs-extensions.h>
  54 #include <eel/eel-string.h>
  55 #include <grp.h>
  56 #include <gtk/gtk.h>
  57 #include <glib/gi18n.h>
  58 #include <glib/gstdio.h>
  59 #include <gio/gio.h>
  60 #include <glib.h>
  61 #include <gdesktop-enums.h>
  62 #include <libnautilus-extension/nautilus-file-info.h>
  63 #include <libnautilus-extension/nautilus-extension-private.h>
  64 #include <libxml/parser.h>
  65 #include <pwd.h>
  66 #include <stdlib.h>
  67 #include <sys/time.h>
  68 #include <time.h>
  69 #include <unistd.h>
  70 #include <sys/stat.h>
  71 
  72 #ifdef HAVE_SELINUX
  73 #include <selinux/selinux.h>
  74 #endif
  75 
  76 #define DEBUG_FLAG NAUTILUS_DEBUG_FILE
  77 #include <libnautilus-private/nautilus-debug.h>
  78 
  79 /* Time in seconds to cache getpwuid results */
  80 #define GETPWUID_CACHE_TIME (5*60)
  81 
  82 #define ICON_NAME_THUMBNAIL_LOADING   "image-loading"
  83 
  84 #undef NAUTILUS_FILE_DEBUG_REF
  85 #undef NAUTILUS_FILE_DEBUG_REF_VALGRIND
  86 
  87 #ifdef NAUTILUS_FILE_DEBUG_REF_VALGRIND
  88 #include <valgrind/valgrind.h>
  89 #define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE
  90 #else
  91 #define DEBUG_REF_PRINTF printf
  92 #endif
  93 
  94 /* Files that start with these characters sort after files that don't. */
  95 #define SORT_LAST_CHAR1 '.'
  96 #define SORT_LAST_CHAR2 '#'
  97 
  98 /* Name of Nautilus trash directories */
  99 #define TRASH_DIRECTORY_NAME ".Trash"
 100 
 101 #define METADATA_ID_IS_LIST_MASK (1<<31)
 102 
 103 typedef enum {
 104 	SHOW_HIDDEN = 1 << 0,
 105 } FilterOptions;
 106 
 107 typedef void (* ModifyListFunction) (GList **list, NautilusFile *file);
 108 
 109 enum {
 110 	CHANGED,
 111 	UPDATED_DEEP_COUNT_IN_PROGRESS,
 112 	LAST_SIGNAL
 113 };
 114 
 115 static guint signals[LAST_SIGNAL];
 116 
 117 static GHashTable *symbolic_links;
 118 
 119 static guint64 cached_thumbnail_limit;
 120 int cached_thumbnail_size;
 121 static NautilusSpeedTradeoffValue show_file_thumbs;
 122 
 123 static NautilusSpeedTradeoffValue show_directory_item_count;
 124 
 125 static GQuark attribute_name_q,
 126 	attribute_size_q,
 127 	attribute_type_q,
 128 	attribute_detailed_type_q,
 129 	attribute_modification_date_q,
 130 	attribute_date_modified_q,
 131 	attribute_date_modified_full_q,
 132 	attribute_accessed_date_q,
 133 	attribute_date_accessed_q,
 134 	attribute_date_accessed_full_q,
 135 	attribute_mime_type_q,
 136 	attribute_size_detail_q,
 137 	attribute_deep_size_q,
 138 	attribute_deep_file_count_q,
 139 	attribute_deep_directory_count_q,
 140 	attribute_deep_total_count_q,
 141 	attribute_search_relevance_q,
 142 	attribute_trashed_on_q,
 143 	attribute_trashed_on_full_q,
 144 	attribute_trash_orig_path_q,
 145 	attribute_permissions_q,
 146 	attribute_selinux_context_q,
 147 	attribute_octal_permissions_q,
 148 	attribute_owner_q,
 149 	attribute_group_q,
 150 	attribute_uri_q,
 151 	attribute_where_q,
 152 	attribute_link_target_q,
 153 	attribute_volume_q,
 154 	attribute_free_space_q;
 155 
 156 static void     nautilus_file_info_iface_init                (NautilusFileInfoIface *iface);
 157 static char *   nautilus_file_get_owner_as_string            (NautilusFile          *file,
 158 							      gboolean               include_real_name);
 159 static char *   nautilus_file_get_type_as_string             (NautilusFile          *file);
 160 static char *   nautilus_file_get_detailed_type_as_string    (NautilusFile          *file);
 161 static gboolean update_info_and_name                         (NautilusFile          *file,
 162 							      GFileInfo             *info);
 163 static const char * nautilus_file_peek_display_name (NautilusFile *file);
 164 static const char * nautilus_file_peek_display_name_collation_key (NautilusFile *file);
 165 static void file_mount_unmounted (GMount *mount,  gpointer data);
 166 static void metadata_hash_free (GHashTable *hash);
 167 
 168 G_DEFINE_TYPE_WITH_CODE (NautilusFile, nautilus_file, G_TYPE_OBJECT,
 169 			 G_IMPLEMENT_INTERFACE (NAUTILUS_TYPE_FILE_INFO,
 170 						nautilus_file_info_iface_init));
 171 
 172 static void
 173 nautilus_file_init (NautilusFile *file)
 174 {
 175 	file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NAUTILUS_TYPE_FILE, NautilusFileDetails);
 176 
 177 	nautilus_file_clear_info (file);
 178 	nautilus_file_invalidate_extension_info_internal (file);
 179 
 180 	file->details->free_space = -1;
 181 }
 182 
 183 static GObject*
 184 nautilus_file_constructor (GType                  type,
 185 			   guint                  n_construct_properties,
 186 			   GObjectConstructParam *construct_params)
 187 {
 188   GObject *object;
 189   NautilusFile *file;
 190 
 191   object = (* G_OBJECT_CLASS (nautilus_file_parent_class)->constructor) (type,
 192 									 n_construct_properties,
 193 									 construct_params);
 194 
 195   file = NAUTILUS_FILE (object);
 196 
 197   /* Set to default type after full construction */
 198   if (NAUTILUS_FILE_GET_CLASS (file)->default_file_type != G_FILE_TYPE_UNKNOWN) {
 199 	  file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;
 200   }
 201   
 202   return object;
 203 }
 204 
 205 gboolean
 206 nautilus_file_set_display_name (NautilusFile *file,
 207 				const char *display_name,
 208 				const char *edit_name,
 209 				gboolean custom)
 210 {
 211 	gboolean changed;
 212 
 213 	if (custom && display_name == NULL) {
 214 		/* We're re-setting a custom display name, invalidate it if
 215 		   we already set it so that the old one is re-read */
 216 		if (file->details->got_custom_display_name) {
 217 			file->details->got_custom_display_name = FALSE;
 218 			nautilus_file_invalidate_attributes (file,
 219 							     NAUTILUS_FILE_ATTRIBUTE_INFO);
 220 		}
 221 		return FALSE;
 222 	}
 223 	
 224 	if (display_name == NULL || *display_name == 0) {
 225 		return FALSE;
 226 	}
 227 	
 228 	if (!custom && file->details->got_custom_display_name) {
 229 		return FALSE;
 230 	}
 231 
 232 	if (edit_name == NULL) {
 233 		edit_name = display_name;
 234 	}
 235 	    
 236 	changed = FALSE;
 237 	
 238 	if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), display_name) != 0) {
 239 		changed = TRUE;
 240 		
 241 		eel_ref_str_unref (file->details->display_name);
 242 		
 243 		if (g_strcmp0 (eel_ref_str_peek (file->details->name), display_name) == 0) {
 244 			file->details->display_name = eel_ref_str_ref (file->details->name);
 245 		} else {
 246 			file->details->display_name = eel_ref_str_new (display_name);
 247 		}
 248 		
 249 		g_free (file->details->display_name_collation_key);
 250 		file->details->display_name_collation_key = g_utf8_collate_key_for_filename (display_name, -1);
 251 	}
 252 
 253 	if (g_strcmp0 (eel_ref_str_peek (file->details->edit_name), edit_name) != 0) {
 254 		changed = TRUE;
 255 		
 256 		eel_ref_str_unref (file->details->edit_name);
 257 		if (g_strcmp0 (eel_ref_str_peek (file->details->display_name), edit_name) == 0) {
 258 			file->details->edit_name = eel_ref_str_ref (file->details->display_name);
 259 		} else {
 260 			file->details->edit_name = eel_ref_str_new (edit_name);
 261 		}
 262 	}
 263 	
 264 	file->details->got_custom_display_name = custom;
 265 	return changed;
 266 }
 267 
 268 static void
 269 nautilus_file_clear_display_name (NautilusFile *file)
 270 {
 271 	eel_ref_str_unref (file->details->display_name);
 272 	file->details->display_name = NULL;
 273 	g_free (file->details->display_name_collation_key);
 274 	file->details->display_name_collation_key = NULL;
 275 	eel_ref_str_unref (file->details->edit_name);
 276 	file->details->edit_name = NULL;
 277 }
 278 
 279 static gboolean
 280 foreach_metadata_free (gpointer  key,
 281 		       gpointer  value,
 282 		       gpointer  user_data)
 283 {
 284 	guint id;
 285 
 286 	id = GPOINTER_TO_UINT (key);
 287 
 288 	if (id & METADATA_ID_IS_LIST_MASK) {
 289 		g_strfreev ((char **)value);
 290 	} else {
 291 		g_free ((char *)value);
 292 	}
 293 	return TRUE;
 294 }
 295 
 296 
 297 static void
 298 metadata_hash_free (GHashTable *hash)
 299 {
 300 	g_hash_table_foreach_remove (hash,
 301 				     foreach_metadata_free,
 302 				     NULL);
 303 	g_hash_table_destroy (hash);
 304 }
 305 
 306 static gboolean
 307 metadata_hash_equal (GHashTable *hash1,
 308 		     GHashTable *hash2)
 309 {
 310 	GHashTableIter iter;
 311 	gpointer key1, value1, value2;
 312 	guint id;
 313 
 314 	if (hash1 == NULL && hash2 == NULL) {
 315 		return TRUE;
 316 	}
 317 
 318 	if (hash1 == NULL || hash2 == NULL) {
 319 		return FALSE;
 320 	}
 321 
 322 	if (g_hash_table_size (hash1) !=
 323 	    g_hash_table_size (hash2)) {
 324 		return FALSE;
 325 	}
 326 
 327 	g_hash_table_iter_init (&iter, hash1);
 328 	while (g_hash_table_iter_next (&iter, &key1, &value1)) {
 329 		value2 = g_hash_table_lookup (hash2, key1);
 330 		if (value2 == NULL) {
 331 			return FALSE;
 332 		}
 333 		id = GPOINTER_TO_UINT (key1);
 334 		if (id & METADATA_ID_IS_LIST_MASK) {
 335 			if (!eel_g_strv_equal ((char **)value1, (char **)value2)) {
 336 				return FALSE;
 337 			}
 338 		} else {
 339 			if (strcmp ((char *)value1, (char *)value2) != 0) {
 340 				return FALSE;
 341 			}
 342 		}
 343 	}
 344 
 345 	return TRUE;
 346 }
 347 
 348 static void
 349 clear_metadata (NautilusFile *file)
 350 {
 351 	if (file->details->metadata) {
 352 		metadata_hash_free (file->details->metadata);
 353 		file->details->metadata = NULL;
 354 	}
 355 }
 356 
 357 static GHashTable *
 358 get_metadata_from_info (GFileInfo *info)
 359 {
 360 	GHashTable *metadata;
 361 	char **attrs;
 362 	guint id;
 363 	int i;
 364 	GFileAttributeType type;
 365 	gpointer value;
 366 
 367 	attrs = g_file_info_list_attributes (info, "metadata");
 368 
 369 	metadata = g_hash_table_new (NULL, NULL);
 370 
 371 	for (i = 0; attrs[i] != NULL; i++) {
 372 		id = nautilus_metadata_get_id (attrs[i] + strlen ("metadata::"));
 373 		if (id == 0) {
 374 			continue;
 375 		}
 376 
 377 		if (!g_file_info_get_attribute_data (info, attrs[i],
 378 						     &type, &value, NULL)) {
 379 			continue;
 380 		}
 381 
 382 		if (type == G_FILE_ATTRIBUTE_TYPE_STRING) {
 383 			g_hash_table_insert (metadata, GUINT_TO_POINTER (id),
 384 					     g_strdup ((char *)value));
 385 		} else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV) {
 386 			id |= METADATA_ID_IS_LIST_MASK;
 387 			g_hash_table_insert (metadata, GUINT_TO_POINTER (id),
 388 					     g_strdupv ((char **)value));
 389 		}
 390 	}
 391 
 392 	g_strfreev (attrs);
 393 
 394 	return metadata;
 395 }
 396 
 397 gboolean
 398 nautilus_file_update_metadata_from_info (NautilusFile *file,
 399 					 GFileInfo *info)
 400 {
 401 	gboolean changed = FALSE;
 402 
 403 	if (g_file_info_has_namespace (info, "metadata")) {
 404 		GHashTable *metadata;
 405 
 406 		metadata = get_metadata_from_info (info);
 407 		if (!metadata_hash_equal (metadata,
 408 					  file->details->metadata)) {
 409 			changed = TRUE;
 410 			clear_metadata (file);
 411 			file->details->metadata = metadata;
 412 		} else {
 413 			metadata_hash_free (metadata);
 414 		}
 415 	} else if (file->details->metadata) {
 416 		changed = TRUE;
 417 		clear_metadata (file);
 418 	}
 419 	return changed;
 420 }
 421 
 422 void
 423 nautilus_file_clear_info (NautilusFile *file)
 424 {
 425 	file->details->got_file_info = FALSE;
 426 	if (file->details->get_info_error) {
 427 		g_error_free (file->details->get_info_error);
 428 		file->details->get_info_error = NULL;
 429 	}
 430 	/* Reset to default type, which might be other than unknown for
 431 	   special kinds of files like the desktop or a search directory */
 432 	file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;
 433 
 434 	if (!file->details->got_custom_display_name) {
 435 		nautilus_file_clear_display_name (file);
 436 	}
 437 
 438 	if (!file->details->got_custom_activation_uri &&
 439 	    file->details->activation_uri != NULL) {
 440 		g_free (file->details->activation_uri);
 441 		file->details->activation_uri = NULL;
 442 	}
 443 	
 444 	if (file->details->icon != NULL) {
 445 		g_object_unref (file->details->icon);
 446 		file->details->icon = NULL;
 447 	}
 448 
 449 	g_free (file->details->thumbnail_path);
 450 	file->details->thumbnail_path = NULL;
 451 	file->details->thumbnailing_failed = FALSE;
 452 	
 453 	file->details->is_launcher = FALSE;
 454 	file->details->is_foreign_link = FALSE;
 455 	file->details->is_trusted_link = FALSE;
 456 	file->details->is_symlink = FALSE;
 457 	file->details->is_hidden = FALSE;
 458 	file->details->is_mountpoint = FALSE;
 459 	file->details->uid = -1;
 460 	file->details->gid = -1;
 461 	file->details->can_read = TRUE;
 462 	file->details->can_write = TRUE;
 463 	file->details->can_execute = TRUE;
 464 	file->details->can_delete = TRUE;
 465 	file->details->can_trash = TRUE;
 466 	file->details->can_rename = TRUE;
 467 	file->details->can_mount = FALSE;
 468 	file->details->can_unmount = FALSE;
 469 	file->details->can_eject = FALSE;
 470 	file->details->can_start = FALSE;
 471 	file->details->can_start_degraded = FALSE;
 472 	file->details->can_stop = FALSE;
 473 	file->details->start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
 474 	file->details->can_poll_for_media = FALSE;
 475 	file->details->is_media_check_automatic = FALSE;
 476 	file->details->has_permissions = FALSE;
 477 	file->details->permissions = 0;
 478 	file->details->size = -1;
 479 	file->details->sort_order = 0;
 480 	file->details->mtime = 0;
 481 	file->details->atime = 0;
 482 	file->details->trash_time = 0;
 483 	g_free (file->details->symlink_name);
 484 	file->details->symlink_name = NULL;
 485 	eel_ref_str_unref (file->details->mime_type);
 486 	file->details->mime_type = NULL;
 487 	g_free (file->details->selinux_context);
 488 	file->details->selinux_context = NULL;
 489 	g_free (file->details->description);
 490 	file->details->description = NULL;
 491 	eel_ref_str_unref (file->details->owner);
 492 	file->details->owner = NULL;
 493 	eel_ref_str_unref (file->details->owner_real);
 494 	file->details->owner_real = NULL;
 495 	eel_ref_str_unref (file->details->group);
 496 	file->details->group = NULL;
 497 
 498 	eel_ref_str_unref (file->details->filesystem_id);
 499 	file->details->filesystem_id = NULL;
 500 
 501 	clear_metadata (file);
 502 }
 503 
 504 static NautilusFile *
 505 nautilus_file_new_from_filename (NautilusDirectory *directory,
 506 				 const char *filename,
 507 				 gboolean self_owned)
 508 {
 509 	NautilusFile *file;
 510 
 511 	g_assert (NAUTILUS_IS_DIRECTORY (directory));
 512 	g_assert (filename != NULL);
 513 	g_assert (filename[0] != '\0');
 514 
 515 	if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
 516 		if (self_owned) {
 517 			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NULL));
 518 		} else {
 519 			/* This doesn't normally happen, unless the user somehow types in a uri
 520 			 * that references a file like this. (See #349840) */
 521 			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
 522 		}
 523 	} else if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
 524 		if (self_owned) {
 525 			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NULL));
 526 		} else {
 527 			/* This doesn't normally happen, unless the user somehow types in a uri
 528 			 * that references a file like this. (See #349840) */
 529 			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
 530 		}
 531 	} else {
 532 		file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
 533 	}
 534 
 535 	file->details->directory = nautilus_directory_ref (directory);
 536 
 537 	file->details->name = eel_ref_str_new (filename);
 538 
 539 #ifdef NAUTILUS_FILE_DEBUG_REF
 540 	DEBUG_REF_PRINTF("%10p ref'd", file);
 541 #endif
 542 
 543 	return file;
 544 }
 545 
 546 static void
 547 modify_link_hash_table (NautilusFile *file,
 548 			ModifyListFunction modify_function)
 549 {
 550 	char *target_uri;
 551 	gboolean found;
 552 	gpointer original_key;
 553 	GList **list_ptr;
 554 
 555 	/* Check if there is a symlink name. If none, we are OK. */
 556 	if (file->details->symlink_name == NULL) {
 557 		return;
 558 	}
 559 
 560 	/* Create the hash table first time through. */
 561 	if (symbolic_links == NULL) {
 562 		symbolic_links = g_hash_table_new (g_str_hash, g_str_equal);
 563 	}
 564 
 565 	target_uri = nautilus_file_get_symbolic_link_target_uri (file);
 566 	
 567 	/* Find the old contents of the hash table. */
 568 	found = g_hash_table_lookup_extended
 569 		(symbolic_links, target_uri,
 570 		 &original_key, (gpointer *)&list_ptr);
 571 	if (!found) {
 572 		list_ptr = g_new0 (GList *, 1);
 573 		original_key = g_strdup (target_uri);
 574 		g_hash_table_insert (symbolic_links, original_key, list_ptr);
 575 	}
 576 	(* modify_function) (list_ptr, file);
 577 	if (*list_ptr == NULL) {
 578 		g_hash_table_remove (symbolic_links, target_uri);
 579 		g_free (list_ptr);
 580 		g_free (original_key);
 581 	}
 582 	g_free (target_uri);
 583 }
 584 
 585 static void
 586 symbolic_link_weak_notify (gpointer      data,
 587 			   GObject      *where_the_object_was)
 588 {
 589 	GList **list = data;
 590 	/* This really shouldn't happen, but we're seeing some strange things in
 591 	   bug #358172 where the symlink hashtable isn't correctly updated. */
 592 	*list = g_list_remove (*list, where_the_object_was);
 593 }
 594 
 595 static void
 596 add_to_link_hash_table_list (GList **list, NautilusFile *file)
 597 {
 598 	if (g_list_find (*list, file) != NULL) {
 599 		g_warning ("Adding file to symlink_table multiple times. "
 600 			   "Please add feedback of what you were doing at http://bugzilla.gnome.org/show_bug.cgi?id=358172\n");
 601 		return;
 602 	}
 603 	g_object_weak_ref (G_OBJECT (file), symbolic_link_weak_notify, list);
 604 	*list = g_list_prepend (*list, file); 
 605 }
 606 
 607 static void
 608 add_to_link_hash_table (NautilusFile *file)
 609 {
 610 	modify_link_hash_table (file, add_to_link_hash_table_list);
 611 }
 612 
 613 static void
 614 remove_from_link_hash_table_list (GList **list, NautilusFile *file)
 615 {
 616 	if (g_list_find (*list, file) != NULL) {
 617 		g_object_weak_unref (G_OBJECT (file), symbolic_link_weak_notify, list);
 618 		*list = g_list_remove (*list, file);
 619 	}
 620 }
 621 
 622 static void
 623 remove_from_link_hash_table (NautilusFile *file)
 624 {
 625 	modify_link_hash_table (file, remove_from_link_hash_table_list);
 626 }
 627 
 628 NautilusFile *
 629 nautilus_file_new_from_info (NautilusDirectory *directory,
 630 			     GFileInfo *info)
 631 {
 632 	NautilusFile *file;
 633 
 634 	g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
 635 	g_return_val_if_fail (info != NULL, NULL);
 636 
 637 	file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
 638 	file->details->directory = nautilus_directory_ref (directory);
 639 
 640 	update_info_and_name (file, info);
 641 
 642 #ifdef NAUTILUS_FILE_DEBUG_REF
 643 	DEBUG_REF_PRINTF("%10p ref'd", file);
 644 #endif
 645 
 646 	return file;
 647 }
 648 
 649 static NautilusFile *
 650 nautilus_file_get_internal (GFile *location, gboolean create)
 651 {
 652 	gboolean self_owned;
 653 	NautilusDirectory *directory;
 654 	NautilusFile *file;
 655 	GFile *parent;
 656 	char *basename;
 657 
 658 	g_assert (location != NULL);
 659 
 660 	parent = g_file_get_parent (location);
 661 	
 662 	self_owned = FALSE;
 663 	if (parent == NULL) {
 664 		self_owned = TRUE;
 665 		parent = g_object_ref (location);
 666 	} 
 667 
 668 	/* Get object that represents the directory. */
 669 	directory = nautilus_directory_get_internal (parent, create);
 670 
 671 	g_object_unref (parent);
 672 
 673 	/* Get the name for the file. */
 674 	if (self_owned && directory != NULL) {
 675 		basename = nautilus_directory_get_name_for_self_as_new_file (directory);
 676 	} else {
 677 		basename = g_file_get_basename (location);
 678 	}
 679 	/* Check to see if it's a file that's already known. */
 680 	if (directory == NULL) {
 681 		file = NULL;
 682 	} else if (self_owned) {
 683 		file = directory->details->as_file;
 684 	} else {
 685 		file = nautilus_directory_find_file_by_name (directory, basename);
 686 	}
 687 
 688 	/* Ref or create the file. */
 689 	if (file != NULL) {
 690 		nautilus_file_ref (file);
 691 	} else if (create) {
 692 		file = nautilus_file_new_from_filename (directory, basename, self_owned);
 693 		if (self_owned) {
 694 			g_assert (directory->details->as_file == NULL);
 695 			directory->details->as_file = file;
 696 		} else {
 697 			nautilus_directory_add_file (directory, file);
 698 		}
 699 	}
 700 
 701 	g_free (basename);
 702 	nautilus_directory_unref (directory);
 703 
 704 	return file;
 705 }
 706 
 707 NautilusFile *
 708 nautilus_file_get (GFile *location)
 709 {
 710 	return nautilus_file_get_internal (location, TRUE);
 711 }
 712 
 713 NautilusFile *
 714 nautilus_file_get_existing (GFile *location)
 715 {
 716 	return nautilus_file_get_internal (location, FALSE);
 717 }
 718 
 719 NautilusFile *
 720 nautilus_file_get_existing_by_uri (const char *uri)
 721 {
 722 	GFile *location;
 723 	NautilusFile *file;
 724 	
 725 	location = g_file_new_for_uri (uri);
 726 	file = nautilus_file_get_internal (location, FALSE);
 727 	g_object_unref (location);
 728 	
 729 	return file;
 730 }
 731 
 732 NautilusFile *
 733 nautilus_file_get_by_uri (const char *uri)
 734 {
 735 	GFile *location;
 736 	NautilusFile *file;
 737 	
 738 	location = g_file_new_for_uri (uri);
 739 	file = nautilus_file_get_internal (location, TRUE);
 740 	g_object_unref (location);
 741 	
 742 	return file;
 743 }
 744 
 745 gboolean
 746 nautilus_file_is_self_owned (NautilusFile *file)
 747 {
 748 	return file->details->directory->details->as_file == file;
 749 }
 750 
 751 static void
 752 finalize (GObject *object)
 753 {
 754 	NautilusDirectory *directory;
 755 	NautilusFile *file;
 756 	char *uri;
 757 
 758 	file = NAUTILUS_FILE (object);
 759 
 760 	g_assert (file->details->operations_in_progress == NULL);
 761 
 762 	if (file->details->is_thumbnailing) {
 763 		uri = nautilus_file_get_uri (file);
 764 		nautilus_thumbnail_remove_from_queue (uri);
 765 		g_free (uri);
 766 	}
 767 	
 768 	nautilus_async_destroying_file (file);
 769 
 770 	remove_from_link_hash_table (file);
 771 
 772 	directory = file->details->directory;
 773 	
 774 	if (nautilus_file_is_self_owned (file)) {
 775 		directory->details->as_file = NULL;
 776 	} else {
 777 		if (!file->details->is_gone) {
 778 			nautilus_directory_remove_file (directory, file);
 779 		}
 780 	}
 781 
 782 	if (file->details->get_info_error) {
 783 		g_error_free (file->details->get_info_error);
 784 	}
 785 
 786 	nautilus_directory_unref (directory);
 787 	eel_ref_str_unref (file->details->name);
 788 	eel_ref_str_unref (file->details->display_name);
 789 	g_free (file->details->display_name_collation_key);
 790 	eel_ref_str_unref (file->details->edit_name);
 791 	if (file->details->icon) {
 792 		g_object_unref (file->details->icon);
 793 	}
 794 	g_free (file->details->thumbnail_path);
 795 	g_free (file->details->symlink_name);
 796 	eel_ref_str_unref (file->details->mime_type);
 797 	eel_ref_str_unref (file->details->owner);
 798 	eel_ref_str_unref (file->details->owner_real);
 799 	eel_ref_str_unref (file->details->group);
 800 	g_free (file->details->selinux_context);
 801 	g_free (file->details->description);
 802 	g_free (file->details->top_left_text);
 803 	g_free (file->details->activation_uri);
 804 	g_clear_object (&file->details->custom_icon);
 805 
 806 	if (file->details->thumbnail) {
 807 		g_object_unref (file->details->thumbnail);
 808 	}
 809 	if (file->details->mount) {
 810 		g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file);
 811 		g_object_unref (file->details->mount);
 812 	}
 813 
 814 	eel_ref_str_unref (file->details->filesystem_id);
 815 	g_free (file->details->trash_orig_path);
 816 
 817 	g_list_free_full (file->details->mime_list, g_free);
 818 	g_list_free_full (file->details->pending_extension_emblems, g_free);
 819 	g_list_free_full (file->details->extension_emblems, g_free);
 820 	g_list_free_full (file->details->pending_info_providers, g_object_unref);
 821 
 822 	if (file->details->pending_extension_attributes) {
 823 		g_hash_table_destroy (file->details->pending_extension_attributes);
 824 	}
 825 	
 826 	if (file->details->extension_attributes) {
 827 		g_hash_table_destroy (file->details->extension_attributes);
 828 	}
 829 
 830 	if (file->details->metadata) {
 831 		metadata_hash_free (file->details->metadata);
 832 	}
 833 
 834 	G_OBJECT_CLASS (nautilus_file_parent_class)->finalize (object);
 835 }
 836 
 837 NautilusFile *
 838 nautilus_file_ref (NautilusFile *file)
 839 {
 840 	if (file == NULL) {
 841 		return NULL;
 842 	}
 843 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
 844 
 845 #ifdef NAUTILUS_FILE_DEBUG_REF
 846 	DEBUG_REF_PRINTF("%10p ref'd", file);
 847 #endif
 848 	
 849 	return g_object_ref (file);
 850 }
 851 
 852 void
 853 nautilus_file_unref (NautilusFile *file)
 854 {
 855 	if (file == NULL) {
 856 		return;
 857 	}
 858 
 859 	g_return_if_fail (NAUTILUS_IS_FILE (file));
 860 
 861 #ifdef NAUTILUS_FILE_DEBUG_REF
 862 	DEBUG_REF_PRINTF("%10p unref'd", file);
 863 #endif
 864 	
 865 	g_object_unref (file);
 866 }
 867 
 868 /**
 869  * nautilus_file_get_parent_uri_for_display:
 870  * 
 871  * Get the uri for the parent directory.
 872  * 
 873  * @file: The file in question.
 874  * 
 875  * Return value: A string representing the parent's location,
 876  * formatted for user display (including stripping "file://").
 877  * If the parent is NULL, returns the empty string.
 878  */ 
 879 char *
 880 nautilus_file_get_parent_uri_for_display (NautilusFile *file) 
 881 {
 882 	GFile *parent;
 883 	char *result;
 884 
 885 	g_assert (NAUTILUS_IS_FILE (file));
 886 	
 887 	parent = nautilus_file_get_parent_location (file);
 888 	if (parent) {
 889 		result = g_file_get_parse_name (parent);
 890 		g_object_unref (parent);
 891 	} else {
 892 		result = g_strdup ("");
 893 	}
 894 
 895 	return result;
 896 }
 897 
 898 /**
 899  * nautilus_file_get_parent_uri:
 900  * 
 901  * Get the uri for the parent directory.
 902  * 
 903  * @file: The file in question.
 904  * 
 905  * Return value: A string for the parent's location, in "raw URI" form.
 906  * Use nautilus_file_get_parent_uri_for_display instead if the
 907  * result is to be displayed on-screen.
 908  * If the parent is NULL, returns the empty string.
 909  */ 
 910 char *
 911 nautilus_file_get_parent_uri (NautilusFile *file) 
 912 {
 913 	g_assert (NAUTILUS_IS_FILE (file));
 914 	
 915 	if (nautilus_file_is_self_owned (file)) {
 916 		/* Callers expect an empty string, not a NULL. */
 917 		return g_strdup ("");
 918 	}
 919 
 920 	return nautilus_directory_get_uri (file->details->directory);
 921 }
 922 
 923 GFile *
 924 nautilus_file_get_parent_location (NautilusFile *file) 
 925 {
 926 	g_assert (NAUTILUS_IS_FILE (file));
 927 	
 928 	if (nautilus_file_is_self_owned (file)) {
 929 		/* Callers expect an empty string, not a NULL. */
 930 		return NULL;
 931 	}
 932 
 933 	return nautilus_directory_get_location (file->details->directory);
 934 }
 935 
 936 NautilusFile *
 937 nautilus_file_get_parent (NautilusFile *file)
 938 {
 939 	g_assert (NAUTILUS_IS_FILE (file));
 940 	
 941 	if (nautilus_file_is_self_owned (file)) {
 942 		return NULL;
 943 	}
 944 
 945 	return nautilus_directory_get_corresponding_file (file->details->directory);
 946 }
 947 
 948 /**
 949  * nautilus_file_can_read:
 950  * 
 951  * Check whether the user is allowed to read the contents of this file.
 952  * 
 953  * @file: The file to check.
 954  * 
 955  * Return value: FALSE if the user is definitely not allowed to read
 956  * the contents of the file. If the user has read permission, or
 957  * the code can't tell whether the user has read permission,
 958  * returns TRUE (so failures must always be handled).
 959  */
 960 gboolean
 961 nautilus_file_can_read (NautilusFile *file)
 962 {
 963 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
 964 	
 965 	return file->details->can_read;
 966 }
 967 
 968 /**
 969  * nautilus_file_can_write:
 970  * 
 971  * Check whether the user is allowed to write to this file.
 972  * 
 973  * @file: The file to check.
 974  * 
 975  * Return value: FALSE if the user is definitely not allowed to write
 976  * to the file. If the user has write permission, or
 977  * the code can't tell whether the user has write permission,
 978  * returns TRUE (so failures must always be handled).
 979  */
 980 gboolean
 981 nautilus_file_can_write (NautilusFile *file)
 982 {
 983 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
 984 
 985 	return file->details->can_write;
 986 }
 987 
 988 /**
 989  * nautilus_file_can_execute:
 990  * 
 991  * Check whether the user is allowed to execute this file.
 992  * 
 993  * @file: The file to check.
 994  * 
 995  * Return value: FALSE if the user is definitely not allowed to execute
 996  * the file. If the user has execute permission, or
 997  * the code can't tell whether the user has execute permission,
 998  * returns TRUE (so failures must always be handled).
 999  */
1000 gboolean
1001 nautilus_file_can_execute (NautilusFile *file)
1002 {
1003 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1004 
1005 	return file->details->can_execute;
1006 }
1007 
1008 gboolean
1009 nautilus_file_can_mount (NautilusFile *file)
1010 {
1011 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1012 	
1013 	return file->details->can_mount;
1014 }
1015 	
1016 gboolean
1017 nautilus_file_can_unmount (NautilusFile *file)
1018 {
1019 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1020 
1021 	return file->details->can_unmount ||
1022 		(file->details->mount != NULL &&
1023 		 g_mount_can_unmount (file->details->mount));
1024 }
1025 	
1026 gboolean
1027 nautilus_file_can_eject (NautilusFile *file)
1028 {
1029 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1030 
1031 	return file->details->can_eject ||
1032 		(file->details->mount != NULL &&
1033 		 g_mount_can_eject (file->details->mount));
1034 }
1035 
1036 gboolean
1037 nautilus_file_can_start (NautilusFile *file)
1038 {
1039 	gboolean ret;
1040 	GDrive *drive;
1041 
1042 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1043 
1044 	ret = FALSE;
1045 
1046 	if (file->details->can_start) {
1047 		ret = TRUE;
1048 		goto out;
1049 	}
1050 
1051 	if (file->details->mount != NULL) {
1052 		drive = g_mount_get_drive (file->details->mount);
1053 		if (drive != NULL) {
1054 			ret = g_drive_can_start (drive);
1055 			g_object_unref (drive);
1056 		}
1057 	}
1058 
1059  out:
1060 	return ret;
1061 }
1062 
1063 gboolean
1064 nautilus_file_can_start_degraded (NautilusFile *file)
1065 {
1066 	gboolean ret;
1067 	GDrive *drive;
1068 
1069 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1070 
1071 	ret = FALSE;
1072 
1073 	if (file->details->can_start_degraded) {
1074 		ret = TRUE;
1075 		goto out;
1076 	}
1077 
1078 	if (file->details->mount != NULL) {
1079 		drive = g_mount_get_drive (file->details->mount);
1080 		if (drive != NULL) {
1081 			ret = g_drive_can_start_degraded (drive);
1082 			g_object_unref (drive);
1083 		}
1084 	}
1085 
1086  out:
1087 	return ret;
1088 }
1089 
1090 gboolean
1091 nautilus_file_can_poll_for_media (NautilusFile *file)
1092 {
1093 	gboolean ret;
1094 	GDrive *drive;
1095 
1096 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1097 
1098 	ret = FALSE;
1099 
1100 	if (file->details->can_poll_for_media) {
1101 		ret = TRUE;
1102 		goto out;
1103 	}
1104 
1105 	if (file->details->mount != NULL) {
1106 		drive = g_mount_get_drive (file->details->mount);
1107 		if (drive != NULL) {
1108 			ret = g_drive_can_poll_for_media (drive);
1109 			g_object_unref (drive);
1110 		}
1111 	}
1112 
1113  out:
1114 	return ret;
1115 }
1116 
1117 gboolean
1118 nautilus_file_is_media_check_automatic (NautilusFile *file)
1119 {
1120 	gboolean ret;
1121 	GDrive *drive;
1122 
1123 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1124 
1125 	ret = FALSE;
1126 
1127 	if (file->details->is_media_check_automatic) {
1128 		ret = TRUE;
1129 		goto out;
1130 	}
1131 
1132 	if (file->details->mount != NULL) {
1133 		drive = g_mount_get_drive (file->details->mount);
1134 		if (drive != NULL) {
1135 			ret = g_drive_is_media_check_automatic (drive);
1136 			g_object_unref (drive);
1137 		}
1138 	}
1139 
1140  out:
1141 	return ret;
1142 }
1143 
1144 
1145 gboolean
1146 nautilus_file_can_stop (NautilusFile *file)
1147 {
1148 	gboolean ret;
1149 	GDrive *drive;
1150 
1151 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1152 
1153 	ret = FALSE;
1154 
1155 	if (file->details->can_stop) {
1156 		ret = TRUE;
1157 		goto out;
1158 	}
1159 
1160 	if (file->details->mount != NULL) {
1161 		drive = g_mount_get_drive (file->details->mount);
1162 		if (drive != NULL) {
1163 			ret = g_drive_can_stop (drive);
1164 			g_object_unref (drive);
1165 		}
1166 	}
1167 
1168  out:
1169 	return ret;
1170 }
1171 
1172 GDriveStartStopType
1173 nautilus_file_get_start_stop_type (NautilusFile *file)
1174 {
1175 	GDriveStartStopType ret;
1176 	GDrive *drive;
1177 
1178 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1179 
1180 	ret = file->details->start_stop_type;
1181 	if (ret != G_DRIVE_START_STOP_TYPE_UNKNOWN)
1182 		goto out;
1183 
1184 	if (file->details->mount != NULL) {
1185 		drive = g_mount_get_drive (file->details->mount);
1186 		if (drive != NULL) {
1187 			ret = g_drive_get_start_stop_type (drive);
1188 			g_object_unref (drive);
1189 		}
1190 	}
1191 
1192  out:
1193 	return ret;
1194 }
1195 
1196 void
1197 nautilus_file_mount (NautilusFile                   *file,
1198 		     GMountOperation                *mount_op,
1199 		     GCancellable                   *cancellable,
1200 		     NautilusFileOperationCallback   callback,
1201 		     gpointer                        callback_data)
1202 {
1203 	GError *error;
1204 	
1205 	if (NAUTILUS_FILE_GET_CLASS (file)->mount == NULL) {
1206 		if (callback) {
1207 			error = NULL;
1208 			g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1209                                              _("This file cannot be mounted"));
1210 			callback (file, NULL, error, callback_data);
1211 			g_error_free (error);
1212 		}
1213 	} else {
1214 		NAUTILUS_FILE_GET_CLASS (file)->mount (file, mount_op, cancellable, callback, callback_data);
1215 	}
1216 }
1217 
1218 typedef struct {
1219 	NautilusFile *file;
1220 	NautilusFileOperationCallback callback;
1221 	gpointer callback_data;
1222 } UnmountData;
1223 
1224 static void
1225 unmount_done (void *callback_data)
1226 {
1227 	UnmountData *data;
1228 
1229 	data = (UnmountData *)callback_data;
1230 	if (data->callback) {
1231 		data->callback (data->file, NULL, NULL, data->callback_data);
1232 	}
1233 	nautilus_file_unref (data->file);
1234 	g_free (data);
1235 }
1236 
1237 void
1238 nautilus_file_unmount (NautilusFile                   *file,
1239 		       GMountOperation                *mount_op,
1240 		       GCancellable                   *cancellable,
1241 		       NautilusFileOperationCallback   callback,
1242 		       gpointer                        callback_data)
1243 {
1244 	GError *error;
1245 	UnmountData *data;
1246 
1247 	if (file->details->can_unmount) {
1248 		if (NAUTILUS_FILE_GET_CLASS (file)->unmount != NULL) {
1249 			NAUTILUS_FILE_GET_CLASS (file)->unmount (file, mount_op, cancellable, callback, callback_data);
1250 		} else {
1251 			if (callback) {
1252 				error = NULL;
1253 				g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1254 						     _("This file cannot be unmounted"));
1255 				callback (file, NULL, error, callback_data);
1256 				g_error_free (error);
1257 			}
1258 		}
1259 	} else if (file->details->mount != NULL &&
1260 		   g_mount_can_unmount (file->details->mount)) {
1261 		data = g_new0 (UnmountData, 1);
1262 		data->file = nautilus_file_ref (file);
1263 		data->callback = callback;
1264 		data->callback_data = callback_data;
1265 		nautilus_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, FALSE, TRUE, unmount_done, data);
1266 	} else if (callback) {
1267 		callback (file, NULL, NULL, callback_data);
1268 	}
1269 }
1270 
1271 void
1272 nautilus_file_eject (NautilusFile                   *file,
1273 		     GMountOperation                *mount_op,
1274 		     GCancellable                   *cancellable,
1275 		     NautilusFileOperationCallback   callback,
1276 		     gpointer                        callback_data)
1277 {
1278 	GError *error;
1279 	UnmountData *data;
1280 
1281 	if (file->details->can_eject) {
1282 		if (NAUTILUS_FILE_GET_CLASS (file)->eject != NULL) {
1283 			NAUTILUS_FILE_GET_CLASS (file)->eject (file, mount_op, cancellable, callback, callback_data);
1284 		} else {
1285 			if (callback) {
1286 				error = NULL;
1287 				g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1288 						     _("This file cannot be ejected"));
1289 				callback (file, NULL, error, callback_data);
1290 				g_error_free (error);
1291 			}
1292 		}
1293 	} else if (file->details->mount != NULL &&
1294 		   g_mount_can_eject (file->details->mount)) {
1295 		data = g_new0 (UnmountData, 1);
1296 		data->file = nautilus_file_ref (file);
1297 		data->callback = callback;
1298 		data->callback_data = callback_data;
1299 		nautilus_file_operations_unmount_mount_full (NULL, file->details->mount, NULL, TRUE, TRUE, unmount_done, data);
1300 	} else if (callback) {
1301 		callback (file, NULL, NULL, callback_data);
1302 	}
1303 }
1304 
1305 void
1306 nautilus_file_start (NautilusFile                   *file,
1307 		     GMountOperation                *start_op,
1308 		     GCancellable                   *cancellable,
1309 		     NautilusFileOperationCallback   callback,
1310 		     gpointer                        callback_data)
1311 {
1312 	GError *error;
1313 
1314 	if ((file->details->can_start || file->details->can_start_degraded) &&
1315 	    NAUTILUS_FILE_GET_CLASS (file)->start != NULL) {
1316 		NAUTILUS_FILE_GET_CLASS (file)->start (file, start_op, cancellable, callback, callback_data);
1317 	} else {
1318 		if (callback) {
1319 			error = NULL;
1320 			g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1321                                              _("This file cannot be started"));
1322 			callback (file, NULL, error, callback_data);
1323 			g_error_free (error);
1324 		}
1325 	}
1326 }
1327 
1328 static void
1329 file_stop_callback (GObject *source_object,
1330 		    GAsyncResult *res,
1331 		    gpointer callback_data)
1332 {
1333 	NautilusFileOperation *op;
1334 	gboolean stopped;
1335 	GError *error;
1336 
1337 	op = callback_data;
1338 
1339 	error = NULL;
1340 	stopped = g_drive_stop_finish (G_DRIVE (source_object),
1341 				       res, &error);
1342 
1343 	if (!stopped &&
1344 	    error->domain == G_IO_ERROR &&
1345 	    (error->code == G_IO_ERROR_FAILED_HANDLED ||
1346 	     error->code == G_IO_ERROR_CANCELLED)) {
1347 		g_error_free (error);
1348 		error = NULL;
1349 	}
1350 
1351 	nautilus_file_operation_complete (op, NULL, error);
1352 	if (error) {
1353 		g_error_free (error);
1354 	}
1355 }
1356 
1357 void
1358 nautilus_file_stop (NautilusFile                   *file,
1359 		    GMountOperation                *mount_op,
1360 		    GCancellable                   *cancellable,
1361 		    NautilusFileOperationCallback   callback,
1362 		    gpointer                        callback_data)
1363 {
1364 	GError *error;
1365 
1366 	if (NAUTILUS_FILE_GET_CLASS (file)->stop != NULL) {
1367 		if (file->details->can_stop) {
1368 			NAUTILUS_FILE_GET_CLASS (file)->stop (file, mount_op, cancellable, callback, callback_data);
1369 		} else {
1370 			if (callback) {
1371 				error = NULL;
1372 				g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1373 						     _("This file cannot be stopped"));
1374 				callback (file, NULL, error, callback_data);
1375 				g_error_free (error);
1376 			}
1377 		}
1378 	} else {
1379 		GDrive *drive;
1380 
1381 		drive = NULL;
1382 		if (file->details->mount != NULL)
1383 			drive = g_mount_get_drive (file->details->mount);
1384 
1385 		if (drive != NULL && g_drive_can_stop (drive)) {
1386 			NautilusFileOperation *op;
1387 
1388 			op = nautilus_file_operation_new (file, callback, callback_data);
1389 			if (cancellable) {
1390 				g_object_unref (op->cancellable);
1391 				op->cancellable = g_object_ref (cancellable);
1392 			}
1393 
1394 			g_drive_stop (drive,
1395 				      G_MOUNT_UNMOUNT_NONE,
1396 				      mount_op,
1397 				      op->cancellable,
1398 				      file_stop_callback,
1399 				      op);
1400 		} else {
1401 			if (callback) {
1402 				error = NULL;
1403 				g_set_error_literal (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1404 						     _("This file cannot be stopped"));
1405 				callback (file, NULL, error, callback_data);
1406 				g_error_free (error);
1407 			}
1408 		}
1409 
1410 		if (drive != NULL) {
1411 			g_object_unref (drive);
1412 		}
1413 	}
1414 }
1415 
1416 void
1417 nautilus_file_poll_for_media (NautilusFile *file)
1418 {
1419 	if (file->details->can_poll_for_media) {
1420 		if (NAUTILUS_FILE_GET_CLASS (file)->stop != NULL) {
1421 			NAUTILUS_FILE_GET_CLASS (file)->poll_for_media (file);
1422 		}
1423 	} else if (file->details->mount != NULL) {
1424 		GDrive *drive;
1425 		drive = g_mount_get_drive (file->details->mount);
1426 		if (drive != NULL) {
1427 			g_drive_poll_for_media (drive,
1428 						NULL,  /* cancellable */
1429 						NULL,  /* GAsyncReadyCallback */
1430 						NULL); /* user_data */
1431 			g_object_unref (drive);
1432 		}
1433 	}
1434 }
1435 
1436 /**
1437  * nautilus_file_is_desktop_directory:
1438  * 
1439  * Check whether this file is the desktop directory.
1440  * 
1441  * @file: The file to check.
1442  * 
1443  * Return value: TRUE if this is the physical desktop directory.
1444  */
1445 gboolean
1446 nautilus_file_is_desktop_directory (NautilusFile *file)
1447 {
1448 	GFile *dir;
1449 
1450 	dir = file->details->directory->details->location;
1451 
1452 	if (dir == NULL) {
1453 		return FALSE;
1454 	}
1455 
1456 	return nautilus_is_desktop_directory_file (dir, eel_ref_str_peek (file->details->name));
1457 }
1458 
1459 static gboolean
1460 is_desktop_file (NautilusFile *file)
1461 {
1462 	return nautilus_file_is_mime_type (file, "application/x-desktop");
1463 }
1464 
1465 static gboolean
1466 can_rename_desktop_file (NautilusFile *file)
1467 {
1468 	GFile *location;
1469 	gboolean res;
1470 
1471 	location = nautilus_file_get_location (file);
1472 	res = g_file_is_native (location);
1473 	g_object_unref (location);
1474 	return res;
1475 }
1476 
1477 /**
1478  * nautilus_file_can_rename:
1479  * 
1480  * Check whether the user is allowed to change the name of the file.
1481  * 
1482  * @file: The file to check.
1483  * 
1484  * Return value: FALSE if the user is definitely not allowed to change
1485  * the name of the file. If the user is allowed to change the name, or
1486  * the code can't tell whether the user is allowed to change the name,
1487  * returns TRUE (so rename failures must always be handled).
1488  */
1489 gboolean
1490 nautilus_file_can_rename (NautilusFile *file)
1491 {
1492 	gboolean can_rename;
1493 	
1494 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1495 
1496 	/* Nonexistent files can't be renamed. */
1497 	if (nautilus_file_is_gone (file)) {
1498 		return FALSE;
1499 	}
1500 
1501 	/* Self-owned files can't be renamed */
1502 	if (nautilus_file_is_self_owned (file)) {
1503 		return FALSE;
1504 	}
1505 
1506 	if ((is_desktop_file (file) && !can_rename_desktop_file (file)) ||
1507 	     nautilus_file_is_home (file)) {
1508 		return FALSE;
1509 	}
1510 	
1511 	can_rename = TRUE;
1512 
1513 	/* Certain types of links can't be renamed */
1514 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
1515 		NautilusDesktopLink *link;
1516 
1517 		link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
1518 
1519 		if (link != NULL) {
1520 			can_rename = nautilus_desktop_link_can_rename (link);
1521 			g_object_unref (link);
1522 		}
1523 	}
1524 
1525 	if (!can_rename) {
1526 		return FALSE;
1527 	}
1528 
1529 	return file->details->can_rename;
1530 }
1531 
1532 gboolean
1533 nautilus_file_can_delete (NautilusFile *file)
1534 {
1535 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1536 
1537 	/* Nonexistent files can't be deleted. */
1538 	if (nautilus_file_is_gone (file)) {
1539 		return FALSE;
1540 	}
1541 
1542 	/* Self-owned files can't be deleted */
1543 	if (nautilus_file_is_self_owned (file)) {
1544 		return FALSE;
1545 	}
1546 
1547 	return file->details->can_delete;
1548 }
1549 
1550 gboolean
1551 nautilus_file_can_trash (NautilusFile *file)
1552 {
1553 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1554 
1555 	/* Nonexistent files can't be deleted. */
1556 	if (nautilus_file_is_gone (file)) {
1557 		return FALSE;
1558 	}
1559 
1560 	/* Self-owned files can't be deleted */
1561 	if (nautilus_file_is_self_owned (file)) {
1562 		return FALSE;
1563 	}
1564 
1565 	return file->details->can_trash;
1566 }
1567 
1568 GFile *
1569 nautilus_file_get_location (NautilusFile *file)
1570 {
1571 	GFile *dir;
1572 	
1573 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1574 
1575 	dir = file->details->directory->details->location;
1576 	
1577 	if (nautilus_file_is_self_owned (file)) {
1578 		return g_object_ref (dir);
1579 	}
1580 	
1581 	return g_file_get_child (dir, eel_ref_str_peek (file->details->name));
1582 }
1583 
1584 /* Return the actual uri associated with the passed-in file. */
1585 char *
1586 nautilus_file_get_uri (NautilusFile *file)
1587 {
1588 	char *uri;
1589 	GFile *loc;
1590 	
1591 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1592 
1593 	loc = nautilus_file_get_location (file);
1594 	uri = g_file_get_uri (loc);
1595 	g_object_unref (loc);
1596 	
1597 	return uri;
1598 }
1599 
1600 char *
1601 nautilus_file_get_uri_scheme (NautilusFile *file)
1602 {
1603 	GFile *loc;
1604 	char *scheme;
1605 	
1606 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1607 
1608 	if (file->details->directory == NULL || 
1609 	    file->details->directory->details->location == NULL) {
1610 		return NULL;
1611 	}
1612 
1613 	loc = nautilus_directory_get_location (file->details->directory);
1614 	scheme = g_file_get_uri_scheme (loc);
1615 	g_object_unref (loc);
1616 	
1617 	return scheme;
1618 }
1619 
1620 NautilusFileOperation *
1621 nautilus_file_operation_new (NautilusFile *file,
1622 			     NautilusFileOperationCallback callback,
1623 			     gpointer callback_data)
1624 {
1625 	NautilusFileOperation *op;
1626 
1627 	op = g_new0 (NautilusFileOperation, 1);
1628 	op->file = nautilus_file_ref (file);
1629 	op->callback = callback;
1630 	op->callback_data = callback_data;
1631 	op->cancellable = g_cancellable_new ();
1632 
1633 	op->file->details->operations_in_progress = g_list_prepend
1634 		(op->file->details->operations_in_progress, op);
1635 
1636 	return op;
1637 }
1638 
1639 static void
1640 nautilus_file_operation_remove (NautilusFileOperation *op)
1641 {
1642 	op->file->details->operations_in_progress = g_list_remove
1643 		(op->file->details->operations_in_progress, op);
1644 }
1645 
1646 void
1647 nautilus_file_operation_free (NautilusFileOperation *op)
1648 {
1649 	nautilus_file_operation_remove (op);
1650 	nautilus_file_unref (op->file);
1651 	g_object_unref (op->cancellable);
1652 	if (op->free_data) {
1653 		op->free_data (op->data);
1654 	}
1655 
1656 	if (op->undo_info != NULL) {
1657 		nautilus_file_undo_manager_set_action (op->undo_info);
1658 		g_object_unref (op->undo_info);
1659 	}
1660 
1661 	g_free (op);
1662 }
1663 
1664 void
1665 nautilus_file_operation_complete (NautilusFileOperation *op,
1666 				  GFile *result_file,
1667 				  GError *error)
1668 {
1669 	/* Claim that something changed even if the operation failed.
1670 	 * This makes it easier for some clients who see the "reverting"
1671 	 * as "changing back".
1672 	 */
1673 	nautilus_file_operation_remove (op);
1674 	nautilus_file_changed (op->file);
1675 	if (op->callback) {
1676 		(* op->callback) (op->file, result_file, error, op->callback_data);
1677 	}
1678 
1679 	if (error != NULL) {
1680 		g_clear_object (&op->undo_info);
1681 	}
1682 
1683 	nautilus_file_operation_free (op);
1684 }
1685 
1686 void
1687 nautilus_file_operation_cancel (NautilusFileOperation *op)
1688 {
1689 	/* Cancel the operation if it's still in progress. */
1690 	g_cancellable_cancel (op->cancellable);
1691 }
1692 
1693 static void
1694 rename_get_info_callback (GObject *source_object,
1695 			  GAsyncResult *res,
1696 			  gpointer callback_data)
1697 {
1698 	NautilusFileOperation *op;
1699 	NautilusDirectory *directory;
1700 	NautilusFile *existing_file;
1701 	char *old_name;
1702 	char *old_uri;
1703 	char *new_uri;
1704 	const char *new_name;
1705 	GFileInfo *new_info;
1706 	GError *error;
1707 	
1708 	op = callback_data;
1709 
1710 	error = NULL;
1711 	new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
1712 	if (new_info != NULL) {
1713 		directory = op->file->details->directory;
1714 
1715 		new_name = g_file_info_get_name (new_info);
1716 		
1717 		/* If there was another file by the same name in this
1718 		 * directory, mark it gone.
1719 		 */
1720 		existing_file = nautilus_directory_find_file_by_name (directory, new_name);
1721 		if (existing_file != NULL) {
1722 			nautilus_file_mark_gone (existing_file);
1723 			nautilus_file_changed (existing_file);
1724 		}
1725 		
1726 		old_uri = nautilus_file_get_uri (op->file);
1727 		old_name = g_strdup (eel_ref_str_peek (op->file->details->name));
1728 		
1729 		update_info_and_name (op->file, new_info);
1730 		
1731 		g_free (old_name);
1732 		
1733 		new_uri = nautilus_file_get_uri (op->file);
1734 		nautilus_directory_moved (old_uri, new_uri);
1735 		g_free (new_uri);
1736 		g_free (old_uri);
1737 		
1738 		/* the rename could have affected the display name if e.g.
1739 		 * we're in a vfolder where the name comes from a desktop file
1740 		 * and a rename affects the contents of the desktop file.
1741 		 */
1742 		if (op->file->details->got_custom_display_name) {
1743 			nautilus_file_invalidate_attributes (op->file,
1744 							     NAUTILUS_FILE_ATTRIBUTE_INFO |
1745 							     NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
1746 		}
1747 		
1748 		g_object_unref (new_info);
1749 	}
1750 	nautilus_file_operation_complete (op, NULL, error);
1751 	if (error) {
1752 		g_error_free (error);
1753 	}
1754 }
1755 
1756 static void
1757 rename_callback (GObject *source_object,
1758 		 GAsyncResult *res,
1759 		 gpointer callback_data)
1760 {
1761 	NautilusFileOperation *op;
1762 	GFile *new_file;
1763 	GError *error;
1764 
1765 	op = callback_data;
1766 
1767 	error = NULL;
1768 	new_file = g_file_set_display_name_finish (G_FILE (source_object),
1769 						   res, &error);
1770 
1771 	if (new_file != NULL) {
1772 		if (op->undo_info != NULL) {
1773 			nautilus_file_undo_info_rename_set_data (NAUTILUS_FILE_UNDO_INFO_RENAME (op->undo_info),
1774 								 G_FILE (source_object), new_file);
1775 		}
1776 
1777 		g_file_query_info_async (new_file,
1778 					 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
1779 					 0,
1780 					 G_PRIORITY_DEFAULT,
1781 					 op->cancellable,
1782 					 rename_get_info_callback, op);
1783 	} else {
1784 		nautilus_file_operation_complete (op, NULL, error);
1785 		g_error_free (error);
1786 	}
1787 }
1788 
1789 static gboolean
1790 name_is (NautilusFile *file, const char *new_name)
1791 {
1792 	const char *old_name;
1793 	old_name = eel_ref_str_peek (file->details->name);
1794 	return strcmp (new_name, old_name) == 0;
1795 }
1796 
1797 void
1798 nautilus_file_rename (NautilusFile *file,
1799 		      const char *new_name,
1800 		      NautilusFileOperationCallback callback,
1801 		      gpointer callback_data)
1802 {
1803 	NautilusFileOperation *op;
1804 	char *uri;
1805 	char *old_name;
1806 	char *new_file_name;
1807 	gboolean success, name_changed;
1808 	gboolean is_renameable_desktop_file;
1809 	GFile *location;
1810 	GError *error;
1811 	
1812 	g_return_if_fail (NAUTILUS_IS_FILE (file));
1813 	g_return_if_fail (new_name != NULL);
1814 	g_return_if_fail (callback != NULL);
1815 
1816 	is_renameable_desktop_file =
1817 		is_desktop_file (file) && can_rename_desktop_file (file);
1818 	
1819 	/* Return an error for incoming names containing path separators.
1820 	 * But not for .desktop files as '/' are allowed for them */
1821 	if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
1822 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
1823 				     _("Slashes are not allowed in filenames"));
1824 		(* callback) (file, NULL, error, callback_data);
1825 		g_error_free (error);
1826 		return;
1827 	}
1828 	
1829 	/* Can't rename a file that's already gone.
1830 	 * We need to check this here because there may be a new
1831 	 * file with the same name.
1832 	 */
1833 	if (nautilus_file_is_gone (file)) {
1834 	       	/* Claim that something changed even if the rename
1835 		 * failed. This makes it easier for some clients who
1836 		 * see the "reverting" to the old name as "changing
1837 		 * back".
1838 		 */
1839 		nautilus_file_changed (file);
1840 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1841 				     _("File not found"));
1842 		(* callback) (file, NULL, error, callback_data);
1843 		g_error_free (error);
1844 		return;
1845 	}
1846 
1847 	/* Test the name-hasn't-changed case explicitly, for two reasons.
1848 	 * (1) rename returns an error if new & old are same.
1849 	 * (2) We don't want to send file-changed signal if nothing changed.
1850 	 */
1851 	if (!NAUTILUS_IS_DESKTOP_ICON_FILE (file) &&
1852 	    !is_renameable_desktop_file &&
1853 	    name_is (file, new_name)) {
1854 		(* callback) (file, NULL, NULL, callback_data);
1855 		return;
1856 	}
1857 
1858 	/* Self-owned files can't be renamed. Test the name-not-actually-changing
1859 	 * case before this case.
1860 	 */
1861 	if (nautilus_file_is_self_owned (file)) {
1862 	       	/* Claim that something changed even if the rename
1863 		 * failed. This makes it easier for some clients who
1864 		 * see the "reverting" to the old name as "changing
1865 		 * back".
1866 		 */
1867 		nautilus_file_changed (file);
1868 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1869 				     _("Toplevel files cannot be renamed"));
1870 		
1871 		(* callback) (file, NULL, error, callback_data);
1872 		g_error_free (error);
1873 		return;
1874 	}
1875 
1876 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
1877 		NautilusDesktopLink *link;
1878 
1879 		link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
1880 		old_name = nautilus_file_get_display_name (file);
1881 
1882 		if ((old_name != NULL && strcmp (new_name, old_name) == 0)) {
1883 			success = TRUE;
1884 		} else {
1885 			success = (link != NULL && nautilus_desktop_link_rename (link, new_name));
1886 		}
1887 
1888 		if (success) {
1889 			(* callback) (file, NULL, NULL, callback_data);
1890 		} else {
1891 			error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1892 					     _("Unable to rename desktop icon"));
1893 			(* callback) (file, NULL, error, callback_data);
1894 			g_error_free (error);
1895 		}
1896 
1897 		g_free (old_name);
1898 		g_object_unref (link);
1899 		return;
1900 	}
1901 	
1902 	if (is_renameable_desktop_file) {
1903 		/* Don't actually change the name if the new name is the same.
1904 		 * This helps for the vfolder method where this can happen and
1905 		 * we want to minimize actual changes
1906 		 */
1907 		uri = nautilus_file_get_uri (file);
1908 		old_name = nautilus_link_local_get_text (uri);
1909 		if (old_name != NULL && strcmp (new_name, old_name) == 0) {
1910 			success = TRUE;
1911 			name_changed = FALSE;
1912 		} else {
1913 			success = nautilus_link_local_set_text (uri, new_name);
1914 			name_changed = TRUE;
1915 		}
1916 		g_free (old_name);
1917 		g_free (uri);
1918 
1919 		if (!success) {
1920 			error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1921 					     _("Unable to rename desktop file"));
1922 			(* callback) (file, NULL, error, callback_data);
1923 			g_error_free (error);
1924 			return;
1925 		}
1926 		new_file_name = g_strdup_printf ("%s.desktop", new_name);
1927 		new_file_name = g_strdelimit (new_file_name, "/", '-');
1928 
1929 		if (name_is (file, new_file_name)) {
1930 			if (name_changed) {
1931 				nautilus_file_invalidate_attributes (file,
1932 								     NAUTILUS_FILE_ATTRIBUTE_INFO |
1933 								     NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
1934 			}
1935 
1936 			(* callback) (file, NULL, NULL, callback_data);
1937 			g_free (new_file_name);
1938 			return;
1939 		}
1940 	} else {
1941 		new_file_name = g_strdup (new_name);
1942 	}
1943 
1944 	/* Set up a renaming operation. */
1945 	op = nautilus_file_operation_new (file, callback, callback_data);
1946 	op->is_rename = TRUE;
1947 	location = nautilus_file_get_location (file);
1948 
1949 	/* Tell the undo manager a rename is taking place */
1950 	if (!nautilus_file_undo_manager_pop_flag ()) {
1951 		op->undo_info = nautilus_file_undo_info_rename_new ();
1952 	}
1953 
1954 	/* Do the renaming. */
1955 	g_file_set_display_name_async (location,
1956 				       new_file_name,
1957 				       G_PRIORITY_DEFAULT,
1958 				       op->cancellable,
1959 				       rename_callback,
1960 				       op);
1961 	g_free (new_file_name);
1962 	g_object_unref (location);
1963 }
1964 
1965 gboolean
1966 nautilus_file_rename_in_progress (NautilusFile *file)
1967 {
1968 	GList *node;
1969 	NautilusFileOperation *op;
1970 
1971 	for (node = file->details->operations_in_progress; node != NULL; node = node->next) {
1972 		op = node->data;
1973 		if (op->is_rename) {
1974 			return TRUE;
1975 		}
1976 	}
1977 	return FALSE;
1978 }
1979 
1980 void
1981 nautilus_file_cancel (NautilusFile *file,
1982 		      NautilusFileOperationCallback callback,
1983 		      gpointer callback_data)
1984 {
1985 	GList *node, *next;
1986 	NautilusFileOperation *op;
1987 
1988 	for (node = file->details->operations_in_progress; node != NULL; node = next) {
1989 		next = node->next;
1990 		op = node->data;
1991 
1992 		g_assert (op->file == file);
1993 		if (op->callback == callback && op->callback_data == callback_data) {
1994 			nautilus_file_operation_cancel (op);
1995 		}
1996 	}
1997 }
1998 
1999 gboolean         
2000 nautilus_file_matches_uri (NautilusFile *file, const char *match_uri)
2001 {
2002 	GFile *match_file, *location;
2003 	gboolean result;
2004 
2005 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
2006 	g_return_val_if_fail (match_uri != NULL, FALSE);
2007 	
2008 	location = nautilus_file_get_location (file);
2009 	match_file = g_file_new_for_uri (match_uri);
2010 	result = g_file_equal (location, match_file);
2011 	g_object_unref (location);
2012 	g_object_unref (match_file);
2013 
2014 	return result;
2015 }
2016 
2017 int
2018 nautilus_file_compare_location (NautilusFile *file_1,
2019                                 NautilusFile *file_2)
2020 {
2021 	GFile *loc_a, *loc_b;
2022 	gboolean res;
2023 
2024 	loc_a = nautilus_file_get_location (file_1);
2025 	loc_b = nautilus_file_get_location (file_2);
2026 
2027 	res = !g_file_equal (loc_a, loc_b);
2028 
2029 	g_object_unref (loc_a);
2030 	g_object_unref (loc_b);
2031 
2032 	return (gint) res;
2033 }
2034 
2035 gboolean
2036 nautilus_file_is_local (NautilusFile *file)
2037 {
2038 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
2039 	
2040 	return nautilus_directory_is_local (file->details->directory);
2041 }
2042 
2043 static void
2044 update_link (NautilusFile *link_file, NautilusFile *target_file)
2045 {
2046 	g_assert (NAUTILUS_IS_FILE (link_file));
2047 	g_assert (NAUTILUS_IS_FILE (target_file));
2048 
2049 	/* FIXME bugzilla.gnome.org 42044: If we don't put any code
2050 	 * here then the hash table is a waste of time.
2051 	 */
2052 }
2053 
2054 static GList *
2055 get_link_files (NautilusFile *target_file)
2056 {
2057 	char *uri;
2058 	GList **link_files;
2059 	
2060 	if (symbolic_links == NULL) {
2061 		link_files = NULL;
2062 	} else {
2063 		uri = nautilus_file_get_uri (target_file);
2064 		link_files = g_hash_table_lookup (symbolic_links, uri);
2065 		g_free (uri);
2066 	}
2067 	if (link_files) {
2068 		return nautilus_file_list_copy (*link_files);
2069 	}
2070 	return NULL;
2071 }
2072 
2073 static void
2074 update_links_if_target (NautilusFile *target_file)
2075 {
2076 	GList *link_files, *p;
2077 
2078 	link_files = get_link_files (target_file);
2079 	for (p = link_files; p != NULL; p = p->next) {
2080 		update_link (NAUTILUS_FILE (p->data), target_file);
2081 	}
2082 	nautilus_file_list_free (link_files);
2083 }
2084 
2085 static gboolean
2086 update_info_internal (NautilusFile *file,
2087 		      GFileInfo *info,
2088 		      gboolean update_name)
2089 {
2090 	GList *node;
2091 	gboolean changed;
2092 	gboolean is_symlink, is_hidden, is_mountpoint;
2093 	gboolean has_permissions;
2094 	guint32 permissions;
2095 	gboolean can_read, can_write, can_execute, can_delete, can_trash, can_rename, can_mount, can_unmount, can_eject;
2096 	gboolean can_start, can_start_degraded, can_stop, can_poll_for_media, is_media_check_automatic;
2097 	GDriveStartStopType start_stop_type;
2098 	gboolean thumbnailing_failed;
2099 	int uid, gid;
2100 	goffset size;
2101 	int sort_order;
2102 	time_t atime, mtime;
2103 	time_t trash_time;
2104 	GTimeVal g_trash_time;
2105 	const char * time_string;
2106 	const char *symlink_name, *mime_type, *selinux_context, *name, *thumbnail_path;
2107 	GFileType file_type;
2108 	GIcon *icon;
2109 	char *old_activation_uri;
2110 	const char *activation_uri;
2111 	const char *description;
2112 	const char *filesystem_id;
2113 	const char *trash_orig_path;
2114 	const char *group, *owner, *owner_real;
2115 	gboolean free_owner, free_group;
2116 	
2117 	if (file->details->is_gone) {
2118 		return FALSE;
2119 	}
2120 
2121 	if (info == NULL) {
2122 		nautilus_file_mark_gone (file);
2123 		return TRUE;
2124 	}
2125 
2126 	file->details->file_info_is_up_to_date = TRUE;
2127 
2128 	/* FIXME bugzilla.gnome.org 42044: Need to let links that
2129 	 * point to the old name know that the file has been renamed.
2130 	 */
2131 
2132 	remove_from_link_hash_table (file);
2133 
2134 	changed = FALSE;
2135 
2136 	if (!file->details->got_file_info) {
2137 		changed = TRUE;
2138 	}
2139 	file->details->got_file_info = TRUE;
2140 
2141 	changed |= nautilus_file_set_display_name (file,
2142 						  g_file_info_get_display_name (info),
2143 						  g_file_info_get_edit_name (info),
2144 						  FALSE);
2145 
2146 	mime_type = g_file_info_get_content_type (info);
2147 	if (g_strcmp0 (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0) {
2148 		g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
2149 	}
2150 
2151 	file_type = g_file_info_get_file_type (info);
2152 	if (file->details->type != file_type) {
2153 		changed = TRUE;
2154 	}
2155 	file->details->type = file_type;
2156 
2157 	if (!file->details->got_custom_activation_uri) {
2158 		activation_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
2159 		if (activation_uri == NULL) {
2160 			if (file->details->activation_uri) {
2161 				g_free (file->details->activation_uri);
2162 				file->details->activation_uri = NULL;
2163 				changed = TRUE;
2164 			}
2165 		} else {
2166 			old_activation_uri = file->details->activation_uri;
2167 			file->details->activation_uri = g_strdup (activation_uri);
2168 			
2169 			if (old_activation_uri) {
2170 				if (strcmp (old_activation_uri,
2171 					    file->details->activation_uri) != 0) {
2172 					changed = TRUE;
2173 				}
2174 				g_free (old_activation_uri);
2175 			} else {
2176 				changed = TRUE;
2177 			}
2178 		}
2179 	}
2180 	
2181 	is_symlink = g_file_info_get_is_symlink (info);
2182 	if (file->details->is_symlink != is_symlink) {
2183 		changed = TRUE;
2184 	}
2185 	file->details->is_symlink = is_symlink;
2186 
2187 	is_hidden = g_file_info_get_is_hidden (info) || g_file_info_get_is_backup (info);
2188 	if (file->details->is_hidden != is_hidden) {
2189 		changed = TRUE;
2190 	}
2191 	file->details->is_hidden = is_hidden;
2192 
2193 	is_mountpoint = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT);
2194 	if (file->details->is_mountpoint != is_mountpoint) {
2195 		changed = TRUE;
2196 	}
2197 	file->details->is_mountpoint = is_mountpoint;
2198 
2199 	has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
2200 	permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);;
2201 	if (file->details->has_permissions != has_permissions ||
2202 	    file->details->permissions != permissions) {
2203 		changed = TRUE;
2204 	}
2205 	file->details->has_permissions = has_permissions;
2206 	file->details->permissions = permissions;
2207 
2208 	/* We default to TRUE for this if we can't know */
2209 	can_read = TRUE;
2210 	can_write = TRUE;
2211 	can_execute = TRUE;
2212 	can_delete = TRUE;
2213 	can_trash = TRUE;
2214 	can_rename = TRUE;
2215 	can_mount = FALSE;
2216 	can_unmount = FALSE;
2217 	can_eject = FALSE;
2218 	can_start = FALSE;
2219 	can_start_degraded = FALSE;
2220 	can_stop = FALSE;
2221 	can_poll_for_media = FALSE;
2222 	is_media_check_automatic = FALSE;
2223 	start_stop_type = G_DRIVE_START_STOP_TYPE_UNKNOWN;
2224 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) {
2225 		can_read = g_file_info_get_attribute_boolean (info,
2226 							      G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
2227 	}
2228 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
2229 		can_write = g_file_info_get_attribute_boolean (info,
2230 							       G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
2231 	}
2232 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) {
2233 		can_execute = g_file_info_get_attribute_boolean (info,
2234 								G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
2235 	}
2236 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) {
2237 		can_delete = g_file_info_get_attribute_boolean (info,
2238 								G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
2239 	}
2240 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) {
2241 		can_trash = g_file_info_get_attribute_boolean (info,
2242 							       G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
2243 	}
2244 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)) {
2245 		can_rename = g_file_info_get_attribute_boolean (info,
2246 								G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME);
2247 	}
2248 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT)) {
2249 		can_mount = g_file_info_get_attribute_boolean (info,
2250 							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT);
2251 	}
2252 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT)) {
2253 		can_unmount = g_file_info_get_attribute_boolean (info,
2254 								 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT);
2255 	}
2256 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT)) {
2257 		can_eject = g_file_info_get_attribute_boolean (info,
2258 							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);
2259 	}
2260 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START)) {
2261 		can_start = g_file_info_get_attribute_boolean (info,
2262 							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START);
2263 	}
2264 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED)) {
2265 		can_start_degraded = g_file_info_get_attribute_boolean (info,
2266 							       G_FILE_ATTRIBUTE_MOUNTABLE_CAN_START_DEGRADED);
2267 	}
2268 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP)) {
2269 		can_stop = g_file_info_get_attribute_boolean (info,
2270 							      G_FILE_ATTRIBUTE_MOUNTABLE_CAN_STOP);
2271 	}
2272 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE)) {
2273 		start_stop_type = g_file_info_get_attribute_uint32 (info,
2274 								    G_FILE_ATTRIBUTE_MOUNTABLE_START_STOP_TYPE);
2275 	}
2276 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL)) {
2277 		can_poll_for_media = g_file_info_get_attribute_boolean (info,
2278 									G_FILE_ATTRIBUTE_MOUNTABLE_CAN_POLL);
2279 	}
2280 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC)) {
2281 		is_media_check_automatic = g_file_info_get_attribute_boolean (info,
2282 									      G_FILE_ATTRIBUTE_MOUNTABLE_IS_MEDIA_CHECK_AUTOMATIC);
2283 	}
2284 	if (file->details->can_read != can_read ||
2285 	    file->details->can_write != can_write ||
2286 	    file->details->can_execute != can_execute ||
2287 	    file->details->can_delete != can_delete ||
2288 	    file->details->can_trash != can_trash ||
2289 	    file->details->can_rename != can_rename ||
2290 	    file->details->can_mount != can_mount ||
2291 	    file->details->can_unmount != can_unmount ||
2292 	    file->details->can_eject != can_eject ||
2293 	    file->details->can_start != can_start ||
2294 	    file->details->can_start_degraded != can_start_degraded ||
2295 	    file->details->can_stop != can_stop ||
2296 	    file->details->start_stop_type != start_stop_type ||
2297 	    file->details->can_poll_for_media != can_poll_for_media ||
2298 	    file->details->is_media_check_automatic != is_media_check_automatic) {
2299 		changed = TRUE;
2300 	}
2301 	
2302 	file->details->can_read = can_read;
2303 	file->details->can_write = can_write;
2304 	file->details->can_execute = can_execute;
2305 	file->details->can_delete = can_delete;
2306 	file->details->can_trash = can_trash;
2307 	file->details->can_rename = can_rename;
2308 	file->details->can_mount = can_mount;
2309 	file->details->can_unmount = can_unmount;
2310 	file->details->can_eject = can_eject;
2311 	file->details->can_start = can_start;
2312 	file->details->can_start_degraded = can_start_degraded;
2313 	file->details->can_stop = can_stop;
2314 	file->details->start_stop_type = start_stop_type;
2315 	file->details->can_poll_for_media = can_poll_for_media;
2316 	file->details->is_media_check_automatic = is_media_check_automatic;
2317 
2318 	free_owner = FALSE;
2319 	owner = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER);
2320 	owner_real = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_USER_REAL);
2321 	free_group = FALSE;
2322 	group = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_OWNER_GROUP);
2323 	
2324 	uid = -1;
2325 	gid = -1;
2326 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID)) {
2327 		uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
2328 		if (owner == NULL) {
2329 			free_owner = TRUE;
2330 			owner = g_strdup_printf ("%d", uid);
2331 		}
2332 	}
2333 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID)) {
2334 		gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
2335 		if (group == NULL) {
2336 			free_group = TRUE;
2337 			group = g_strdup_printf ("%d", gid);
2338 		}
2339 	}
2340 	if (file->details->uid != uid ||
2341 	    file->details->gid != gid) {
2342 		changed = TRUE;
2343 	}
2344 	file->details->uid = uid;
2345 	file->details->gid = gid;
2346 
2347 	if (g_strcmp0 (eel_ref_str_peek (file->details->owner), owner) != 0) {
2348 		changed = TRUE;
2349 		eel_ref_str_unref (file->details->owner);
2350 		file->details->owner = eel_ref_str_get_unique (owner);
2351 	}
2352 	
2353 	if (g_strcmp0 (eel_ref_str_peek (file->details->owner_real), owner_real) != 0) {
2354 		changed = TRUE;
2355 		eel_ref_str_unref (file->details->owner_real);
2356 		file->details->owner_real = eel_ref_str_get_unique (owner_real);
2357 	}
2358 	
2359 	if (g_strcmp0 (eel_ref_str_peek (file->details->group), group) != 0) {
2360 		changed = TRUE;
2361 		eel_ref_str_unref (file->details->group);
2362 		file->details->group = eel_ref_str_get_unique (group);
2363 	}
2364 
2365 	if (free_owner) {
2366 		g_free ((char *)owner);
2367 	}
2368 	if (free_group) {
2369 		g_free ((char *)group);
2370 	}
2371 	
2372 	size = -1;
2373 	if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) {
2374 		size = g_file_info_get_size (info);
2375 	}
2376 	if (file->details->size != size) {
2377 		changed = TRUE;
2378 	}
2379 	file->details->size = size;
2380 
2381 	sort_order = g_file_info_get_sort_order (info);
2382 	if (file->details->sort_order != sort_order) {
2383 		changed = TRUE;
2384 	}
2385 	file->details->sort_order = sort_order;
2386 	
2387 	atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
2388 	mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
2389 	if (file->details->atime != atime ||
2390 	    file->details->mtime != mtime) {
2391 		if (file->details->thumbnail == NULL) {
2392 			file->details->thumbnail_is_up_to_date = FALSE;
2393 		}
2394 
2395 		changed = TRUE;
2396 	}
2397 	file->details->atime = atime;
2398 	file->details->mtime = mtime;
2399 
2400 	if (file->details->thumbnail != NULL &&
2401 	    file->details->thumbnail_mtime != 0 &&
2402 	    file->details->thumbnail_mtime != mtime) {
2403 		file->details->thumbnail_is_up_to_date = FALSE;
2404 		changed = TRUE;
2405 	}
2406 
2407 	icon = g_file_info_get_icon (info);
2408 	if (!g_icon_equal (icon, file->details->icon)) {
2409 		changed = TRUE;
2410 
2411 		if (file->details->icon) {
2412 			g_object_unref (file->details->icon);
2413 		}
2414 		file->details->icon = g_object_ref (icon);
2415 	}
2416 
2417 	thumbnail_path =  g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
2418 	if (g_strcmp0 (file->details->thumbnail_path, thumbnail_path) != 0) {
2419 		changed = TRUE;
2420 		g_free (file->details->thumbnail_path);
2421 		file->details->thumbnail_path = g_strdup (thumbnail_path);
2422 	}
2423 
2424 	thumbnailing_failed =  g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
2425 	if (file->details->thumbnailing_failed != thumbnailing_failed) {
2426 		changed = TRUE;
2427 		file->details->thumbnailing_failed = thumbnailing_failed;
2428 	}
2429 	
2430 	symlink_name = g_file_info_get_symlink_target (info);
2431 	if (g_strcmp0 (file->details->symlink_name, symlink_name) != 0) {
2432 		changed = TRUE;
2433 		g_free (file->details->symlink_name);
2434 		file->details->symlink_name = g_strdup (symlink_name);
2435 	}
2436 
2437 	mime_type = g_file_info_get_content_type (info);
2438 	if (g_strcmp0 (eel_ref_str_peek (file->details->mime_type), mime_type) != 0) {
2439 		changed = TRUE;
2440 		eel_ref_str_unref (file->details->mime_type);
2441 		file->details->mime_type = eel_ref_str_get_unique (mime_type);
2442 	}
2443 	
2444 	selinux_context = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT);
2445 	if (g_strcmp0 (file->details->selinux_context, selinux_context) != 0) {
2446 		changed = TRUE;
2447 		g_free (file->details->selinux_context);
2448 		file->details->selinux_context = g_strdup (selinux_context);
2449 	}
2450 	
2451 	description = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION);
2452 	if (g_strcmp0 (file->details->description, description) != 0) {
2453 		changed = TRUE;
2454 		g_free (file->details->description);
2455 		file->details->description = g_strdup (description);
2456 	}
2457 
2458 	filesystem_id = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_ID_FILESYSTEM);
2459 	if (g_strcmp0 (eel_ref_str_peek (file->details->filesystem_id), filesystem_id) != 0) {
2460 		changed = TRUE;
2461 		eel_ref_str_unref (file->details->filesystem_id);
2462 		file->details->filesystem_id = eel_ref_str_get_unique (filesystem_id);
2463 	}
2464 
2465 	trash_time = 0;
2466 	time_string = g_file_info_get_attribute_string (info, "trash::deletion-date");
2467 	if (time_string != NULL) {
2468 		g_time_val_from_iso8601 (time_string, &g_trash_time);
2469 		trash_time = g_trash_time.tv_sec;
2470 	}
2471 	if (file->details->trash_time != trash_time) {
2472 		changed = TRUE;
2473 		file->details->trash_time = trash_time;
2474 	}
2475 
2476 	trash_orig_path = g_file_info_get_attribute_byte_string (info, "trash::orig-path");
2477 	if (g_strcmp0 (file->details->trash_orig_path, trash_orig_path) != 0) {
2478 		changed = TRUE;
2479 		g_free (file->details->trash_orig_path);
2480 		file->details->trash_orig_path = g_strdup (trash_orig_path);
2481 	}
2482 
2483 	changed |=
2484 		nautilus_file_update_metadata_from_info (file, info);
2485 
2486 	if (update_name) {
2487 		name = g_file_info_get_name (info);
2488 		if (file->details->name == NULL ||
2489 		    strcmp (eel_ref_str_peek (file->details->name), name) != 0) {
2490 			changed = TRUE;
2491 
2492 			node = nautilus_directory_begin_file_name_change
2493 				(file->details->directory, file);
2494 			
2495 			eel_ref_str_unref (file->details->name);
2496 			if (g_strcmp0 (eel_ref_str_peek (file->details->display_name),
2497 				       name) == 0) {
2498 				file->details->name = eel_ref_str_ref (file->details->display_name);
2499 			} else {
2500 				file->details->name = eel_ref_str_new (name);
2501 			}
2502 
2503 			if (!file->details->got_custom_display_name &&
2504 			    g_file_info_get_display_name (info) == NULL) {
2505 				/* If the file info's display name is NULL,
2506 				 * nautilus_file_set_display_name() did
2507 				 * not unset the display name.
2508 				 */
2509 				nautilus_file_clear_display_name (file);
2510 			}
2511 
2512 			nautilus_directory_end_file_name_change
2513 				(file->details->directory, file, node);
2514 		}
2515 	}
2516 
2517 	if (changed) {
2518 		add_to_link_hash_table (file);
2519 		
2520 		update_links_if_target (file);
2521 	}
2522 
2523 	return changed;
2524 }
2525 
2526 static gboolean
2527 update_info_and_name (NautilusFile *file,
2528 		      GFileInfo *info)
2529 {
2530 	return update_info_internal (file, info, TRUE);
2531 }
2532 
2533 gboolean
2534 nautilus_file_update_info (NautilusFile *file,
2535 			   GFileInfo *info)
2536 {
2537 	return update_info_internal (file, info, FALSE);
2538 }
2539 
2540 static gboolean
2541 update_name_internal (NautilusFile *file,
2542 		      const char *name,
2543 		      gboolean in_directory)
2544 {
2545 	GList *node;
2546 
2547 	g_assert (name != NULL);
2548 
2549 	if (file->details->is_gone) {
2550 		return FALSE;
2551 	}
2552 
2553 	if (name_is (file, name)) {
2554 		return FALSE;
2555 	}
2556 	
2557 	node = NULL;
2558 	if (in_directory) {
2559 		node = nautilus_directory_begin_file_name_change
2560 			(file->details->directory, file);
2561 	}
2562 	
2563 	eel_ref_str_unref (file->details->name);
2564 	file->details->name = eel_ref_str_new (name);
2565 
2566 	if (!file->details->got_custom_display_name) {
2567 		nautilus_file_clear_display_name (file);
2568 	}
2569 
2570 	if (in_directory) {
2571 		nautilus_directory_end_file_name_change
2572 			(file->details->directory, file, node);
2573 	}
2574 
2575 	return TRUE;
2576 }
2577 
2578 gboolean
2579 nautilus_file_update_name (NautilusFile *file, const char *name)
2580 {
2581 	gboolean ret;
2582 	
2583 	ret = update_name_internal (file, name, TRUE);
2584 
2585 	if (ret) {
2586 		update_links_if_target (file);
2587 	}
2588 
2589 	return ret;
2590 }
2591 
2592 gboolean
2593 nautilus_file_update_name_and_directory (NautilusFile *file, 
2594 					 const char *name,
2595 					 NautilusDirectory *new_directory)
2596 {
2597 	NautilusDirectory *old_directory;
2598 	FileMonitors *monitors;
2599 
2600 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
2601 	g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (file->details->directory), FALSE);
2602 	g_return_val_if_fail (!file->details->is_gone, FALSE);
2603 	g_return_val_if_fail (!nautilus_file_is_self_owned (file), FALSE);
2604 	g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (new_directory), FALSE);
2605 
2606 	old_directory = file->details->directory;
2607 	if (old_directory == new_directory) {
2608 		if (name) {
2609 			return update_name_internal (file, name, TRUE);
2610 		} else {
2611 			return FALSE;
2612 		}
2613 	}
2614 
2615 	nautilus_file_ref (file);
2616 
2617 	/* FIXME bugzilla.gnome.org 42044: Need to let links that
2618 	 * point to the old name know that the file has been moved.
2619 	 */
2620 
2621 	remove_from_link_hash_table (file);
2622 
2623 	monitors = nautilus_directory_remove_file_monitors (old_directory, file);
2624 	nautilus_directory_remove_file (old_directory, file);
2625 
2626 	file->details->directory = nautilus_directory_ref (new_directory);
2627 	nautilus_directory_unref (old_directory);
2628 
2629 	if (name) {
2630 		update_name_internal (file, name, FALSE);
2631 	}
2632 
2633 	nautilus_directory_add_file (new_directory, file);
2634 	nautilus_directory_add_file_monitors (new_directory, file, monitors);
2635 
2636 	add_to_link_hash_table (file);
2637 
2638 	update_links_if_target (file);
2639 
2640 	nautilus_file_unref (file);
2641 
2642 	return TRUE;
2643 }
2644 
2645 void
2646 nautilus_file_set_directory (NautilusFile *file,
2647 			     NautilusDirectory *new_directory)
2648 {
2649 	nautilus_file_update_name_and_directory (file, NULL, new_directory);
2650 }
2651 
2652 static Knowledge
2653 get_item_count (NautilusFile *file,
2654 		guint *count)
2655 {
2656 	gboolean known, unreadable;
2657 
2658 	known = nautilus_file_get_directory_item_count
2659 		(file, count, &unreadable);
2660 	if (!known) {
2661 		return UNKNOWN;
2662 	}
2663 	if (unreadable) {
2664 		return UNKNOWABLE;
2665 	}
2666 	return KNOWN;
2667 }
2668 
2669 static Knowledge
2670 get_size (NautilusFile *file,
2671 	  goffset *size)
2672 {
2673 	/* If we tried and failed, then treat it like there is no size
2674 	 * to know.
2675 	 */
2676 	if (file->details->get_info_failed) {
2677 		return UNKNOWABLE;
2678 	}
2679 
2680 	/* If the info is NULL that means we haven't even tried yet,
2681 	 * so it's just unknown, not unknowable.
2682 	 */
2683 	if (!file->details->got_file_info) {
2684 		return UNKNOWN;
2685 	}
2686 
2687 	/* If we got info with no size in it, it means there is no
2688 	 * such thing as a size as far as gnome-vfs is concerned,
2689 	 * so "unknowable".
2690 	 */
2691 	if (file->details->size == -1) {
2692 		return UNKNOWABLE;
2693 	}
2694 
2695 	/* We have a size! */
2696 	*size = file->details->size;
2697 	return KNOWN;
2698 }
2699 
2700 static Knowledge
2701 get_time (NautilusFile *file,
2702 	  time_t *time_out,
2703 	  NautilusDateType type)
2704 {
2705 	time_t time;
2706 
2707 	/* If we tried and failed, then treat it like there is no size
2708 	 * to know.
2709 	 */
2710 	if (file->details->get_info_failed) {
2711 		return UNKNOWABLE;
2712 	}
2713 
2714 	/* If the info is NULL that means we haven't even tried yet,
2715 	 * so it's just unknown, not unknowable.
2716 	 */
2717 	if (!file->details->got_file_info) {
2718 		return UNKNOWN;
2719 	}
2720 
2721 	switch (type) {
2722 	case NAUTILUS_DATE_TYPE_MODIFIED:
2723 		time = file->details->mtime;
2724 		break;
2725 	case NAUTILUS_DATE_TYPE_ACCESSED:
2726 		time = file->details->atime;
2727 		break;
2728 	case NAUTILUS_DATE_TYPE_TRASHED:
2729 		time = file->details->trash_time;
2730 		break;
2731 	default:
2732 		g_assert_not_reached ();
2733 		break;
2734 	}
2735 
2736 	*time_out = time;
2737 	
2738 	/* If we got info with no modification time in it, it means
2739 	 * there is no such thing as a modification time as far as
2740 	 * gnome-vfs is concerned, so "unknowable".
2741 	 */
2742 	if (time == 0) {
2743 		return UNKNOWABLE;
2744 	}
2745 	return KNOWN;
2746 }
2747 
2748 static int
2749 compare_directories_by_count (NautilusFile *file_1, NautilusFile *file_2)
2750 {
2751 	/* Sort order:
2752 	 *   Directories with unknown # of items
2753 	 *   Directories with "unknowable" # of items
2754 	 *   Directories with 0 items
2755 	 *   Directories with n items
2756 	 */
2757 
2758 	Knowledge count_known_1, count_known_2;
2759 	guint count_1, count_2;
2760 
2761 	count_known_1 = get_item_count (file_1, &count_1);
2762 	count_known_2 = get_item_count (file_2, &count_2);
2763 
2764 	if (count_known_1 > count_known_2) {
2765 		return -1;
2766 	}
2767 	if (count_known_1 < count_known_2) {
2768 		return +1;
2769 	}
2770 
2771 	/* count_known_1 and count_known_2 are equal now. Check if count
2772 	 * details are UNKNOWABLE or UNKNOWN.
2773 	 */ 
2774 	if (count_known_1 == UNKNOWABLE || count_known_1 == UNKNOWN) {
2775 		return 0;
2776 	}
2777 
2778 	if (count_1 < count_2) {
2779 		return -1;
2780 	}
2781 	if (count_1 > count_2) {
2782 		return +1;
2783 	}
2784 
2785 	return 0;
2786 }
2787 
2788 static int
2789 compare_files_by_size (NautilusFile *file_1, NautilusFile *file_2)
2790 {
2791 	/* Sort order:
2792 	 *   Files with unknown size.
2793 	 *   Files with "unknowable" size.
2794 	 *   Files with smaller sizes.
2795 	 *   Files with large sizes.
2796 	 */
2797 
2798 	Knowledge size_known_1, size_known_2;
2799 	goffset size_1 = 0, size_2 = 0;
2800 
2801 	size_known_1 = get_size (file_1, &size_1);
2802 	size_known_2 = get_size (file_2, &size_2);
2803 
2804 	if (size_known_1 > size_known_2) {
2805 		return -1;
2806 	}
2807 	if (size_known_1 < size_known_2) {
2808 		return +1;
2809 	}
2810 
2811 	/* size_known_1 and size_known_2 are equal now. Check if size 
2812 	 * details are UNKNOWABLE or UNKNOWN 
2813 	 */ 
2814 	if (size_known_1 == UNKNOWABLE || size_known_1 == UNKNOWN) {
2815 		return 0;
2816 	}
2817 
2818 	if (size_1 < size_2) {
2819 		return -1;
2820 	}
2821 	if (size_1 > size_2) {
2822 		return +1;
2823 	}
2824 
2825 	return 0;
2826 }
2827 
2828 static int
2829 compare_by_size (NautilusFile *file_1, NautilusFile *file_2)
2830 {
2831 	/* Sort order:
2832 	 *   Directories with n items
2833 	 *   Directories with 0 items
2834 	 *   Directories with "unknowable" # of items
2835 	 *   Directories with unknown # of items
2836 	 *   Files with large sizes.
2837 	 *   Files with smaller sizes.
2838 	 *   Files with "unknowable" size.
2839 	 *   Files with unknown size.
2840 	 */
2841 
2842 	gboolean is_directory_1, is_directory_2;
2843 
2844 	is_directory_1 = nautilus_file_is_directory (file_1);
2845 	is_directory_2 = nautilus_file_is_directory (file_2);
2846 
2847 	if (is_directory_1 && !is_directory_2) {
2848 		return -1;
2849 	}
2850 	if (is_directory_2 && !is_directory_1) {
2851 		return +1;
2852 	}
2853 
2854 	if (is_directory_1) {
2855 		return compare_directories_by_count (file_1, file_2);
2856 	} else {
2857 		return compare_files_by_size (file_1, file_2);
2858 	}
2859 }
2860 
2861 static int
2862 compare_by_display_name (NautilusFile *file_1, NautilusFile *file_2)
2863 {
2864 	const char *name_1, *name_2;
2865 	const char *key_1, *key_2;
2866 	gboolean sort_last_1, sort_last_2;
2867 	int compare;
2868 
2869 	name_1 = nautilus_file_peek_display_name (file_1);
2870 	name_2 = nautilus_file_peek_display_name (file_2);
2871 
2872 	sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
2873 	sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
2874 
2875 	if (sort_last_1 && !sort_last_2) {
2876 		compare = +1;
2877 	} else if (!sort_last_1 && sort_last_2) {
2878 		compare = -1;
2879 	} else {
2880 		key_1 = nautilus_file_peek_display_name_collation_key (file_1);
2881 		key_2 = nautilus_file_peek_display_name_collation_key (file_2);
2882 		compare = strcmp (key_1, key_2);
2883 	}
2884 
2885 	return compare;
2886 }
2887 
2888 static int
2889 compare_by_directory_name (NautilusFile *file_1, NautilusFile *file_2)
2890 {
2891 	char *directory_1, *directory_2;
2892 	int compare;
2893 
2894 	if (file_1->details->directory == file_2->details->directory) {
2895 		return 0;
2896 	}
2897 
2898 	directory_1 = nautilus_file_get_parent_uri_for_display (file_1);
2899 	directory_2 = nautilus_file_get_parent_uri_for_display (file_2);
2900 
2901 	compare = g_utf8_collate (directory_1, directory_2);
2902 
2903 	g_free (directory_1);
2904 	g_free (directory_2);
2905 
2906 	return compare;
2907 }
2908 
2909 static GList *
2910 prepend_automatic_keywords (NautilusFile *file,
2911 			    GList *names)
2912 {
2913 	/* Prepend in reverse order. */
2914 	NautilusFile *parent;
2915 
2916 	parent = nautilus_file_get_parent (file);
2917 
2918 	/* Trash files are assumed to be read-only, 
2919 	 * so we want to ignore them here. */
2920 	if (!nautilus_file_can_write (file) &&
2921 	    !nautilus_file_is_in_trash (file) &&
2922 	    (parent == NULL || nautilus_file_can_write (parent))) {
2923 		names = g_list_prepend
2924 			(names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE));
2925 	}
2926 	if (!nautilus_file_can_read (file)) {
2927 		names = g_list_prepend
2928 			(names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_CANT_READ));
2929 	}
2930 	if (nautilus_file_is_symbolic_link (file)) {
2931 		names = g_list_prepend
2932 			(names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_SYMBOLIC_LINK));
2933 	}
2934 
2935 	if (parent) {
2936 		nautilus_file_unref (parent);
2937 	}
2938 		
2939 	
2940 	return names;
2941 }
2942 
2943 static int
2944 compare_by_type (NautilusFile *file_1, NautilusFile *file_2)
2945 {
2946 	gboolean is_directory_1;
2947 	gboolean is_directory_2;
2948 	char *type_string_1;
2949 	char *type_string_2;
2950 	int result;
2951 
2952 	/* Directories go first. Then, if mime types are identical,
2953 	 * don't bother getting strings (for speed). This assumes
2954 	 * that the string is dependent entirely on the mime type,
2955 	 * which is true now but might not be later.
2956 	 */
2957 	is_directory_1 = nautilus_file_is_directory (file_1);
2958 	is_directory_2 = nautilus_file_is_directory (file_2);
2959 	
2960 	if (is_directory_1 && is_directory_2) {
2961 		return 0;
2962 	}
2963 
2964 	if (is_directory_1) {
2965 		return -1;
2966 	}
2967 
2968 	if (is_directory_2) {
2969 		return +1;
2970 	}
2971 
2972 	if (file_1->details->mime_type != NULL &&
2973 	    file_2->details->mime_type != NULL &&
2974 	    strcmp (eel_ref_str_peek (file_1->details->mime_type),
2975 		    eel_ref_str_peek (file_2->details->mime_type)) == 0) {
2976 		return 0;
2977 	}
2978 
2979 	type_string_1 = nautilus_file_get_type_as_string (file_1);
2980 	type_string_2 = nautilus_file_get_type_as_string (file_2);
2981 
2982 	if (type_string_1 == NULL || type_string_2 == NULL) {
2983 		if (type_string_1 != NULL) {
2984 			return -1;
2985 		}
2986 
2987 		if (type_string_2 != NULL) {
2988 			return 1;
2989 		}
2990 
2991 		return 0;
2992 	}
2993 
2994 	result = g_utf8_collate (type_string_1, type_string_2);
2995 
2996 	g_free (type_string_1);
2997 	g_free (type_string_2);
2998 
2999 	return result;
3000 }
3001 
3002 static Knowledge
3003 get_search_relevance (NautilusFile *file,
3004 		      gdouble      *relevance_out)
3005 {
3006 	/* we're only called in search directories, and in that
3007 	 * case, the relevance is always known (or zero).
3008 	 */
3009 	*relevance_out = file->details->search_relevance;
3010 	return KNOWN;
3011 }
3012 
3013 static int
3014 compare_by_search_relevance (NautilusFile *file_1, NautilusFile *file_2)
3015 {
3016 	gdouble r_1, r_2;
3017 
3018 	get_search_relevance (file_1, &r_1);
3019 	get_search_relevance (file_2, &r_2);
3020 
3021 	if (r_1 < r_2) {
3022 		return -1;
3023 	}
3024 	if (r_1 > r_2) {
3025 		return +1;
3026 	}
3027 
3028 	return 0;
3029 }
3030 
3031 static int
3032 compare_by_time (NautilusFile *file_1, NautilusFile *file_2, NautilusDateType type)
3033 {
3034 	/* Sort order:
3035 	 *   Files with unknown times.
3036 	 *   Files with "unknowable" times.
3037 	 *   Files with older times.
3038 	 *   Files with newer times.
3039 	 */
3040 
3041 	Knowledge time_known_1, time_known_2;
3042 	time_t time_1, time_2;
3043 
3044 	time_1 = 0;
3045 	time_2 = 0;
3046 
3047 	time_known_1 = get_time (file_1, &time_1, type);
3048 	time_known_2 = get_time (file_2, &time_2, type);
3049 
3050 	if (time_known_1 > time_known_2) {
3051 		return -1;
3052 	}
3053 	if (time_known_1 < time_known_2) {
3054 		return +1;
3055 	}
3056 	
3057 	/* Now time_known_1 is equal to time_known_2. Check whether 
3058 	 * we failed to get modification times for files
3059 	 */
3060 	if(time_known_1 == UNKNOWABLE || time_known_1 == UNKNOWN) {
3061 		return 0;
3062 	}
3063 		
3064 	if (time_1 < time_2) {
3065 		return -1;
3066 	}
3067 	if (time_1 > time_2) {
3068 		return +1;
3069 	}
3070 
3071 	return 0;
3072 }
3073 
3074 static int
3075 compare_by_full_path (NautilusFile *file_1, NautilusFile *file_2)
3076 {
3077 	int compare;
3078 
3079 	compare = compare_by_directory_name (file_1, file_2);
3080 	if (compare != 0) {
3081 		return compare;
3082 	}
3083 	return compare_by_display_name (file_1, file_2);
3084 }
3085 
3086 static int
3087 nautilus_file_compare_for_sort_internal (NautilusFile *file_1,
3088 					 NautilusFile *file_2,
3089 					 gboolean directories_first,
3090 					 gboolean reversed)
3091 {
3092 	gboolean is_directory_1, is_directory_2;
3093 
3094 	if (directories_first) {
3095 		is_directory_1 = nautilus_file_is_directory (file_1);
3096 		is_directory_2 = nautilus_file_is_directory (file_2);
3097 
3098 		if (is_directory_1 && !is_directory_2) {
3099 			return -1;
3100 		}
3101 
3102 		if (is_directory_2 && !is_directory_1) {
3103 			return +1;
3104 		}
3105 	}
3106 
3107 	if (file_1->details->sort_order < file_2->details->sort_order) {
3108 		return reversed ? 1 : -1;
3109 	} else if (file_1->details->sort_order > file_2->details->sort_order) {
3110 		return reversed ? -1 : 1;
3111 	}
3112 
3113 	return 0;
3114 }
3115 
3116 /**
3117  * nautilus_file_compare_for_sort:
3118  * @file_1: A file object
3119  * @file_2: Another file object
3120  * @sort_type: Sort criterion
3121  * @directories_first: Put all directories before any non-directories
3122  * @reversed: Reverse the order of the items, except that
3123  * the directories_first flag is still respected.
3124  * 
3125  * Return value: int < 0 if @file_1 should come before file_2 in a
3126  * sorted list; int > 0 if @file_2 should come before file_1 in a
3127  * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note
3128  * that each named sort type may actually break ties several ways, with the name
3129  * of the sort criterion being the primary but not only differentiator.
3130  **/
3131 int
3132 nautilus_file_compare_for_sort (NautilusFile *file_1,
3133 				NautilusFile *file_2,
3134 				NautilusFileSortType sort_type,
3135 				gboolean directories_first,
3136 				gboolean reversed)
3137 {
3138 	int result;
3139 
3140 	if (file_1 == file_2) {
3141 		return 0;
3142 	}
3143 	
3144 	result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed);
3145 	
3146 	if (result == 0) {
3147 		switch (sort_type) {
3148 		case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME:
3149 			result = compare_by_display_name (file_1, file_2);
3150 			if (result == 0) {
3151 				result = compare_by_directory_name (file_1, file_2);
3152 			}
3153 			break;
3154 		case NAUTILUS_FILE_SORT_BY_SIZE:
3155 			/* Compare directory sizes ourselves, then if necessary
3156 			 * use GnomeVFS to compare file sizes.
3157 			 */
3158 			result = compare_by_size (file_1, file_2);
3159 			if (result == 0) {
3160 				result = compare_by_full_path (file_1, file_2);
3161 			}
3162 			break;
3163 		case NAUTILUS_FILE_SORT_BY_TYPE:
3164 			/* GnomeVFS doesn't know about our special text for certain
3165 			 * mime types, so we handle the mime-type sorting ourselves.
3166 			 */
3167 			result = compare_by_type (file_1, file_2);
3168 			if (result == 0) {
3169 				result = compare_by_full_path (file_1, file_2);
3170 			}
3171 			break;
3172 		case NAUTILUS_FILE_SORT_BY_MTIME:
3173 			result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_MODIFIED);
3174 			if (result == 0) {
3175 				result = compare_by_full_path (file_1, file_2);
3176 			}
3177 			break;
3178 		case NAUTILUS_FILE_SORT_BY_ATIME:
3179 			result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_ACCESSED);
3180 			if (result == 0) {
3181 				result = compare_by_full_path (file_1, file_2);
3182 			}
3183 			break;
3184 		case NAUTILUS_FILE_SORT_BY_TRASHED_TIME:
3185 			result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_TRASHED);
3186 			if (result == 0) {
3187 				result = compare_by_full_path (file_1, file_2);
3188 			}
3189 			break;
3190 		case NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE:
3191 			result = compare_by_search_relevance (file_1, file_2);
3192 			if (result == 0) {
3193 				result = compare_by_full_path (file_1, file_2);
3194 			}
3195 			break;
3196 		default:
3197 			g_return_val_if_reached (0);
3198 		}
3199 
3200 		if (reversed) {
3201 			result = -result;
3202 		}
3203 	}
3204 
3205 	return result;
3206 }
3207 
3208 int
3209 nautilus_file_compare_for_sort_by_attribute_q   (NautilusFile                   *file_1,
3210 						 NautilusFile                   *file_2,
3211 						 GQuark                          attribute,
3212 						 gboolean                        directories_first,
3213 						 gboolean                        reversed)
3214 {
3215 	int result;
3216 
3217 	if (file_1 == file_2) {
3218 		return 0;
3219 	}
3220 
3221 	/* Convert certain attributes into NautilusFileSortTypes and use
3222 	 * nautilus_file_compare_for_sort()
3223 	 */
3224 	if (attribute == 0 || attribute == attribute_name_q) {
3225 		return nautilus_file_compare_for_sort (file_1, file_2,
3226 						       NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
3227 						       directories_first,
3228 						       reversed);
3229 	} else if (attribute == attribute_size_q) {
3230 		return nautilus_file_compare_for_sort (file_1, file_2,
3231 						       NAUTILUS_FILE_SORT_BY_SIZE,
3232 						       directories_first,
3233 						       reversed);
3234 	} else if (attribute == attribute_type_q) {
3235 		return nautilus_file_compare_for_sort (file_1, file_2,
3236 						       NAUTILUS_FILE_SORT_BY_TYPE,
3237 						       directories_first,
3238 						       reversed);
3239 	} else if (attribute == attribute_modification_date_q || attribute == attribute_date_modified_q || attribute == attribute_date_modified_full_q) {
3240 		return nautilus_file_compare_for_sort (file_1, file_2,
3241 						       NAUTILUS_FILE_SORT_BY_MTIME,
3242 						       directories_first,
3243 						       reversed);
3244         } else if (attribute == attribute_accessed_date_q || attribute == attribute_date_accessed_q || attribute == attribute_date_accessed_full_q) {
3245 		return nautilus_file_compare_for_sort (file_1, file_2,
3246 						       NAUTILUS_FILE_SORT_BY_ATIME,
3247 						       directories_first,
3248 						       reversed);
3249         } else if (attribute == attribute_trashed_on_q || attribute == attribute_trashed_on_full_q) {
3250 		return nautilus_file_compare_for_sort (file_1, file_2,
3251 						       NAUTILUS_FILE_SORT_BY_TRASHED_TIME,
3252 						       directories_first,
3253 						       reversed);
3254         } else if (attribute == attribute_search_relevance_q) {
3255 		return nautilus_file_compare_for_sort (file_1, file_2,
3256 						       NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE,
3257 						       directories_first,
3258 						       reversed);
3259 	}
3260 
3261 	/* it is a normal attribute, compare by strings */
3262 
3263 	result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first, reversed);
3264 	
3265 	if (result == 0) {
3266 		char *value_1;
3267 		char *value_2;
3268 		
3269 		value_1 = nautilus_file_get_string_attribute_q (file_1, 
3270 								attribute);
3271 		value_2 = nautilus_file_get_string_attribute_q (file_2, 
3272 								attribute);
3273 
3274 		if (value_1 != NULL && value_2 != NULL) {
3275 			result = strcmp (value_1, value_2);
3276 		}
3277 
3278 		g_free (value_1);
3279 		g_free (value_2);
3280 
3281 		if (reversed) {
3282 			result = -result;
3283 		}
3284 	}
3285 	
3286 	return result;
3287 }
3288 
3289 int
3290 nautilus_file_compare_for_sort_by_attribute     (NautilusFile                   *file_1,
3291 						 NautilusFile                   *file_2,
3292 						 const char                     *attribute,
3293 						 gboolean                        directories_first,
3294 						 gboolean                        reversed)
3295 {
3296 	return nautilus_file_compare_for_sort_by_attribute_q (file_1, file_2,
3297 							      g_quark_from_string (attribute),
3298 							      directories_first,
3299 							      reversed);
3300 }
3301 
3302 
3303 /**
3304  * nautilus_file_compare_name:
3305  * @file: A file object
3306  * @pattern: A string we are comparing it with
3307  * 
3308  * Return value: result of a comparison of the file name and the given pattern,
3309  * using the same sorting order as sort by name.
3310  **/
3311 int
3312 nautilus_file_compare_display_name (NautilusFile *file,
3313 				    const char *pattern)
3314 {
3315 	const char *name;
3316 	int result;
3317 
3318 	g_return_val_if_fail (pattern != NULL, -1);
3319 
3320 	name = nautilus_file_peek_display_name (file);
3321 	result = g_utf8_collate (name, pattern);
3322 	return result;
3323 }
3324 
3325 
3326 gboolean
3327 nautilus_file_is_hidden_file (NautilusFile *file)
3328 {
3329 	return file->details->is_hidden;
3330 }
3331 
3332 static gboolean
3333 is_file_hidden (NautilusFile *file)
3334 {
3335 	return file->details->directory->details->hidden_file_hash != NULL &&
3336 		g_hash_table_lookup (file->details->directory->details->hidden_file_hash,
3337 				     eel_ref_str_peek (file->details->name)) != NULL;
3338 	
3339 }
3340 
3341 /**
3342  * nautilus_file_should_show:
3343  * @file: the file to check.
3344  * @show_hidden: whether we want to show hidden files or not.
3345  * 
3346  * Determines if a #NautilusFile should be shown. Note that when browsing
3347  * a trash directory, this function will always return %TRUE. 
3348  *
3349  * Returns: %TRUE if the file should be shown, %FALSE if it shouldn't.
3350  */
3351 gboolean 
3352 nautilus_file_should_show (NautilusFile *file, 
3353 			   gboolean show_hidden,
3354 			   gboolean show_foreign)
3355 {
3356 	/* Never hide any files in trash. */
3357 	if (nautilus_file_is_in_trash (file)) {
3358 		return TRUE;
3359 	} else {
3360 		return (show_hidden || (!nautilus_file_is_hidden_file (file) && !is_file_hidden (file))) &&
3361 			(show_foreign || !(nautilus_file_is_in_desktop (file) && nautilus_file_is_foreign_link (file)));
3362 	}
3363 }
3364 
3365 gboolean
3366 nautilus_file_is_home (NautilusFile *file)
3367 {
3368 	GFile *dir;
3369 
3370 	dir = file->details->directory->details->location;
3371 	if (dir == NULL) {
3372 		return FALSE;
3373 	}
3374 
3375 	return nautilus_is_home_directory_file (dir,
3376 						eel_ref_str_peek (file->details->name));
3377 }
3378 
3379 gboolean
3380 nautilus_file_is_in_desktop (NautilusFile *file)
3381 {
3382 	if (file->details->directory->details->location) {
3383 		return nautilus_is_desktop_directory (file->details->directory->details->location);
3384 	}
3385 	return FALSE;
3386 }
3387 
3388 gboolean
3389 nautilus_file_is_in_search (NautilusFile *file)
3390 {
3391 	char *uri;
3392 	gboolean ret;
3393 
3394 	uri = nautilus_file_get_uri (file);
3395 	ret = eel_uri_is_search (uri);
3396 	g_free (uri);
3397 
3398 	return ret;
3399 }
3400 
3401 static gboolean
3402 filter_hidden_partition_callback (gpointer data,
3403 				  gpointer callback_data)
3404 {
3405 	NautilusFile *file;
3406 	FilterOptions options;
3407 
3408 	file = NAUTILUS_FILE (data);
3409 	options = GPOINTER_TO_INT (callback_data);
3410 
3411 	return nautilus_file_should_show (file,
3412 					  options & SHOW_HIDDEN,
3413 					  TRUE);
3414 }
3415 
3416 GList *
3417 nautilus_file_list_filter_hidden (GList    *files,
3418 				  gboolean  show_hidden)
3419 {
3420 	GList *filtered_files;
3421 	GList *removed_files;
3422 
3423 	/* FIXME bugzilla.gnome.org 40653:
3424 	 * Eventually this should become a generic filtering thingy.
3425 	 */
3426 
3427 	filtered_files = nautilus_file_list_copy (files);
3428 	filtered_files = eel_g_list_partition (filtered_files,
3429 					       filter_hidden_partition_callback,
3430 					       GINT_TO_POINTER ((show_hidden ? SHOW_HIDDEN : 0)),
3431 					       &removed_files);
3432 	nautilus_file_list_free (removed_files);
3433 
3434 	return filtered_files;
3435 }
3436 
3437 char *
3438 nautilus_file_get_metadata (NautilusFile *file,
3439 			    const char *key,
3440 			    const char *default_metadata)
3441 {
3442 	guint id;
3443 	char *value;
3444 
3445 	g_return_val_if_fail (key != NULL, g_strdup (default_metadata));
3446 	g_return_val_if_fail (key[0] != '\0', g_strdup (default_metadata));
3447 
3448 	if (file == NULL ||
3449 	    file->details->metadata == NULL) {
3450 		return g_strdup (default_metadata);
3451 	}
3452 
3453 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), g_strdup (default_metadata));
3454 
3455 	id = nautilus_metadata_get_id (key);
3456 	value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id));
3457 
3458 	if (value) {
3459 		return g_strdup (value);
3460 	}
3461 	return g_strdup (default_metadata);
3462 }
3463 
3464 GList *
3465 nautilus_file_get_metadata_list (NautilusFile *file,
3466 				 const char *key)
3467 {
3468 	GList *res;
3469 	guint id;
3470 	char **value;
3471 	int i;
3472 
3473 	g_return_val_if_fail (key != NULL, NULL);
3474 	g_return_val_if_fail (key[0] != '\0', NULL);
3475 
3476 	if (file == NULL ||
3477 	    file->details->metadata == NULL) {
3478 		return NULL;
3479 	}
3480 
3481 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3482 
3483 	id = nautilus_metadata_get_id (key);
3484 	id |= METADATA_ID_IS_LIST_MASK;
3485 
3486 	value = g_hash_table_lookup (file->details->metadata, GUINT_TO_POINTER (id));
3487 
3488 	if (value) {
3489 		res = NULL;
3490 		for (i = 0; value[i] != NULL; i++) {
3491 			res = g_list_prepend (res, g_strdup (value[i]));
3492 		}
3493 		return g_list_reverse (res);
3494 	}
3495 
3496 	return NULL;
3497 }
3498 
3499 void
3500 nautilus_file_set_metadata (NautilusFile *file,
3501 			    const char *key,
3502 			    const char *default_metadata,
3503 			    const char *metadata)
3504 {
3505 	const char *val;
3506 
3507 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3508 	g_return_if_fail (key != NULL);
3509 	g_return_if_fail (key[0] != '\0');
3510 
3511 	val = metadata;
3512 	if (val == NULL) {
3513 		val = default_metadata;
3514 	}
3515 
3516 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata (file, key, val);
3517 }
3518 
3519 void
3520 nautilus_file_set_metadata_list (NautilusFile *file,
3521 				 const char *key,
3522 				 GList *list)
3523 {
3524 	char **val;
3525 	int len, i;
3526 	GList *l;
3527 
3528 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3529 	g_return_if_fail (key != NULL);
3530 	g_return_if_fail (key[0] != '\0');
3531 
3532 	len = g_list_length (list);
3533 	val = g_new (char *, len + 1);
3534 	for (l = list, i = 0; l != NULL; l = l->next, i++) {
3535 		val[i] = l->data;
3536 	}
3537 	val[i] = NULL;
3538 
3539 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->set_metadata_as_list (file, key, val);
3540 
3541 	g_free (val);
3542 }
3543 
3544 gboolean
3545 nautilus_file_get_boolean_metadata (NautilusFile *file,
3546 				    const char   *key,
3547 				    gboolean      default_metadata)
3548 {
3549 	char *result_as_string;
3550 	gboolean result;
3551 
3552 	g_return_val_if_fail (key != NULL, default_metadata);
3553 	g_return_val_if_fail (key[0] != '\0', default_metadata);
3554 
3555 	if (file == NULL) {
3556 		return default_metadata;
3557 	}
3558 
3559 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), default_metadata);
3560 
3561 	result_as_string = nautilus_file_get_metadata
3562 		(file, key, default_metadata ? "true" : "false");
3563 	g_assert (result_as_string != NULL);
3564 
3565 	if (g_ascii_strcasecmp (result_as_string, "true") == 0) {
3566 		result = TRUE;
3567 	} else if (g_ascii_strcasecmp (result_as_string, "false") == 0) {
3568 		result = FALSE;
3569 	} else {
3570 		g_error ("boolean metadata with value other than true or false");
3571 		result = default_metadata;
3572 	}
3573 
3574 	g_free (result_as_string);
3575 	return result;
3576 }
3577 
3578 int
3579 nautilus_file_get_integer_metadata (NautilusFile *file,
3580 				    const char   *key,
3581 				    int           default_metadata)
3582 {
3583 	char *result_as_string;
3584 	char default_as_string[32];
3585 	int result;
3586 	char c;
3587 
3588 	g_return_val_if_fail (key != NULL, default_metadata);
3589 	g_return_val_if_fail (key[0] != '\0', default_metadata);
3590 
3591 	if (file == NULL) {
3592 		return default_metadata;
3593 	}
3594 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), default_metadata);
3595 
3596 	g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata);
3597 	result_as_string = nautilus_file_get_metadata
3598 		(file, key, default_as_string);
3599 
3600 	/* Normally we can't get a a NULL, but we check for it here to
3601 	 * handle the oddball case of a non-existent directory.
3602 	 */
3603 	if (result_as_string == NULL) {
3604 		result = default_metadata;
3605 	} else {
3606 		if (sscanf (result_as_string, " %d %c", &result, &c) != 1) {
3607 			result = default_metadata;
3608 		}
3609 		g_free (result_as_string);
3610 	}
3611 
3612 	return result;
3613 }
3614 
3615 static gboolean
3616 get_time_from_time_string (const char *time_string,
3617 			   time_t *time)
3618 {
3619 	long scanned_time;
3620 	char c;
3621 
3622 	g_assert (time != NULL);
3623 
3624 	/* Only accept string if it has one integer with nothing
3625 	 * afterwards.
3626 	 */
3627 	if (time_string == NULL ||
3628 	    sscanf (time_string, "%ld%c", &scanned_time, &c) != 1) {
3629 		return FALSE;
3630 	}
3631 	*time = (time_t) scanned_time;
3632 	return TRUE;
3633 }
3634 
3635 time_t
3636 nautilus_file_get_time_metadata (NautilusFile *file,
3637 				 const char   *key)
3638 {
3639 	time_t time;
3640 	char *time_string;
3641 
3642 	time_string = nautilus_file_get_metadata (file, key, NULL);
3643 	if (!get_time_from_time_string (time_string, &time)) {
3644 		time = UNDEFINED_TIME;
3645 	}
3646 	g_free (time_string);
3647 
3648 	return time;
3649 }
3650 
3651 void
3652 nautilus_file_set_time_metadata (NautilusFile *file,
3653 				 const char   *key,
3654 				 time_t        time)
3655 {
3656 	char time_str[21];
3657 	char *metadata;
3658 
3659 	if (time != UNDEFINED_TIME) {
3660 		/* 2^64 turns out to be 20 characters */
3661 		g_snprintf (time_str, 20, "%ld", (long int)time);
3662 		time_str[20] = '\0';
3663 		metadata = time_str;
3664 	} else {
3665 		metadata = NULL;
3666 	}
3667 
3668 	nautilus_file_set_metadata (file, key, NULL, metadata);
3669 }
3670 
3671 
3672 void
3673 nautilus_file_set_boolean_metadata (NautilusFile *file,
3674 				    const char   *key,
3675 				    gboolean      default_metadata,
3676 				    gboolean      metadata)
3677 {
3678 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3679 	g_return_if_fail (key != NULL);
3680 	g_return_if_fail (key[0] != '\0');
3681 
3682 	nautilus_file_set_metadata (file, key,
3683 				    default_metadata ? "true" : "false",
3684 				    metadata ? "true" : "false");
3685 }
3686 
3687 void
3688 nautilus_file_set_integer_metadata (NautilusFile *file,
3689 				    const char   *key,
3690 				    int           default_metadata,
3691 				    int           metadata)
3692 {
3693 	char value_as_string[32];
3694 	char default_as_string[32];
3695 
3696 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3697 	g_return_if_fail (key != NULL);
3698 	g_return_if_fail (key[0] != '\0');
3699 
3700 	g_snprintf (value_as_string, sizeof (value_as_string), "%d", metadata);
3701 	g_snprintf (default_as_string, sizeof (default_as_string), "%d", default_metadata);
3702 
3703 	nautilus_file_set_metadata (file, key,
3704 				    default_as_string, value_as_string);
3705 }
3706 
3707 static const char *
3708 nautilus_file_peek_display_name_collation_key (NautilusFile *file)
3709 {
3710 	const char *res;
3711 
3712 	res = file->details->display_name_collation_key;
3713 	if (res == NULL)
3714 		res = "";
3715 
3716 	return res;
3717 }
3718 
3719 static const char *
3720 nautilus_file_peek_display_name (NautilusFile *file)
3721 {
3722 	const char *name;
3723 	char *escaped_name;
3724 
3725 	/* FIXME: for some reason we can get a NautilusFile instance which is
3726 	 *        no longer valid or could be freed somewhere else in the same time.
3727 	 *        There's race condition somewhere. See bug 602500.
3728 	 */
3729 	if (file == NULL || nautilus_file_is_gone (file))
3730 		return "";
3731 
3732 	/* Default to display name based on filename if its not set yet */
3733 	
3734 	if (file->details->display_name == NULL) {
3735 		name = eel_ref_str_peek (file->details->name);
3736 		if (g_utf8_validate (name, -1, NULL)) {
3737 			nautilus_file_set_display_name (file,
3738 							name,
3739 							NULL,
3740 							FALSE);
3741 		} else {
3742 			escaped_name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
3743 			nautilus_file_set_display_name (file,
3744 							escaped_name,
3745 							NULL,
3746 							FALSE);
3747 			g_free (escaped_name);
3748 		}
3749 	}
3750 	
3751 	return eel_ref_str_peek (file->details->display_name);
3752 }
3753 
3754 char *
3755 nautilus_file_get_display_name (NautilusFile *file)
3756 {
3757 	return g_strdup (nautilus_file_peek_display_name (file));
3758 }
3759 
3760 char *
3761 nautilus_file_get_edit_name (NautilusFile *file)
3762 {
3763 	const char *res;
3764 	
3765 	res = eel_ref_str_peek (file->details->edit_name);
3766 	if (res == NULL)
3767 		res = "";
3768 	
3769 	return g_strdup (res);
3770 }
3771 
3772 char *
3773 nautilus_file_get_name (NautilusFile *file)
3774 {
3775 	return g_strdup (eel_ref_str_peek (file->details->name));
3776 }
3777 
3778 /**
3779  * nautilus_file_get_description:
3780  * @file: a #NautilusFile.
3781  * 
3782  * Gets the standard::description key from @file, if 
3783  * it has been cached.
3784  * 
3785  * Returns: a string containing the value of the standard::description 
3786  * 	key, or %NULL.
3787  */
3788 char *
3789 nautilus_file_get_description (NautilusFile *file)
3790 {
3791 	return g_strdup (file->details->description);
3792 }
3793    
3794 void             
3795 nautilus_file_monitor_add (NautilusFile *file,
3796 			   gconstpointer client,
3797 			   NautilusFileAttributes attributes)
3798 {
3799 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3800 	g_return_if_fail (client != NULL);
3801 
3802 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_add (file, client, attributes);
3803 }   
3804 			   
3805 void
3806 nautilus_file_monitor_remove (NautilusFile *file,
3807 			      gconstpointer client)
3808 {
3809 	g_return_if_fail (NAUTILUS_IS_FILE (file));
3810 	g_return_if_fail (client != NULL);
3811 
3812 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->monitor_remove (file, client);
3813 }			      
3814 
3815 gboolean
3816 nautilus_file_is_launcher (NautilusFile *file)
3817 {
3818 	return file->details->is_launcher;
3819 }
3820 
3821 gboolean
3822 nautilus_file_is_foreign_link (NautilusFile *file)
3823 {
3824 	return file->details->is_foreign_link;
3825 }
3826 
3827 gboolean
3828 nautilus_file_is_trusted_link (NautilusFile *file)
3829 {
3830 	return file->details->is_trusted_link;
3831 }
3832 
3833 gboolean
3834 nautilus_file_has_activation_uri (NautilusFile *file)
3835 {
3836 	return file->details->activation_uri != NULL;
3837 }
3838 
3839 
3840 /* Return the uri associated with the passed-in file, which may not be
3841  * the actual uri if the file is an desktop file or a nautilus
3842  * xml link file.
3843  */
3844 char *
3845 nautilus_file_get_activation_uri (NautilusFile *file)
3846 {
3847 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3848 
3849 	if (file->details->activation_uri != NULL) {
3850 		return g_strdup (file->details->activation_uri);
3851 	}
3852 	
3853 	return nautilus_file_get_uri (file);
3854 }
3855 
3856 GFile *
3857 nautilus_file_get_activation_location (NautilusFile *file)
3858 {
3859 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3860 
3861 	if (file->details->activation_uri != NULL) {
3862 		return g_file_new_for_uri (file->details->activation_uri);
3863 	}
3864 	
3865 	return nautilus_file_get_location (file);
3866 }
3867 
3868 
3869 char *
3870 nautilus_file_get_drop_target_uri (NautilusFile *file)
3871 {
3872 	char *uri, *target_uri;
3873 	GFile *location;
3874 	NautilusDesktopLink *link;
3875 	
3876 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3877 
3878 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
3879 		link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
3880 
3881 		if (link != NULL) {
3882 			location = nautilus_desktop_link_get_activation_location (link);
3883 			g_object_unref (link);
3884 			if (location != NULL) {
3885 				uri = g_file_get_uri (location);
3886 				g_object_unref (location);
3887 				return uri;
3888 			}
3889 		}
3890 	}
3891 	
3892 	uri = nautilus_file_get_uri (file);
3893 			
3894 	/* Check for Nautilus link */
3895 	if (nautilus_file_is_nautilus_link (file)) {
3896 		location = nautilus_file_get_location (file);
3897 		/* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */
3898 		if (g_file_is_native (location)) {
3899 			target_uri = nautilus_link_local_get_link_uri (uri);
3900 			if (target_uri != NULL) {
3901 				g_free (uri);
3902 				uri = target_uri;
3903 			}
3904 		}
3905 		g_object_unref (location);
3906 	}
3907 
3908 	return uri;
3909 }
3910 
3911 static gboolean
3912 is_uri_relative (const char *uri)
3913 {
3914 	char *scheme;
3915 	gboolean ret;
3916 
3917 	scheme = g_uri_parse_scheme (uri);
3918 	ret = (scheme == NULL);
3919 	g_free (scheme);
3920 	return ret;
3921 }
3922 
3923 static char *
3924 get_custom_icon_metadata_uri (NautilusFile *file)
3925 {
3926 	char *custom_icon_uri;
3927 	char *uri;
3928 	char *dir_uri;
3929 	
3930 	uri = nautilus_file_get_metadata (file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL);
3931 	if (uri != NULL &&
3932 	    nautilus_file_is_directory (file) &&
3933 	    is_uri_relative (uri)) {
3934 		dir_uri = nautilus_file_get_uri (file);
3935 		custom_icon_uri = g_build_filename (dir_uri, uri, NULL);
3936 		g_free (dir_uri);
3937 		g_free (uri);
3938 	} else {
3939 		custom_icon_uri = uri;
3940 	}
3941 	return custom_icon_uri;
3942 }
3943 
3944 static char *
3945 get_custom_icon_metadata_name (NautilusFile *file)
3946 {
3947 	char *icon_name;
3948 
3949 	icon_name = nautilus_file_get_metadata (file,
3950 						NAUTILUS_METADATA_KEY_CUSTOM_ICON_NAME, NULL);
3951 
3952 	return icon_name;
3953 }
3954 
3955 static GIcon *
3956 get_link_icon (NautilusFile *file)
3957 {
3958 	GIcon *icon = NULL;
3959 
3960 	if (file->details->got_link_info && file->details->custom_icon != NULL) {
3961 		icon = g_object_ref (file->details->custom_icon);
3962 	}
3963 
3964 	return icon;
3965 }
3966 
3967 static GIcon *
3968 get_custom_icon (NautilusFile *file)
3969 {
3970 	char *custom_icon_uri, *custom_icon_name;
3971 	GFile *icon_file;
3972 	GIcon *icon;
3973 
3974 	if (file == NULL) {
3975 		return NULL;
3976 	}
3977 
3978 	icon = NULL;
3979 	
3980 	/* Metadata takes precedence; first we look at the custom
3981 	 * icon URI, then at the custom icon name.
3982 	 */
3983 	custom_icon_uri = get_custom_icon_metadata_uri (file);
3984 
3985 	if (custom_icon_uri) {
3986 		icon_file = g_file_new_for_uri (custom_icon_uri);
3987 		icon = g_file_icon_new (icon_file);
3988 		g_object_unref (icon_file);
3989 		g_free (custom_icon_uri);
3990 	}
3991 
3992 	if (icon == NULL) {
3993 		custom_icon_name = get_custom_icon_metadata_name (file);
3994 
3995 		if (custom_icon_name != NULL) {
3996 			icon = g_themed_icon_new_with_default_fallbacks (custom_icon_name);
3997 			g_free (custom_icon_name);
3998 		}
3999 	}
4000 
4001 	return icon;
4002 }
4003 
4004 GFilesystemPreviewType
4005 nautilus_file_get_filesystem_use_preview (NautilusFile *file)
4006 {
4007 	GFilesystemPreviewType use_preview;
4008 	NautilusFile *parent;
4009 
4010 	parent = nautilus_file_get_parent (file);
4011 	if (parent != NULL) {
4012 		use_preview = parent->details->filesystem_use_preview;
4013 		g_object_unref (parent);
4014 	} else {
4015 		use_preview = 0;
4016 	}
4017 
4018 	return use_preview;
4019 }
4020 
4021 gboolean
4022 nautilus_file_should_show_thumbnail (NautilusFile *file)
4023 {
4024 	const char *mime_type;
4025 	GFilesystemPreviewType use_preview;
4026 
4027 	use_preview = nautilus_file_get_filesystem_use_preview (file);
4028 
4029 	mime_type = eel_ref_str_peek (file->details->mime_type);
4030 	if (mime_type == NULL) {
4031 		mime_type = "application/octet-stream";
4032 	}
4033 
4034 	/* If the thumbnail has already been created, don't care about the size
4035 	 * of the original file.
4036 	 */
4037 	if (nautilus_thumbnail_is_mimetype_limited_by_size (mime_type) &&
4038 	    file->details->thumbnail_path == NULL &&
4039 	    nautilus_file_get_size (file) > cached_thumbnail_limit) {
4040 		return FALSE;
4041 	}
4042 
4043 	if (show_file_thumbs == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
4044 		if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
4045 			return FALSE;
4046 		} else {
4047 			return TRUE;
4048 		}
4049 	} else if (show_file_thumbs == NAUTILUS_SPEED_TRADEOFF_NEVER) {
4050 		return FALSE;
4051 	} else {
4052 		if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
4053 			/* file system says to never thumbnail anything */
4054 			return FALSE;
4055 		} else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
4056 			/* file system says we should treat file as if it's local */
4057 			return TRUE;
4058 		} else {
4059 			/* only local files */
4060 			return nautilus_file_is_local (file);
4061 		}
4062 	}
4063 
4064 	return FALSE;
4065 }
4066 
4067 static void
4068 prepend_icon_name (const char *name,
4069 		   GThemedIcon *icon)
4070 {
4071 	g_themed_icon_prepend_name(icon, name);
4072 }
4073 
4074 GIcon *
4075 nautilus_file_get_gicon (NautilusFile *file,
4076 			 NautilusFileIconFlags flags)
4077 {
4078 	const char * const * names;
4079 	const char *name;
4080 	GPtrArray *prepend_array;
4081 	GMount *mount;
4082 	GIcon *icon, *mount_icon = NULL, *emblemed_icon;
4083 	GEmblem *emblem;
4084 	int i;
4085 	gboolean is_folder = FALSE, is_preview = FALSE, is_inode_directory = FALSE;
4086 
4087 	if (file == NULL) {
4088 		return NULL;
4089 	}
4090 
4091 	icon = get_custom_icon (file);
4092 
4093 	if (icon != NULL) {
4094 		return icon;
4095 	}
4096 
4097 	icon = get_link_icon (file);
4098 
4099 	if (icon != NULL) {
4100 		return icon;
4101 	}
4102 
4103 	if (file->details->icon) {
4104 		icon = NULL;
4105 
4106 		/* fetch the mount icon here, we'll use it later */
4107 		if (flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON ||
4108 		    flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) {
4109 			mount = nautilus_file_get_mount (file);
4110 
4111 			if (mount != NULL) {
4112 				mount_icon = g_mount_get_icon (mount);
4113 				g_object_unref (mount);
4114 			}
4115 		}
4116 
4117 		if (((flags & NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT) ||
4118 		     (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT) ||
4119 		     (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER) ||
4120 		     (flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON) ||
4121 		     (flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) ||
4122 		     ((flags & NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
4123 		      nautilus_file_has_open_window (file))) &&
4124 		    G_IS_THEMED_ICON (file->details->icon)) {
4125 			names = g_themed_icon_get_names (G_THEMED_ICON (file->details->icon));
4126 			prepend_array = g_ptr_array_new ();
4127 
4128 			for (i = 0; names[i] != NULL; i++) {
4129 				name = names[i];
4130 
4131 				if (strcmp (name, "folder") == 0) {
4132 					is_folder = TRUE;
4133 				}
4134 				if (strcmp (name, "inode-directory") == 0) {
4135 					is_inode_directory = TRUE;
4136 				}
4137 				if (strcmp (name, "text-x-generic") == 0 &&
4138 				    (flags & NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT)) {
4139 					is_preview = TRUE;
4140 				}
4141 			}
4142 
4143 			/* Here, we add icons in reverse order of precedence,
4144 			 * because they are later prepended */
4145 			if (is_preview) {
4146 				g_ptr_array_add (prepend_array, "text-x-preview");
4147 			}
4148 			
4149 			/* "folder" should override "inode-directory", not the other way around */
4150 			if (is_inode_directory) {
4151 				g_ptr_array_add (prepend_array, "folder");
4152 			}
4153 			if (is_folder && (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER)) {
4154 				g_ptr_array_add (prepend_array, "folder-open");
4155 			}
4156 			if (is_folder &&
4157 			    (flags & NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
4158 			    nautilus_file_has_open_window (file)) {
4159 				g_ptr_array_add (prepend_array, "folder-visiting");
4160 			}
4161 			if (is_folder &&
4162 			    (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT)) {
4163 				g_ptr_array_add (prepend_array, "folder-drag-accept");
4164 			}
4165 
4166 			if (prepend_array->len) {
4167 				/* When constructing GThemed Icon, pointers from the array
4168 				 * are reused, but not the array itself, so the cast is safe */
4169 				icon = g_themed_icon_new_from_names ((char**) names, -1);
4170 				g_ptr_array_foreach (prepend_array, (GFunc) prepend_icon_name, icon);
4171 			}
4172 
4173 			g_ptr_array_free (prepend_array, TRUE);
4174 		}
4175 
4176 		if (icon == NULL) {
4177 			icon = g_object_ref (file->details->icon);
4178 		}
4179 
4180 		if ((flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON) &&
4181 		    mount_icon != NULL) {
4182 			g_object_unref (icon);
4183 			icon = mount_icon;
4184 		} else if ((flags & NAUTILUS_FILE_ICON_FLAGS_USE_MOUNT_ICON_AS_EMBLEM) &&
4185 			     mount_icon != NULL && !g_icon_equal (mount_icon, icon)) {
4186 
4187 			emblem = g_emblem_new (mount_icon);
4188 			emblemed_icon = g_emblemed_icon_new (icon, emblem);
4189 
4190 			g_object_unref (emblem);
4191 			g_object_unref (icon);
4192 			g_object_unref (mount_icon);
4193 
4194 			icon = emblemed_icon;
4195 		} else if (mount_icon != NULL) {
4196 			g_object_unref (mount_icon);
4197 		}
4198 
4199 		return icon;
4200 	}
4201 	
4202 	return g_themed_icon_new ("text-x-generic");
4203 }
4204 
4205 static GIcon *
4206 get_default_file_icon (NautilusFileIconFlags flags)
4207 {
4208 	static GIcon *fallback_icon = NULL;
4209 	static GIcon *fallback_icon_preview = NULL;
4210 	if (fallback_icon == NULL) {
4211 		fallback_icon = g_themed_icon_new ("text-x-generic");
4212 		fallback_icon_preview = g_themed_icon_new ("text-x-preview");
4213 		g_themed_icon_append_name (G_THEMED_ICON (fallback_icon_preview), "text-x-generic");
4214 	}
4215 	if (flags & NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT) {
4216 		return fallback_icon_preview;
4217 	} else {
4218 		return fallback_icon;
4219 	}
4220 }
4221 
4222 char *
4223 nautilus_file_get_thumbnail_path (NautilusFile *file)
4224 {
4225 	return g_strdup (file->details->thumbnail_path);
4226 }
4227 
4228 NautilusIconInfo *
4229 nautilus_file_get_icon (NautilusFile *file,
4230 			int size,
4231 			NautilusFileIconFlags flags)
4232 {
4233 	NautilusIconInfo *icon;
4234 	GIcon *gicon;
4235 	GdkPixbuf *raw_pixbuf, *scaled_pixbuf;
4236 	int modified_size;
4237 
4238 	if (file == NULL) {
4239 		return NULL;
4240 	}
4241 
4242 	gicon = get_custom_icon (file);
4243 	if (gicon == NULL) {
4244 		gicon = get_link_icon (file);
4245 	}
4246 
4247 	if (gicon != NULL) {
4248 		icon = nautilus_icon_info_lookup (gicon, size);
4249 		g_object_unref (gicon);
4250 
4251 		return icon;
4252 	}
4253 
4254 	DEBUG ("Called file_get_icon(), at size %d, force thumbnail %d", size,
4255 	       flags & NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE);
4256 	
4257 	if (flags & NAUTILUS_FILE_ICON_FLAGS_FORCE_THUMBNAIL_SIZE) {
4258 		modified_size = size;
4259 	} else {
4260 		modified_size = size * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
4261 		DEBUG ("Modifying icon size to %d, as our cached thumbnail size is %d",
4262 		       modified_size, cached_thumbnail_size);
4263 	}
4264 
4265 	if (flags & NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS &&
4266 	    nautilus_file_should_show_thumbnail (file)) {
4267 		if (file->details->thumbnail) {
4268 			int w, h, s;
4269 			double scale;
4270 
4271 			raw_pixbuf = g_object_ref (file->details->thumbnail);
4272 
4273 			w = gdk_pixbuf_get_width (raw_pixbuf);
4274 			h = gdk_pixbuf_get_height (raw_pixbuf);
4275 			
4276 			s = MAX (w, h);			
4277 			/* Don't scale up small thumbnails in the standard view */
4278 			if (s <= cached_thumbnail_size) {
4279 				scale = (double)size / NAUTILUS_ICON_SIZE_STANDARD;
4280 			}
4281 			else {
4282 				scale = (double)modified_size / s;
4283 			}
4284 			/* Make sure that icons don't get smaller than NAUTILUS_ICON_SIZE_SMALLEST */
4285 			if (s*scale <= NAUTILUS_ICON_SIZE_SMALLEST) {
4286 				scale = (double) NAUTILUS_ICON_SIZE_SMALLEST / s;
4287 			}
4288 
4289 			scaled_pixbuf = gdk_pixbuf_scale_simple (raw_pixbuf,
4290 								 MAX (w * scale, 1),
4291 								 MAX (h * scale, 1),
4292 								 GDK_INTERP_BILINEAR);
4293 
4294 			/* We don't want frames around small icons */
4295 			if (!gdk_pixbuf_get_has_alpha (raw_pixbuf) || s >= 128) {
4296 				nautilus_ui_frame_image (&scaled_pixbuf);
4297 			}
4298 
4299 			g_object_unref (raw_pixbuf);
4300 
4301 			/* Don't scale up if more than 25%, then read the original
4302 			   image instead. We don't want to compare to exactly 100%,
4303 			   since the zoom level 150% gives thumbnails at 144, which is
4304 			   ok to scale up from 128. */
4305 			if (modified_size > 128*1.25 &&
4306 			    !file->details->thumbnail_wants_original &&
4307 			    nautilus_can_thumbnail_internally (file)) {
4308 				/* Invalidate if we resize upward */
4309 				file->details->thumbnail_wants_original = TRUE;
4310 				nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL);
4311 			}
4312 
4313 			DEBUG ("Returning thumbnailed image, at size %d %d",
4314 			       (int) (w * scale), (int) (h * scale));
4315 			
4316 			icon = nautilus_icon_info_new_for_pixbuf (scaled_pixbuf);
4317 			g_object_unref (scaled_pixbuf);
4318 			return icon;
4319 		} else if (file->details->thumbnail_path == NULL &&
4320 			   file->details->can_read &&				
4321 			   !file->details->is_thumbnailing &&
4322 			   !file->details->thumbnailing_failed) {
4323 			if (nautilus_can_thumbnail (file)) {
4324 				nautilus_create_thumbnail (file);
4325 			}
4326 		}
4327 	}
4328 
4329 	if (file->details->is_thumbnailing &&
4330 	    flags & NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS)
4331 		gicon = g_themed_icon_new (ICON_NAME_THUMBNAIL_LOADING);
4332 	else
4333 		gicon = nautilus_file_get_gicon (file, flags);
4334 	
4335 	if (gicon) {
4336 		icon = nautilus_icon_info_lookup (gicon, size);
4337 		if (nautilus_icon_info_is_fallback (icon)) {
4338 			g_object_unref (icon);
4339 			icon = nautilus_icon_info_lookup (get_default_file_icon (flags), size);
4340 		}
4341 		g_object_unref (gicon);
4342 		return icon;
4343 	} else {
4344 		return nautilus_icon_info_lookup (get_default_file_icon (flags), size);
4345 	}
4346 }
4347 
4348 GdkPixbuf *
4349 nautilus_file_get_icon_pixbuf (NautilusFile *file,
4350 			       int size,
4351 			       gboolean force_size,
4352 			       NautilusFileIconFlags flags)
4353 {
4354 	NautilusIconInfo *info;
4355 	GdkPixbuf *pixbuf;
4356 
4357 	info = nautilus_file_get_icon (file, size, flags);
4358 	if (force_size) {
4359 		pixbuf =  nautilus_icon_info_get_pixbuf_at_size (info, size);
4360 	} else {
4361 		pixbuf = nautilus_icon_info_get_pixbuf (info);
4362 	}
4363 	g_object_unref (info);
4364 	
4365 	return pixbuf;
4366 }
4367 
4368 gboolean
4369 nautilus_file_get_date (NautilusFile *file,
4370 			NautilusDateType date_type,
4371 			time_t *date)
4372 {
4373 	if (date != NULL) {
4374 		*date = 0;
4375 	}
4376 
4377 	g_return_val_if_fail (date_type == NAUTILUS_DATE_TYPE_ACCESSED
4378 			      || date_type == NAUTILUS_DATE_TYPE_MODIFIED
4379 			      || date_type == NAUTILUS_DATE_TYPE_TRASHED,
4380 			      FALSE);
4381 
4382 	if (file == NULL) {
4383 		return FALSE;
4384 	}
4385 
4386 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4387 
4388 	return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_date (file, date_type, date);
4389 }
4390 
4391 static char *
4392 nautilus_file_get_where_string (NautilusFile *file)
4393 {
4394 	if (file == NULL) {
4395 		return NULL;
4396 	}
4397 
4398 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
4399 
4400 	return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_where_string (file);
4401 }
4402 
4403 static char *
4404 nautilus_file_get_trash_original_file_parent_as_string (NautilusFile *file)
4405 {
4406 	NautilusFile *orig_file, *parent;
4407 	GFile *location;
4408 	char *filename;
4409 
4410 	if (file->details->trash_orig_path != NULL) {
4411 		orig_file = nautilus_file_get_trash_original_file (file);
4412 		parent = nautilus_file_get_parent (orig_file);
4413 		location = nautilus_file_get_location (parent);
4414 
4415 		filename = g_file_get_parse_name (location);
4416 
4417 		g_object_unref (location);
4418 		nautilus_file_unref (parent);
4419 		nautilus_file_unref (orig_file);
4420 
4421 		return filename;
4422 	}
4423 
4424 	return NULL;
4425 }
4426 
4427 /*
4428  * Note to localizers: You can look at man strftime
4429  * for details on the format, but you should only use
4430  * the specifiers from the C standard, not extensions.
4431  * These include "%" followed by one of
4432  * "aAbBcdHIjmMpSUwWxXyYZ". There are two extensions
4433  * in the Nautilus version of strftime that can be
4434  * used (and match GNU extensions). Putting a "-"
4435  * between the "%" and any numeric directive will turn
4436  * off zero padding, and putting a "_" there will use
4437  * space padding instead of zero padding.
4438  */
4439 #define TODAY_TIME_FORMAT_24 N_("%R")
4440 #define TODAY_TIME_FORMAT N_("%-I:%M %P")
4441 #define THIS_MONTH_TIME_FORMAT N_("%b %-e")
4442 #define THIS_YEAR_TIME_FORMAT N_("%b %-e")
4443 #define ANYTIME_TIME_FORMAT N_("%b %-d %Y")
4444 #define FULL_FORMAT N_("%a, %b %e %Y %I:%M:%S %p")
4445 #define FULL_FORMAT_24 N_("%a, %b %e %Y %T")
4446 
4447 /**
4448  * nautilus_file_get_date_as_string:
4449  * 
4450  * Get a user-displayable string representing a file modification date. 
4451  * The caller is responsible for g_free-ing this string.
4452  * @file: NautilusFile representing the file in question.
4453  * 
4454  * Returns: Newly allocated string ready to display to the user.
4455  * 
4456  **/
4457 static char *
4458 nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type, gboolean compact)
4459 {
4460 	time_t file_time_raw;
4461 	const char *format;
4462 	char *result = NULL;
4463 	GDateTime *date_time, *today;
4464 	int y, m, d;
4465 	int y_now, m_now, d_now;
4466 	GDesktopClockFormat value;
4467 	gboolean use_24;
4468 
4469 	if (!nautilus_file_get_date (file, date_type, &file_time_raw)) {
4470 		return NULL;
4471 	}
4472 
4473 	date_time = g_date_time_new_from_unix_local (file_time_raw);
4474 
4475 	g_date_time_get_ymd (date_time, &y, &m, &d);
4476 
4477 	today = g_date_time_new_now_local ();
4478 	g_date_time_get_ymd (today, &y_now, &m_now, &d_now);
4479 	g_date_time_unref (today);
4480 
4481 	value = g_settings_get_enum (gnome_interface_preferences, "clock-format");
4482 	use_24 = value == G_DESKTOP_CLOCK_FORMAT_24H;
4483 
4484 	if (!compact) {
4485 		format = use_24 ? FULL_FORMAT_24 : FULL_FORMAT;
4486 	} else if (y == y_now && m == m_now && d == d_now) {
4487 		format = use_24 ? TODAY_TIME_FORMAT_24 : TODAY_TIME_FORMAT;
4488 	} else if (y == y_now && m == m_now) {
4489 		format = THIS_MONTH_TIME_FORMAT;
4490 	} else if (y == y_now) {
4491 		format = THIS_YEAR_TIME_FORMAT;
4492 	} else {
4493 		format = ANYTIME_TIME_FORMAT;
4494 	}
4495 
4496 	result = g_date_time_format (date_time, _(format));
4497 
4498 	g_date_time_unref (date_time);
4499 
4500 	return result;
4501 }
4502 
4503 static void
4504 show_directory_item_count_changed_callback (gpointer callback_data)
4505 {
4506 	show_directory_item_count = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS);
4507 }
4508 
4509 static gboolean
4510 get_speed_tradeoff_preference_for_file (NautilusFile *file, NautilusSpeedTradeoffValue value)
4511 {
4512 	GFilesystemPreviewType use_preview;
4513 
4514 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4515 
4516 	use_preview = nautilus_file_get_filesystem_use_preview (file);
4517 	
4518 	if (value == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
4519 		if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
4520 			return FALSE;
4521 		} else {
4522 			return TRUE;
4523 		}
4524 	}
4525 	
4526 	if (value == NAUTILUS_SPEED_TRADEOFF_NEVER) {
4527 		return FALSE;
4528 	}
4529 
4530 	g_assert (value == NAUTILUS_SPEED_TRADEOFF_LOCAL_ONLY);
4531 
4532 	if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
4533 		/* file system says to never preview anything */
4534 		return FALSE;
4535 	} else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
4536 		/* file system says we should treat file as if it's local */
4537 		return TRUE;
4538 	} else {
4539 		/* only local files */
4540 		return nautilus_file_is_local (file);
4541 	}
4542 }
4543 
4544 gboolean
4545 nautilus_file_should_show_directory_item_count (NautilusFile *file)
4546 {
4547 	static gboolean show_directory_item_count_callback_added = FALSE;
4548 	
4549 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4550 	
4551 	if (file->details->mime_type &&
4552 	    strcmp (eel_ref_str_peek (file->details->mime_type), "x-directory/smb-share") == 0) {
4553 		return FALSE;
4554 	}
4555 	
4556 	/* Add the callback once for the life of our process */
4557 	if (!show_directory_item_count_callback_added) {
4558 		g_signal_connect_swapped (nautilus_preferences,
4559 					  "changed::" NAUTILUS_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS,
4560 					  G_CALLBACK(show_directory_item_count_changed_callback),
4561 					  NULL);
4562 		show_directory_item_count_callback_added = TRUE;
4563 
4564 		/* Peek for the first time */
4565 		show_directory_item_count_changed_callback (NULL);
4566 	}
4567 
4568 	return get_speed_tradeoff_preference_for_file (file, show_directory_item_count);
4569 }
4570 
4571 gboolean
4572 nautilus_file_should_show_type (NautilusFile *file)
4573 {
4574 	char *uri;
4575 	gboolean ret;
4576 
4577 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4578 
4579 	uri = nautilus_file_get_uri (file);
4580 	ret = ((strcmp (uri, "computer:///") != 0) &&
4581 	       (strcmp (uri, "network:///") != 0) &&
4582 	       (strcmp (uri, "smb:///") != 0));
4583 	g_free (uri);
4584 
4585 	return ret;
4586 }
4587 
4588 gboolean
4589 nautilus_file_should_get_top_left_text (NautilusFile *file)
4590 {
4591 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4592 
4593 	if (show_file_thumbs == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
4594 		return TRUE;
4595 	}
4596 	
4597 	if (show_file_thumbs == NAUTILUS_SPEED_TRADEOFF_NEVER) {
4598 		return FALSE;
4599 	}
4600 
4601 	return get_speed_tradeoff_preference_for_file (file, show_file_thumbs);
4602 }
4603 
4604 /**
4605  * nautilus_file_get_directory_item_count
4606  * 
4607  * Get the number of items in a directory.
4608  * @file: NautilusFile representing a directory.
4609  * @count: Place to put count.
4610  * @count_unreadable: Set to TRUE (if non-NULL) if permissions prevent
4611  * the item count from being read on this directory. Otherwise set to FALSE.
4612  * 
4613  * Returns: TRUE if count is available.
4614  * 
4615  **/
4616 gboolean
4617 nautilus_file_get_directory_item_count (NautilusFile *file, 
4618 					guint *count,
4619 					gboolean *count_unreadable)
4620 {
4621 	if (count != NULL) {
4622 		*count = 0;
4623 	}
4624 	if (count_unreadable != NULL) {
4625 		*count_unreadable = FALSE;
4626 	}
4627 	
4628 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4629 
4630 	if (!nautilus_file_is_directory (file)) {
4631 		return FALSE;
4632 	}
4633 
4634 	if (!nautilus_file_should_show_directory_item_count (file)) {
4635 		return FALSE;
4636 	}
4637 
4638 	return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_item_count 
4639 		(file, count, count_unreadable);
4640 }
4641 
4642 /**
4643  * nautilus_file_get_deep_counts
4644  * 
4645  * Get the statistics about items inside a directory.
4646  * @file: NautilusFile representing a directory or file.
4647  * @directory_count: Place to put count of directories inside.
4648  * @files_count: Place to put count of files inside.
4649  * @unreadable_directory_count: Number of directories encountered
4650  * that were unreadable.
4651  * @total_size: Total size of all files and directories visited.
4652  * @force: Whether the deep counts should even be collected if
4653  * nautilus_file_should_show_directory_item_count returns FALSE
4654  * for this file.
4655  * 
4656  * Returns: Status to indicate whether sizes are available.
4657  * 
4658  **/
4659 NautilusRequestStatus
4660 nautilus_file_get_deep_counts (NautilusFile *file,
4661 			       guint *directory_count,
4662 			       guint *file_count,
4663 			       guint *unreadable_directory_count,
4664 			       goffset *total_size,
4665 			       gboolean force)
4666 {
4667 	if (directory_count != NULL) {
4668 		*directory_count = 0;
4669 	}
4670 	if (file_count != NULL) {
4671 		*file_count = 0;
4672 	}
4673 	if (unreadable_directory_count != NULL) {
4674 		*unreadable_directory_count = 0;
4675 	}
4676 	if (total_size != NULL) {
4677 		*total_size = 0;
4678 	}
4679 
4680 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NAUTILUS_REQUEST_DONE);
4681 
4682 	if (!force && !nautilus_file_should_show_directory_item_count (file)) {
4683 		/* Set field so an existing value isn't treated as up-to-date
4684 		 * when preference changes later.
4685 		 */
4686 		file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
4687 		return file->details->deep_counts_status;
4688 	}
4689 
4690 	return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->get_deep_counts 
4691 		(file, directory_count, file_count,
4692 		 unreadable_directory_count, total_size);
4693 }
4694 
4695 void
4696 nautilus_file_recompute_deep_counts (NautilusFile *file)
4697 {
4698 	if (file->details->deep_counts_status != NAUTILUS_REQUEST_IN_PROGRESS) {
4699 		file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
4700 		if (file->details->directory != NULL) {
4701 			nautilus_directory_add_file_to_work_queue (file->details->directory, file);
4702 			nautilus_directory_async_state_changed (file->details->directory);
4703 		}
4704 	}
4705 }
4706 
4707 
4708 /**
4709  * nautilus_file_get_directory_item_mime_types
4710  * 
4711  * Get the list of mime-types present in a directory.
4712  * @file: NautilusFile representing a directory. It is an error to
4713  * call this function on a file that is not a directory.
4714  * @mime_list: Place to put the list of mime-types.
4715  * 
4716  * Returns: TRUE if mime-type list is available.
4717  * 
4718  **/
4719 gboolean
4720 nautilus_file_get_directory_item_mime_types (NautilusFile *file,
4721 					     GList **mime_list)
4722 {
4723 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4724 	g_return_val_if_fail (mime_list != NULL, FALSE);
4725 
4726 	if (!nautilus_file_is_directory (file)
4727 	    || !file->details->got_mime_list) {
4728 		*mime_list = NULL;
4729 		return FALSE;
4730 	}
4731 
4732 	*mime_list = eel_g_str_list_copy (file->details->mime_list);
4733 	return TRUE;
4734 }
4735 
4736 gboolean
4737 nautilus_file_can_get_size (NautilusFile *file)
4738 {
4739 	return file->details->size == -1;
4740 }
4741 	
4742 
4743 /**
4744  * nautilus_file_get_size
4745  * 
4746  * Get the file size.
4747  * @file: NautilusFile representing the file in question.
4748  * 
4749  * Returns: Size in bytes.
4750  * 
4751  **/
4752 goffset
4753 nautilus_file_get_size (NautilusFile *file)
4754 {
4755 	/* Before we have info on the file, we don't know the size. */
4756 	if (file->details->size == -1)
4757 		return 0;
4758 	return file->details->size;
4759 }
4760 
4761 time_t
4762 nautilus_file_get_mtime (NautilusFile *file)
4763 {
4764 	return file->details->mtime;
4765 }
4766 
4767 
4768 static void
4769 set_attributes_get_info_callback (GObject *source_object,
4770 				  GAsyncResult *res,
4771 				  gpointer callback_data)
4772 {
4773 	NautilusFileOperation *op;
4774 	GFileInfo *new_info;
4775 	GError *error;
4776 	
4777 	op = callback_data;
4778 
4779 	error = NULL;
4780 	new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
4781 	if (new_info != NULL) {
4782 		if (nautilus_file_update_info (op->file, new_info)) {
4783 			nautilus_file_changed (op->file);
4784 		}
4785 		g_object_unref (new_info);
4786 	}
4787 	nautilus_file_operation_complete (op, NULL, error);
4788 	if (error) {
4789 		g_error_free (error);
4790 	}
4791 }
4792 
4793 
4794 static void
4795 set_attributes_callback (GObject *source_object,
4796 			 GAsyncResult *result,
4797 			 gpointer callback_data)
4798 {
4799 	NautilusFileOperation *op;
4800 	GError *error;
4801 	gboolean res;
4802 
4803 	op = callback_data;
4804 
4805 	error = NULL;
4806 	res = g_file_set_attributes_finish (G_FILE (source_object),
4807 					    result,
4808 					    NULL,
4809 					    &error);
4810 
4811 	if (res) {
4812 		g_file_query_info_async (G_FILE (source_object),
4813 					 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
4814 					 0,
4815 					 G_PRIORITY_DEFAULT,
4816 					 op->cancellable,
4817 					 set_attributes_get_info_callback, op);
4818 	} else {
4819 		nautilus_file_operation_complete (op, NULL, error);
4820 		g_error_free (error);
4821 	}
4822 }
4823 
4824 void
4825 nautilus_file_set_attributes (NautilusFile *file, 
4826 			      GFileInfo *attributes,
4827 			      NautilusFileOperationCallback callback,
4828 			      gpointer callback_data)
4829 {
4830 	NautilusFileOperation *op;
4831 	GFile *location;
4832 	
4833 	op = nautilus_file_operation_new (file, callback, callback_data);
4834 
4835 	location = nautilus_file_get_location (file);
4836 	g_file_set_attributes_async (location,
4837 				     attributes,
4838 				     0, 
4839 				     G_PRIORITY_DEFAULT,
4840 				     op->cancellable,
4841 				     set_attributes_callback,
4842 				     op);
4843 	g_object_unref (location);
4844 }
4845 
4846 void
4847 nautilus_file_set_search_relevance (NautilusFile *file,
4848 				    gdouble       relevance)
4849 {
4850 	file->details->search_relevance = relevance;
4851 }
4852 
4853 /**
4854  * nautilus_file_can_get_permissions:
4855  * 
4856  * Check whether the permissions for a file are determinable.
4857  * This might not be the case for files on non-UNIX file systems.
4858  * 
4859  * @file: The file in question.
4860  * 
4861  * Return value: TRUE if the permissions are valid.
4862  */
4863 gboolean
4864 nautilus_file_can_get_permissions (NautilusFile *file)
4865 {
4866 	return file->details->has_permissions;
4867 }
4868 
4869 /**
4870  * nautilus_file_can_set_permissions:
4871  * 
4872  * Check whether the current user is allowed to change
4873  * the permissions of a file.
4874  * 
4875  * @file: The file in question.
4876  * 
4877  * Return value: TRUE if the current user can change the
4878  * permissions of @file, FALSE otherwise. It's always possible
4879  * that when you actually try to do it, you will fail.
4880  */
4881 gboolean
4882 nautilus_file_can_set_permissions (NautilusFile *file)
4883 {
4884 	uid_t user_id;
4885 
4886 	if (file->details->uid != -1 &&
4887 	    nautilus_file_is_local (file)) {
4888 		/* Check the user. */
4889 		user_id = geteuid();
4890 
4891 		/* Owner is allowed to set permissions. */
4892 		if (user_id == (uid_t) file->details->uid) {
4893 			return TRUE;
4894 		}
4895 
4896 		/* Root is also allowed to set permissions. */
4897 		if (user_id == 0) {
4898 			return TRUE;
4899 		}
4900 
4901 		/* Nobody else is allowed. */
4902 		return FALSE;
4903 	}
4904 
4905 	/* pretend to have full chmod rights when no info is available, relevant when
4906 	 * the FS can't provide ownership info, for instance for FTP */
4907 	return TRUE;
4908 }
4909 
4910 guint
4911 nautilus_file_get_permissions (NautilusFile *file)
4912 {
4913 	g_return_val_if_fail (nautilus_file_can_get_permissions (file), 0);
4914 
4915 	return file->details->permissions;
4916 }
4917 
4918 /**
4919  * nautilus_file_set_permissions:
4920  * 
4921  * Change a file's permissions. This should only be called if
4922  * nautilus_file_can_set_permissions returned TRUE.
4923  * 
4924  * @file: NautilusFile representing the file in question.
4925  * @new_permissions: New permissions value. This is the whole
4926  * set of permissions, not a delta.
4927  **/
4928 void
4929 nautilus_file_set_permissions (NautilusFile *file, 
4930 			       guint32 new_permissions,
4931 			       NautilusFileOperationCallback callback,
4932 			       gpointer callback_data)
4933 {
4934 	GFileInfo *info;
4935 	GError *error;
4936 
4937 	if (!nautilus_file_can_set_permissions (file)) {
4938 		/* Claim that something changed even if the permission change failed.
4939 		 * This makes it easier for some clients who see the "reverting"
4940 		 * to the old permissions as "changing back".
4941 		 */
4942 		nautilus_file_changed (file);
4943 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
4944 				     _("Not allowed to set permissions"));
4945 		(* callback) (file, NULL, error, callback_data);
4946 		g_error_free (error);
4947 		return;
4948 	}
4949 			       
4950 	/* Test the permissions-haven't-changed case explicitly
4951 	 * because we don't want to send the file-changed signal if
4952 	 * nothing changed.
4953 	 */
4954 	if (new_permissions == file->details->permissions) {
4955 		(* callback) (file, NULL, NULL, callback_data);
4956 		return;
4957 	}
4958 
4959 	if (!nautilus_file_undo_manager_pop_flag ()) {
4960 		NautilusFileUndoInfo *undo_info;
4961 
4962 		undo_info = nautilus_file_undo_info_permissions_new (nautilus_file_get_location (file),
4963 								     file->details->permissions,
4964 								     new_permissions);
4965 		nautilus_file_undo_manager_set_action (undo_info);
4966 	}
4967 
4968 	info = g_file_info_new ();
4969 	g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, new_permissions);
4970 	nautilus_file_set_attributes (file, info, callback, callback_data);
4971 	
4972 	g_object_unref (info);
4973 }
4974 
4975 /**
4976  * nautilus_file_can_get_selinux_context:
4977  * 
4978  * Check whether the selinux context for a file are determinable.
4979  * This might not be the case for files on non-UNIX file systems,
4980  * files without a context or systems that don't support selinux.
4981  * 
4982  * @file: The file in question.
4983  * 
4984  * Return value: TRUE if the permissions are valid.
4985  */
4986 gboolean
4987 nautilus_file_can_get_selinux_context (NautilusFile *file)
4988 {
4989 	return file->details->selinux_context != NULL;
4990 }
4991 
4992 
4993 /**
4994  * nautilus_file_get_selinux_context:
4995  * 
4996  * Get a user-displayable string representing a file's selinux
4997  * context
4998  * @file: NautilusFile representing the file in question.
4999  * 
5000  * Returns: Newly allocated string ready to display to the user.
5001  * 
5002  **/
5003 char *
5004 nautilus_file_get_selinux_context (NautilusFile *file)
5005 {
5006 	char *translated;
5007 	char *raw;
5008 	
5009 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
5010 
5011 	if (!nautilus_file_can_get_selinux_context (file)) {
5012 		return NULL;
5013 	}
5014 
5015 	raw = file->details->selinux_context;
5016 
5017 #ifdef HAVE_SELINUX
5018 	if (selinux_raw_to_trans_context (raw, &translated) == 0) {
5019 		char *tmp;
5020 		tmp = g_strdup (translated);
5021 		freecon (translated);
5022 		translated = tmp;
5023 	}
5024 	else
5025 #endif
5026 	{
5027 		translated = g_strdup (raw);
5028 	}
5029 	
5030 	return translated;
5031 }
5032 
5033 static char *
5034 get_real_name (const char *name, const char *gecos)
5035 {
5036 	char *locale_string, *part_before_comma, *capitalized_login_name, *real_name;
5037 
5038 	if (gecos == NULL) {
5039 		return NULL;
5040 	}
5041 
5042 	locale_string = eel_str_strip_substring_and_after (gecos, ",");
5043 	if (!g_utf8_validate (locale_string, -1, NULL)) {
5044 		part_before_comma = g_locale_to_utf8 (locale_string, -1, NULL, NULL, NULL);
5045 		g_free (locale_string);
5046 	} else {
5047 		part_before_comma = locale_string;
5048 	}
5049 
5050 	if (!g_utf8_validate (name, -1, NULL)) {
5051 		locale_string = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
5052 	} else {
5053 		locale_string = g_strdup (name);
5054 	}
5055 	
5056 	capitalized_login_name = eel_str_capitalize (locale_string);
5057 	g_free (locale_string);
5058 
5059 	if (capitalized_login_name == NULL) {
5060 		real_name = part_before_comma;
5061 	} else {
5062 		real_name = eel_str_replace_substring
5063 			(part_before_comma, "&", capitalized_login_name);
5064 		g_free (part_before_comma);
5065 	}
5066 
5067 
5068 	if (g_strcmp0 (real_name, NULL) == 0
5069 	    || g_strcmp0 (name, real_name) == 0
5070 	    || g_strcmp0 (capitalized_login_name, real_name) == 0) {
5071 		g_free (real_name);
5072 		real_name = NULL;
5073 	}
5074 
5075 	g_free (capitalized_login_name);
5076 
5077 	return real_name;
5078 }
5079 
5080 static gboolean
5081 get_group_id_from_group_name (const char *group_name, uid_t *gid)
5082 {
5083 	struct group *group;
5084 
5085 	g_assert (gid != NULL);
5086 
5087 	group = getgrnam (group_name);
5088 
5089 	if (group == NULL) {
5090 		return FALSE;
5091 	}
5092 
5093 	*gid = group->gr_gid;
5094 
5095 	return TRUE;
5096 }
5097 
5098 static gboolean
5099 get_ids_from_user_name (const char *user_name, uid_t *uid, uid_t *gid)
5100 {
5101 	struct passwd *password_info;
5102 
5103 	g_assert (uid != NULL || gid != NULL);
5104 
5105 	password_info = getpwnam (user_name);
5106 
5107 	if (password_info == NULL) {
5108 		return FALSE;
5109 	}
5110 
5111 	if (uid != NULL) {
5112 		*uid = password_info->pw_uid;
5113 	}
5114 
5115 	if (gid != NULL) {
5116 		*gid = password_info->pw_gid;
5117 	}
5118 
5119 	return TRUE;
5120 }
5121 
5122 static gboolean
5123 get_user_id_from_user_name (const char *user_name, uid_t *id)
5124 {
5125 	return get_ids_from_user_name (user_name, id, NULL);
5126 }
5127 
5128 static gboolean
5129 get_id_from_digit_string (const char *digit_string, uid_t *id)
5130 {
5131 	long scanned_id;
5132 	char c;
5133 
5134 	g_assert (id != NULL);
5135 
5136 	/* Only accept string if it has one integer with nothing
5137 	 * afterwards.
5138 	 */
5139 	if (sscanf (digit_string, "%ld%c", &scanned_id, &c) != 1) {
5140 		return FALSE;
5141 	}
5142 	*id = scanned_id;
5143 	return TRUE;
5144 }
5145 
5146 /**
5147  * nautilus_file_can_get_owner:
5148  * 
5149  * Check whether the owner a file is determinable.
5150  * This might not be the case for files on non-UNIX file systems.
5151  * 
5152  * @file: The file in question.
5153  * 
5154  * Return value: TRUE if the owner is valid.
5155  */
5156 gboolean
5157 nautilus_file_can_get_owner (NautilusFile *file)
5158 {
5159 	/* Before we have info on a file, the owner is unknown. */
5160 	return file->details->uid != -1;
5161 }
5162 
5163 /**
5164  * nautilus_file_get_owner_name:
5165  * 
5166  * Get the user name of the file's owner. If the owner has no
5167  * name, returns the userid as a string. The caller is responsible
5168  * for g_free-ing this string.
5169  * 
5170  * @file: The file in question.
5171  * 
5172  * Return value: A newly-allocated string.
5173  */
5174 char *
5175 nautilus_file_get_owner_name (NautilusFile *file)
5176 {
5177 	return nautilus_file_get_owner_as_string (file, FALSE);
5178 }
5179 
5180 /**
5181  * nautilus_file_can_set_owner:
5182  * 
5183  * Check whether the current user is allowed to change
5184  * the owner of a file.
5185  * 
5186  * @file: The file in question.
5187  * 
5188  * Return value: TRUE if the current user can change the
5189  * owner of @file, FALSE otherwise. It's always possible
5190  * that when you actually try to do it, you will fail.
5191  */
5192 gboolean
5193 nautilus_file_can_set_owner (NautilusFile *file)
5194 {
5195 	/* Not allowed to set the owner if we can't
5196 	 * even read it. This can happen on non-UNIX file
5197 	 * systems.
5198 	 */
5199 	if (!nautilus_file_can_get_owner (file)) {
5200 		return FALSE;
5201 	}
5202 
5203 	/* Only root is also allowed to set the owner. */
5204 	return geteuid() == 0;
5205 }
5206 
5207 /**
5208  * nautilus_file_set_owner:
5209  * 
5210  * Set the owner of a file. This will only have any effect if
5211  * nautilus_file_can_set_owner returns TRUE.
5212  * 
5213  * @file: The file in question.
5214  * @user_name_or_id: The user name to set the owner to.
5215  * If the string does not match any user name, and the
5216  * string is an integer, the owner will be set to the
5217  * userid represented by that integer.
5218  * @callback: Function called when asynch owner change succeeds or fails.
5219  * @callback_data: Parameter passed back with callback function.
5220  */
5221 void
5222 nautilus_file_set_owner (NautilusFile *file, 
5223 			 const char *user_name_or_id,
5224 			 NautilusFileOperationCallback callback,
5225 			 gpointer callback_data)
5226 {
5227 	GError *error;
5228 	GFileInfo *info;
5229 	uid_t new_id;
5230 
5231 	if (!nautilus_file_can_set_owner (file)) {
5232 		/* Claim that something changed even if the permission
5233 		 * change failed. This makes it easier for some
5234 		 * clients who see the "reverting" to the old owner as
5235 		 * "changing back".
5236 		 */
5237 		nautilus_file_changed (file);
5238 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
5239 				     _("Not allowed to set owner"));
5240 		(* callback) (file, NULL, error, callback_data);
5241 		g_error_free (error);
5242 		return;
5243 	}
5244 
5245 	/* If no match treating user_name_or_id as name, try treating
5246 	 * it as id.
5247 	 */
5248 	if (!get_user_id_from_user_name (user_name_or_id, &new_id)
5249 	    && !get_id_from_digit_string (user_name_or_id, &new_id)) {
5250 		/* Claim that something changed even if the permission
5251 		 * change failed. This makes it easier for some
5252 		 * clients who see the "reverting" to the old owner as
5253 		 * "changing back".
5254 		 */
5255 		nautilus_file_changed (file);
5256 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
5257 				     _("Specified owner '%s' doesn't exist"), user_name_or_id);
5258 		(* callback) (file, NULL, error, callback_data);
5259 		g_error_free (error);
5260 		return;		
5261 	}
5262 
5263 	/* Test the owner-hasn't-changed case explicitly because we
5264 	 * don't want to send the file-changed signal if nothing
5265 	 * changed.
5266 	 */
5267 	if (new_id == (uid_t) file->details->uid) {
5268 		(* callback) (file, NULL, NULL, callback_data);
5269 		return;
5270 	}
5271 	
5272 	if (!nautilus_file_undo_manager_pop_flag ()) {
5273 		NautilusFileUndoInfo *undo_info;
5274 		char* current_owner;
5275 
5276 		current_owner = nautilus_file_get_owner_as_string (file, FALSE);
5277 
5278 		undo_info = nautilus_file_undo_info_ownership_new (NAUTILUS_FILE_UNDO_OP_CHANGE_OWNER,
5279 								   nautilus_file_get_location (file),
5280 								   current_owner,
5281 								   user_name_or_id);
5282 		nautilus_file_undo_manager_set_action (undo_info);
5283 
5284 		g_free (current_owner);
5285 	}
5286 
5287 	info = g_file_info_new ();
5288 	g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, new_id);
5289 	nautilus_file_set_attributes (file, info, callback, callback_data);
5290 	g_object_unref (info);
5291 }
5292 
5293 /**
5294  * nautilus_get_user_names:
5295  * 
5296  * Get a list of user names. For users with a different associated 
5297  * "real name", the real name follows the standard user name, separated 
5298  * by a carriage return. The caller is responsible for freeing this list 
5299  * and its contents.
5300  */
5301 GList *
5302 nautilus_get_user_names (void)
5303 {
5304 	GList *list;
5305 	char *real_name, *name;
5306 	struct passwd *user;
5307 
5308 	list = NULL;
5309 	
5310 	setpwent ();
5311 
5312 	while ((user = getpwent ()) != NULL) {
5313 		real_name = get_real_name (user->pw_name, user->pw_gecos);
5314 		if (real_name != NULL) {
5315 			name = g_strconcat (user->pw_name, "\n", real_name, NULL);
5316 		} else {
5317 			name = g_strdup (user->pw_name);
5318 		}
5319 		g_free (real_name);
5320 		list = g_list_prepend (list, name);
5321 	}
5322 
5323 	endpwent ();
5324 
5325 	return g_list_sort (list, (GCompareFunc) g_utf8_collate);
5326 }
5327 
5328 /**
5329  * nautilus_file_can_get_group:
5330  * 
5331  * Check whether the group a file is determinable.
5332  * This might not be the case for files on non-UNIX file systems.
5333  * 
5334  * @file: The file in question.
5335  * 
5336  * Return value: TRUE if the group is valid.
5337  */
5338 gboolean
5339 nautilus_file_can_get_group (NautilusFile *file)
5340 {
5341 	/* Before we have info on a file, the group is unknown. */
5342 	return file->details->gid != -1;
5343 }
5344 
5345 /**
5346  * nautilus_file_get_group_name:
5347  * 
5348  * Get the name of the file's group. If the group has no
5349  * name, returns the groupid as a string. The caller is responsible
5350  * for g_free-ing this string.
5351  * 
5352  * @file: The file in question.
5353  * 
5354  * Return value: A newly-allocated string.
5355  **/
5356 char *
5357 nautilus_file_get_group_name (NautilusFile *file)
5358 {
5359 	return g_strdup (eel_ref_str_peek (file->details->group));
5360 }
5361 
5362 /**
5363  * nautilus_file_can_set_group:
5364  * 
5365  * Check whether the current user is allowed to change
5366  * the group of a file.
5367  * 
5368  * @file: The file in question.
5369  * 
5370  * Return value: TRUE if the current user can change the
5371  * group of @file, FALSE otherwise. It's always possible
5372  * that when you actually try to do it, you will fail.
5373  */
5374 gboolean
5375 nautilus_file_can_set_group (NautilusFile *file)
5376 {
5377 	uid_t user_id;
5378 
5379 	/* Not allowed to set the permissions if we can't
5380 	 * even read them. This can happen on non-UNIX file
5381 	 * systems.
5382 	 */
5383 	if (!nautilus_file_can_get_group (file)) {
5384 		return FALSE;
5385 	}
5386 
5387 	/* Check the user. */
5388 	user_id = geteuid();
5389 
5390 	/* Owner is allowed to set group (with restrictions). */
5391 	if (user_id == (uid_t) file->details->uid) {
5392 		return TRUE;
5393 	}
5394 
5395 	/* Root is also allowed to set group. */
5396 	if (user_id == 0) {
5397 		return TRUE;
5398 	}
5399 
5400 	/* Nobody else is allowed. */
5401 	return FALSE;
5402 }
5403 
5404 /* Get a list of group names, filtered to only the ones
5405  * that contain the given username. If the username is
5406  * NULL, returns a list of all group names.
5407  */
5408 static GList *
5409 nautilus_get_group_names_for_user (void)
5410 {
5411 	GList *list;
5412 	struct group *group;
5413 	int count, i;
5414 	gid_t gid_list[NGROUPS_MAX + 1];
5415 	
5416 
5417 	list = NULL;
5418 
5419 	count = getgroups (NGROUPS_MAX + 1, gid_list);
5420 	for (i = 0; i < count; i++) {
5421 		group = getgrgid (gid_list[i]);
5422 		if (group == NULL)
5423 			break;
5424 		
5425 		list = g_list_prepend (list, g_strdup (group->gr_name));
5426 	}
5427 
5428 	return g_list_sort (list, (GCompareFunc) g_utf8_collate);
5429 }
5430 
5431 /**
5432  * nautilus_get_group_names:
5433  * 
5434  * Get a list of all group names.
5435  */
5436 GList *
5437 nautilus_get_all_group_names (void)
5438 {
5439 	GList *list;
5440 	struct group *group;
5441 	
5442 	list = NULL;
5443 
5444 	setgrent ();
5445 	
5446 	while ((group = getgrent ()) != NULL)
5447 		list = g_list_prepend (list, g_strdup (group->gr_name));
5448 	
5449 	endgrent ();
5450 	
5451 	return g_list_sort (list, (GCompareFunc) g_utf8_collate);
5452 }
5453 
5454 /**
5455  * nautilus_file_get_settable_group_names:
5456  * 
5457  * Get a list of all group names that the current user
5458  * can set the group of a specific file to.
5459  * 
5460  * @file: The NautilusFile in question.
5461  */
5462 GList *
5463 nautilus_file_get_settable_group_names (NautilusFile *file)
5464 {
5465 	uid_t user_id;
5466 	GList *result;
5467 
5468 	if (!nautilus_file_can_set_group (file)) {
5469 		return NULL;
5470 	}	
5471 
5472 	/* Check the user. */
5473 	user_id = geteuid();
5474 
5475 	if (user_id == 0) {
5476 		/* Root is allowed to set group to anything. */
5477 		result = nautilus_get_all_group_names ();
5478 	} else if (user_id == (uid_t) file->details->uid) {
5479 		/* Owner is allowed to set group to any that owner is member of. */
5480 		result = nautilus_get_group_names_for_user ();
5481 	} else {
5482 		g_warning ("unhandled case in nautilus_get_settable_group_names");
5483 		result = NULL;
5484 	}
5485 
5486 	return result;
5487 }
5488 
5489 /**
5490  * nautilus_file_set_group:
5491  * 
5492  * Set the group of a file. This will only have any effect if
5493  * nautilus_file_can_set_group returns TRUE.
5494  * 
5495  * @file: The file in question.
5496  * @group_name_or_id: The group name to set the owner to.
5497  * If the string does not match any group name, and the
5498  * string is an integer, the group will be set to the
5499  * group id represented by that integer.
5500  * @callback: Function called when asynch group change succeeds or fails.
5501  * @callback_data: Parameter passed back with callback function.
5502  */
5503 void
5504 nautilus_file_set_group (NautilusFile *file, 
5505 			 const char *group_name_or_id,
5506 			 NautilusFileOperationCallback callback,
5507 			 gpointer callback_data)
5508 {
5509 	GError *error;
5510 	GFileInfo *info;
5511 	uid_t new_id;
5512 
5513 	if (!nautilus_file_can_set_group (file)) {
5514 		/* Claim that something changed even if the group
5515 		 * change failed. This makes it easier for some
5516 		 * clients who see the "reverting" to the old group as
5517 		 * "changing back".
5518 		 */
5519 		nautilus_file_changed (file);
5520 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
5521 				     _("Not allowed to set group"));
5522 		(* callback) (file, NULL, error, callback_data);
5523 		g_error_free (error);
5524 		return;
5525 	}
5526 
5527 	/* If no match treating group_name_or_id as name, try treating
5528 	 * it as id.
5529 	 */
5530 	if (!get_group_id_from_group_name (group_name_or_id, &new_id)
5531 	    && !get_id_from_digit_string (group_name_or_id, &new_id)) {
5532 		/* Claim that something changed even if the group
5533 		 * change failed. This makes it easier for some
5534 		 * clients who see the "reverting" to the old group as
5535 		 * "changing back".
5536 		 */
5537 		nautilus_file_changed (file);
5538 		error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
5539 				     _("Specified group '%s' doesn't exist"), group_name_or_id);
5540 		(* callback) (file, NULL, error, callback_data);
5541 		g_error_free (error);
5542 		return;		
5543 	}
5544 
5545 	if (new_id == (gid_t) file->details->gid) {
5546 		(* callback) (file, NULL, NULL, callback_data);
5547 		return;
5548 	}
5549 
5550 	if (!nautilus_file_undo_manager_pop_flag ()) {
5551 		NautilusFileUndoInfo *undo_info;
5552 		char *current_group;
5553 
5554 		current_group = nautilus_file_get_group_name (file);
5555 		undo_info = nautilus_file_undo_info_ownership_new (NAUTILUS_FILE_UNDO_OP_CHANGE_GROUP,
5556 								   nautilus_file_get_location (file),
5557 								   current_group,
5558 								   group_name_or_id);
5559 		nautilus_file_undo_manager_set_action (undo_info);
5560 
5561 		g_free (current_group);
5562 	}
5563 
5564 	info = g_file_info_new ();
5565 	g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, new_id);
5566 	nautilus_file_set_attributes (file, info, callback, callback_data);
5567 	g_object_unref (info);
5568 }
5569 
5570 /**
5571  * nautilus_file_get_octal_permissions_as_string:
5572  * 
5573  * Get a user-displayable string representing a file's permissions
5574  * as an octal number. The caller
5575  * is responsible for g_free-ing this string.
5576  * @file: NautilusFile representing the file in question.
5577  * 
5578  * Returns: Newly allocated string ready to display to the user.
5579  * 
5580  **/
5581 static char *
5582 nautilus_file_get_octal_permissions_as_string (NautilusFile *file)
5583 {
5584 	guint32 permissions;
5585 
5586 	g_assert (NAUTILUS_IS_FILE (file));
5587 
5588 	if (!nautilus_file_can_get_permissions (file)) {
5589 		return NULL;
5590 	}
5591 
5592 	permissions = file->details->permissions;
5593 	return g_strdup_printf ("%03o", permissions);
5594 }
5595 
5596 /**
5597  * nautilus_file_get_permissions_as_string:
5598  * 
5599  * Get a user-displayable string representing a file's permissions. The caller
5600  * is responsible for g_free-ing this string.
5601  * @file: NautilusFile representing the file in question.
5602  * 
5603  * Returns: Newly allocated string ready to display to the user.
5604  * 
5605  **/
5606 static char *
5607 nautilus_file_get_permissions_as_string (NautilusFile *file)
5608 {
5609 	guint32 permissions;
5610 	gboolean is_directory;
5611 	gboolean is_link;
5612 	gboolean suid, sgid, sticky;
5613 
5614 	if (!nautilus_file_can_get_permissions (file)) {
5615 		return NULL;
5616 	}
5617 
5618 	g_assert (NAUTILUS_IS_FILE (file));
5619 
5620 	permissions = file->details->permissions;
5621 	is_directory = nautilus_file_is_directory (file);
5622 	is_link = nautilus_file_is_symbolic_link (file);
5623 
5624 	/* We use ls conventions for displaying these three obscure flags */
5625 	suid = permissions & S_ISUID;
5626 	sgid = permissions & S_ISGID;
5627 	sticky = permissions & S_ISVTX;
5628 
5629 	return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c",
5630 				 is_link ? 'l' : is_directory ? 'd' : '-',
5631 		 		 permissions & S_IRUSR ? 'r' : '-',
5632 				 permissions & S_IWUSR ? 'w' : '-',
5633 				 permissions & S_IXUSR 
5634 				 	? (suid ? 's' : 'x') 
5635 				 	: (suid ? 'S' : '-'),
5636 				 permissions & S_IRGRP ? 'r' : '-',
5637 				 permissions & S_IWGRP ? 'w' : '-',
5638 				 permissions & S_IXGRP
5639 				 	? (sgid ? 's' : 'x') 
5640 				 	: (sgid ? 'S' : '-'),		
5641 				 permissions & S_IROTH ? 'r' : '-',
5642 				 permissions & S_IWOTH ? 'w' : '-',
5643 				 permissions & S_IXOTH
5644 				 	? (sticky ? 't' : 'x') 
5645 				 	: (sticky ? 'T' : '-'));
5646 }
5647 
5648 /**
5649  * nautilus_file_get_owner_as_string:
5650  * 
5651  * Get a user-displayable string representing a file's owner. The caller
5652  * is responsible for g_free-ing this string.
5653  * @file: NautilusFile representing the file in question.
5654  * @include_real_name: Whether or not to append the real name (if any)
5655  * for this user after the user name.
5656  * 
5657  * Returns: Newly allocated string ready to display to the user.
5658  * 
5659  **/
5660 static char *
5661 nautilus_file_get_owner_as_string (NautilusFile *file, gboolean include_real_name)
5662 {
5663 	char *user_name;
5664 
5665 	/* Before we have info on a file, the owner is unknown. */
5666 	if (file->details->owner == NULL &&
5667 	    file->details->owner_real == NULL) {
5668 		return NULL;
5669 	}
5670 
5671 	if (file->details->uid == getuid ()) {
5672 		/* Translators: "Me" is used to indicate the file is owned by me (the current user) */
5673 		user_name = g_strdup (_("Me"));
5674 	} else if (file->details->owner_real == NULL) {
5675 		user_name = g_strdup (eel_ref_str_peek (file->details->owner));
5676 	} else if (file->details->owner == NULL) {
5677 		user_name = g_strdup (eel_ref_str_peek (file->details->owner_real));
5678 	} else if (include_real_name &&
5679 		   strcmp (eel_ref_str_peek (file->details->owner), eel_ref_str_peek (file->details->owner_real)) != 0) {
5680 		user_name = g_strdup (eel_ref_str_peek (file->details->owner_real));
5681 	} else {
5682 		user_name = g_strdup (eel_ref_str_peek (file->details->owner));
5683 	}
5684 
5685 	return user_name;
5686 }
5687 
5688 static char *
5689 format_item_count_for_display (guint item_count, 
5690 			       gboolean includes_directories, 
5691 			       gboolean includes_files)
5692 {
5693 	g_assert (includes_directories || includes_files);
5694 
5695 	return g_strdup_printf (includes_directories
5696 			? (includes_files 
5697 			   ? ngettext ("%'u item", "%'u items", item_count) 
5698 			   : ngettext ("%'u folder", "%'u folders", item_count))
5699 			: ngettext ("%'u file", "%'u files", item_count), item_count);
5700 }
5701 
5702 /**
5703  * nautilus_file_get_size_as_string:
5704  * 
5705  * Get a user-displayable string representing a file size. The caller
5706  * is responsible for g_free-ing this string. The string is an item
5707  * count for directories.
5708  * @file: NautilusFile representing the file in question.
5709  * 
5710  * Returns: Newly allocated string ready to display to the user.
5711  * 
5712  **/
5713 static char *
5714 nautilus_file_get_size_as_string (NautilusFile *file)
5715 {
5716 	guint item_count;
5717 	gboolean count_unreadable;
5718 
5719 	if (file == NULL) {
5720 		return NULL;
5721 	}
5722 	
5723 	g_assert (NAUTILUS_IS_FILE (file));
5724 	
5725 	if (nautilus_file_is_directory (file)) {
5726 		if (!nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
5727 			return NULL;
5728 		}
5729 		return format_item_count_for_display (item_count, TRUE, TRUE);
5730 	}
5731 	
5732 	if (file->details->size == -1) {
5733 		return NULL;
5734 	}
5735 	return g_format_size (file->details->size);
5736 }
5737 
5738 /**
5739  * nautilus_file_get_size_as_string_with_real_size:
5740  * 
5741  * Get a user-displayable string representing a file size. The caller
5742  * is responsible for g_free-ing this string. The string is an item
5743  * count for directories.
5744  * This function adds the real size in the string.
5745  * @file: NautilusFile representing the file in question.
5746  * 
5747  * Returns: Newly allocated string ready to display to the user.
5748  * 
5749  **/
5750 static char *
5751 nautilus_file_get_size_as_string_with_real_size (NautilusFile *file)
5752 {
5753 	guint item_count;
5754 	gboolean count_unreadable;
5755 
5756 	if (file == NULL) {
5757 		return NULL;
5758 	}
5759 	
5760 	g_assert (NAUTILUS_IS_FILE (file));
5761 	
5762 	if (nautilus_file_is_directory (file)) {
5763 		if (!nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
5764 			return NULL;
5765 		}
5766 		return format_item_count_for_display (item_count, TRUE, TRUE);
5767 	}
5768 	
5769 	if (file->details->size == -1) {
5770 		return NULL;
5771 	}
5772 
5773 	return g_format_size_full (file->details->size, G_FORMAT_SIZE_LONG_FORMAT);
5774 }
5775 
5776 
5777 static char *
5778 nautilus_file_get_deep_count_as_string_internal (NautilusFile *file,
5779 						 gboolean report_size,
5780 						 gboolean report_directory_count,
5781 						 gboolean report_file_count)
5782 {
5783 	NautilusRequestStatus status;
5784 	guint directory_count;
5785 	guint file_count;
5786 	guint unreadable_count;
5787 	guint total_count;
5788 	goffset total_size;
5789 
5790 	/* Must ask for size or some kind of count, but not both. */
5791 	g_assert (!report_size || (!report_directory_count && !report_file_count));
5792 	g_assert (report_size || report_directory_count || report_file_count);
5793 
5794 	if (file == NULL) {
5795 		return NULL;
5796 	}
5797 	
5798 	g_assert (NAUTILUS_IS_FILE (file));
5799 	g_assert (nautilus_file_is_directory (file));
5800 
5801 	status = nautilus_file_get_deep_counts 
5802 		(file, &directory_count, &file_count, &unreadable_count, &total_size, FALSE);
5803 
5804 	/* Check whether any info is available. */
5805 	if (status == NAUTILUS_REQUEST_NOT_STARTED) {
5806 		return NULL;
5807 	}
5808 
5809 	total_count = file_count + directory_count;
5810 
5811 	if (total_count == 0) {
5812 		switch (status) {
5813 		case NAUTILUS_REQUEST_IN_PROGRESS:
5814 			/* Don't return confident "zero" until we're finished looking,
5815 			 * because of next case.
5816 			 */
5817 			return NULL;
5818 		case NAUTILUS_REQUEST_DONE:
5819 			/* Don't return "zero" if we there were contents but we couldn't read them. */
5820 			if (unreadable_count != 0) {
5821 				return NULL;
5822 			}
5823 		default: break;
5824 		}
5825 	}
5826 
5827 	/* Note that we don't distinguish the "everything was readable" case
5828 	 * from the "some things but not everything was readable" case here.
5829 	 * Callers can distinguish them using nautilus_file_get_deep_counts
5830 	 * directly if desired.
5831 	 */
5832 	if (report_size) {
5833 		return g_format_size (total_size);
5834 	}
5835 
5836 	return format_item_count_for_display (report_directory_count
5837 		? (report_file_count ? total_count : directory_count)
5838 		: file_count,
5839 		report_directory_count, report_file_count);
5840 }
5841 
5842 /**
5843  * nautilus_file_get_deep_size_as_string:
5844  * 
5845  * Get a user-displayable string representing the size of all contained
5846  * items (only makes sense for directories). The caller
5847  * is responsible for g_free-ing this string.
5848  * @file: NautilusFile representing the file in question.
5849  * 
5850  * Returns: Newly allocated string ready to display to the user.
5851  * 
5852  **/
5853 static char *
5854 nautilus_file_get_deep_size_as_string (NautilusFile *file)
5855 {
5856 	return nautilus_file_get_deep_count_as_string_internal (file, TRUE, FALSE, FALSE);
5857 }
5858 
5859 /**
5860  * nautilus_file_get_deep_total_count_as_string:
5861  * 
5862  * Get a user-displayable string representing the count of all contained
5863  * items (only makes sense for directories). The caller
5864  * is responsible for g_free-ing this string.
5865  * @file: NautilusFile representing the file in question.
5866  * 
5867  * Returns: Newly allocated string ready to display to the user.
5868  * 
5869  **/
5870 static char *
5871 nautilus_file_get_deep_total_count_as_string (NautilusFile *file)
5872 {
5873 	return nautilus_file_get_deep_count_as_string_internal (file, FALSE, TRUE, TRUE);
5874 }
5875 
5876 /**
5877  * nautilus_file_get_deep_file_count_as_string:
5878  * 
5879  * Get a user-displayable string representing the count of all contained
5880  * items, not including directories. It only makes sense to call this
5881  * function on a directory. The caller
5882  * is responsible for g_free-ing this string.
5883  * @file: NautilusFile representing the file in question.
5884  * 
5885  * Returns: Newly allocated string ready to display to the user.
5886  * 
5887  **/
5888 static char *
5889 nautilus_file_get_deep_file_count_as_string (NautilusFile *file)
5890 {
5891 	return nautilus_file_get_deep_count_as_string_internal (file, FALSE, FALSE, TRUE);
5892 }
5893 
5894 /**
5895  * nautilus_file_get_deep_directory_count_as_string:
5896  * 
5897  * Get a user-displayable string representing the count of all contained
5898  * directories. It only makes sense to call this
5899  * function on a directory. The caller
5900  * is responsible for g_free-ing this string.
5901  * @file: NautilusFile representing the file in question.
5902  * 
5903  * Returns: Newly allocated string ready to display to the user.
5904  * 
5905  **/
5906 static char *
5907 nautilus_file_get_deep_directory_count_as_string (NautilusFile *file)
5908 {
5909 	return nautilus_file_get_deep_count_as_string_internal (file, FALSE, TRUE, FALSE);
5910 }
5911 
5912 /**
5913  * nautilus_file_get_string_attribute:
5914  * 
5915  * Get a user-displayable string from a named attribute. Use g_free to
5916  * free this string. If the value is unknown, returns NULL. You can call
5917  * nautilus_file_get_string_attribute_with_default if you want a non-NULL
5918  * default.
5919  * 
5920  * @file: NautilusFile representing the file in question.
5921  * @attribute_name: The name of the desired attribute. The currently supported
5922  * set includes "name", "type", "detailed_type", "mime_type", "size", "deep_size", "deep_directory_count",
5923  * "deep_file_count", "deep_total_count", "date_modified", "date_accessed",
5924  * "date_modified_full", "date_accessed_full",
5925  * "owner", "group", "permissions", "octal_permissions", "uri", "where",
5926  * "link_target", "volume", "free_space", "selinux_context", "trashed_on", "trashed_on_full", "trashed_orig_path"
5927  * 
5928  * Returns: Newly allocated string ready to display to the user, or NULL
5929  * if the value is unknown or @attribute_name is not supported.
5930  * 
5931  **/
5932 char *
5933 nautilus_file_get_string_attribute_q (NautilusFile *file, GQuark attribute_q)
5934 {
5935 	char *extension_attribute;
5936 
5937 	if (attribute_q == attribute_name_q) {
5938 		return nautilus_file_get_display_name (file);
5939 	}
5940 	if (attribute_q == attribute_type_q) {
5941 		return nautilus_file_get_type_as_string (file);
5942 	}
5943 	if (attribute_q == attribute_detailed_type_q) {
5944 		return nautilus_file_get_detailed_type_as_string (file);
5945 	}
5946 	if (attribute_q == attribute_mime_type_q) {
5947 		return nautilus_file_get_mime_type (file);
5948 	}
5949 	if (attribute_q == attribute_size_q) {
5950 		return nautilus_file_get_size_as_string (file);
5951 	}
5952 	if (attribute_q == attribute_size_detail_q) {
5953 		return nautilus_file_get_size_as_string_with_real_size (file);
5954 	}
5955 	if (attribute_q == attribute_deep_size_q) {
5956 		return nautilus_file_get_deep_size_as_string (file);
5957 	}
5958 	if (attribute_q == attribute_deep_file_count_q) {
5959 		return nautilus_file_get_deep_file_count_as_string (file);
5960 	}
5961 	if (attribute_q == attribute_deep_directory_count_q) {
5962 		return nautilus_file_get_deep_directory_count_as_string (file);
5963 	}
5964 	if (attribute_q == attribute_deep_total_count_q) {
5965 		return nautilus_file_get_deep_total_count_as_string (file);
5966 	}
5967 	if (attribute_q == attribute_trash_orig_path_q) {
5968 		return nautilus_file_get_trash_original_file_parent_as_string (file);
5969 	}
5970 	if (attribute_q == attribute_date_modified_q) {
5971 		return nautilus_file_get_date_as_string (file, 
5972 							 NAUTILUS_DATE_TYPE_MODIFIED,
5973 							 TRUE);
5974 	}
5975 	if (attribute_q == attribute_date_modified_full_q) {
5976 		return nautilus_file_get_date_as_string (file, 
5977 							 NAUTILUS_DATE_TYPE_MODIFIED,
5978 							 FALSE);
5979 	}
5980 	if (attribute_q == attribute_date_accessed_q) {
5981 		return nautilus_file_get_date_as_string (file,
5982 							 NAUTILUS_DATE_TYPE_ACCESSED,
5983 							 TRUE);
5984 	}
5985 	if (attribute_q == attribute_date_accessed_full_q) {
5986 		return nautilus_file_get_date_as_string (file,
5987 							 NAUTILUS_DATE_TYPE_ACCESSED,
5988 							 FALSE);
5989 	}
5990 	if (attribute_q == attribute_trashed_on_q) {
5991 		return nautilus_file_get_date_as_string (file,
5992 							 NAUTILUS_DATE_TYPE_TRASHED,
5993 							 TRUE);
5994 	}
5995 	if (attribute_q == attribute_trashed_on_full_q) {
5996 		return nautilus_file_get_date_as_string (file,
5997 							 NAUTILUS_DATE_TYPE_TRASHED,
5998 							 FALSE);
5999 	}
6000 	if (attribute_q == attribute_permissions_q) {
6001 		return nautilus_file_get_permissions_as_string (file);
6002 	}
6003 	if (attribute_q == attribute_selinux_context_q) {
6004 		return nautilus_file_get_selinux_context (file);
6005 	}
6006 	if (attribute_q == attribute_octal_permissions_q) {
6007 		return nautilus_file_get_octal_permissions_as_string (file);
6008 	}
6009 	if (attribute_q == attribute_owner_q) {
6010 		return nautilus_file_get_owner_as_string (file, TRUE);
6011 	}
6012 	if (attribute_q == attribute_group_q) {
6013 		return nautilus_file_get_group_name (file);
6014 	}
6015 	if (attribute_q == attribute_uri_q) {
6016 		return nautilus_file_get_uri (file);
6017 	}
6018 	if (attribute_q == attribute_where_q) {
6019 		return nautilus_file_get_where_string (file);
6020 	}
6021 	if (attribute_q == attribute_link_target_q) {
6022 		return nautilus_file_get_symbolic_link_target_path (file);
6023 	}
6024 	if (attribute_q == attribute_volume_q) {
6025 		return nautilus_file_get_volume_name (file);
6026 	}
6027 	if (attribute_q == attribute_free_space_q) {
6028 		return nautilus_file_get_volume_free_space (file);
6029 	}
6030 
6031 	extension_attribute = NULL;
6032 	
6033 	if (file->details->pending_extension_attributes) {
6034 		extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes,
6035 							   GINT_TO_POINTER (attribute_q));
6036 	} 
6037 
6038 	if (extension_attribute == NULL && file->details->extension_attributes) {
6039 		extension_attribute = g_hash_table_lookup (file->details->extension_attributes,
6040 							   GINT_TO_POINTER (attribute_q));
6041 	}
6042 		
6043 	return g_strdup (extension_attribute);
6044 }
6045 
6046 char *
6047 nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name)
6048 {
6049 	return nautilus_file_get_string_attribute_q (file, g_quark_from_string (attribute_name));
6050 }
6051 
6052 
6053 /**
6054  * nautilus_file_get_string_attribute_with_default:
6055  * 
6056  * Get a user-displayable string from a named attribute. Use g_free to
6057  * free this string. If the value is unknown, returns a string representing
6058  * the unknown value, which varies with attribute. You can call
6059  * nautilus_file_get_string_attribute if you want NULL instead of a default
6060  * result.
6061  * 
6062  * @file: NautilusFile representing the file in question.
6063  * @attribute_name: The name of the desired attribute. See the description of
6064  * nautilus_file_get_string for the set of available attributes.
6065  * 
6066  * Returns: Newly allocated string ready to display to the user, or a string
6067  * such as "unknown" if the value is unknown or @attribute_name is not supported.
6068  * 
6069  **/
6070 char *
6071 nautilus_file_get_string_attribute_with_default_q (NautilusFile *file, GQuark attribute_q)
6072 {
6073 	char *result;
6074 	guint item_count;
6075 	gboolean count_unreadable;
6076 	NautilusRequestStatus status;
6077 
6078 	result = nautilus_file_get_string_attribute_q (file, attribute_q);
6079 	if (result != NULL) {
6080 		return result;
6081 	}
6082 
6083 	/* Supply default values for the ones we know about. */
6084 	/* FIXME bugzilla.gnome.org 40646: 
6085 	 * Use hash table and switch statement or function pointers for speed? 
6086 	 */
6087 	if (attribute_q == attribute_size_q) {
6088 		if (!nautilus_file_should_show_directory_item_count (file)) {
6089 			return g_strdup ("--");
6090 		}
6091 		count_unreadable = FALSE;
6092 		if (nautilus_file_is_directory (file)) {
6093 			nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable);
6094 		}
6095 		return g_strdup (count_unreadable ? _("? items") : "...");
6096 	}
6097 	if (attribute_q == attribute_deep_size_q) {
6098 		status = nautilus_file_get_deep_counts (file, NULL, NULL, NULL, NULL, FALSE);
6099 		if (status == NAUTILUS_REQUEST_DONE) {
6100 			/* This means no contents at all were readable */
6101 			return g_strdup (_("? bytes"));
6102 		}
6103 		return g_strdup ("...");
6104 	}
6105 	if (attribute_q == attribute_deep_file_count_q
6106 	    || attribute_q == attribute_deep_directory_count_q
6107 	    || attribute_q == attribute_deep_total_count_q) {
6108 		status = nautilus_file_get_deep_counts (file, NULL, NULL, NULL, NULL, FALSE);
6109 		if (status == NAUTILUS_REQUEST_DONE) {
6110 			/* This means no contents at all were readable */
6111 			return g_strdup (_("? items"));
6112 		}
6113 		return g_strdup ("...");
6114 	}
6115 	if (attribute_q == attribute_type_q
6116 	    || attribute_q == attribute_detailed_type_q
6117 	    || attribute_q == attribute_mime_type_q) {
6118 		return g_strdup (_("Unknown"));
6119 	}
6120 	if (attribute_q == attribute_trashed_on_q) {
6121 		/* If n/a */
6122 		return g_strdup ("");
6123 	}
6124 	if (attribute_q == attribute_trash_orig_path_q) {
6125 		/* If n/a */
6126 		return g_strdup ("");
6127 	}
6128 	
6129 	/* Fallback, use for both unknown attributes and attributes
6130 	 * for which we have no more appropriate default.
6131 	 */
6132 	return g_strdup (_("unknown"));
6133 }
6134 
6135 char *
6136 nautilus_file_get_string_attribute_with_default (NautilusFile *file, const char *attribute_name)
6137 {
6138 	return nautilus_file_get_string_attribute_with_default_q (file, g_quark_from_string (attribute_name));
6139 }
6140 
6141 gboolean
6142 nautilus_file_is_date_sort_attribute_q (GQuark attribute_q)
6143 {
6144 	if (attribute_q == attribute_modification_date_q ||
6145 	    attribute_q == attribute_date_modified_q ||
6146 	    attribute_q == attribute_date_modified_full_q ||
6147 	    attribute_q == attribute_accessed_date_q ||
6148 	    attribute_q == attribute_date_accessed_q ||
6149 	    attribute_q == attribute_date_accessed_full_q ||
6150 	    attribute_q == attribute_trashed_on_q ||
6151 	    attribute_q == attribute_trashed_on_full_q) {
6152 		return TRUE;
6153 	}
6154 
6155 	return FALSE;
6156 }
6157 
6158 struct {
6159         const char *icon_name;
6160         const char *display_name;
6161 } mime_type_map[] = {
6162 	{ "application-x-executable", N_("Program") },
6163 	{ "audio-x-generic", N_("Audio") },
6164 	{ "font-x-generic", N_("Font") },
6165 	{ "image-x-generic", N_("Image") },
6166 	{ "package-x-generic", N_("Archive") },
6167 	{ "text-html", N_("Markup") },
6168 	{ "text-x-generic", N_("Text") },
6169 	{ "text-x-generic-template", N_("Text") },
6170 	{ "text-x-script", N_("Program") },
6171 	{ "video-x-generic", N_("Video") },
6172 	{ "x-office-address-book", N_("Contacts") },
6173 	{ "x-office-calendar", N_("Calendar") },
6174 	{ "x-office-document", N_("Document") },
6175 	{ "x-office-presentation", N_("Presentation") },
6176 	{ "x-office-spreadsheet", N_("Spreadsheet") },
6177 };
6178 
6179 static char *
6180 get_basic_type_for_mime_type (const char *mime_type)
6181 {
6182 	char *icon_name;
6183 	char *basic_type = NULL;
6184 
6185 	icon_name = g_content_type_get_generic_icon_name (mime_type);
6186 	if (icon_name != NULL) {
6187 		int i;
6188 
6189 		for (i = 0; i < G_N_ELEMENTS (mime_type_map); i++) {
6190 			if (strcmp (mime_type_map[i].icon_name, icon_name) == 0) {
6191 				basic_type = g_strdup (gettext (mime_type_map[i].display_name));
6192 				break;
6193 			}
6194 		}
6195         }
6196 
6197 	if (basic_type == NULL) {
6198 		basic_type = g_strdup (_("Unknown"));
6199 	}
6200 
6201 	g_free (icon_name);
6202 
6203 	return basic_type;
6204 }
6205 
6206 static char *
6207 get_description (NautilusFile *file,
6208 		 gboolean      detailed)
6209 {
6210 	const char *mime_type;
6211 
6212 	g_assert (NAUTILUS_IS_FILE (file));
6213 
6214 	mime_type = eel_ref_str_peek (file->details->mime_type);
6215 	if (mime_type == NULL) {
6216 		return NULL;
6217 	}
6218 
6219 	if (g_content_type_is_unknown (mime_type)) {
6220 		if (nautilus_file_is_executable (file)) {
6221 			return g_strdup (_("Program"));
6222 		}
6223 		return g_strdup (_("Binary"));
6224 	}
6225 
6226 	if (strcmp (mime_type, "inode/directory") == 0) {
6227 		return g_strdup (_("Folder"));
6228 	}
6229 
6230 	if (detailed) {
6231 		char *description;
6232 
6233 		description = g_content_type_get_description (mime_type);
6234 		if (description != NULL) {
6235 			return description;
6236 		}
6237 	} else {
6238 		char *category;
6239 
6240 		category = get_basic_type_for_mime_type (mime_type);
6241 		if (category != NULL) {
6242 			return category;
6243 		}
6244 	}
6245 
6246 	return g_strdup (mime_type);
6247 }
6248 
6249 /* Takes ownership of string */
6250 static char *
6251 update_description_for_link (NautilusFile *file, char *string)
6252 {
6253 	char *res;
6254 	
6255 	if (nautilus_file_is_symbolic_link (file)) {
6256 		g_assert (!nautilus_file_is_broken_symbolic_link (file));
6257 		if (string == NULL) {
6258 			return g_strdup (_("Link"));
6259 		}
6260 		/* Note to localizers: convert file type string for file 
6261 		 * (e.g. "folder", "plain text") to file type for symbolic link 
6262 		 * to that kind of file (e.g. "link to folder").
6263 		 */
6264 		res = g_strdup_printf (_("Link to %s"), string);
6265 		g_free (string);
6266 		return res;
6267 	}
6268 
6269 	return string;
6270 }
6271 
6272 static char *
6273 nautilus_file_get_type_as_string (NautilusFile *file)
6274 {
6275 	if (file == NULL) {
6276 		return NULL;
6277 	}
6278 
6279 	if (nautilus_file_is_broken_symbolic_link (file)) {
6280 		return g_strdup (_("Link (broken)"));
6281 	}
6282 	
6283 	return update_description_for_link (file, get_description (file, FALSE));
6284 }
6285 
6286 static char *
6287 nautilus_file_get_detailed_type_as_string (NautilusFile *file)
6288 {
6289 	if (file == NULL) {
6290 		return NULL;
6291 	}
6292 
6293 	if (nautilus_file_is_broken_symbolic_link (file)) {
6294 		return g_strdup (_("Link (broken)"));
6295 	}
6296 	
6297 	return update_description_for_link (file, get_description (file, TRUE));
6298 }
6299 
6300 /**
6301  * nautilus_file_get_file_type
6302  * 
6303  * Return this file's type.
6304  * @file: NautilusFile representing the file in question.
6305  * 
6306  * Returns: The type.
6307  * 
6308  **/
6309 GFileType
6310 nautilus_file_get_file_type (NautilusFile *file)
6311 {
6312 	if (file == NULL) {
6313 		return G_FILE_TYPE_UNKNOWN;
6314 	}
6315 	
6316 	return file->details->type;
6317 }
6318 
6319 /**
6320  * nautilus_file_get_mime_type
6321  * 
6322  * Return this file's default mime type.
6323  * @file: NautilusFile representing the file in question.
6324  * 
6325  * Returns: The mime type.
6326  * 
6327  **/
6328 char *
6329 nautilus_file_get_mime_type (NautilusFile *file)
6330 {
6331 	if (file != NULL) {
6332 		g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
6333 		if (file->details->mime_type != NULL) {
6334 			return g_strdup (eel_ref_str_peek (file->details->mime_type));
6335 		}
6336 	}
6337 	return g_strdup ("application/octet-stream");
6338 }
6339 
6340 /**
6341  * nautilus_file_is_mime_type
6342  * 
6343  * Check whether a file is of a particular MIME type, or inherited
6344  * from it.
6345  * @file: NautilusFile representing the file in question.
6346  * @mime_type: The MIME-type string to test (e.g. "text/plain")
6347  * 
6348  * Return value: TRUE if @mime_type exactly matches the
6349  * file's MIME type.
6350  * 
6351  **/
6352 gboolean
6353 nautilus_file_is_mime_type (NautilusFile *file, const char *mime_type)
6354 {
6355 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6356 	g_return_val_if_fail (mime_type != NULL, FALSE);
6357 	
6358 	if (file->details->mime_type == NULL) {
6359 		return FALSE;
6360 	}
6361 	return g_content_type_is_a (eel_ref_str_peek (file->details->mime_type),
6362 				    mime_type);
6363 }
6364 
6365 char *
6366 nautilus_file_get_extension (NautilusFile *file)
6367 {
6368 	char *name;
6369 	char *extension = NULL;
6370 
6371 	name = nautilus_file_get_name (file);
6372 	if (name != NULL) {
6373 		extension = g_strdup (eel_filename_get_extension_offset (name));
6374 		g_free (name);
6375 	}
6376 
6377 	return extension;
6378 }
6379 
6380 gboolean
6381 nautilus_file_is_launchable (NautilusFile *file)
6382 {
6383 	gboolean type_can_be_executable;
6384 
6385 	type_can_be_executable = FALSE;
6386 	if (file->details->mime_type != NULL) {
6387 		type_can_be_executable =
6388 			g_content_type_can_be_executable (eel_ref_str_peek (file->details->mime_type));
6389 	}
6390 		
6391 	return type_can_be_executable &&
6392 		nautilus_file_can_get_permissions (file) &&
6393 		nautilus_file_can_execute (file) &&
6394 		nautilus_file_is_executable (file) &&
6395 		!nautilus_file_is_directory (file);
6396 }
6397 
6398 static GList *
6399 sort_keyword_list_and_remove_duplicates (GList *keywords)
6400 {
6401 	GList *p;
6402 	GList *duplicate_link;
6403 	
6404 	if (keywords != NULL) {
6405 		keywords = g_list_sort (keywords, (GCompareFunc) g_utf8_collate);
6406 
6407 		p = keywords;
6408 		while (p->next != NULL) {
6409 			if (strcmp ((const char *) p->data, (const char *) p->next->data) == 0) {
6410 				duplicate_link = p->next;
6411 				keywords = g_list_remove_link (keywords, duplicate_link);
6412 				g_list_free_full (duplicate_link, g_free);
6413 			} else {
6414 				p = p->next;
6415 			}
6416 		}
6417 	}
6418 	
6419 	return keywords;
6420 }
6421 
6422 static void
6423 clean_up_metadata_keywords (NautilusFile *file,
6424 			    GList **metadata_keywords)
6425 {
6426 	NautilusFile *parent_file;
6427 	GList *l, *res = NULL;
6428 	char *exclude[4];
6429 	char *keyword;
6430 	gboolean found;
6431 	gint i;
6432 
6433 	i = 0;
6434 	exclude[i++] = NAUTILUS_FILE_EMBLEM_NAME_TRASH;
6435 	exclude[i++] = NAUTILUS_FILE_EMBLEM_NAME_NOTE;
6436 
6437 	parent_file = nautilus_file_get_parent (file);
6438 	if (parent_file) {
6439 		if (!nautilus_file_can_write (parent_file)) {
6440 			exclude[i++] = NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE;
6441 		}
6442 		nautilus_file_unref (parent_file);
6443 	}
6444 	exclude[i++] = NULL;
6445 
6446 	for (l = *metadata_keywords; l != NULL; l = l->next) {
6447 		keyword = l->data;
6448 		found = FALSE;
6449 
6450 		for (i = 0; exclude[i] != NULL; i++) {
6451 			if (strcmp (exclude[i], keyword) == 0) {
6452 				found = TRUE;
6453 				break;
6454 			}
6455 		}
6456 
6457 		if (!found) {
6458 			res = g_list_prepend (res, keyword);
6459 		}
6460 	}
6461 
6462 	g_list_free (*metadata_keywords);
6463 	*metadata_keywords = res;
6464 }
6465 
6466 /**
6467  * nautilus_file_get_keywords
6468  * 
6469  * Return this file's keywords.
6470  * @file: NautilusFile representing the file in question.
6471  * 
6472  * Returns: A list of keywords.
6473  * 
6474  **/
6475 static GList *
6476 nautilus_file_get_keywords (NautilusFile *file)
6477 {
6478 	GList *keywords, *metadata_keywords;
6479 
6480 	if (file == NULL) {
6481 		return NULL;
6482 	}
6483 
6484 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
6485 
6486 	keywords = eel_g_str_list_copy (file->details->extension_emblems);
6487 	keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems));
6488 
6489 	metadata_keywords = nautilus_file_get_metadata_list (file, NAUTILUS_METADATA_KEY_EMBLEMS);
6490 	clean_up_metadata_keywords (file, &metadata_keywords);
6491 	keywords = g_list_concat (keywords, metadata_keywords);
6492 
6493 	return sort_keyword_list_and_remove_duplicates (keywords);
6494 }
6495 
6496 /**
6497  * nautilus_file_get_emblem_icons
6498  * 
6499  * Return the list of names of emblems that this file should display,
6500  * in canonical order.
6501  * @file: NautilusFile representing the file in question.
6502  * 
6503  * Returns: A list of emblem names.
6504  * 
6505  **/
6506 GList *
6507 nautilus_file_get_emblem_icons (NautilusFile *file)
6508 {
6509 	GList *keywords, *l;
6510 	GList *icons;
6511 	char *icon_names[2];
6512 	char *keyword;
6513 	GIcon *icon;
6514 	
6515 	if (file == NULL) {
6516 		return NULL;
6517 	}
6518 	
6519 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
6520 
6521 	keywords = nautilus_file_get_keywords (file);
6522 	keywords = prepend_automatic_keywords (file, keywords);
6523 
6524 	icons = NULL;
6525 	for (l = keywords; l != NULL; l = l->next) {
6526 		keyword = l->data;
6527 
6528 		icon_names[0] = g_strconcat ("emblem-", keyword, NULL);
6529 		icon_names[1] = keyword;
6530 		icon = g_themed_icon_new_from_names (icon_names, 2);
6531 		g_free (icon_names[0]);
6532 
6533 		icons = g_list_prepend (icons, icon);
6534 	}
6535 
6536 	g_list_free_full (keywords, g_free);
6537 	
6538 	return icons;
6539 }
6540 
6541 /**
6542  * nautilus_file_is_symbolic_link
6543  * 
6544  * Check if this file is a symbolic link.
6545  * @file: NautilusFile representing the file in question.
6546  * 
6547  * Returns: True if the file is a symbolic link.
6548  * 
6549  **/
6550 gboolean
6551 nautilus_file_is_symbolic_link (NautilusFile *file)
6552 {
6553 	return file->details->is_symlink;
6554 }
6555 
6556 gboolean
6557 nautilus_file_is_mountpoint (NautilusFile *file)
6558 {
6559 	return file->details->is_mountpoint;
6560 }
6561 
6562 GMount *
6563 nautilus_file_get_mount (NautilusFile *file)
6564 {
6565 	if (file->details->mount) {
6566 		return g_object_ref (file->details->mount);
6567 	}
6568 	return NULL;
6569 }
6570 
6571 static void
6572 file_mount_unmounted (GMount *mount,
6573 		      gpointer data)
6574 {
6575 	NautilusFile *file;
6576 
6577 	file = NAUTILUS_FILE (data);
6578 
6579 	nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_MOUNT);
6580 }
6581 
6582 void
6583 nautilus_file_set_mount (NautilusFile *file,
6584 			 GMount *mount)
6585 {
6586 	if (file->details->mount) {
6587 		g_signal_handlers_disconnect_by_func (file->details->mount, file_mount_unmounted, file);
6588 		g_object_unref (file->details->mount);
6589 		file->details->mount = NULL;
6590 	}
6591 
6592 	if (mount) {
6593 		file->details->mount = g_object_ref (mount);
6594 		g_signal_connect (mount, "unmounted",
6595 				  G_CALLBACK (file_mount_unmounted), file);
6596 	}
6597 }
6598 
6599 /**
6600  * nautilus_file_is_broken_symbolic_link
6601  * 
6602  * Check if this file is a symbolic link with a missing target.
6603  * @file: NautilusFile representing the file in question.
6604  * 
6605  * Returns: True if the file is a symbolic link with a missing target.
6606  * 
6607  **/
6608 gboolean
6609 nautilus_file_is_broken_symbolic_link (NautilusFile *file)
6610 {
6611 	if (file == NULL) {
6612 		return FALSE;
6613 	}
6614 		
6615 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6616 
6617 	/* Non-broken symbolic links return the target's type for get_file_type. */
6618 	return nautilus_file_get_file_type (file) == G_FILE_TYPE_SYMBOLIC_LINK;
6619 }
6620 
6621 static void
6622 get_fs_free_cb (GObject *source_object,
6623 		GAsyncResult *res,
6624 		gpointer user_data)
6625 {
6626 	NautilusFile *file;
6627 	guint64 free_space;
6628 	GFileInfo *info;
6629 
6630 	file = NAUTILUS_FILE (user_data);
6631 	
6632 	free_space = (guint64)-1;
6633 	info = g_file_query_filesystem_info_finish (G_FILE (source_object),
6634 						    res, NULL);
6635 	if (info) {
6636 		if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) {
6637 			free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
6638 		}
6639 		g_object_unref (info);
6640 	}
6641 
6642 	if (file->details->free_space != free_space) {
6643 		file->details->free_space = free_space;
6644 		nautilus_file_emit_changed (file);
6645 	}
6646 
6647 	nautilus_file_unref (file);
6648 }
6649 
6650 /**
6651  * nautilus_file_get_volume_free_space
6652  * Get a nicely formatted char with free space on the file's volume
6653  * @file: NautilusFile representing the file in question.
6654  *
6655  * Returns: newly-allocated copy of file size in a formatted string
6656  */
6657 char *
6658 nautilus_file_get_volume_free_space (NautilusFile *file)
6659 {
6660 	GFile *location;
6661 	char *res;
6662 	time_t now;
6663 
6664 	now = time (NULL);
6665 	/* Update first time and then every 2 seconds */
6666 	if (file->details->free_space_read == 0 ||
6667 	    (now - file->details->free_space_read) > 2)  {
6668 		file->details->free_space_read = now;
6669 		location = nautilus_file_get_location (file);
6670 		g_file_query_filesystem_info_async (location,
6671 						    G_FILE_ATTRIBUTE_FILESYSTEM_FREE,
6672 						    0, NULL,
6673 						    get_fs_free_cb,
6674 						    nautilus_file_ref (file));
6675 		g_object_unref (location);
6676 	}
6677 
6678 	res = NULL;
6679 	if (file->details->free_space != (guint64)-1) {
6680 		res = g_format_size (file->details->free_space);
6681 	}
6682 
6683 	return res;
6684 }
6685 
6686 /**
6687  * nautilus_file_get_volume_name
6688  * Get the path of the volume the file resides on
6689  * @file: NautilusFile representing the file in question.
6690  * 
6691  * Returns: newly-allocated copy of the volume name of the target file, 
6692  * if the volume name isn't set, it returns the mount path of the volume
6693  */ 
6694 char *
6695 nautilus_file_get_volume_name (NautilusFile *file)
6696 {
6697 	GFile *location;
6698 	char *res;
6699 	GMount *mount;
6700 
6701 	res = NULL;
6702 	
6703 	location = nautilus_file_get_location (file);
6704 	mount = g_file_find_enclosing_mount (location, NULL, NULL);
6705 	if (mount) {
6706 		res = g_strdup (g_mount_get_name (mount));
6707 		g_object_unref (mount);
6708 	}
6709 	g_object_unref (location);
6710 
6711 	return res;
6712 }
6713 
6714 /**
6715  * nautilus_file_get_symbolic_link_target_path
6716  * 
6717  * Get the file path of the target of a symbolic link. It is an error 
6718  * to call this function on a file that isn't a symbolic link.
6719  * @file: NautilusFile representing the symbolic link in question.
6720  * 
6721  * Returns: newly-allocated copy of the file path of the target of the symbolic link.
6722  */
6723 char *
6724 nautilus_file_get_symbolic_link_target_path (NautilusFile *file)
6725 {
6726 	if (!nautilus_file_is_symbolic_link (file)) {
6727 		g_warning ("File has symlink target, but  is not marked as symlink");
6728 	}
6729 
6730 	return g_strdup (file->details->symlink_name);
6731 }
6732 
6733 /**
6734  * nautilus_file_get_symbolic_link_target_uri
6735  * 
6736  * Get the uri of the target of a symbolic link. It is an error 
6737  * to call this function on a file that isn't a symbolic link.
6738  * @file: NautilusFile representing the symbolic link in question.
6739  * 
6740  * Returns: newly-allocated copy of the uri of the target of the symbolic link.
6741  */
6742 char *
6743 nautilus_file_get_symbolic_link_target_uri (NautilusFile *file)
6744 {
6745 	GFile *location, *parent, *target;
6746 	char *target_uri;
6747 
6748 	if (!nautilus_file_is_symbolic_link (file)) {
6749 		g_warning ("File has symlink target, but  is not marked as symlink");
6750 	}
6751 
6752 	if (file->details->symlink_name == NULL) {
6753 		return NULL;
6754 	} else {
6755 		target = NULL;
6756 		
6757 		location = nautilus_file_get_location (file);
6758 		parent = g_file_get_parent (location);
6759 		g_object_unref (location);
6760 		if (parent) {
6761 			target = g_file_resolve_relative_path (parent, file->details->symlink_name);
6762 			g_object_unref (parent);
6763 		}
6764 		
6765 		target_uri = NULL;
6766 		if (target) {
6767 			target_uri = g_file_get_uri (target);
6768 			g_object_unref (target);
6769 		}
6770 		return target_uri;
6771 	}
6772 }
6773 
6774 /**
6775  * nautilus_file_is_nautilus_link
6776  * 
6777  * Check if this file is a "nautilus link", meaning a historical
6778  * nautilus xml link file or a desktop file.
6779  * @file: NautilusFile representing the file in question.
6780  * 
6781  * Returns: True if the file is a nautilus link.
6782  * 
6783  **/
6784 gboolean
6785 nautilus_file_is_nautilus_link (NautilusFile *file)
6786 {
6787 	if (file->details->mime_type == NULL) {
6788 		return FALSE;
6789 	}
6790 	return g_content_type_equals (eel_ref_str_peek (file->details->mime_type),
6791 				      "application/x-desktop");
6792 }
6793 
6794 /**
6795  * nautilus_file_is_directory
6796  * 
6797  * Check if this file is a directory.
6798  * @file: NautilusFile representing the file in question.
6799  * 
6800  * Returns: TRUE if @file is a directory.
6801  * 
6802  **/
6803 gboolean
6804 nautilus_file_is_directory (NautilusFile *file)
6805 {
6806 	return nautilus_file_get_file_type (file) == G_FILE_TYPE_DIRECTORY;
6807 }
6808 
6809 /**
6810  * nautilus_file_is_user_special_directory
6811  *
6812  * Check if this file is a special platform directory.
6813  * @file: NautilusFile representing the file in question.
6814  * @special_directory: GUserDirectory representing the type to test for
6815  * 
6816  * Returns: TRUE if @file is a special directory of the given kind.
6817  */
6818 gboolean
6819 nautilus_file_is_user_special_directory (NautilusFile *file,
6820 					 GUserDirectory special_directory)
6821 {
6822 	gboolean is_special_dir;
6823 	const gchar *special_dir;
6824 
6825 	special_dir = g_get_user_special_dir (special_directory);
6826 	is_special_dir = FALSE;
6827 
6828 	if (special_dir) {
6829 		GFile *loc;
6830 		GFile *special_gfile;
6831 
6832 		loc = nautilus_file_get_location (file);
6833 		special_gfile = g_file_new_for_path (special_dir);
6834 		is_special_dir = g_file_equal (loc, special_gfile);
6835 		g_object_unref (special_gfile);
6836 		g_object_unref (loc);
6837 	}
6838 
6839 	return is_special_dir;
6840 }
6841 
6842 gboolean
6843 nautilus_file_is_archive (NautilusFile *file)
6844 {
6845 	char *mime_type;
6846 	int i;
6847 	static const char * archive_mime_types[] = { "application/x-gtar",
6848 						     "application/x-zip",
6849 						     "application/x-zip-compressed",
6850 						     "application/zip",
6851 						     "application/x-zip",
6852 						     "application/x-tar",
6853 						     "application/x-7z-compressed",
6854 						     "application/x-rar",
6855 						     "application/x-rar-compressed",
6856 						     "application/x-jar",
6857 						     "application/x-java-archive",
6858 						     "application/x-war",
6859 						     "application/x-ear",
6860 						     "application/x-arj",
6861 						     "application/x-gzip",
6862 						     "application/x-bzip-compressed-tar",
6863 						     "application/x-compressed-tar" };
6864 
6865 	g_return_val_if_fail (file != NULL, FALSE);
6866 
6867 	mime_type = nautilus_file_get_mime_type (file);
6868 	for (i = 0; i < G_N_ELEMENTS (archive_mime_types); i++) {
6869 		if (!strcmp (mime_type, archive_mime_types[i])) {
6870 			g_free (mime_type);
6871 			return TRUE;
6872 		}
6873 	}
6874 	g_free (mime_type);
6875 
6876 	return FALSE;
6877 }
6878 
6879 
6880 /**
6881  * nautilus_file_is_in_trash
6882  * 
6883  * Check if this file is a file in trash.
6884  * @file: NautilusFile representing the file in question.
6885  * 
6886  * Returns: TRUE if @file is in a trash.
6887  * 
6888  **/
6889 gboolean
6890 nautilus_file_is_in_trash (NautilusFile *file)
6891 {
6892 	g_assert (NAUTILUS_IS_FILE (file));
6893 
6894 	return nautilus_directory_is_in_trash (file->details->directory);
6895 }
6896 
6897 /**
6898  * nautilus_file_is_in_recent
6899  * 
6900  * Check if this file is a file in Recent.
6901  * @file: NautilusFile representing the file in question.
6902  * 
6903  * Returns: TRUE if @file is in Recent.
6904  * 
6905  **/
6906 gboolean
6907 nautilus_file_is_in_recent (NautilusFile *file)
6908 {
6909 	g_assert (NAUTILUS_IS_FILE (file));
6910 
6911 	return nautilus_directory_is_in_recent (file->details->directory);
6912 }
6913 
6914 /**
6915  * nautilus_file_is_in_network
6916  * 
6917  * Check if this file is a file in Network.
6918  * @file: NautilusFile representing the file in question.
6919  * 
6920  * Returns: TRUE if @file is in Network.
6921  * 
6922  **/
6923 gboolean
6924 nautilus_file_is_in_network (NautilusFile *file)
6925 {
6926 	g_assert (NAUTILUS_IS_FILE (file));
6927 
6928 	return nautilus_directory_is_in_network (file->details->directory);
6929 }
6930 
6931 GError *
6932 nautilus_file_get_file_info_error (NautilusFile *file)
6933 {
6934 	if (!file->details->get_info_failed) {
6935 		return NULL;
6936 	}
6937 
6938 	return file->details->get_info_error;
6939 }
6940 
6941 /**
6942  * nautilus_file_contains_text
6943  * 
6944  * Check if this file contains text.
6945  * This is private and is used to decide whether or not to read the top left text.
6946  * @file: NautilusFile representing the file in question.
6947  * 
6948  * Returns: TRUE if @file has a text MIME type.
6949  * 
6950  **/
6951 gboolean
6952 nautilus_file_contains_text (NautilusFile *file)
6953 {
6954 	if (file == NULL) {
6955 		return FALSE;
6956 	}
6957 
6958 	/* All text files inherit from text/plain */
6959 	return nautilus_file_is_mime_type (file, "text/plain");
6960 }
6961 
6962 /**
6963  * nautilus_file_is_executable
6964  * 
6965  * Check if this file is executable at all.
6966  * @file: NautilusFile representing the file in question.
6967  * 
6968  * Returns: TRUE if any of the execute bits are set. FALSE if
6969  * not, or if the permissions are unknown.
6970  * 
6971  **/
6972 gboolean
6973 nautilus_file_is_executable (NautilusFile *file)
6974 {
6975 	if (!file->details->has_permissions) {
6976 		/* File's permissions field is not valid.
6977 		 * Can't access specific permissions, so return FALSE.
6978 		 */
6979 		return FALSE;
6980 	}
6981 
6982 	return file->details->can_execute;
6983 }
6984 
6985 /**
6986  * nautilus_file_peek_top_left_text
6987  * 
6988  * Peek at the text from the top left of the file.
6989  * @file: NautilusFile representing the file in question.
6990  * 
6991  * Returns: NULL if there is no text readable, otherwise, the text.
6992  *          This string is owned by the file object and should not
6993  *          be kept around or freed.
6994  * 
6995  **/
6996 char *
6997 nautilus_file_peek_top_left_text (NautilusFile *file,
6998 				  gboolean  need_large_text,
6999 				  gboolean *needs_loading)
7000 {
7001 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
7002 
7003 	if (!nautilus_file_should_get_top_left_text (file)) {
7004 		if (needs_loading) {
7005 			*needs_loading = FALSE;
7006 		}
7007 		return NULL;
7008 	}
7009 	
7010 	if (needs_loading) {
7011 		*needs_loading = !file->details->top_left_text_is_up_to_date;
7012 		if (need_large_text) {
7013 			*needs_loading |= file->details->got_top_left_text != file->details->got_large_top_left_text;
7014 		}
7015 	}
7016 
7017 	/* Show " ..." in the file until we read the contents in. */
7018 	if (!file->details->got_top_left_text) {
7019 		
7020 		if (nautilus_file_contains_text (file)) {
7021 			return " ...";
7022 		}
7023 		return NULL;
7024 	}
7025 	
7026 	/* Show what we read in. */
7027 	return file->details->top_left_text;
7028 }
7029 
7030 /**
7031  * nautilus_file_get_top_left_text
7032  * 
7033  * Get the text from the top left of the file.
7034  * @file: NautilusFile representing the file in question.
7035  * 
7036  * Returns: NULL if there is no text readable, otherwise, the text.
7037  * 
7038  **/
7039 char *
7040 nautilus_file_get_top_left_text (NautilusFile *file)
7041 {
7042 	return g_strdup (nautilus_file_peek_top_left_text (file, FALSE, NULL));
7043 }
7044 
7045 char *
7046 nautilus_file_get_filesystem_id (NautilusFile *file)
7047 {
7048 	return g_strdup (eel_ref_str_peek (file->details->filesystem_id));
7049 }
7050 
7051 NautilusFile *
7052 nautilus_file_get_trash_original_file (NautilusFile *file)
7053 {
7054 	GFile *location;
7055 	NautilusFile *original_file;
7056 	char *filename;
7057 
7058 	original_file = NULL;
7059 
7060 	if (file->details->trash_orig_path != NULL) {
7061 		/* file name is stored in URL encoding */
7062 		filename = g_uri_unescape_string (file->details->trash_orig_path, "");
7063 		location = g_file_new_for_path (filename);
7064 		original_file = nautilus_file_get (location);
7065 		g_object_unref (G_OBJECT (location));
7066 		g_free (filename);
7067 	}
7068 
7069 	return original_file;
7070 
7071 }
7072 
7073 void
7074 nautilus_file_mark_gone (NautilusFile *file)
7075 {
7076 	NautilusDirectory *directory;
7077 
7078 	if (file->details->is_gone)
7079 		return;
7080 
7081 	file->details->is_gone = TRUE;
7082 
7083 	update_links_if_target (file);
7084 
7085 	/* Drop it from the symlink hash ! */
7086 	remove_from_link_hash_table (file);
7087 
7088 	/* Let the directory know it's gone. */
7089 	directory = file->details->directory;
7090 	if (!nautilus_file_is_self_owned (file)) {
7091 		nautilus_directory_remove_file (directory, file);
7092 	}
7093 
7094 	nautilus_file_clear_info (file);
7095 
7096 	/* FIXME bugzilla.gnome.org 42429: 
7097 	 * Maybe we can get rid of the name too eventually, but
7098 	 * for now that would probably require too many if statements
7099 	 * everywhere anyone deals with the name. Maybe we can give it
7100 	 * a hard-coded "<deleted>" name or something.
7101 	 */
7102 }
7103 
7104 /**
7105  * nautilus_file_changed
7106  * 
7107  * Notify the user that this file has changed.
7108  * @file: NautilusFile representing the file in question.
7109  **/
7110 void
7111 nautilus_file_changed (NautilusFile *file)
7112 {
7113 	GList fake_list;
7114 
7115 	g_return_if_fail (NAUTILUS_IS_FILE (file));
7116 
7117 	if (nautilus_file_is_self_owned (file)) {
7118 		nautilus_file_emit_changed (file);
7119 	} else {
7120 		fake_list.data = file;
7121 		fake_list.next = NULL;
7122 		fake_list.prev = NULL;
7123 		nautilus_directory_emit_change_signals
7124 			(file->details->directory, &fake_list);
7125 	}
7126 }
7127 
7128 /**
7129  * nautilus_file_updated_deep_count_in_progress
7130  * 
7131  * Notify clients that a newer deep count is available for
7132  * the directory in question.
7133  */
7134 void
7135 nautilus_file_updated_deep_count_in_progress (NautilusFile *file) {
7136 	GList *link_files, *node;
7137 
7138 	g_assert (NAUTILUS_IS_FILE (file));
7139 	g_assert (nautilus_file_is_directory (file));
7140 
7141 	/* Send out a signal. */
7142 	g_signal_emit (file, signals[UPDATED_DEEP_COUNT_IN_PROGRESS], 0, file);
7143 
7144 	/* Tell link files pointing to this object about the change. */
7145 	link_files = get_link_files (file);
7146 	for (node = link_files; node != NULL; node = node->next) {
7147 		nautilus_file_updated_deep_count_in_progress (NAUTILUS_FILE (node->data));
7148 	}
7149 	nautilus_file_list_free (link_files);	
7150 }
7151 
7152 /**
7153  * nautilus_file_emit_changed
7154  * 
7155  * Emit a file changed signal.
7156  * This can only be called by the directory, since the directory
7157  * also has to emit a files_changed signal.
7158  *
7159  * @file: NautilusFile representing the file in question.
7160  **/
7161 void
7162 nautilus_file_emit_changed (NautilusFile *file)
7163 {
7164 	GList *link_files, *p;
7165 
7166 	g_assert (NAUTILUS_IS_FILE (file));
7167 
7168 	/* Send out a signal. */
7169 	g_signal_emit (file, signals[CHANGED], 0, file);
7170 
7171 	/* Tell link files pointing to this object about the change. */
7172 	link_files = get_link_files (file);
7173 	for (p = link_files; p != NULL; p = p->next) {
7174 		if (p->data != file) {
7175 			nautilus_file_changed (NAUTILUS_FILE (p->data));
7176 		}
7177 	}
7178 	nautilus_file_list_free (link_files);
7179 }
7180 
7181 /**
7182  * nautilus_file_is_gone
7183  * 
7184  * Check if a file has already been deleted.
7185  * @file: NautilusFile representing the file in question.
7186  *
7187  * Returns: TRUE if the file is already gone.
7188  **/
7189 gboolean
7190 nautilus_file_is_gone (NautilusFile *file)
7191 {
7192 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
7193 
7194 	return file->details->is_gone;
7195 }
7196 
7197 /**
7198  * nautilus_file_is_not_yet_confirmed
7199  * 
7200  * Check if we're in a state where we don't know if a file really
7201  * exists or not, before the initial I/O is complete.
7202  * @file: NautilusFile representing the file in question.
7203  *
7204  * Returns: TRUE if the file is already gone.
7205  **/
7206 gboolean
7207 nautilus_file_is_not_yet_confirmed (NautilusFile *file)
7208 {
7209 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
7210 
7211 	return !file->details->got_file_info;
7212 }
7213 
7214 /**
7215  * nautilus_file_check_if_ready
7216  *
7217  * Check whether the values for a set of file attributes are
7218  * currently available, without doing any additional work. This
7219  * is useful for callers that want to reflect updated information
7220  * when it is ready but don't want to force the work required to
7221  * obtain the information, which might be slow network calls, e.g.
7222  *
7223  * @file: The file being queried.
7224  * @file_attributes: A bit-mask with the desired information.
7225  * 
7226  * Return value: TRUE if all of the specified attributes are currently readable.
7227  */
7228 gboolean
7229 nautilus_file_check_if_ready (NautilusFile *file,
7230 			      NautilusFileAttributes file_attributes)
7231 {
7232 	/* To be parallel with call_when_ready, return
7233 	 * TRUE for NULL file.
7234 	 */
7235 	if (file == NULL) {
7236 		return TRUE;
7237 	}
7238 
7239 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
7240 
7241 	return NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->check_if_ready (file, file_attributes);
7242 }			      
7243 
7244 void
7245 nautilus_file_call_when_ready (NautilusFile *file,
7246 			       NautilusFileAttributes file_attributes,
7247 			       NautilusFileCallback callback,
7248 			       gpointer callback_data)
7249 
7250 {
7251 	if (file == NULL) {
7252 		(* callback) (file, callback_data);
7253 		return;
7254 	}
7255 
7256 	g_return_if_fail (NAUTILUS_IS_FILE (file));
7257 
7258 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->call_when_ready
7259 		(file, file_attributes, callback, callback_data);
7260 }
7261 
7262 void
7263 nautilus_file_cancel_call_when_ready (NautilusFile *file,
7264 				      NautilusFileCallback callback,
7265 				      gpointer callback_data)
7266 {
7267 	g_return_if_fail (callback != NULL);
7268 
7269 	if (file == NULL) {
7270 		return;
7271 	}
7272 
7273 	g_return_if_fail (NAUTILUS_IS_FILE (file));
7274 
7275 	NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready
7276 		(file, callback, callback_data);
7277 }
7278 
7279 static void
7280 invalidate_directory_count (NautilusFile *file)
7281 {
7282 	file->details->directory_count_is_up_to_date = FALSE;
7283 }
7284 
7285 static void
7286 invalidate_deep_counts (NautilusFile *file)
7287 {
7288 	file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
7289 }
7290 
7291 static void
7292 invalidate_mime_list (NautilusFile *file)
7293 {
7294 	file->details->mime_list_is_up_to_date = FALSE;
7295 }
7296 
7297 static void
7298 invalidate_top_left_text (NautilusFile *file)
7299 {
7300 	file->details->top_left_text_is_up_to_date = FALSE;
7301 }
7302 
7303 static void
7304 invalidate_file_info (NautilusFile *file)
7305 {
7306 	file->details->file_info_is_up_to_date = FALSE;
7307 }
7308 
7309 static void
7310 invalidate_link_info (NautilusFile *file)
7311 {
7312 	file->details->link_info_is_up_to_date = FALSE;
7313 }
7314 
7315 static void
7316 invalidate_thumbnail (NautilusFile *file)
7317 {
7318 	file->details->thumbnail_is_up_to_date = FALSE;
7319 }
7320 
7321 static void
7322 invalidate_mount (NautilusFile *file)
7323 {
7324 	file->details->mount_is_up_to_date = FALSE;
7325 }
7326 
7327 void
7328 nautilus_file_invalidate_extension_info_internal (NautilusFile *file)
7329 {
7330 	if (file->details->pending_info_providers)
7331 		g_list_free_full (file->details->pending_info_providers, g_object_unref);
7332 
7333 	file->details->pending_info_providers =
7334 		nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_INFO_PROVIDER);
7335 }
7336 
7337 void
7338 nautilus_file_invalidate_attributes_internal (NautilusFile *file,
7339 					      NautilusFileAttributes file_attributes)
7340 {
7341 	Request request;
7342 
7343 	if (file == NULL) {
7344 		return;
7345 	}
7346 
7347 	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
7348 		/* Desktop icon files are always up to date.
7349 		 * If we invalidate their attributes they
7350 		 * will lose data, so we just ignore them.
7351 		 */
7352 		return;
7353 	}
7354 	
7355 	request = nautilus_directory_set_up_request (file_attributes);
7356 
7357 	if (REQUEST_WANTS_TYPE (request, REQUEST_DIRECTORY_COUNT)) {
7358 		invalidate_directory_count (file);
7359 	}
7360 	if (REQUEST_WANTS_TYPE (request, REQUEST_DEEP_COUNT)) {
7361 		invalidate_deep_counts (file);
7362 	}
7363 	if (REQUEST_WANTS_TYPE (request, REQUEST_MIME_LIST)) {
7364 		invalidate_mime_list (file);
7365 	}
7366 	if (REQUEST_WANTS_TYPE (request, REQUEST_FILE_INFO)) {
7367 		invalidate_file_info (file);
7368 	}
7369 	if (REQUEST_WANTS_TYPE (request, REQUEST_TOP_LEFT_TEXT)) {
7370 		invalidate_top_left_text (file);
7371 	}
7372 	if (REQUEST_WANTS_TYPE (request, REQUEST_LINK_INFO)) {
7373 		invalidate_link_info (file);
7374 	}
7375 	if (REQUEST_WANTS_TYPE (request, REQUEST_EXTENSION_INFO)) {
7376 		nautilus_file_invalidate_extension_info_internal (file);
7377 	}
7378 	if (REQUEST_WANTS_TYPE (request, REQUEST_THUMBNAIL)) {
7379 		invalidate_thumbnail (file);
7380 	}
7381 	if (REQUEST_WANTS_TYPE (request, REQUEST_MOUNT)) {
7382 		invalidate_mount (file);
7383 	}
7384 
7385 	/* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */
7386 }
7387 
7388 gboolean
7389 nautilus_file_has_open_window (NautilusFile *file)
7390 {
7391 	return file->details->has_open_window;
7392 }
7393 
7394 void
7395 nautilus_file_set_has_open_window (NautilusFile *file,
7396 				   gboolean has_open_window)
7397 {
7398 	has_open_window = (has_open_window != FALSE);
7399 
7400 	if (file->details->has_open_window != has_open_window) {
7401 		file->details->has_open_window = has_open_window;
7402 		nautilus_file_changed (file);
7403 	}
7404 }
7405 
7406 
7407 gboolean
7408 nautilus_file_is_thumbnailing (NautilusFile *file)
7409 {
7410 	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
7411 	
7412 	return file->details->is_thumbnailing;
7413 }
7414 
7415 void
7416 nautilus_file_set_is_thumbnailing (NautilusFile *file,
7417 				   gboolean is_thumbnailing)
7418 {
7419 	g_return_if_fail (NAUTILUS_IS_FILE (file));
7420 	
7421 	file->details->is_thumbnailing = is_thumbnailing;
7422 }
7423 
7424 
7425 /**
7426  * nautilus_file_invalidate_attributes
7427  * 
7428  * Invalidate the specified attributes and force a reload.
7429  * @file: NautilusFile representing the file in question.
7430  * @file_attributes: attributes to froget.
7431  **/
7432 
7433 void
7434 nautilus_file_invalidate_attributes (NautilusFile *file,
7435 				     NautilusFileAttributes file_attributes)
7436 {
7437 	/* Cancel possible in-progress loads of any of these attributes */
7438 	nautilus_directory_cancel_loading_file_attributes (file->details->directory,
7439 							   file,
7440 							   file_attributes);
7441 	
7442 	/* Actually invalidate the values */
7443 	nautilus_file_invalidate_attributes_internal (file, file_attributes);
7444 
7445 	nautilus_directory_add_file_to_work_queue (file->details->directory, file);
7446 	
7447 	/* Kick off I/O if necessary */
7448 	nautilus_directory_async_state_changed (file->details->directory);
7449 }
7450 
7451 NautilusFileAttributes 
7452 nautilus_file_get_all_attributes (void)
7453 {
7454 	return  NAUTILUS_FILE_ATTRIBUTE_INFO |
7455 		NAUTILUS_FILE_ATTRIBUTE_LINK_INFO |
7456 		NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS |
7457 		NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT | 
7458 		NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES | 
7459 		NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT | 
7460 		NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT |
7461 		NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO |
7462 		NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL |
7463 		NAUTILUS_FILE_ATTRIBUTE_MOUNT;
7464 }
7465 
7466 void
7467 nautilus_file_invalidate_all_attributes (NautilusFile *file)
7468 {
7469 	NautilusFileAttributes all_attributes;
7470 
7471 	all_attributes = nautilus_file_get_all_attributes ();
7472 	nautilus_file_invalidate_attributes (file, all_attributes);
7473 }
7474 
7475 
7476 /**
7477  * nautilus_file_dump
7478  *
7479  * Debugging call, prints out the contents of the file
7480  * fields.
7481  *
7482  * @file: file to dump.
7483  **/
7484 void
7485 nautilus_file_dump (NautilusFile *file)
7486 {
7487 	long size = file->details->deep_size;
7488 	char *uri;
7489 	const char *file_kind;
7490 
7491 	uri = nautilus_file_get_uri (file);
7492 	g_print ("uri: %s \n", uri);
7493 	if (!file->details->got_file_info) {
7494 		g_print ("no file info \n");
7495 	} else if (file->details->get_info_failed) {
7496 		g_print ("failed to get file info \n");
7497 	} else {
7498 		g_print ("size: %ld \n", size);
7499 		switch (file->details->type) {
7500 		case G_FILE_TYPE_REGULAR:
7501 			file_kind = "regular file";
7502 			break;
7503 		case G_FILE_TYPE_DIRECTORY:
7504 			file_kind = "folder";
7505 			break;
7506 		case G_FILE_TYPE_SPECIAL:
7507 			file_kind = "special";
7508 			break;
7509 		case G_FILE_TYPE_SYMBOLIC_LINK:
7510 			file_kind = "symbolic link";
7511 			break;
7512 		case G_FILE_TYPE_UNKNOWN:
7513 		default:
7514 			file_kind = "unknown";
7515 			break;
7516 		}
7517 		g_print ("kind: %s \n", file_kind);
7518 		if (file->details->type == G_FILE_TYPE_SYMBOLIC_LINK) {
7519 			g_print ("link to %s \n", file->details->symlink_name);
7520 			/* FIXME bugzilla.gnome.org 42430: add following of symlinks here */
7521 		}
7522 		/* FIXME bugzilla.gnome.org 42431: add permissions and other useful stuff here */
7523 	}
7524 	g_free (uri);
7525 }
7526 
7527 /**
7528  * nautilus_file_list_ref
7529  *
7530  * Ref all the files in a list.
7531  * @list: GList of files.
7532  **/
7533 GList *
7534 nautilus_file_list_ref (GList *list)
7535 {
7536 	g_list_foreach (list, (GFunc) nautilus_file_ref, NULL);
7537 	return list;
7538 }
7539 
7540 /**
7541  * nautilus_file_list_unref
7542  *
7543  * Unref all the files in a list.
7544  * @list: GList of files.
7545  **/
7546 void
7547 nautilus_file_list_unref (GList *list)
7548 {
7549 	g_list_foreach (list, (GFunc) nautilus_file_unref, NULL);
7550 }
7551 
7552 /**
7553  * nautilus_file_list_free
7554  *
7555  * Free a list of files after unrefing them.
7556  * @list: GList of files.
7557  **/
7558 void
7559 nautilus_file_list_free (GList *list)
7560 {
7561 	nautilus_file_list_unref (list);
7562 	g_list_free (list);
7563 }
7564 
7565 /**
7566  * nautilus_file_list_copy
7567  *
7568  * Copy the list of files, making a new ref of each,
7569  * @list: GList of files.
7570  **/
7571 GList *
7572 nautilus_file_list_copy (GList *list)
7573 {
7574 	return g_list_copy (nautilus_file_list_ref (list));
7575 }
7576 
7577 GList *
7578 nautilus_file_list_from_uris (GList *uri_list)
7579 {
7580 	GList *l, *file_list;
7581 	const char *uri;
7582 	GFile *file;
7583 	
7584 	file_list = NULL;
7585 
7586 	for (l = uri_list; l != NULL; l = l->next) {
7587 		uri = l->data;
7588 		file = g_file_new_for_uri (uri);
7589 		file_list = g_list_prepend (file_list, file);
7590 	}
7591 	return g_list_reverse (file_list);
7592 }
7593 
7594 static gboolean
7595 get_attributes_for_default_sort_type (NautilusFile *file,
7596 				      gboolean *is_recent,
7597 				      gboolean *is_download,
7598 				      gboolean *is_trash,
7599 				      gboolean *is_search)
7600 {
7601 	gboolean is_recent_dir, is_download_dir, is_desktop_dir, is_trash_dir, is_search_dir, retval;
7602 
7603 	*is_recent = FALSE;
7604 	*is_download = FALSE;
7605 	*is_trash = FALSE;
7606 	*is_search = FALSE;
7607 	retval = FALSE;
7608 
7609 	/* special handling for certain directories */
7610 	if (file && nautilus_file_is_directory (file)) {
7611 		is_recent_dir =
7612 			nautilus_file_is_in_recent (file);
7613 		is_download_dir =
7614 			nautilus_file_is_user_special_directory (file, G_USER_DIRECTORY_DOWNLOAD);
7615 		is_desktop_dir =
7616 			nautilus_file_is_user_special_directory (file, G_USER_DIRECTORY_DESKTOP);
7617 		is_trash_dir =
7618 			nautilus_file_is_in_trash (file);
7619 		is_search_dir =
7620 			nautilus_file_is_in_search (file);
7621 
7622 		if (is_download_dir && !is_desktop_dir) {
7623 			*is_download = TRUE;
7624 			retval = TRUE;
7625 		} else if (is_trash_dir) {
7626 			*is_trash = TRUE;
7627 			retval = TRUE;
7628 		} else if (is_recent_dir) {
7629 			*is_recent = TRUE;
7630 			retval = TRUE;
7631 		} else if (is_search_dir) {
7632 			*is_search = TRUE;
7633 			retval = TRUE;
7634 		}
7635 	}
7636 
7637 	return retval;
7638 }
7639 
7640 NautilusFileSortType
7641 nautilus_file_get_default_sort_type (NautilusFile *file,
7642 				     gboolean *reversed)
7643 {
7644 	NautilusFileSortType retval;
7645 	gboolean is_recent, is_download, is_trash, is_search, res;
7646 
7647 	retval = NAUTILUS_FILE_SORT_NONE;
7648 	is_recent = is_download = is_trash = is_search = FALSE;
7649 	res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash, &is_search);
7650 
7651 	if (res) {
7652 		if (is_recent || is_download) {
7653 			retval = NAUTILUS_FILE_SORT_BY_MTIME;
7654 		} else if (is_trash) {
7655 			retval = NAUTILUS_FILE_SORT_BY_TRASHED_TIME;
7656 		} else if (is_search) {
7657 			retval = NAUTILUS_FILE_SORT_BY_SEARCH_RELEVANCE;
7658 		}
7659 
7660 		if (reversed != NULL) {
7661 			*reversed = res;
7662 		}
7663 	}
7664 
7665 	return retval;
7666 }
7667 
7668 const gchar *
7669 nautilus_file_get_default_sort_attribute (NautilusFile *file,
7670 					  gboolean *reversed)
7671 {
7672 	const gchar *retval;
7673 	gboolean is_recent, is_download, is_trash, is_search, res;
7674 
7675 	retval = NULL;
7676 	is_download = is_trash = is_search = FALSE;
7677 	res = get_attributes_for_default_sort_type (file, &is_recent, &is_download, &is_trash, &is_search);
7678 
7679 	if (res) {
7680 		if (is_recent || is_download) {
7681 			retval = g_quark_to_string (attribute_date_modified_q);
7682 		} else if (is_trash) {
7683 			retval = g_quark_to_string (attribute_trashed_on_q);
7684 		} else if (is_search) {
7685 			retval = g_quark_to_string (attribute_search_relevance_q);
7686 		}
7687 
7688 		if (reversed != NULL) {
7689 			*reversed = res;
7690 		}
7691 	}
7692 
7693 	return retval;
7694 }
7695 
7696 static int
7697 compare_by_display_name_cover (gconstpointer a, gconstpointer b)
7698 {
7699 	return compare_by_display_name (NAUTILUS_FILE (a), NAUTILUS_FILE (b));
7700 }
7701 
7702 /**
7703  * nautilus_file_list_sort_by_display_name
7704  * 
7705  * Sort the list of files by file name.
7706  * @list: GList of files.
7707  **/
7708 GList *
7709 nautilus_file_list_sort_by_display_name (GList *list)
7710 {
7711 	return g_list_sort (list, compare_by_display_name_cover);
7712 }
7713 
7714 static GList *ready_data_list = NULL;
7715 
7716 typedef struct 
7717 {
7718 	GList *file_list;
7719 	GList *remaining_files;
7720 	NautilusFileListCallback callback;
7721 	gpointer callback_data;
7722 } FileListReadyData;
7723 
7724 static void
7725 file_list_ready_data_free (FileListReadyData *data)
7726 {
7727 	GList *l;
7728 
7729 	l = g_list_find (ready_data_list, data);
7730 	if (l != NULL) {
7731 		ready_data_list = g_list_delete_link (ready_data_list, l);
7732 
7733 		nautilus_file_list_free (data->file_list);
7734 		g_list_free (data->remaining_files);
7735 		g_free (data);
7736 	}
7737 }
7738 
7739 static FileListReadyData *
7740 file_list_ready_data_new (GList *file_list,
7741 			  NautilusFileListCallback callback,
7742 			  gpointer callback_data)
7743 {
7744 	FileListReadyData *data;
7745 
7746 	data = g_new0 (FileListReadyData, 1);
7747 	data->file_list = nautilus_file_list_copy (file_list);
7748 	data->remaining_files = g_list_copy (file_list);
7749 	data->callback = callback;
7750 	data->callback_data = callback_data;
7751 
7752 	ready_data_list = g_list_prepend (ready_data_list, data);
7753 
7754 	return data;
7755 }
7756 
7757 static void
7758 file_list_file_ready_callback (NautilusFile *file,
7759 			       gpointer user_data)
7760 {
7761 	FileListReadyData *data;
7762 
7763 	data = user_data;
7764 	data->remaining_files = g_list_remove (data->remaining_files, file);
7765 	
7766 	if (data->remaining_files == NULL) {
7767 		if (data->callback) {
7768 			(*data->callback) (data->file_list, data->callback_data);
7769 		}
7770 
7771 		file_list_ready_data_free (data);
7772 	}
7773 }
7774 
7775 void 
7776 nautilus_file_list_call_when_ready (GList *file_list,
7777 				    NautilusFileAttributes attributes,
7778 				    NautilusFileListHandle **handle,
7779 				    NautilusFileListCallback callback,
7780 				    gpointer callback_data)
7781 {
7782 	GList *l;
7783 	FileListReadyData *data;
7784 	NautilusFile *file;
7785 	
7786 	g_return_if_fail (file_list != NULL);
7787 
7788 	data = file_list_ready_data_new
7789 		(file_list, callback, callback_data);
7790 
7791 	if (handle) {
7792 		*handle = (NautilusFileListHandle *) data;
7793 	}
7794 
7795 
7796 	l = file_list;
7797 	while (l != NULL) {
7798 		file = NAUTILUS_FILE (l->data);
7799 		/* Need to do this here, as the list can be modified by this call */
7800 		l = l->next; 
7801 		nautilus_file_call_when_ready (file,
7802 					       attributes,
7803 					       file_list_file_ready_callback,
7804 					       data);
7805 	}
7806 }
7807 
7808 void
7809 nautilus_file_list_cancel_call_when_ready (NautilusFileListHandle *handle)
7810 {
7811 	GList *l;
7812 	NautilusFile *file;
7813 	FileListReadyData *data;
7814 
7815 	g_return_if_fail (handle != NULL);
7816 
7817 	data = (FileListReadyData *) handle;
7818 
7819 	l = g_list_find (ready_data_list, data);
7820 	if (l != NULL) {
7821 		for (l = data->remaining_files; l != NULL; l = l->next) {
7822 			file = NAUTILUS_FILE (l->data);
7823 
7824 			NAUTILUS_FILE_CLASS (G_OBJECT_GET_CLASS (file))->cancel_call_when_ready
7825 				(file, file_list_file_ready_callback, data);
7826 		}
7827 
7828 		file_list_ready_data_free (data);
7829 	}
7830 }
7831 
7832 static char *
7833 try_to_make_utf8 (const char *text, int *length)
7834 {
7835 	static const char *encodings_to_try[2];
7836 	static int n_encodings_to_try = 0;
7837         gsize converted_length;
7838         GError *conversion_error;
7839 	char *utf8_text;
7840 	int i;
7841 	
7842 	if (n_encodings_to_try == 0) {
7843 		const char *charset;
7844 		gboolean charset_is_utf8;
7845 		
7846 		charset_is_utf8 = g_get_charset (&charset);
7847 		if (!charset_is_utf8) {
7848 			encodings_to_try[n_encodings_to_try++] = charset;
7849 		}
7850         
7851 		if (g_ascii_strcasecmp (charset, "ISO-8859-1") != 0) {
7852 			encodings_to_try[n_encodings_to_try++] = "ISO-8859-1";
7853 		}
7854 	}
7855 
7856         utf8_text = NULL;
7857 	for (i = 0; i < n_encodings_to_try; i++) {
7858 		conversion_error = NULL;
7859 		utf8_text = g_convert (text, *length, 
7860 					   "UTF-8", encodings_to_try[i],
7861 					   NULL, &converted_length, &conversion_error);
7862 		if (utf8_text != NULL) {
7863 			*length = converted_length;
7864 			break;
7865 		}
7866 		g_error_free (conversion_error);
7867 	}
7868 	
7869 	return utf8_text;
7870 }
7871 
7872 
7873 
7874 /* Extract the top left part of the read-in text. */
7875 char *
7876 nautilus_extract_top_left_text (const char *text,
7877 				gboolean large,
7878 				int length)
7879 {
7880         GString* buffer;
7881 	const gchar *in;
7882 	const gchar *end;
7883 	int line, i;
7884 	gunichar c;
7885 	char *text_copy;
7886 	const char *utf8_end;
7887 	gboolean validated;
7888 	int max_bytes, max_lines, max_cols;
7889 
7890 	if (large) {
7891 		max_bytes = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES;
7892 		max_lines = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES;
7893 		max_cols = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_CHARACTERS_PER_LINE;
7894 	} else {
7895 		max_bytes = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES;
7896 		max_lines = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES;
7897 		max_cols = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_CHARACTERS_PER_LINE;
7898 	}
7899 			
7900 	
7901 
7902         text_copy = NULL;
7903         if (text != NULL) {
7904 		/* Might be a partial utf8 character at the end if we didn't read whole file */
7905 		validated = g_utf8_validate (text, length, &utf8_end);
7906 		if (!validated &&
7907 		    !(length >= max_bytes &&
7908 		      text + length - utf8_end < 6)) {
7909 			text_copy = try_to_make_utf8 (text, &length);
7910 			text = text_copy;
7911 		} else if (!validated) {
7912 			length = utf8_end - text;
7913 		}
7914         }
7915 
7916 	if (text == NULL || length == 0) {
7917 		return NULL;
7918 	}
7919 
7920 	buffer = g_string_new ("");
7921 	end = text + length; in = text;
7922 
7923 	for (line = 0; line < max_lines; line++) {
7924 		/* Extract one line. */
7925 		for (i = 0; i < max_cols; ) {
7926 			if (*in == '\n') {
7927 				break;
7928 			}
7929 			
7930 			c = g_utf8_get_char (in);
7931 			
7932 			if (g_unichar_isprint (c)) {
7933 				g_string_append_unichar (buffer, c);
7934 				i++;
7935 			}
7936 			
7937 			in = g_utf8_next_char (in);
7938 			if (in == end) {
7939 				goto done;
7940 			}
7941 		}
7942 
7943 		/* Skip the rest of the line. */
7944 		while (*in != '\n') {
7945 			if (++in == end) {
7946 				goto done;
7947 			}
7948 		}
7949 		if (++in == end) {
7950 			goto done;
7951 		}
7952 
7953 		/* Put a new-line separator in. */
7954 		g_string_append_c(buffer, '\n');
7955 	}
7956  done:
7957 	g_free (text_copy);
7958 
7959 	return g_string_free(buffer, FALSE);
7960 }
7961 
7962 static void
7963 thumbnail_limit_changed_callback (gpointer user_data)
7964 {
7965 	g_settings_get (nautilus_preferences,
7966 			NAUTILUS_PREFERENCES_FILE_THUMBNAIL_LIMIT,
7967 			"t", &cached_thumbnail_limit);
7968 
7969 	/* Tell the world that icons might have changed. We could invent a narrower-scope
7970 	 * signal to mean only "thumbnails might have changed" if this ends up being slow
7971 	 * for some reason.
7972 	 */
7973 	emit_change_signals_for_all_files_in_all_directories ();
7974 }
7975 
7976 static void
7977 thumbnail_size_changed_callback (gpointer user_data)
7978 {
7979 	cached_thumbnail_size = g_settings_get_int (nautilus_icon_view_preferences,
7980 						    NAUTILUS_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE);
7981 
7982 	/* Tell the world that icons might have changed. We could invent a narrower-scope
7983 	 * signal to mean only "thumbnails might have changed" if this ends up being slow
7984 	 * for some reason.
7985 	 */
7986 	emit_change_signals_for_all_files_in_all_directories ();
7987 }
7988 
7989 static void
7990 show_thumbnails_changed_callback (gpointer user_data)
7991 {
7992 	show_file_thumbs = g_settings_get_enum (nautilus_preferences, NAUTILUS_PREFERENCES_SHOW_FILE_THUMBNAILS);
7993 
7994 	/* Tell the world that icons might have changed. We could invent a narrower-scope
7995 	 * signal to mean only "thumbnails might have changed" if this ends up being slow
7996 	 * for some reason.
7997 	 */
7998 	emit_change_signals_for_all_files_in_all_directories ();
7999 }
8000 
8001 static void
8002 mime_type_data_changed_callback (GObject *signaller, gpointer user_data)
8003 {
8004 	/* Tell the world that icons might have changed. We could invent a narrower-scope
8005 	 * signal to mean only "thumbnails might have changed" if this ends up being slow
8006 	 * for some reason.
8007 	 */
8008 	emit_change_signals_for_all_files_in_all_directories ();
8009 }
8010 
8011 static void
8012 icon_theme_changed_callback (GtkIconTheme *icon_theme,
8013 			     gpointer user_data)
8014 {
8015 	/* Clear all pixmap caches as the icon => pixmap lookup changed */
8016 	nautilus_icon_info_clear_caches ();
8017 
8018 	/* Tell the world that icons might have changed. We could invent a narrower-scope
8019 	 * signal to mean only "thumbnails might have changed" if this ends up being slow
8020 	 * for some reason.
8021 	 */
8022 	emit_change_signals_for_all_files_in_all_directories ();
8023 }
8024 
8025 static void
8026 real_set_metadata (NautilusFile  *file,
8027 		   const char    *key,
8028 		   const char    *value)
8029 {
8030 	/* Dummy default impl */
8031 }
8032 
8033 static void
8034 real_set_metadata_as_list (NautilusFile *file,
8035 			   const char   *key,
8036 			   char         **value)
8037 {
8038 	/* Dummy default impl */
8039 }
8040 
8041 static void
8042 nautilus_file_class_init (NautilusFileClass *class)
8043 {
8044 	GtkIconTheme *icon_theme;
8045 
8046 	nautilus_file_info_getter = nautilus_file_get_internal;
8047 
8048 	attribute_name_q = g_quark_from_static_string ("name");
8049 	attribute_size_q = g_quark_from_static_string ("size");
8050 	attribute_type_q = g_quark_from_static_string ("type");
8051 	attribute_detailed_type_q = g_quark_from_static_string ("detailed_type");
8052 	attribute_modification_date_q = g_quark_from_static_string ("modification_date");
8053 	attribute_date_modified_q = g_quark_from_static_string ("date_modified");
8054 	attribute_date_modified_full_q = g_quark_from_static_string ("date_modified_full");
8055 	attribute_accessed_date_q = g_quark_from_static_string ("accessed_date");
8056 	attribute_date_accessed_q = g_quark_from_static_string ("date_accessed");
8057 	attribute_date_accessed_full_q = g_quark_from_static_string ("date_accessed_full");
8058 	attribute_mime_type_q = g_quark_from_static_string ("mime_type");
8059 	attribute_size_detail_q = g_quark_from_static_string ("size_detail");
8060 	attribute_deep_size_q = g_quark_from_static_string ("deep_size");
8061 	attribute_deep_file_count_q = g_quark_from_static_string ("deep_file_count");
8062 	attribute_deep_directory_count_q = g_quark_from_static_string ("deep_directory_count");
8063 	attribute_deep_total_count_q = g_quark_from_static_string ("deep_total_count");
8064 	attribute_search_relevance_q = g_quark_from_static_string ("search_relevance");
8065 	attribute_trashed_on_q = g_quark_from_static_string ("trashed_on");
8066 	attribute_trashed_on_full_q = g_quark_from_static_string ("trashed_on_full");
8067 	attribute_trash_orig_path_q = g_quark_from_static_string ("trash_orig_path");
8068 	attribute_permissions_q = g_quark_from_static_string ("permissions");
8069 	attribute_selinux_context_q = g_quark_from_static_string ("selinux_context");
8070 	attribute_octal_permissions_q = g_quark_from_static_string ("octal_permissions");
8071 	attribute_owner_q = g_quark_from_static_string ("owner");
8072 	attribute_group_q = g_quark_from_static_string ("group");
8073 	attribute_uri_q = g_quark_from_static_string ("uri");
8074 	attribute_where_q = g_quark_from_static_string ("where");
8075 	attribute_link_target_q = g_quark_from_static_string ("link_target");
8076 	attribute_volume_q = g_quark_from_static_string ("volume");
8077 	attribute_free_space_q = g_quark_from_static_string ("free_space");
8078 	
8079 	G_OBJECT_CLASS (class)->finalize = finalize;
8080 	G_OBJECT_CLASS (class)->constructor = nautilus_file_constructor;
8081 
8082 	class->set_metadata = real_set_metadata;
8083 	class->set_metadata_as_list = real_set_metadata_as_list;
8084 
8085 	signals[CHANGED] =
8086 		g_signal_new ("changed",
8087 		              G_TYPE_FROM_CLASS (class),
8088 		              G_SIGNAL_RUN_LAST,
8089 		              G_STRUCT_OFFSET (NautilusFileClass, changed),
8090 		              NULL, NULL,
8091 		              g_cclosure_marshal_VOID__VOID,
8092 		              G_TYPE_NONE, 0);
8093 
8094 	signals[UPDATED_DEEP_COUNT_IN_PROGRESS] =
8095 		g_signal_new ("updated_deep_count_in_progress",
8096 		              G_TYPE_FROM_CLASS (class),
8097 		              G_SIGNAL_RUN_LAST,
8098 		              G_STRUCT_OFFSET (NautilusFileClass, updated_deep_count_in_progress),
8099 		              NULL, NULL,
8100 			      g_cclosure_marshal_VOID__VOID,
8101 		              G_TYPE_NONE, 0);
8102 
8103 	g_type_class_add_private (class, sizeof (NautilusFileDetails));
8104 
8105 	thumbnail_limit_changed_callback (NULL);
8106 	g_signal_connect_swapped (nautilus_preferences,
8107 				  "changed::" NAUTILUS_PREFERENCES_FILE_THUMBNAIL_LIMIT,
8108 				  G_CALLBACK (thumbnail_limit_changed_callback),
8109 				  NULL);
8110 	thumbnail_size_changed_callback (NULL);
8111 	g_signal_connect_swapped (nautilus_preferences,
8112 				  "changed::" NAUTILUS_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE,
8113 				  G_CALLBACK (thumbnail_size_changed_callback),
8114 				  NULL);
8115 	show_thumbnails_changed_callback (NULL);
8116 	g_signal_connect_swapped (nautilus_preferences,
8117 				  "changed::" NAUTILUS_PREFERENCES_SHOW_FILE_THUMBNAILS,
8118 				  G_CALLBACK (show_thumbnails_changed_callback),
8119 				  NULL);
8120 
8121 	icon_theme = gtk_icon_theme_get_default ();
8122 	g_signal_connect_object (icon_theme,
8123 				 "changed",
8124 				 G_CALLBACK (icon_theme_changed_callback),
8125 				 NULL, 0);
8126 
8127 	g_signal_connect (nautilus_signaller_get_current (),
8128 			  "mime_data_changed",
8129 			  G_CALLBACK (mime_type_data_changed_callback),
8130 			  NULL);
8131 }
8132 
8133 static void
8134 nautilus_file_add_emblem (NautilusFile *file,
8135 			  const char *emblem_name)
8136 {
8137 	if (file->details->pending_info_providers) {
8138 		file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems,
8139 									   g_strdup (emblem_name));
8140 	} else {
8141 		file->details->extension_emblems = g_list_prepend (file->details->extension_emblems,
8142 								   g_strdup (emblem_name));
8143 	}
8144 
8145 	nautilus_file_changed (file);
8146 }
8147 
8148 static void
8149 nautilus_file_add_string_attribute (NautilusFile *file,
8150 				    const char *attribute_name,
8151 				    const char *value)
8152 {
8153 	if (file->details->pending_info_providers) {
8154 		/* Lazily create hashtable */
8155 		if (!file->details->pending_extension_attributes) {
8156 			file->details->pending_extension_attributes = 
8157 				g_hash_table_new_full (g_direct_hash, g_direct_equal,
8158 						       NULL, 
8159 						       (GDestroyNotify)g_free);
8160 		}
8161 		g_hash_table_insert (file->details->pending_extension_attributes,
8162 				     GINT_TO_POINTER (g_quark_from_string (attribute_name)),
8163 				     g_strdup (value));
8164 	} else {
8165 		if (!file->details->extension_attributes) {
8166 			file->details->extension_attributes = 
8167 				g_hash_table_new_full (g_direct_hash, g_direct_equal,
8168 						       NULL, 
8169 						       (GDestroyNotify)g_free);
8170 		}
8171 		g_hash_table_insert (file->details->extension_attributes,
8172 				     GINT_TO_POINTER (g_quark_from_string (attribute_name)),
8173 				     g_strdup (value));
8174 	}
8175 
8176 	nautilus_file_changed (file);
8177 }
8178 
8179 static void
8180 nautilus_file_invalidate_extension_info (NautilusFile *file)
8181 {
8182 	nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO);
8183 }
8184 
8185 void
8186 nautilus_file_info_providers_done (NautilusFile *file)
8187 {
8188 	g_list_free_full (file->details->extension_emblems, g_free);
8189 	file->details->extension_emblems = file->details->pending_extension_emblems;
8190 	file->details->pending_extension_emblems = NULL;
8191 
8192 	if (file->details->extension_attributes) {
8193 		g_hash_table_destroy (file->details->extension_attributes);
8194 	}
8195 	
8196 	file->details->extension_attributes = file->details->pending_extension_attributes;
8197 	file->details->pending_extension_attributes = NULL;
8198 
8199 	nautilus_file_changed (file);
8200 }
8201 
8202 static void     
8203 nautilus_file_info_iface_init (NautilusFileInfoIface *iface)
8204 {
8205 	iface->is_gone = nautilus_file_is_gone;
8206 	iface->get_name = nautilus_file_get_name;
8207 	iface->get_file_type = nautilus_file_get_file_type;
8208 	iface->get_location = nautilus_file_get_location;
8209 	iface->get_uri = nautilus_file_get_uri;
8210 	iface->get_parent_location = nautilus_file_get_parent_location;
8211 	iface->get_parent_uri = nautilus_file_get_parent_uri;
8212 	iface->get_parent_info = nautilus_file_get_parent;
8213 	iface->get_mount = nautilus_file_get_mount;
8214 	iface->get_uri_scheme = nautilus_file_get_uri_scheme;
8215 	iface->get_activation_uri = nautilus_file_get_activation_uri;
8216 	iface->get_mime_type = nautilus_file_get_mime_type;
8217 	iface->is_mime_type = nautilus_file_is_mime_type;
8218 	iface->is_directory = nautilus_file_is_directory;
8219 	iface->can_write = nautilus_file_can_write;
8220 	iface->add_emblem = nautilus_file_add_emblem;
8221 	iface->get_string_attribute = nautilus_file_get_string_attribute;
8222 	iface->add_string_attribute = nautilus_file_add_string_attribute;
8223 	iface->invalidate_extension_info = nautilus_file_invalidate_extension_info;
8224 }
8225 
8226 #if !defined (NAUTILUS_OMIT_SELF_CHECK)
8227 
8228 void
8229 nautilus_self_check_file (void)
8230 {
8231 	NautilusFile *file_1;
8232 	NautilusFile *file_2;
8233 	GList *list;
8234 
8235         /* refcount checks */
8236 
8237         EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
8238 
8239 	file_1 = nautilus_file_get_by_uri ("file:///home/");
8240 
8241 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
8242 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1->details->directory)->ref_count, 1);
8243         EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 1);
8244 
8245 	nautilus_file_unref (file_1);
8246 
8247         EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
8248 	
8249 	file_1 = nautilus_file_get_by_uri ("file:///etc");
8250 	file_2 = nautilus_file_get_by_uri ("file:///usr");
8251 
8252         list = NULL;
8253         list = g_list_prepend (list, file_1);
8254         list = g_list_prepend (list, file_2);
8255 
8256         nautilus_file_list_ref (list);
8257         
8258 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 2);
8259 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 2);
8260 
8261 	nautilus_file_list_unref (list);
8262         
8263 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
8264 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
8265 
8266 	nautilus_file_list_free (list);
8267 
8268         EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
8269 	
8270 
8271         /* name checks */
8272 	file_1 = nautilus_file_get_by_uri ("file:///home/");
8273 
8274 	EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "home");
8275 
8276 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_get_by_uri ("file:///home/") == file_1, TRUE);
8277 	nautilus_file_unref (file_1);
8278 
8279 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_get_by_uri ("file:///home") == file_1, TRUE);
8280 	nautilus_file_unref (file_1);
8281 
8282 	nautilus_file_unref (file_1);
8283 
8284 	file_1 = nautilus_file_get_by_uri ("file:///home");
8285 	EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "home");
8286 	nautilus_file_unref (file_1);
8287 
8288 	/* ALEX: I removed this, because it was breaking distchecks.
8289 	 * It used to work, but when canonical uris changed from
8290 	 * foo: to foo:/// it broke. I don't expect it to matter
8291 	 * in real life */
8292 	file_1 = nautilus_file_get_by_uri (":");
8293 	EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), ":");
8294 	nautilus_file_unref (file_1);
8295 
8296 	file_1 = nautilus_file_get_by_uri ("eazel:");
8297 	EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "eazel:///");
8298 	nautilus_file_unref (file_1);
8299 
8300 	/* sorting */
8301 	file_1 = nautilus_file_get_by_uri ("file:///etc");
8302 	file_2 = nautilus_file_get_by_uri ("file:///usr");
8303 
8304 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
8305 	EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
8306 
8307 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_2, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) < 0, TRUE);
8308 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_2, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) > 0, TRUE);
8309 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) == 0, TRUE);
8310 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, TRUE, FALSE) == 0, TRUE);
8311 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) == 0, TRUE);
8312 	EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, TRUE, TRUE) == 0, TRUE);
8313 
8314 	nautilus_file_unref (file_1);
8315 	nautilus_file_unref (file_2);
8316 }
8317 
8318 #endif /* !NAUTILUS_OMIT_SELF_CHECK */