nautilus-file.c 183 KB
Newer Older
1 2 3 4
/* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-

   nautilus-file.c: Nautilus file model.
 
5
   Copyright (C) 1999, 2000, 2001 Eazel, Inc.
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
  
   This program is free software; you can redistribute it and/or
   modify it under the terms of the GNU General Public License as
   published by the Free Software Foundation; either version 2 of the
   License, or (at your option) any later version.
  
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
   General Public License for more details.
  
   You should have received a copy of the GNU General Public
   License along with this program; if not, write to the
   Free Software Foundation, Inc., 59 Temple Place - Suite 330,
   Boston, MA 02111-1307, USA.
  
22
   Author: Darin Adler <darin@bentspoon.com>
23 24 25
*/

#include <config.h>
26
#include "nautilus-file.h"
27

28
#include "nautilus-directory-metafile.h"
29
#include "nautilus-directory-notify.h"
30
#include "nautilus-directory-private.h"
Alexander Larsson's avatar
Alexander Larsson committed
31
#include "nautilus-signaller.h"
Alexander Larsson's avatar
Alexander Larsson committed
32 33 34
#include "nautilus-desktop-directory.h"
#include "nautilus-desktop-directory-file.h"
#include "nautilus-desktop-icon-file.h"
35 36
#include "nautilus-file-attributes.h"
#include "nautilus-file-private.h"
Alexander Larsson's avatar
Alexander Larsson committed
37
#include "nautilus-file-operations.h"
38
#include "nautilus-file-utilities.h"
39 40 41
#include "nautilus-global-preferences.h"
#include "nautilus-lib-self-check-functions.h"
#include "nautilus-link.h"
42
#include "nautilus-metadata.h"
43
#include "nautilus-module.h"
44 45
#include "nautilus-search-directory.h"
#include "nautilus-search-directory-file.h"
46
#include "nautilus-thumbnails.h"
47
#include "nautilus-users-groups-cache.h"
48
#include "nautilus-vfs-file.h"
49
#include "nautilus-saved-search-file.h"
50
#include <eel/eel-debug.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
51 52
#include <eel/eel-glib-extensions.h>
#include <eel/eel-gtk-extensions.h>
53
#include <eel/eel-vfs-extensions.h>
Ramiro Estrugo's avatar
Ramiro Estrugo committed
54 55
#include <eel/eel-gtk-macros.h>
#include <eel/eel-string.h>
56
#include <grp.h>
57
#include <gtk/gtksignal.h>
58
#include <glib/gi18n.h>
59
#include <gio/gio.h>
Alexander Larsson's avatar
Alexander Larsson committed
60
#include <glib/gurifuncs.h>
61
#include <libgnome/gnome-macros.h>
Alexander Larsson's avatar
Alexander Larsson committed
62
#include <glib/gfileutils.h>
63
#include <libnautilus-extension/nautilus-file-info.h>
64
#include <libxml/parser.h>
65 66
#include <pwd.h>
#include <stdlib.h>
67
#include <sys/time.h>
68
#include <time.h>
69
#include <unistd.h>
70

71 72 73 74
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif

75 76
/* Time in seconds to cache getpwuid results */
#define GETPWUID_CACHE_TIME (5*60)
77

Alexander Larsson's avatar
Alexander Larsson committed
78
#define ICON_NAME_THUMBNAIL_LOADING   "image-loading"
79

80
#undef NAUTILUS_FILE_DEBUG_REF
81
#undef NAUTILUS_FILE_DEBUG_REF_VALGRIND
82

83 84 85 86 87
#ifdef NAUTILUS_FILE_DEBUG_REF_VALGRIND
#include <valgrind/valgrind.h>
#define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE
#else
#define DEBUG_REF_PRINTF printf
88 89
#endif

90
/* Files that start with these characters sort after files that don't. */
91 92
#define SORT_LAST_CHAR1 '.'
#define SORT_LAST_CHAR2 '#'
93 94 95 96

/* Name to use to tag metadata for the directory itself. */
#define FILE_NAME_FOR_DIRECTORY_METADATA "."

97 98 99
/* Name of Nautilus trash directories */
#define TRASH_DIRECTORY_NAME ".Trash"

100 101 102 103
typedef enum {
	SHOW_HIDDEN = 1 << 0,
	SHOW_BACKUP = 1 << 1
} FilterOptions;
104

105
typedef void (* ModifyListFunction) (GList **list, NautilusFile *file);
106

107 108
enum {
	CHANGED,
109
	UPDATED_DEEP_COUNT_IN_PROGRESS,
110 111 112
	LAST_SIGNAL
};

113 114
static int date_format_pref;

115 116
static guint signals[LAST_SIGNAL];

