2008-04-30 A. Walton <awalton@gnome.org>
[nautilus.git] / libnautilus-private / nautilus-file.c
blobc19cf06354779e71b514e14629ca46b392a5ab0e
1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
3 nautilus-file.c: Nautilus file model.
5 Copyright (C) 1999, 2000, 2001 Eazel, Inc.
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.
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.
17 You should have received a copy of the GNU General Public
18 License along with this program; if not, write to the
19 Free Software Foundation, Inc., 59 Temple Place - Suite 330,
20 Boston, MA 02111-1307, USA.
22 Author: Darin Adler <darin@bentspoon.com>
25 #include <config.h>
26 #include "nautilus-file.h"
28 #include "nautilus-directory-metafile.h"
29 #include "nautilus-directory-notify.h"
30 #include "nautilus-directory-private.h"
31 #include "nautilus-signaller.h"
32 #include "nautilus-desktop-directory.h"
33 #include "nautilus-desktop-directory-file.h"
34 #include "nautilus-desktop-icon-file.h"
35 #include "nautilus-file-attributes.h"
36 #include "nautilus-file-private.h"
37 #include "nautilus-file-operations.h"
38 #include "nautilus-file-utilities.h"
39 #include "nautilus-global-preferences.h"
40 #include "nautilus-lib-self-check-functions.h"
41 #include "nautilus-link.h"
42 #include "nautilus-metadata.h"
43 #include "nautilus-module.h"
44 #include "nautilus-search-directory.h"
45 #include "nautilus-search-directory-file.h"
46 #include "nautilus-thumbnails.h"
47 #include "nautilus-users-groups-cache.h"
48 #include "nautilus-vfs-file.h"
49 #include "nautilus-saved-search-file.h"
50 #include <eel/eel-debug.h>
51 #include <eel/eel-glib-extensions.h>
52 #include <eel/eel-gtk-extensions.h>
53 #include <eel/eel-vfs-extensions.h>
54 #include <eel/eel-gtk-macros.h>
55 #include <eel/eel-string.h>
56 #include <grp.h>
57 #include <gtk/gtksignal.h>
58 #include <glib/gi18n.h>
59 #include <gio/gio.h>
60 #include <glib/gurifuncs.h>
61 #include <libgnome/gnome-macros.h>
62 #include <glib/gfileutils.h>
63 #include <libnautilus-extension/nautilus-file-info.h>
64 #include <libxml/parser.h>
65 #include <pwd.h>
66 #include <stdlib.h>
67 #include <sys/time.h>
68 #include <time.h>
69 #include <unistd.h>
71 #ifdef HAVE_SELINUX
72 #include <selinux/selinux.h>
73 #endif
75 /* Time in seconds to cache getpwuid results */
76 #define GETPWUID_CACHE_TIME (5*60)
78 #define ICON_NAME_THUMBNAIL_LOADING "image-loading"
80 #undef NAUTILUS_FILE_DEBUG_REF
81 #undef NAUTILUS_FILE_DEBUG_REF_VALGRIND
83 #ifdef NAUTILUS_FILE_DEBUG_REF_VALGRIND
84 #include <valgrind/valgrind.h>
85 #define DEBUG_REF_PRINTF VALGRIND_PRINTF_BACKTRACE
86 #else
87 #define DEBUG_REF_PRINTF printf
88 #endif
90 /* Files that start with these characters sort after files that don't. */
91 #define SORT_LAST_CHAR1 '.'
92 #define SORT_LAST_CHAR2 '#'
94 /* Name to use to tag metadata for the directory itself. */
95 #define FILE_NAME_FOR_DIRECTORY_METADATA "."
97 /* Name of Nautilus trash directories */
98 #define TRASH_DIRECTORY_NAME ".Trash"
100 typedef enum {
101 SHOW_HIDDEN = 1 << 0,
102 SHOW_BACKUP = 1 << 1
103 } FilterOptions;
105 typedef void (* ModifyListFunction) (GList **list, NautilusFile *file);
107 enum {
108 CHANGED,
109 UPDATED_DEEP_COUNT_IN_PROGRESS,
110 LAST_SIGNAL
113 static int date_format_pref;
115 static guint signals[LAST_SIGNAL];
117 static GObjectClass *parent_class = NULL;
119 static GHashTable *symbolic_links;
121 static GQuark attribute_name_q,
122 attribute_size_q,
123 attribute_type_q,
124 attribute_modification_date_q,
125 attribute_date_modified_q,
126 attribute_accessed_date_q,
127 attribute_date_accessed_q,
128 attribute_emblems_q,
129 attribute_mime_type_q,
130 attribute_size_detail_q,
131 attribute_deep_size_q,
132 attribute_deep_file_count_q,
133 attribute_deep_directory_count_q,
134 attribute_deep_total_count_q,
135 attribute_date_changed_q,
136 attribute_date_permissions_q,
137 attribute_permissions_q,
138 attribute_selinux_context_q,
139 attribute_octal_permissions_q,
140 attribute_owner_q,
141 attribute_group_q,
142 attribute_uri_q,
143 attribute_where_q,
144 attribute_link_target_q,
145 attribute_volume_q,
146 attribute_free_space_q;
149 static void nautilus_file_instance_init (NautilusFile *file);
150 static void nautilus_file_class_init (NautilusFileClass *class);
151 static void nautilus_file_info_iface_init (NautilusFileInfoIface *iface);
152 static char * nautilus_file_get_owner_as_string (NautilusFile *file,
153 gboolean include_real_name);
154 static char * nautilus_file_get_type_as_string (NautilusFile *file);
155 static gboolean update_info_and_name (NautilusFile *file,
156 GFileInfo *info);
157 static const char * nautilus_file_peek_display_name (NautilusFile *file);
158 static const char * nautilus_file_peek_display_name_collation_key (NautilusFile *file);
160 GType
161 nautilus_file_get_type (void)
163 static GType type = 0;
165 if (!type) {
166 const GTypeInfo info = {
167 sizeof (NautilusFileClass),
168 NULL,
169 NULL,
170 (GClassInitFunc) nautilus_file_class_init,
171 NULL,
172 NULL,
173 sizeof (NautilusFile),
175 (GInstanceInitFunc) nautilus_file_instance_init,
178 const GInterfaceInfo file_info_iface_info = {
179 (GInterfaceInitFunc) nautilus_file_info_iface_init,
180 NULL,
181 NULL
184 type = g_type_register_static (G_TYPE_OBJECT,
185 "NautilusFile",
186 &info, 0);
187 g_type_add_interface_static (type,
188 NAUTILUS_TYPE_FILE_INFO,
189 &file_info_iface_info);
192 return type;
195 static void
196 nautilus_file_instance_init (NautilusFile *file)
198 file->details = G_TYPE_INSTANCE_GET_PRIVATE ((file), NAUTILUS_TYPE_FILE, NautilusFileDetails);
200 nautilus_file_clear_info (file);
201 nautilus_file_invalidate_extension_info_internal (file);
204 static GObject*
205 nautilus_file_constructor (GType type,
206 guint n_construct_properties,
207 GObjectConstructParam *construct_params)
209 GObject *object;
210 NautilusFile *file;
212 object = (* G_OBJECT_CLASS (parent_class)->constructor) (type,
213 n_construct_properties,
214 construct_params);
216 file = NAUTILUS_FILE (object);
218 /* Set to default type after full construction */
219 if (NAUTILUS_FILE_GET_CLASS (file)->default_file_type != G_FILE_TYPE_UNKNOWN) {
220 file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;
223 return object;
226 gboolean
227 nautilus_file_set_display_name (NautilusFile *file,
228 const char *display_name,
229 const char *edit_name,
230 gboolean custom)
232 gboolean changed;
234 if (display_name == NULL || *display_name == 0) {
235 return FALSE;
238 if (!custom && file->details->got_custom_display_name) {
239 return FALSE;
242 if (custom && display_name == NULL) {
243 /* We're re-setting a custom display name, invalidate it if
244 we already set it so that the old one is re-read */
245 if (file->details->got_custom_display_name) {
246 file->details->got_custom_display_name = FALSE;
247 nautilus_file_invalidate_attributes (file,
248 NAUTILUS_FILE_ATTRIBUTE_INFO);
250 return FALSE;
253 if (edit_name == NULL) {
254 edit_name = display_name;
257 changed = FALSE;
259 if (eel_strcmp (eel_ref_str_peek (file->details->display_name), display_name) != 0) {
260 changed = TRUE;
262 eel_ref_str_unref (file->details->display_name);
264 if (eel_strcmp (eel_ref_str_peek (file->details->name), display_name) == 0) {
265 file->details->display_name = eel_ref_str_ref (file->details->name);
266 } else {
267 file->details->display_name = eel_ref_str_new (display_name);
270 g_free (file->details->display_name_collation_key);
271 file->details->display_name_collation_key = g_utf8_collate_key_for_filename (display_name, -1);
274 if (eel_strcmp (eel_ref_str_peek (file->details->edit_name), edit_name) != 0) {
275 changed = TRUE;
277 eel_ref_str_unref (file->details->edit_name);
278 if (eel_strcmp (eel_ref_str_peek (file->details->display_name), edit_name) == 0) {
279 file->details->edit_name = eel_ref_str_ref (file->details->display_name);
280 } else {
281 file->details->edit_name = eel_ref_str_new (edit_name);
285 file->details->got_custom_display_name = custom;
286 return changed;
289 void
290 nautilus_file_clear_info (NautilusFile *file)
292 file->details->got_file_info = FALSE;
293 if (file->details->get_info_error) {
294 g_error_free (file->details->get_info_error);
295 file->details->get_info_error = NULL;
297 /* Reset to default type, which might be other than unknown for
298 special kinds of files like the desktop or a search directory */
299 file->details->type = NAUTILUS_FILE_GET_CLASS (file)->default_file_type;
301 if (!file->details->got_custom_display_name) {
302 eel_ref_str_unref (file->details->display_name);
303 file->details->display_name = NULL;
304 g_free (file->details->display_name_collation_key);
305 file->details->display_name_collation_key = NULL;
306 eel_ref_str_unref (file->details->edit_name);
307 file->details->edit_name = NULL;
310 if (!file->details->got_custom_activation_location &&
311 file->details->activation_location != NULL) {
312 g_object_unref (file->details->activation_location);
313 file->details->activation_location = NULL;
316 if (file->details->icon != NULL) {
317 g_object_unref (file->details->icon);
318 file->details->icon = NULL;
321 g_free (file->details->thumbnail_path);
322 file->details->thumbnail_path = NULL;
323 file->details->thumbnailing_failed = FALSE;
325 file->details->is_launcher = FALSE;
326 file->details->is_symlink = FALSE;
327 file->details->is_hidden = FALSE;
328 file->details->is_backup = FALSE;
329 file->details->is_mountpoint = FALSE;
330 file->details->uid = -1;
331 file->details->gid = -1;
332 file->details->can_read = TRUE;
333 file->details->can_write = TRUE;
334 file->details->can_execute = TRUE;
335 file->details->can_delete = TRUE;
336 file->details->can_trash = TRUE;
337 file->details->can_rename = TRUE;
338 file->details->can_mount = FALSE;
339 file->details->can_unmount = FALSE;
340 file->details->can_eject = FALSE;
341 file->details->has_permissions = FALSE;
342 file->details->permissions = 0;
343 file->details->size = -1;
344 file->details->sort_order = 0;
345 file->details->mtime = 0;
346 file->details->atime = 0;
347 file->details->ctime = 0;
348 g_free (file->details->symlink_name);
349 file->details->symlink_name = NULL;
350 eel_ref_str_unref (file->details->mime_type);
351 file->details->mime_type = NULL;
352 g_free (file->details->selinux_context);
353 file->details->selinux_context = NULL;
356 static NautilusFile *
357 nautilus_file_new_from_filename (NautilusDirectory *directory,
358 const char *filename,
359 gboolean self_owned)
361 NautilusFile *file;
363 g_assert (NAUTILUS_IS_DIRECTORY (directory));
364 g_assert (filename != NULL);
365 g_assert (filename[0] != '\0');
367 if (NAUTILUS_IS_DESKTOP_DIRECTORY (directory)) {
368 if (self_owned) {
369 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_DESKTOP_DIRECTORY_FILE, NULL));
370 } else {
371 /* This doesn't normally happen, unless the user somehow types in a uri
372 * that references a file like this. (See #349840) */
373 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
375 } else if (NAUTILUS_IS_SEARCH_DIRECTORY (directory)) {
376 if (self_owned) {
377 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SEARCH_DIRECTORY_FILE, NULL));
378 } else {
379 /* This doesn't normally happen, unless the user somehow types in a uri
380 * that references a file like this. (See #349840) */
381 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
383 } else if (g_str_has_suffix (filename, NAUTILUS_SAVED_SEARCH_EXTENSION)) {
384 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
385 } else {
386 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
389 file->details->directory = nautilus_directory_ref (directory);
391 file->details->name = eel_ref_str_new (filename);
393 #ifdef NAUTILUS_FILE_DEBUG_REF
394 DEBUG_REF_PRINTF("%10p ref'd", file);
395 #endif
397 return file;
400 static void
401 modify_link_hash_table (NautilusFile *file,
402 ModifyListFunction modify_function)
404 char *target_uri;
405 gboolean found;
406 gpointer original_key;
407 GList **list_ptr;
409 /* Check if there is a symlink name. If none, we are OK. */
410 if (file->details->symlink_name == NULL) {
411 return;
414 /* Create the hash table first time through. */
415 if (symbolic_links == NULL) {
416 symbolic_links = eel_g_hash_table_new_free_at_exit
417 (g_str_hash, g_str_equal, "nautilus-file.c: symbolic_links");
420 target_uri = nautilus_file_get_symbolic_link_target_uri (file);
422 /* Find the old contents of the hash table. */
423 found = g_hash_table_lookup_extended
424 (symbolic_links, target_uri,
425 &original_key, (gpointer *)&list_ptr);
426 if (!found) {
427 list_ptr = g_new0 (GList *, 1);
428 original_key = g_strdup (target_uri);
429 g_hash_table_insert (symbolic_links, original_key, list_ptr);
431 (* modify_function) (list_ptr, file);
432 if (*list_ptr == NULL) {
433 g_hash_table_remove (symbolic_links, target_uri);
434 g_free (list_ptr);
435 g_free (original_key);
437 g_free (target_uri);
440 static void
441 symbolic_link_weak_notify (gpointer data,
442 GObject *where_the_object_was)
444 GList **list = data;
445 /* This really shouldn't happen, but we're seeing some strange things in
446 bug #358172 where the symlink hashtable isn't correctly updated. */
447 *list = g_list_remove (*list, where_the_object_was);
450 static void
451 add_to_link_hash_table_list (GList **list, NautilusFile *file)
453 if (g_list_find (*list, file) != NULL) {
454 g_warning ("Adding file to symlink_table multiple times. "
455 "Please add feedback of what you were doing at http://bugzilla.gnome.org/show_bug.cgi?id=358172\n");
456 return;
458 g_object_weak_ref (G_OBJECT (file), symbolic_link_weak_notify, list);
459 *list = g_list_prepend (*list, file);
462 static void
463 add_to_link_hash_table (NautilusFile *file)
465 modify_link_hash_table (file, add_to_link_hash_table_list);
468 static void
469 remove_from_link_hash_table_list (GList **list, NautilusFile *file)
471 if (g_list_find (*list, file) != NULL) {
472 g_object_weak_unref (G_OBJECT (file), symbolic_link_weak_notify, list);
473 *list = g_list_remove (*list, file);
477 static void
478 remove_from_link_hash_table (NautilusFile *file)
480 modify_link_hash_table (file, remove_from_link_hash_table_list);
483 NautilusFile *
484 nautilus_file_new_from_info (NautilusDirectory *directory,
485 GFileInfo *info)
487 NautilusFile *file;
488 const char *mime_type;
490 g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (directory), NULL);
491 g_return_val_if_fail (info != NULL, NULL);
493 mime_type = g_file_info_get_content_type (info);
494 if (mime_type &&
495 strcmp (mime_type, NAUTILUS_SAVED_SEARCH_MIMETYPE) == 0) {
496 g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
497 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_SAVED_SEARCH_FILE, NULL));
498 } else {
499 file = NAUTILUS_FILE (g_object_new (NAUTILUS_TYPE_VFS_FILE, NULL));
502 file->details->directory = nautilus_directory_ref (directory);
504 update_info_and_name (file, info);
506 #ifdef NAUTILUS_FILE_DEBUG_REF
507 DEBUG_REF_PRINTF("%10p ref'd", file);
508 #endif
510 return file;
513 static NautilusFile *
514 nautilus_file_get_internal (GFile *location, gboolean create)
516 gboolean self_owned;
517 NautilusDirectory *directory;
518 NautilusFile *file;
519 GFile *parent;
520 char *basename;
522 g_assert (location != NULL);
524 parent = g_file_get_parent (location);
526 self_owned = FALSE;
527 if (parent == NULL) {
528 self_owned = TRUE;
529 parent = g_object_ref (location);
532 /* Get object that represents the directory. */
533 directory = nautilus_directory_get_internal (parent, create);
535 g_object_unref (parent);
537 /* Get the name for the file. */
538 if (self_owned && directory != NULL) {
539 basename = nautilus_directory_get_name_for_self_as_new_file (directory);
540 } else {
541 basename = g_file_get_basename (location);
543 /* Check to see if it's a file that's already known. */
544 if (directory == NULL) {
545 file = NULL;
546 } else if (self_owned) {
547 file = directory->details->as_file;
548 } else {
549 file = nautilus_directory_find_file_by_name (directory, basename);
552 /* Ref or create the file. */
553 if (file != NULL) {
554 nautilus_file_ref (file);
555 } else if (create) {
556 file = nautilus_file_new_from_filename (directory, basename, self_owned);
557 if (self_owned) {
558 g_assert (directory->details->as_file == NULL);
559 directory->details->as_file = file;
560 } else {
561 nautilus_directory_add_file (directory, file);
565 g_free (basename);
566 nautilus_directory_unref (directory);
568 return file;
571 NautilusFile *
572 nautilus_file_get (GFile *location)
574 return nautilus_file_get_internal (location, TRUE);
577 NautilusFile *
578 nautilus_file_get_existing (GFile *location)
580 return nautilus_file_get_internal (location, FALSE);
583 NautilusFile *
584 nautilus_file_get_existing_by_uri (const char *uri)
586 GFile *location;
587 NautilusFile *file;
589 location = g_file_new_for_uri (uri);
590 file = nautilus_file_get_internal (location, FALSE);
591 g_object_unref (location);
593 return file;
596 NautilusFile *
597 nautilus_file_get_by_uri (const char *uri)
599 GFile *location;
600 NautilusFile *file;
602 location = g_file_new_for_uri (uri);
603 file = nautilus_file_get_internal (location, TRUE);
604 g_object_unref (location);
606 return file;
609 gboolean
610 nautilus_file_is_self_owned (NautilusFile *file)
612 return file->details->directory->details->as_file == file;
615 static void
616 finalize (GObject *object)
618 NautilusDirectory *directory;
619 NautilusFile *file;
620 char *uri;
622 file = NAUTILUS_FILE (object);
624 g_assert (file->details->operations_in_progress == NULL);
626 if (file->details->is_thumbnailing) {
627 uri = nautilus_file_get_uri (file);
628 nautilus_thumbnail_remove_from_queue (uri);
629 g_free (uri);
632 nautilus_async_destroying_file (file);
634 remove_from_link_hash_table (file);
636 directory = file->details->directory;
638 if (nautilus_file_is_self_owned (file)) {
639 directory->details->as_file = NULL;
640 } else {
641 if (!file->details->is_gone) {
642 nautilus_directory_remove_file (directory, file);
646 if (file->details->get_info_error) {
647 g_error_free (file->details->get_info_error);
650 nautilus_directory_unref (directory);
651 eel_ref_str_unref (file->details->name);
652 eel_ref_str_unref (file->details->display_name);
653 g_free (file->details->display_name_collation_key);
654 eel_ref_str_unref (file->details->edit_name);
655 if (file->details->icon) {
656 g_object_unref (file->details->icon);
658 g_free (file->details->thumbnail_path);
659 g_free (file->details->symlink_name);
660 eel_ref_str_unref (file->details->mime_type);
661 g_free (file->details->selinux_context);
662 g_free (file->details->top_left_text);
663 g_free (file->details->custom_icon);
664 if (file->details->activation_location) {
665 g_object_unref (file->details->activation_location);
667 g_free (file->details->compare_by_emblem_cache);
669 if (file->details->thumbnail) {
670 g_object_unref (file->details->thumbnail);
672 if (file->details->mount) {
673 g_object_unref (file->details->mount);
676 eel_g_list_free_deep (file->details->mime_list);
678 eel_g_list_free_deep (file->details->pending_extension_emblems);
679 eel_g_list_free_deep (file->details->extension_emblems);
681 if (file->details->pending_extension_attributes) {
682 g_hash_table_destroy (file->details->pending_extension_attributes);
685 if (file->details->extension_attributes) {
686 g_hash_table_destroy (file->details->extension_attributes);
689 G_OBJECT_CLASS (parent_class)->finalize (object);
692 NautilusFile *
693 nautilus_file_ref (NautilusFile *file)
695 if (file == NULL) {
696 return NULL;
698 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
700 #ifdef NAUTILUS_FILE_DEBUG_REF
701 DEBUG_REF_PRINTF("%10p ref'd", file);
702 #endif
704 return g_object_ref (file);
707 void
708 nautilus_file_unref (NautilusFile *file)
710 if (file == NULL) {
711 return;
714 g_return_if_fail (NAUTILUS_IS_FILE (file));
716 #ifdef NAUTILUS_FILE_DEBUG_REF
717 DEBUG_REF_PRINTF("%10p unref'd", file);
718 #endif
720 g_object_unref (file);
724 * nautilus_file_get_parent_uri_for_display:
726 * Get the uri for the parent directory.
728 * @file: The file in question.
730 * Return value: A string representing the parent's location,
731 * formatted for user display (including stripping "file://").
732 * If the parent is NULL, returns the empty string.
734 char *
735 nautilus_file_get_parent_uri_for_display (NautilusFile *file)
737 GFile *parent;
738 char *result;
740 g_assert (NAUTILUS_IS_FILE (file));
742 parent = nautilus_file_get_parent_location (file);
743 if (parent) {
744 result = g_file_get_parse_name (parent);
745 g_object_unref (parent);
746 } else {
747 result = g_strdup ("");
750 return result;
754 * nautilus_file_get_parent_uri:
756 * Get the uri for the parent directory.
758 * @file: The file in question.
760 * Return value: A string for the parent's location, in "raw URI" form.
761 * Use nautilus_file_get_parent_uri_for_display instead if the
762 * result is to be displayed on-screen.
763 * If the parent is NULL, returns the empty string.
765 char *
766 nautilus_file_get_parent_uri (NautilusFile *file)
768 g_assert (NAUTILUS_IS_FILE (file));
770 if (nautilus_file_is_self_owned (file)) {
771 /* Callers expect an empty string, not a NULL. */
772 return g_strdup ("");
775 return nautilus_directory_get_uri (file->details->directory);
778 GFile *
779 nautilus_file_get_parent_location (NautilusFile *file)
781 g_assert (NAUTILUS_IS_FILE (file));
783 if (nautilus_file_is_self_owned (file)) {
784 /* Callers expect an empty string, not a NULL. */
785 return NULL;
788 return nautilus_directory_get_location (file->details->directory);
791 NautilusFile *
792 nautilus_file_get_parent (NautilusFile *file)
794 g_assert (NAUTILUS_IS_FILE (file));
796 if (nautilus_file_is_self_owned (file)) {
797 return NULL;
800 return nautilus_directory_get_corresponding_file (file->details->directory);
804 * nautilus_file_can_read:
806 * Check whether the user is allowed to read the contents of this file.
808 * @file: The file to check.
810 * Return value: FALSE if the user is definitely not allowed to read
811 * the contents of the file. If the user has read permission, or
812 * the code can't tell whether the user has read permission,
813 * returns TRUE (so failures must always be handled).
815 gboolean
816 nautilus_file_can_read (NautilusFile *file)
818 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
820 return file->details->can_read;
824 * nautilus_file_can_write:
826 * Check whether the user is allowed to write to this file.
828 * @file: The file to check.
830 * Return value: FALSE if the user is definitely not allowed to write
831 * to the file. If the user has write permission, or
832 * the code can't tell whether the user has write permission,
833 * returns TRUE (so failures must always be handled).
835 gboolean
836 nautilus_file_can_write (NautilusFile *file)
838 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
840 return file->details->can_write;
844 * nautilus_file_can_execute:
846 * Check whether the user is allowed to execute this file.
848 * @file: The file to check.
850 * Return value: FALSE if the user is definitely not allowed to execute
851 * the file. If the user has execute permission, or
852 * the code can't tell whether the user has execute permission,
853 * returns TRUE (so failures must always be handled).
855 gboolean
856 nautilus_file_can_execute (NautilusFile *file)
858 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
860 return file->details->can_execute;
863 gboolean
864 nautilus_file_can_mount (NautilusFile *file)
866 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
868 return file->details->can_mount;
871 gboolean
872 nautilus_file_can_unmount (NautilusFile *file)
874 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
876 return file->details->can_unmount ||
877 (file->details->mount != NULL &&
878 g_mount_can_unmount (file->details->mount));
881 gboolean
882 nautilus_file_can_eject (NautilusFile *file)
884 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
886 return file->details->can_eject ||
887 (file->details->mount != NULL &&
888 g_mount_can_eject (file->details->mount));
891 void
892 nautilus_file_mount (NautilusFile *file,
893 GMountOperation *mount_op,
894 GCancellable *cancellable,
895 NautilusFileOperationCallback callback,
896 gpointer callback_data)
898 GError *error;
900 if (NAUTILUS_FILE_GET_CLASS (file)->mount == NULL) {
901 if (callback) {
902 error = NULL;
903 g_set_error (&error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
904 _("This file cannot be mounted"));
905 callback (file, NULL, error, callback_data);
906 g_error_free (error);
908 } else {
909 NAUTILUS_FILE_GET_CLASS (file)->mount (file, mount_op, cancellable, callback, callback_data);
913 void
914 nautilus_file_unmount (NautilusFile *file)
916 if (file->details->can_unmount) {
917 if (NAUTILUS_FILE_GET_CLASS (file)->unmount != NULL) {
918 NAUTILUS_FILE_GET_CLASS (file)->unmount (file);
920 } else if (file->details->mount != NULL &&
921 g_mount_can_unmount (file->details->mount)) {
922 nautilus_file_operations_unmount_mount (NULL, file->details->mount, FALSE, TRUE);
926 void
927 nautilus_file_eject (NautilusFile *file)
929 if (file->details->can_eject) {
930 if (NAUTILUS_FILE_GET_CLASS (file)->eject != NULL) {
931 NAUTILUS_FILE_GET_CLASS (file)->eject (file);
933 } else if (file->details->mount != NULL &&
934 g_mount_can_eject (file->details->mount)) {
935 nautilus_file_operations_unmount_mount (NULL, file->details->mount, TRUE, TRUE);
940 * nautilus_file_is_desktop_directory:
942 * Check whether this file is the desktop directory.
944 * @file: The file to check.
946 * Return value: TRUE if this is the physical desktop directory.
948 gboolean
949 nautilus_file_is_desktop_directory (NautilusFile *file)
951 GFile *dir;
953 dir = file->details->directory->details->location;
955 if (dir == NULL) {
956 return FALSE;
959 return nautilus_is_desktop_directory_file (dir, eel_ref_str_peek (file->details->name));
962 static gboolean
963 is_desktop_file (NautilusFile *file)
965 return nautilus_file_is_mime_type (file, "application/x-desktop");
968 static gboolean
969 can_rename_desktop_file (NautilusFile *file)
971 GFile *location;
972 gboolean res;
974 location = nautilus_file_get_location (file);
975 res = g_file_is_native (location);
976 g_object_unref (location);
977 return res;
981 * nautilus_file_can_rename:
983 * Check whether the user is allowed to change the name of the file.
985 * @file: The file to check.
987 * Return value: FALSE if the user is definitely not allowed to change
988 * the name of the file. If the user is allowed to change the name, or
989 * the code can't tell whether the user is allowed to change the name,
990 * returns TRUE (so rename failures must always be handled).
992 gboolean
993 nautilus_file_can_rename (NautilusFile *file)
995 gboolean can_rename;
997 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
999 /* Nonexistent files can't be renamed. */
1000 if (nautilus_file_is_gone (file)) {
1001 return FALSE;
1004 /* Self-owned files can't be renamed */
1005 if (nautilus_file_is_self_owned (file)) {
1006 return FALSE;
1009 if ((is_desktop_file (file) && !can_rename_desktop_file (file)) ||
1010 nautilus_file_is_home (file)) {
1011 return FALSE;
1014 can_rename = TRUE;
1016 /* Certain types of links can't be renamed */
1017 if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
1018 NautilusDesktopLink *link;
1020 link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
1022 if (link != NULL) {
1023 can_rename = nautilus_desktop_link_can_rename (link);
1024 g_object_unref (link);
1028 if (!can_rename) {
1029 return FALSE;
1032 return file->details->can_rename;
1035 gboolean
1036 nautilus_file_can_delete (NautilusFile *file)
1038 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1040 /* Nonexistent files can't be deleted. */
1041 if (nautilus_file_is_gone (file)) {
1042 return FALSE;
1045 /* Self-owned files can't be deleted */
1046 if (nautilus_file_is_self_owned (file)) {
1047 return FALSE;
1050 return file->details->can_delete;
1053 gboolean
1054 nautilus_file_can_trash (NautilusFile *file)
1056 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1058 /* Nonexistent files can't be deleted. */
1059 if (nautilus_file_is_gone (file)) {
1060 return FALSE;
1063 /* Self-owned files can't be deleted */
1064 if (nautilus_file_is_self_owned (file)) {
1065 return FALSE;
1068 return file->details->can_trash;
1071 GFile *
1072 nautilus_file_get_location (NautilusFile *file)
1074 GFile *dir;
1076 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1078 dir = file->details->directory->details->location;
1080 if (nautilus_file_is_self_owned (file)) {
1081 return g_object_ref (dir);
1084 return g_file_get_child (dir, eel_ref_str_peek (file->details->name));
1087 /* Return the actual uri associated with the passed-in file. */
1088 char *
1089 nautilus_file_get_uri (NautilusFile *file)
1091 char *uri;
1092 GFile *loc;
1094 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1096 loc = nautilus_file_get_location (file);
1097 uri = g_file_get_uri (loc);
1098 g_object_unref (loc);
1100 return uri;
1103 char *
1104 nautilus_file_get_uri_scheme (NautilusFile *file)
1106 GFile *loc;
1107 char *scheme;
1109 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
1111 if (file->details->directory == NULL ||
1112 file->details->directory->details->location == NULL) {
1113 return NULL;
1116 loc = nautilus_directory_get_location (file->details->directory);
1117 scheme = g_file_get_uri_scheme (loc);
1118 g_object_unref (loc);
1120 return scheme;
1123 NautilusFileOperation *
1124 nautilus_file_operation_new (NautilusFile *file,
1125 NautilusFileOperationCallback callback,
1126 gpointer callback_data)
1128 NautilusFileOperation *op;
1130 op = g_new0 (NautilusFileOperation, 1);
1131 op->file = nautilus_file_ref (file);
1132 op->callback = callback;
1133 op->callback_data = callback_data;
1134 op->cancellable = g_cancellable_new ();
1136 op->file->details->operations_in_progress = g_list_prepend
1137 (op->file->details->operations_in_progress, op);
1139 return op;
1142 static void
1143 nautilus_file_operation_remove (NautilusFileOperation *op)
1145 op->file->details->operations_in_progress = g_list_remove
1146 (op->file->details->operations_in_progress, op);
1149 void
1150 nautilus_file_operation_free (NautilusFileOperation *op)
1152 nautilus_file_operation_remove (op);
1153 nautilus_file_unref (op->file);
1154 g_object_unref (op->cancellable);
1155 if (op->free_data) {
1156 op->free_data (op->data);
1158 g_free (op);
1161 void
1162 nautilus_file_operation_complete (NautilusFileOperation *op, GFile *result_file, GError *error)
1164 /* Claim that something changed even if the operation failed.
1165 * This makes it easier for some clients who see the "reverting"
1166 * as "changing back".
1168 nautilus_file_operation_remove (op);
1169 nautilus_file_changed (op->file);
1170 if (op->callback) {
1171 (* op->callback) (op->file, result_file, error, op->callback_data);
1173 nautilus_file_operation_free (op);
1176 void
1177 nautilus_file_operation_cancel (NautilusFileOperation *op)
1179 /* Cancel the operation if it's still in progress. */
1180 g_cancellable_cancel (op->cancellable);
1183 static void
1184 rename_get_info_callback (GObject *source_object,
1185 GAsyncResult *res,
1186 gpointer callback_data)
1188 NautilusFileOperation *op;
1189 NautilusDirectory *directory;
1190 NautilusFile *existing_file;
1191 char *old_name;
1192 char *old_uri;
1193 char *new_uri;
1194 const char *new_name;
1195 GFileInfo *new_info;
1196 GError *error;
1198 op = callback_data;
1200 error = NULL;
1201 new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
1202 if (new_info != NULL) {
1203 directory = op->file->details->directory;
1205 new_name = g_file_info_get_name (new_info);
1207 /* If there was another file by the same name in this
1208 * directory, mark it gone.
1210 existing_file = nautilus_directory_find_file_by_name (directory, new_name);
1211 if (existing_file != NULL) {
1212 nautilus_file_mark_gone (existing_file);
1213 nautilus_file_changed (existing_file);
1216 old_uri = nautilus_file_get_uri (op->file);
1217 old_name = g_strdup (eel_ref_str_peek (op->file->details->name));
1219 update_info_and_name (op->file, new_info);
1221 /* Self-owned files store their metadata under the
1222 * hard-code name "." so there's no need to rename
1223 * their metadata when they are renamed.
1225 if (!nautilus_file_is_self_owned (op->file)) {
1226 nautilus_directory_rename_file_metadata
1227 (directory, old_name, eel_ref_str_peek (op->file->details->name));
1230 g_free (old_name);
1232 new_uri = nautilus_file_get_uri (op->file);
1233 nautilus_directory_moved (old_uri, new_uri);
1234 g_free (new_uri);
1235 g_free (old_uri);
1237 /* the rename could have affected the display name if e.g.
1238 * we're in a vfolder where the name comes from a desktop file
1239 * and a rename affects the contents of the desktop file.
1241 if (op->file->details->got_custom_display_name) {
1242 nautilus_file_invalidate_attributes (op->file,
1243 NAUTILUS_FILE_ATTRIBUTE_INFO |
1244 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
1247 g_object_unref (new_info);
1249 nautilus_file_operation_complete (op, NULL, error);
1250 if (error) {
1251 g_error_free (error);
1255 static void
1256 rename_callback (GObject *source_object,
1257 GAsyncResult *res,
1258 gpointer callback_data)
1260 NautilusFileOperation *op;
1261 GFile *new_file;
1262 GError *error;
1264 op = callback_data;
1266 error = NULL;
1267 new_file = g_file_set_display_name_finish (G_FILE (source_object),
1268 res, &error);
1270 if (new_file != NULL) {
1271 g_file_query_info_async (new_file,
1272 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
1274 G_PRIORITY_DEFAULT,
1275 op->cancellable,
1276 rename_get_info_callback, op);
1277 } else {
1278 nautilus_file_operation_complete (op, NULL, error);
1279 g_error_free (error);
1283 static gboolean
1284 name_is (NautilusFile *file, const char *new_name)
1286 const char *old_name;
1287 old_name = eel_ref_str_peek (file->details->name);
1288 return strcmp (new_name, old_name) == 0;
1291 void
1292 nautilus_file_rename (NautilusFile *file,
1293 const char *new_name,
1294 NautilusFileOperationCallback callback,
1295 gpointer callback_data)
1297 NautilusFileOperation *op;
1298 char *uri;
1299 char *old_name;
1300 gboolean success;
1301 gboolean is_renameable_desktop_file;
1302 GFile *location;
1303 GError *error;
1305 g_return_if_fail (NAUTILUS_IS_FILE (file));
1306 g_return_if_fail (new_name != NULL);
1307 g_return_if_fail (callback != NULL);
1309 is_renameable_desktop_file =
1310 is_desktop_file (file) && can_rename_desktop_file (file);
1312 /* Return an error for incoming names containing path separators.
1313 * But not for .desktop files as '/' are allowed for them */
1314 if (strstr (new_name, "/") != NULL && !is_renameable_desktop_file) {
1315 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
1316 _("Slashes are not allowed in filenames"));
1317 (* callback) (file, NULL, error, callback_data);
1318 g_error_free (error);
1319 return;
1322 /* Can't rename a file that's already gone.
1323 * We need to check this here because there may be a new
1324 * file with the same name.
1326 if (nautilus_file_is_gone (file)) {
1327 /* Claim that something changed even if the rename
1328 * failed. This makes it easier for some clients who
1329 * see the "reverting" to the old name as "changing
1330 * back".
1332 nautilus_file_changed (file);
1333 error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
1334 _("File not found"));
1335 (* callback) (file, NULL, error, callback_data);
1336 g_error_free (error);
1337 return;
1340 /* Test the name-hasn't-changed case explicitly, for two reasons.
1341 * (1) rename returns an error if new & old are same.
1342 * (2) We don't want to send file-changed signal if nothing changed.
1344 if (name_is (file, new_name)) {
1345 (* callback) (file, NULL, NULL, callback_data);
1346 return;
1349 /* Self-owned files can't be renamed. Test the name-not-actually-changing
1350 * case before this case.
1352 if (nautilus_file_is_self_owned (file)) {
1353 /* Claim that something changed even if the rename
1354 * failed. This makes it easier for some clients who
1355 * see the "reverting" to the old name as "changing
1356 * back".
1358 nautilus_file_changed (file);
1359 error = g_error_new (G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
1360 _("Toplevel files cannot be renamed"));
1362 (* callback) (file, NULL, error, callback_data);
1363 g_error_free (error);
1364 return;
1367 if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
1368 NautilusDesktopLink *link;
1370 link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
1372 if (link != NULL &&
1373 nautilus_desktop_link_rename (link, new_name)) {
1374 (* callback) (file, NULL, NULL, callback_data);
1375 } else {
1376 error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1377 _("Unable to rename desktop icon"));
1378 (* callback) (file, NULL, error, callback_data);
1379 g_error_free (error);
1382 g_object_unref (link);
1383 return;
1386 if (is_renameable_desktop_file) {
1387 /* Don't actually change the name if the new name is the same.
1388 * This helps for the vfolder method where this can happen and
1389 * we want to minimize actual changes
1391 uri = nautilus_file_get_uri (file);
1392 old_name = nautilus_link_local_get_text (uri);
1393 if (old_name != NULL && strcmp (new_name, old_name) == 0) {
1394 success = TRUE;
1395 } else {
1396 success = nautilus_link_local_set_text (uri, new_name);
1398 g_free (old_name);
1399 g_free (uri);
1401 if (success) {
1402 nautilus_file_invalidate_attributes (file,
1403 NAUTILUS_FILE_ATTRIBUTE_INFO |
1404 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO);
1405 (* callback) (file, NULL, NULL, callback_data);
1406 return;
1407 } else {
1408 error = g_error_new (G_IO_ERROR, G_IO_ERROR_FAILED,
1409 _("Unable to rename desktop file"));
1410 (* callback) (file, NULL, error, callback_data);
1411 g_error_free (error);
1412 return;
1416 /* Set up a renaming operation. */
1417 op = nautilus_file_operation_new (file, callback, callback_data);
1418 op->is_rename = TRUE;
1420 /* Do the renaming. */
1422 location = nautilus_file_get_location (file);
1423 g_file_set_display_name_async (location,
1424 new_name,
1425 G_PRIORITY_DEFAULT,
1426 op->cancellable,
1427 rename_callback,
1428 op);
1429 g_object_unref (location);
1432 gboolean
1433 nautilus_file_rename_in_progress (NautilusFile *file)
1435 GList *node;
1436 NautilusFileOperation *op;
1438 for (node = file->details->operations_in_progress; node != NULL; node = node->next) {
1439 op = node->data;
1440 if (op->is_rename) {
1441 return TRUE;
1444 return FALSE;
1447 void
1448 nautilus_file_cancel (NautilusFile *file,
1449 NautilusFileOperationCallback callback,
1450 gpointer callback_data)
1452 GList *node, *next;
1453 NautilusFileOperation *op;
1455 for (node = file->details->operations_in_progress; node != NULL; node = next) {
1456 next = node->next;
1457 op = node->data;
1459 g_assert (op->file == file);
1460 if (op->callback == callback && op->callback_data == callback_data) {
1461 nautilus_file_operation_cancel (op);
1466 gboolean
1467 nautilus_file_matches_uri (NautilusFile *file, const char *match_uri)
1469 GFile *match_file, *location;
1470 gboolean result;
1472 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1473 g_return_val_if_fail (match_uri != NULL, FALSE);
1475 location = nautilus_file_get_location (file);
1476 match_file = g_file_new_for_uri (match_uri);
1477 result = g_file_equal (location, match_file);
1478 g_object_unref (location);
1479 g_object_unref (match_file);
1481 return result;
1484 gboolean
1485 nautilus_file_is_local (NautilusFile *file)
1487 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1489 return nautilus_directory_is_local (file->details->directory);
1492 static void
1493 update_link (NautilusFile *link_file, NautilusFile *target_file)
1495 g_assert (NAUTILUS_IS_FILE (link_file));
1496 g_assert (NAUTILUS_IS_FILE (target_file));
1498 /* FIXME bugzilla.gnome.org 42044: If we don't put any code
1499 * here then the hash table is a waste of time.
1503 static GList *
1504 get_link_files (NautilusFile *target_file)
1506 char *uri;
1507 GList **link_files;
1509 if (symbolic_links == NULL) {
1510 link_files = NULL;
1511 } else {
1512 uri = nautilus_file_get_uri (target_file);
1513 link_files = g_hash_table_lookup (symbolic_links, uri);
1514 g_free (uri);
1516 if (link_files) {
1517 return nautilus_file_list_copy (*link_files);
1519 return NULL;
1522 static void
1523 update_links_if_target (NautilusFile *target_file)
1525 GList *link_files, *p;
1527 link_files = get_link_files (target_file);
1528 for (p = link_files; p != NULL; p = p->next) {
1529 update_link (NAUTILUS_FILE (p->data), target_file);
1531 nautilus_file_list_free (link_files);
1534 static gboolean
1535 update_info_internal (NautilusFile *file,
1536 GFileInfo *info,
1537 gboolean update_name)
1539 GList *node;
1540 gboolean changed;
1541 gboolean is_symlink, is_hidden, is_backup, is_mountpoint;
1542 gboolean has_permissions;
1543 guint32 permissions;
1544 gboolean can_read, can_write, can_execute, can_delete, can_trash, can_rename, can_mount, can_unmount, can_eject;
1545 gboolean thumbnailing_failed;
1546 int uid, gid;
1547 goffset size;
1548 int sort_order;
1549 time_t atime, mtime, ctime;
1550 const char *symlink_name, *mime_type, *selinux_context, *name, *thumbnail_path;
1551 GFileType file_type;
1552 GIcon *icon;
1553 GFile *old_activation_location;
1554 const char *activation_uri;
1555 const char *description;
1557 if (file->details->is_gone) {
1558 return FALSE;
1561 if (info == NULL) {
1562 nautilus_file_mark_gone (file);
1563 return TRUE;
1566 file->details->file_info_is_up_to_date = TRUE;
1568 /* FIXME bugzilla.gnome.org 42044: Need to let links that
1569 * point to the old name know that the file has been renamed.
1572 remove_from_link_hash_table (file);
1574 changed = FALSE;
1576 if (!file->details->got_file_info) {
1577 changed = TRUE;
1579 file->details->got_file_info = TRUE;
1581 changed |= nautilus_file_set_display_name (file,
1582 g_file_info_get_display_name (info),
1583 g_file_info_get_edit_name (info),
1584 FALSE);
1586 file_type = g_file_info_get_file_type (info);
1587 if (file->details->type != file_type) {
1588 changed = TRUE;
1590 file->details->type = file_type;
1592 if (!file->details->got_custom_activation_location) {
1593 activation_uri = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_TARGET_URI);
1594 if (activation_uri == NULL) {
1595 if (file->details->activation_location) {
1596 g_object_unref (file->details->activation_location);
1597 file->details->activation_location = NULL;
1598 changed = TRUE;
1600 } else {
1601 old_activation_location = file->details->activation_location;
1602 file->details->activation_location = g_file_new_for_uri (activation_uri);
1604 if (old_activation_location) {
1605 if (!g_file_equal (old_activation_location,
1606 file->details->activation_location)) {
1607 changed = TRUE;
1609 g_object_unref (old_activation_location);
1610 } else {
1611 changed = TRUE;
1616 is_symlink = g_file_info_get_is_symlink (info);
1617 if (file->details->is_symlink != is_symlink) {
1618 changed = TRUE;
1620 file->details->is_symlink = is_symlink;
1622 is_hidden = g_file_info_get_is_hidden (info);
1623 if (file->details->is_hidden != is_hidden) {
1624 changed = TRUE;
1626 file->details->is_hidden = is_hidden;
1628 is_backup = g_file_info_get_is_backup (info);
1629 if (file->details->is_backup != is_backup) {
1630 changed = TRUE;
1632 file->details->is_backup = is_backup;
1634 is_mountpoint = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_UNIX_IS_MOUNTPOINT);
1635 if (file->details->is_mountpoint != is_mountpoint) {
1636 changed = TRUE;
1638 file->details->is_mountpoint = is_mountpoint;
1640 has_permissions = g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_MODE);
1641 permissions = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE);;
1642 if (file->details->has_permissions != has_permissions ||
1643 file->details->permissions != permissions) {
1644 changed = TRUE;
1646 file->details->has_permissions = has_permissions;
1647 file->details->permissions = permissions;
1649 /* We default to TRUE for this if we can't know */
1650 can_read = TRUE;
1651 can_write = TRUE;
1652 can_execute = TRUE;
1653 can_delete = TRUE;
1654 can_trash = TRUE;
1655 can_rename = TRUE;
1656 can_mount = FALSE;
1657 can_unmount = FALSE;
1658 can_eject = FALSE;
1659 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_READ)) {
1660 can_read = g_file_info_get_attribute_boolean (info,
1661 G_FILE_ATTRIBUTE_ACCESS_CAN_READ);
1663 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE)) {
1664 can_write = g_file_info_get_attribute_boolean (info,
1665 G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE);
1667 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE)) {
1668 can_execute = g_file_info_get_attribute_boolean (info,
1669 G_FILE_ATTRIBUTE_ACCESS_CAN_EXECUTE);
1671 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE)) {
1672 can_delete = g_file_info_get_attribute_boolean (info,
1673 G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE);
1675 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH)) {
1676 can_trash = g_file_info_get_attribute_boolean (info,
1677 G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH);
1679 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME)) {
1680 can_rename = g_file_info_get_attribute_boolean (info,
1681 G_FILE_ATTRIBUTE_ACCESS_CAN_RENAME);
1683 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT)) {
1684 can_mount = g_file_info_get_attribute_boolean (info,
1685 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_MOUNT);
1687 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT)) {
1688 can_unmount = g_file_info_get_attribute_boolean (info,
1689 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_UNMOUNT);
1691 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT)) {
1692 can_eject = g_file_info_get_attribute_boolean (info,
1693 G_FILE_ATTRIBUTE_MOUNTABLE_CAN_EJECT);
1695 if (file->details->can_read != can_read ||
1696 file->details->can_write != can_write ||
1697 file->details->can_execute != can_execute ||
1698 file->details->can_delete != can_delete ||
1699 file->details->can_trash != can_trash ||
1700 file->details->can_rename != can_rename ||
1701 file->details->can_mount != can_mount ||
1702 file->details->can_unmount != can_unmount ||
1703 file->details->can_eject != can_eject) {
1704 changed = TRUE;
1707 file->details->can_read = can_read;
1708 file->details->can_write = can_write;
1709 file->details->can_execute = can_execute;
1710 file->details->can_delete = can_delete;
1711 file->details->can_trash = can_trash;
1712 file->details->can_rename = can_rename;
1713 file->details->can_mount = can_mount;
1714 file->details->can_unmount = can_unmount;
1715 file->details->can_eject = can_eject;
1717 uid = -1;
1718 gid = -1;
1719 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_UID)) {
1720 uid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID);
1722 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_UNIX_GID)) {
1723 gid = g_file_info_get_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID);
1725 if (file->details->uid != uid ||
1726 file->details->gid != gid) {
1727 changed = TRUE;
1729 file->details->uid = uid;
1730 file->details->gid = gid;
1732 size = -1;
1733 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_STANDARD_SIZE)) {
1734 size = g_file_info_get_size (info);
1736 if (file->details->size != size) {
1737 changed = TRUE;
1739 file->details->size = size;
1741 sort_order = g_file_info_get_sort_order (info);
1742 if (file->details->sort_order != sort_order) {
1743 changed = TRUE;
1745 file->details->sort_order = sort_order;
1747 atime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_ACCESS);
1748 ctime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_CHANGED);
1749 mtime = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_TIME_MODIFIED);
1750 if (file->details->atime != atime ||
1751 file->details->mtime != mtime ||
1752 file->details->ctime != ctime) {
1753 changed = TRUE;
1755 file->details->atime = atime;
1756 file->details->ctime = ctime;
1757 file->details->mtime = mtime;
1759 if (file->details->thumbnail != NULL &&
1760 file->details->thumbnail_mtime != 0 &&
1761 file->details->thumbnail_mtime != mtime) {
1762 file->details->thumbnail_is_up_to_date = FALSE;
1763 changed = TRUE;
1766 icon = g_file_info_get_icon (info);
1767 if (!g_icon_equal (icon, file->details->icon)) {
1768 changed = TRUE;
1770 if (file->details->icon) {
1771 g_object_unref (file->details->icon);
1773 file->details->icon = g_object_ref (icon);
1776 thumbnail_path = g_file_info_get_attribute_byte_string (info, G_FILE_ATTRIBUTE_THUMBNAIL_PATH);
1777 if (eel_strcmp (file->details->thumbnail_path, thumbnail_path) != 0) {
1778 changed = TRUE;
1779 g_free (file->details->thumbnail_path);
1780 file->details->thumbnail_path = g_strdup (thumbnail_path);
1783 thumbnailing_failed = g_file_info_get_attribute_boolean (info, G_FILE_ATTRIBUTE_THUMBNAILING_FAILED);
1784 if (file->details->thumbnailing_failed != thumbnailing_failed) {
1785 changed = TRUE;
1786 file->details->thumbnailing_failed = thumbnailing_failed;
1789 symlink_name = g_file_info_get_symlink_target (info);
1790 if (eel_strcmp (file->details->symlink_name, symlink_name) != 0) {
1791 changed = TRUE;
1792 g_free (file->details->symlink_name);
1793 file->details->symlink_name = g_strdup (symlink_name);
1796 mime_type = g_file_info_get_content_type (info);
1797 if (eel_strcmp (eel_ref_str_peek (file->details->mime_type), mime_type) != 0) {
1798 changed = TRUE;
1800 eel_ref_str_unref (file->details->mime_type);
1801 file->details->mime_type = eel_ref_str_get_unique (mime_type);
1803 selinux_context = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_SELINUX_CONTEXT);
1804 if (eel_strcmp (file->details->selinux_context, selinux_context) != 0) {
1805 changed = TRUE;
1806 g_free (file->details->selinux_context);
1807 file->details->selinux_context = g_strdup (selinux_context);
1810 description = g_file_info_get_attribute_string (info, G_FILE_ATTRIBUTE_STANDARD_DESCRIPTION);
1811 if (eel_strcmp (file->details->description, description) != 0) {
1812 changed = TRUE;
1813 g_free (file->details->description);
1814 file->details->description = g_strdup (description);
1817 if (update_name) {
1818 name = g_file_info_get_name (info);
1819 if (file->details->name == NULL ||
1820 strcmp (eel_ref_str_peek (file->details->name), name) != 0) {
1821 node = nautilus_directory_begin_file_name_change
1822 (file->details->directory, file);
1824 eel_ref_str_unref (file->details->name);
1825 if (eel_strcmp (eel_ref_str_peek (file->details->display_name),
1826 name) == 0) {
1827 file->details->name = eel_ref_str_ref (file->details->display_name);
1828 } else {
1829 file->details->name = eel_ref_str_new (name);
1832 nautilus_directory_end_file_name_change
1833 (file->details->directory, file, node);
1837 if (changed) {
1838 add_to_link_hash_table (file);
1840 update_links_if_target (file);
1843 return changed;
1846 static gboolean
1847 update_info_and_name (NautilusFile *file,
1848 GFileInfo *info)
1850 return update_info_internal (file, info, TRUE);
1853 gboolean
1854 nautilus_file_update_info (NautilusFile *file,
1855 GFileInfo *info)
1857 return update_info_internal (file, info, FALSE);
1860 static gboolean
1861 update_name_internal (NautilusFile *file,
1862 const char *name,
1863 gboolean in_directory)
1865 GList *node;
1867 g_assert (name != NULL);
1869 if (file->details->is_gone) {
1870 return FALSE;
1873 if (name_is (file, name)) {
1874 return FALSE;
1877 node = NULL;
1878 if (in_directory) {
1879 node = nautilus_directory_begin_file_name_change
1880 (file->details->directory, file);
1883 eel_ref_str_unref (file->details->name);
1884 file->details->name = eel_ref_str_new (name);
1886 if (in_directory) {
1887 nautilus_directory_end_file_name_change
1888 (file->details->directory, file, node);
1891 return TRUE;
1894 gboolean
1895 nautilus_file_update_name (NautilusFile *file, const char *name)
1897 gboolean ret;
1899 ret = update_name_internal (file, name, TRUE);
1901 if (ret) {
1902 update_links_if_target (file);
1905 return ret;
1908 gboolean
1909 nautilus_file_update_name_and_directory (NautilusFile *file,
1910 const char *name,
1911 NautilusDirectory *new_directory)
1913 NautilusDirectory *old_directory;
1914 FileMonitors *monitors;
1916 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
1917 g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (file->details->directory), FALSE);
1918 g_return_val_if_fail (!file->details->is_gone, FALSE);
1919 g_return_val_if_fail (!nautilus_file_is_self_owned (file), FALSE);
1920 g_return_val_if_fail (NAUTILUS_IS_DIRECTORY (new_directory), FALSE);
1922 old_directory = file->details->directory;
1923 if (old_directory == new_directory) {
1924 if (name) {
1925 return update_name_internal (file, name, TRUE);
1926 } else {
1927 return FALSE;
1931 nautilus_file_ref (file);
1933 /* FIXME bugzilla.gnome.org 42044: Need to let links that
1934 * point to the old name know that the file has been moved.
1937 remove_from_link_hash_table (file);
1939 monitors = nautilus_directory_remove_file_monitors (old_directory, file);
1940 nautilus_directory_remove_file (old_directory, file);
1942 file->details->directory = nautilus_directory_ref (new_directory);
1943 nautilus_directory_unref (old_directory);
1945 if (name) {
1946 update_name_internal (file, name, FALSE);
1949 nautilus_directory_add_file (new_directory, file);
1950 nautilus_directory_add_file_monitors (new_directory, file, monitors);
1952 add_to_link_hash_table (file);
1954 update_links_if_target (file);
1956 nautilus_file_unref (file);
1958 return TRUE;
1961 void
1962 nautilus_file_set_directory (NautilusFile *file,
1963 NautilusDirectory *new_directory)
1965 nautilus_file_update_name_and_directory (file, NULL, new_directory);
1968 static Knowledge
1969 get_item_count (NautilusFile *file,
1970 guint *count)
1972 gboolean known, unreadable;
1974 known = nautilus_file_get_directory_item_count
1975 (file, count, &unreadable);
1976 if (!known) {
1977 return UNKNOWN;
1979 if (unreadable) {
1980 return UNKNOWABLE;
1982 return KNOWN;
1985 static Knowledge
1986 get_size (NautilusFile *file,
1987 goffset *size)
1989 /* If we tried and failed, then treat it like there is no size
1990 * to know.
1992 if (file->details->get_info_failed) {
1993 return UNKNOWABLE;
1996 /* If the info is NULL that means we haven't even tried yet,
1997 * so it's just unknown, not unknowable.
1999 if (!file->details->got_file_info) {
2000 return UNKNOWN;
2003 /* If we got info with no size in it, it means there is no
2004 * such thing as a size as far as gnome-vfs is concerned,
2005 * so "unknowable".
2007 if (file->details->size == -1) {
2008 return UNKNOWABLE;
2011 /* We have a size! */
2012 *size = file->details->size;
2013 return KNOWN;
2016 static Knowledge
2017 get_time (NautilusFile *file,
2018 time_t *time_out,
2019 NautilusDateType type)
2021 time_t time;
2023 /* If we tried and failed, then treat it like there is no size
2024 * to know.
2026 if (file->details->get_info_failed) {
2027 return UNKNOWABLE;
2030 /* If the info is NULL that means we haven't even tried yet,
2031 * so it's just unknown, not unknowable.
2033 if (!file->details->got_file_info) {
2034 return UNKNOWN;
2037 time = 0;
2038 switch (type) {
2039 case NAUTILUS_DATE_TYPE_MODIFIED:
2040 time = file->details->mtime;
2041 break;
2042 case NAUTILUS_DATE_TYPE_ACCESSED:
2043 time = file->details->atime;
2044 break;
2045 default:
2046 g_assert_not_reached ();
2047 break;
2050 *time_out = time;
2052 /* If we got info with no modification time in it, it means
2053 * there is no such thing as a modification time as far as
2054 * gnome-vfs is concerned, so "unknowable".
2056 if (time == 0) {
2057 return UNKNOWABLE;
2059 return KNOWN;
2062 static int
2063 compare_directories_by_count (NautilusFile *file_1, NautilusFile *file_2)
2065 /* Sort order:
2066 * Directories with unknown # of items
2067 * Directories with "unknowable" # of items
2068 * Directories with 0 items
2069 * Directories with n items
2072 Knowledge count_known_1, count_known_2;
2073 guint count_1, count_2;
2075 count_known_1 = get_item_count (file_1, &count_1);
2076 count_known_2 = get_item_count (file_2, &count_2);
2078 if (count_known_1 > count_known_2) {
2079 return -1;
2081 if (count_known_1 < count_known_2) {
2082 return +1;
2085 /* count_known_1 and count_known_2 are equal now. Check if count
2086 * details are UNKNOWABLE or UNKNOWN.
2088 if (count_known_1 == UNKNOWABLE || count_known_1 == UNKNOWN) {
2089 return 0;
2092 if (count_1 < count_2) {
2093 return -1;
2095 if (count_1 > count_2) {
2096 return +1;
2099 return 0;
2102 static int
2103 compare_files_by_size (NautilusFile *file_1, NautilusFile *file_2)
2105 /* Sort order:
2106 * Files with unknown size.
2107 * Files with "unknowable" size.
2108 * Files with smaller sizes.
2109 * Files with large sizes.
2112 Knowledge size_known_1, size_known_2;
2113 goffset size_1, size_2;
2115 size_known_1 = get_size (file_1, &size_1);
2116 size_known_2 = get_size (file_2, &size_2);
2118 if (size_known_1 > size_known_2) {
2119 return -1;
2121 if (size_known_1 < size_known_2) {
2122 return +1;
2125 /* size_known_1 and size_known_2 are equal now. Check if size
2126 * details are UNKNOWABLE or UNKNOWN
2128 if (size_known_1 == UNKNOWABLE || size_known_1 == UNKNOWN) {
2129 return 0;
2132 if (size_1 < size_2) {
2133 return -1;
2135 if (size_1 > size_2) {
2136 return +1;
2139 return 0;
2142 static int
2143 compare_by_size (NautilusFile *file_1, NautilusFile *file_2)
2145 /* Sort order:
2146 * Directories with n items
2147 * Directories with 0 items
2148 * Directories with "unknowable" # of items
2149 * Directories with unknown # of items
2150 * Files with large sizes.
2151 * Files with smaller sizes.
2152 * Files with "unknowable" size.
2153 * Files with unknown size.
2156 gboolean is_directory_1, is_directory_2;
2158 is_directory_1 = nautilus_file_is_directory (file_1);
2159 is_directory_2 = nautilus_file_is_directory (file_2);
2161 if (is_directory_1 && !is_directory_2) {
2162 return -1;
2164 if (is_directory_2 && !is_directory_1) {
2165 return +1;
2168 if (is_directory_1) {
2169 return compare_directories_by_count (file_1, file_2);
2170 } else {
2171 return compare_files_by_size (file_1, file_2);
2175 static int
2176 compare_by_display_name (NautilusFile *file_1, NautilusFile *file_2)
2178 const char *name_1, *name_2;
2179 const char *key_1, *key_2;
2180 gboolean sort_last_1, sort_last_2;
2181 int compare;
2183 name_1 = nautilus_file_peek_display_name (file_1);
2184 name_2 = nautilus_file_peek_display_name (file_2);
2186 sort_last_1 = name_1[0] == SORT_LAST_CHAR1 || name_1[0] == SORT_LAST_CHAR2;
2187 sort_last_2 = name_2[0] == SORT_LAST_CHAR1 || name_2[0] == SORT_LAST_CHAR2;
2189 if (sort_last_1 && !sort_last_2) {
2190 compare = +1;
2191 } else if (!sort_last_1 && sort_last_2) {
2192 compare = -1;
2193 } else {
2194 key_1 = nautilus_file_peek_display_name_collation_key (file_1);
2195 key_2 = nautilus_file_peek_display_name_collation_key (file_2);
2196 compare = strcmp (key_1, key_2);
2199 return compare;
2202 static int
2203 compare_by_directory_name (NautilusFile *file_1, NautilusFile *file_2)
2205 char *directory_1, *directory_2;
2206 int compare;
2208 if (file_1->details->directory == file_2->details->directory) {
2209 return 0;
2212 directory_1 = nautilus_file_get_parent_uri_for_display (file_1);
2213 directory_2 = nautilus_file_get_parent_uri_for_display (file_2);
2215 compare = g_utf8_collate (directory_1, directory_2);
2217 g_free (directory_1);
2218 g_free (directory_2);
2220 return compare;
2223 static gboolean
2224 file_has_note (NautilusFile *file)
2226 char *note;
2227 gboolean res;
2229 note = nautilus_file_get_metadata (file, NAUTILUS_METADATA_KEY_ANNOTATION, NULL);
2230 res = note != NULL && note[0] != 0;
2231 g_free (note);
2233 return res;
2236 static GList *
2237 prepend_automatic_keywords (NautilusFile *file,
2238 GList *names)
2240 /* Prepend in reverse order. */
2241 NautilusFile *parent;
2243 parent = nautilus_file_get_parent (file);
2245 #ifdef TRASH_IS_FAST_ENOUGH
2246 if (nautilus_file_is_in_trash (file)) {
2247 names = g_list_prepend
2248 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_TRASH));
2250 #endif
2251 if (nautilus_file_is_desktop_directory (file)) {
2252 names = g_list_prepend
2253 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_DESKTOP));
2255 if (file_has_note (file)) {
2256 names = g_list_prepend
2257 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_NOTE));
2259 if (!nautilus_file_can_write (file) &&
2260 (parent == NULL || nautilus_file_can_write (parent))) {
2261 names = g_list_prepend
2262 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_CANT_WRITE));
2264 if (!nautilus_file_can_read (file)) {
2265 names = g_list_prepend
2266 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_CANT_READ));
2268 if (nautilus_file_is_symbolic_link (file)) {
2269 names = g_list_prepend
2270 (names, g_strdup (NAUTILUS_FILE_EMBLEM_NAME_SYMBOLIC_LINK));
2273 if (parent) {
2274 nautilus_file_unref (parent);
2278 return names;
2281 static void
2282 fill_emblem_cache_if_needed (NautilusFile *file)
2284 GList *node, *keywords;
2285 char *scanner;
2286 size_t length;
2288 if (file->details->compare_by_emblem_cache != NULL) {
2289 /* Got a cache already. */
2290 return;
2293 keywords = nautilus_file_get_keywords (file);
2295 /* Add up the keyword string lengths */
2296 length = 1;
2297 for (node = keywords; node != NULL; node = node->next) {
2298 length += strlen ((const char *) node->data) + 1;
2301 /* Now that we know how large the cache struct needs to be, allocate it. */
2302 file->details->compare_by_emblem_cache = g_malloc (sizeof(NautilusFileSortByEmblemCache) + length);
2304 /* Copy them into the cache. */
2305 scanner = file->details->compare_by_emblem_cache->emblem_keywords;
2306 for (node = keywords; node != NULL; node = node->next) {
2307 length = strlen ((const char *) node->data) + 1;
2308 memcpy (scanner, (const char *) node->data, length);
2309 scanner += length;
2312 /* Zero-terminate so we can tell where the list ends. */
2313 *scanner = 0;
2315 eel_g_list_free_deep (keywords);
2318 static int
2319 compare_by_emblems (NautilusFile *file_1, NautilusFile *file_2)
2321 const char *keyword_cache_1, *keyword_cache_2;
2322 size_t length;
2323 int compare_result;
2325 fill_emblem_cache_if_needed (file_1);
2326 fill_emblem_cache_if_needed (file_2);
2328 /* We ignore automatic emblems, and only sort by user-added keywords. */
2329 compare_result = 0;
2330 keyword_cache_1 = file_1->details->compare_by_emblem_cache->emblem_keywords;
2331 keyword_cache_2 = file_2->details->compare_by_emblem_cache->emblem_keywords;
2332 for (; *keyword_cache_1 != '\0' && *keyword_cache_2 != '\0';) {
2333 compare_result = g_utf8_collate (keyword_cache_1, keyword_cache_2);
2334 if (compare_result != 0) {
2335 return compare_result;
2338 /* Advance to the next keyword */
2339 length = strlen (keyword_cache_1);
2340 keyword_cache_1 += length + 1;
2341 keyword_cache_2 += length + 1;
2345 /* One or both is now NULL. */
2346 if (*keyword_cache_1 != '\0') {
2347 g_assert (*keyword_cache_2 == '\0');
2348 return -1;
2349 } else if (*keyword_cache_2 != '\0') {
2350 return +1;
2353 return 0;
2356 static int
2357 compare_by_type (NautilusFile *file_1, NautilusFile *file_2)
2359 gboolean is_directory_1;
2360 gboolean is_directory_2;
2361 char *type_string_1;
2362 char *type_string_2;
2363 int result;
2365 /* Directories go first. Then, if mime types are identical,
2366 * don't bother getting strings (for speed). This assumes
2367 * that the string is dependent entirely on the mime type,
2368 * which is true now but might not be later.
2370 is_directory_1 = nautilus_file_is_directory (file_1);
2371 is_directory_2 = nautilus_file_is_directory (file_2);
2373 if (is_directory_1 && is_directory_2) {
2374 return 0;
2377 if (is_directory_1) {
2378 return -1;
2381 if (is_directory_2) {
2382 return +1;
2385 if (file_1->details->mime_type != NULL &&
2386 file_2->details->mime_type != NULL &&
2387 strcmp (eel_ref_str_peek (file_1->details->mime_type),
2388 eel_ref_str_peek (file_2->details->mime_type)) == 0) {
2389 return 0;
2392 type_string_1 = nautilus_file_get_type_as_string (file_1);
2393 type_string_2 = nautilus_file_get_type_as_string (file_2);
2395 result = g_utf8_collate (type_string_1, type_string_2);
2397 g_free (type_string_1);
2398 g_free (type_string_2);
2400 return result;
2403 static int
2404 compare_by_time (NautilusFile *file_1, NautilusFile *file_2, NautilusDateType type)
2406 /* Sort order:
2407 * Files with unknown times.
2408 * Files with "unknowable" times.
2409 * Files with older times.
2410 * Files with newer times.
2413 Knowledge time_known_1, time_known_2;
2414 time_t time_1, time_2;
2416 time_1 = 0;
2417 time_2 = 0;
2419 time_known_1 = get_time (file_1, &time_1, type);
2420 time_known_2 = get_time (file_2, &time_2, type);
2422 if (time_known_1 > time_known_2) {
2423 return -1;
2425 if (time_known_1 < time_known_2) {
2426 return +1;
2429 /* Now time_known_1 is equal to time_known_2. Check whether
2430 * we failed to get modification times for files
2432 if(time_known_1 == UNKNOWABLE || time_known_1 == UNKNOWN) {
2433 return 0;
2436 if (time_1 < time_2) {
2437 return -1;
2439 if (time_1 > time_2) {
2440 return +1;
2443 return 0;
2446 static int
2447 compare_by_full_path (NautilusFile *file_1, NautilusFile *file_2)
2449 int compare;
2451 compare = compare_by_directory_name (file_1, file_2);
2452 if (compare != 0) {
2453 return compare;
2455 return compare_by_display_name (file_1, file_2);
2458 static int
2459 nautilus_file_compare_for_sort_internal (NautilusFile *file_1,
2460 NautilusFile *file_2,
2461 gboolean directories_first)
2463 gboolean is_directory_1, is_directory_2;
2465 if (directories_first) {
2466 is_directory_1 = nautilus_file_is_directory (file_1);
2467 is_directory_2 = nautilus_file_is_directory (file_2);
2469 if (is_directory_1 && !is_directory_2) {
2470 return -1;
2473 if (is_directory_2 && !is_directory_1) {
2474 return +1;
2478 if (file_1->details->sort_order < file_2->details->sort_order) {
2479 return -1;
2480 } else if (file_1->details->sort_order > file_2->details->sort_order) {
2481 return 1;
2484 return 0;
2488 * nautilus_file_compare_for_sort:
2489 * @file_1: A file object
2490 * @file_2: Another file object
2491 * @sort_type: Sort criterion
2492 * @directories_first: Put all directories before any non-directories
2493 * @reversed: Reverse the order of the items, except that
2494 * the directories_first flag is still respected.
2496 * Return value: int < 0 if @file_1 should come before file_2 in a
2497 * sorted list; int > 0 if @file_2 should come before file_1 in a
2498 * sorted list; 0 if @file_1 and @file_2 are equal for this sort criterion. Note
2499 * that each named sort type may actually break ties several ways, with the name
2500 * of the sort criterion being the primary but not only differentiator.
2503 nautilus_file_compare_for_sort (NautilusFile *file_1,
2504 NautilusFile *file_2,
2505 NautilusFileSortType sort_type,
2506 gboolean directories_first,
2507 gboolean reversed)
2509 int result;
2511 if (file_1 == file_2) {
2512 return 0;
2515 result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first);
2517 if (result == 0) {
2518 switch (sort_type) {
2519 case NAUTILUS_FILE_SORT_BY_DISPLAY_NAME:
2520 result = compare_by_display_name (file_1, file_2);
2521 if (result == 0) {
2522 result = compare_by_directory_name (file_1, file_2);
2524 break;
2525 case NAUTILUS_FILE_SORT_BY_DIRECTORY:
2526 result = compare_by_full_path (file_1, file_2);
2527 break;
2528 case NAUTILUS_FILE_SORT_BY_SIZE:
2529 /* Compare directory sizes ourselves, then if necessary
2530 * use GnomeVFS to compare file sizes.
2532 result = compare_by_size (file_1, file_2);
2533 if (result == 0) {
2534 result = compare_by_full_path (file_1, file_2);
2536 break;
2537 case NAUTILUS_FILE_SORT_BY_TYPE:
2538 /* GnomeVFS doesn't know about our special text for certain
2539 * mime types, so we handle the mime-type sorting ourselves.
2541 result = compare_by_type (file_1, file_2);
2542 if (result == 0) {
2543 result = compare_by_full_path (file_1, file_2);
2545 break;
2546 case NAUTILUS_FILE_SORT_BY_MTIME:
2547 result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_MODIFIED);
2548 if (result == 0) {
2549 result = compare_by_full_path (file_1, file_2);
2551 break;
2552 case NAUTILUS_FILE_SORT_BY_ATIME:
2553 result = compare_by_time (file_1, file_2, NAUTILUS_DATE_TYPE_ACCESSED);
2554 if (result == 0) {
2555 result = compare_by_full_path (file_1, file_2);
2557 break;
2558 case NAUTILUS_FILE_SORT_BY_EMBLEMS:
2559 /* GnomeVFS doesn't know squat about our emblems, so
2560 * we handle comparing them here, before falling back
2561 * to tie-breakers.
2563 result = compare_by_emblems (file_1, file_2);
2564 if (result == 0) {
2565 result = compare_by_full_path (file_1, file_2);
2567 break;
2568 default:
2569 g_return_val_if_reached (0);
2573 if (reversed) {
2574 result = -result;
2577 return result;
2581 nautilus_file_compare_for_sort_by_attribute_q (NautilusFile *file_1,
2582 NautilusFile *file_2,
2583 GQuark attribute,
2584 gboolean directories_first,
2585 gboolean reversed)
2587 int result;
2589 if (file_1 == file_2) {
2590 return 0;
2593 /* Convert certain attributes into NautilusFileSortTypes and use
2594 * nautilus_file_compare_for_sort()
2596 if (attribute == 0 || attribute == attribute_name_q) {
2597 return nautilus_file_compare_for_sort (file_1, file_2,
2598 NAUTILUS_FILE_SORT_BY_DISPLAY_NAME,
2599 directories_first,
2600 reversed);
2601 } else if (attribute == attribute_size_q) {
2602 return nautilus_file_compare_for_sort (file_1, file_2,
2603 NAUTILUS_FILE_SORT_BY_SIZE,
2604 directories_first,
2605 reversed);
2606 } else if (attribute == attribute_type_q) {
2607 return nautilus_file_compare_for_sort (file_1, file_2,
2608 NAUTILUS_FILE_SORT_BY_TYPE,
2609 directories_first,
2610 reversed);
2611 } else if (attribute == attribute_modification_date_q || attribute == attribute_date_modified_q) {
2612 return nautilus_file_compare_for_sort (file_1, file_2,
2613 NAUTILUS_FILE_SORT_BY_MTIME,
2614 directories_first,
2615 reversed);
2616 } else if (attribute == attribute_accessed_date_q || attribute == attribute_date_accessed_q) {
2617 return nautilus_file_compare_for_sort (file_1, file_2,
2618 NAUTILUS_FILE_SORT_BY_ATIME,
2619 directories_first,
2620 reversed);
2621 } else if (attribute == attribute_emblems_q) {
2622 return nautilus_file_compare_for_sort (file_1, file_2,
2623 NAUTILUS_FILE_SORT_BY_EMBLEMS,
2624 directories_first,
2625 reversed);
2628 /* it is a normal attribute, compare by strings */
2630 result = nautilus_file_compare_for_sort_internal (file_1, file_2, directories_first);
2632 if (result == 0) {
2633 char *value_1;
2634 char *value_2;
2636 value_1 = nautilus_file_get_string_attribute_q (file_1,
2637 attribute);
2638 value_2 = nautilus_file_get_string_attribute_q (file_2,
2639 attribute);
2641 if (value_1 != NULL && value_2 != NULL) {
2642 result = strcmp (value_1, value_2);
2645 g_free (value_1);
2646 g_free (value_2);
2649 if (reversed) {
2650 result = -result;
2653 return result;
2657 nautilus_file_compare_for_sort_by_attribute (NautilusFile *file_1,
2658 NautilusFile *file_2,
2659 const char *attribute,
2660 gboolean directories_first,
2661 gboolean reversed)
2663 return nautilus_file_compare_for_sort_by_attribute_q (file_1, file_2,
2664 g_quark_from_string (attribute),
2665 directories_first,
2666 reversed);
2671 * nautilus_file_compare_name:
2672 * @file: A file object
2673 * @pattern: A string we are comparing it with
2675 * Return value: result of a comparison of the file name and the given pattern,
2676 * using the same sorting order as sort by name.
2679 nautilus_file_compare_display_name (NautilusFile *file,
2680 const char *pattern)
2682 const char *name;
2683 int result;
2685 g_return_val_if_fail (pattern != NULL, -1);
2687 name = nautilus_file_peek_display_name (file);
2688 result = g_utf8_collate (name, pattern);
2689 return result;
2693 gboolean
2694 nautilus_file_is_hidden_file (NautilusFile *file)
2696 return file->details->is_hidden;
2699 gboolean
2700 nautilus_file_is_backup_file (NautilusFile *file)
2702 return file->details->is_backup;
2705 static gboolean
2706 is_file_hidden (NautilusFile *file)
2708 return file->details->directory->details->hidden_file_hash != NULL &&
2709 g_hash_table_lookup (file->details->directory->details->hidden_file_hash,
2710 eel_ref_str_peek (file->details->name)) != NULL;
2714 gboolean
2715 nautilus_file_should_show (NautilusFile *file,
2716 gboolean show_hidden,
2717 gboolean show_backup)
2719 return (show_hidden || (!nautilus_file_is_hidden_file (file) && !is_file_hidden (file))) &&
2720 (show_backup || !nautilus_file_is_backup_file (file));
2724 gboolean
2725 nautilus_file_is_home (NautilusFile *file)
2727 GFile *dir;
2729 dir = file->details->directory->details->location;
2730 if (dir == NULL) {
2731 return FALSE;
2734 return nautilus_is_home_directory_file (dir,
2735 eel_ref_str_peek (file->details->name));
2738 gboolean
2739 nautilus_file_is_in_desktop (NautilusFile *file)
2741 if (file->details->directory->details->location) {
2742 return nautilus_is_desktop_directory (file->details->directory->details->location);
2744 return FALSE;
2748 static gboolean
2749 filter_hidden_and_backup_partition_callback (gpointer data,
2750 gpointer callback_data)
2752 NautilusFile *file;
2753 FilterOptions options;
2755 file = NAUTILUS_FILE (data);
2756 options = GPOINTER_TO_INT (callback_data);
2758 return nautilus_file_should_show (file,
2759 options & SHOW_HIDDEN,
2760 options & SHOW_BACKUP);
2763 GList *
2764 nautilus_file_list_filter_hidden_and_backup (GList *files,
2765 gboolean show_hidden,
2766 gboolean show_backup)
2768 GList *filtered_files;
2769 GList *removed_files;
2771 /* FIXME bugzilla.gnome.org 40653:
2772 * Eventually this should become a generic filtering thingy.
2775 filtered_files = nautilus_file_list_copy (files);
2776 filtered_files = eel_g_list_partition (filtered_files,
2777 filter_hidden_and_backup_partition_callback,
2778 GINT_TO_POINTER ((show_hidden ? SHOW_HIDDEN : 0) |
2779 (show_backup ? SHOW_BACKUP : 0)),
2780 &removed_files);
2781 nautilus_file_list_free (removed_files);
2783 return filtered_files;
2789 /* We use the file's URI for the metadata for files in a directory,
2790 * but we use a hard-coded string for the metadata for the directory
2791 * itself.
2793 static const char *
2794 get_metadata_name (NautilusFile *file)
2796 if (nautilus_file_is_self_owned (file)) {
2797 return FILE_NAME_FOR_DIRECTORY_METADATA;
2799 return eel_ref_str_peek (file->details->name);
2802 char *
2803 nautilus_file_get_metadata (NautilusFile *file,
2804 const char *key,
2805 const char *default_metadata)
2807 g_return_val_if_fail (key != NULL, g_strdup (default_metadata));
2808 g_return_val_if_fail (key[0] != '\0', g_strdup (default_metadata));
2809 if (file == NULL) {
2810 return g_strdup (default_metadata);
2812 g_return_val_if_fail (NAUTILUS_IS_FILE (file), g_strdup (default_metadata));
2814 return nautilus_directory_get_file_metadata
2815 (file->details->directory,
2816 get_metadata_name (file),
2817 key,
2818 default_metadata);
2821 GList *
2822 nautilus_file_get_metadata_list (NautilusFile *file,
2823 const char *list_key,
2824 const char *list_subkey)
2826 g_return_val_if_fail (list_key != NULL, NULL);
2827 g_return_val_if_fail (list_key[0] != '\0', NULL);
2828 g_return_val_if_fail (list_subkey != NULL, NULL);
2829 g_return_val_if_fail (list_subkey[0] != '\0', NULL);
2830 if (file == NULL) {
2831 return NULL;
2833 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
2835 return nautilus_directory_get_file_metadata_list
2836 (file->details->directory,
2837 get_metadata_name (file),
2838 list_key,
2839 list_subkey);
2842 void
2843 nautilus_file_set_metadata (NautilusFile *file,
2844 const char *key,
2845 const char *default_metadata,
2846 const char *metadata)
2848 g_return_if_fail (NAUTILUS_IS_FILE (file));
2849 g_return_if_fail (key != NULL);
2850 g_return_if_fail (key[0] != '\0');
2852 nautilus_directory_set_file_metadata
2853 (file->details->directory,
2854 get_metadata_name (file),
2855 key,
2856 default_metadata,
2857 metadata);
2860 void
2861 nautilus_file_set_metadata_list (NautilusFile *file,
2862 const char *list_key,
2863 const char *list_subkey,
2864 GList *list)
2866 g_return_if_fail (NAUTILUS_IS_FILE (file));
2867 g_return_if_fail (list_key != NULL);
2868 g_return_if_fail (list_key[0] != '\0');
2869 g_return_if_fail (list_subkey != NULL);
2870 g_return_if_fail (list_subkey[0] != '\0');
2872 nautilus_directory_set_file_metadata_list
2873 (file->details->directory,
2874 get_metadata_name (file),
2875 list_key,
2876 list_subkey,
2877 list);
2881 gboolean
2882 nautilus_file_get_boolean_metadata (NautilusFile *file,
2883 const char *key,
2884 gboolean default_metadata)
2886 g_return_val_if_fail (key != NULL, default_metadata);
2887 g_return_val_if_fail (key[0] != '\0', default_metadata);
2888 if (file == NULL) {
2889 return default_metadata;
2891 g_return_val_if_fail (NAUTILUS_IS_FILE (file), default_metadata);
2893 return nautilus_directory_get_boolean_file_metadata
2894 (file->details->directory,
2895 get_metadata_name (file),
2896 key,
2897 default_metadata);
2901 nautilus_file_get_integer_metadata (NautilusFile *file,
2902 const char *key,
2903 int default_metadata)
2905 g_return_val_if_fail (key != NULL, default_metadata);
2906 g_return_val_if_fail (key[0] != '\0', default_metadata);
2907 if (file == NULL) {
2908 return default_metadata;
2910 g_return_val_if_fail (NAUTILUS_IS_FILE (file), default_metadata);
2912 return nautilus_directory_get_integer_file_metadata
2913 (file->details->directory,
2914 get_metadata_name (file),
2915 key,
2916 default_metadata);
2920 void
2921 nautilus_file_set_boolean_metadata (NautilusFile *file,
2922 const char *key,
2923 gboolean default_metadata,
2924 gboolean metadata)
2926 g_return_if_fail (NAUTILUS_IS_FILE (file));
2927 g_return_if_fail (key != NULL);
2928 g_return_if_fail (key[0] != '\0');
2930 nautilus_directory_set_boolean_file_metadata
2931 (file->details->directory,
2932 get_metadata_name (file),
2933 key,
2934 default_metadata,
2935 metadata);
2938 void
2939 nautilus_file_set_integer_metadata (NautilusFile *file,
2940 const char *key,
2941 int default_metadata,
2942 int metadata)
2944 g_return_if_fail (NAUTILUS_IS_FILE (file));
2945 g_return_if_fail (key != NULL);
2946 g_return_if_fail (key[0] != '\0');
2948 nautilus_directory_set_integer_file_metadata
2949 (file->details->directory,
2950 get_metadata_name (file),
2951 key,
2952 default_metadata,
2953 metadata);
2956 static const char *
2957 nautilus_file_peek_display_name_collation_key (NautilusFile *file)
2959 const char *res;
2961 res = file->details->display_name_collation_key;
2962 if (res == NULL)
2963 res = "";
2965 return res;
2968 static const char *
2969 nautilus_file_peek_display_name (NautilusFile *file)
2971 const char *name;
2972 char *escaped_name;
2974 /* Default to display name based on filename if its not set yet */
2976 if (file->details->display_name == NULL) {
2977 name = eel_ref_str_peek (file->details->name);
2978 if (g_utf8_validate (name, -1, NULL)) {
2979 nautilus_file_set_display_name (file,
2980 name,
2981 NULL,
2982 FALSE);
2983 } else {
2984 escaped_name = g_uri_escape_string (name, G_URI_RESERVED_CHARS_ALLOWED_IN_PATH, TRUE);
2985 nautilus_file_set_display_name (file,
2986 escaped_name,
2987 NULL,
2988 FALSE);
2989 g_free (escaped_name);
2993 return eel_ref_str_peek (file->details->display_name);
2996 char *
2997 nautilus_file_get_display_name (NautilusFile *file)
2999 return g_strdup (nautilus_file_peek_display_name (file));
3002 char *
3003 nautilus_file_get_edit_name (NautilusFile *file)
3005 const char *res;
3007 res = eel_ref_str_peek (file->details->edit_name);
3008 if (res == NULL)
3009 res = "";
3011 return g_strdup (res);
3014 char *
3015 nautilus_file_get_name (NautilusFile *file)
3017 return g_strdup (eel_ref_str_peek (file->details->name));
3021 * nautilus_file_get_description:
3022 * @file: a #NautilusFile.
3024 * Gets the standard::description key from @file, if
3025 * it has been cached.
3027 * Returns: a string containing the value of the standard::description
3028 * key, or %NULL.
3030 char *
3031 nautilus_file_get_description (NautilusFile *file)
3033 return g_strdup (file->details->description);
3036 void
3037 nautilus_file_monitor_add (NautilusFile *file,
3038 gconstpointer client,
3039 NautilusFileAttributes attributes)
3041 g_return_if_fail (NAUTILUS_IS_FILE (file));
3042 g_return_if_fail (client != NULL);
3044 EEL_CALL_METHOD
3045 (NAUTILUS_FILE_CLASS, file,
3046 monitor_add, (file, client, attributes));
3049 void
3050 nautilus_file_monitor_remove (NautilusFile *file,
3051 gconstpointer client)
3053 g_return_if_fail (NAUTILUS_IS_FILE (file));
3054 g_return_if_fail (client != NULL);
3056 EEL_CALL_METHOD
3057 (NAUTILUS_FILE_CLASS, file,
3058 monitor_remove, (file, client));
3061 gboolean
3062 nautilus_file_is_launcher (NautilusFile *file)
3064 return file->details->is_launcher;
3067 gboolean
3068 nautilus_file_has_activation_uri (NautilusFile *file)
3070 return file->details->activation_location != NULL;
3074 /* Return the uri associated with the passed-in file, which may not be
3075 * the actual uri if the file is an desktop file or a nautilus
3076 * xml link file.
3078 char *
3079 nautilus_file_get_activation_uri (NautilusFile *file)
3081 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3083 if (file->details->activation_location != NULL) {
3084 return g_file_get_uri (file->details->activation_location);
3087 return nautilus_file_get_uri (file);
3090 GFile *
3091 nautilus_file_get_activation_location (NautilusFile *file)
3093 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3095 if (file->details->activation_location != NULL) {
3096 return g_object_ref (file->details->activation_location);
3099 return nautilus_file_get_location (file);
3103 char *
3104 nautilus_file_get_drop_target_uri (NautilusFile *file)
3106 char *uri, *target_uri;
3107 GFile *location;
3108 NautilusDesktopLink *link;
3110 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3112 if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
3113 link = nautilus_desktop_icon_file_get_link (NAUTILUS_DESKTOP_ICON_FILE (file));
3115 if (link != NULL) {
3116 location = nautilus_desktop_link_get_activation_location (link);
3117 g_object_unref (link);
3118 if (location != NULL) {
3119 uri = g_file_get_uri (location);
3120 g_object_unref (location);
3121 return uri;
3126 uri = nautilus_file_get_uri (file);
3128 /* Check for Nautilus link */
3129 if (nautilus_file_is_nautilus_link (file)) {
3130 location = nautilus_file_get_location (file);
3131 /* FIXME bugzilla.gnome.org 43020: This does sync. I/O and works only locally. */
3132 if (g_file_is_native (location)) {
3133 target_uri = nautilus_link_local_get_link_uri (uri);
3134 if (target_uri != NULL) {
3135 g_free (uri);
3136 uri = target_uri;
3139 g_object_unref (location);
3142 return uri;
3145 static gboolean
3146 is_uri_relative (const char *uri)
3148 char *scheme;
3150 scheme = g_uri_parse_scheme (uri);
3151 g_free (scheme);
3152 return scheme == NULL;
3155 static char *
3156 get_custom_icon_metadata_uri (NautilusFile *file)
3158 char *custom_icon_uri;
3159 char *uri;
3160 char *dir_uri;
3162 uri = nautilus_file_get_metadata (file, NAUTILUS_METADATA_KEY_CUSTOM_ICON, NULL);
3163 if (uri != NULL &&
3164 nautilus_file_is_directory (file) &&
3165 is_uri_relative (uri)) {
3166 dir_uri = nautilus_file_get_uri (file);
3167 custom_icon_uri = g_build_filename (dir_uri, uri, NULL);
3168 g_free (dir_uri);
3169 g_free (uri);
3170 } else {
3171 custom_icon_uri = uri;
3173 return custom_icon_uri;
3176 static GIcon *
3177 get_custom_icon (NautilusFile *file)
3179 char *custom_icon_uri;
3180 GFile *icon_file;
3181 GIcon *icon;
3183 if (file == NULL) {
3184 return NULL;
3187 icon = NULL;
3189 /* Metadata takes precedence */
3190 custom_icon_uri = get_custom_icon_metadata_uri (file);
3192 if (custom_icon_uri) {
3193 icon_file = g_file_new_for_uri (custom_icon_uri);
3194 icon = g_file_icon_new (icon_file);
3195 g_object_unref (icon_file);
3198 if (icon == NULL && file->details->got_link_info && file->details->custom_icon != NULL) {
3199 if (g_path_is_absolute (file->details->custom_icon)) {
3200 icon_file = g_file_new_for_path (file->details->custom_icon);
3201 icon = g_file_icon_new (icon_file);
3202 g_object_unref (icon_file);
3203 } else {
3204 icon = g_themed_icon_new (file->details->custom_icon);
3208 return icon;
3212 static int cached_thumbnail_limit;
3213 static int cached_thumbnail_size;
3214 static int show_image_thumbs;
3216 GFilesystemPreviewType
3217 nautilus_file_get_filesystem_use_preview (NautilusFile *file)
3219 GFilesystemPreviewType use_preview;
3220 NautilusFile *parent;
3222 parent = nautilus_file_get_parent (file);
3223 if (parent != NULL) {
3224 use_preview = parent->details->filesystem_use_preview;
3225 g_object_unref (parent);
3226 } else {
3227 use_preview = 0;
3230 return use_preview;
3233 gboolean
3234 nautilus_file_should_show_thumbnail (NautilusFile *file)
3236 const char *mime_type;
3237 GFilesystemPreviewType use_preview;
3239 use_preview = nautilus_file_get_filesystem_use_preview (file);
3241 mime_type = eel_ref_str_peek (file->details->mime_type);
3242 if (mime_type == NULL) {
3243 mime_type = "application/octet-stream";
3246 /* If the thumbnail has already been created, don't care about the size
3247 * of the original file.
3249 if (nautilus_thumbnail_is_mimetype_limited_by_size (mime_type) &&
3250 file->details->thumbnail_path == NULL &&
3251 nautilus_file_get_size (file) > (unsigned int)cached_thumbnail_limit) {
3252 return FALSE;
3255 if (show_image_thumbs == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
3256 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
3257 return FALSE;
3258 } else {
3259 return TRUE;
3261 } else if (show_image_thumbs == NAUTILUS_SPEED_TRADEOFF_NEVER) {
3262 return FALSE;
3263 } else {
3264 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
3265 /* file system says to never thumbnail anything */
3266 return FALSE;
3267 } else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
3268 /* file system says we should treat file as if it's local */
3269 return TRUE;
3270 } else {
3271 /* only local files */
3272 return nautilus_file_is_local (file);
3276 return FALSE;
3279 GIcon *
3280 nautilus_file_get_gicon (NautilusFile *file,
3281 NautilusFileIconFlags flags)
3283 const char * const * names;
3284 const char *name;
3285 GPtrArray *array;
3286 GIcon *icon;
3287 int i;
3288 gboolean changed;
3290 if (file == NULL) {
3291 return NULL;
3294 if (file->details->icon) {
3295 icon = NULL;
3297 if (((flags & NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT) ||
3298 (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT) ||
3299 (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER) ||
3300 ((flags & NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
3301 nautilus_file_has_open_window (file))) &&
3302 G_IS_THEMED_ICON (file->details->icon)) {
3303 names = g_themed_icon_get_names (G_THEMED_ICON (file->details->icon));
3304 array = g_ptr_array_new ();
3306 changed = TRUE;
3307 for (i = 0; names[i] != NULL; i++) {
3308 name = names[i];
3310 if (strcmp (name, "folder") == 0 &&
3311 (flags & NAUTILUS_FILE_ICON_FLAGS_IGNORE_VISITING) == 0 &&
3312 nautilus_file_has_open_window (file)) {
3313 changed = TRUE;
3314 g_ptr_array_add (array, "folder-visiting");
3316 if (strcmp (name, "folder") == 0 &&
3317 (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_DRAG_ACCEPT)) {
3318 changed = TRUE;
3319 g_ptr_array_add (array, "folder-drag-accept");
3321 if (strcmp (name, "folder") == 0 &&
3322 (flags & NAUTILUS_FILE_ICON_FLAGS_FOR_OPEN_FOLDER)) {
3323 changed = TRUE;
3324 g_ptr_array_add (array, "folder-open");
3326 if (strcmp (name, "text-x-generic") == 0 &&
3327 (flags & NAUTILUS_FILE_ICON_FLAGS_EMBEDDING_TEXT)) {
3328 changed = TRUE;
3329 g_ptr_array_add (array, "text-x-preview");
3331 g_ptr_array_add (array, (char *)name);
3334 if (changed) {
3335 icon = g_themed_icon_new_from_names ((char **)array->pdata, array->len);
3338 g_ptr_array_free (array, TRUE);
3341 if (icon == NULL) {
3342 icon = g_object_ref (file->details->icon);
3345 return icon;
3348 return g_themed_icon_new ("text-x-generic");
3351 NautilusIconInfo *
3352 nautilus_file_get_icon (NautilusFile *file,
3353 int size,
3354 NautilusFileIconFlags flags)
3356 NautilusIconInfo *icon;
3357 GIcon *gicon;
3358 GdkPixbuf *raw_pixbuf, *scaled_pixbuf;
3359 int modified_size;
3361 if (file == NULL) {
3362 return NULL;
3365 gicon = get_custom_icon (file);
3366 if (gicon) {
3367 icon = nautilus_icon_info_lookup (gicon, size);
3368 g_object_unref (gicon);
3369 return icon;
3372 modified_size = size * cached_thumbnail_size / NAUTILUS_ICON_SIZE_STANDARD;
3374 if (flags & NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS &&
3375 nautilus_file_should_show_thumbnail (file)) {
3376 if (file->details->thumbnail) {
3377 if (file->details->thumbnail_size == modified_size) {
3378 scaled_pixbuf = g_object_ref (file->details->thumbnail);
3379 } else {
3380 int w, h, s;
3381 double scale;
3383 if (file->details->thumbnail_size == 0) {
3384 raw_pixbuf = g_object_ref (file->details->thumbnail);
3385 } else {
3386 raw_pixbuf = nautilus_thumbnail_unframe_image (file->details->thumbnail);
3389 w = gdk_pixbuf_get_width (raw_pixbuf);
3390 h = gdk_pixbuf_get_height (raw_pixbuf);
3392 /* These compensates for frame size which will be added on the raw image */
3393 s = MAX (NAUTILUS_THUMBNAIL_FRAME_LEFT + w + NAUTILUS_THUMBNAIL_FRAME_RIGHT,
3394 NAUTILUS_THUMBNAIL_FRAME_TOP + h + NAUTILUS_THUMBNAIL_FRAME_BOTTOM);
3396 scale = (double)modified_size / s;
3398 scaled_pixbuf = gdk_pixbuf_scale_simple (raw_pixbuf,
3399 w * scale, h * scale,
3400 GDK_INTERP_HYPER);
3401 nautilus_thumbnail_frame_image (&scaled_pixbuf);
3403 g_object_unref (raw_pixbuf);
3405 if (modified_size > file->details->thumbnail_size) {
3406 /* Invalidate if we resize upward (and the
3407 loaded was not the original raw version, w/ size 0).
3409 if (file->details->thumbnail_size != 0 ||
3410 (modified_size > 128 && !file->details->thumbnail_tried_original)) {
3411 nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL);
3413 file->details->thumbnail_size = modified_size;
3414 g_object_unref (file->details->thumbnail);
3415 file->details->thumbnail = g_object_ref (scaled_pixbuf);
3419 icon = nautilus_icon_info_new_for_pixbuf (scaled_pixbuf);
3420 g_object_unref (scaled_pixbuf);
3421 return icon;
3422 } else if (file->details->thumbnail_path == NULL &&
3423 file->details->can_read &&
3424 !file->details->thumbnailing_failed &&
3425 !file->details->is_thumbnailing) {
3426 if (nautilus_can_thumbnail (file)) {
3427 nautilus_create_thumbnail (file);
3432 if (file->details->is_thumbnailing &&
3433 flags & NAUTILUS_FILE_ICON_FLAGS_USE_THUMBNAILS)
3434 gicon = g_themed_icon_new (ICON_NAME_THUMBNAIL_LOADING);
3435 else
3436 gicon = nautilus_file_get_gicon (file, flags);
3438 if (gicon) {
3439 icon = nautilus_icon_info_lookup (gicon, size);
3440 g_object_unref (gicon);
3441 return icon;
3444 return nautilus_icon_info_new_for_pixbuf (NULL);
3447 GdkPixbuf *
3448 nautilus_file_get_icon_pixbuf (NautilusFile *file,
3449 int size,
3450 gboolean force_size,
3451 NautilusFileIconFlags flags)
3453 NautilusIconInfo *info;
3454 GdkPixbuf *pixbuf;
3456 info = nautilus_file_get_icon (file, size, flags);
3457 if (force_size) {
3458 pixbuf = nautilus_icon_info_get_pixbuf_at_size (info, size);
3459 } else {
3460 pixbuf = nautilus_icon_info_get_pixbuf (info);
3462 g_object_unref (info);
3464 return pixbuf;
3467 char *
3468 nautilus_file_get_custom_icon (NautilusFile *file)
3470 char *custom_icon;
3472 if (file == NULL) {
3473 return NULL;
3476 /* Metadata takes precedence */
3477 custom_icon = get_custom_icon_metadata_uri (file);
3479 if (custom_icon == NULL && file->details->got_link_info) {
3480 custom_icon = g_strdup (file->details->custom_icon);
3483 return custom_icon;
3487 gboolean
3488 nautilus_file_get_date (NautilusFile *file,
3489 NautilusDateType date_type,
3490 time_t *date)
3492 if (date != NULL) {
3493 *date = 0;
3496 g_return_val_if_fail (date_type == NAUTILUS_DATE_TYPE_CHANGED
3497 || date_type == NAUTILUS_DATE_TYPE_ACCESSED
3498 || date_type == NAUTILUS_DATE_TYPE_MODIFIED
3499 || date_type == NAUTILUS_DATE_TYPE_PERMISSIONS_CHANGED, FALSE);
3501 if (file == NULL) {
3502 return FALSE;
3505 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3507 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3508 (NAUTILUS_FILE_CLASS, file,
3509 get_date, (file, date_type, date));
3512 static char *
3513 nautilus_file_get_where_string (NautilusFile *file)
3515 if (file == NULL) {
3516 return NULL;
3519 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
3521 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3522 (NAUTILUS_FILE_CLASS, file,
3523 get_where_string, (file));
3526 static const char *TODAY_TIME_FORMATS [] = {
3527 /* Today, use special word.
3528 * strftime patterns preceeded with the widest
3529 * possible resulting string for that pattern.
3531 * Note to localizers: You can look at man strftime
3532 * for details on the format, but you should only use
3533 * the specifiers from the C standard, not extensions.
3534 * These include "%" followed by one of
3535 * "aAbBcdHIjmMpSUwWxXyYZ". There are two extensions
3536 * in the Nautilus version of strftime that can be
3537 * used (and match GNU extensions). Putting a "-"
3538 * between the "%" and any numeric directive will turn
3539 * off zero padding, and putting a "_" there will use
3540 * space padding instead of zero padding.
3542 N_("today at 00:00:00 PM"),
3543 N_("today at %-I:%M:%S %p"),
3545 N_("today at 00:00 PM"),
3546 N_("today at %-I:%M %p"),
3548 N_("today, 00:00 PM"),
3549 N_("today, %-I:%M %p"),
3551 N_("today"),
3552 N_("today"),
3554 NULL
3557 static const char *YESTERDAY_TIME_FORMATS [] = {
3558 /* Yesterday, use special word.
3559 * Note to localizers: Same issues as "today" string.
3561 N_("yesterday at 00:00:00 PM"),
3562 N_("yesterday at %-I:%M:%S %p"),
3564 N_("yesterday at 00:00 PM"),
3565 N_("yesterday at %-I:%M %p"),
3567 N_("yesterday, 00:00 PM"),
3568 N_("yesterday, %-I:%M %p"),
3570 N_("yesterday"),
3571 N_("yesterday"),
3573 NULL
3576 static const char *CURRENT_WEEK_TIME_FORMATS [] = {
3577 /* Current week, include day of week.
3578 * Note to localizers: Same issues as "today" string.
3579 * The width measurement templates correspond to
3580 * the day/month name with the most letters.
3582 N_("Wednesday, September 00 0000 at 00:00:00 PM"),
3583 N_("%A, %B %-d %Y at %-I:%M:%S %p"),
3585 N_("Mon, Oct 00 0000 at 00:00:00 PM"),
3586 N_("%a, %b %-d %Y at %-I:%M:%S %p"),
3588 N_("Mon, Oct 00 0000 at 00:00 PM"),
3589 N_("%a, %b %-d %Y at %-I:%M %p"),
3591 N_("Oct 00 0000 at 00:00 PM"),
3592 N_("%b %-d %Y at %-I:%M %p"),
3594 N_("Oct 00 0000, 00:00 PM"),
3595 N_("%b %-d %Y, %-I:%M %p"),
3597 N_("00/00/00, 00:00 PM"),
3598 N_("%m/%-d/%y, %-I:%M %p"),
3600 N_("00/00/00"),
3601 N_("%m/%d/%y"),
3603 NULL
3606 static char *
3607 nautilus_file_fit_date_as_string (NautilusFile *file,
3608 NautilusDateType date_type,
3609 int width,
3610 NautilusWidthMeasureCallback measure_callback,
3611 NautilusTruncateCallback truncate_callback,
3612 void *measure_context)
3614 time_t file_time_raw;
3615 struct tm *file_time;
3616 const char **formats;
3617 const char *width_template;
3618 const char *format;
3619 char *date_string;
3620 char *result;
3621 GDate *today;
3622 GDate *file_date;
3623 guint32 file_date_age;
3624 int i;
3626 if (!nautilus_file_get_date (file, date_type, &file_time_raw)) {
3627 return NULL;
3630 file_time = localtime (&file_time_raw);
3632 if (date_format_pref == NAUTILUS_DATE_FORMAT_LOCALE) {
3633 return eel_strdup_strftime ("%c", file_time);
3634 } else if (date_format_pref == NAUTILUS_DATE_FORMAT_ISO) {
3635 return eel_strdup_strftime ("%Y-%m-%d %H:%M:%S", file_time);
3638 file_date = eel_g_date_new_tm (file_time);
3640 today = g_date_new ();
3641 g_date_set_time_t (today, time (NULL));
3643 /* Overflow results in a large number; fine for our purposes. */
3644 file_date_age = (g_date_get_julian (today) -
3645 g_date_get_julian (file_date));
3647 g_date_free (file_date);
3648 g_date_free (today);
3650 /* Format varies depending on how old the date is. This minimizes
3651 * the length (and thus clutter & complication) of typical dates
3652 * while providing sufficient detail for recent dates to make
3653 * them maximally understandable at a glance. Keep all format
3654 * strings separate rather than combining bits & pieces for
3655 * internationalization's sake.
3658 if (file_date_age == 0) {
3659 formats = TODAY_TIME_FORMATS;
3660 } else if (file_date_age == 1) {
3661 formats = YESTERDAY_TIME_FORMATS;
3662 } else if (file_date_age < 7) {
3663 formats = CURRENT_WEEK_TIME_FORMATS;
3664 } else {
3665 formats = CURRENT_WEEK_TIME_FORMATS;
3668 /* Find the date format that just fits the required width. Instead of measuring
3669 * the resulting string width directly, measure the width of a template that represents
3670 * the widest possible version of a date in a given format. This is done by using M, m
3671 * and 0 for the variable letters/digits respectively.
3673 format = NULL;
3675 for (i = 0; ; i += 2) {
3676 width_template = (formats [i] ? _(formats [i]) : NULL);
3677 if (width_template == NULL) {
3678 /* no more formats left */
3679 g_assert (format != NULL);
3681 /* Can't fit even the shortest format -- return an ellipsized form in the
3682 * shortest format
3685 date_string = eel_strdup_strftime (format, file_time);
3687 if (truncate_callback == NULL) {
3688 return date_string;
3691 result = (* truncate_callback) (date_string, width, measure_context);
3692 g_free (date_string);
3693 return result;
3696 format = _(formats [i + 1]);
3698 if (measure_callback == NULL) {
3699 /* don't care about fitting the width */
3700 break;
3703 if ((* measure_callback) (width_template, measure_context) <= width) {
3704 /* The template fits, this is the format we can fit. */
3705 break;
3709 return eel_strdup_strftime (format, file_time);
3714 * nautilus_file_fit_modified_date_as_string:
3716 * Get a user-displayable string representing a file modification date,
3717 * truncated to @width using the measuring and truncating callbacks.
3718 * @file: NautilusFile representing the file in question.
3719 * @width: The desired resulting string width.
3720 * @measure_callback: The callback used to measure the string width.
3721 * @truncate_callback: The callback used to truncate the string to a desired width.
3722 * @measure_context: Data neede when measuring and truncating.
3724 * Returns: Newly allocated string ready to display to the user.
3727 char *
3728 nautilus_file_fit_modified_date_as_string (NautilusFile *file,
3729 int width,
3730 NautilusWidthMeasureCallback measure_callback,
3731 NautilusTruncateCallback truncate_callback,
3732 void *measure_context)
3734 return nautilus_file_fit_date_as_string (file, NAUTILUS_DATE_TYPE_MODIFIED,
3735 width, measure_callback, truncate_callback, measure_context);
3739 * nautilus_file_get_date_as_string:
3741 * Get a user-displayable string representing a file modification date.
3742 * The caller is responsible for g_free-ing this string.
3743 * @file: NautilusFile representing the file in question.
3745 * Returns: Newly allocated string ready to display to the user.
3748 static char *
3749 nautilus_file_get_date_as_string (NautilusFile *file, NautilusDateType date_type)
3751 return nautilus_file_fit_date_as_string (file, date_type,
3752 0, NULL, NULL, NULL);
3755 static NautilusSpeedTradeoffValue show_directory_item_count;
3756 static NautilusSpeedTradeoffValue show_text_in_icons;
3758 static void
3759 show_text_in_icons_changed_callback (gpointer callback_data)
3761 show_text_in_icons = eel_preferences_get_enum (NAUTILUS_PREFERENCES_SHOW_TEXT_IN_ICONS);
3764 static void
3765 show_directory_item_count_changed_callback (gpointer callback_data)
3767 show_directory_item_count = eel_preferences_get_enum (NAUTILUS_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS);
3770 static gboolean
3771 get_speed_tradeoff_preference_for_file (NautilusFile *file, NautilusSpeedTradeoffValue value)
3773 GFilesystemPreviewType use_preview;
3775 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3777 use_preview = nautilus_file_get_filesystem_use_preview (file);
3779 if (value == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
3780 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
3781 return FALSE;
3782 } else {
3783 return TRUE;
3787 if (value == NAUTILUS_SPEED_TRADEOFF_NEVER) {
3788 return FALSE;
3791 g_assert (value == NAUTILUS_SPEED_TRADEOFF_LOCAL_ONLY);
3793 if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_NEVER) {
3794 /* file system says to never preview anything */
3795 return FALSE;
3796 } else if (use_preview == G_FILESYSTEM_PREVIEW_TYPE_IF_LOCAL) {
3797 /* file system says we should treat file as if it's local */
3798 return TRUE;
3799 } else {
3800 /* only local files */
3801 return nautilus_file_is_local (file);
3805 gboolean
3806 nautilus_file_should_show_directory_item_count (NautilusFile *file)
3808 static gboolean show_directory_item_count_callback_added = FALSE;
3810 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3812 if (file->details->mime_type &&
3813 strcmp (eel_ref_str_peek (file->details->mime_type), "x-directory/smb-share") == 0) {
3814 return FALSE;
3817 /* Add the callback once for the life of our process */
3818 if (!show_directory_item_count_callback_added) {
3819 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_DIRECTORY_ITEM_COUNTS,
3820 show_directory_item_count_changed_callback,
3821 NULL);
3822 show_directory_item_count_callback_added = TRUE;
3824 /* Peek for the first time */
3825 show_directory_item_count_changed_callback (NULL);
3828 return get_speed_tradeoff_preference_for_file (file, show_directory_item_count);
3831 gboolean
3832 nautilus_file_should_show_type (NautilusFile *file)
3834 char *uri;
3835 gboolean ret;
3837 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3839 uri = nautilus_file_get_uri (file);
3840 ret = ((strcmp (uri, "computer:///") != 0) &&
3841 (strcmp (uri, "network:///") != 0) &&
3842 (strcmp (uri, "smb:///") != 0));
3843 g_free (uri);
3845 return ret;
3848 gboolean
3849 nautilus_file_should_get_top_left_text (NautilusFile *file)
3851 static gboolean show_text_in_icons_callback_added = FALSE;
3853 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3855 /* Add the callback once for the life of our process */
3856 if (!show_text_in_icons_callback_added) {
3857 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_TEXT_IN_ICONS,
3858 show_text_in_icons_changed_callback,
3859 NULL);
3860 show_text_in_icons_callback_added = TRUE;
3862 /* Peek for the first time */
3863 show_text_in_icons_changed_callback (NULL);
3866 if (show_text_in_icons == NAUTILUS_SPEED_TRADEOFF_ALWAYS) {
3867 return TRUE;
3870 if (show_text_in_icons == NAUTILUS_SPEED_TRADEOFF_NEVER) {
3871 return FALSE;
3874 return get_speed_tradeoff_preference_for_file (file, show_text_in_icons);
3878 * nautilus_file_get_directory_item_count
3880 * Get the number of items in a directory.
3881 * @file: NautilusFile representing a directory.
3882 * @count: Place to put count.
3883 * @count_unreadable: Set to TRUE (if non-NULL) if permissions prevent
3884 * the item count from being read on this directory. Otherwise set to FALSE.
3886 * Returns: TRUE if count is available.
3889 gboolean
3890 nautilus_file_get_directory_item_count (NautilusFile *file,
3891 guint *count,
3892 gboolean *count_unreadable)
3894 if (count != NULL) {
3895 *count = 0;
3897 if (count_unreadable != NULL) {
3898 *count_unreadable = FALSE;
3901 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
3903 if (!nautilus_file_is_directory (file)) {
3904 return FALSE;
3907 if (!nautilus_file_should_show_directory_item_count (file)) {
3908 return FALSE;
3911 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3912 (NAUTILUS_FILE_CLASS, file,
3913 get_item_count, (file, count, count_unreadable));
3917 * nautilus_file_get_deep_counts
3919 * Get the statistics about items inside a directory.
3920 * @file: NautilusFile representing a directory or file.
3921 * @directory_count: Place to put count of directories inside.
3922 * @files_count: Place to put count of files inside.
3923 * @unreadable_directory_count: Number of directories encountered
3924 * that were unreadable.
3925 * @total_size: Total size of all files and directories visited.
3926 * @force: Whether the deep counts should even be collected if
3927 * nautilus_file_should_show_directory_item_count returns FALSE
3928 * for this file.
3930 * Returns: Status to indicate whether sizes are available.
3933 NautilusRequestStatus
3934 nautilus_file_get_deep_counts (NautilusFile *file,
3935 guint *directory_count,
3936 guint *file_count,
3937 guint *unreadable_directory_count,
3938 goffset *total_size,
3939 gboolean force)
3941 if (directory_count != NULL) {
3942 *directory_count = 0;
3944 if (file_count != NULL) {
3945 *file_count = 0;
3947 if (unreadable_directory_count != NULL) {
3948 *unreadable_directory_count = 0;
3950 if (total_size != NULL) {
3951 *total_size = 0;
3954 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NAUTILUS_REQUEST_DONE);
3956 if (!force && !nautilus_file_should_show_directory_item_count (file)) {
3957 /* Set field so an existing value isn't treated as up-to-date
3958 * when preference changes later.
3960 file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
3961 return file->details->deep_counts_status;
3964 return EEL_CALL_METHOD_WITH_RETURN_VALUE
3965 (NAUTILUS_FILE_CLASS, file,
3966 get_deep_counts, (file,
3967 directory_count,
3968 file_count,
3969 unreadable_directory_count,
3970 total_size));
3973 void
3974 nautilus_file_recompute_deep_counts (NautilusFile *file)
3976 if (file->details->deep_counts_status != NAUTILUS_REQUEST_IN_PROGRESS) {
3977 file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
3978 if (file->details->directory != NULL) {
3979 nautilus_directory_add_file_to_work_queue (file->details->directory, file);
3980 nautilus_directory_async_state_changed (file->details->directory);
3987 * nautilus_file_get_directory_item_mime_types
3989 * Get the list of mime-types present in a directory.
3990 * @file: NautilusFile representing a directory. It is an error to
3991 * call this function on a file that is not a directory.
3992 * @mime_list: Place to put the list of mime-types.
3994 * Returns: TRUE if mime-type list is available.
3997 gboolean
3998 nautilus_file_get_directory_item_mime_types (NautilusFile *file,
3999 GList **mime_list)
4001 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
4002 g_return_val_if_fail (mime_list != NULL, FALSE);
4004 if (!nautilus_file_is_directory (file)
4005 || !file->details->got_mime_list) {
4006 *mime_list = NULL;
4007 return FALSE;
4010 *mime_list = eel_g_str_list_copy (file->details->mime_list);
4011 return TRUE;
4014 gboolean
4015 nautilus_file_can_get_size (NautilusFile *file)
4017 return file->details->size == -1;
4022 * nautilus_file_get_size
4024 * Get the file size.
4025 * @file: NautilusFile representing the file in question.
4027 * Returns: Size in bytes.
4030 goffset
4031 nautilus_file_get_size (NautilusFile *file)
4033 /* Before we have info on the file, we don't know the size. */
4034 if (file->details->size == -1)
4035 return 0;
4036 return file->details->size;
4039 time_t
4040 nautilus_file_get_mtime (NautilusFile *file)
4042 return file->details->mtime;
4046 static void
4047 set_attributes_get_info_callback (GObject *source_object,
4048 GAsyncResult *res,
4049 gpointer callback_data)
4051 NautilusFileOperation *op;
4052 GFileInfo *new_info;
4053 GError *error;
4055 op = callback_data;
4057 error = NULL;
4058 new_info = g_file_query_info_finish (G_FILE (source_object), res, &error);
4059 if (new_info != NULL) {
4060 nautilus_file_update_info (op->file, new_info);
4061 g_object_unref (new_info);
4063 nautilus_file_operation_complete (op, NULL, error);
4064 if (error) {
4065 g_error_free (error);
4070 static void
4071 set_attributes_callback (GObject *source_object,
4072 GAsyncResult *result,
4073 gpointer callback_data)
4075 NautilusFileOperation *op;
4076 GError *error;
4077 gboolean res;
4079 op = callback_data;
4081 error = NULL;
4082 res = g_file_set_attributes_finish (G_FILE (source_object),
4083 result,
4084 NULL,
4085 &error);
4087 if (res) {
4088 g_file_query_info_async (G_FILE (source_object),
4089 NAUTILUS_FILE_DEFAULT_ATTRIBUTES,
4091 G_PRIORITY_DEFAULT,
4092 op->cancellable,
4093 set_attributes_get_info_callback, op);
4094 } else {
4095 nautilus_file_operation_complete (op, NULL, error);
4096 g_error_free (error);
4100 void
4101 nautilus_file_set_attributes (NautilusFile *file,
4102 GFileInfo *attributes,
4103 NautilusFileOperationCallback callback,
4104 gpointer callback_data)
4106 NautilusFileOperation *op;
4107 GFile *location;
4109 op = nautilus_file_operation_new (file, callback, callback_data);
4111 location = nautilus_file_get_location (file);
4112 g_file_set_attributes_async (location,
4113 attributes,
4115 G_PRIORITY_DEFAULT,
4116 op->cancellable,
4117 set_attributes_callback,
4118 op);
4119 g_object_unref (location);
4124 * nautilus_file_can_get_permissions:
4126 * Check whether the permissions for a file are determinable.
4127 * This might not be the case for files on non-UNIX file systems.
4129 * @file: The file in question.
4131 * Return value: TRUE if the permissions are valid.
4133 gboolean
4134 nautilus_file_can_get_permissions (NautilusFile *file)
4136 return file->details->has_permissions;
4140 * nautilus_file_can_set_permissions:
4142 * Check whether the current user is allowed to change
4143 * the permissions of a file.
4145 * @file: The file in question.
4147 * Return value: TRUE if the current user can change the
4148 * permissions of @file, FALSE otherwise. It's always possible
4149 * that when you actually try to do it, you will fail.
4151 gboolean
4152 nautilus_file_can_set_permissions (NautilusFile *file)
4154 uid_t user_id;
4156 if (file->details->uid != -1 &&
4157 nautilus_file_is_local (file)) {
4158 /* Check the user. */
4159 user_id = geteuid();
4161 /* Owner is allowed to set permissions. */
4162 if (user_id == (uid_t) file->details->uid) {
4163 return TRUE;
4166 /* Root is also allowed to set permissions. */
4167 if (user_id == 0) {
4168 return TRUE;
4171 /* Nobody else is allowed. */
4172 return FALSE;
4175 /* pretend to have full chmod rights when no info is available, relevant when
4176 * the FS can't provide ownership info, for instance for FTP */
4177 return TRUE;
4180 guint
4181 nautilus_file_get_permissions (NautilusFile *file)
4183 g_return_val_if_fail (nautilus_file_can_get_permissions (file), 0);
4185 return file->details->permissions;
4189 * nautilus_file_set_permissions:
4191 * Change a file's permissions. This should only be called if
4192 * nautilus_file_can_set_permissions returned TRUE.
4194 * @file: NautilusFile representing the file in question.
4195 * @new_permissions: New permissions value. This is the whole
4196 * set of permissions, not a delta.
4198 void
4199 nautilus_file_set_permissions (NautilusFile *file,
4200 guint32 new_permissions,
4201 NautilusFileOperationCallback callback,
4202 gpointer callback_data)
4204 GFileInfo *info;
4205 GError *error;
4207 if (!nautilus_file_can_set_permissions (file)) {
4208 /* Claim that something changed even if the permission change failed.
4209 * This makes it easier for some clients who see the "reverting"
4210 * to the old permissions as "changing back".
4212 nautilus_file_changed (file);
4213 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
4214 _("Not allowed to set permissions"));
4215 (* callback) (file, NULL, error, callback_data);
4216 g_error_free (error);
4217 return;
4220 /* Test the permissions-haven't-changed case explicitly
4221 * because we don't want to send the file-changed signal if
4222 * nothing changed.
4224 if (new_permissions == file->details->permissions) {
4225 (* callback) (file, NULL, NULL, callback_data);
4226 return;
4229 info = g_file_info_new ();
4230 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_MODE, new_permissions);
4231 nautilus_file_set_attributes (file, info, callback, callback_data);
4232 g_object_unref (info);
4236 * nautilus_file_can_get_selinux_context:
4238 * Check whether the selinux context for a file are determinable.
4239 * This might not be the case for files on non-UNIX file systems,
4240 * files without a context or systems that don't support selinux.
4242 * @file: The file in question.
4244 * Return value: TRUE if the permissions are valid.
4246 gboolean
4247 nautilus_file_can_get_selinux_context (NautilusFile *file)
4249 return file->details->selinux_context != NULL;
4254 * nautilus_file_get_selinux_context:
4256 * Get a user-displayable string representing a file's selinux
4257 * context
4258 * @file: NautilusFile representing the file in question.
4260 * Returns: Newly allocated string ready to display to the user.
4263 char *
4264 nautilus_file_get_selinux_context (NautilusFile *file)
4266 char *translated;
4267 char *raw;
4269 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
4271 if (!nautilus_file_can_get_selinux_context (file)) {
4272 return NULL;
4275 raw = file->details->selinux_context;
4277 #ifdef HAVE_SELINUX
4278 if (selinux_raw_to_trans_context (raw, &translated) == 0) {
4279 char *tmp;
4280 tmp = g_strdup (translated);
4281 freecon (translated);
4282 translated = tmp;
4284 else
4285 #endif
4287 translated = g_strdup (raw);
4290 return translated;
4293 static char *
4294 get_real_name (const char *name, const char *gecos)
4296 char *locale_string, *part_before_comma, *capitalized_login_name, *real_name;
4298 if (gecos == NULL) {
4299 return NULL;
4302 locale_string = eel_str_strip_substring_and_after (gecos, ",");
4303 if (!g_utf8_validate (locale_string, -1, NULL)) {
4304 part_before_comma = g_locale_to_utf8 (locale_string, -1, NULL, NULL, NULL);
4305 g_free (locale_string);
4306 } else {
4307 part_before_comma = locale_string;
4310 if (!g_utf8_validate (name, -1, NULL)) {
4311 locale_string = g_locale_to_utf8 (name, -1, NULL, NULL, NULL);
4312 } else {
4313 locale_string = g_strdup (name);
4316 capitalized_login_name = eel_str_capitalize (locale_string);
4317 g_free (locale_string);
4319 if (capitalized_login_name == NULL) {
4320 real_name = part_before_comma;
4321 } else {
4322 real_name = eel_str_replace_substring
4323 (part_before_comma, "&", capitalized_login_name);
4324 g_free (part_before_comma);
4328 if (eel_str_is_empty (real_name)
4329 || eel_strcmp (name, real_name) == 0
4330 || eel_strcmp (capitalized_login_name, real_name) == 0) {
4331 g_free (real_name);
4332 real_name = NULL;
4335 g_free (capitalized_login_name);
4337 return real_name;
4340 static char *
4341 get_user_and_real_name_from_id (uid_t uid)
4343 char *name, *gecos;
4344 char *real_name, *user_and_real_name;
4346 name = nautilus_users_cache_get_name (uid);
4347 gecos = nautilus_users_cache_get_gecos (uid);
4349 real_name = get_real_name (name, gecos);
4350 if (real_name != NULL) {
4351 user_and_real_name = g_strdup_printf ("%s - %s", name, real_name);
4352 } else {
4353 user_and_real_name = g_strdup (name);
4355 g_free (real_name);
4357 g_free (name);
4358 g_free (gecos);
4360 return user_and_real_name;
4363 static gboolean
4364 get_group_id_from_group_name (const char *group_name, uid_t *gid)
4366 struct group *group;
4368 g_assert (gid != NULL);
4370 group = getgrnam (group_name);
4372 if (group == NULL) {
4373 return FALSE;
4376 *gid = group->gr_gid;
4378 return TRUE;
4381 static gboolean
4382 get_ids_from_user_name (const char *user_name, uid_t *uid, uid_t *gid)
4384 struct passwd *password_info;
4386 g_assert (uid != NULL || gid != NULL);
4388 password_info = getpwnam (user_name);
4390 if (password_info == NULL) {
4391 return FALSE;
4394 if (uid != NULL) {
4395 *uid = password_info->pw_uid;
4398 if (gid != NULL) {
4399 *gid = password_info->pw_gid;
4402 return TRUE;
4405 static gboolean
4406 get_user_id_from_user_name (const char *user_name, uid_t *id)
4408 return get_ids_from_user_name (user_name, id, NULL);
4411 static gboolean
4412 get_id_from_digit_string (const char *digit_string, uid_t *id)
4414 long scanned_id;
4415 char c;
4417 g_assert (id != NULL);
4419 /* Only accept string if it has one integer with nothing
4420 * afterwards.
4422 if (sscanf (digit_string, "%ld%c", &scanned_id, &c) != 1) {
4423 return FALSE;
4425 *id = scanned_id;
4426 return TRUE;
4430 * nautilus_file_can_get_owner:
4432 * Check whether the owner a file is determinable.
4433 * This might not be the case for files on non-UNIX file systems.
4435 * @file: The file in question.
4437 * Return value: TRUE if the owner is valid.
4439 gboolean
4440 nautilus_file_can_get_owner (NautilusFile *file)
4442 /* Before we have info on a file, the owner is unknown. */
4443 return file->details->uid != -1;
4447 * nautilus_file_get_owner_name:
4449 * Get the user name of the file's owner. If the owner has no
4450 * name, returns the userid as a string. The caller is responsible
4451 * for g_free-ing this string.
4453 * @file: The file in question.
4455 * Return value: A newly-allocated string.
4457 char *
4458 nautilus_file_get_owner_name (NautilusFile *file)
4460 return nautilus_file_get_owner_as_string (file, FALSE);
4464 * nautilus_file_can_set_owner:
4466 * Check whether the current user is allowed to change
4467 * the owner of a file.
4469 * @file: The file in question.
4471 * Return value: TRUE if the current user can change the
4472 * owner of @file, FALSE otherwise. It's always possible
4473 * that when you actually try to do it, you will fail.
4475 gboolean
4476 nautilus_file_can_set_owner (NautilusFile *file)
4478 /* Not allowed to set the owner if we can't
4479 * even read it. This can happen on non-UNIX file
4480 * systems.
4482 if (!nautilus_file_can_get_owner (file)) {
4483 return FALSE;
4486 /* Only root is also allowed to set the owner. */
4487 return geteuid() == 0;
4491 * nautilus_file_set_owner:
4493 * Set the owner of a file. This will only have any effect if
4494 * nautilus_file_can_set_owner returns TRUE.
4496 * @file: The file in question.
4497 * @user_name_or_id: The user name to set the owner to.
4498 * If the string does not match any user name, and the
4499 * string is an integer, the owner will be set to the
4500 * userid represented by that integer.
4501 * @callback: Function called when asynch owner change succeeds or fails.
4502 * @callback_data: Parameter passed back with callback function.
4504 void
4505 nautilus_file_set_owner (NautilusFile *file,
4506 const char *user_name_or_id,
4507 NautilusFileOperationCallback callback,
4508 gpointer callback_data)
4510 GError *error;
4511 GFileInfo *info;
4512 uid_t new_id;
4514 if (!nautilus_file_can_set_owner (file)) {
4515 /* Claim that something changed even if the permission
4516 * change failed. This makes it easier for some
4517 * clients who see the "reverting" to the old owner as
4518 * "changing back".
4520 nautilus_file_changed (file);
4521 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
4522 _("Not allowed to set owner"));
4523 (* callback) (file, NULL, error, callback_data);
4524 g_error_free (error);
4525 return;
4528 /* If no match treating user_name_or_id as name, try treating
4529 * it as id.
4531 if (!get_user_id_from_user_name (user_name_or_id, &new_id)
4532 && !get_id_from_digit_string (user_name_or_id, &new_id)) {
4533 /* Claim that something changed even if the permission
4534 * change failed. This makes it easier for some
4535 * clients who see the "reverting" to the old owner as
4536 * "changing back".
4538 nautilus_file_changed (file);
4539 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
4540 _("Specified owner '%s' doesn't exist"), user_name_or_id);
4541 (* callback) (file, NULL, error, callback_data);
4542 g_error_free (error);
4543 return;
4546 /* Test the owner-hasn't-changed case explicitly because we
4547 * don't want to send the file-changed signal if nothing
4548 * changed.
4550 if (new_id == (uid_t) file->details->uid) {
4551 (* callback) (file, NULL, NULL, callback_data);
4552 return;
4555 info = g_file_info_new ();
4556 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_UID, new_id);
4557 nautilus_file_set_attributes (file, info, callback, callback_data);
4558 g_object_unref (info);
4562 * nautilus_get_user_names:
4564 * Get a list of user names. For users with a different associated
4565 * "real name", the real name follows the standard user name, separated
4566 * by a carriage return. The caller is responsible for freeing this list
4567 * and its contents.
4569 GList *
4570 nautilus_get_user_names (void)
4572 GList *list;
4573 char *real_name, *name;
4574 struct passwd *user;
4576 list = NULL;
4578 setpwent ();
4580 while ((user = getpwent ()) != NULL) {
4581 real_name = get_real_name (user->pw_name, user->pw_gecos);
4582 if (real_name != NULL) {
4583 name = g_strconcat (user->pw_name, "\n", real_name, NULL);
4584 } else {
4585 name = g_strdup (user->pw_name);
4587 g_free (real_name);
4588 list = g_list_prepend (list, name);
4591 endpwent ();
4593 return eel_g_str_list_alphabetize (list);
4597 * nautilus_file_can_get_group:
4599 * Check whether the group a file is determinable.
4600 * This might not be the case for files on non-UNIX file systems.
4602 * @file: The file in question.
4604 * Return value: TRUE if the group is valid.
4606 gboolean
4607 nautilus_file_can_get_group (NautilusFile *file)
4609 /* Before we have info on a file, the group is unknown. */
4610 return file->details->gid != -1;
4614 * nautilus_file_get_group_name:
4616 * Get the name of the file's group. If the group has no
4617 * name, returns the groupid as a string. The caller is responsible
4618 * for g_free-ing this string.
4620 * @file: The file in question.
4622 * Return value: A newly-allocated string.
4624 char *
4625 nautilus_file_get_group_name (NautilusFile *file)
4627 char *group_name;
4629 /* Before we have info on a file, the owner is unknown. */
4630 if (file->details->gid == -1) {
4631 return NULL;
4634 group_name = nautilus_groups_cache_get_name ((gid_t) file->details->gid);
4635 if (group_name == NULL) {
4636 /* In the oddball case that the group name has been set to an id for which
4637 * there is no defined group, return the id in string form.
4639 group_name = g_strdup_printf ("%d", file->details->gid);
4642 return group_name;
4646 * nautilus_file_can_set_group:
4648 * Check whether the current user is allowed to change
4649 * the group of a file.
4651 * @file: The file in question.
4653 * Return value: TRUE if the current user can change the
4654 * group of @file, FALSE otherwise. It's always possible
4655 * that when you actually try to do it, you will fail.
4657 gboolean
4658 nautilus_file_can_set_group (NautilusFile *file)
4660 uid_t user_id;
4662 /* Not allowed to set the permissions if we can't
4663 * even read them. This can happen on non-UNIX file
4664 * systems.
4666 if (!nautilus_file_can_get_group (file)) {
4667 return FALSE;
4670 /* Check the user. */
4671 user_id = geteuid();
4673 /* Owner is allowed to set group (with restrictions). */
4674 if (user_id == (uid_t) file->details->uid) {
4675 return TRUE;
4678 /* Root is also allowed to set group. */
4679 if (user_id == 0) {
4680 return TRUE;
4683 /* Nobody else is allowed. */
4684 return FALSE;
4687 /* Get a list of group names, filtered to only the ones
4688 * that contain the given username. If the username is
4689 * NULL, returns a list of all group names.
4691 static GList *
4692 nautilus_get_group_names_for_user (void)
4694 GList *list;
4695 struct group *group;
4696 int count, i;
4697 gid_t gid_list[NGROUPS_MAX + 1];
4700 list = NULL;
4702 count = getgroups (NGROUPS_MAX + 1, gid_list);
4703 for (i = 0; i < count; i++) {
4704 group = getgrgid (gid_list[i]);
4705 if (group == NULL)
4706 break;
4708 list = g_list_prepend (list, g_strdup (group->gr_name));
4711 return eel_g_str_list_alphabetize (list);
4715 * nautilus_get_group_names:
4717 * Get a list of all group names.
4719 GList *
4720 nautilus_get_all_group_names (void)
4722 GList *list;
4723 struct group *group;
4725 list = NULL;
4727 setgrent ();
4729 while ((group = getgrent ()) != NULL)
4730 list = g_list_prepend (list, g_strdup (group->gr_name));
4732 endgrent ();
4734 return eel_g_str_list_alphabetize (list);
4738 * nautilus_file_get_settable_group_names:
4740 * Get a list of all group names that the current user
4741 * can set the group of a specific file to.
4743 * @file: The NautilusFile in question.
4745 GList *
4746 nautilus_file_get_settable_group_names (NautilusFile *file)
4748 uid_t user_id;
4749 GList *result;
4751 if (!nautilus_file_can_set_group (file)) {
4752 return NULL;
4755 /* Check the user. */
4756 user_id = geteuid();
4758 if (user_id == 0) {
4759 /* Root is allowed to set group to anything. */
4760 result = nautilus_get_all_group_names ();
4761 } else if (user_id == (uid_t) file->details->uid) {
4762 /* Owner is allowed to set group to any that owner is member of. */
4763 result = nautilus_get_group_names_for_user ();
4764 } else {
4765 g_warning ("unhandled case in nautilus_get_settable_group_names");
4766 result = NULL;
4769 return result;
4773 * nautilus_file_set_group:
4775 * Set the group of a file. This will only have any effect if
4776 * nautilus_file_can_set_group returns TRUE.
4778 * @file: The file in question.
4779 * @group_name_or_id: The group name to set the owner to.
4780 * If the string does not match any group name, and the
4781 * string is an integer, the group will be set to the
4782 * group id represented by that integer.
4783 * @callback: Function called when asynch group change succeeds or fails.
4784 * @callback_data: Parameter passed back with callback function.
4786 void
4787 nautilus_file_set_group (NautilusFile *file,
4788 const char *group_name_or_id,
4789 NautilusFileOperationCallback callback,
4790 gpointer callback_data)
4792 GError *error;
4793 GFileInfo *info;
4794 uid_t new_id;
4796 if (!nautilus_file_can_set_group (file)) {
4797 /* Claim that something changed even if the group
4798 * change failed. This makes it easier for some
4799 * clients who see the "reverting" to the old group as
4800 * "changing back".
4802 nautilus_file_changed (file);
4803 error = g_error_new (G_IO_ERROR, G_IO_ERROR_PERMISSION_DENIED,
4804 _("Not allowed to set group"));
4805 (* callback) (file, NULL, error, callback_data);
4806 g_error_free (error);
4807 return;
4810 /* If no match treating group_name_or_id as name, try treating
4811 * it as id.
4813 if (!get_group_id_from_group_name (group_name_or_id, &new_id)
4814 && !get_id_from_digit_string (group_name_or_id, &new_id)) {
4815 /* Claim that something changed even if the group
4816 * change failed. This makes it easier for some
4817 * clients who see the "reverting" to the old group as
4818 * "changing back".
4820 nautilus_file_changed (file);
4821 error = g_error_new (G_IO_ERROR, G_IO_ERROR_INVALID_ARGUMENT,
4822 _("Specified group '%s' doesn't exist"), group_name_or_id);
4823 (* callback) (file, NULL, error, callback_data);
4824 g_error_free (error);
4825 return;
4828 if (new_id == (gid_t) file->details->gid) {
4829 (* callback) (file, NULL, NULL, callback_data);
4830 return;
4834 info = g_file_info_new ();
4835 g_file_info_set_attribute_uint32 (info, G_FILE_ATTRIBUTE_UNIX_GID, new_id);
4836 nautilus_file_set_attributes (file, info, callback, callback_data);
4837 g_object_unref (info);
4841 * nautilus_file_get_octal_permissions_as_string:
4843 * Get a user-displayable string representing a file's permissions
4844 * as an octal number. The caller
4845 * is responsible for g_free-ing this string.
4846 * @file: NautilusFile representing the file in question.
4848 * Returns: Newly allocated string ready to display to the user.
4851 static char *
4852 nautilus_file_get_octal_permissions_as_string (NautilusFile *file)
4854 guint32 permissions;
4856 g_assert (NAUTILUS_IS_FILE (file));
4858 if (!nautilus_file_can_get_permissions (file)) {
4859 return NULL;
4862 permissions = file->details->permissions;
4863 return g_strdup_printf ("%03o", permissions);
4867 * nautilus_file_get_permissions_as_string:
4869 * Get a user-displayable string representing a file's permissions. The caller
4870 * is responsible for g_free-ing this string.
4871 * @file: NautilusFile representing the file in question.
4873 * Returns: Newly allocated string ready to display to the user.
4876 static char *
4877 nautilus_file_get_permissions_as_string (NautilusFile *file)
4879 guint32 permissions;
4880 gboolean is_directory;
4881 gboolean is_link;
4882 gboolean suid, sgid, sticky;
4884 if (!nautilus_file_can_get_permissions (file)) {
4885 return NULL;
4888 g_assert (NAUTILUS_IS_FILE (file));
4890 permissions = file->details->permissions;
4891 is_directory = nautilus_file_is_directory (file);
4892 is_link = nautilus_file_is_symbolic_link (file);
4894 /* We use ls conventions for displaying these three obscure flags */
4895 suid = permissions & S_ISGID;
4896 sgid = permissions & S_ISGID;
4897 sticky = permissions & S_ISVTX;
4899 return g_strdup_printf ("%c%c%c%c%c%c%c%c%c%c",
4900 is_link ? 'l' : is_directory ? 'd' : '-',
4901 permissions & S_IRUSR ? 'r' : '-',
4902 permissions & S_IWUSR ? 'w' : '-',
4903 permissions & S_IXUSR
4904 ? (suid ? 's' : 'x')
4905 : (suid ? 'S' : '-'),
4906 permissions & S_IRGRP ? 'r' : '-',
4907 permissions & S_IWGRP ? 'w' : '-',
4908 permissions & S_IXGRP
4909 ? (sgid ? 's' : 'x')
4910 : (sgid ? 'S' : '-'),
4911 permissions & S_IROTH ? 'r' : '-',
4912 permissions & S_IWOTH ? 'w' : '-',
4913 permissions & S_IXOTH
4914 ? (sticky ? 't' : 'x')
4915 : (sticky ? 'T' : '-'));
4919 * nautilus_file_get_owner_as_string:
4921 * Get a user-displayable string representing a file's owner. The caller
4922 * is responsible for g_free-ing this string.
4923 * @file: NautilusFile representing the file in question.
4924 * @include_real_name: Whether or not to append the real name (if any)
4925 * for this user after the user name.
4927 * Returns: Newly allocated string ready to display to the user.
4930 static char *
4931 nautilus_file_get_owner_as_string (NautilusFile *file, gboolean include_real_name)
4933 char *user_name;
4935 /* Before we have info on a file, the owner is unknown. */
4936 if (file->details->uid == -1) {
4937 return NULL;
4940 if (include_real_name) {
4941 user_name = get_user_and_real_name_from_id (file->details->uid);
4942 } else {
4943 user_name = nautilus_users_cache_get_name (file->details->uid);
4946 if (user_name == NULL) {
4947 /* In the oddball case that the user name has been set to an id for which
4948 * there is no defined user, return the id in string form.
4950 user_name = g_strdup_printf ("%d", file->details->uid);
4953 return user_name;
4956 static char *
4957 format_item_count_for_display (guint item_count,
4958 gboolean includes_directories,
4959 gboolean includes_files)
4961 g_assert (includes_directories || includes_files);
4963 return g_strdup_printf (includes_directories
4964 ? (includes_files
4965 ? ngettext ("%'u item", "%'u items", item_count)
4966 : ngettext ("%'u folder", "%'u folders", item_count))
4967 : ngettext ("%'u file", "%'u files", item_count), item_count);
4971 * nautilus_file_get_size_as_string:
4973 * Get a user-displayable string representing a file size. The caller
4974 * is responsible for g_free-ing this string. The string is an item
4975 * count for directories.
4976 * @file: NautilusFile representing the file in question.
4978 * Returns: Newly allocated string ready to display to the user.
4981 static char *
4982 nautilus_file_get_size_as_string (NautilusFile *file)
4984 guint item_count;
4985 gboolean count_unreadable;
4987 if (file == NULL) {
4988 return NULL;
4991 g_assert (NAUTILUS_IS_FILE (file));
4993 if (nautilus_file_is_directory (file)) {
4994 if (!nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
4995 return NULL;
4997 return format_item_count_for_display (item_count, TRUE, TRUE);
5000 if (file->details->size == -1) {
5001 return NULL;
5003 return g_format_size_for_display (file->details->size);
5007 * nautilus_file_get_size_as_string_with_real_size:
5009 * Get a user-displayable string representing a file size. The caller
5010 * is responsible for g_free-ing this string. The string is an item
5011 * count for directories.
5012 * This function adds the real size in the string.
5013 * @file: NautilusFile representing the file in question.
5015 * Returns: Newly allocated string ready to display to the user.
5018 static char *
5019 nautilus_file_get_size_as_string_with_real_size (NautilusFile *file)
5021 guint item_count;
5022 gboolean count_unreadable;
5023 char * formated;
5024 char * formated_plus_real;
5025 char * real_size;
5027 if (file == NULL) {
5028 return NULL;
5031 g_assert (NAUTILUS_IS_FILE (file));
5033 if (nautilus_file_is_directory (file)) {
5034 if (!nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable)) {
5035 return NULL;
5037 return format_item_count_for_display (item_count, TRUE, TRUE);
5040 if (file->details->size == -1) {
5041 return NULL;
5044 formated = g_format_size_for_display (file->details->size);
5045 /* Do this in a separate stage so that we don't have to put G_GUINT64_FORMAT in the translated string */
5046 real_size = g_strdup_printf (_("%"G_GUINT64_FORMAT), (guint64) file->details->size);
5047 formated_plus_real = g_strdup_printf (_("%s (%s bytes)"), formated, real_size);
5048 g_free (real_size);
5049 g_free (formated);
5050 return formated_plus_real;
5054 static char *
5055 nautilus_file_get_deep_count_as_string_internal (NautilusFile *file,
5056 gboolean report_size,
5057 gboolean report_directory_count,
5058 gboolean report_file_count)
5060 NautilusRequestStatus status;
5061 guint directory_count;
5062 guint file_count;
5063 guint unreadable_count;
5064 guint total_count;
5065 goffset total_size;
5067 /* Must ask for size or some kind of count, but not both. */
5068 g_assert (!report_size || (!report_directory_count && !report_file_count));
5069 g_assert (report_size || report_directory_count || report_file_count);
5071 if (file == NULL) {
5072 return NULL;
5075 g_assert (NAUTILUS_IS_FILE (file));
5076 g_assert (nautilus_file_is_directory (file));
5078 status = nautilus_file_get_deep_counts
5079 (file, &directory_count, &file_count, &unreadable_count, &total_size, FALSE);
5081 /* Check whether any info is available. */
5082 if (status == NAUTILUS_REQUEST_NOT_STARTED) {
5083 return NULL;
5086 total_count = file_count + directory_count;
5088 if (total_count == 0) {
5089 switch (status) {
5090 case NAUTILUS_REQUEST_IN_PROGRESS:
5091 /* Don't return confident "zero" until we're finished looking,
5092 * because of next case.
5094 return NULL;
5095 case NAUTILUS_REQUEST_DONE:
5096 /* Don't return "zero" if we there were contents but we couldn't read them. */
5097 if (unreadable_count != 0) {
5098 return NULL;
5100 default: break;
5104 /* Note that we don't distinguish the "everything was readable" case
5105 * from the "some things but not everything was readable" case here.
5106 * Callers can distinguish them using nautilus_file_get_deep_counts
5107 * directly if desired.
5109 if (report_size) {
5110 return g_format_size_for_display (total_size);
5113 return format_item_count_for_display (report_directory_count
5114 ? (report_file_count ? total_count : directory_count)
5115 : file_count,
5116 report_directory_count, report_file_count);
5120 * nautilus_file_get_deep_size_as_string:
5122 * Get a user-displayable string representing the size of all contained
5123 * items (only makes sense for directories). The caller
5124 * is responsible for g_free-ing this string.
5125 * @file: NautilusFile representing the file in question.
5127 * Returns: Newly allocated string ready to display to the user.
5130 static char *
5131 nautilus_file_get_deep_size_as_string (NautilusFile *file)
5133 return nautilus_file_get_deep_count_as_string_internal (file, TRUE, FALSE, FALSE);
5137 * nautilus_file_get_deep_total_count_as_string:
5139 * Get a user-displayable string representing the count of all contained
5140 * items (only makes sense for directories). The caller
5141 * is responsible for g_free-ing this string.
5142 * @file: NautilusFile representing the file in question.
5144 * Returns: Newly allocated string ready to display to the user.
5147 static char *
5148 nautilus_file_get_deep_total_count_as_string (NautilusFile *file)
5150 return nautilus_file_get_deep_count_as_string_internal (file, FALSE, TRUE, TRUE);
5154 * nautilus_file_get_deep_file_count_as_string:
5156 * Get a user-displayable string representing the count of all contained
5157 * items, not including directories. It only makes sense to call this
5158 * function on a directory. The caller
5159 * is responsible for g_free-ing this string.
5160 * @file: NautilusFile representing the file in question.
5162 * Returns: Newly allocated string ready to display to the user.
5165 static char *
5166 nautilus_file_get_deep_file_count_as_string (NautilusFile *file)
5168 return nautilus_file_get_deep_count_as_string_internal (file, FALSE, FALSE, TRUE);
5172 * nautilus_file_get_deep_directory_count_as_string:
5174 * Get a user-displayable string representing the count of all contained
5175 * directories. It only makes sense to call this
5176 * function on a directory. The caller
5177 * is responsible for g_free-ing this string.
5178 * @file: NautilusFile representing the file in question.
5180 * Returns: Newly allocated string ready to display to the user.
5183 static char *
5184 nautilus_file_get_deep_directory_count_as_string (NautilusFile *file)
5186 return nautilus_file_get_deep_count_as_string_internal (file, FALSE, TRUE, FALSE);
5190 * nautilus_file_get_string_attribute:
5192 * Get a user-displayable string from a named attribute. Use g_free to
5193 * free this string. If the value is unknown, returns NULL. You can call
5194 * nautilus_file_get_string_attribute_with_default if you want a non-NULL
5195 * default.
5197 * @file: NautilusFile representing the file in question.
5198 * @attribute_name: The name of the desired attribute. The currently supported
5199 * set includes "name", "type", "mime_type", "size", "deep_size", "deep_directory_count",
5200 * "deep_file_count", "deep_total_count", "date_modified", "date_changed", "date_accessed",
5201 * "date_permissions", "owner", "group", "permissions", "octal_permissions", "uri", "where",
5202 * "link_target", "volume", "free_space", "selinux_context"
5204 * Returns: Newly allocated string ready to display to the user, or NULL
5205 * if the value is unknown or @attribute_name is not supported.
5208 char *
5209 nautilus_file_get_string_attribute_q (NautilusFile *file, GQuark attribute_q)
5211 char *extension_attribute;
5213 if (attribute_q == attribute_name_q) {
5214 return nautilus_file_get_display_name (file);
5216 if (attribute_q == attribute_type_q) {
5217 return nautilus_file_get_type_as_string (file);
5219 if (attribute_q == attribute_mime_type_q) {
5220 return nautilus_file_get_mime_type (file);
5222 if (attribute_q == attribute_size_q) {
5223 return nautilus_file_get_size_as_string (file);
5225 if (attribute_q == attribute_size_detail_q) {
5226 return nautilus_file_get_size_as_string_with_real_size (file);
5228 if (attribute_q == attribute_deep_size_q) {
5229 return nautilus_file_get_deep_size_as_string (file);
5231 if (attribute_q == attribute_deep_file_count_q) {
5232 return nautilus_file_get_deep_file_count_as_string (file);
5234 if (attribute_q == attribute_deep_directory_count_q) {
5235 return nautilus_file_get_deep_directory_count_as_string (file);
5237 if (attribute_q == attribute_deep_total_count_q) {
5238 return nautilus_file_get_deep_total_count_as_string (file);
5240 if (attribute_q == attribute_date_modified_q) {
5241 return nautilus_file_get_date_as_string (file,
5242 NAUTILUS_DATE_TYPE_MODIFIED);
5244 if (attribute_q == attribute_date_changed_q) {
5245 return nautilus_file_get_date_as_string (file,
5246 NAUTILUS_DATE_TYPE_CHANGED);
5248 if (attribute_q == attribute_date_accessed_q) {
5249 return nautilus_file_get_date_as_string (file,
5250 NAUTILUS_DATE_TYPE_ACCESSED);
5252 if (attribute_q == attribute_date_permissions_q) {
5253 return nautilus_file_get_date_as_string (file,
5254 NAUTILUS_DATE_TYPE_PERMISSIONS_CHANGED);
5256 if (attribute_q == attribute_permissions_q) {
5257 return nautilus_file_get_permissions_as_string (file);
5259 if (attribute_q == attribute_selinux_context_q) {
5260 return nautilus_file_get_selinux_context (file);
5262 if (attribute_q == attribute_octal_permissions_q) {
5263 return nautilus_file_get_octal_permissions_as_string (file);
5265 if (attribute_q == attribute_owner_q) {
5266 return nautilus_file_get_owner_as_string (file, TRUE);
5268 if (attribute_q == attribute_group_q) {
5269 return nautilus_file_get_group_name (file);
5271 if (attribute_q == attribute_uri_q) {
5272 return nautilus_file_get_uri (file);
5274 if (attribute_q == attribute_where_q) {
5275 return nautilus_file_get_where_string (file);
5277 if (attribute_q == attribute_link_target_q) {
5278 return nautilus_file_get_symbolic_link_target_path (file);
5280 if (attribute_q == attribute_volume_q) {
5281 return nautilus_file_get_volume_name (file);
5283 if (attribute_q == attribute_free_space_q) {
5284 return nautilus_file_get_volume_free_space (file);
5287 extension_attribute = NULL;
5289 if (file->details->pending_extension_attributes) {
5290 extension_attribute = g_hash_table_lookup (file->details->pending_extension_attributes,
5291 GINT_TO_POINTER (attribute_q));
5294 if (extension_attribute == NULL && file->details->extension_attributes) {
5295 extension_attribute = g_hash_table_lookup (file->details->extension_attributes,
5296 GINT_TO_POINTER (attribute_q));
5299 return g_strdup (extension_attribute);
5302 char *
5303 nautilus_file_get_string_attribute (NautilusFile *file, const char *attribute_name)
5305 return nautilus_file_get_string_attribute_q (file, g_quark_from_string (attribute_name));
5310 * nautilus_file_get_string_attribute_with_default:
5312 * Get a user-displayable string from a named attribute. Use g_free to
5313 * free this string. If the value is unknown, returns a string representing
5314 * the unknown value, which varies with attribute. You can call
5315 * nautilus_file_get_string_attribute if you want NULL instead of a default
5316 * result.
5318 * @file: NautilusFile representing the file in question.
5319 * @attribute_name: The name of the desired attribute. See the description of
5320 * nautilus_file_get_string for the set of available attributes.
5322 * Returns: Newly allocated string ready to display to the user, or a string
5323 * such as "unknown" if the value is unknown or @attribute_name is not supported.
5326 char *
5327 nautilus_file_get_string_attribute_with_default_q (NautilusFile *file, GQuark attribute_q)
5329 char *result;
5330 guint item_count;
5331 gboolean count_unreadable;
5332 NautilusRequestStatus status;
5334 result = nautilus_file_get_string_attribute_q (file, attribute_q);
5335 if (result != NULL) {
5336 return result;
5339 /* Supply default values for the ones we know about. */
5340 /* FIXME bugzilla.gnome.org 40646:
5341 * Use hash table and switch statement or function pointers for speed?
5343 if (attribute_q == attribute_size_q) {
5344 if (!nautilus_file_should_show_directory_item_count (file)) {
5345 return g_strdup ("--");
5347 count_unreadable = FALSE;
5348 if (nautilus_file_is_directory (file)) {
5349 nautilus_file_get_directory_item_count (file, &item_count, &count_unreadable);
5351 return g_strdup (count_unreadable ? _("? items") : "...");
5353 if (attribute_q == attribute_deep_size_q) {
5354 status = nautilus_file_get_deep_counts (file, NULL, NULL, NULL, NULL, FALSE);
5355 if (status == NAUTILUS_REQUEST_DONE) {
5356 /* This means no contents at all were readable */
5357 return g_strdup (_("? bytes"));
5359 return g_strdup ("...");
5361 if (attribute_q == attribute_deep_file_count_q
5362 || attribute_q == attribute_deep_directory_count_q
5363 || attribute_q == attribute_deep_total_count_q) {
5364 status = nautilus_file_get_deep_counts (file, NULL, NULL, NULL, NULL, FALSE);
5365 if (status == NAUTILUS_REQUEST_DONE) {
5366 /* This means no contents at all were readable */
5367 return g_strdup (_("? items"));
5369 return g_strdup ("...");
5371 if (attribute_q == attribute_type_q) {
5372 return g_strdup (_("unknown type"));
5374 if (attribute_q == attribute_mime_type_q) {
5375 return g_strdup (_("unknown MIME type"));
5378 /* Fallback, use for both unknown attributes and attributes
5379 * for which we have no more appropriate default.
5381 return g_strdup (_("unknown"));
5384 char *
5385 nautilus_file_get_string_attribute_with_default (NautilusFile *file, const char *attribute_name)
5387 return nautilus_file_get_string_attribute_with_default_q (file, g_quark_from_string (attribute_name));
5391 * get_description:
5393 * Get a user-displayable string representing a file type. The caller
5394 * is responsible for g_free-ing this string.
5395 * @file: NautilusFile representing the file in question.
5397 * Returns: Newly allocated string ready to display to the user.
5400 static char *
5401 get_description (NautilusFile *file)
5403 const char *mime_type;
5404 char *description;
5406 g_assert (NAUTILUS_IS_FILE (file));
5408 mime_type = eel_ref_str_peek (file->details->mime_type);
5409 if (eel_str_is_empty (mime_type)) {
5410 return NULL;
5413 if (g_content_type_is_unknown (mime_type) &&
5414 nautilus_file_is_executable (file)) {
5415 return g_strdup (_("program"));
5418 description = g_content_type_get_description (mime_type);
5419 if (!eel_str_is_empty (description)) {
5420 return description;
5423 return g_strdup (mime_type);
5426 /* Takes ownership of string */
5427 static char *
5428 update_description_for_link (NautilusFile *file, char *string)
5430 char *res;
5432 if (nautilus_file_is_symbolic_link (file)) {
5433 g_assert (!nautilus_file_is_broken_symbolic_link (file));
5434 if (string == NULL) {
5435 return g_strdup (_("link"));
5437 /* Note to localizers: convert file type string for file
5438 * (e.g. "folder", "plain text") to file type for symbolic link
5439 * to that kind of file (e.g. "link to folder").
5441 res = g_strdup_printf (_("Link to %s"), string);
5442 g_free (string);
5443 return res;
5446 return string;
5449 static char *
5450 nautilus_file_get_type_as_string (NautilusFile *file)
5452 if (file == NULL) {
5453 return NULL;
5456 if (nautilus_file_is_broken_symbolic_link (file)) {
5457 return g_strdup (_("link (broken)"));
5460 return update_description_for_link (file, get_description (file));
5464 * nautilus_file_get_file_type
5466 * Return this file's type.
5467 * @file: NautilusFile representing the file in question.
5469 * Returns: The type.
5472 GFileType
5473 nautilus_file_get_file_type (NautilusFile *file)
5475 if (file == NULL) {
5476 return G_FILE_TYPE_UNKNOWN;
5479 return file->details->type;
5483 * nautilus_file_get_mime_type
5485 * Return this file's default mime type.
5486 * @file: NautilusFile representing the file in question.
5488 * Returns: The mime type.
5491 char *
5492 nautilus_file_get_mime_type (NautilusFile *file)
5494 if (file != NULL) {
5495 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
5496 if (file->details->mime_type != NULL) {
5497 return g_strdup (eel_ref_str_peek (file->details->mime_type));
5500 return g_strdup ("application/octet-stream");
5504 * nautilus_file_is_mime_type
5506 * Check whether a file is of a particular MIME type, or inherited
5507 * from it.
5508 * @file: NautilusFile representing the file in question.
5509 * @mime_type: The MIME-type string to test (e.g. "text/plain")
5511 * Return value: TRUE if @mime_type exactly matches the
5512 * file's MIME type.
5515 gboolean
5516 nautilus_file_is_mime_type (NautilusFile *file, const char *mime_type)
5518 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
5519 g_return_val_if_fail (mime_type != NULL, FALSE);
5521 if (file->details->mime_type == NULL) {
5522 return FALSE;
5524 return g_content_type_is_a (eel_ref_str_peek (file->details->mime_type),
5525 mime_type);
5528 gboolean
5529 nautilus_file_is_launchable (NautilusFile *file)
5531 gboolean type_can_be_executable;
5533 type_can_be_executable = FALSE;
5534 if (file->details->mime_type != NULL) {
5535 type_can_be_executable =
5536 g_content_type_can_be_executable (eel_ref_str_peek (file->details->mime_type));
5539 return type_can_be_executable &&
5540 nautilus_file_can_get_permissions (file) &&
5541 nautilus_file_can_execute (file) &&
5542 nautilus_file_is_executable (file) &&
5543 !nautilus_file_is_directory (file);
5548 * nautilus_file_get_emblem_icons
5550 * Return the list of names of emblems that this file should display,
5551 * in canonical order.
5552 * @file: NautilusFile representing the file in question.
5554 * Returns: A list of emblem names.
5557 GList *
5558 nautilus_file_get_emblem_icons (NautilusFile *file,
5559 char **exclude)
5561 GList *keywords, *l;
5562 GList *icons;
5563 char *icon_name;
5564 char *keyword;
5565 int i;
5566 GIcon *icon;
5568 if (file == NULL) {
5569 return NULL;
5572 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
5574 keywords = nautilus_file_get_keywords (file);
5575 keywords = prepend_automatic_keywords (file, keywords);
5577 icons = NULL;
5578 for (l = keywords; l != NULL; l = l->next) {
5579 keyword = l->data;
5581 #ifdef TRASH_IS_FAST_ENOUGH
5582 if (strcmp (keyword, NAUTILUS_FILE_EMBLEM_NAME_TRASH) == 0) {
5583 char *uri;
5584 gboolean file_is_trash;
5585 /* Leave out the trash emblem for the trash itself, since
5586 * putting a trash emblem on a trash icon is gilding the
5587 * lily.
5589 uri = nautilus_file_get_uri (file);
5590 file_is_trash = strcmp (uri, EEL_TRASH_URI) == 0;
5591 g_free (uri);
5592 if (file_is_trash) {
5593 continue;
5596 #endif
5597 if (exclude) {
5598 for (i = 0; exclude[i] != NULL; i++) {
5599 if (strcmp (exclude[i], keyword) == 0) {
5600 continue;
5605 icon_name = nautilus_icon_get_emblem_icon_by_name (keyword);
5606 icon = g_themed_icon_new (icon_name);
5607 g_free (icon_name);
5608 icons = g_list_prepend (icons, icon);
5611 eel_g_list_free_deep (keywords);
5613 return icons;
5616 GList *
5617 nautilus_file_get_emblem_pixbufs (NautilusFile *file,
5618 int size,
5619 gboolean force_size,
5620 char **exclude)
5622 GList *icons, *l;
5623 GList *pixbufs;
5624 GIcon *icon;
5625 GdkPixbuf *pixbuf;
5626 NautilusIconInfo *icon_info;
5628 icons = nautilus_file_get_emblem_icons (file, exclude);
5629 pixbufs = NULL;
5631 for (l = icons; l != NULL; l = l->next) {
5632 icon = l->data;
5634 icon_info = nautilus_icon_info_lookup (icon, size);
5635 if (force_size) {
5636 pixbuf = nautilus_icon_info_get_pixbuf_nodefault_at_size (icon_info, size);
5637 } else {
5638 pixbuf = nautilus_icon_info_get_pixbuf_nodefault (icon_info);
5641 if (pixbuf) {
5642 pixbufs = g_list_prepend (pixbufs, pixbuf);
5646 g_object_unref (icon_info);
5647 g_object_unref (icon);
5649 g_list_free (icons);
5651 return g_list_reverse (pixbufs);
5656 static GList *
5657 sort_keyword_list_and_remove_duplicates (GList *keywords)
5659 GList *p;
5660 GList *duplicate_link;
5662 if (keywords != NULL) {
5663 keywords = eel_g_str_list_alphabetize (keywords);
5665 p = keywords;
5666 while (p->next != NULL) {
5667 if (strcmp ((const char *) p->data, (const char *) p->next->data) == 0) {
5668 duplicate_link = p->next;
5669 keywords = g_list_remove_link (keywords, duplicate_link);
5670 eel_g_list_free_deep (duplicate_link);
5671 } else {
5672 p = p->next;
5677 return keywords;
5681 * nautilus_file_get_keywords
5683 * Return this file's keywords.
5684 * @file: NautilusFile representing the file in question.
5686 * Returns: A list of keywords.
5689 GList *
5690 nautilus_file_get_keywords (NautilusFile *file)
5692 GList *keywords;
5694 if (file == NULL) {
5695 return NULL;
5698 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
5700 /* Put all the keywords into a list. */
5701 keywords = nautilus_file_get_metadata_list
5702 (file, "keyword", "name");
5704 keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->extension_emblems));
5705 keywords = g_list_concat (keywords, eel_g_str_list_copy (file->details->pending_extension_emblems));
5707 return sort_keyword_list_and_remove_duplicates (keywords);
5711 * nautilus_file_set_keywords
5713 * Change this file's keywords.
5714 * @file: NautilusFile representing the file in question.
5715 * @keywords: New set of keywords (a GList of strings).
5718 void
5719 nautilus_file_set_keywords (NautilusFile *file, GList *keywords)
5721 GList *canonical_keywords;
5723 /* Invalidate the emblem compare cache */
5724 g_free (file->details->compare_by_emblem_cache);
5725 file->details->compare_by_emblem_cache = NULL;
5727 g_return_if_fail (NAUTILUS_IS_FILE (file));
5729 canonical_keywords = sort_keyword_list_and_remove_duplicates
5730 (g_list_copy (keywords));
5731 nautilus_file_set_metadata_list
5732 (file, "keyword", "name", canonical_keywords);
5733 g_list_free (canonical_keywords);
5737 * nautilus_file_is_symbolic_link
5739 * Check if this file is a symbolic link.
5740 * @file: NautilusFile representing the file in question.
5742 * Returns: True if the file is a symbolic link.
5745 gboolean
5746 nautilus_file_is_symbolic_link (NautilusFile *file)
5748 return file->details->is_symlink;
5751 gboolean
5752 nautilus_file_is_mountpoint (NautilusFile *file)
5754 return file->details->is_mountpoint;
5757 GMount *
5758 nautilus_file_get_mount (NautilusFile *file)
5760 if (file->details->mount) {
5761 return g_object_ref (file->details->mount);
5763 return NULL;
5767 * nautilus_file_is_broken_symbolic_link
5769 * Check if this file is a symbolic link with a missing target.
5770 * @file: NautilusFile representing the file in question.
5772 * Returns: True if the file is a symbolic link with a missing target.
5775 gboolean
5776 nautilus_file_is_broken_symbolic_link (NautilusFile *file)
5778 if (file == NULL) {
5779 return FALSE;
5782 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
5784 /* Non-broken symbolic links return the target's type for get_file_type. */
5785 return nautilus_file_get_file_type (file) == G_FILE_TYPE_SYMBOLIC_LINK;
5789 * nautilus_file_get_volume_free_space
5790 * Get a nicely formatted char with free space on the file's volume
5791 * @file: NautilusFile representing the file in question.
5793 * Returns: newly-allocated copy of file size in a formatted string
5795 char *
5796 nautilus_file_get_volume_free_space (NautilusFile *file)
5798 goffset free_space;
5799 GFileInfo *info;
5800 GFile *location;
5801 char *res;
5803 res = NULL;
5805 location = nautilus_file_get_location (file);
5806 info = g_file_query_filesystem_info (location, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, NULL, NULL);
5807 if (info) {
5808 if (g_file_info_has_attribute (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE)) {
5809 free_space = g_file_info_get_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE);
5810 res = g_format_size_for_display (free_space);
5812 g_object_unref (info);
5814 g_object_unref (location);
5816 return res;
5820 * nautilus_file_get_volume_name
5821 * Get the path of the volume the file resides on
5822 * @file: NautilusFile representing the file in question.
5824 * Returns: newly-allocated copy of the volume name of the target file,
5825 * if the volume name isn't set, it returns the mount path of the volume
5827 char *
5828 nautilus_file_get_volume_name (NautilusFile *file)
5830 GFile *location;
5831 char *res;
5832 GMount *mount;
5834 res = NULL;
5836 location = nautilus_file_get_location (file);
5837 mount = g_file_find_enclosing_mount (location, NULL, NULL);
5838 if (mount) {
5839 res = g_strdup (g_mount_get_name (mount));
5840 g_object_unref (mount);
5842 g_object_unref (location);
5844 return res;
5848 * nautilus_file_get_symbolic_link_target_path
5850 * Get the file path of the target of a symbolic link. It is an error
5851 * to call this function on a file that isn't a symbolic link.
5852 * @file: NautilusFile representing the symbolic link in question.
5854 * Returns: newly-allocated copy of the file path of the target of the symbolic link.
5856 char *
5857 nautilus_file_get_symbolic_link_target_path (NautilusFile *file)
5859 g_return_val_if_fail (nautilus_file_is_symbolic_link (file), NULL);
5861 return g_strdup (file->details->symlink_name);
5865 * nautilus_file_get_symbolic_link_target_uri
5867 * Get the uri of the target of a symbolic link. It is an error
5868 * to call this function on a file that isn't a symbolic link.
5869 * @file: NautilusFile representing the symbolic link in question.
5871 * Returns: newly-allocated copy of the uri of the target of the symbolic link.
5873 char *
5874 nautilus_file_get_symbolic_link_target_uri (NautilusFile *file)
5876 GFile *location, *parent, *target;
5877 char *target_uri;
5879 g_return_val_if_fail (nautilus_file_is_symbolic_link (file), NULL);
5881 if (file->details->symlink_name == NULL) {
5882 return NULL;
5883 } else {
5884 target = NULL;
5886 location = nautilus_file_get_location (file);
5887 parent = g_file_get_parent (location);
5888 g_object_unref (location);
5889 if (parent) {
5890 target = g_file_resolve_relative_path (parent, file->details->symlink_name);
5891 g_object_unref (parent);
5894 target_uri = NULL;
5895 if (target) {
5896 target_uri = g_file_get_uri (target);
5897 g_object_unref (target);
5899 return target_uri;
5904 * nautilus_file_is_nautilus_link
5906 * Check if this file is a "nautilus link", meaning a historical
5907 * nautilus xml link file or a desktop file.
5908 * @file: NautilusFile representing the file in question.
5910 * Returns: True if the file is a nautilus link.
5913 gboolean
5914 nautilus_file_is_nautilus_link (NautilusFile *file)
5916 /* NOTE: I removed the historical link here, because i don't think we
5917 even detect that mimetype anymore */
5918 return nautilus_file_is_mime_type (file, "application/x-desktop");
5922 * nautilus_file_is_directory
5924 * Check if this file is a directory.
5925 * @file: NautilusFile representing the file in question.
5927 * Returns: TRUE if @file is a directory.
5930 gboolean
5931 nautilus_file_is_directory (NautilusFile *file)
5933 return nautilus_file_get_file_type (file) == G_FILE_TYPE_DIRECTORY;
5937 * nautilus_file_is_in_trash
5939 * Check if this file is a file in trash.
5940 * @file: NautilusFile representing the file in question.
5942 * Returns: TRUE if @file is in a trash.
5945 gboolean
5946 nautilus_file_is_in_trash (NautilusFile *file)
5948 g_assert (NAUTILUS_IS_FILE (file));
5950 return nautilus_directory_is_in_trash (file->details->directory);
5953 GError *
5954 nautilus_file_get_file_info_error (NautilusFile *file)
5956 if (!file->details->get_info_failed) {
5957 return NULL;
5960 return file->details->get_info_error;
5964 * nautilus_file_contains_text
5966 * Check if this file contains text.
5967 * This is private and is used to decide whether or not to read the top left text.
5968 * @file: NautilusFile representing the file in question.
5970 * Returns: TRUE if @file has a text MIME type.
5973 gboolean
5974 nautilus_file_contains_text (NautilusFile *file)
5976 if (file == NULL) {
5977 return FALSE;
5980 /* All text files inherit from text/plain */
5981 return nautilus_file_is_mime_type (file, "text/plain");
5985 * nautilus_file_is_executable
5987 * Check if this file is executable at all.
5988 * @file: NautilusFile representing the file in question.
5990 * Returns: TRUE if any of the execute bits are set. FALSE if
5991 * not, or if the permissions are unknown.
5994 gboolean
5995 nautilus_file_is_executable (NautilusFile *file)
5997 if (!file->details->has_permissions) {
5998 /* File's permissions field is not valid.
5999 * Can't access specific permissions, so return FALSE.
6001 return FALSE;
6004 return file->details->can_execute;
6008 * nautilus_file_peek_top_left_text
6010 * Peek at the text from the top left of the file.
6011 * @file: NautilusFile representing the file in question.
6013 * Returns: NULL if there is no text readable, otherwise, the text.
6014 * This string is owned by the file object and should not
6015 * be kept around or freed.
6018 char *
6019 nautilus_file_peek_top_left_text (NautilusFile *file,
6020 gboolean need_large_text,
6021 gboolean *needs_loading)
6023 g_return_val_if_fail (NAUTILUS_IS_FILE (file), NULL);
6025 if (!nautilus_file_should_get_top_left_text (file)) {
6026 if (needs_loading) {
6027 *needs_loading = FALSE;
6029 return NULL;
6032 if (needs_loading) {
6033 *needs_loading = !file->details->top_left_text_is_up_to_date;
6034 if (need_large_text) {
6035 *needs_loading |= file->details->got_top_left_text != file->details->got_large_top_left_text;
6039 /* Show " ..." in the file until we read the contents in. */
6040 if (!file->details->got_top_left_text) {
6042 if (nautilus_file_contains_text (file)) {
6043 return " ...";
6045 return NULL;
6048 /* Show what we read in. */
6049 return file->details->top_left_text;
6053 * nautilus_file_get_top_left_text
6055 * Get the text from the top left of the file.
6056 * @file: NautilusFile representing the file in question.
6058 * Returns: NULL if there is no text readable, otherwise, the text.
6061 char *
6062 nautilus_file_get_top_left_text (NautilusFile *file)
6064 return g_strdup (nautilus_file_peek_top_left_text (file, FALSE, NULL));
6068 void
6069 nautilus_file_mark_gone (NautilusFile *file)
6071 NautilusDirectory *directory;
6073 if (file->details->is_gone)
6074 return;
6076 file->details->is_gone = TRUE;
6078 update_links_if_target (file);
6080 /* Drop it from the symlink hash ! */
6081 remove_from_link_hash_table (file);
6083 /* Let the directory know it's gone. */
6084 directory = file->details->directory;
6085 if (!nautilus_file_is_self_owned (file)) {
6086 nautilus_directory_remove_file (directory, file);
6089 nautilus_file_clear_info (file);
6091 /* FIXME bugzilla.gnome.org 42429:
6092 * Maybe we can get rid of the name too eventually, but
6093 * for now that would probably require too many if statements
6094 * everywhere anyone deals with the name. Maybe we can give it
6095 * a hard-coded "<deleted>" name or something.
6100 * nautilus_file_changed
6102 * Notify the user that this file has changed.
6103 * @file: NautilusFile representing the file in question.
6105 void
6106 nautilus_file_changed (NautilusFile *file)
6108 GList fake_list;
6110 g_return_if_fail (NAUTILUS_IS_FILE (file));
6112 if (nautilus_file_is_self_owned (file)) {
6113 nautilus_file_emit_changed (file);
6114 } else {
6115 fake_list.data = file;
6116 fake_list.next = NULL;
6117 fake_list.prev = NULL;
6118 nautilus_directory_emit_change_signals
6119 (file->details->directory, &fake_list);
6124 * nautilus_file_updated_deep_count_in_progress
6126 * Notify clients that a newer deep count is available for
6127 * the directory in question.
6129 void
6130 nautilus_file_updated_deep_count_in_progress (NautilusFile *file) {
6131 GList *link_files, *node;
6133 g_assert (NAUTILUS_IS_FILE (file));
6134 g_assert (nautilus_file_is_directory (file));
6136 /* Send out a signal. */
6137 g_signal_emit (file, signals[UPDATED_DEEP_COUNT_IN_PROGRESS], 0, file);
6139 /* Tell link files pointing to this object about the change. */
6140 link_files = get_link_files (file);
6141 for (node = link_files; node != NULL; node = node->next) {
6142 nautilus_file_updated_deep_count_in_progress (NAUTILUS_FILE (node->data));
6144 nautilus_file_list_free (link_files);
6148 * nautilus_file_emit_changed
6150 * Emit a file changed signal.
6151 * This can only be called by the directory, since the directory
6152 * also has to emit a files_changed signal.
6154 * @file: NautilusFile representing the file in question.
6156 void
6157 nautilus_file_emit_changed (NautilusFile *file)
6159 GList *link_files, *p;
6161 g_assert (NAUTILUS_IS_FILE (file));
6164 /* Invalidate the emblem compare cache. -- This is not the cleanest
6165 * place to do it but it is the one guaranteed bottleneck through
6166 * which all change notifications pass.
6168 g_free (file->details->compare_by_emblem_cache);
6169 file->details->compare_by_emblem_cache = NULL;
6171 /* Send out a signal. */
6172 g_signal_emit (file, signals[CHANGED], 0, file);
6174 /* Tell link files pointing to this object about the change. */
6175 link_files = get_link_files (file);
6176 for (p = link_files; p != NULL; p = p->next) {
6177 if (p->data != file) {
6178 nautilus_file_changed (NAUTILUS_FILE (p->data));
6181 nautilus_file_list_free (link_files);
6185 * nautilus_file_is_gone
6187 * Check if a file has already been deleted.
6188 * @file: NautilusFile representing the file in question.
6190 * Returns: TRUE if the file is already gone.
6192 gboolean
6193 nautilus_file_is_gone (NautilusFile *file)
6195 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6197 return file->details->is_gone;
6201 * nautilus_file_is_not_yet_confirmed
6203 * Check if we're in a state where we don't know if a file really
6204 * exists or not, before the initial I/O is complete.
6205 * @file: NautilusFile representing the file in question.
6207 * Returns: TRUE if the file is already gone.
6209 gboolean
6210 nautilus_file_is_not_yet_confirmed (NautilusFile *file)
6212 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6214 return !file->details->got_file_info;
6218 * nautilus_file_check_if_ready
6220 * Check whether the values for a set of file attributes are
6221 * currently available, without doing any additional work. This
6222 * is useful for callers that want to reflect updated information
6223 * when it is ready but don't want to force the work required to
6224 * obtain the information, which might be slow network calls, e.g.
6226 * @file: The file being queried.
6227 * @file_attributes: A bit-mask with the desired information.
6229 * Return value: TRUE if all of the specified attributes are currently readable.
6231 gboolean
6232 nautilus_file_check_if_ready (NautilusFile *file,
6233 NautilusFileAttributes file_attributes)
6235 /* To be parallel with call_when_ready, return
6236 * TRUE for NULL file.
6238 if (file == NULL) {
6239 return TRUE;
6242 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6244 return EEL_CALL_METHOD_WITH_RETURN_VALUE
6245 (NAUTILUS_FILE_CLASS, file,
6246 check_if_ready, (file, file_attributes));
6249 void
6250 nautilus_file_call_when_ready (NautilusFile *file,
6251 NautilusFileAttributes file_attributes,
6252 NautilusFileCallback callback,
6253 gpointer callback_data)
6256 if (file == NULL) {
6257 (* callback) (file, callback_data);
6258 return;
6261 g_return_if_fail (NAUTILUS_IS_FILE (file));
6263 EEL_CALL_METHOD
6264 (NAUTILUS_FILE_CLASS, file,
6265 call_when_ready, (file, file_attributes,
6266 callback, callback_data));
6269 void
6270 nautilus_file_cancel_call_when_ready (NautilusFile *file,
6271 NautilusFileCallback callback,
6272 gpointer callback_data)
6274 g_return_if_fail (callback != NULL);
6276 if (file == NULL) {
6277 return;
6280 g_return_if_fail (NAUTILUS_IS_FILE (file));
6282 EEL_CALL_METHOD
6283 (NAUTILUS_FILE_CLASS, file,
6284 cancel_call_when_ready, (file, callback, callback_data));
6287 static void
6288 invalidate_directory_count (NautilusFile *file)
6290 file->details->directory_count_is_up_to_date = FALSE;
6293 static void
6294 invalidate_deep_counts (NautilusFile *file)
6296 file->details->deep_counts_status = NAUTILUS_REQUEST_NOT_STARTED;
6299 static void
6300 invalidate_mime_list (NautilusFile *file)
6302 file->details->mime_list_is_up_to_date = FALSE;
6305 static void
6306 invalidate_top_left_text (NautilusFile *file)
6308 file->details->top_left_text_is_up_to_date = FALSE;
6311 static void
6312 invalidate_file_info (NautilusFile *file)
6314 file->details->file_info_is_up_to_date = FALSE;
6317 static void
6318 invalidate_link_info (NautilusFile *file)
6320 file->details->link_info_is_up_to_date = FALSE;
6323 static void
6324 invalidate_thumbnail (NautilusFile *file)
6326 file->details->thumbnail_is_up_to_date = FALSE;
6329 void
6330 nautilus_file_invalidate_extension_info_internal (NautilusFile *file)
6332 file->details->pending_info_providers =
6333 nautilus_module_get_extensions_for_type (NAUTILUS_TYPE_INFO_PROVIDER);
6336 void
6337 nautilus_file_invalidate_attributes_internal (NautilusFile *file,
6338 NautilusFileAttributes file_attributes)
6340 Request request;
6342 if (file == NULL) {
6343 return;
6346 if (NAUTILUS_IS_DESKTOP_ICON_FILE (file)) {
6347 /* Desktop icon files are always up to date.
6348 * If we invalidate their attributes they
6349 * will lose data, so we just ignore them.
6351 return;
6354 nautilus_directory_set_up_request (&request, file_attributes);
6356 if (request.directory_count) {
6357 invalidate_directory_count (file);
6359 if (request.deep_count) {
6360 invalidate_deep_counts (file);
6362 if (request.mime_list) {
6363 invalidate_mime_list (file);
6365 if (request.file_info) {
6366 invalidate_file_info (file);
6368 if (request.top_left_text) {
6369 invalidate_top_left_text (file);
6371 if (request.link_info) {
6372 invalidate_link_info (file);
6374 if (request.extension_info) {
6375 nautilus_file_invalidate_extension_info_internal (file);
6377 if (request.thumbnail) {
6378 invalidate_thumbnail (file);
6381 /* FIXME bugzilla.gnome.org 45075: implement invalidating metadata */
6384 gboolean
6385 nautilus_file_has_open_window (NautilusFile *file)
6387 return file->details->has_open_window;
6390 void
6391 nautilus_file_set_has_open_window (NautilusFile *file,
6392 gboolean has_open_window)
6394 has_open_window = (has_open_window != FALSE);
6396 if (file->details->has_open_window != has_open_window) {
6397 file->details->has_open_window = has_open_window;
6398 nautilus_file_changed (file);
6403 gboolean
6404 nautilus_file_is_thumbnailing (NautilusFile *file)
6406 g_return_val_if_fail (NAUTILUS_IS_FILE (file), FALSE);
6408 return file->details->is_thumbnailing;
6411 void
6412 nautilus_file_set_is_thumbnailing (NautilusFile *file,
6413 gboolean is_thumbnailing)
6415 g_return_if_fail (NAUTILUS_IS_FILE (file));
6417 file->details->is_thumbnailing = is_thumbnailing;
6422 * nautilus_file_invalidate_attributes
6424 * Invalidate the specified attributes and force a reload.
6425 * @file: NautilusFile representing the file in question.
6426 * @file_attributes: attributes to froget.
6429 void
6430 nautilus_file_invalidate_attributes (NautilusFile *file,
6431 NautilusFileAttributes file_attributes)
6433 /* Cancel possible in-progress loads of any of these attributes */
6434 nautilus_directory_cancel_loading_file_attributes (file->details->directory,
6435 file,
6436 file_attributes);
6438 /* Actually invalidate the values */
6439 nautilus_file_invalidate_attributes_internal (file, file_attributes);
6441 nautilus_directory_add_file_to_work_queue (file->details->directory, file);
6443 /* Kick off I/O if necessary */
6444 nautilus_directory_async_state_changed (file->details->directory);
6447 NautilusFileAttributes
6448 nautilus_file_get_all_attributes (void)
6450 return NAUTILUS_FILE_ATTRIBUTE_INFO |
6451 NAUTILUS_FILE_ATTRIBUTE_LINK_INFO |
6452 NAUTILUS_FILE_ATTRIBUTE_DEEP_COUNTS |
6453 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_COUNT |
6454 NAUTILUS_FILE_ATTRIBUTE_DIRECTORY_ITEM_MIME_TYPES |
6455 NAUTILUS_FILE_ATTRIBUTE_METADATA |
6456 NAUTILUS_FILE_ATTRIBUTE_TOP_LEFT_TEXT |
6457 NAUTILUS_FILE_ATTRIBUTE_LARGE_TOP_LEFT_TEXT |
6458 NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO |
6459 NAUTILUS_FILE_ATTRIBUTE_THUMBNAIL |
6460 NAUTILUS_FILE_ATTRIBUTE_MOUNT;
6463 void
6464 nautilus_file_invalidate_all_attributes (NautilusFile *file)
6466 NautilusFileAttributes all_attributes;
6468 all_attributes = nautilus_file_get_all_attributes ();
6469 nautilus_file_invalidate_attributes (file, all_attributes);
6474 * nautilus_file_dump
6476 * Debugging call, prints out the contents of the file
6477 * fields.
6479 * @file: file to dump.
6481 void
6482 nautilus_file_dump (NautilusFile *file)
6484 long size = file->details->deep_size;
6485 char *uri;
6486 const char *file_kind;
6488 uri = nautilus_file_get_uri (file);
6489 g_print ("uri: %s \n", uri);
6490 if (!file->details->got_file_info) {
6491 g_print ("no file info \n");
6492 } else if (file->details->get_info_failed) {
6493 g_print ("failed to get file info \n");
6494 } else {
6495 g_print ("size: %ld \n", size);
6496 switch (file->details->type) {
6497 case G_FILE_TYPE_REGULAR:
6498 file_kind = "regular file";
6499 break;
6500 case G_FILE_TYPE_DIRECTORY:
6501 file_kind = "folder";
6502 break;
6503 case G_FILE_TYPE_SPECIAL:
6504 file_kind = "special";
6505 break;
6506 case G_FILE_TYPE_SYMBOLIC_LINK:
6507 file_kind = "symbolic link";
6508 break;
6509 case G_FILE_TYPE_UNKNOWN:
6510 default:
6511 file_kind = "unknown";
6512 break;
6514 g_print ("kind: %s \n", file_kind);
6515 if (file->details->type == G_FILE_TYPE_SYMBOLIC_LINK) {
6516 g_print ("link to %s \n", file->details->symlink_name);
6517 /* FIXME bugzilla.gnome.org 42430: add following of symlinks here */
6519 /* FIXME bugzilla.gnome.org 42431: add permissions and other useful stuff here */
6521 g_free (uri);
6525 * nautilus_file_list_ref
6527 * Ref all the files in a list.
6528 * @list: GList of files.
6530 GList *
6531 nautilus_file_list_ref (GList *list)
6533 g_list_foreach (list, (GFunc) nautilus_file_ref, NULL);
6534 return list;
6538 * nautilus_file_list_unref
6540 * Unref all the files in a list.
6541 * @list: GList of files.
6543 void
6544 nautilus_file_list_unref (GList *list)
6546 g_list_foreach (list, (GFunc) nautilus_file_unref, NULL);
6550 * nautilus_file_list_free
6552 * Free a list of files after unrefing them.
6553 * @list: GList of files.
6555 void
6556 nautilus_file_list_free (GList *list)
6558 nautilus_file_list_unref (list);
6559 g_list_free (list);
6563 * nautilus_file_list_copy
6565 * Copy the list of files, making a new ref of each,
6566 * @list: GList of files.
6568 GList *
6569 nautilus_file_list_copy (GList *list)
6571 return g_list_copy (nautilus_file_list_ref (list));
6574 static int
6575 compare_by_display_name_cover (gconstpointer a, gconstpointer b)
6577 return compare_by_display_name (NAUTILUS_FILE (a), NAUTILUS_FILE (b));
6581 * nautilus_file_list_sort_by_display_name
6583 * Sort the list of files by file name.
6584 * @list: GList of files.
6586 GList *
6587 nautilus_file_list_sort_by_display_name (GList *list)
6589 return g_list_sort (list, compare_by_display_name_cover);
6592 static GList *ready_data_list = NULL;
6594 typedef struct
6596 GList *file_list;
6597 GList *remaining_files;
6598 NautilusFileListCallback callback;
6599 gpointer callback_data;
6600 } FileListReadyData;
6602 static void
6603 file_list_ready_data_free (FileListReadyData *data)
6605 GList *l;
6607 l = g_list_find (ready_data_list, data);
6608 if (l != NULL) {
6609 ready_data_list = g_list_delete_link (ready_data_list, l);
6611 nautilus_file_list_free (data->file_list);
6612 g_list_free (data->remaining_files);
6613 g_free (data);
6617 static FileListReadyData *
6618 file_list_ready_data_new (GList *file_list,
6619 NautilusFileListCallback callback,
6620 gpointer callback_data)
6622 FileListReadyData *data;
6624 data = g_new0 (FileListReadyData, 1);
6625 data->file_list = nautilus_file_list_copy (file_list);
6626 data->remaining_files = g_list_copy (file_list);
6627 data->callback = callback;
6628 data->callback_data = callback_data;
6630 ready_data_list = g_list_prepend (ready_data_list, data);
6632 return data;
6635 static void
6636 file_list_file_ready_callback (NautilusFile *file,
6637 gpointer user_data)
6639 FileListReadyData *data;
6641 data = user_data;
6642 data->remaining_files = g_list_remove (data->remaining_files, file);
6644 if (data->remaining_files == NULL) {
6645 if (data->callback) {
6646 (*data->callback) (data->file_list, data->callback_data);
6649 file_list_ready_data_free (data);
6653 void
6654 nautilus_file_list_call_when_ready (GList *file_list,
6655 NautilusFileAttributes attributes,
6656 NautilusFileListHandle **handle,
6657 NautilusFileListCallback callback,
6658 gpointer callback_data)
6660 GList *l;
6661 FileListReadyData *data;
6662 NautilusFile *file;
6664 g_return_if_fail (file_list != NULL);
6666 data = file_list_ready_data_new
6667 (file_list, callback, callback_data);
6669 if (handle) {
6670 *handle = (NautilusFileListHandle *) data;
6674 l = file_list;
6675 while (l != NULL) {
6676 file = NAUTILUS_FILE (l->data);
6677 /* Need to do this here, as the list can be modified by this call */
6678 l = l->next;
6679 nautilus_file_call_when_ready (file,
6680 attributes,
6681 file_list_file_ready_callback,
6682 data);
6686 void
6687 nautilus_file_list_cancel_call_when_ready (NautilusFileListHandle *handle)
6689 GList *l;
6690 NautilusFile *file;
6691 FileListReadyData *data;
6693 g_return_if_fail (handle != NULL);
6695 data = (FileListReadyData *) handle;
6697 l = g_list_find (ready_data_list, data);
6698 if (l != NULL) {
6699 for (l = data->remaining_files; l != NULL; l = l->next) {
6700 file = NAUTILUS_FILE (l->data);
6702 EEL_CALL_METHOD
6703 (NAUTILUS_FILE_CLASS, file,
6704 cancel_call_when_ready, (file, file_list_file_ready_callback, data));
6707 file_list_ready_data_free (data);
6711 static char *
6712 try_to_make_utf8 (const char *text, int *length)
6714 static const char *encodings_to_try[2];
6715 static int n_encodings_to_try = 0;
6716 gsize converted_length;
6717 GError *conversion_error;
6718 char *utf8_text;
6719 int i;
6721 if (n_encodings_to_try == 0) {
6722 const char *charset;
6723 gboolean charset_is_utf8;
6725 charset_is_utf8 = g_get_charset (&charset);
6726 if (!charset_is_utf8) {
6727 encodings_to_try[n_encodings_to_try++] = charset;
6730 if (g_ascii_strcasecmp (charset, "ISO-8859-1") != 0) {
6731 encodings_to_try[n_encodings_to_try++] = "ISO-8859-1";
6735 utf8_text = NULL;
6736 for (i = 0; i < n_encodings_to_try; i++) {
6737 conversion_error = NULL;
6738 utf8_text = g_convert (text, *length,
6739 "UTF-8", encodings_to_try[i],
6740 NULL, &converted_length, &conversion_error);
6741 if (utf8_text != NULL) {
6742 *length = converted_length;
6743 break;
6745 g_error_free (conversion_error);
6748 return utf8_text;
6753 /* Extract the top left part of the read-in text. */
6754 char *
6755 nautilus_extract_top_left_text (const char *text,
6756 gboolean large,
6757 int length)
6759 GString* buffer;
6760 const gchar *in;
6761 const gchar *end;
6762 int line, i;
6763 gunichar c;
6764 char *text_copy;
6765 const char *utf8_end;
6766 gboolean validated;
6767 int max_bytes, max_lines, max_cols;
6769 if (large) {
6770 max_bytes = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_BYTES;
6771 max_lines = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_LINES;
6772 max_cols = NAUTILUS_FILE_LARGE_TOP_LEFT_TEXT_MAXIMUM_CHARACTERS_PER_LINE;
6773 } else {
6774 max_bytes = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_BYTES;
6775 max_lines = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_LINES;
6776 max_cols = NAUTILUS_FILE_TOP_LEFT_TEXT_MAXIMUM_CHARACTERS_PER_LINE;
6781 text_copy = NULL;
6782 if (text != NULL) {
6783 /* Might be a partial utf8 character at the end if we didn't read whole file */
6784 validated = g_utf8_validate (text, length, &utf8_end);
6785 if (!validated &&
6786 !(length >= max_bytes &&
6787 text + length - utf8_end < 6)) {
6788 text_copy = try_to_make_utf8 (text, &length);
6789 text = text_copy;
6790 } else if (!validated) {
6791 length = utf8_end - text;
6795 if (text == NULL || length == 0) {
6796 return NULL;
6799 buffer = g_string_new ("");
6800 end = text + length; in = text;
6802 for (line = 0; line < max_lines; line++) {
6803 /* Extract one line. */
6804 for (i = 0; i < max_cols; ) {
6805 if (*in == '\n') {
6806 break;
6809 c = g_utf8_get_char (in);
6811 if (g_unichar_isprint (c)) {
6812 g_string_append_unichar (buffer, c);
6813 i++;
6816 in = g_utf8_next_char (in);
6817 if (in == end) {
6818 goto done;
6822 /* Skip the rest of the line. */
6823 while (*in != '\n') {
6824 if (++in == end) {
6825 goto done;
6828 if (++in == end) {
6829 goto done;
6832 /* Put a new-line separator in. */
6833 g_string_append_c(buffer, '\n');
6835 done:
6836 g_free (text_copy);
6838 return g_string_free(buffer, FALSE);
6841 static void
6842 thumbnail_limit_changed_callback (gpointer user_data)
6844 cached_thumbnail_limit = eel_preferences_get_integer (NAUTILUS_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT);
6846 /* Tell the world that icons might have changed. We could invent a narrower-scope
6847 * signal to mean only "thumbnails might have changed" if this ends up being slow
6848 * for some reason.
6850 emit_change_signals_for_all_files_in_all_directories ();
6853 static void
6854 thumbnail_size_changed_callback (gpointer user_data)
6856 cached_thumbnail_size = eel_preferences_get_integer (NAUTILUS_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE);
6858 /* Tell the world that icons might have changed. We could invent a narrower-scope
6859 * signal to mean only "thumbnails might have changed" if this ends up being slow
6860 * for some reason.
6862 emit_change_signals_for_all_files_in_all_directories ();
6865 static void
6866 show_thumbnails_changed_callback (gpointer user_data)
6868 show_image_thumbs = eel_preferences_get_enum (NAUTILUS_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS);
6870 /* Tell the world that icons might have changed. We could invent a narrower-scope
6871 * signal to mean only "thumbnails might have changed" if this ends up being slow
6872 * for some reason.
6874 emit_change_signals_for_all_files_in_all_directories ();
6877 static void
6878 mime_type_data_changed_callback (GObject *signaller, gpointer user_data)
6880 /* Tell the world that icons might have changed. We could invent a narrower-scope
6881 * signal to mean only "thumbnails might have changed" if this ends up being slow
6882 * for some reason.
6884 emit_change_signals_for_all_files_in_all_directories ();
6887 static void
6888 icon_theme_changed_callback (GtkIconTheme *icon_theme,
6889 gpointer user_data)
6891 /* Clear all pixmap caches as the icon => pixmap lookup changed */
6892 nautilus_icon_info_clear_caches ();
6894 /* Tell the world that icons might have changed. We could invent a narrower-scope
6895 * signal to mean only "thumbnails might have changed" if this ends up being slow
6896 * for some reason.
6898 emit_change_signals_for_all_files_in_all_directories ();
6901 static void
6902 nautilus_file_class_init (NautilusFileClass *class)
6904 GtkIconTheme *icon_theme;
6906 parent_class = g_type_class_peek_parent (class);
6908 attribute_name_q = g_quark_from_static_string ("name");
6909 attribute_size_q = g_quark_from_static_string ("size");
6910 attribute_type_q = g_quark_from_static_string ("type");
6911 attribute_modification_date_q = g_quark_from_static_string ("modification_date");
6912 attribute_date_modified_q = g_quark_from_static_string ("date_modified");
6913 attribute_accessed_date_q = g_quark_from_static_string ("accessed_date");
6914 attribute_date_accessed_q = g_quark_from_static_string ("date_accessed");
6915 attribute_emblems_q = g_quark_from_static_string ("emblems");
6916 attribute_mime_type_q = g_quark_from_static_string ("mime_type");
6917 attribute_size_detail_q = g_quark_from_static_string ("size_detail");
6918 attribute_deep_size_q = g_quark_from_static_string ("deep_size");
6919 attribute_deep_file_count_q = g_quark_from_static_string ("deep_file_count");
6920 attribute_deep_directory_count_q = g_quark_from_static_string ("deep_directory_count");
6921 attribute_deep_total_count_q = g_quark_from_static_string ("deep_total_count");
6922 attribute_date_changed_q = g_quark_from_static_string ("date_changed");
6923 attribute_date_permissions_q = g_quark_from_static_string ("date_permissions");
6924 attribute_permissions_q = g_quark_from_static_string ("permissions");
6925 attribute_selinux_context_q = g_quark_from_static_string ("selinux_context");
6926 attribute_octal_permissions_q = g_quark_from_static_string ("octal_permissions");
6927 attribute_owner_q = g_quark_from_static_string ("owner");
6928 attribute_group_q = g_quark_from_static_string ("group");
6929 attribute_uri_q = g_quark_from_static_string ("uri");
6930 attribute_where_q = g_quark_from_static_string ("where");
6931 attribute_link_target_q = g_quark_from_static_string ("link_target");
6932 attribute_volume_q = g_quark_from_static_string ("volume");
6933 attribute_free_space_q = g_quark_from_static_string ("free_space");
6935 G_OBJECT_CLASS (class)->finalize = finalize;
6936 G_OBJECT_CLASS (class)->constructor = nautilus_file_constructor;
6938 signals[CHANGED] =
6939 g_signal_new ("changed",
6940 G_TYPE_FROM_CLASS (class),
6941 G_SIGNAL_RUN_LAST,
6942 G_STRUCT_OFFSET (NautilusFileClass, changed),
6943 NULL, NULL,
6944 g_cclosure_marshal_VOID__VOID,
6945 G_TYPE_NONE, 0);
6947 signals[UPDATED_DEEP_COUNT_IN_PROGRESS] =
6948 g_signal_new ("updated_deep_count_in_progress",
6949 G_TYPE_FROM_CLASS (class),
6950 G_SIGNAL_RUN_LAST,
6951 G_STRUCT_OFFSET (NautilusFileClass, updated_deep_count_in_progress),
6952 NULL, NULL,
6953 g_cclosure_marshal_VOID__VOID,
6954 G_TYPE_NONE, 0);
6956 g_type_class_add_private (class, sizeof (NautilusFileDetails));
6959 eel_preferences_add_auto_enum (NAUTILUS_PREFERENCES_DATE_FORMAT,
6960 &date_format_pref);
6962 thumbnail_limit_changed_callback (NULL);
6963 eel_preferences_add_callback (NAUTILUS_PREFERENCES_IMAGE_FILE_THUMBNAIL_LIMIT,
6964 thumbnail_limit_changed_callback,
6965 NULL);
6966 thumbnail_size_changed_callback (NULL);
6967 eel_preferences_add_callback (NAUTILUS_PREFERENCES_ICON_VIEW_THUMBNAIL_SIZE,
6968 thumbnail_size_changed_callback,
6969 NULL);
6970 show_thumbnails_changed_callback (NULL);
6971 eel_preferences_add_callback (NAUTILUS_PREFERENCES_SHOW_IMAGE_FILE_THUMBNAILS,
6972 show_thumbnails_changed_callback,
6973 NULL);
6975 icon_theme = gtk_icon_theme_get_default ();
6976 g_signal_connect_object (icon_theme,
6977 "changed",
6978 G_CALLBACK (icon_theme_changed_callback),
6979 NULL, 0);
6981 g_signal_connect (nautilus_signaller_get_current (),
6982 "mime_data_changed",
6983 G_CALLBACK (mime_type_data_changed_callback),
6984 NULL);
6987 static void
6988 nautilus_file_add_emblem (NautilusFile *file,
6989 const char *emblem_name)
6991 if (file->details->pending_info_providers) {
6992 file->details->pending_extension_emblems = g_list_prepend (file->details->pending_extension_emblems,
6993 g_strdup (emblem_name));
6994 } else {
6995 file->details->extension_emblems = g_list_prepend (file->details->extension_emblems,
6996 g_strdup (emblem_name));
6999 nautilus_file_changed (file);
7002 static void
7003 nautilus_file_add_string_attribute (NautilusFile *file,
7004 const char *attribute_name,
7005 const char *value)
7007 if (file->details->pending_info_providers) {
7008 /* Lazily create hashtable */
7009 if (!file->details->pending_extension_attributes) {
7010 file->details->pending_extension_attributes =
7011 g_hash_table_new_full (g_direct_hash, g_direct_equal,
7012 NULL,
7013 (GDestroyNotify)g_free);
7015 g_hash_table_insert (file->details->pending_extension_attributes,
7016 GINT_TO_POINTER (g_quark_from_string (attribute_name)),
7017 g_strdup (value));
7018 } else {
7019 if (!file->details->extension_attributes) {
7020 file->details->extension_attributes =
7021 g_hash_table_new_full (g_direct_hash, g_direct_equal,
7022 NULL,
7023 (GDestroyNotify)g_free);
7025 g_hash_table_insert (file->details->extension_attributes,
7026 GINT_TO_POINTER (g_quark_from_string (attribute_name)),
7027 g_strdup (value));
7030 nautilus_file_changed (file);
7033 static void
7034 nautilus_file_invalidate_extension_info (NautilusFile *file)
7036 nautilus_file_invalidate_attributes (file, NAUTILUS_FILE_ATTRIBUTE_EXTENSION_INFO);
7039 void
7040 nautilus_file_info_providers_done (NautilusFile *file)
7042 eel_g_list_free_deep (file->details->extension_emblems);
7043 file->details->extension_emblems = file->details->pending_extension_emblems;
7044 file->details->pending_extension_emblems = NULL;
7046 if (file->details->extension_attributes) {
7047 g_hash_table_destroy (file->details->extension_attributes);
7050 file->details->extension_attributes = file->details->pending_extension_attributes;
7051 file->details->pending_extension_attributes = NULL;
7053 nautilus_file_changed (file);
7056 static void
7057 nautilus_file_info_iface_init (NautilusFileInfoIface *iface)
7059 iface->is_gone = nautilus_file_is_gone;
7060 iface->get_name = nautilus_file_get_name;
7061 iface->get_file_type = nautilus_file_get_file_type;
7062 iface->get_location = nautilus_file_get_location;
7063 iface->get_uri = nautilus_file_get_uri;
7064 iface->get_parent_location = nautilus_file_get_parent_location;
7065 iface->get_parent_uri = nautilus_file_get_parent_uri;
7066 iface->get_parent_info = nautilus_file_get_parent;
7067 iface->get_mount = nautilus_file_get_mount;
7068 iface->get_uri_scheme = nautilus_file_get_uri_scheme;
7069 iface->get_activation_uri = nautilus_file_get_activation_uri;
7070 iface->get_mime_type = nautilus_file_get_mime_type;
7071 iface->is_mime_type = nautilus_file_is_mime_type;
7072 iface->is_directory = nautilus_file_is_directory;
7073 iface->can_write = nautilus_file_can_write;
7074 iface->add_emblem = nautilus_file_add_emblem;
7075 iface->get_string_attribute = nautilus_file_get_string_attribute;
7076 iface->add_string_attribute = nautilus_file_add_string_attribute;
7077 iface->invalidate_extension_info = nautilus_file_invalidate_extension_info;
7080 #if !defined (NAUTILUS_OMIT_SELF_CHECK)
7082 void
7083 nautilus_self_check_file (void)
7085 NautilusFile *file_1;
7086 NautilusFile *file_2;
7087 GList *list;
7089 /* refcount checks */
7091 EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
7093 file_1 = nautilus_file_get_by_uri ("file:///home/");
7095 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
7096 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1->details->directory)->ref_count, 1);
7097 EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 1);
7099 nautilus_file_unref (file_1);
7101 EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
7103 file_1 = nautilus_file_get_by_uri ("file:///etc");
7104 file_2 = nautilus_file_get_by_uri ("file:///usr");
7106 list = NULL;
7107 list = g_list_prepend (list, file_1);
7108 list = g_list_prepend (list, file_2);
7110 nautilus_file_list_ref (list);
7112 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 2);
7113 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 2);
7115 nautilus_file_list_unref (list);
7117 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
7118 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
7120 nautilus_file_list_free (list);
7122 EEL_CHECK_INTEGER_RESULT (nautilus_directory_number_outstanding (), 0);
7125 /* name checks */
7126 file_1 = nautilus_file_get_by_uri ("file:///home/");
7128 EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "home");
7130 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_get_by_uri ("file:///home/") == file_1, TRUE);
7131 nautilus_file_unref (file_1);
7133 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_get_by_uri ("file:///home") == file_1, TRUE);
7134 nautilus_file_unref (file_1);
7136 nautilus_file_unref (file_1);
7138 file_1 = nautilus_file_get_by_uri ("file:///home");
7139 EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "home");
7140 nautilus_file_unref (file_1);
7142 #if 0
7143 /* ALEX: I removed this, because it was breaking distchecks.
7144 * It used to work, but when canonical uris changed from
7145 * foo: to foo:/// it broke. I don't expect it to matter
7146 * in real life */
7147 file_1 = nautilus_file_get_by_uri (":");
7148 EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), ":");
7149 nautilus_file_unref (file_1);
7150 #endif
7152 file_1 = nautilus_file_get_by_uri ("eazel:");
7153 EEL_CHECK_STRING_RESULT (nautilus_file_get_name (file_1), "eazel");
7154 nautilus_file_unref (file_1);
7156 /* sorting */
7157 file_1 = nautilus_file_get_by_uri ("file:///etc");
7158 file_2 = nautilus_file_get_by_uri ("file:///usr");
7160 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_1)->ref_count, 1);
7161 EEL_CHECK_INTEGER_RESULT (G_OBJECT (file_2)->ref_count, 1);
7163 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_2, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) < 0, TRUE);
7164 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_2, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) > 0, TRUE);
7165 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, FALSE) == 0, TRUE);
7166 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, TRUE, FALSE) == 0, TRUE);
7167 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, FALSE, TRUE) == 0, TRUE);
7168 EEL_CHECK_BOOLEAN_RESULT (nautilus_file_compare_for_sort (file_1, file_1, NAUTILUS_FILE_SORT_BY_DISPLAY_NAME, TRUE, TRUE) == 0, TRUE);
7170 nautilus_file_unref (file_1);
7171 nautilus_file_unref (file_2);
7174 #endif /* !NAUTILUS_OMIT_SELF_CHECK */