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