117
static GObjectClass *parent_class = NULL;
118

119
static GHashTable *symbolic_links;
120

121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148
static GQuark attribute_name_q,
	attribute_size_q,
	attribute_type_q,
	attribute_modification_date_q,
	attribute_date_modified_q,
	attribute_accessed_date_q,
	attribute_date_accessed_q,
	attribute_emblems_q,
	attribute_mime_type_q,
	attribute_size_detail_q,
	attribute_deep_size_q,
	attribute_deep_file_count_q,
	attribute_deep_directory_count_q,
	attribute_deep_total_count_q,
	attribute_date_changed_q,
	attribute_date_permissions_q,
	attribute_permissions_q,
	attribute_selinux_context_q,
	attribute_octal_permissions_q,
	attribute_owner_q,
	attribute_group_q,
	attribute_uri_q,
	attribute_where_q,
	attribute_link_target_q,
	attribute_volume_q,
	attribute_free_space_q;


149 150 151 152 153 154 155
static void     nautilus_file_instance_init                  (NautilusFile          *file);
static void     nautilus_file_class_init                     (NautilusFileClass     *class);
static void     nautilus_file_info_iface_init                (NautilusFileInfoIface *iface);
static char *   nautilus_file_get_owner_as_string            (NautilusFile          *file,
							      gboolean               include_real_name);
static char *   nautilus_file_get_type_as_string             (NautilusFile          *file);
static gboolean update_info_and_name                         (NautilusFile          *file,
Alexander Larsson's avatar
Alexander Larsson committed
156 157 158
							      GFileInfo             *info);
static const char * nautilus_file_peek_display_name (NautilusFile *file);
static const char * nautilus_file_peek_display_name_collation_key (NautilusFile *file);
159 160 161 162 163 164 165

GType
nautilus_file_get_type (void)
{
	static GType type = 0;
	
	if (!type) {
166
		const GTypeInfo info = {
167 168 169 170 171 172 173 174 175 176 177
			sizeof (NautilusFileClass),
			NULL, 
			NULL,
			(GClassInitFunc) nautilus_file_class_init,
			NULL,
			NULL,
			sizeof (NautilusFile),
			0,
			(GInstanceInitFunc) nautilus_file_instance_init,
		};
		
178
		const GInterfaceInfo file_info_iface_info = {
179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
			(GInterfaceInitFunc) nautilus_file_info_iface_init,
			NULL,
			NULL
		};
		
		type = g_type_register_static (G_TYPE_OBJECT,
					       "NautilusFile",
					       &info, 0);
		g_type_add_interface_static (type, 
					     NAUTILUS_TYPE_FILE_INFO,
					     &file_info_iface_info);
	}
	
	return type;
}
194 195

static void
196
nautilus_file_instance_init (NautilusFile *file)
197
{
Alexander Larsson's avatar
Alexander Larsson committed
198
	file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NAUTILUS_TYPE_FILE, NautilusFileDetails);
199

Alexander Larsson's avatar
Alexander Larsson committed
200
	nautilus_file_clear_info (file);
201
	nautilus_file_invalidate_extension_info_internal (file);
202 203
}

Alexander Larsson's avatar
Alexander Larsson committed
204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324
static GObject*
nautilus_file_constructor (GType                  type,
			   guint                  n_construct_properties,
			   GObjectConstructParam *construct_params)
{
  GObject *object;
  NautilusFile *file;

  object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
							   n_construct_properties,
							   construct_params);

  file = NAUTILUS_FILE (object);

  /* Set to default type after full construction */
  if (NAUTILUS_FILE_GET_CLASS (file)->default_file_type != G_FILE_TYPE_UNKNOWN) {
	  file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;
  }
  
  return object;
}

