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,
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 time_t now = time (NULL);
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 (now - folder_unix->asof >= FOLDER_CACHE_LIFETIME &&
423 folder_unix->stat_info)
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;
435 g_object_ref (folder_unix);
436 folder_unix->types |= types;
437 types = folder_unix->types;
446 code = my_errno = 0; /* shut up GCC */
448 result = stat (filename, &statbuf);
452 if (!S_ISDIR (statbuf.st_mode))
455 code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER;
463 if (my_errno == ENOENT)
464 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
466 code = GTK_FILE_SYSTEM_ERROR_FAILED;
471 gchar *display_name = g_filename_display_name (filename);
473 GTK_FILE_SYSTEM_ERROR,
475 _("Error getting information for '%s': %s"),
477 g_strerror (my_errno));
479 g_free (display_name);
480 g_free (filename_copy);
484 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
485 folder_unix->system_unix = system_unix;
486 folder_unix->filename = filename_copy;
487 folder_unix->types = types;
488 folder_unix->stat_info = NULL;
489 folder_unix->asof = now;
490 folder_unix->have_mime_type = FALSE;
491 folder_unix->have_stat = FALSE;
492 folder_unix->have_hidden = FALSE;
494 if ((system_unix->have_afs &&
495 system_unix->afs_statbuf.st_dev == statbuf.st_dev &&
496 system_unix->afs_statbuf.st_ino == statbuf.st_ino) ||
497 (system_unix->have_net &&
498 system_unix->net_statbuf.st_dev == statbuf.st_dev &&
499 system_unix->net_statbuf.st_ino == statbuf.st_ino))
500 folder_unix->is_network_dir = TRUE;
502 folder_unix->is_network_dir = FALSE;
504 g_hash_table_insert (system_unix->folder_hash,
505 folder_unix->filename,
509 if ((types & STAT_NEEDED_MASK) != 0)
510 fill_in_stats (folder_unix);
512 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
513 fill_in_mime_type (folder_unix);
515 return GTK_FILE_FOLDER (folder_unix);
519 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
520 const GtkFilePath *path,
523 GtkFileSystemUnix *system_unix;
524 const char *filename;
527 int save_errno = errno;
529 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
531 filename = gtk_file_path_get_string (path);
532 g_return_val_if_fail (filename != NULL, FALSE);
533 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
535 tmp = remove_trailing_slash (filename);
537 result = mkdir (tmp, 0777) == 0;
543 gchar *display_name = g_filename_display_name (filename);
545 GTK_FILE_SYSTEM_ERROR,
546 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
547 _("Error creating directory '%s': %s"),
549 g_strerror (save_errno));
550 g_free (display_name);
554 if (filename_is_root (filename))
555 return TRUE; /* hmmm, but with no notification */
557 parent = get_parent_dir (filename);
560 GtkFileFolderUnix *folder_unix;
562 folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
565 GtkFileInfoType types;
566 GtkFilePath *parent_path;
568 GtkFileFolder *folder;
570 /* This is sort of a hack. We re-get the folder, to ensure that the
571 * newly-created directory gets read into the folder's info hash table.
574 types = folder_unix->types;
576 parent_path = gtk_file_path_new_dup (parent);
577 folder = gtk_file_system_get_folder (file_system, parent_path, types, NULL);
578 gtk_file_path_free (parent_path);
582 paths = g_slist_append (NULL, (GtkFilePath *) path);
583 g_signal_emit_by_name (folder, "files-added", paths);
584 g_slist_free (paths);
585 g_object_unref (folder);
596 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
597 GtkFileSystemVolume *volume)
601 path = (GtkFilePath *) volume;
602 gtk_file_path_free (path);
606 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
607 GtkFileSystemVolume *volume)
609 return gtk_file_path_new_dup ("/");
613 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
614 GtkFileSystemVolume *volume)
620 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
621 GtkFileSystemVolume *volume,
625 GTK_FILE_SYSTEM_ERROR,
626 GTK_FILE_SYSTEM_ERROR_FAILED,
627 _("This file system does not support mounting"));
632 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
633 GtkFileSystemVolume *volume)
635 return g_strdup (_("Filesystem")); /* Same as Nautilus */
639 get_icon_type_from_stat (struct stat *statp)
641 if (S_ISBLK (statp->st_mode))
642 return ICON_BLOCK_DEVICE;
643 else if (S_ISLNK (statp->st_mode))
644 return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
645 else if (S_ISCHR (statp->st_mode))
646 return ICON_CHARACTER_DEVICE;
647 else if (S_ISDIR (statp->st_mode))
648 return ICON_DIRECTORY;
650 else if (S_ISFIFO (statp->st_mode))
654 else if (S_ISSOCK (statp->st_mode))
662 get_icon_type (const char *filename,
667 /* If stat fails, try to fall back to lstat to catch broken links
669 if (stat (filename, &statbuf) != 0)
671 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
673 int save_errno = errno;
674 gchar *display_name = g_filename_display_name (filename);
676 GTK_FILE_SYSTEM_ERROR,
677 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
678 _("Error getting information for '%s': %s"),
680 g_strerror (save_errno));
681 g_free (display_name);
687 return get_icon_type_from_stat (&statbuf);
697 icon_cache_element_free (IconCacheElement *element)
700 g_object_unref (element->pixbuf);
705 icon_theme_changed (GtkIconTheme *icon_theme)
709 /* Difference from the initial creation is that we don't
710 * reconnect the signal
712 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
713 (GDestroyNotify)g_free,
714 (GDestroyNotify)icon_cache_element_free);
715 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
716 cache, (GDestroyNotify)g_hash_table_destroy);
720 get_cached_icon (GtkWidget *widget,
724 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
725 GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
726 IconCacheElement *element;
730 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
731 (GDestroyNotify)g_free,
732 (GDestroyNotify)icon_cache_element_free);
734 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
735 cache, (GDestroyNotify)g_hash_table_destroy);
736 g_signal_connect (icon_theme, "changed",
737 G_CALLBACK (icon_theme_changed), NULL);
740 element = g_hash_table_lookup (cache, name);
743 element = g_new0 (IconCacheElement, 1);
744 g_hash_table_insert (cache, g_strdup (name), element);
747 if (element->size != pixel_size)
750 g_object_unref (element->pixbuf);
751 element->size = pixel_size;
752 element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
753 pixel_size, 0, NULL);
756 return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
759 /* Renders a fallback icon from the stock system */
761 get_fallback_icon (GtkWidget *widget,
765 const char *stock_name;
770 case ICON_BLOCK_DEVICE:
771 stock_name = GTK_STOCK_HARDDISK;
775 stock_name = GTK_STOCK_DIRECTORY;
778 case ICON_EXECUTABLE:
779 stock_name = GTK_STOCK_EXECUTE;
783 stock_name = GTK_STOCK_FILE;
787 pixbuf = gtk_widget_render_icon (widget, stock_name, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
790 GTK_FILE_SYSTEM_ERROR,
791 GTK_FILE_SYSTEM_ERROR_FAILED,
792 _("Could not get a stock icon for %s"),
799 gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
800 GtkFileSystemVolume *volume,
807 pixbuf = get_cached_icon (widget, "gnome-fs-blockdev", pixel_size);
811 pixbuf = get_fallback_icon (widget, ICON_BLOCK_DEVICE, error);
812 g_assert (pixbuf != NULL);
818 get_parent_dir (const char *filename)
822 len = strlen (filename);
824 /* Ignore trailing slashes */
825 if (len > 1 && filename[len - 1] == '/')
829 tmp = g_strndup (filename, len - 1);
831 parent = g_path_get_dirname (tmp);
837 return g_path_get_dirname (filename);
841 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
842 const GtkFilePath *path,
843 GtkFilePath **parent,
846 const char *filename;
848 filename = gtk_file_path_get_string (path);
849 g_return_val_if_fail (filename != NULL, FALSE);
850 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
852 if (filename_is_root (filename))
858 gchar *parent_filename = get_parent_dir (filename);
859 *parent = filename_to_path (parent_filename);
860 g_free (parent_filename);
867 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
868 const GtkFilePath *base_path,
869 const gchar *display_name,
872 const char *base_filename;
874 gchar *full_filename;
875 GError *tmp_error = NULL;
878 base_filename = gtk_file_path_get_string (base_path);
879 g_return_val_if_fail (base_filename != NULL, NULL);
880 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
882 if (strchr (display_name, G_DIR_SEPARATOR))
885 GTK_FILE_SYSTEM_ERROR,
886 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
887 _("The name \"%s\" is not valid because it contains the character \"%s\". "
888 "Please use a different name."),
894 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
898 GTK_FILE_SYSTEM_ERROR,
899 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
903 g_error_free (tmp_error);
908 full_filename = g_build_filename (base_filename, filename, NULL);
909 result = filename_to_path (full_filename);
911 g_free (full_filename);
916 /* If this was a publically exported function, it should return
917 * a dup'ed result, but we make it modify-in-place for efficiency
918 * here, and because it works for us.
921 canonicalize_filename (gchar *filename)
924 gboolean last_was_slash = FALSE;
931 if (*p == G_DIR_SEPARATOR)
934 *q++ = G_DIR_SEPARATOR;
936 last_was_slash = TRUE;
940 if (last_was_slash && *p == '.')
942 if (*(p + 1) == G_DIR_SEPARATOR ||
945 if (*(p + 1) == '\0')
950 else if (*(p + 1) == '.' &&
951 (*(p + 2) == G_DIR_SEPARATOR ||
954 if (q > filename + 1)
957 while (q > filename + 1 &&
958 *(q - 1) != G_DIR_SEPARATOR)
962 if (*(p + 2) == '\0')
970 last_was_slash = FALSE;
976 last_was_slash = FALSE;
983 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
989 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
991 expand_tilde (const char *filename)
997 if (filename[0] != '~')
998 return g_strdup (filename);
1000 notilde = filename + 1;
1002 slash = strchr (notilde, G_DIR_SEPARATOR);
1006 if (slash == notilde)
1008 home = g_get_home_dir ();
1011 return g_strdup (filename);
1016 struct passwd *passwd;
1018 username = g_strndup (notilde, slash - notilde);
1019 passwd = getpwnam (username);
1023 return g_strdup (filename);
1025 home = passwd->pw_dir;
1028 return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
1032 gtk_file_system_unix_parse (GtkFileSystem *file_system,
1033 const GtkFilePath *base_path,
1035 GtkFilePath **folder,
1039 const char *base_filename;
1042 gboolean result = FALSE;
1044 base_filename = gtk_file_path_get_string (base_path);
1045 g_return_val_if_fail (base_filename != NULL, FALSE);
1046 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
1048 filename = expand_tilde (str);
1052 GTK_FILE_SYSTEM_ERROR,
1053 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1054 "%s", ""); /* nothing for now, as we are string-frozen */
1058 last_slash = strrchr (filename, G_DIR_SEPARATOR);
1061 *folder = gtk_file_path_copy (base_path);
1062 *file_part = g_strdup (filename);
1069 GError *tmp_error = NULL;
1071 if (last_slash == filename)
1072 folder_part = g_strdup ("/");
1074 folder_part = g_filename_from_utf8 (filename, last_slash - filename,
1075 NULL, NULL, &tmp_error);
1080 GTK_FILE_SYSTEM_ERROR,
1081 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1083 tmp_error->message);
1084 g_error_free (tmp_error);
1088 if (folder_part[0] == G_DIR_SEPARATOR)
1089 folder_path = folder_part;
1092 folder_path = g_build_filename (base_filename, folder_part, NULL);
1093 g_free (folder_part);
1096 canonicalize_filename (folder_path);
1098 *folder = filename_to_path (folder_path);
1099 *file_part = g_strdup (last_slash + 1);
1101 g_free (folder_path);
1113 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
1114 const GtkFilePath *path)
1116 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
1120 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
1121 const GtkFilePath *path)
1123 return g_strdup (gtk_file_path_get_string (path));
1126 static GtkFilePath *
1127 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
1131 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
1135 path = filename_to_path (filename);
1144 static GtkFilePath *
1145 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
1146 const gchar *filename)
1148 return filename_to_path (filename);
1151 /* Returns the name of the icon to be used for a path which is known to be a
1152 * directory. This can vary for Home, Desktop, etc.
1155 get_icon_name_for_directory (const char *path)
1157 static char *desktop_path = NULL;
1159 if (!g_get_home_dir ())
1160 return "gnome-fs-directory";
1163 desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
1165 if (strcmp (g_get_home_dir (), path) == 0)
1166 return "gnome-fs-home";
1167 else if (strcmp (desktop_path, path) == 0)
1168 return "gnome-fs-desktop";
1170 return "gnome-fs-directory";
1173 /* Computes our internal icon type based on a path name; also returns the MIME
1174 * type in case we come up with ICON_REGULAR.
1177 get_icon_type_from_path (GtkFileSystemUnix *system_unix,
1178 const GtkFilePath *path,
1179 const char **mime_type)
1181 const char *filename;
1183 GtkFileFolderUnix *folder_unix;
1186 filename = gtk_file_path_get_string (path);
1187 dirname = g_path_get_dirname (filename);
1188 folder_unix = g_hash_table_lookup (system_unix->folder_hash, dirname);
1193 if (folder_unix && folder_unix->have_stat)
1196 struct stat_info_entry *entry;
1198 g_assert (folder_unix->stat_info != NULL);
1200 basename = g_path_get_basename (filename);
1201 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1205 if (entry->icon_type == ICON_UNDECIDED)
1207 entry->icon_type = get_icon_type_from_stat (&entry->statbuf);
1208 g_assert (entry->icon_type != ICON_UNDECIDED);
1210 icon_type = entry->icon_type;
1211 if (icon_type == ICON_REGULAR)
1213 fill_in_mime_type (folder_unix);
1214 *mime_type = entry->mime_type;
1221 icon_type = get_icon_type (filename, NULL);
1222 if (icon_type == ICON_REGULAR)
1223 *mime_type = xdg_mime_get_mime_type_for_file (filename);
1228 /* Renders an icon for a non-ICON_REGULAR file */
1230 get_special_icon (IconType icon_type,
1231 const GtkFilePath *path,
1237 g_assert (icon_type != ICON_REGULAR);
1241 case ICON_BLOCK_DEVICE:
1242 name = "gnome-fs-blockdev";
1244 case ICON_BROKEN_SYMBOLIC_LINK:
1245 name = "gnome-fs-symlink";
1247 case ICON_CHARACTER_DEVICE:
1248 name = "gnome-fs-chardev";
1250 case ICON_DIRECTORY: {
1251 const char *filename;
1253 filename = gtk_file_path_get_string (path);
1254 name = get_icon_name_for_directory (filename);
1257 case ICON_EXECUTABLE:
1258 name ="gnome-fs-executable";
1261 name = "gnome-fs-fifo";
1264 name = "gnome-fs-socket";
1267 g_assert_not_reached ();
1271 return get_cached_icon (widget, name, pixel_size);
1275 get_icon_for_mime_type (GtkWidget *widget,
1276 const char *mime_type,
1279 const char *separator;
1283 separator = strchr (mime_type, '/');
1285 return NULL; /* maybe we should return a GError with "invalid MIME-type" */
1287 icon_name = g_string_new ("gnome-mime-");
1288 g_string_append_len (icon_name, mime_type, separator - mime_type);
1289 g_string_append_c (icon_name, '-');
1290 g_string_append (icon_name, separator + 1);
1291 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1292 g_string_free (icon_name, TRUE);
1296 icon_name = g_string_new ("gnome-mime-");
1297 g_string_append_len (icon_name, mime_type, separator - mime_type);
1298 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1299 g_string_free (icon_name, TRUE);
1305 gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
1306 const GtkFilePath *path,
1311 GtkFileSystemUnix *system_unix;
1313 const char *mime_type;
1316 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
1318 icon_type = get_icon_type_from_path (system_unix, path, &mime_type);
1320 switch (icon_type) {
1325 pixbuf = get_icon_for_mime_type (widget, mime_type, pixel_size);
1329 pixbuf = get_special_icon (icon_type, path, widget, pixel_size);
1337 pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
1341 pixbuf = get_fallback_icon (widget, icon_type, error);
1349 bookmark_list_free (GSList *list)
1353 for (l = list; l; l = l->next)
1356 g_slist_free (list);
1359 /* Returns whether a URI is a local file:// */
1361 is_local_uri (const char *uri)
1367 /* This is rather crude, but hey */
1368 filename = g_filename_from_uri (uri, &hostname, NULL);
1370 result = (filename && !hostname);
1379 bookmark_get_filename (void)
1383 filename = g_build_filename (g_get_home_dir (),
1384 BOOKMARKS_FILENAME, NULL);
1385 g_assert (filename != NULL);
1390 bookmark_list_read (GSList **bookmarks, GError **error)
1394 gboolean result = FALSE;
1396 filename = bookmark_get_filename ();
1399 if (g_file_get_contents (filename, &contents, NULL, error))
1401 gchar **lines = g_strsplit (contents, "\n", -1);
1405 table = g_hash_table_new (g_str_hash, g_str_equal);
1407 for (i = 0; lines[i]; i++)
1409 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1411 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1412 g_hash_table_insert (table, lines[i], lines[i]);
1417 g_hash_table_destroy (table);
1420 *bookmarks = g_slist_reverse (*bookmarks);
1430 bookmark_list_write (GSList *bookmarks,
1436 GError *tmp_error = NULL;
1439 string = g_string_new ("");
1441 for (l = bookmarks; l; l = l->next)
1443 g_string_append (string, l->data);
1444 g_string_append_c (string, '\n');
1447 filename = bookmark_get_filename ();
1449 result = g_file_set_contents (filename, string->str, -1, &tmp_error);
1452 g_string_free (string, TRUE);
1457 GTK_FILE_SYSTEM_ERROR,
1458 GTK_FILE_SYSTEM_ERROR_FAILED,
1459 _("Bookmark saving failed: %s"),
1460 tmp_error->message);
1462 g_error_free (tmp_error);
1469 gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
1470 const GtkFilePath *path,
1482 if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1484 g_propagate_error (error, err);
1488 num_bookmarks = g_slist_length (bookmarks);
1489 g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1493 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1495 for (l = bookmarks; l; l = l->next)
1497 char *bookmark, *space;
1501 space = strchr (bookmark, ' ');
1504 if (strcmp (bookmark, uri) != 0)
1512 GTK_FILE_SYSTEM_ERROR,
1513 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1514 _("'%s' already exists in the bookmarks list"),
1520 bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1521 if (bookmark_list_write (bookmarks, error))
1524 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1530 bookmark_list_free (bookmarks);
1536 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1537 const GtkFilePath *path,
1545 if (!bookmark_list_read (&bookmarks, error))
1550 uri = gtk_file_system_path_to_uri (file_system, path);
1552 for (l = bookmarks; l; l = l->next)
1554 char *bookmark, *space;
1556 bookmark = (char *)l->data;
1557 space = strchr (bookmark, ' ');
1561 if (strcmp (bookmark, uri) != 0)
1569 bookmarks = g_slist_remove_link (bookmarks, l);
1572 if (bookmark_list_write (bookmarks, error))
1576 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1584 GTK_FILE_SYSTEM_ERROR,
1585 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1586 _("'%s' does not exist in the bookmarks list"),
1592 bookmark_list_free (bookmarks);
1598 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1604 if (!bookmark_list_read (&bookmarks, NULL))
1609 for (l = bookmarks; l; l = l->next)
1611 char *bookmark, *space;
1613 bookmark = (char *)l->data;
1614 space = strchr (bookmark, ' ');
1618 if (is_local_uri (bookmark))
1619 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
1622 bookmark_list_free (bookmarks);
1624 result = g_slist_reverse (result);
1629 gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
1630 const GtkFilePath *path)
1635 char *bookmark, *space, *uri;
1640 uri = gtk_file_system_path_to_uri (file_system, path);
1641 bookmark_list_read (&labels, NULL);
1643 for (l = labels; l && !label; l = l->next)
1645 bookmark = (char *)l->data;
1646 space = strchr (bookmark, ' ');
1652 if (strcmp (uri, bookmark) == 0)
1653 label = g_strdup (space + 1);
1656 bookmark_list_free (labels);
1663 gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
1664 const GtkFilePath *path,
1669 gchar *bookmark, *space, *uri;
1674 uri = gtk_file_system_path_to_uri (file_system, path);
1675 bookmark_list_read (&labels, NULL);
1678 for (l = labels; l && !found; l = l->next)
1680 bookmark = (gchar *)l->data;
1681 space = strchr (bookmark, ' ');
1685 if (strcmp (bookmark, uri) != 0)
1694 if (label && *label)
1695 l->data = g_strdup_printf ("%s %s", uri, label);
1697 l->data = g_strdup (uri);
1706 if (bookmark_list_write (labels, NULL))
1707 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1710 bookmark_list_free (labels);
1718 gtk_file_folder_unix_get_type (void)
1720 static GType file_folder_unix_type = 0;
1722 if (!file_folder_unix_type)
1724 static const GTypeInfo file_folder_unix_info =
1726 sizeof (GtkFileFolderUnixClass),
1727 NULL, /* base_init */
1728 NULL, /* base_finalize */
1729 (GClassInitFunc) gtk_file_folder_unix_class_init,
1730 NULL, /* class_finalize */
1731 NULL, /* class_data */
1732 sizeof (GtkFileFolderUnix),
1733 0, /* n_preallocs */
1734 (GInstanceInitFunc) gtk_file_folder_unix_init,
1737 static const GInterfaceInfo file_folder_info =
1739 (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1740 NULL, /* interface_finalize */
1741 NULL /* interface_data */
1744 file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1745 "GtkFileFolderUnix",
1746 &file_folder_unix_info, 0);
1747 g_type_add_interface_static (file_folder_unix_type,
1748 GTK_TYPE_FILE_FOLDER,
1752 return file_folder_unix_type;
1756 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1758 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1760 folder_parent_class = g_type_class_peek_parent (class);
1762 gobject_class->finalize = gtk_file_folder_unix_finalize;
1766 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1768 iface->get_info = gtk_file_folder_unix_get_info;
1769 iface->list_children = gtk_file_folder_unix_list_children;
1770 iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;
1774 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1779 gtk_file_folder_unix_finalize (GObject *object)
1781 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1783 g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
1785 if (folder_unix->stat_info)
1788 g_print ("Releasing information for directory %s\n", folder_unix->filename);
1790 g_hash_table_destroy (folder_unix->stat_info);
1793 g_free (folder_unix->filename);
1795 folder_parent_class->finalize (object);
1798 /* Creates a GtkFileInfo for "/" by stat()ing it */
1799 static GtkFileInfo *
1800 file_info_for_root_with_error (const char *root_name,
1803 struct stat statbuf;
1806 if (stat (root_name, &statbuf) != 0)
1810 saved_errno = errno;
1812 GTK_FILE_SYSTEM_ERROR,
1813 GTK_FILE_SYSTEM_ERROR_FAILED,
1814 _("Error getting information for '/': %s"),
1815 g_strerror (saved_errno));
1820 info = gtk_file_info_new ();
1821 gtk_file_info_set_display_name (info, "/");
1822 gtk_file_info_set_is_folder (info, TRUE);
1823 gtk_file_info_set_is_hidden (info, FALSE);
1824 gtk_file_info_set_mime_type (info, "x-directory/normal");
1825 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1826 gtk_file_info_set_size (info, statbuf.st_size);
1832 stat_with_error (const char *filename,
1833 struct stat *statbuf,
1836 if (stat (filename, statbuf) == -1 &&
1837 (errno != ENOENT || lstat (filename, statbuf) == -1))
1843 saved_errno = errno;
1845 if (saved_errno == ENOENT)
1846 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
1848 code = GTK_FILE_SYSTEM_ERROR_FAILED;
1850 display_name = g_filename_display_name (filename);
1852 GTK_FILE_SYSTEM_ERROR,
1854 _("Error getting information for '%s': %s"),
1856 g_strerror (saved_errno));
1858 g_free (display_name);
1865 /* Creates a new GtkFileInfo from the specified data */
1866 static GtkFileInfo *
1867 create_file_info (GtkFileFolderUnix *folder_unix,
1868 const char *filename,
1869 const char *basename,
1870 GtkFileInfoType types,
1871 struct stat *statbuf,
1872 const char *mime_type)
1876 info = gtk_file_info_new ();
1878 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1880 gchar *display_name = g_filename_display_basename (filename);
1881 gtk_file_info_set_display_name (info, display_name);
1882 g_free (display_name);
1885 if (types & GTK_FILE_INFO_IS_HIDDEN)
1887 if (file_is_hidden (folder_unix, basename))
1888 gtk_file_info_set_is_hidden (info, TRUE);
1891 if (types & GTK_FILE_INFO_IS_FOLDER)
1892 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode));
1894 if (types & GTK_FILE_INFO_MIME_TYPE)
1895 gtk_file_info_set_mime_type (info, mime_type);
1897 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1898 gtk_file_info_set_modification_time (info, statbuf->st_mtime);
1900 if (types & GTK_FILE_INFO_SIZE)
1901 gtk_file_info_set_size (info, (gint64) statbuf->st_size);
1906 static struct stat_info_entry *
1907 create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix,
1908 const char *filename,
1909 const char *basename,
1910 struct stat *statbuf)
1914 struct stat_info_entry *entry;
1916 entry = g_new0 (struct stat_info_entry, 1);
1918 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
1919 entry->statbuf = *statbuf;
1921 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
1922 entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename));
1924 g_hash_table_insert (folder_unix->stat_info,
1925 g_strdup (basename),
1928 path = gtk_file_path_new_dup (filename);
1929 paths = g_slist_append (NULL, path);
1930 g_signal_emit_by_name (folder_unix, "files-added", paths);
1931 gtk_file_path_free (path);
1932 g_slist_free (paths);
1937 static GtkFileInfo *
1938 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
1939 const GtkFilePath *path,
1942 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1944 gchar *dirname, *basename;
1945 const char *filename;
1946 GtkFileInfoType types;
1947 struct stat statbuf;
1948 const char *mime_type;
1950 /* Get_info for "/" */
1953 g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL);
1954 return file_info_for_root_with_error (folder_unix->filename, error);
1957 /* Get_info for normal files */
1959 filename = gtk_file_path_get_string (path);
1960 g_return_val_if_fail (filename != NULL, NULL);
1961 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
1963 dirname = get_parent_dir (filename);
1964 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
1967 basename = g_path_get_basename (filename);
1968 types = folder_unix->types;
1970 if (folder_unix->have_stat)
1972 struct stat_info_entry *entry;
1974 g_assert (folder_unix->stat_info != NULL);
1975 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1979 if (!stat_with_error (filename, &statbuf, error))
1985 entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf);
1988 info = create_file_info (folder_unix, filename, basename, types, &entry->statbuf, entry->mime_type);
1994 if (!stat_with_error (filename, &statbuf, error))
2000 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
2001 mime_type = xdg_mime_get_mime_type_for_file (filename);
2005 info = create_file_info (folder_unix, filename, basename, types, &statbuf, mime_type);
2013 cb_list_children (gpointer key, gpointer value, gpointer user_data)
2015 GSList **children = user_data;
2016 *children = g_slist_prepend (*children, key);
2020 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
2024 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2027 if (!fill_in_names (folder_unix, error))
2032 /* Get the list of basenames. */
2033 g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
2035 /* Turn basenames into GFilePaths. */
2036 for (l = *children; l; l = l->next)
2038 const char *basename = l->data;
2039 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2040 l->data = filename_to_path (fullname);
2048 gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
2050 /* Since we don't do asynchronous loads, we are always finished loading */
2055 free_stat_info_entry (struct stat_info_entry *entry)
2057 g_free (entry->mime_type);
2062 fill_in_names (GtkFileFolderUnix *folder_unix, GError **error)
2066 if (folder_unix->stat_info)
2069 dir = g_dir_open (folder_unix->filename, 0, error);
2073 folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal,
2074 (GDestroyNotify) g_free,
2075 (GDestroyNotify) free_stat_info_entry);
2079 struct stat_info_entry *entry;
2080 const gchar *basename;
2082 basename = g_dir_read_name (dir);
2086 entry = g_new0 (struct stat_info_entry, 1);
2087 if (folder_unix->is_network_dir)
2089 entry->statbuf.st_mode = S_IFDIR;
2090 entry->mime_type = g_strdup ("x-directory/normal");
2093 g_hash_table_insert (folder_unix->stat_info,
2094 g_strdup (basename),
2100 folder_unix->asof = time (NULL);
2105 cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data)
2107 const char *basename = key;
2108 struct stat_info_entry *entry = value;
2109 GtkFileFolderUnix *folder_unix = user_data;
2110 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2113 if (stat (fullname, &entry->statbuf) == -1 &&
2114 (errno != ENOENT || lstat (fullname, &entry->statbuf) == -1))
2115 result = TRUE; /* Couldn't stat -- remove from hash. */
2125 fill_in_stats (GtkFileFolderUnix *folder_unix)
2127 if (folder_unix->have_stat)
2130 if (!fill_in_names (folder_unix, NULL))
2133 if (!folder_unix->is_network_dir)
2134 g_hash_table_foreach_remove (folder_unix->stat_info,
2138 folder_unix->have_stat = TRUE;
2143 cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data)
2145 const char *basename = key;
2146 struct stat_info_entry *entry = value;
2147 GtkFileFolderUnix *folder_unix = user_data;
2148 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2150 /* FIXME: Should not need to re-stat. */
2151 const char *mime_type = xdg_mime_get_mime_type_for_file (fullname);
2152 entry->mime_type = g_strdup (mime_type);
2155 /* FIXME: free on NULL? */
2160 fill_in_mime_type (GtkFileFolderUnix *folder_unix)
2162 if (folder_unix->have_mime_type)
2165 if (!folder_unix->have_stat)
2168 g_assert (folder_unix->stat_info != NULL);
2170 if (!folder_unix->is_network_dir)
2171 g_hash_table_foreach_remove (folder_unix->stat_info,
2172 cb_fill_in_mime_type,
2175 folder_unix->have_mime_type = TRUE;
2179 fill_in_hidden (GtkFileFolderUnix *folder_unix)
2184 if (folder_unix->have_hidden)
2187 hidden_file = g_build_filename (folder_unix->filename, HIDDEN_FILENAME, NULL);
2189 if (g_file_get_contents (hidden_file, &contents, NULL, NULL))
2194 lines = g_strsplit (contents, "\n", -1);
2195 for (i = 0; lines[i]; i++)
2199 struct stat_info_entry *entry;
2201 entry = g_hash_table_lookup (folder_unix->stat_info, lines[i]);
2203 entry->hidden = TRUE;
2211 g_free (hidden_file);
2212 folder_unix->have_hidden = TRUE;
2215 static GtkFilePath *
2216 filename_to_path (const char *filename)
2220 tmp = remove_trailing_slash (filename);
2221 return gtk_file_path_new_steal (tmp);
2225 filename_is_root (const char *filename)
2227 const gchar *after_root;
2229 after_root = g_path_skip_root (filename);
2231 return (after_root != NULL && *after_root == '\0');
2235 file_is_hidden (GtkFileFolderUnix *folder_unix,
2236 const char *basename)
2238 struct stat_info_entry *entry;
2240 if (basename[0] == '.' || basename[strlen (basename) - 1] == '~')
2243 if (folder_unix->have_stat)
2245 fill_in_hidden (folder_unix);
2247 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2250 return entry->hidden;
2256 #define __GTK_FILE_SYSTEM_UNIX_C__
2257 #include "gtkaliasdef.c"