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"
28 #define XDG_PREFIX _gtk_xdg
29 #include "xdgmime/xdgmime.h"
34 #include <sys/types.h>
38 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
39 #define BOOKMARKS_TMP_FILENAME ".gtk-bookmarks-XXXXXX"
41 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
43 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
44 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
45 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
47 struct _GtkFileSystemUnixClass
49 GObjectClass parent_class;
52 struct _GtkFileSystemUnix
54 GObject parent_instance;
56 GHashTable *folder_hash;
59 /* Icon type, supplemented by MIME type
63 ICON_REGULAR, /* Use mime type for icon */
65 ICON_BROKEN_SYMBOLIC_LINK,
66 ICON_CHARACTER_DEVICE,
74 #define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
75 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
76 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
77 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
78 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
79 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
81 typedef struct _GtkFileFolderUnix GtkFileFolderUnix;
82 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
84 struct _GtkFileFolderUnixClass
86 GObjectClass parent_class;
89 struct _GtkFileFolderUnix
91 GObject parent_instance;
93 GtkFileSystemUnix *system_unix;
94 GtkFileInfoType types;
98 static GObjectClass *system_parent_class;
99 static GObjectClass *folder_parent_class;
101 static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class);
102 static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
103 static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
104 static void gtk_file_system_unix_finalize (GObject *object);
106 static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
107 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
108 const GtkFilePath *path);
110 static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
111 const GtkFilePath *path,
112 GtkFileInfoType types,
114 static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
115 const GtkFilePath *path,
118 static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
119 GtkFileSystemVolume *volume);
120 static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
121 GtkFileSystemVolume *volume);
122 static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
123 GtkFileSystemVolume *volume);
124 static gboolean gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
125 GtkFileSystemVolume *volume,
127 static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
128 GtkFileSystemVolume *volume);
129 static GdkPixbuf * gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
130 GtkFileSystemVolume *volume,
135 static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
136 const GtkFilePath *path,
137 GtkFilePath **parent,
139 static GtkFilePath * gtk_file_system_unix_make_path (GtkFileSystem *file_system,
140 const GtkFilePath *base_path,
141 const gchar *display_name,
143 static gboolean gtk_file_system_unix_parse (GtkFileSystem *file_system,
144 const GtkFilePath *base_path,
146 GtkFilePath **folder,
150 static gchar * gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
151 const GtkFilePath *path);
152 static gchar * gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
153 const GtkFilePath *path);
154 static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
156 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
157 const gchar *filename);
159 static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
160 const GtkFilePath *path,
165 static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
166 const GtkFilePath *path,
169 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
170 const GtkFilePath *path,
172 static GSList * gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system);
174 static GType gtk_file_folder_unix_get_type (void);
175 static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
176 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
177 static void gtk_file_folder_unix_init (GtkFileFolderUnix *impl);
178 static void gtk_file_folder_unix_finalize (GObject *object);
180 static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
181 const GtkFilePath *path,
183 static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder,
187 static GtkFilePath *filename_to_path (const gchar *filename);
189 static gboolean filename_is_root (const char *filename);
190 static GtkFileInfo *filename_get_info (const gchar *filename,
191 GtkFileInfoType types,
198 gtk_file_system_unix_get_type (void)
200 static GType file_system_unix_type = 0;
202 if (!file_system_unix_type)
204 static const GTypeInfo file_system_unix_info =
206 sizeof (GtkFileSystemUnixClass),
207 NULL, /* base_init */
208 NULL, /* base_finalize */
209 (GClassInitFunc) gtk_file_system_unix_class_init,
210 NULL, /* class_finalize */
211 NULL, /* class_data */
212 sizeof (GtkFileSystemUnix),
214 (GInstanceInitFunc) gtk_file_system_unix_init,
217 static const GInterfaceInfo file_system_info =
219 (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
220 NULL, /* interface_finalize */
221 NULL /* interface_data */
224 file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
226 &file_system_unix_info, 0);
227 g_type_add_interface_static (file_system_unix_type,
228 GTK_TYPE_FILE_SYSTEM,
232 return file_system_unix_type;
236 * gtk_file_system_unix_new:
238 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
239 * implements the #GtkFileSystem interface with direct access to
240 * the filesystem using Unix/Linux API calls
242 * Return value: the new #GtkFileSystemUnix object
245 gtk_file_system_unix_new (void)
247 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
251 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
253 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
255 system_parent_class = g_type_class_peek_parent (class);
257 gobject_class->finalize = gtk_file_system_unix_finalize;
261 gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
263 iface->list_volumes = gtk_file_system_unix_list_volumes;
264 iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
265 iface->get_folder = gtk_file_system_unix_get_folder;
266 iface->create_folder = gtk_file_system_unix_create_folder;
267 iface->volume_free = gtk_file_system_unix_volume_free;
268 iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
269 iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
270 iface->volume_mount = gtk_file_system_unix_volume_mount;
271 iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
272 iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
273 iface->get_parent = gtk_file_system_unix_get_parent;
274 iface->make_path = gtk_file_system_unix_make_path;
275 iface->parse = gtk_file_system_unix_parse;
276 iface->path_to_uri = gtk_file_system_unix_path_to_uri;
277 iface->path_to_filename = gtk_file_system_unix_path_to_filename;
278 iface->uri_to_path = gtk_file_system_unix_uri_to_path;
279 iface->filename_to_path = gtk_file_system_unix_filename_to_path;
280 iface->render_icon = gtk_file_system_unix_render_icon;
281 iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
282 iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
283 iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
287 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
289 system_unix->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
293 gtk_file_system_unix_finalize (GObject *object)
295 GtkFileSystemUnix *system_unix;
297 system_unix = GTK_FILE_SYSTEM_UNIX (object);
299 /* FIXME: assert that the hash is empty? */
300 g_hash_table_destroy (system_unix->folder_hash);
302 system_parent_class->finalize (object);
305 /* Returns our single root volume */
306 static GtkFileSystemVolume *
307 get_root_volume (void)
309 return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
313 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
315 return g_slist_append (NULL, get_root_volume ());
318 static GtkFileSystemVolume *
319 gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
320 const GtkFilePath *path)
322 return get_root_volume ();
325 static GtkFileFolder *
326 gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
327 const GtkFilePath *path,
328 GtkFileInfoType types,
331 GtkFileSystemUnix *system_unix;
332 GtkFileFolderUnix *folder_unix;
333 const char *filename;
335 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
337 filename = gtk_file_path_get_string (path);
338 g_return_val_if_fail (filename != NULL, NULL);
339 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
341 folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename);
345 folder_unix->types |= types;
346 return g_object_ref (folder_unix);
350 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
351 folder_unix->system_unix = system_unix;
352 folder_unix->filename = g_strdup (filename);
353 folder_unix->types = types;
355 g_hash_table_insert (system_unix->folder_hash, folder_unix->filename, folder_unix);
357 return GTK_FILE_FOLDER (folder_unix);
362 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
363 const GtkFilePath *path,
366 GtkFileSystemUnix *system_unix;
367 const char *filename;
371 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
373 filename = gtk_file_path_get_string (path);
374 g_return_val_if_fail (filename != NULL, FALSE);
375 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
377 result = mkdir (filename, 0777) == 0;
381 int save_errno = errno;
382 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
384 GTK_FILE_SYSTEM_ERROR,
385 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
386 _("error creating directory '%s': %s"),
387 filename_utf8 ? filename_utf8 : "???",
388 g_strerror (save_errno));
389 g_free (filename_utf8);
393 if (filename_is_root (filename))
394 return TRUE; /* hmmm, but with no notification */
396 parent = g_path_get_dirname (filename);
399 GtkFileFolderUnix *folder_unix;
401 folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
406 paths = g_slist_append (NULL, (GtkFilePath *) path);
407 g_signal_emit_by_name (folder_unix, "files-added", paths);
408 g_slist_free (paths);
416 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
417 GtkFileSystemVolume *volume)
421 path = (GtkFilePath *) volume;
422 gtk_file_path_free (path);
426 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
427 GtkFileSystemVolume *volume)
429 return gtk_file_path_new_dup ("/");
433 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
434 GtkFileSystemVolume *volume)
440 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
441 GtkFileSystemVolume *volume,
445 GTK_FILE_SYSTEM_ERROR,
446 GTK_FILE_SYSTEM_ERROR_FAILED,
447 _("This file system does not support mounting"));
452 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
453 GtkFileSystemVolume *volume)
455 return g_strdup (_("Filesystem")); /* Same as Nautilus */
459 get_icon_type (const char *filename,
465 /* If stat fails, try to fall back to lstat to catch broken links
467 if (stat (filename, &statbuf) != 0)
469 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
471 int save_errno = errno;
472 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
474 GTK_FILE_SYSTEM_ERROR,
475 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
476 _("error getting information for '%s': %s"),
477 filename_utf8 ? filename_utf8 : "???",
478 g_strerror (save_errno));
479 g_free (filename_utf8);
485 if (S_ISBLK (statbuf.st_mode))
486 icon_type = ICON_BLOCK_DEVICE;
487 else if (S_ISLNK (statbuf.st_mode))
488 icon_type = ICON_BROKEN_SYMBOLIC_LINK; /* See above */
489 else if (S_ISCHR (statbuf.st_mode))
490 icon_type = ICON_CHARACTER_DEVICE;
491 else if (S_ISDIR (statbuf.st_mode))
492 icon_type = ICON_DIRECTORY;
493 else if (S_ISFIFO (statbuf.st_mode))
494 icon_type = ICON_FIFO;
495 else if (S_ISSOCK (statbuf.st_mode))
496 icon_type = ICON_SOCKET;
499 icon_type = ICON_REGULAR;
502 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
503 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
504 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
505 strcmp (mime_type, "application/x-executable") == 0 ||
506 strcmp (mime_type, "application/x-shellscript") == 0))
507 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
521 icon_cache_element_free (IconCacheElement *element)
524 g_object_unref (element->pixbuf);
529 icon_theme_changed (GtkIconTheme *icon_theme)
533 /* Difference from the initial creation is that we don't
534 * reconnect the signal
536 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
537 (GDestroyNotify)g_free,
538 (GDestroyNotify)icon_cache_element_free);
539 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
540 cache, (GDestroyNotify)g_hash_table_destroy);
544 get_cached_icon (GtkWidget *widget,
548 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
549 GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
550 IconCacheElement *element;
554 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
555 (GDestroyNotify)g_free,
556 (GDestroyNotify)icon_cache_element_free);
558 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
559 cache, (GDestroyNotify)g_hash_table_destroy);
560 g_signal_connect (icon_theme, "changed",
561 G_CALLBACK (icon_theme_changed), NULL);
564 element = g_hash_table_lookup (cache, name);
567 element = g_new0 (IconCacheElement, 1);
568 g_hash_table_insert (cache, g_strdup (name), element);
571 if (element->size != pixel_size)
574 g_object_unref (element->pixbuf);
575 element->size = pixel_size;
576 element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
577 pixel_size, 0, NULL);
580 return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
584 gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
585 GtkFileSystemVolume *volume,
590 /* FIXME: set the GError if we can't load the icon */
591 return get_cached_icon (widget, "gnome-fs-blockdev", pixel_size);
595 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
596 const GtkFilePath *path,
597 GtkFilePath **parent,
600 const char *filename;
602 filename = gtk_file_path_get_string (path);
603 g_return_val_if_fail (filename != NULL, FALSE);
604 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
606 if (filename_is_root (filename))
612 gchar *parent_filename = g_path_get_dirname (filename);
613 *parent = filename_to_path (parent_filename);
614 g_free (parent_filename);
621 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
622 const GtkFilePath *base_path,
623 const gchar *display_name,
626 const char *base_filename;
628 gchar *full_filename;
629 GError *tmp_error = NULL;
632 base_filename = gtk_file_path_get_string (base_path);
633 g_return_val_if_fail (base_filename != NULL, NULL);
634 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
636 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
640 GTK_FILE_SYSTEM_ERROR,
641 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
645 g_error_free (tmp_error);
650 full_filename = g_build_filename (base_filename, filename, NULL);
651 result = filename_to_path (full_filename);
653 g_free (full_filename);
658 /* If this was a publically exported function, it should return
659 * a dup'ed result, but we make it modify-in-place for efficiency
660 * here, and because it works for us.
663 canonicalize_filename (gchar *filename)
666 gboolean last_was_slash = FALSE;
673 if (*p == G_DIR_SEPARATOR)
676 *q++ = G_DIR_SEPARATOR;
678 last_was_slash = TRUE;
682 if (last_was_slash && *p == '.')
684 if (*(p + 1) == G_DIR_SEPARATOR ||
687 if (*(p + 1) == '\0')
692 else if (*(p + 1) == '.' &&
693 (*(p + 2) == G_DIR_SEPARATOR ||
696 if (q > filename + 1)
699 while (q > filename + 1 &&
700 *(q - 1) != G_DIR_SEPARATOR)
704 if (*(p + 2) == '\0')
712 last_was_slash = FALSE;
718 last_was_slash = FALSE;
725 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
732 gtk_file_system_unix_parse (GtkFileSystem *file_system,
733 const GtkFilePath *base_path,
735 GtkFilePath **folder,
739 const char *base_filename;
741 gboolean result = FALSE;
743 base_filename = gtk_file_path_get_string (base_path);
744 g_return_val_if_fail (base_filename != NULL, FALSE);
745 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
747 last_slash = strrchr (str, G_DIR_SEPARATOR);
750 *folder = gtk_file_path_copy (base_path);
751 *file_part = g_strdup (str);
758 GError *tmp_error = NULL;
760 if (last_slash == str)
761 folder_part = g_strdup ("/");
763 folder_part = g_filename_from_utf8 (str, last_slash - str,
764 NULL, NULL, &tmp_error);
769 GTK_FILE_SYSTEM_ERROR,
770 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
773 g_error_free (tmp_error);
777 if (folder_part[0] == G_DIR_SEPARATOR)
778 folder_path = folder_part;
781 folder_path = g_build_filename (base_filename, folder_part, NULL);
782 g_free (folder_part);
785 canonicalize_filename (folder_path);
787 *folder = filename_to_path (folder_path);
788 *file_part = g_strdup (last_slash + 1);
790 g_free (folder_path);
800 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
801 const GtkFilePath *path)
803 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
807 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
808 const GtkFilePath *path)
810 return g_strdup (gtk_file_path_get_string (path));
814 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
817 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
819 return gtk_file_path_new_steal (filename);
825 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
826 const gchar *filename)
828 return gtk_file_path_new_dup (filename);
832 get_icon_for_directory (const char *path)
834 static char *desktop_path = NULL;
836 if (!g_get_home_dir ())
837 return "gnome-fs-directory";
840 desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
842 if (strcmp (g_get_home_dir (), path) == 0)
843 return "gnome-fs-home";
844 else if (strcmp (desktop_path, path) == 0)
845 return "gnome-fs-desktop";
847 return "gnome-fs-directory";
851 gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
852 const GtkFilePath *path,
857 const char *filename;
859 const char *mime_type;
861 filename = gtk_file_path_get_string (path);
862 icon_type = get_icon_type (filename, error);
864 /* FIXME: this function should not return NULL without setting the GError; we
865 * should perhaps provide a "never fails" generic stock icon for when all else
869 if (icon_type == ICON_NONE)
872 if (icon_type != ICON_REGULAR)
878 case ICON_BLOCK_DEVICE:
879 name = "gnome-fs-blockdev";
881 case ICON_BROKEN_SYMBOLIC_LINK:
882 name = "gnome-fs-symlink";
884 case ICON_CHARACTER_DEVICE:
885 name = "gnome-fs-chardev";
888 name = get_icon_for_directory (filename);
890 case ICON_EXECUTABLE:
891 name ="gnome-fs-executable";
894 name = "gnome-fs-fifo";
897 name = "gnome-fs-socket";
900 g_assert_not_reached ();
904 return get_cached_icon (widget, name, pixel_size);
907 mime_type = xdg_mime_get_mime_type_for_file (filename);
910 const char *separator;
914 separator = strchr (mime_type, '/');
918 icon_name = g_string_new ("gnome-mime-");
919 g_string_append_len (icon_name, mime_type, separator - mime_type);
920 g_string_append_c (icon_name, '-');
921 g_string_append (icon_name, separator + 1);
922 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
923 g_string_free (icon_name, TRUE);
927 icon_name = g_string_new ("gnome-mime-");
928 g_string_append_len (icon_name, mime_type, separator - mime_type);
929 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
930 g_string_free (icon_name, TRUE);
935 return get_cached_icon (widget, "gnome-fs-regular", pixel_size);
939 bookmark_list_free (GSList *list)
943 for (l = list; l; l = l->next)
949 /* Returns whether a URI is a local file:// */
951 is_local_uri (const char *uri)
957 /* This is rather crude, but hey */
958 filename = g_filename_from_uri (uri, &hostname, NULL);
960 result = (filename && !hostname);
969 bookmark_get_filename (gboolean tmp_file)
973 filename = g_build_filename (g_get_home_dir (),
974 tmp_file ? BOOKMARKS_TMP_FILENAME : BOOKMARKS_FILENAME,
976 g_assert (filename != NULL);
981 bookmark_list_read (GSList **bookmarks, GError **error)
985 gboolean result = FALSE;
987 filename = bookmark_get_filename (FALSE);
990 if (g_file_get_contents (filename, &contents, NULL, error))
992 gchar **lines = g_strsplit (contents, "\n", -1);
996 table = g_hash_table_new (g_str_hash, g_str_equal);
998 for (i = 0; lines[i]; i++)
1000 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1002 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1003 g_hash_table_insert (table, lines[i], lines[i]);
1008 g_hash_table_destroy (table);
1011 *bookmarks = g_slist_reverse (*bookmarks);
1021 bookmark_list_write (GSList *bookmarks, GError **error)
1025 gboolean result = TRUE;
1030 /* First, write a temporary file */
1032 tmp_filename = bookmark_get_filename (TRUE);
1033 filename = bookmark_get_filename (FALSE);
1035 fd = g_mkstemp (tmp_filename);
1038 saved_errno = errno;
1042 if ((file = fdopen (fd, "w")) != NULL)
1046 for (l = bookmarks; l; l = l->next)
1047 if (fputs (l->data, file) == EOF
1048 || fputs ("\n", file) == EOF)
1050 saved_errno = errno;
1054 if (fclose (file) == EOF)
1056 saved_errno = errno;
1060 if (rename (tmp_filename, filename) == -1)
1062 saved_errno = errno;
1071 saved_errno = errno;
1073 /* fdopen() failed, so we can't do much error checking here anyway */
1080 GTK_FILE_SYSTEM_ERROR,
1081 GTK_FILE_SYSTEM_ERROR_FAILED,
1082 _("Bookmark saving failed (%s)"),
1083 g_strerror (saved_errno));
1087 unlink (tmp_filename); /* again, not much error checking we can do here */
1092 g_free (tmp_filename);
1098 gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
1099 const GtkFilePath *path,
1111 if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1113 g_propagate_error (error, err);
1117 num_bookmarks = g_slist_length (bookmarks);
1118 g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1122 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1124 for (l = bookmarks; l; l = l->next)
1126 const char *bookmark;
1129 if (strcmp (bookmark, uri) == 0)
1132 GTK_FILE_SYSTEM_ERROR,
1133 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1134 "%s already exists in the bookmarks list",
1140 bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1141 if (bookmark_list_write (bookmarks, error))
1144 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1150 bookmark_list_free (bookmarks);
1156 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1157 const GtkFilePath *path,
1165 if (!bookmark_list_read (&bookmarks, error))
1170 uri = gtk_file_system_path_to_uri (file_system, path);
1172 for (l = bookmarks; l; l = l->next)
1174 const char *bookmark;
1177 if (strcmp (bookmark, uri) == 0)
1180 bookmarks = g_slist_remove_link (bookmarks, l);
1183 if (bookmark_list_write (bookmarks, error))
1186 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1194 GTK_FILE_SYSTEM_ERROR,
1195 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1196 "%s does not exist in the bookmarks list",
1202 bookmark_list_free (bookmarks);
1208 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1214 if (!bookmark_list_read (&bookmarks, NULL))
1219 for (l = bookmarks; l; l = l->next)
1225 if (is_local_uri (name))
1226 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, name));
1229 bookmark_list_free (bookmarks);
1231 result = g_slist_reverse (result);
1239 gtk_file_folder_unix_get_type (void)
1241 static GType file_folder_unix_type = 0;
1243 if (!file_folder_unix_type)
1245 static const GTypeInfo file_folder_unix_info =
1247 sizeof (GtkFileFolderUnixClass),
1248 NULL, /* base_init */
1249 NULL, /* base_finalize */
1250 (GClassInitFunc) gtk_file_folder_unix_class_init,
1251 NULL, /* class_finalize */
1252 NULL, /* class_data */
1253 sizeof (GtkFileFolderUnix),
1254 0, /* n_preallocs */
1255 (GInstanceInitFunc) gtk_file_folder_unix_init,
1258 static const GInterfaceInfo file_folder_info =
1260 (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1261 NULL, /* interface_finalize */
1262 NULL /* interface_data */
1265 file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1266 "GtkFileFolderUnix",
1267 &file_folder_unix_info, 0);
1268 g_type_add_interface_static (file_folder_unix_type,
1269 GTK_TYPE_FILE_FOLDER,
1273 return file_folder_unix_type;
1277 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1279 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1281 folder_parent_class = g_type_class_peek_parent (class);
1283 gobject_class->finalize = gtk_file_folder_unix_finalize;
1287 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1289 iface->get_info = gtk_file_folder_unix_get_info;
1290 iface->list_children = gtk_file_folder_unix_list_children;
1294 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1299 gtk_file_folder_unix_finalize (GObject *object)
1301 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1303 g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
1305 g_free (folder_unix->filename);
1307 folder_parent_class->finalize (object);
1310 static GtkFileInfo *
1311 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
1312 const GtkFilePath *path,
1315 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1318 const char *filename;
1320 filename = gtk_file_path_get_string (path);
1321 g_return_val_if_fail (filename != NULL, NULL);
1322 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
1324 dirname = g_path_get_dirname (filename);
1325 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
1328 info = filename_get_info (filename, folder_unix->types, error);
1334 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
1338 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1339 GError *tmp_error = NULL;
1344 dir = g_dir_open (folder_unix->filename, 0, &tmp_error);
1348 GTK_FILE_SYSTEM_ERROR,
1349 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1351 tmp_error->message);
1353 g_error_free (tmp_error);
1360 const gchar *filename = g_dir_read_name (dir);
1366 fullname = g_build_filename (folder_unix->filename, filename, NULL);
1367 *children = g_slist_prepend (*children, filename_to_path (fullname));
1373 *children = g_slist_reverse (*children);
1378 static GtkFileInfo *
1379 filename_get_info (const gchar *filename,
1380 GtkFileInfoType types,
1384 struct stat statbuf;
1385 gboolean do_stat = (types & (GTK_FILE_INFO_IS_FOLDER |
1386 GTK_FILE_INFO_IS_HIDDEN |
1387 GTK_FILE_INFO_MODIFICATION_TIME |
1388 GTK_FILE_INFO_SIZE));
1390 /* If stat fails, try to fall back to lstat to catch broken links
1392 if (do_stat && stat (filename, &statbuf) != 0)
1394 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
1396 int save_errno = errno;
1397 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1399 GTK_FILE_SYSTEM_ERROR,
1400 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1401 _("error getting information for '%s': %s"),
1402 filename_utf8 ? filename_utf8 : "???",
1403 g_strerror (save_errno));
1404 g_free (filename_utf8);
1410 info = gtk_file_info_new ();
1412 if (filename_is_root (filename))
1414 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1415 gtk_file_info_set_display_name (info, "/");
1417 if (types & GTK_FILE_INFO_IS_HIDDEN)
1418 gtk_file_info_set_is_hidden (info, FALSE);
1422 gchar *basename = g_path_get_basename (filename);
1424 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1426 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1428 display_name = g_strescape (basename, NULL);
1430 gtk_file_info_set_display_name (info, display_name);
1432 g_free (display_name);
1435 if (types & GTK_FILE_INFO_IS_HIDDEN)
1437 gtk_file_info_set_is_hidden (info, basename[0] == '.');
1443 if (types & GTK_FILE_INFO_IS_FOLDER)
1445 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf.st_mode));
1448 if (types & GTK_FILE_INFO_MIME_TYPE)
1450 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1451 gtk_file_info_set_mime_type (info, mime_type);
1454 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1456 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1459 if (types & GTK_FILE_INFO_SIZE)
1461 gtk_file_info_set_size (info, (gint64)statbuf.st_size);
1467 static GtkFilePath *
1468 filename_to_path (const char *filename)
1470 return gtk_file_path_new_dup (filename);
1474 filename_is_root (const char *filename)
1476 const gchar *after_root;
1478 after_root = g_path_skip_root (filename);
1480 return (after_root != NULL && *after_root == '\0');