gboolean
nautilus_file_set_display_name (NautilusFile *file,
				const char *display_name,
				const char *edit_name,
				gboolean custom)
{
	gboolean changed;

	if (display_name == NULL) {
		return FALSE;
	}
	
	if (!custom && file->details->got_custom_display_name) {
		return FALSE;
	}

	if (custom && display_name == NULL) {
		/* We're re-setting a custom display name, invalidate it if
		   we already set it so that the old one is re-read */
		if (file->details->got_custom_display_name) {
			file->details->got_custom_display_name = FALSE;
			nautilus_file_invalidate_attributes (file,
							     NAUTILUS_FILE_ATTRIBUTE_INFO);
		}
		return FALSE;
	}

	if (edit_name == NULL) {
		edit_name = display_name;
	}
	    
	changed = FALSE;
	
	if (eel_strcmp (eel_ref_str_peek (file->details->display_name), display_name) != 0) {
		changed = TRUE;
		
		eel_ref_str_unref (file->details->display_name);
		
		if (eel_strcmp (eel_ref_str_peek (file->details->name), display_name) == 0) {
			file->details->display_name = eel_ref_str_ref (file->details->name);
		} else {
			file->details->display_name = eel_ref_str_new (display_name);
		}
		
		g_free (file->details->display_name_collation_key);
		file->details->display_name_collation_key = g_utf8_collate_key_for_filename (display_name, -1);
	}

	if (eel_strcmp (eel_ref_str_peek (file->details->edit_name), edit_name) != 0) {
		changed = TRUE;
		
		eel_ref_str_unref (file->details->edit_name);
		if (eel_strcmp (eel_ref_str_peek (file->details->display_name), edit_name) == 0) {
			file->details->edit_name = eel_ref_str_ref (file->details->display_name);
		} else {
			file->details->edit_name = eel_ref_str_new (edit_name);
		}
	}
	
	file->details->got_custom_display_name = custom;
	return changed;
}

void
nautilus_file_clear_info (NautilusFile *file)
{
	file->details->got_file_info = FALSE;
	if (file->details->get_info_error) {
		g_error_free (file->details->get_info_error);
		file->details->get_info_error = NULL;
	}
	/* Reset to default type, which might be other than unknown for
	   special kinds of files like the desktop or a search directory */
	file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;

	if (!file->details->got_custom_display_name) {
		eel_ref_str_unref (file->details->display_name);
		file->details->display_name = NULL;
		g_free (file->details->display_name_collation_key);
		file->details->display_name_collation_key = NULL;
		eel_ref_str_unref (file->details->edit_name);
		file->details->edit_name = NULL;
	}

	if (!file->details->got_custom_activation_location &&
	    file->details->activation_location != NULL) {
		g_object_unref (file->details->activation_location);
		file->details->activation_location = NULL;
	}
	
	if (file->details->icon != NULL) {
		g_object_unref (file->details->icon);
		file->details->icon = NULL;
	}

	g_free (file->details->thumbnail_path);
	file->details->thumbnail_path = NULL;
	file->details->thumbnailing_failed = FALSE;
	
325
	file->details->is_launcher = FALSE;
Alexander Larsson's avatar
Alexander Larsson committed
326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355
	file->details->is_symlink = FALSE;
	file->details->is_hidden = FALSE;
	file->details->is_backup = FALSE;
	file->details->is_mountpoint = FALSE;
	file->details->uid = -1;
	file->details->gid = -1;
	file->details->can_read = TRUE;
	file->details->can_write = TRUE;
	file->details->can_execute = TRUE;
	file->details->can_delete = TRUE;
	file->details->can_trash = TRUE;
	file->details->can_rename = TRUE;
	file->details->can_mount = FALSE;
	file->details->can_unmount = FALSE;
	file->details->can_eject = FALSE;
	file->details->has_permissions = FALSE;
	file->details->permissions = 0;
	file->details->size = -1;
	file->details->sort_order = 0;
	file->details->mtime = 0;
	file->details->atime = 0;
	file->details->ctime = 0;
	g_free (file->details->symlink_name);
	file->details->symlink_name = NULL;
	eel_ref_str_unref (file->details->mime_type);
	file->details->mime_type = NULL;
	g_free (file->details->selinux_context);
	file->details->selinux_context = NULL;
}

356
static NautilusFile *
Alexander Larsson's avatar
Alexander Larsson committed
357 358 359
nautilus_file_new_from_filename (NautilusDirectory *directory,
				 const char *filename,
				 gboolean self_owned)
360 361 362 363
{
	NautilusFile *file;

	g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
Alexander Larsson's avatar
Alexander Larsson committed
364 365
	g_return_val_if_fail (filename != NULL, NULL);
	g_return_val_if_fail (filename[0] != '\0', NULL);
366

Alexander Larsson's avatar
Alexander Larsson committed
367
	if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
Alexander Larsson's avatar
Alexander Larsson committed
368 369 370
		if (self_owned) {
			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NULL));
		} else {
371 372 373
			/* This doesn't normally happen, unless the user somehow types in a uri
			 * that references a file like this. (See #349840) */
			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
Alexander Larsson's avatar
Alexander Larsson committed
374
		}
375 376 377 378
	} else if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
		if (self_owned) {
			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NULL));
		} else {
379 380 381
			/* This doesn't normally happen, unless the user somehow types in a uri
			 * that references a file like this. (See #349840) */
			file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
382
		}
