1 /* GTK - The GIMP Toolkit
2 * gtkfilesystemunix.c: Default implementation of GtkFileSystem for UNIX-like systems
3 * Copyright (C) 2003, Red Hat, Inc.
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the
17 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
18 * Boston, MA 02111-1307, USA.
23 #include "gtkfilesystem.h"
24 #include "gtkfilesystemunix.h"
25 #include "gtkicontheme.h"
30 #define XDG_PREFIX _gtk_xdg
31 #include "xdgmime/xdgmime.h"
36 #include <sys/types.h>
44 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
46 #define HIDDEN_FILENAME ".hidden"
48 #define FOLDER_CACHE_LIFETIME 2 /* seconds */
50 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
52 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
53 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
54 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
56 struct _GtkFileSystemUnixClass
58 GObjectClass parent_class;
61 struct _GtkFileSystemUnix
63 GObject parent_instance;
65 GHashTable *folder_hash;
67 /* For /afs and /net */
68 struct stat afs_statbuf;
69 struct stat net_statbuf;
75 /* Icon type, supplemented by MIME type
78 ICON_UNDECIDED, /* Only used while we have not yet computed the icon in a struct stat_info_entry */
79 ICON_NONE, /* "Could not compute the icon type" */
80 ICON_REGULAR, /* Use mime type for icon */
82 ICON_BROKEN_SYMBOLIC_LINK,
83 ICON_CHARACTER_DEVICE,
91 #define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
92 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
93 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
94 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
95 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
96 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
98 typedef struct _GtkFileFolderUnix GtkFileFolderUnix;
99 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
101 struct _GtkFileFolderUnixClass
103 GObjectClass parent_class;
106 struct _GtkFileFolderUnix
108 GObject parent_instance;
110 GtkFileSystemUnix *system_unix;
111 GtkFileInfoType types;
113 GHashTable *stat_info;
115 guint have_mime_type : 1;
116 guint is_network_dir : 1;
117 guint have_hidden : 1;
121 struct stat_info_entry {
128 static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
129 GTK_FILE_INFO_MODIFICATION_TIME |
132 static GObjectClass *system_parent_class;
133 static GObjectClass *folder_parent_class;
135 static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class);
136 static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
137 static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
138 static void gtk_file_system_unix_finalize (GObject *object);
140 static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
141 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
142 const GtkFilePath *path);
144 static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
145 const GtkFilePath *path,
146 GtkFileInfoType types,
148 static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
149 const GtkFilePath *path,
152 static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
153 GtkFileSystemVolume *volume);
154 static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
155 GtkFileSystemVolume *volume);
156 static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
157 GtkFileSystemVolume *volume);
158 static gboolean gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
159 GtkFileSystemVolume *volume,
161 static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
162 GtkFileSystemVolume *volume);
163 static GdkPixbuf * gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
164 GtkFileSystemVolume *volume,
169 static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
170 const GtkFilePath *path,
171 GtkFilePath **parent,
173 static GtkFilePath * gtk_file_system_unix_make_path (GtkFileSystem *file_system,
174 const GtkFilePath *base_path,
175 const gchar *display_name,
177 static gboolean gtk_file_system_unix_parse (GtkFileSystem *file_system,
178 const GtkFilePath *base_path,
180 GtkFilePath **folder,
184 static gchar * gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
185 const GtkFilePath *path);
186 static gchar * gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
187 const GtkFilePath *path);
188 static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
190 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
191 const gchar *filename);
193 static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
194 const GtkFilePath *path,
199 static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
200 const GtkFilePath *path,
203 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
204 const GtkFilePath *path,
206 static GSList * gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system);
207 static gchar * gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
208 const GtkFilePath *path);
209 static void gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
210 const GtkFilePath *path,
213 static GType gtk_file_folder_unix_get_type (void);
214 static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
215 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
216 static void gtk_file_folder_unix_init (GtkFileFolderUnix *impl);
217 static void gtk_file_folder_unix_finalize (GObject *object);
219 static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
220 const GtkFilePath *path,
222 static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder,
226 static gboolean gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder);
228 static GtkFilePath *filename_to_path (const gchar *filename);
230 static gboolean filename_is_root (const char *filename);
232 static gboolean file_is_hidden (GtkFileFolderUnix *folder_unix,
233 const char *basename);
235 static gboolean fill_in_names (GtkFileFolderUnix *folder_unix, GError **error);
236 static void fill_in_stats (GtkFileFolderUnix *folder_unix);
237 static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
238 static void fill_in_hidden (GtkFileFolderUnix *folder_unix);
240 static char * get_parent_dir (const char *filename);
246 gtk_file_system_unix_get_type (void)
248 static GType file_system_unix_type = 0;
250 if (!file_system_unix_type)
252 static const GTypeInfo file_system_unix_info =
254 sizeof (GtkFileSystemUnixClass),
255 NULL, /* base_init */
256 NULL, /* base_finalize */
257 (GClassInitFunc) gtk_file_system_unix_class_init,
258 NULL, /* class_finalize */
259 NULL, /* class_data */
260 sizeof (GtkFileSystemUnix),
262 (GInstanceInitFunc) gtk_file_system_unix_init,
265 static const GInterfaceInfo file_system_info =
267 (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
268 NULL, /* interface_finalize */
269 NULL /* interface_data */
272 file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
273 g_intern_static_string ("GtkFileSystemUnix"),
274 &file_system_unix_info, 0);
275 g_type_add_interface_static (file_system_unix_type,
276 GTK_TYPE_FILE_SYSTEM,
280 return file_system_unix_type;
284 * gtk_file_system_unix_new:
286 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
287 * implements the #GtkFileSystem interface with direct access to
288 * the filesystem using Unix/Linux API calls
290 * Return value: the new #GtkFileSystemUnix object
293 gtk_file_system_unix_new (void)
295 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
299 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
301 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
303 system_parent_class = g_type_class_peek_parent (class);
305 gobject_class->finalize = gtk_file_system_unix_finalize;
309 gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
311 iface->list_volumes = gtk_file_system_unix_list_volumes;
312 iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
313 iface->get_folder = gtk_file_system_unix_get_folder;
314 iface->create_folder = gtk_file_system_unix_create_folder;
315 iface->volume_free = gtk_file_system_unix_volume_free;
316 iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
317 iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
318 iface->volume_mount = gtk_file_system_unix_volume_mount;
319 iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
320 iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
321 iface->get_parent = gtk_file_system_unix_get_parent;
322 iface->make_path = gtk_file_system_unix_make_path;
323 iface->parse = gtk_file_system_unix_parse;
324 iface->path_to_uri = gtk_file_system_unix_path_to_uri;
325 iface->path_to_filename = gtk_file_system_unix_path_to_filename;
326 iface->uri_to_path = gtk_file_system_unix_uri_to_path;
327 iface->filename_to_path = gtk_file_system_unix_filename_to_path;
328 iface->render_icon = gtk_file_system_unix_render_icon;
329 iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
330 iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
331 iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
332 iface->get_bookmark_label = gtk_file_system_unix_get_bookmark_label;
333 iface->set_bookmark_label = gtk_file_system_unix_set_bookmark_label;
337 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
339 system_unix->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
341 if (stat ("/afs", &system_unix->afs_statbuf) == 0)
342 system_unix->have_afs = TRUE;
344 system_unix->have_afs = FALSE;
346 if (stat ("/net", &system_unix->net_statbuf) == 0)
347 system_unix->have_net = TRUE;
349 system_unix->have_net = FALSE;
353 gtk_file_system_unix_finalize (GObject *object)
355 GtkFileSystemUnix *system_unix;
357 system_unix = GTK_FILE_SYSTEM_UNIX (object);
359 /* FIXME: assert that the hash is empty? */
360 g_hash_table_destroy (system_unix->folder_hash);
362 system_parent_class->finalize (object);
365 /* Returns our single root volume */
366 static GtkFileSystemVolume *
367 get_root_volume (void)
369 return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
373 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
375 return g_slist_append (NULL, get_root_volume ());
378 static GtkFileSystemVolume *
379 gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
380 const GtkFilePath *path)
382 return get_root_volume ();
386 remove_trailing_slash (const char *filename)
390 len = strlen (filename);
392 if (len > 1 && filename[len - 1] == '/')
393 return g_strndup (filename, len - 1);
395 return g_memdup (filename, len + 1);
398 static GtkFileFolder *
399 gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
400 const GtkFilePath *path,
401 GtkFileInfoType types,
404 GtkFileSystemUnix *system_unix;
405 GtkFileFolderUnix *folder_unix;
406 const char *filename;
408 gboolean set_asof = FALSE;
410 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
412 filename = gtk_file_path_get_string (path);
413 g_return_val_if_fail (filename != NULL, NULL);
414 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
416 filename_copy = remove_trailing_slash (filename);
417 folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename_copy);
421 g_free (filename_copy);
422 if (folder_unix->stat_info &&
423 time (NULL) - folder_unix->asof >= FOLDER_CACHE_LIFETIME)
426 g_print ("Cleaning out cached directory %s\n", filename);
428 g_hash_table_destroy (folder_unix->stat_info);
429 folder_unix->stat_info = NULL;
430 folder_unix->have_mime_type = FALSE;
431 folder_unix->have_stat = FALSE;
432 folder_unix->have_hidden = FALSE;
436 g_object_ref (folder_unix);
437 folder_unix->types |= types;
438 types = folder_unix->types;
447 code = my_errno = 0; /* shut up GCC */
449 result = stat (filename, &statbuf);
453 if (!S_ISDIR (statbuf.st_mode))
456 code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER;
464 if (my_errno == ENOENT)
465 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
467 code = GTK_FILE_SYSTEM_ERROR_FAILED;
472 gchar *display_name = g_filename_display_name (filename);
474 GTK_FILE_SYSTEM_ERROR,
476 _("Error getting information for '%s': %s"),
478 g_strerror (my_errno));
480 g_free (display_name);
481 g_free (filename_copy);
485 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
486 folder_unix->system_unix = system_unix;
487 folder_unix->filename = filename_copy;
488 folder_unix->types = types;
489 folder_unix->stat_info = NULL;
490 folder_unix->have_mime_type = FALSE;
491 folder_unix->have_stat = FALSE;
492 folder_unix->have_hidden = FALSE;
495 if ((system_unix->have_afs &&
496 system_unix->afs_statbuf.st_dev == statbuf.st_dev &&
497 system_unix->afs_statbuf.st_ino == statbuf.st_ino) ||
498 (system_unix->have_net &&
499 system_unix->net_statbuf.st_dev == statbuf.st_dev &&
500 system_unix->net_statbuf.st_ino == statbuf.st_ino))
501 folder_unix->is_network_dir = TRUE;
503 folder_unix->is_network_dir = FALSE;
505 g_hash_table_insert (system_unix->folder_hash,
506 folder_unix->filename,
510 if ((types & STAT_NEEDED_MASK) != 0)
511 fill_in_stats (folder_unix);
513 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
514 fill_in_mime_type (folder_unix);
517 folder_unix->asof = time (NULL);
519 return GTK_FILE_FOLDER (folder_unix);
523 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
524 const GtkFilePath *path,
527 GtkFileSystemUnix *system_unix;
528 const char *filename;
531 int save_errno = errno;
533 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
535 filename = gtk_file_path_get_string (path);
536 g_return_val_if_fail (filename != NULL, FALSE);
537 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
539 tmp = remove_trailing_slash (filename);
541 result = mkdir (tmp, 0777) == 0;
547 gchar *display_name = g_filename_display_name (filename);
549 GTK_FILE_SYSTEM_ERROR,
550 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
551 _("Error creating directory '%s': %s"),
553 g_strerror (save_errno));
554 g_free (display_name);
558 if (filename_is_root (filename))
559 return TRUE; /* hmmm, but with no notification */
561 parent = get_parent_dir (filename);
564 GtkFileFolderUnix *folder_unix;
566 folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
569 GtkFileInfoType types;
570 GtkFilePath *parent_path;
572 GtkFileFolder *folder;
574 /* This is sort of a hack. We re-get the folder, to ensure that the
575 * newly-created directory gets read into the folder's info hash table.
578 types = folder_unix->types;
580 parent_path = gtk_file_path_new_dup (parent);
581 folder = gtk_file_system_get_folder (file_system, parent_path, types, NULL);
582 gtk_file_path_free (parent_path);
586 paths = g_slist_append (NULL, (GtkFilePath *) path);
587 g_signal_emit_by_name (folder, "files-added", paths);
588 g_slist_free (paths);
589 g_object_unref (folder);
600 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
601 GtkFileSystemVolume *volume)
605 path = (GtkFilePath *) volume;
606 gtk_file_path_free (path);
610 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
611 GtkFileSystemVolume *volume)
613 return gtk_file_path_new_dup ("/");
617 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
618 GtkFileSystemVolume *volume)
624 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
625 GtkFileSystemVolume *volume,
629 GTK_FILE_SYSTEM_ERROR,
630 GTK_FILE_SYSTEM_ERROR_FAILED,
631 _("This file system does not support mounting"));
636 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
637 GtkFileSystemVolume *volume)
639 return g_strdup (_("File System")); /* Same as Nautilus */
643 get_icon_type_from_stat (struct stat *statp)
645 if (S_ISBLK (statp->st_mode))
646 return ICON_BLOCK_DEVICE;
647 else if (S_ISLNK (statp->st_mode))
648 return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
649 else if (S_ISCHR (statp->st_mode))
650 return ICON_CHARACTER_DEVICE;
651 else if (S_ISDIR (statp->st_mode))
652 return ICON_DIRECTORY;
654 else if (S_ISFIFO (statp->st_mode))
658 else if (S_ISSOCK (statp->st_mode))
666 get_icon_type (const char *filename,
671 /* If stat fails, try to fall back to lstat to catch broken links
673 if (stat (filename, &statbuf) != 0)
675 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
677 int save_errno = errno;
678 gchar *display_name = g_filename_display_name (filename);
680 GTK_FILE_SYSTEM_ERROR,
681 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
682 _("Error getting information for '%s': %s"),
684 g_strerror (save_errno));
685 g_free (display_name);
691 return get_icon_type_from_stat (&statbuf);
701 icon_cache_element_free (IconCacheElement *element)
704 g_object_unref (element->pixbuf);
709 icon_theme_changed (GtkIconTheme *icon_theme)
713 /* Difference from the initial creation is that we don't
714 * reconnect the signal
716 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
717 (GDestroyNotify)g_free,
718 (GDestroyNotify)icon_cache_element_free);
719 g_object_set_data_full (G_OBJECT (icon_theme), g_intern_static_string ("gtk-file-icon-cache"),
720 cache, (GDestroyNotify)g_hash_table_destroy);
724 get_cached_icon (GtkWidget *widget,
728 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
729 GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
730 IconCacheElement *element;
734 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
735 (GDestroyNotify)g_free,
736 (GDestroyNotify)icon_cache_element_free);
738 g_object_set_data_full (G_OBJECT (icon_theme), g_intern_static_string ("gtk-file-icon-cache"),
739 cache, (GDestroyNotify)g_hash_table_destroy);
740 g_signal_connect (icon_theme, "changed",
741 G_CALLBACK (icon_theme_changed), NULL);
744 element = g_hash_table_lookup (cache, name);
747 element = g_new0 (IconCacheElement, 1);
748 g_hash_table_insert (cache, g_strdup (name), element);
751 if (element->size != pixel_size)
754 g_object_unref (element->pixbuf);
755 element->size = pixel_size;
756 element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
757 pixel_size, 0, NULL);
760 return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
763 /* Renders a fallback icon from the stock system */
765 get_fallback_icon (GtkWidget *widget,
769 const char *stock_name;
774 case ICON_BLOCK_DEVICE:
775 stock_name = GTK_STOCK_HARDDISK;
779 stock_name = GTK_STOCK_DIRECTORY;
782 case ICON_EXECUTABLE:
783 stock_name = GTK_STOCK_EXECUTE;
787 stock_name = GTK_STOCK_FILE;
791 pixbuf = gtk_widget_render_icon (widget, stock_name, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
794 GTK_FILE_SYSTEM_ERROR,
795 GTK_FILE_SYSTEM_ERROR_FAILED,
796 _("Could not get a stock icon for %s"),
803 gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
804 GtkFileSystemVolume *volume,
811 pixbuf = get_cached_icon (widget, "gnome-dev-harddisk", pixel_size);
815 pixbuf = get_fallback_icon (widget, ICON_BLOCK_DEVICE, error);
816 g_assert (pixbuf != NULL);
822 get_parent_dir (const char *filename)
826 len = strlen (filename);
828 /* Ignore trailing slashes */
829 if (len > 1 && filename[len - 1] == '/')
833 tmp = g_strndup (filename, len - 1);
835 parent = g_path_get_dirname (tmp);
841 return g_path_get_dirname (filename);
845 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
846 const GtkFilePath *path,
847 GtkFilePath **parent,
850 const char *filename;
852 filename = gtk_file_path_get_string (path);
853 g_return_val_if_fail (filename != NULL, FALSE);
854 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
856 if (filename_is_root (filename))
862 gchar *parent_filename = get_parent_dir (filename);
863 *parent = filename_to_path (parent_filename);
864 g_free (parent_filename);
871 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
872 const GtkFilePath *base_path,
873 const gchar *display_name,
876 const char *base_filename;
878 gchar *full_filename;
879 GError *tmp_error = NULL;
882 base_filename = gtk_file_path_get_string (base_path);
883 g_return_val_if_fail (base_filename != NULL, NULL);
884 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
886 if (strchr (display_name, G_DIR_SEPARATOR))
889 GTK_FILE_SYSTEM_ERROR,
890 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
891 _("The name \"%s\" is not valid because it contains the character \"%s\". "
892 "Please use a different name."),
898 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
902 GTK_FILE_SYSTEM_ERROR,
903 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
907 g_error_free (tmp_error);
912 full_filename = g_build_filename (base_filename, filename, NULL);
913 result = filename_to_path (full_filename);
915 g_free (full_filename);
920 /* If this was a publically exported function, it should return
921 * a dup'ed result, but we make it modify-in-place for efficiency
922 * here, and because it works for us.
925 canonicalize_filename (gchar *filename)
928 gboolean last_was_slash = FALSE;
935 if (*p == G_DIR_SEPARATOR)
938 *q++ = G_DIR_SEPARATOR;
940 last_was_slash = TRUE;
944 if (last_was_slash && *p == '.')
946 if (*(p + 1) == G_DIR_SEPARATOR ||
949 if (*(p + 1) == '\0')
954 else if (*(p + 1) == '.' &&
955 (*(p + 2) == G_DIR_SEPARATOR ||
958 if (q > filename + 1)
961 while (q > filename + 1 &&
962 *(q - 1) != G_DIR_SEPARATOR)
966 if (*(p + 2) == '\0')
974 last_was_slash = FALSE;
980 last_was_slash = FALSE;
987 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
993 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
995 expand_tilde (const char *filename)
1001 if (filename[0] != '~')
1002 return g_strdup (filename);
1004 notilde = filename + 1;
1006 slash = strchr (notilde, G_DIR_SEPARATOR);
1010 if (slash == notilde)
1012 home = g_get_home_dir ();
1015 return g_strdup (filename);
1020 struct passwd *passwd;
1022 username = g_strndup (notilde, slash - notilde);
1023 passwd = getpwnam (username);
1027 return g_strdup (filename);
1029 home = passwd->pw_dir;
1032 return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
1036 gtk_file_system_unix_parse (GtkFileSystem *file_system,
1037 const GtkFilePath *base_path,
1039 GtkFilePath **folder,
1043 const char *base_filename;
1046 gboolean result = FALSE;
1048 base_filename = gtk_file_path_get_string (base_path);
1049 g_return_val_if_fail (base_filename != NULL, FALSE);
1050 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
1052 filename = expand_tilde (str);
1056 GTK_FILE_SYSTEM_ERROR,
1057 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1058 "%s", ""); /* nothing for now, as we are string-frozen */
1062 last_slash = strrchr (filename, G_DIR_SEPARATOR);
1065 *folder = gtk_file_path_copy (base_path);
1066 *file_part = g_strdup (filename);
1073 GError *tmp_error = NULL;
1075 if (last_slash == filename)
1076 folder_part = g_strdup ("/");
1078 folder_part = g_filename_from_utf8 (filename, last_slash - filename,
1079 NULL, NULL, &tmp_error);
1084 GTK_FILE_SYSTEM_ERROR,
1085 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1087 tmp_error->message);
1088 g_error_free (tmp_error);
1092 if (folder_part[0] == G_DIR_SEPARATOR)
1093 folder_path = folder_part;
1096 folder_path = g_build_filename (base_filename, folder_part, NULL);
1097 g_free (folder_part);
1100 canonicalize_filename (folder_path);
1102 *folder = filename_to_path (folder_path);
1103 *file_part = g_strdup (last_slash + 1);
1105 g_free (folder_path);
1117 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
1118 const GtkFilePath *path)
1120 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
1124 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
1125 const GtkFilePath *path)
1127 return g_strdup (gtk_file_path_get_string (path));
1130 static GtkFilePath *
1131 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
1135 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
1139 path = filename_to_path (filename);
1148 static GtkFilePath *
1149 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
1150 const gchar *filename)
1152 return filename_to_path (filename);
1155 /* Returns the name of the icon to be used for a path which is known to be a
1156 * directory. This can vary for Home, Desktop, etc.
1159 get_icon_name_for_directory (const char *path)
1161 static char *desktop_path = NULL;
1163 if (!g_get_home_dir ())
1164 return "gnome-fs-directory";
1167 desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
1169 if (strcmp (g_get_home_dir (), path) == 0)
1170 return "gnome-fs-home";
1171 else if (strcmp (desktop_path, path) == 0)
1172 return "gnome-fs-desktop";
1174 return "gnome-fs-directory";
1177 /* Computes our internal icon type based on a path name; also returns the MIME
1178 * type in case we come up with ICON_REGULAR.
1181 get_icon_type_from_path (GtkFileSystemUnix *system_unix,
1182 const GtkFilePath *path,
1183 const char **mime_type)
1185 const char *filename;
1187 GtkFileFolderUnix *folder_unix;
1190 filename = gtk_file_path_get_string (path);
1191 dirname = g_path_get_dirname (filename);
1192 folder_unix = g_hash_table_lookup (system_unix->folder_hash, dirname);
1197 if (folder_unix && folder_unix->have_stat)
1200 struct stat_info_entry *entry;
1202 g_assert (folder_unix->stat_info != NULL);
1204 basename = g_path_get_basename (filename);
1205 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1209 if (entry->icon_type == ICON_UNDECIDED)
1211 entry->icon_type = get_icon_type_from_stat (&entry->statbuf);
1212 g_assert (entry->icon_type != ICON_UNDECIDED);
1214 icon_type = entry->icon_type;
1215 if (icon_type == ICON_REGULAR)
1217 fill_in_mime_type (folder_unix);
1218 *mime_type = entry->mime_type;
1225 icon_type = get_icon_type (filename, NULL);
1226 if (icon_type == ICON_REGULAR)
1227 *mime_type = xdg_mime_get_mime_type_for_file (filename);
1232 /* Renders an icon for a non-ICON_REGULAR file */
1234 get_special_icon (IconType icon_type,
1235 const GtkFilePath *path,
1241 g_assert (icon_type != ICON_REGULAR);
1245 case ICON_BLOCK_DEVICE:
1246 name = "gnome-fs-blockdev";
1248 case ICON_BROKEN_SYMBOLIC_LINK:
1249 name = "gnome-fs-symlink";
1251 case ICON_CHARACTER_DEVICE:
1252 name = "gnome-fs-chardev";
1254 case ICON_DIRECTORY: {
1255 const char *filename;
1257 filename = gtk_file_path_get_string (path);
1258 name = get_icon_name_for_directory (filename);
1261 case ICON_EXECUTABLE:
1262 name ="gnome-fs-executable";
1265 name = "gnome-fs-fifo";
1268 name = "gnome-fs-socket";
1271 g_assert_not_reached ();
1275 return get_cached_icon (widget, name, pixel_size);
1279 get_icon_for_mime_type (GtkWidget *widget,
1280 const char *mime_type,
1283 const char *separator;
1287 separator = strchr (mime_type, '/');
1289 return NULL; /* maybe we should return a GError with "invalid MIME-type" */
1291 icon_name = g_string_new ("gnome-mime-");
1292 g_string_append_len (icon_name, mime_type, separator - mime_type);
1293 g_string_append_c (icon_name, '-');
1294 g_string_append (icon_name, separator + 1);
1295 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1296 g_string_free (icon_name, TRUE);
1300 icon_name = g_string_new ("gnome-mime-");
1301 g_string_append_len (icon_name, mime_type, separator - mime_type);
1302 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1303 g_string_free (icon_name, TRUE);
1309 gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
1310 const GtkFilePath *path,
1315 GtkFileSystemUnix *system_unix;
1317 const char *mime_type;
1320 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
1322 icon_type = get_icon_type_from_path (system_unix, path, &mime_type);
1324 switch (icon_type) {
1329 pixbuf = get_icon_for_mime_type (widget, mime_type, pixel_size);
1333 pixbuf = get_special_icon (icon_type, path, widget, pixel_size);
1341 pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
1345 pixbuf = get_fallback_icon (widget, icon_type, error);
1353 bookmark_list_free (GSList *list)
1357 for (l = list; l; l = l->next)
1360 g_slist_free (list);
1363 /* Returns whether a URI is a local file:// */
1365 is_local_uri (const char *uri)
1371 /* This is rather crude, but hey */
1372 filename = g_filename_from_uri (uri, &hostname, NULL);
1374 result = (filename && !hostname);
1383 bookmark_get_filename (void)
1387 filename = g_build_filename (g_get_home_dir (),
1388 BOOKMARKS_FILENAME, NULL);
1389 g_assert (filename != NULL);
1394 bookmark_list_read (GSList **bookmarks, GError **error)
1398 gboolean result = FALSE;
1400 filename = bookmark_get_filename ();
1403 if (g_file_get_contents (filename, &contents, NULL, error))
1405 gchar **lines = g_strsplit (contents, "\n", -1);
1409 table = g_hash_table_new (g_str_hash, g_str_equal);
1411 for (i = 0; lines[i]; i++)
1413 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1415 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1416 g_hash_table_insert (table, lines[i], lines[i]);
1421 g_hash_table_destroy (table);
1424 *bookmarks = g_slist_reverse (*bookmarks);
1434 bookmark_list_write (GSList *bookmarks,
1440 GError *tmp_error = NULL;
1443 string = g_string_new ("");
1445 for (l = bookmarks; l; l = l->next)
1447 g_string_append (string, l->data);
1448 g_string_append_c (string, '\n');
1451 filename = bookmark_get_filename ();
1453 result = g_file_set_contents (filename, string->str, -1, &tmp_error);
1456 g_string_free (string, TRUE);
1461 GTK_FILE_SYSTEM_ERROR,
1462 GTK_FILE_SYSTEM_ERROR_FAILED,
1463 _("Bookmark saving failed: %s"),
1464 tmp_error->message);
1466 g_error_free (tmp_error);
1473 gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
1474 const GtkFilePath *path,
1486 if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1488 g_propagate_error (error, err);
1492 num_bookmarks = g_slist_length (bookmarks);
1493 g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1497 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1499 for (l = bookmarks; l; l = l->next)
1501 char *bookmark, *space;
1505 space = strchr (bookmark, ' ');
1508 if (strcmp (bookmark, uri) != 0)
1516 GTK_FILE_SYSTEM_ERROR,
1517 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1518 _("'%s' already exists in the bookmarks list"),
1524 bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1525 if (bookmark_list_write (bookmarks, error))
1528 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1534 bookmark_list_free (bookmarks);
1540 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1541 const GtkFilePath *path,
1549 if (!bookmark_list_read (&bookmarks, error))
1554 uri = gtk_file_system_path_to_uri (file_system, path);
1556 for (l = bookmarks; l; l = l->next)
1558 char *bookmark, *space;
1560 bookmark = (char *)l->data;
1561 space = strchr (bookmark, ' ');
1565 if (strcmp (bookmark, uri) != 0)
1573 bookmarks = g_slist_remove_link (bookmarks, l);
1576 if (bookmark_list_write (bookmarks, error))
1580 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1588 GTK_FILE_SYSTEM_ERROR,
1589 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1590 _("'%s' does not exist in the bookmarks list"),
1596 bookmark_list_free (bookmarks);
1602 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1608 if (!bookmark_list_read (&bookmarks, NULL))
1613 for (l = bookmarks; l; l = l->next)
1615 char *bookmark, *space;
1617 bookmark = (char *)l->data;
1618 space = strchr (bookmark, ' ');
1622 if (is_local_uri (bookmark))
1623 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
1626 bookmark_list_free (bookmarks);
1628 result = g_slist_reverse (result);
1633 gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
1634 const GtkFilePath *path)
1639 char *bookmark, *space, *uri;
1644 uri = gtk_file_system_path_to_uri (file_system, path);
1645 bookmark_list_read (&labels, NULL);
1647 for (l = labels; l && !label; l = l->next)
1649 bookmark = (char *)l->data;
1650 space = strchr (bookmark, ' ');
1656 if (strcmp (uri, bookmark) == 0)
1657 label = g_strdup (space + 1);
1660 bookmark_list_free (labels);
1667 gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
1668 const GtkFilePath *path,
1673 gchar *bookmark, *space, *uri;
1678 uri = gtk_file_system_path_to_uri (file_system, path);
1679 bookmark_list_read (&labels, NULL);
1682 for (l = labels; l && !found; l = l->next)
1684 bookmark = (gchar *)l->data;
1685 space = strchr (bookmark, ' ');
1689 if (strcmp (bookmark, uri) != 0)
1698 if (label && *label)
1699 l->data = g_strdup_printf ("%s %s", uri, label);
1701 l->data = g_strdup (uri);
1710 if (bookmark_list_write (labels, NULL))
1711 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1714 bookmark_list_free (labels);
1722 gtk_file_folder_unix_get_type (void)
1724 static GType file_folder_unix_type = 0;
1726 if (!file_folder_unix_type)
1728 static const GTypeInfo file_folder_unix_info =
1730 sizeof (GtkFileFolderUnixClass),
1731 NULL, /* base_init */
1732 NULL, /* base_finalize */
1733 (GClassInitFunc) gtk_file_folder_unix_class_init,
1734 NULL, /* class_finalize */
1735 NULL, /* class_data */
1736 sizeof (GtkFileFolderUnix),
1737 0, /* n_preallocs */
1738 (GInstanceInitFunc) gtk_file_folder_unix_init,
1741 static const GInterfaceInfo file_folder_info =
1743 (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1744 NULL, /* interface_finalize */
1745 NULL /* interface_data */
1748 file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1749 g_intern_static_string ("GtkFileFolderUnix"),
1750 &file_folder_unix_info, 0);
1751 g_type_add_interface_static (file_folder_unix_type,
1752 GTK_TYPE_FILE_FOLDER,
1756 return file_folder_unix_type;
1760 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1762 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1764 folder_parent_class = g_type_class_peek_parent (class);
1766 gobject_class->finalize = gtk_file_folder_unix_finalize;
1770 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1772 iface->get_info = gtk_file_folder_unix_get_info;
1773 iface->list_children = gtk_file_folder_unix_list_children;
1774 iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;
1778 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1783 gtk_file_folder_unix_finalize (GObject *object)
1785 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1787 g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
1789 if (folder_unix->stat_info)
1792 g_print ("Releasing information for directory %s\n", folder_unix->filename);
1794 g_hash_table_destroy (folder_unix->stat_info);
1797 g_free (folder_unix->filename);
1799 folder_parent_class->finalize (object);
1802 /* Creates a GtkFileInfo for "/" by stat()ing it */
1803 static GtkFileInfo *
1804 file_info_for_root_with_error (const char *root_name,
1807 struct stat statbuf;
1810 if (stat (root_name, &statbuf) != 0)
1814 saved_errno = errno;
1816 GTK_FILE_SYSTEM_ERROR,
1817 GTK_FILE_SYSTEM_ERROR_FAILED,
1818 _("Error getting information for '/': %s"),
1819 g_strerror (saved_errno));
1824 info = gtk_file_info_new ();
1825 gtk_file_info_set_display_name (info, "/");
1826 gtk_file_info_set_is_folder (info, TRUE);
1827 gtk_file_info_set_is_hidden (info, FALSE);
1828 gtk_file_info_set_mime_type (info, "x-directory/normal");
1829 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1830 gtk_file_info_set_size (info, statbuf.st_size);
1836 stat_with_error (const char *filename,
1837 struct stat *statbuf,
1840 if (stat (filename, statbuf) == -1 &&
1841 (errno != ENOENT || lstat (filename, statbuf) == -1))
1847 saved_errno = errno;
1849 if (saved_errno == ENOENT)
1850 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
1852 code = GTK_FILE_SYSTEM_ERROR_FAILED;
1854 display_name = g_filename_display_name (filename);
1856 GTK_FILE_SYSTEM_ERROR,
1858 _("Error getting information for '%s': %s"),
1860 g_strerror (saved_errno));
1862 g_free (display_name);
1869 /* Creates a new GtkFileInfo from the specified data */
1870 static GtkFileInfo *
1871 create_file_info (GtkFileFolderUnix *folder_unix,
1872 const char *filename,
1873 const char *basename,
1874 GtkFileInfoType types,
1875 struct stat *statbuf,
1876 const char *mime_type)
1880 info = gtk_file_info_new ();
1882 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1884 gchar *display_name = g_filename_display_basename (filename);
1885 gtk_file_info_set_display_name (info, display_name);
1886 g_free (display_name);
1889 if (types & GTK_FILE_INFO_IS_HIDDEN)
1891 if (file_is_hidden (folder_unix, basename))
1892 gtk_file_info_set_is_hidden (info, TRUE);
1895 if (types & GTK_FILE_INFO_IS_FOLDER)
1896 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode));
1898 if (types & GTK_FILE_INFO_MIME_TYPE)
1899 gtk_file_info_set_mime_type (info, mime_type);
1901 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1902 gtk_file_info_set_modification_time (info, statbuf->st_mtime);
1904 if (types & GTK_FILE_INFO_SIZE)
1905 gtk_file_info_set_size (info, (gint64) statbuf->st_size);
1910 static struct stat_info_entry *
1911 create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix,
1912 const char *filename,
1913 const char *basename,
1914 struct stat *statbuf)
1918 struct stat_info_entry *entry;
1920 entry = g_new0 (struct stat_info_entry, 1);
1922 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
1923 entry->statbuf = *statbuf;
1925 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
1926 entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename));
1928 g_hash_table_insert (folder_unix->stat_info,
1929 g_strdup (basename),
1932 path = gtk_file_path_new_dup (filename);
1933 paths = g_slist_append (NULL, path);
1934 g_signal_emit_by_name (folder_unix, "files-added", paths);
1935 gtk_file_path_free (path);
1936 g_slist_free (paths);
1941 static GtkFileInfo *
1942 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
1943 const GtkFilePath *path,
1946 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1948 gchar *dirname, *basename;
1949 const char *filename;
1950 GtkFileInfoType types;
1951 struct stat statbuf;
1952 const char *mime_type;
1954 /* Get_info for "/" */
1957 g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL);
1958 return file_info_for_root_with_error (folder_unix->filename, error);
1961 /* Get_info for normal files */
1963 filename = gtk_file_path_get_string (path);
1964 g_return_val_if_fail (filename != NULL, NULL);
1965 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
1967 dirname = get_parent_dir (filename);
1968 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
1971 basename = g_path_get_basename (filename);
1972 types = folder_unix->types;
1974 if (folder_unix->have_stat)
1976 struct stat_info_entry *entry;
1978 g_assert (folder_unix->stat_info != NULL);
1979 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1983 if (!stat_with_error (filename, &statbuf, error))
1989 entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf);
1992 info = create_file_info (folder_unix, filename, basename, types, &entry->statbuf, entry->mime_type);
1998 if (!stat_with_error (filename, &statbuf, error))
2004 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
2005 mime_type = xdg_mime_get_mime_type_for_file (filename);
2009 info = create_file_info (folder_unix, filename, basename, types, &statbuf, mime_type);
2017 cb_list_children (gpointer key, gpointer value, gpointer user_data)
2019 GSList **children = user_data;
2020 *children = g_slist_prepend (*children, key);
2024 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
2028 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2031 if (!fill_in_names (folder_unix, error))
2036 /* Get the list of basenames. */
2037 g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
2039 /* Turn basenames into GFilePaths. */
2040 for (l = *children; l; l = l->next)
2042 const char *basename = l->data;
2043 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2044 l->data = filename_to_path (fullname);
2052 gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
2054 /* Since we don't do asynchronous loads, we are always finished loading */
2059 free_stat_info_entry (struct stat_info_entry *entry)
2061 g_free (entry->mime_type);
2066 fill_in_names (GtkFileFolderUnix *folder_unix, GError **error)
2070 if (folder_unix->stat_info)
2073 dir = g_dir_open (folder_unix->filename, 0, error);
2077 folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal,
2078 (GDestroyNotify) g_free,
2079 (GDestroyNotify) free_stat_info_entry);
2083 struct stat_info_entry *entry;
2084 const gchar *basename;
2086 basename = g_dir_read_name (dir);
2090 entry = g_new0 (struct stat_info_entry, 1);
2091 if (folder_unix->is_network_dir)
2093 entry->statbuf.st_mode = S_IFDIR;
2094 entry->mime_type = g_strdup ("x-directory/normal");
2097 g_hash_table_insert (folder_unix->stat_info,
2098 g_strdup (basename),
2104 folder_unix->asof = time (NULL);
2109 cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data)
2111 const char *basename = key;
2112 struct stat_info_entry *entry = value;
2113 GtkFileFolderUnix *folder_unix = user_data;
2114 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2117 if (stat (fullname, &entry->statbuf) == -1 &&
2118 (errno != ENOENT || lstat (fullname, &entry->statbuf) == -1))
2119 result = TRUE; /* Couldn't stat -- remove from hash. */
2129 fill_in_stats (GtkFileFolderUnix *folder_unix)
2131 if (folder_unix->have_stat)
2134 if (!fill_in_names (folder_unix, NULL))
2137 if (!folder_unix->is_network_dir)
2138 g_hash_table_foreach_remove (folder_unix->stat_info,
2142 folder_unix->have_stat = TRUE;
2147 cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data)
2149 const char *basename = key;
2150 struct stat_info_entry *entry = value;
2151 GtkFileFolderUnix *folder_unix = user_data;
2152 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2154 /* FIXME: Should not need to re-stat. */
2155 const char *mime_type = xdg_mime_get_mime_type_for_file (fullname);
2156 entry->mime_type = g_strdup (mime_type);
2159 /* FIXME: free on NULL? */
2164 fill_in_mime_type (GtkFileFolderUnix *folder_unix)
2166 if (folder_unix->have_mime_type)
2169 if (!folder_unix->have_stat)
2172 g_assert (folder_unix->stat_info != NULL);
2174 if (!folder_unix->is_network_dir)
2175 g_hash_table_foreach_remove (folder_unix->stat_info,
2176 cb_fill_in_mime_type,
2179 folder_unix->have_mime_type = TRUE;
2183 fill_in_hidden (GtkFileFolderUnix *folder_unix)
2188 if (folder_unix->have_hidden)
2191 hidden_file = g_build_filename (folder_unix->filename, HIDDEN_FILENAME, NULL);
2193 if (g_file_get_contents (hidden_file, &contents, NULL, NULL))
2198 lines = g_strsplit (contents, "\n", -1);
2199 for (i = 0; lines[i]; i++)
2203 struct stat_info_entry *entry;
2205 entry = g_hash_table_lookup (folder_unix->stat_info, lines[i]);
2207 entry->hidden = TRUE;
2215 g_free (hidden_file);
2216 folder_unix->have_hidden = TRUE;
2219 static GtkFilePath *
2220 filename_to_path (const char *filename)
2224 tmp = remove_trailing_slash (filename);
2225 return gtk_file_path_new_steal (tmp);
2229 filename_is_root (const char *filename)
2231 const gchar *after_root;
2233 after_root = g_path_skip_root (filename);
2235 return (after_root != NULL && *after_root == '\0');
2239 file_is_hidden (GtkFileFolderUnix *folder_unix,
2240 const char *basename)
2242 struct stat_info_entry *entry;
2244 if (basename[0] == '.' || basename[strlen (basename) - 1] == '~')
2247 if (folder_unix->have_stat)
2249 fill_in_hidden (folder_unix);
2251 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2254 return entry->hidden;
2260 #define __GTK_FILE_SYSTEM_UNIX_C__
2261 #include "gtkaliasdef.c"