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.
21 #include "gtkfilesystem.h"
22 #include "gtkfilesystemunix.h"
23 #include "gtkicontheme.h"
26 #define XDG_PREFIX _gtk_xdg
27 #include "xdgmime/xdgmime.h"
32 #include <sys/types.h>
36 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
37 #define BOOKMARKS_TMP_FILENAME ".gtk-bookmarks-XXXXXX"
39 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
41 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
42 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
43 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
45 struct _GtkFileSystemUnixClass
47 GObjectClass parent_class;
50 struct _GtkFileSystemUnix
52 GObject parent_instance;
55 /* Icon type, supplemented by MIME type
59 ICON_REGULAR, /* Use mime type for icon */
61 ICON_BROKEN_SYMBOLIC_LINK,
62 ICON_CHARACTER_DEVICE,
70 #define GTK_TYPE_FILE_FOLDER_UNIX (gtk_file_folder_unix_get_type ())
71 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
72 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
73 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
74 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
75 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
77 typedef struct _GtkFileFolderUnix GtkFileFolderUnix;
78 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
80 struct _GtkFileFolderUnixClass
82 GObjectClass parent_class;
85 struct _GtkFileFolderUnix
87 GObject parent_instance;
89 GtkFileInfoType types;
93 static GObjectClass *system_parent_class;
94 static GObjectClass *folder_parent_class;
96 static void gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class);
97 static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
98 static void gtk_file_system_unix_init (GtkFileSystemUnix *impl);
99 static void gtk_file_system_unix_finalize (GObject *object);
101 static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
102 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
103 const GtkFilePath *path);
105 static GtkFileFolder *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
106 const GtkFilePath *path,
107 GtkFileInfoType types,
109 static gboolean gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
110 const GtkFilePath *path,
113 static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
114 GtkFileSystemVolume *volume);
115 static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
116 GtkFileSystemVolume *volume);
117 static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
118 GtkFileSystemVolume *volume);
119 static gboolean gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
120 GtkFileSystemVolume *volume,
122 static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
123 GtkFileSystemVolume *volume);
124 static GdkPixbuf * gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
125 GtkFileSystemVolume *volume,
130 static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
131 const GtkFilePath *path,
132 GtkFilePath **parent,
134 static GtkFilePath * gtk_file_system_unix_make_path (GtkFileSystem *file_system,
135 const GtkFilePath *base_path,
136 const gchar *display_name,
138 static gboolean gtk_file_system_unix_parse (GtkFileSystem *file_system,
139 const GtkFilePath *base_path,
141 GtkFilePath **folder,
145 static gchar * gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
146 const GtkFilePath *path);
147 static gchar * gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
148 const GtkFilePath *path);
149 static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
151 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
152 const gchar *filename);
154 static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
155 const GtkFilePath *path,
160 static gboolean gtk_file_system_unix_add_bookmark (GtkFileSystem *file_system,
161 const GtkFilePath *path,
163 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
164 const GtkFilePath *path,
166 static GSList * gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system);
168 static GType gtk_file_folder_unix_get_type (void);
169 static void gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
170 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
171 static void gtk_file_folder_unix_init (GtkFileFolderUnix *impl);
172 static void gtk_file_folder_unix_finalize (GObject *object);
174 static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
175 const GtkFilePath *path,
177 static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder,
181 static GtkFilePath *filename_to_path (const gchar *filename);
183 static gboolean filename_is_root (const char *filename);
184 static GtkFileInfo *filename_get_info (const gchar *filename,
185 GtkFileInfoType types,
192 gtk_file_system_unix_get_type (void)
194 static GType file_system_unix_type = 0;
196 if (!file_system_unix_type)
198 static const GTypeInfo file_system_unix_info =
200 sizeof (GtkFileSystemUnixClass),
201 NULL, /* base_init */
202 NULL, /* base_finalize */
203 (GClassInitFunc) gtk_file_system_unix_class_init,
204 NULL, /* class_finalize */
205 NULL, /* class_data */
206 sizeof (GtkFileSystemUnix),
208 (GInstanceInitFunc) gtk_file_system_unix_init,
211 static const GInterfaceInfo file_system_info =
213 (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
214 NULL, /* interface_finalize */
215 NULL /* interface_data */
218 file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
220 &file_system_unix_info, 0);
221 g_type_add_interface_static (file_system_unix_type,
222 GTK_TYPE_FILE_SYSTEM,
226 return file_system_unix_type;
230 * gtk_file_system_unix_new:
232 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
233 * implements the #GtkFileSystem interface with direct access to
234 * the filesystem using Unix/Linux API calls
236 * Return value: the new #GtkFileSystemUnix object
239 gtk_file_system_unix_new (void)
241 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
245 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
247 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
249 system_parent_class = g_type_class_peek_parent (class);
251 gobject_class->finalize = gtk_file_system_unix_finalize;
255 gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
257 iface->list_volumes = gtk_file_system_unix_list_volumes;
258 iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
259 iface->get_folder = gtk_file_system_unix_get_folder;
260 iface->create_folder = gtk_file_system_unix_create_folder;
261 iface->volume_free = gtk_file_system_unix_volume_free;
262 iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
263 iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
264 iface->volume_mount = gtk_file_system_unix_volume_mount;
265 iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
266 iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
267 iface->get_parent = gtk_file_system_unix_get_parent;
268 iface->make_path = gtk_file_system_unix_make_path;
269 iface->parse = gtk_file_system_unix_parse;
270 iface->path_to_uri = gtk_file_system_unix_path_to_uri;
271 iface->path_to_filename = gtk_file_system_unix_path_to_filename;
272 iface->uri_to_path = gtk_file_system_unix_uri_to_path;
273 iface->filename_to_path = gtk_file_system_unix_filename_to_path;
274 iface->render_icon = gtk_file_system_unix_render_icon;
275 iface->add_bookmark = gtk_file_system_unix_add_bookmark;
276 iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
277 iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
281 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
286 gtk_file_system_unix_finalize (GObject *object)
288 system_parent_class->finalize (object);
291 /* Returns our single root volume */
292 static GtkFileSystemVolume *
293 get_root_volume (void)
295 return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
299 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
301 return g_slist_append (NULL, get_root_volume ());
304 static GtkFileSystemVolume *
305 gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
306 const GtkFilePath *path)
308 return get_root_volume ();
311 static GtkFileFolder *
312 gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
313 const GtkFilePath *path,
314 GtkFileInfoType types,
317 GtkFileFolderUnix *folder_unix;
318 const char *filename;
320 filename = gtk_file_path_get_string (path);
321 g_return_val_if_fail (filename != NULL, NULL);
322 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
324 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
325 folder_unix->filename = g_strdup (filename);
326 folder_unix->types = types;
328 return GTK_FILE_FOLDER (folder_unix);
332 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
333 const GtkFilePath *path,
336 const char *filename;
339 filename = gtk_file_path_get_string (path);
340 g_return_val_if_fail (filename != NULL, FALSE);
341 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
343 result = mkdir (filename, 0777) == 0;
347 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
349 GTK_FILE_SYSTEM_ERROR,
350 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
351 _("error creating directory '%s': %s"),
352 filename_utf8 ? filename_utf8 : "???",
354 g_free (filename_utf8);
361 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
362 GtkFileSystemVolume *volume)
366 path = (GtkFilePath *) volume;
367 gtk_file_path_free (path);
371 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
372 GtkFileSystemVolume *volume)
374 return gtk_file_path_new_dup ("/");
378 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
379 GtkFileSystemVolume *volume)
385 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
386 GtkFileSystemVolume *volume,
390 GTK_FILE_SYSTEM_ERROR,
391 GTK_FILE_SYSTEM_ERROR_FAILED,
392 _("This file system does not support mounting"));
397 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
398 GtkFileSystemVolume *volume)
400 return g_strdup (_("Filesystem")); /* Same as Nautilus */
404 get_icon_type (const char *filename,
410 /* If stat fails, try to fall back to lstat to catch broken links
412 if (stat (filename, &statbuf) != 0 &&
413 lstat (filename, &statbuf) != 0)
415 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
417 GTK_FILE_SYSTEM_ERROR,
418 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
419 _("error getting information for '%s': %s"),
420 filename_utf8 ? filename_utf8 : "???",
422 g_free (filename_utf8);
427 if (S_ISBLK (statbuf.st_mode))
428 icon_type = ICON_BLOCK_DEVICE;
429 else if (S_ISLNK (statbuf.st_mode))
430 icon_type = ICON_BROKEN_SYMBOLIC_LINK; /* See above */
431 else if (S_ISCHR (statbuf.st_mode))
432 icon_type = ICON_CHARACTER_DEVICE;
433 else if (S_ISDIR (statbuf.st_mode))
434 icon_type = ICON_DIRECTORY;
435 else if (S_ISFIFO (statbuf.st_mode))
436 icon_type = ICON_FIFO;
437 else if (S_ISSOCK (statbuf.st_mode))
438 icon_type = ICON_SOCKET;
441 icon_type = ICON_REGULAR;
444 if ((types & GTK_FILE_INFO_ICON) && icon_type == GTK_FILE_ICON_REGULAR &&
445 (statbuf.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) &&
446 (strcmp (mime_type, XDG_MIME_TYPE_UNKNOWN) == 0 ||
447 strcmp (mime_type, "application/x-executable") == 0 ||
448 strcmp (mime_type, "application/x-shellscript") == 0))
449 gtk_file_info_set_icon_type (info, GTK_FILE_ICON_EXECUTABLE);
463 icon_cache_element_free (IconCacheElement *element)
466 g_object_unref (element->pixbuf);
471 icon_theme_changed (GtkIconTheme *icon_theme)
475 /* Difference from the initial creation is that we don't
476 * reconnect the signal
478 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
479 (GDestroyNotify)g_free,
480 (GDestroyNotify)icon_cache_element_free);
481 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
482 cache, (GDestroyNotify)g_hash_table_destroy);
486 get_cached_icon (GtkWidget *widget,
490 GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
491 GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
492 IconCacheElement *element;
496 cache = g_hash_table_new_full (g_str_hash, g_str_equal,
497 (GDestroyNotify)g_free,
498 (GDestroyNotify)icon_cache_element_free);
500 g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
501 cache, (GDestroyNotify)g_hash_table_destroy);
502 g_signal_connect (icon_theme, "changed",
503 G_CALLBACK (icon_theme_changed), NULL);
506 element = g_hash_table_lookup (cache, name);
509 element = g_new0 (IconCacheElement, 1);
510 g_hash_table_insert (cache, g_strdup (name), element);
513 if (element->size != pixel_size)
516 g_object_unref (element->pixbuf);
517 element->size = pixel_size;
518 element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
519 pixel_size, 0, NULL);
522 return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
526 gtk_file_system_unix_volume_render_icon (GtkFileSystem *file_system,
527 GtkFileSystemVolume *volume,
532 /* FIXME: set the GError if we can't load the icon */
533 return get_cached_icon (widget, "gnome-fs-blockdev", pixel_size);
537 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
538 const GtkFilePath *path,
539 GtkFilePath **parent,
542 const char *filename;
544 filename = gtk_file_path_get_string (path);
545 g_return_val_if_fail (filename != NULL, FALSE);
546 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
548 if (filename_is_root (filename))
554 gchar *parent_filename = g_path_get_dirname (filename);
555 *parent = filename_to_path (parent_filename);
556 g_free (parent_filename);
563 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
564 const GtkFilePath *base_path,
565 const gchar *display_name,
568 const char *base_filename;
570 gchar *full_filename;
571 GError *tmp_error = NULL;
574 base_filename = gtk_file_path_get_string (base_path);
575 g_return_val_if_fail (base_filename != NULL, NULL);
576 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
578 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
582 GTK_FILE_SYSTEM_ERROR,
583 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
587 g_error_free (tmp_error);
592 full_filename = g_build_filename (base_filename, filename, NULL);
593 result = filename_to_path (full_filename);
595 g_free (full_filename);
600 /* If this was a publically exported function, it should return
601 * a dup'ed result, but we make it modify-in-place for efficiency
602 * here, and because it works for us.
605 canonicalize_filename (gchar *filename)
608 gboolean last_was_slash = FALSE;
615 if (*p == G_DIR_SEPARATOR)
618 *q++ = G_DIR_SEPARATOR;
620 last_was_slash = TRUE;
624 if (last_was_slash && *p == '.')
626 if (*(p + 1) == G_DIR_SEPARATOR ||
629 if (*(p + 1) == '\0')
634 else if (*(p + 1) == '.' &&
635 (*(p + 2) == G_DIR_SEPARATOR ||
638 if (q > filename + 1)
641 while (q > filename + 1 &&
642 *(q - 1) != G_DIR_SEPARATOR)
646 if (*(p + 2) == '\0')
654 last_was_slash = FALSE;
660 last_was_slash = FALSE;
667 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
674 gtk_file_system_unix_parse (GtkFileSystem *file_system,
675 const GtkFilePath *base_path,
677 GtkFilePath **folder,
681 const char *base_filename;
683 gboolean result = FALSE;
685 base_filename = gtk_file_path_get_string (base_path);
686 g_return_val_if_fail (base_filename != NULL, FALSE);
687 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
689 last_slash = strrchr (str, G_DIR_SEPARATOR);
692 *folder = gtk_file_path_copy (base_path);
693 *file_part = g_strdup (str);
700 GError *tmp_error = NULL;
702 if (last_slash == str)
703 folder_part = g_strdup ("/");
705 folder_part = g_filename_from_utf8 (str, last_slash - str,
706 NULL, NULL, &tmp_error);
711 GTK_FILE_SYSTEM_ERROR,
712 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
715 g_error_free (tmp_error);
719 if (folder_part[0] == G_DIR_SEPARATOR)
720 folder_path = folder_part;
723 folder_path = g_build_filename (base_filename, folder_part, NULL);
724 g_free (folder_part);
727 canonicalize_filename (folder_path);
729 *folder = filename_to_path (folder_path);
730 *file_part = g_strdup (last_slash + 1);
732 g_free (folder_path);
742 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
743 const GtkFilePath *path)
745 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
749 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
750 const GtkFilePath *path)
752 return g_strdup (gtk_file_path_get_string (path));
756 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
759 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
761 return gtk_file_path_new_steal (filename);
767 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
768 const gchar *filename)
770 return gtk_file_path_new_dup (filename);
774 gtk_file_system_unix_render_icon (GtkFileSystem *file_system,
775 const GtkFilePath *path,
780 const char *filename;
782 const char *mime_type;
784 filename = gtk_file_path_get_string (path);
785 icon_type = get_icon_type (filename, error);
787 /* FIXME: this function should not return NULL without setting the GError; we
788 * should perhaps provide a "never fails" generic stock icon for when all else
792 if (icon_type == ICON_NONE)
795 if (icon_type != ICON_REGULAR)
801 case ICON_BLOCK_DEVICE:
802 name = "gnome-fs-blockdev";
804 case ICON_BROKEN_SYMBOLIC_LINK:
805 name = "gnome-fs-symlink";
807 case ICON_CHARACTER_DEVICE:
808 name = "gnome-fs-chardev";
811 name = "gnome-fs-directory";
813 case ICON_EXECUTABLE:
814 name ="gnome-fs-executable";
817 name = "gnome-fs-fifo";
820 name = "gnome-fs-socket";
823 g_assert_not_reached ();
827 return get_cached_icon (widget, name, pixel_size);
830 mime_type = xdg_mime_get_mime_type_for_file (filename);
833 const char *separator;
837 separator = strchr (mime_type, '/');
841 icon_name = g_string_new ("gnome-mime-");
842 g_string_append_len (icon_name, mime_type, separator - mime_type);
843 g_string_append_c (icon_name, '-');
844 g_string_append (icon_name, separator + 1);
845 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
846 g_string_free (icon_name, TRUE);
850 icon_name = g_string_new ("gnome-mime-");
851 g_string_append_len (icon_name, mime_type, separator - mime_type);
852 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
853 g_string_free (icon_name, TRUE);
858 return get_cached_icon (widget, "gnome-fs-regular", pixel_size);
862 bookmark_list_free (GSList *list)
866 for (l = list; l; l = l->next)
872 /* Returns whether a URI is a local file:// */
874 is_local_uri (const char *uri)
880 /* This is rather crude, but hey */
881 filename = g_filename_from_uri (uri, &hostname, NULL);
883 result = (filename && !hostname);
892 bookmark_get_filename (gboolean tmp_file)
896 filename = g_build_filename (g_get_home_dir (),
897 tmp_file ? BOOKMARKS_TMP_FILENAME : BOOKMARKS_FILENAME,
899 g_assert (filename != NULL);
904 bookmark_list_read (GSList **bookmarks, GError **error)
910 filename = bookmark_get_filename (FALSE);
913 if (g_file_get_contents (filename, &contents, NULL, error))
915 gchar **lines = g_strsplit (contents, "\n", -1);
919 table = g_hash_table_new (g_str_hash, g_str_equal);
921 for (i = 0; lines[i]; i++)
923 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
925 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
926 g_hash_table_insert (table, lines[i], lines[i]);
931 g_hash_table_destroy (table);
934 *bookmarks = g_slist_reverse (*bookmarks);
944 bookmark_list_write (GSList *bookmarks, GError **error)
948 gboolean result = TRUE;
953 /* First, write a temporary file */
955 tmp_filename = bookmark_get_filename (TRUE);
956 filename = bookmark_get_filename (FALSE);
958 fd = g_mkstemp (tmp_filename);
965 if ((file = fdopen (fd, "w")) != NULL)
969 for (l = bookmarks; l; l = l->next)
970 if (fputs (l->data, file) == EOF
971 || fputs ("\n", file) == EOF)
977 if (fclose (file) == EOF)
983 if (rename (tmp_filename, filename) == -1)
996 /* fdopen() failed, so we can't do much error checking here anyway */
1003 GTK_FILE_SYSTEM_ERROR,
1004 GTK_FILE_SYSTEM_ERROR_FAILED,
1005 _("Bookmark saving failed (%s)"),
1006 g_strerror (saved_errno));
1010 unlink (tmp_filename); /* again, not much error checking we can do here */
1015 g_free (tmp_filename);
1021 gtk_file_system_unix_add_bookmark (GtkFileSystem *file_system,
1022 const GtkFilePath *path,
1030 if (!bookmark_list_read (&bookmarks, error))
1035 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1037 for (l = bookmarks; l; l = l->next)
1039 const char *bookmark;
1042 if (strcmp (bookmark, uri) == 0)
1048 bookmarks = g_slist_append (bookmarks, g_strdup (uri));
1049 if (bookmark_list_write (bookmarks, error))
1052 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1057 bookmark_list_free (bookmarks);
1063 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1064 const GtkFilePath *path,
1072 if (!bookmark_list_read (&bookmarks, error))
1077 uri = gtk_file_system_path_to_uri (file_system, path);
1079 for (l = bookmarks; l; l = l->next)
1081 const char *bookmark;
1084 if (strcmp (bookmark, uri) == 0)
1091 bookmarks = g_slist_remove_link (bookmarks, l);
1094 if (bookmark_list_write (bookmarks, error))
1101 bookmark_list_free (bookmarks);
1104 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1110 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1116 if (!bookmark_list_read (&bookmarks, NULL))
1121 for (l = bookmarks; l; l = l->next)
1127 if (is_local_uri (name))
1128 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, name));
1131 bookmark_list_free (bookmarks);
1133 result = g_slist_reverse (result);
1141 gtk_file_folder_unix_get_type (void)
1143 static GType file_folder_unix_type = 0;
1145 if (!file_folder_unix_type)
1147 static const GTypeInfo file_folder_unix_info =
1149 sizeof (GtkFileFolderUnixClass),
1150 NULL, /* base_init */
1151 NULL, /* base_finalize */
1152 (GClassInitFunc) gtk_file_folder_unix_class_init,
1153 NULL, /* class_finalize */
1154 NULL, /* class_data */
1155 sizeof (GtkFileFolderUnix),
1156 0, /* n_preallocs */
1157 (GInstanceInitFunc) gtk_file_folder_unix_init,
1160 static const GInterfaceInfo file_folder_info =
1162 (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1163 NULL, /* interface_finalize */
1164 NULL /* interface_data */
1167 file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1168 "GtkFileFolderUnix",
1169 &file_folder_unix_info, 0);
1170 g_type_add_interface_static (file_folder_unix_type,
1171 GTK_TYPE_FILE_FOLDER,
1175 return file_folder_unix_type;
1179 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1181 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1183 folder_parent_class = g_type_class_peek_parent (class);
1185 gobject_class->finalize = gtk_file_folder_unix_finalize;
1189 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1191 iface->get_info = gtk_file_folder_unix_get_info;
1192 iface->list_children = gtk_file_folder_unix_list_children;
1196 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1201 gtk_file_folder_unix_finalize (GObject *object)
1203 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1205 g_free (folder_unix->filename);
1207 folder_parent_class->finalize (object);
1210 static GtkFileInfo *
1211 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
1212 const GtkFilePath *path,
1215 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1218 const char *filename;
1220 filename = gtk_file_path_get_string (path);
1221 g_return_val_if_fail (filename != NULL, NULL);
1222 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
1224 dirname = g_path_get_dirname (filename);
1225 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
1228 info = filename_get_info (filename, folder_unix->types, error);
1234 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
1238 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1239 GError *tmp_error = NULL;
1244 dir = g_dir_open (folder_unix->filename, 0, &tmp_error);
1248 GTK_FILE_SYSTEM_ERROR,
1249 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1251 tmp_error->message);
1253 g_error_free (tmp_error);
1260 const gchar *filename = g_dir_read_name (dir);
1266 fullname = g_build_filename (folder_unix->filename, filename, NULL);
1267 *children = g_slist_prepend (*children, filename_to_path (fullname));
1273 *children = g_slist_reverse (*children);
1278 static GtkFileInfo *
1279 filename_get_info (const gchar *filename,
1280 GtkFileInfoType types,
1284 struct stat statbuf;
1286 /* If stat fails, try to fall back to lstat to catch broken links
1288 if (stat (filename, &statbuf) != 0 &&
1289 lstat (filename, &statbuf) != 0)
1291 gchar *filename_utf8 = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
1293 GTK_FILE_SYSTEM_ERROR,
1294 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1295 _("error getting information for '%s': %s"),
1296 filename_utf8 ? filename_utf8 : "???",
1297 g_strerror (errno));
1298 g_free (filename_utf8);
1303 info = gtk_file_info_new ();
1305 if (filename_is_root (filename))
1307 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1308 gtk_file_info_set_display_name (info, "/");
1310 if (types & GTK_FILE_INFO_IS_HIDDEN)
1311 gtk_file_info_set_is_hidden (info, FALSE);
1315 gchar *basename = g_path_get_basename (filename);
1317 if (types & GTK_FILE_INFO_DISPLAY_NAME)
1319 gchar *display_name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
1321 display_name = g_strescape (basename, NULL);
1323 gtk_file_info_set_display_name (info, display_name);
1325 g_free (display_name);
1328 if (types & GTK_FILE_INFO_IS_HIDDEN)
1330 gtk_file_info_set_is_hidden (info, basename[0] == '.');
1336 if (types & GTK_FILE_INFO_IS_FOLDER)
1338 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf.st_mode));
1341 if (types & GTK_FILE_INFO_MIME_TYPE)
1343 const char *mime_type = xdg_mime_get_mime_type_for_file (filename);
1344 gtk_file_info_set_mime_type (info, mime_type);
1347 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1349 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1352 if (types & GTK_FILE_INFO_SIZE)
1354 gtk_file_info_set_size (info, (gint64)statbuf.st_size);
1360 static GtkFilePath *
1361 filename_to_path (const char *filename)
1363 return gtk_file_path_new_dup (filename);
1367 filename_is_root (const char *filename)
1369 const gchar *after_root;
1371 after_root = g_path_skip_root (filename);
1373 return (after_root != NULL && *after_root == '\0');