Alexander Larsson's avatar
Alexander Larsson committed
383
	} else if (g_str_has_suffix (filename, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
384
		file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
385
	} else {
386
		file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
387
	}
388

Alexander Larsson's avatar
Alexander Larsson committed
389
	file->details->directory = nautilus_directory_ref (directory);
390

Alexander Larsson's avatar
Alexander Larsson committed
391
	file->details->name = eel_ref_str_new (filename);
392

393 394 395 396
#ifdef NAUTILUS_FILE_DEBUG_REF
	DEBUG_REF_PRINTF("%10p ref'd", file);
#endif

397 398 399
	return file;
}

400 401 402 403
static void
modify_link_hash_table (NautilusFile *file,
			ModifyListFunction modify_function)
{
404
	char *target_uri;
405 406
	gboolean found;
	gpointer original_key;
407
	GList **list_ptr;
408 409

	/* Check if there is a symlink name. If none, we are OK. */
Alexander Larsson's avatar
Alexander Larsson committed
410
	if (file->details->symlink_name == NULL) {
411 412 413
		return;
	}

414
	/* Create the hash table first time through. */
415
	if (symbolic_links == NULL) {
Ramiro Estrugo's avatar
Ramiro Estrugo committed
416
		symbolic_links = eel_g_hash_table_new_free_at_exit
417 418 419
			(g_str_hash, g_str_equal, "nautilus-file.c: symbolic_links");
	}

420 421
	target_uri = nautilus_file_get_symbolic_link_target_uri (file);
	
422 423
	/* Find the old contents of the hash table. */
	found = g_hash_table_lookup_extended
424 425
		(symbolic_links, target_uri,
		 &original_key, (gpointer *)&list_ptr);
426
	if (!found) {
427
		list_ptr = g_new0 (GList *, 1);
Alexander Larsson's avatar
Alexander Larsson committed
428 429
		original_key = g_strdup (target_uri);
		g_hash_table_insert (symbolic_links, original_key, list_ptr);
430
	}
431 432 433 434
	(* modify_function) (list_ptr, file);
	if (*list_ptr == NULL) {
		g_hash_table_remove (symbolic_links, target_uri);
		g_free (list_ptr);
Martin Wehner's avatar
Martin Wehner committed
435
		g_free (original_key);
436
	}
437
	g_free (target_uri);
438 439
}

440 441 442 443 444 445 446 447 448 449 450 451
static void
symbolic_link_weak_notify (gpointer      data,
			   GObject      *where_the_object_was)
{
	GList **list = data;
	/* This really shouldn't happen, but we're seeing some strange things in
	   bug #358172 where the symlink hashtable isn't correctly updated. */
	*list = g_list_remove (*list, where_the_object_was);
}

static void
add_to_link_hash_table_list (GList **list, NautilusFile *file)
452
{
453 454 455 456 457 458 459
	if (g_list_find (*list, file) != NULL) {
		g_warning ("Adding file to symlink_table multiple times. "
			   "Please add feedback of what you were doing at http://bugzilla.gnome.org/show_bug.cgi?id=358172\n");
		return;
	}
	g_object_weak_ref (G_OBJECT (file), symbolic_link_weak_notify, list);
	*list = g_list_prepend (*list, file); 
460 461 462 463 464 465 466 467
}

static void
add_to_link_hash_table (NautilusFile *file)
{
	modify_link_hash_table (file, add_to_link_hash_table_list);
}

468 469
static void
remove_from_link_hash_table_list (GList **list, NautilusFile *file)
470
{
471 472 473 474
	if (g_list_find (*list, file) != NULL) {
		g_object_weak_unref (G_OBJECT (file), symbolic_link_weak_notify, list);
		*list = g_list_remove (*list, file);
	}
475 476 477 478 479 480 481 482
}

static void
remove_from_link_hash_table (NautilusFile *file)
{
	modify_link_hash_table (file, remove_from_link_hash_table_list);
}

483
NautilusFile *
484
nautilus_file_new_from_info (NautilusDirectory *directory,
Alexander Larsson's avatar
Alexander Larsson committed
485
			     GFileInfo *info)
486 487
{
	NautilusFile *file;
Alexander Larsson's avatar
Alexander Larsson committed
488
	const char *mime_type;
489 490 491 492

	g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
	g_return_val_if_fail (info != NULL, NULL);

Alexander Larsson's avatar
Alexander Larsson committed
493 494 495 496
	mime_type = g_file_info_get_content_type (info);
	if (mime_type &&
	    strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0) {
		g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
497 498 499 500
		file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
	} else {
		file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
	}
501

Alexander Larsson's avatar
Alexander Larsson committed
502
	file->details->directory = nautilus_directory_ref (directory);
503

Alexander Larsson's avatar
Alexander Larsson committed
504
	update_info_and_name (file, info);
505 506 507 508 509

#ifdef NAUTILUS_FILE_DEBUG_REF
	DEBUG_REF_PRINTF("%10p ref'd", file);
#endif

510 511 512
	return file;
}

