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