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 FOLDER_CACHE_LIFETIME 2 /* seconds */
48 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
50 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
51 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
52 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
54 struct _GtkFileSystemUnixClass
56 GObjectClass parent_class;
59 struct _GtkFileSystemUnix
61 GObject parent_instance;
63 GHashTable *folder_hash;
65 /* For /afs and /net */
66 struct stat afs_statbuf;
67 struct stat net_statbuf;
73 /* Icon type, supplemented by MIME type
76 ICON_UNDECIDED, /* Only used while we have not yet computed the icon in a struct stat_info_entry */
77 ICON_NONE, /* "Could not compute the icon type" */
78 ICON_REGULAR, /* Use mime type for icon */
80 ICON_BROKEN_SYMBOLIC_LINK,
81 ICON_CHARACTER_DEVICE,
89 #define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
90 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
91 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
92 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
93 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
94 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
96 typedef struct _GtkFileFolderUnix GtkFileFolderUnix;
97 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
99 struct _GtkFileFolderUnixClass
101 GObjectClass parent_class;
104 struct _GtkFileFolderUnix
106 GObject parent_instance;
108 GtkFileSystemUnix *system_unix;
109 GtkFileInfoType types;
111 GHashTable *stat_info;
113 guint have_mime_type : 1;
114 guint is_network_dir : 1;
118 struct stat_info_entry {
124 static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
125 GTK_FILE_INFO_MODIFICATION_TIME |
128 static GObjectClass *system_parent_class;
129 static GObjectClass *folder_parent_class;
131 static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class);
132 static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
133 static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
134 static void gtk_file_system_unix_finalize (GObject *object);
136 static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
137 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
138 const GtkFilePath *path);
140 static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
141 const GtkFilePath *path,
142 GtkFileInfoType types,
144 static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
145 const GtkFilePath *path,
148 static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
149 GtkFileSystemVolume *volume);
150 static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
151 GtkFileSystemVolume *volume);
152 static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
153 GtkFileSystemVolume *volume);
154 static gboolean gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
155 GtkFileSystemVolume *volume,
157 static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
158 GtkFileSystemVolume *volume);
159 static GdkPixbuf * gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
160 GtkFileSystemVolume *volume,
165 static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
166 const GtkFilePath *path,
167 GtkFilePath **parent,
169 static GtkFilePath * gtk_file_system_unix_make_path (GtkFileSystem *file_system,
170 const GtkFilePath *base_path,
171 const gchar *display_name,
173 static gboolean gtk_file_system_unix_parse (GtkFileSystem *file_system,
174 const GtkFilePath *base_path,
176 GtkFilePath **folder,
180 static gchar * gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
181 const GtkFilePath *path);
182 static gchar * gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
183 const GtkFilePath *path);
184 static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
186 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
187 const gchar *filename);
189 static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
190 const GtkFilePath *path,
195 static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
196 const GtkFilePath *path,
199 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
200 const GtkFilePath *path,
202 static GSList * gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system);
203 static gchar * gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
204 const GtkFilePath *path);
205 static void gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
206 const GtkFilePath *path,
209 static GType gtk_file_folder_unix_get_type (void);
210 static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
211 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
212 static void gtk_file_folder_unix_init (GtkFileFolderUnix *impl);
213 static void gtk_file_folder_unix_finalize (GObject *object);
215 static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
216 const GtkFilePath *path,
218 static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder,
222 static gboolean gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder);
224 static GtkFilePath *filename_to_path (const gchar *filename);
226 static gboolean filename_is_root (const char *filename);
228 static gboolean fill_in_names (GtkFileFolderUnix *folder_unix, GError **error);
229 static void fill_in_stats (GtkFileFolderUnix *folder_unix);
230 static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
232 static char * get_parent_dir (const char *filename);
238 gtk_file_system_unix_get_type (void)
240 static GType file_system_unix_type = 0;
242 if (!file_system_unix_type)
244 static const GTypeInfo file_system_unix_info =
246 sizeof (GtkFileSystemUnixClass),
247 NULL, /* base_init */
248 NULL, /* base_finalize */
249 (GClassInitFunc) gtk_file_system_unix_class_init,
250 NULL, /* class_finalize */
251 NULL, /* class_data */
252 sizeof (GtkFileSystemUnix),
254 (GInstanceInitFunc) gtk_file_system_unix_init,
257 static const GInterfaceInfo file_system_info =
259 (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
260 NULL, /* interface_finalize */
261 NULL /* interface_data */
264 file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
266 &file_system_unix_info, 0);
267 g_type_add_interface_static (file_system_unix_type,
268 GTK_TYPE_FILE_SYSTEM,
272 return file_system_unix_type;
276 * gtk_file_system_unix_new:
278 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
279 * implements the #GtkFileSystem interface with direct access to
280 * the filesystem using Unix/Linux API calls
282 * Return value: the new #GtkFileSystemUnix object
285 gtk_file_system_unix_new (void)
287 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
291 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
293 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
295 system_parent_class = g_type_class_peek_parent (class);
297 gobject_class->finalize = gtk_file_system_unix_finalize;
301 gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
303 iface->list_volumes = gtk_file_system_unix_list_volumes;
304 iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
305 iface->get_folder = gtk_file_system_unix_get_folder;
306 iface->create_folder = gtk_file_system_unix_create_folder;
307 iface->volume_free = gtk_file_system_unix_volume_free;
308 iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
309 iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
310 iface->volume_mount = gtk_file_system_unix_volume_mount;
311 iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
312 iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
313 iface->get_parent = gtk_file_system_unix_get_parent;
314 iface->make_path = gtk_file_system_unix_make_path;
315 iface->parse = gtk_file_system_unix_parse;
316 iface->path_to_uri = gtk_file_system_unix_path_to_uri;
317 iface->path_to_filename = gtk_file_system_unix_path_to_filename;
318 iface->uri_to_path = gtk_file_system_unix_uri_to_path;
319 iface->filename_to_path = gtk_file_system_unix_filename_to_path;
320 iface->render_icon = gtk_file_system_unix_render_icon;
321 iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
322 iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
323 iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
324 iface->get_bookmark_label = gtk_file_system_unix_get_bookmark_label;
325 iface->set_bookmark_label = gtk_file_system_unix_set_bookmark_label;
329 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
331 system_unix->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
333 if (stat ("/afs", &system_unix->afs_statbuf) == 0)
334 system_unix->have_afs = TRUE;
336 system_unix->have_afs = FALSE;
338 if (stat ("/net", &system_unix->net_statbuf) == 0)
339 system_unix->have_net = TRUE;
341 system_unix->have_net = FALSE;
345 gtk_file_system_unix_finalize (GObject *object)
347 GtkFileSystemUnix *system_unix;
349 system_unix = GTK_FILE_SYSTEM_UNIX (object);
351 /* FIXME: assert that the hash is empty? */
352 g_hash_table_destroy (system_unix->folder_hash);
354 system_parent_class->finalize (object);
357 /* Returns our single root volume */
358 static GtkFileSystemVolume *
359 get_root_volume (void)
361 return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
365 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
367 return g_slist_append (NULL, get_root_volume ());
370 static GtkFileSystemVolume *
371 gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
372 const GtkFilePath *path)
374 return get_root_volume ();
378 remove_trailing_slash (const char *filename)
382 len = strlen (filename);
384 if (len > 1 && filename[len - 1] == '/')
385 return g_strndup (filename, len - 1);
387 return g_memdup (filename, len + 1);
390 static GtkFileFolder *
391 gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
392 const GtkFilePath *path,
393 GtkFileInfoType types,
396 GtkFileSystemUnix *system_unix;
397 GtkFileFolderUnix *folder_unix;
398 const char *filename;
400 time_t now = time (NULL);
402 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
404 filename = gtk_file_path_get_string (path);
405 g_return_val_if_fail (filename != NULL, NULL);
406 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
408 filename_copy = remove_trailing_slash (filename);
409 folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename_copy);
413 g_free (filename_copy);
414 if (now - folder_unix->asof >= FOLDER_CACHE_LIFETIME &&
415 folder_unix->stat_info)
418 g_print ("Cleaning out cached directory %s\n", filename);
420 g_hash_table_destroy (folder_unix->stat_info);
421 folder_unix->stat_info = NULL;
422 folder_unix->have_mime_type = FALSE;
423 folder_unix->have_stat = FALSE;
426 g_object_ref (folder_unix);
427 folder_unix->types |= types;
428 types = folder_unix->types;
437 code = my_errno = 0; /* shut up GCC */
439 result = stat (filename, &statbuf);
443 if (!S_ISDIR (statbuf.st_mode))
446 code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER;
454 if (my_errno == ENOENT)
455 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
457 code = GTK_FILE_SYSTEM_ERROR_FAILED;
462 gchar *display_name = g_filename_display_name (filename);
464 GTK_FILE_SYSTEM_ERROR,
466 _("Error getting information for '%s': %s"),
468 g_strerror (my_errno));
470 g_free (display_name);
471 g_free (filename_copy);
475 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
476 folder_unix->system_unix = system_unix;
477 folder_unix->filename = filename_copy;
478 folder_unix->types = types;
479 folder_unix->stat_info = NULL;
480 folder_unix->asof = now;
481 folder_unix->have_mime_type = FALSE;
482 folder_unix->have_stat = FALSE;
484 if ((system_unix->have_afs &&
485 system_unix->afs_statbuf.st_dev == statbuf.st_dev &&
486 system_unix->afs_statbuf.st_ino == statbuf.st_ino) ||
487 (system_unix->have_net &&
488 system_unix->net_statbuf.st_dev == statbuf.st_dev &&
489 system_unix->net_statbuf.st_ino == statbuf.st_ino))
490 folder_unix->is_network_dir = TRUE;
492 folder_unix->is_network_dir = FALSE;
494 g_hash_table_insert (system_unix->folder_hash,
495 folder_unix->filename,
499 if ((types & STAT_NEEDED_MASK) != 0)
500 fill_in_stats (folder_unix);
502 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
503 fill_in_mime_type (folder_unix);
505 return GTK_FILE_FOLDER (folder_unix);
509 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
510 const GtkFilePath *path,
513 GtkFileSystemUnix *system_unix;
514 const char *filename;
517 int save_errno = errno;
519 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
521 filename = gtk_file_path_get_string (path);
522 g_return_val_if_fail (filename != NULL, FALSE);
523 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
525 tmp = remove_trailing_slash (filename);
527 result = mkdir (tmp, 0777) == 0;
533 gchar *display_name = g_filename_display_name (filename);
535 GTK_FILE_SYSTEM_ERROR,
536 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
537 _("Error creating directory '%s': %s"),
539 g_strerror (save_errno));
540 g_free (display_name);
544 if (filename_is_root (filename))
545 return TRUE; /* hmmm, but with no notification */
547 parent = get_parent_dir (filename);
550 GtkFileFolderUnix *folder_unix;
552 folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
555 GtkFileInfoType types;
556 GtkFilePath *parent_path;
558 GtkFileFolder *folder;
560 /* This is sort of a hack. We re-get the folder, to ensure that the
561 * newly-created directory gets read into the folder's info hash table.
564 types = folder_unix->types;
566 parent_path = gtk_file_path_new_dup (parent);
567 folder = gtk_file_system_get_folder (file_system, parent_path, types, NULL);
568 gtk_file_path_free (parent_path);
572 paths = g_slist_append (NULL, (GtkFilePath *) path);
573 g_signal_emit_by_name (folder, "files-added", paths);
574 g_slist_free (paths);
575 g_object_unref (folder);
586 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
587 GtkFileSystemVolume *volume)
591 path = (GtkFilePath *) volume;
592 gtk_file_path_free (path);
596 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
597 GtkFileSystemVolume *volume)
599 return gtk_file_path_new_dup ("/");
603 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
604 GtkFileSystemVolume *volume)
610 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
611 GtkFileSystemVolume *volume,
615 GTK_FILE_SYSTEM_ERROR,
616 GTK_FILE_SYSTEM_ERROR_FAILED,
617 _("This file system does not support mounting"));
622 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
623 GtkFileSystemVolume *volume)
625 return g_strdup (_("Filesystem")); /* Same as Nautilus */
629 get_icon_type_from_stat (struct stat *statp)
631 if (S_ISBLK (statp->st_mode))
632 return ICON_BLOCK_DEVICE;
633 else if (S_ISLNK (statp->st_mode))
634 return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
635 else if (S_ISCHR (statp->st_mode))
636 return ICON_CHARACTER_DEVICE;
637 else if (S_ISDIR (statp->st_mode))
638 return ICON_DIRECTORY;
640 else if (S_ISFIFO (statp->st_mode))
644 else if (S_ISSOCK (statp->st_mode))
652 get_icon_type (const char *filename,
657 /* If stat fails, try to fall back to lstat to catch broken links
659 if (stat (filename, &statbuf) != 0)
661 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
663 int save_errno = errno;
664 gchar *display_name = g_filename_display_name (filename);
666 GTK_FILE_SYSTEM_ERROR,
667 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
668 _("Error getting information for '%s': %s"),
670 g_strerror (save_errno));
671 g_free (display_name);
677 return get_icon_type_from_stat (&statbuf);
687 icon_cache_element_free (IconCacheElement *element)
690 g_object_unref (element->pixbuf);
695 icon_theme_changed (GtkIconTheme *icon_theme)
699 /* Difference from the initial creation is that we don't
700 * reconnect the signal
702 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
703 (GDestroyNotify)g_free,
704 (GDestroyNotify)icon_cache_element_free);
705 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
706 cache, (GDestroyNotify)g_hash_table_destroy);
710 get_cached_icon (GtkWidget *widget,
714 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
715 GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
716 IconCacheElement *element;
720 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
721 (GDestroyNotify)g_free,
722 (GDestroyNotify)icon_cache_element_free);
724 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
725 cache, (GDestroyNotify)g_hash_table_destroy);
726 g_signal_connect (icon_theme, "changed",
727 G_CALLBACK (icon_theme_changed), NULL);
730 element = g_hash_table_lookup (cache, name);
733 element = g_new0 (IconCacheElement, 1);
734 g_hash_table_insert (cache, g_strdup (name), element);
737 if (element->size != pixel_size)
740 g_object_unref (element->pixbuf);
741 element->size = pixel_size;
742 element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
743 pixel_size, 0, NULL);
746 return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
749 /* Renders a fallback icon from the stock system */
751 get_fallback_icon (GtkWidget *widget,
755 const char *stock_name;
760 case ICON_BLOCK_DEVICE:
761 stock_name = GTK_STOCK_HARDDISK;
765 stock_name = GTK_STOCK_DIRECTORY;
768 case ICON_EXECUTABLE:
769 stock_name = GTK_STOCK_EXECUTE;
773 stock_name = GTK_STOCK_FILE;
777 pixbuf = gtk_widget_render_icon (widget, stock_name, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
780 GTK_FILE_SYSTEM_ERROR,
781 GTK_FILE_SYSTEM_ERROR_FAILED,
782 _("Could not get a stock icon for %s"),
789 gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
790 GtkFileSystemVolume *volume,
797 pixbuf = get_cached_icon (widget, "gnome-fs-blockdev", pixel_size);
801 pixbuf = get_fallback_icon (widget, ICON_BLOCK_DEVICE, error);
802 g_assert (pixbuf != NULL);
808 get_parent_dir (const char *filename)
812 len = strlen (filename);
814 /* Ignore trailing slashes */
815 if (len > 1 && filename[len - 1] == '/')
819 tmp = g_strndup (filename, len - 1);
821 parent = g_path_get_dirname (tmp);
827 return g_path_get_dirname (filename);
831 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
832 const GtkFilePath *path,
833 GtkFilePath **parent,
836 const char *filename;
838 filename = gtk_file_path_get_string (path);
839 g_return_val_if_fail (filename != NULL, FALSE);
840 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
842 if (filename_is_root (filename))
848 gchar *parent_filename = get_parent_dir (filename);
849 *parent = filename_to_path (parent_filename);
850 g_free (parent_filename);
857 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
858 const GtkFilePath *base_path,
859 const gchar *display_name,
862 const char *base_filename;
864 gchar *full_filename;
865 GError *tmp_error = NULL;
868 base_filename = gtk_file_path_get_string (base_path);
869 g_return_val_if_fail (base_filename != NULL, NULL);
870 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
872 if (strchr (display_name, G_DIR_SEPARATOR))
875 GTK_FILE_SYSTEM_ERROR,
876 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
877 _("The name \"%s\" is not valid because it contains the character \"%s\". "
878 "Please use a different name."),
884 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
888 GTK_FILE_SYSTEM_ERROR,
889 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
893 g_error_free (tmp_error);
898 full_filename = g_build_filename (base_filename, filename, NULL);
899 result = filename_to_path (full_filename);
901 g_free (full_filename);
906 /* If this was a publically exported function, it should return
907 * a dup'ed result, but we make it modify-in-place for efficiency
908 * here, and because it works for us.
911 canonicalize_filename (gchar *filename)
914 gboolean last_was_slash = FALSE;
921 if (*p == G_DIR_SEPARATOR)
924 *q++ = G_DIR_SEPARATOR;
926 last_was_slash = TRUE;
930 if (last_was_slash && *p == '.')
932 if (*(p + 1) == G_DIR_SEPARATOR ||
935 if (*(p + 1) == '\0')
940 else if (*(p + 1) == '.' &&
941 (*(p + 2) == G_DIR_SEPARATOR ||
944 if (q > filename + 1)
947 while (q > filename + 1 &&
948 *(q - 1) != G_DIR_SEPARATOR)
952 if (*(p + 2) == '\0')
960 last_was_slash = FALSE;
966 last_was_slash = FALSE;
973 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
979 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
981 expand_tilde (const char *filename)
987 if (filename[0] != '~')
988 return g_strdup (filename);
990 notilde = filename + 1;
992 slash = strchr (notilde, G_DIR_SEPARATOR);
996 if (slash == notilde)
998 home = g_get_home_dir ();
1001 return g_strdup (filename);
1006 struct passwd *passwd;
1008 username = g_strndup (notilde, slash - notilde);
1009 passwd = getpwnam (username);
1013 return g_strdup (filename);
1015 home = passwd->pw_dir;
1018 return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
1022 gtk_file_system_unix_parse (GtkFileSystem *file_system,
1023 const GtkFilePath *base_path,
1025 GtkFilePath **folder,
1029 const char *base_filename;
1032 gboolean result = FALSE;
1034 base_filename = gtk_file_path_get_string (base_path);
1035 g_return_val_if_fail (base_filename != NULL, FALSE);
1036 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
1038 filename = expand_tilde (str);
1042 GTK_FILE_SYSTEM_ERROR,
1043 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1044 "%s", ""); /* nothing for now, as we are string-frozen */
1048 last_slash = strrchr (filename, G_DIR_SEPARATOR);
1051 *folder = gtk_file_path_copy (base_path);
1052 *file_part = g_strdup (filename);
1059 GError *tmp_error = NULL;
1061 if (last_slash == filename)
1062 folder_part = g_strdup ("/");
1064 folder_part = g_filename_from_utf8 (filename, last_slash - filename,
1065 NULL, NULL, &tmp_error);
1070 GTK_FILE_SYSTEM_ERROR,
1071 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1073 tmp_error->message);
1074 g_error_free (tmp_error);
1078 if (folder_part[0] == G_DIR_SEPARATOR)
1079 folder_path = folder_part;
1082 folder_path = g_build_filename (base_filename, folder_part, NULL);
1083 g_free (folder_part);
1086 canonicalize_filename (folder_path);
1088 *folder = filename_to_path (folder_path);
1089 *file_part = g_strdup (last_slash + 1);
1091 g_free (folder_path);
1103 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
1104 const GtkFilePath *path)
1106 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
1110 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
1111 const GtkFilePath *path)
1113 return g_strdup (gtk_file_path_get_string (path));
1116 static GtkFilePath *
1117 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
1121 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
1125 path = filename_to_path (filename);
1134 static GtkFilePath *
1135 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
1136 const gchar *filename)
1138 return filename_to_path (filename);
1141 /* Returns the name of the icon to be used for a path which is known to be a
1142 * directory. This can vary for Home, Desktop, etc.
1145 get_icon_name_for_directory (const char *path)
1147 static char *desktop_path = NULL;
1149 if (!g_get_home_dir ())
1150 return "gnome-fs-directory";
1153 desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
1155 if (strcmp (g_get_home_dir (), path) == 0)
1156 return "gnome-fs-home";
1157 else if (strcmp (desktop_path, path) == 0)
1158 return "gnome-fs-desktop";
1160 return "gnome-fs-directory";
1163 /* Computes our internal icon type based on a path name; also returns the MIME
1164 * type in case we come up with ICON_REGULAR.
1167 get_icon_type_from_path (GtkFileSystemUnix *system_unix,
1168 const GtkFilePath *path,
1169 const char **mime_type)
1171 const char *filename;
1173 GtkFileFolderUnix *folder_unix;
1176 filename = gtk_file_path_get_string (path);
1177 dirname = g_path_get_dirname (filename);
1178 folder_unix = g_hash_table_lookup (system_unix->folder_hash, dirname);
1183 if (folder_unix && folder_unix->have_stat)
1186 struct stat_info_entry *entry;
1188 g_assert (folder_unix->stat_info != NULL);
1190 basename = g_path_get_basename (filename);
1191 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1195 if (entry->icon_type == ICON_UNDECIDED)
1197 entry->icon_type = get_icon_type_from_stat (&entry->statbuf);
1198 g_assert (entry->icon_type != ICON_UNDECIDED);
1200 icon_type = entry->icon_type;
1201 if (icon_type == ICON_REGULAR)
1203 fill_in_mime_type (folder_unix);
1204 *mime_type = entry->mime_type;
1211 icon_type = get_icon_type (filename, NULL);
1212 if (icon_type == ICON_REGULAR)
1213 *mime_type = xdg_mime_get_mime_type_for_file (filename);
1218 /* Renders an icon for a non-ICON_REGULAR file */
1220 get_special_icon (IconType icon_type,
1221 const GtkFilePath *path,
1227 g_assert (icon_type != ICON_REGULAR);
1231 case ICON_BLOCK_DEVICE:
1232 name = "gnome-fs-blockdev";
1234 case ICON_BROKEN_SYMBOLIC_LINK:
1235 name = "gnome-fs-symlink";
1237 case ICON_CHARACTER_DEVICE:
1238 name = "gnome-fs-chardev";
1240 case ICON_DIRECTORY: {
1241 const char *filename;
1243 filename = gtk_file_path_get_string (path);
1244 name = get_icon_name_for_directory (filename);
1247 case ICON_EXECUTABLE:
1248 name ="gnome-fs-executable";
1251 name = "gnome-fs-fifo";
1254 name = "gnome-fs-socket";
1257 g_assert_not_reached ();
1261 return get_cached_icon (widget, name, pixel_size);
1265 get_icon_for_mime_type (GtkWidget *widget,
1266 const char *mime_type,
1269 const char *separator;
1273 separator = strchr (mime_type, '/');
1275 return NULL; /* maybe we should return a GError with "invalid MIME-type" */
1277 icon_name = g_string_new ("gnome-mime-");
1278 g_string_append_len (icon_name, mime_type, separator - mime_type);
1279 g_string_append_c (icon_name, '-');
1280 g_string_append (icon_name, separator + 1);
1281 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1282 g_string_free (icon_name, TRUE);
1286 icon_name = g_string_new ("gnome-mime-");
1287 g_string_append_len (icon_name, mime_type, separator - mime_type);
1288 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1289 g_string_free (icon_name, TRUE);
1295 gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
1296 const GtkFilePath *path,
1301 GtkFileSystemUnix *system_unix;
1303 const char *mime_type;
1306 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
1308 icon_type = get_icon_type_from_path (system_unix, path, &mime_type);
1310 switch (icon_type) {
1315 pixbuf = get_icon_for_mime_type (widget, mime_type, pixel_size);
1319 pixbuf = get_special_icon (icon_type, path, widget, pixel_size);
1327 pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
1331 pixbuf = get_fallback_icon (widget, icon_type, error);
1339 string_list_free (GSList *list)
1343 for (l = list; l; l = l->next)
1346 g_slist_free (list);
1349 /* Returns whether a URI is a local file:// */
1351 is_local_uri (const char *uri)
1357 /* This is rather crude, but hey */
1358 filename = g_filename_from_uri (uri, &hostname, NULL);
1360 result = (filename && !hostname);
1369 bookmark_get_filename (void)
1373 filename = g_build_filename (g_get_home_dir (), BOOKMARKS_FILENAME, NULL);
1375 g_assert (filename != NULL);
1381 string_list_read (const gchar *filename,
1386 gboolean result = FALSE;
1390 if (g_file_get_contents (filename, &contents, NULL, error))
1392 gchar **lines = g_strsplit (contents, "\n", -1);
1396 table = g_hash_table_new (g_str_hash, g_str_equal);
1398 for (i = 0; lines[i]; i++)
1400 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1402 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1403 g_hash_table_insert (table, lines[i], lines[i]);
1408 g_hash_table_destroy (table);
1411 *bookmarks = g_slist_reverse (*bookmarks);
1419 string_list_write (gchar *filename,
1424 gboolean result = TRUE;
1429 /* First, write a temporary file */
1430 tmp_filename = g_strdup_printf ("%s-XXXXXX", filename);
1432 fd = g_mkstemp (tmp_filename);
1435 saved_errno = errno;
1439 if ((file = fdopen (fd, "w")) != NULL)
1443 for (l = bookmarks; l; l = l->next)
1444 if (fputs (l->data, file) == EOF
1445 || fputs ("\n", file) == EOF)
1447 saved_errno = errno;
1451 if (fclose (file) == EOF)
1453 saved_errno = errno;
1457 if (rename (tmp_filename, filename) == -1)
1459 saved_errno = errno;
1468 saved_errno = errno;
1470 /* fdopen() failed, so we can't do much error checking here anyway */
1477 GTK_FILE_SYSTEM_ERROR,
1478 GTK_FILE_SYSTEM_ERROR_FAILED,
1479 _("Writing %s failed: %s"),
1481 g_strerror (saved_errno));
1485 unlink (tmp_filename); /* again, not much error checking we can do here */
1489 g_free (tmp_filename);
1495 bookmark_list_read (GSList **bookmarks,
1501 filename = bookmark_get_filename ();
1502 result = string_list_read (filename, bookmarks, error);
1509 bookmark_list_write (GSList *bookmarks,
1515 filename = bookmark_get_filename ();
1516 result = string_list_write (filename, bookmarks, error);
1523 gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
1524 const GtkFilePath *path,
1536 if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1538 g_propagate_error (error, err);
1542 num_bookmarks = g_slist_length (bookmarks);
1543 g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1547 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1549 for (l = bookmarks; l; l = l->next)
1551 char *bookmark, *space;
1555 space = strchr (bookmark, ' ');
1558 if (strcmp (bookmark, uri) != 0)
1566 GTK_FILE_SYSTEM_ERROR,
1567 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1568 _("'%s' already exists in the bookmarks list"),
1574 bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1575 if (bookmark_list_write (bookmarks, error))
1578 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1584 string_list_free (bookmarks);
1590 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1591 const GtkFilePath *path,
1599 if (!bookmark_list_read (&bookmarks, error))
1604 uri = gtk_file_system_path_to_uri (file_system, path);
1606 for (l = bookmarks; l; l = l->next)
1608 char *bookmark, *space;
1610 bookmark = (char *)l->data;
1611 space = strchr (bookmark, ' ');
1615 if (strcmp (bookmark, uri) != 0)
1623 bookmarks = g_slist_remove_link (bookmarks, l);
1626 if (bookmark_list_write (bookmarks, error))
1630 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1638 GTK_FILE_SYSTEM_ERROR,
1639 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1640 _("'%s' does not exist in the bookmarks list"),
1646 string_list_free (bookmarks);
1652 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1658 if (!bookmark_list_read (&bookmarks, NULL))
1663 for (l = bookmarks; l; l = l->next)
1665 char *bookmark, *space;
1667 bookmark = (char *)l->data;
1668 space = strchr (bookmark, ' ');
1672 if (is_local_uri (bookmark))
1673 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
1676 string_list_free (bookmarks);
1678 result = g_slist_reverse (result);
1683 gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
1684 const GtkFilePath *path)
1689 char *bookmark, *space, *uri;
1694 uri = gtk_file_system_path_to_uri (file_system, path);
1695 bookmark_list_read (&labels, NULL);
1697 for (l = labels; l && !label; l = l->next)
1699 bookmark = (char *)l->data;
1700 space = strchr (bookmark, ' ');
1706 if (strcmp (uri, bookmark) == 0)
1707 label = g_strdup (space + 1);
1710 string_list_free (labels);
1717 gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
1718 const GtkFilePath *path,
1723 gchar *bookmark, *space, *uri;
1728 uri = gtk_file_system_path_to_uri (file_system, path);
1729 bookmark_list_read (&labels, NULL);
1732 for (l = labels; l && !found; l = l->next)
1734 bookmark = (gchar *)l->data;
1735 space = strchr (bookmark, ' ');
1739 if (strcmp (bookmark, uri) != 0)
1748 if (label && *label)
1749 l->data = g_strdup_printf ("%s %s", uri, label);
1751 l->data = g_strdup (uri);
1760 if (bookmark_list_write (labels, NULL))
1761 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1764 string_list_free (labels);
1772 gtk_file_folder_unix_get_type (void)
1774 static GType file_folder_unix_type = 0;
1776 if (!file_folder_unix_type)
1778 static const GTypeInfo file_folder_unix_info =
1780 sizeof (GtkFileFolderUnixClass),
1781 NULL, /* base_init */
1782 NULL, /* base_finalize */
1783 (GClassInitFunc) gtk_file_folder_unix_class_init,
1784 NULL, /* class_finalize */
1785 NULL, /* class_data */
1786 sizeof (GtkFileFolderUnix),
1787 0, /* n_preallocs */
1788 (GInstanceInitFunc) gtk_file_folder_unix_init,
1791 static const GInterfaceInfo file_folder_info =
1793 (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1794 NULL, /* interface_finalize */
1795 NULL /* interface_data */
1798 file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1799 "GtkFileFolderUnix",
1800 &file_folder_unix_info, 0);
1801 g_type_add_interface_static (file_folder_unix_type,
1802 GTK_TYPE_FILE_FOLDER,
1806 return file_folder_unix_type;
1810 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1812 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1814 folder_parent_class = g_type_class_peek_parent (class);
1816 gobject_class->finalize = gtk_file_folder_unix_finalize;
1820 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1822 iface->get_info = gtk_file_folder_unix_get_info;
1823 iface->list_children = gtk_file_folder_unix_list_children;
1824 iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;
1828 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1833 gtk_file_folder_unix_finalize (GObject *object)
1835 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1837 g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
1839 if (folder_unix->stat_info)
1842 g_print ("Releasing information for directory %s\n", folder_unix->filename);
1844 g_hash_table_destroy (folder_unix->stat_info);
1847 g_free (folder_unix->filename);
1849 folder_parent_class->finalize (object);
1852 /* Creates a GtkFileInfo for "/" by stat()ing it */
1853 static GtkFileInfo *
1854 file_info_for_root_with_error (const char *root_name,
1857 struct stat statbuf;
1860 if (stat (root_name, &statbuf) != 0)
1864 saved_errno = errno;
1866 GTK_FILE_SYSTEM_ERROR,
1867 GTK_FILE_SYSTEM_ERROR_FAILED,
1868 _("Error getting information for '/': %s"),
1869 g_strerror (saved_errno));
1874 info = gtk_file_info_new ();
1875 gtk_file_info_set_display_name (info, "/");
1876 gtk_file_info_set_is_folder (info, TRUE);
1877 gtk_file_info_set_is_hidden (info, FALSE);
1878 gtk_file_info_set_mime_type (info, "x-directory/normal");
1879 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1880 gtk_file_info_set_size (info, statbuf.st_size);
1886 stat_with_error (const char *filename,
1887 struct stat *statbuf,
1890 if (stat (filename, statbuf) == -1 &&
1891 (errno != ENOENT || lstat (filename, statbuf) == -1))
1897 saved_errno = errno;
1899 if (saved_errno == ENOENT)
1900 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
1902 code = GTK_FILE_SYSTEM_ERROR_FAILED;
1904 display_name = g_filename_display_name (filename);
1906 GTK_FILE_SYSTEM_ERROR,
1908 _("Error getting information for '%s': %s"),
1910 g_strerror (saved_errno));
1912 g_free (display_name);
1919 /* Creates a new GtkFileInfo from the specified data */
1920 static GtkFileInfo *
1921 create_file_info (const char *filename,
1922 const char *basename,
1923 GtkFileInfoType types,
1924 struct stat *statbuf,
1925 const char *mime_type)
1929 info = gtk_file_info_new ();
1931 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1933 gchar *display_name = g_filename_display_basename (filename);
1934 gtk_file_info_set_display_name (info, display_name);
1935 g_free (display_name);
1938 if (types & GTK_FILE_INFO_IS_HIDDEN)
1939 gtk_file_info_set_is_hidden (info, basename[0] == '.');
1941 if (types & GTK_FILE_INFO_IS_FOLDER)
1942 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode));
1944 if (types & GTK_FILE_INFO_MIME_TYPE)
1945 gtk_file_info_set_mime_type (info, mime_type);
1947 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1948 gtk_file_info_set_modification_time (info, statbuf->st_mtime);
1950 if (types & GTK_FILE_INFO_SIZE)
1951 gtk_file_info_set_size (info, (gint64) statbuf->st_size);
1956 static struct stat_info_entry *
1957 create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix,
1958 const char *filename,
1959 const char *basename,
1960 struct stat *statbuf)
1964 struct stat_info_entry *entry;
1966 entry = g_new0 (struct stat_info_entry, 1);
1968 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
1969 entry->statbuf = *statbuf;
1971 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
1972 entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename));
1974 g_hash_table_insert (folder_unix->stat_info,
1975 g_strdup (basename),
1978 path = gtk_file_path_new_dup (filename);
1979 paths = g_slist_append (NULL, path);
1980 g_signal_emit_by_name (folder_unix, "files-added", paths);
1981 gtk_file_path_free (path);
1982 g_slist_free (paths);
1987 static GtkFileInfo *
1988 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
1989 const GtkFilePath *path,
1992 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1994 gchar *dirname, *basename;
1995 const char *filename;
1996 GtkFileInfoType types;
1997 struct stat statbuf;
1998 const char *mime_type;
2000 /* Get_info for "/" */
2003 g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL);
2004 return file_info_for_root_with_error (folder_unix->filename, error);
2007 /* Get_info for normal files */
2009 filename = gtk_file_path_get_string (path);
2010 g_return_val_if_fail (filename != NULL, NULL);
2011 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
2013 dirname = get_parent_dir (filename);
2014 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
2017 basename = g_path_get_basename (filename);
2018 types = folder_unix->types;
2020 if (folder_unix->have_stat)
2022 struct stat_info_entry *entry;
2024 g_assert (folder_unix->stat_info != NULL);
2025 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2029 if (!stat_with_error (filename, &statbuf, error))
2035 entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf);
2038 info = create_file_info (filename, basename, types, &entry->statbuf, entry->mime_type);
2044 if (!stat_with_error (filename, &statbuf, error))
2050 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
2051 mime_type = xdg_mime_get_mime_type_for_file (filename);
2055 info = create_file_info (filename, basename, types, &statbuf, mime_type);
2063 cb_list_children (gpointer key, gpointer value, gpointer user_data)
2065 GSList **children = user_data;
2066 *children = g_slist_prepend (*children, key);
2070 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
2074 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2077 if (!fill_in_names (folder_unix, error))
2082 /* Get the list of basenames. */
2083 g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
2085 /* Turn basenames into GFilePaths. */
2086 for (l = *children; l; l = l->next)
2088 const char *basename = l->data;
2089 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2090 l->data = filename_to_path (fullname);
2098 gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
2100 /* Since we don't do asynchronous loads, we are always finished loading */
2105 free_stat_info_entry (struct stat_info_entry *entry)
2107 g_free (entry->mime_type);
2112 fill_in_names (GtkFileFolderUnix *folder_unix, GError **error)
2116 if (folder_unix->stat_info)
2119 dir = g_dir_open (folder_unix->filename, 0, error);
2123 folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal,
2124 (GDestroyNotify) g_free,
2125 (GDestroyNotify) free_stat_info_entry);
2129 struct stat_info_entry *entry;
2130 const gchar *basename;
2132 basename = g_dir_read_name (dir);
2136 entry = g_new0 (struct stat_info_entry, 1);
2137 if (folder_unix->is_network_dir)
2138 entry->statbuf.st_mode = S_IFDIR;
2140 g_hash_table_insert (folder_unix->stat_info,
2141 g_strdup (basename),
2147 folder_unix->asof = time (NULL);
2152 cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data)
2154 const char *basename = key;
2155 struct stat_info_entry *entry = value;
2156 GtkFileFolderUnix *folder_unix = user_data;
2157 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2160 if (stat (fullname, &entry->statbuf) == -1 &&
2161 (errno != ENOENT || lstat (fullname, &entry->statbuf) == -1))
2162 result = TRUE; /* Couldn't stat -- remove from hash. */
2172 fill_in_stats (GtkFileFolderUnix *folder_unix)
2174 if (folder_unix->have_stat)
2177 if (!fill_in_names (folder_unix, NULL))
2180 if (!folder_unix->is_network_dir)
2181 g_hash_table_foreach_remove (folder_unix->stat_info,
2185 folder_unix->have_stat = TRUE;
2190 cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data)
2192 const char *basename = key;
2193 struct stat_info_entry *entry = value;
2194 GtkFileFolderUnix *folder_unix = user_data;
2195 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2197 /* FIXME: Should not need to re-stat. */
2198 const char *mime_type = xdg_mime_get_mime_type_for_file (fullname);
2199 entry->mime_type = g_strdup (mime_type);
2202 /* FIXME: free on NULL? */
2207 fill_in_mime_type (GtkFileFolderUnix *folder_unix)
2209 if (folder_unix->have_mime_type)
2212 if (!folder_unix->have_stat)
2215 g_assert (folder_unix->stat_info != NULL);
2217 g_hash_table_foreach_remove (folder_unix->stat_info,
2218 cb_fill_in_mime_type,
2221 folder_unix->have_mime_type = TRUE;
2224 static GtkFilePath *
2225 filename_to_path (const char *filename)
2229 tmp = remove_trailing_slash (filename);
2230 return gtk_file_path_new_steal (tmp);
2234 filename_is_root (const char *filename)
2236 const gchar *after_root;
2238 after_root = g_path_skip_root (filename);
2240 return (after_root != NULL && *after_root == '\0');
2243 #define __GTK_FILE_SYSTEM_UNIX_C__
2244 #include "gtkaliasdef.c"