513
static NautilusFile *
Alexander Larsson's avatar
Alexander Larsson committed
514
nautilus_file_get_internal (GFile *location, gboolean create)
515
{
516
	gboolean self_owned;
517 518
	NautilusDirectory *directory;
	NautilusFile *file;
Alexander Larsson's avatar
Alexander Larsson committed
519 520
	GFile *parent;
	char *basename;
521

Alexander Larsson's avatar
Alexander Larsson committed
522
	g_return_val_if_fail (location != NULL, NULL);
523

Alexander Larsson's avatar
Alexander Larsson committed
524
	parent = g_file_get_parent (location);
Alexander Larsson's avatar
Alexander Larsson committed
525
	
Alexander Larsson's avatar
Alexander Larsson committed
526 527
	self_owned = FALSE;
	if (parent == NULL) {
Alexander Larsson's avatar
Alexander Larsson committed
528
		self_owned = TRUE;
Alexander Larsson's avatar
Alexander Larsson committed
529 530
		parent = g_object_ref (location);
	} 
531 532

	/* Get object that represents the directory. */
Alexander Larsson's avatar
Alexander Larsson committed
533 534 535
	directory = nautilus_directory_get_internal (parent, create);

	g_object_unref (parent);
536 537

	/* Get the name for the file. */
Alexander Larsson's avatar
Alexander Larsson committed
538 539 540 541
	if (self_owned && directory != NULL) {
		basename = nautilus_directory_get_name_for_self_as_new_file (directory);
	} else {
		basename = g_file_get_basename (location);
542
	}
543
	/* Check to see if it's a file that's already known. */
544 545 546 547
	if (directory == NULL) {
		file = NULL;
	} else if (self_owned) {
		file = directory->details->as_file;
548
	} else {
Alexander Larsson's avatar
Alexander Larsson committed
549
		file = nautilus_directory_find_file_by_name (directory, basename);
550
	}
551 552

	/* Ref or create the file. */
553 554
	if (file != NULL) {
		nautilus_file_ref (file);
555
	} else if (create) {
Alexander Larsson's avatar
Alexander Larsson committed
556
		file = nautilus_file_new_from_filename (directory, basename, self_owned);
557 558 559 560
		if (self_owned) {
			g_assert (directory->details->as_file == NULL);
			directory->details->as_file = file;
		} else {
561
			nautilus_directory_add_file (directory, file);
562
		}
563
	}
564

Alexander Larsson's avatar
Alexander Larsson committed
565
	g_free (basename);
566
	nautilus_directory_unref (directory);
567

568 569 570
	return file;
}

571
NautilusFile *
Alexander Larsson's avatar
Alexander Larsson committed
572 573 574 575 576 577 578 579 580 581 582 583 584
nautilus_file_get (GFile *location)
{
	return nautilus_file_get_internal (location, TRUE);
}

NautilusFile *
nautilus_file_get_existing (GFile *location)
{
	return nautilus_file_get_internal (location, FALSE);
}

NautilusFile *
nautilus_file_get_existing_by_uri (const char *uri)
585
{
Alexander Larsson's avatar
Alexander Larsson committed
586 587 588 589 590 591 592 593
	GFile *location;
	NautilusFile *file;
	
	location = g_file_new_for_uri (uri);
	file = nautilus_file_get_internal (location, FALSE);
	g_object_unref (location);
	
	return file;
594 595 596
}

NautilusFile *
Alexander Larsson's avatar
Alexander Larsson committed
597
nautilus_file_get_by_uri (const char *uri)
598
{
Alexander Larsson's avatar
Alexander Larsson committed
599 600 601 602 603 604 605 606
	GFile *location;
	NautilusFile *file;
	
	location = g_file_new_for_uri (uri);
	file = nautilus_file_get_internal (location, TRUE);
	g_object_unref (location);
	
	return file;
607 608
}

609 610
gboolean
nautilus_file_is_self_owned (NautilusFile *file)
611 612 613 614
{
	return file->details->directory->details->as_file == file;
}

