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