615
static void
616
finalize (GObject *object)
617
{
618
	NautilusDirectory *directory;
619
	NautilusFile *file;
620
	char *uri;
621 622 623

	file = NAUTILUS_FILE (object);

624 625
	g_assert (file->details->operations_in_progress == NULL);

626 627 628 629 630 631
	if (file->details->is_thumbnailing) {
		uri = nautilus_file_get_uri (file);
		nautilus_thumbnail_remove_from_queue (uri);
		g_free (uri);
	}
	
632
	nautilus_async_destroying_file (file);
633

634 635
	remove_from_link_hash_table (file);

636 637
	directory = file->details->directory;
	
638
	if (nautilus_file_is_self_owned (file)) {
639
		directory->details->as_file = NULL;
640
	} else {
641 642
		if (!file->details->is_gone) {
			nautilus_directory_remove_file (directory, file);
643
		}
644 645
	}

Alexander Larsson's avatar
Alexander Larsson committed
646 647 648 649
	if (file->details->get_info_error) {
		g_error_free (file->details->get_info_error);
	}

650
	nautilus_directory_unref (directory);
Alexander Larsson's avatar
Alexander Larsson committed
651 652
	eel_ref_str_unref (file->details->name);
	eel_ref_str_unref (file->details->display_name);
653
	g_free (file->details->display_name_collation_key);
Alexander Larsson's avatar
Alexander Larsson committed
654 655 656 657 658 659 660 661
	eel_ref_str_unref (file->details->edit_name);
	if (file->details->icon) {
		g_object_unref (file->details->icon);
	}
	g_free (file->details->thumbnail_path);
	g_free (file->details->symlink_name);
	eel_ref_str_unref (file->details->mime_type);
	g_free (file->details->selinux_context);
662
	g_free (file->details->top_left_text);
663
	g_free (file->details->custom_icon);
Alexander Larsson's avatar
Alexander Larsson committed
664 665 666
	if (file->details->activation_location) {
		g_object_unref (file->details->activation_location);
	}
667
	g_free (file->details->compare_by_emblem_cache);
Alexander Larsson's avatar
Alexander Larsson committed
668 669 670 671

	if (file->details->thumbnail) {
		g_object_unref (file->details->thumbnail);
	}
672 673 674
	if (file->details->mount) {
		g_object_unref (file->details->mount);
	}
675
	
Ramiro Estrugo's avatar
Ramiro Estrugo committed
676
	eel_g_list_free_deep (file->details->mime_list);
677

678 679 680 681 682 683 684 685 686 687 688
	eel_g_list_free_deep (file->details->pending_extension_emblems);
	eel_g_list_free_deep (file->details->extension_emblems);	

	if (file->details->pending_extension_attributes) {
		g_hash_table_destroy (file->details->pending_extension_attributes);
	}
	
	if (file->details->extension_attributes) {
		g_hash_table_destroy (file->details->extension_attributes);
	}

689
	G_OBJECT_CLASS (parent_class)->finalize (object);
690 691
}

692
NautilusFile *
693 694
nautilus_file_ref (NautilusFile *file)
{
695
	if (file == NULL) {
696
		return NULL;
697
	}
698
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
699 700

#ifdef NAUTILUS_FILE_DEBUG_REF
701
	DEBUG_REF_PRINTF("%10p ref'd", file);
702
#endif
703 704
	
	return g_object_ref (file);
705 706 707 708 709
}

void
nautilus_file_unref (NautilusFile *file)
{
710 711 712 713
	if (file == NULL) {
		return;
	}

714
	g_return_if_fail (NAUTILUS_IS_FILE (file));
715

716
#ifdef NAUTILUS_FILE_DEBUG_REF
717
	DEBUG_REF_PRINTF("%10p unref'd", file);
718
#endif
719
	
720
	g_object_unref (file);
721 722
}

723
/**
724
 * nautilus_file_get_parent_uri_for_display:
725 726 727 728 729
 * 
 * Get the uri for the parent directory.
 * 
 * @file: The file in question.
 * 
730 731
 * Return value: A string representing the parent's location,
 * formatted for user display (including stripping "file://").
732
 * If the parent is NULL, returns the empty string.
733 734
 */ 
char *
735
nautilus_file_get_parent_uri_for_display (NautilusFile *file) 
736
{
Alexander Larsson's avatar
Alexander Larsson committed
737
	GFile *parent;
738 739 740 741
	char *result;

	g_assert (NAUTILUS_IS_FILE (file));
	
Alexander Larsson's avatar
Alexander Larsson committed
742 743 744 745 746 747 748
	parent = nautilus_file_get_parent_location (file);
	if (parent) {
		result = g_file_get_parse_name (parent);
		g_object_unref (parent);
	} else {
		result = g_strdup ("");
	}
749

750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767
	return result;
}

/**
 * nautilus_file_get_parent_uri:
 * 
 * Get the uri for the parent directory.
 * 
 * @file: The file in question.
 * 
 * Return value: A string for the parent's location, in "raw URI" form.
 * Use nautilus_file_get_parent_uri_for_display instead if the
 * result is to be displayed on-screen.
 * If the parent is NULL, returns the empty string.
 */ 
char *
nautilus_file_get_parent_uri (NautilusFile *file) 
{
768 769
	g_assert (NAUTILUS_IS_FILE (file));
	
770
	if (nautilus_file_is_self_owned (file)) {
771
		/* Callers expect an empty string, not a NULL. */
772
		return g_strdup ("");
773 774
	}

775
	return nautilus_directory_get_uri (file->details->directory);
776 777
}

Alexander Larsson's avatar
Alexander Larsson committed
778 779
GFile *
nautilus_file_get_parent_location (NautilusFile *file) 
780 781 782
{
	g_assert (NAUTILUS_IS_FILE (file));
	
783
	if (nautilus_file_is_self_owned (file)) {
Alexander Larsson's avatar
Alexander Larsson committed
784
		/* Callers expect an empty string, not a NULL. */
785 786 787
		return NULL;
	}

Alexander Larsson's avatar
Alexander Larsson committed
788
	return nautilus_directory_get_location (file->details->directory);
789 790
}

Alexander Larsson's avatar
Alexander Larsson committed
791 792
NautilusFile *
nautilus_file_get_parent (NautilusFile *file)
793 794
{
	g_assert (NAUTILUS_IS_FILE (file));
795
	
Alexander Larsson's avatar
Alexander Larsson committed
796 797
	if (nautilus_file_is_self_owned (file)) {
		return NULL;
798 799
	}

Alexander Larsson's avatar
Alexander Larsson committed
800
	return nautilus_directory_get_corresponding_file (file->details->directory);
801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818
}

/**
 * nautilus_file_can_read:
 * 
 * Check whether the user is allowed to read the contents of this file.
 * 
 * @file: The file to check.
 * 
 * Return value: FALSE if the user is definitely not allowed to read
 * the contents of the file. If the user has read permission, or
 * the code can't tell whether the user has read permission,
 * returns TRUE (so failures must always be handled).
 */
gboolean
nautilus_file_can_read (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
Alexander Larsson's avatar
Alexander Larsson committed
819 820
	
	return file->details->can_read;
821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
}

/**
 * nautilus_file_can_write:
 * 
 * Check whether the user is allowed to write to this file.
 * 
 * @file: The file to check.
 * 
 * Return value: FALSE if the user is definitely not allowed to write
 * to the file. If the user has write permission, or
 * the code can't tell whether the user has write permission,
 * returns TRUE (so failures must always be handled).
 */
gboolean
nautilus_file_can_write (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);

Alexander Larsson's avatar
Alexander Larsson committed
840
	return file->details->can_write;
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859
}

/**
 * nautilus_file_can_execute:
 * 
 * Check whether the user is allowed to execute this file.
 * 
 * @file: The file to check.
 * 
 * Return value: FALSE if the user is definitely not allowed to execute
 * the file. If the user has execute permission, or
 * the code can't tell whether the user has execute permission,
 * returns TRUE (so failures must always be handled).
 */
gboolean
nautilus_file_can_execute (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);

Alexander Larsson's avatar
Alexander Larsson committed
860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875
	return file->details->can_execute;
}

gboolean
nautilus_file_can_mount (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
	
	return file->details->can_mount;
}
	
gboolean
nautilus_file_can_unmount (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);

Alexander Larsson's avatar
Alexander Larsson committed
876 877 878
	return file->details->can_unmount ||
		(file->details->mount != NULL &&
		 g_mount_can_unmount (file->details->mount));
Alexander Larsson's avatar
Alexander Larsson committed
879 880 881 882 883 884 885
}
	
gboolean
nautilus_file_can_eject (NautilusFile *file)
{
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);

Alexander Larsson's avatar
Alexander Larsson committed
886 887 888
	return file->details->can_eject ||
		(file->details->mount != NULL &&
		 g_mount_can_eject (file->details->mount));
Alexander Larsson's avatar
Alexander Larsson committed
889 890 891 892 893
}

void
nautilus_file_mount (NautilusFile                   *file,
		     GMountOperation                *mount_op,
894
		     GCancellable                   *cancellable,
Alexander Larsson's avatar
Alexander Larsson committed
895 896 897 898 899 900 901 902 903 904 905 906 907 908
		     NautilusFileOperationCallback   callback,
		     gpointer                        callback_data)
{
	GError *error;
	
	if (NAUTILUS_FILE_GET_CLASS (file)->mount == NULL) {
		if (callback) {
			error = NULL;
			g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
				     _("This file cannot be mounted"));
			callback (file, NULL, error, callback_data);
			g_error_free (error);
		}
	} else {
909
		NAUTILUS_FILE_GET_CLASS (file)->mount (file, mount_op, cancellable, callback, callback_data);
Alexander Larsson's avatar
Alexander Larsson committed
910 911 912 913
	}
}

void
914
nautilus_file_unmount (NautilusFile *file)
Alexander Larsson's avatar
Alexander Larsson committed
915
{
Alexander Larsson's avatar
Alexander Larsson committed
916 917 918 919 920 921 922
	if (file->details->can_unmount) {
		if (NAUTILUS_FILE_GET_CLASS (file)->unmount != NULL) {
			NAUTILUS_FILE_GET_CLASS (file)->unmount (file);
		}
	} else if (file->details->mount != NULL &&
		   g_mount_can_unmount (file->details->mount)) {
		nautilus_file_operations_unmount_mount (NULL, file->details->mount, FALSE, TRUE);
Alexander Larsson's avatar
Alexander Larsson committed
923 924 925 926
	}
}

void
927
nautilus_file_eject (NautilusFile *file)
Alexander Larsson's avatar
Alexander Larsson committed
928
{
Alexander Larsson's avatar
Alexander Larsson committed
929 930 931 932 933 934 935
	if (file->details->can_eject) {
		if (NAUTILUS_FILE_GET_CLASS (file)->eject != NULL) {
			NAUTILUS_FILE_GET_CLASS (file)->eject (file);
		}
	} else if (file->details->mount != NULL &&
		   g_mount_can_eject (file->details->mount)) {
		nautilus_file_operations_unmount_mount (NULL, file->details->mount, TRUE, TRUE);
Alexander Larsson's avatar
Alexander Larsson committed
936
	}
937 938
}

939 940 941 942 943 944 945 946 947 948 949
/**
 * nautilus_file_is_desktop_directory:
 * 
 * Check whether this file is the desktop directory.
 * 
 * @file: The file to check.
 * 
 * Return value: TRUE if this is the physical desktop directory.
 */
gboolean
nautilus_file_is_desktop_directory (NautilusFile *file)
950
{
Alexander Larsson's avatar
Alexander Larsson committed
951
	GFile *dir;
952

Alexander Larsson's avatar
Alexander Larsson committed
953
	dir = file->details->directory->details->location;
954

Alexander Larsson's avatar
Alexander Larsson committed
955
	if (dir == NULL) {
956 957 958
		return FALSE;
	}

Alexander Larsson's avatar
Alexander Larsson committed
959
	return nautilus_is_desktop_directory_file (dir, eel_ref_str_peek (file->details->name));
960 961
}

962 963 964
static gboolean
is_desktop_file (NautilusFile *file)
{
Alexander Larsson's avatar
Alexander Larsson committed
965
	return nautilus_file_is_mime_type (file, "application/x-desktop");
966 967 968 969 970
}

static gboolean
can_rename_desktop_file (NautilusFile *file)
{
Alexander Larsson's avatar
Alexander Larsson committed
971
	GFile *location;
972 973
	gboolean res;

Alexander Larsson's avatar
Alexander Larsson committed
974 975 976
	location = nautilus_file_get_location (file);
	res = g_file_is_native (location);
	g_object_unref (location);
977 978 979
	return res;
}

980 981 982 983 984 985 986 987 988 989 990 991
/**
 * nautilus_file_can_rename:
 * 
 * Check whether the user is allowed to change the name of the file.
 * 
 * @file: The file to check.
 * 
 * Return value: FALSE if the user is definitely not allowed to change
 * the name of the file. If the user is allowed to change the name, or
 * the code can't tell whether the user is allowed to change the name,
 * returns TRUE (so rename failures must always be handled).
 */
992 993 994
gboolean
nautilus_file_can_rename (NautilusFile *file)
{
995
	gboolean can_rename;
996
	
997 998
	g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);

999 1000 1001 1002 1003
	/* Nonexistent files can't be renamed. */
	if (nautilus_file_is_gone (file)) {
		return FALSE;
	}

1004
	/* Self-owned files can't be renamed */
1005
	if (nautilus_file_is_self_owned (file)) {
1006 1007 1008
		return FALSE;
	}

1009 1010
	if ((is_desktop_file (file) && !can_rename_desktop_file (file)) ||
	     nautilus_file_is_home (file)) {
1011 1012 1013
		return FALSE;
	}
	
1014
	can_rename = TRUE;
1015

1016
	/* Certain types of links can't be renamed */
Alexander Larsson's avatar
Alexander Larsson committed
1017 1018 1019 1020 1021
	if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
		NautilusDesktopLink *link;

		link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));

1022 1023 1024 1025
		if (link != NULL) {
			can_rename = nautilus_desktop_link_can_rename (link);
			g_object_unref (link);
		}
1026
	}
1027 1028 1029

	if (!can_rename) {
		return FALSE;