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 /* #define this if you want the program to crash when a file system gets
22 * finalized while async handles are still outstanding.
24 #undef HANDLE_ME_HARDER
28 #include "gtkfilesystem.h"
29 #include "gtkfilesystemunix.h"
30 #include "gtkicontheme.h"
35 #define XDG_PREFIX _gtk_xdg
36 #include "xdgmime/xdgmime.h"
41 #include <sys/types.h>
49 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
51 #define HIDDEN_FILENAME ".hidden"
53 #define FOLDER_CACHE_LIFETIME 2 /* seconds */
55 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
57 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
58 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
59 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
61 struct _GtkFileSystemUnixClass
63 GObjectClass parent_class;
66 struct _GtkFileSystemUnix
68 GObject parent_instance;
70 GHashTable *folder_hash;
72 /* For /afs and /net */
73 struct stat afs_statbuf;
74 struct stat net_statbuf;
78 guint execute_callbacks_idle_id;
85 /* Icon type, supplemented by MIME type
88 ICON_UNDECIDED, /* Only used while we have not yet computed the icon in a struct stat_info_entry */
89 ICON_NONE, /* "Could not compute the icon type" */
90 ICON_REGULAR, /* Use mime type for icon */
92 ICON_BROKEN_SYMBOLIC_LINK,
93 ICON_CHARACTER_DEVICE,
101 #define GTK_TYPE_FILE_FOLDER_UNIX (_gtk_file_folder_unix_get_type ())
102 #define GTK_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
103 #define GTK_IS_FILE_FOLDER_UNIX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
104 #define GTK_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
105 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
106 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
108 typedef struct _GtkFileFolderUnix GtkFileFolderUnix;
109 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
111 struct _GtkFileFolderUnixClass
113 GObjectClass parent_class;
116 struct _GtkFileFolderUnix
118 GObject parent_instance;
120 GtkFileSystemUnix *system_unix;
121 GtkFileInfoType types;
123 GHashTable *stat_info;
124 guint load_folder_id;
126 guint have_mime_type : 1;
127 guint is_network_dir : 1;
128 guint have_hidden : 1;
129 guint is_finished_loading : 1;
133 struct stat_info_entry {
140 static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
141 GTK_FILE_INFO_MODIFICATION_TIME |
145 static void gtk_file_system_unix_iface_init (GtkFileSystemIface *iface);
146 static void gtk_file_system_unix_dispose (GObject *object);
147 static void gtk_file_system_unix_finalize (GObject *object);
149 static GSList * gtk_file_system_unix_list_volumes (GtkFileSystem *file_system);
150 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
151 const GtkFilePath *path);
153 static GtkFileSystemHandle *gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
154 const GtkFilePath *path,
155 GtkFileInfoType types,
156 GtkFileSystemGetFolderCallback callback,
158 static GtkFileSystemHandle *gtk_file_system_unix_get_info (GtkFileSystem *file_system,
159 const GtkFilePath *path,
160 GtkFileInfoType types,
161 GtkFileSystemGetInfoCallback callback,
163 static GtkFileSystemHandle *gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
164 const GtkFilePath *path,
165 GtkFileSystemCreateFolderCallback callback,
167 static void gtk_file_system_unix_cancel_operation (GtkFileSystemHandle *handle);
169 static void gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
170 GtkFileSystemVolume *volume);
171 static GtkFilePath *gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
172 GtkFileSystemVolume *volume);
173 static gboolean gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
174 GtkFileSystemVolume *volume);
175 static GtkFileSystemHandle *gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
176 GtkFileSystemVolume *volume,
177 GtkFileSystemVolumeMountCallback callback,
179 static gchar * gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
180 GtkFileSystemVolume *volume);
181 static gchar * gtk_file_system_unix_volume_get_icon_name (GtkFileSystem *file_system,
182 GtkFileSystemVolume *volume,
185 static gboolean gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
186 const GtkFilePath *path,
187 GtkFilePath **parent,
189 static GtkFilePath * gtk_file_system_unix_make_path (GtkFileSystem *file_system,
190 const GtkFilePath *base_path,
191 const gchar *display_name,
193 static gboolean gtk_file_system_unix_parse (GtkFileSystem *file_system,
194 const GtkFilePath *base_path,
196 GtkFilePath **folder,
200 static gchar * gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
201 const GtkFilePath *path);
202 static gchar * gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
203 const GtkFilePath *path);
204 static GtkFilePath *gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
206 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
207 const gchar *filename);
210 static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
211 const GtkFilePath *path,
214 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
215 const GtkFilePath *path,
217 static GSList * gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system);
218 static gchar * gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
219 const GtkFilePath *path);
220 static void gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
221 const GtkFilePath *path,
224 static void gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface);
225 static void gtk_file_folder_unix_finalize (GObject *object);
227 static GtkFileInfo *gtk_file_folder_unix_get_info (GtkFileFolder *folder,
228 const GtkFilePath *path,
230 static gboolean gtk_file_folder_unix_list_children (GtkFileFolder *folder,
234 static gboolean gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder);
236 static GtkFilePath *filename_to_path (const gchar *filename);
238 static gboolean filename_is_root (const char *filename);
240 static gboolean get_is_hidden_for_file (const char *filename,
241 const char *basename);
242 static gboolean file_is_hidden (GtkFileFolderUnix *folder_unix,
243 const char *basename);
245 static GtkFileInfo *file_info_for_root_with_error (const char *root_name,
247 static gboolean stat_with_error (const char *filename,
248 struct stat *statbuf,
250 static GtkFileInfo *create_file_info (GtkFileFolderUnix *folder_unix,
251 const char *filename,
252 const char *basename,
253 GtkFileInfoType types,
254 struct stat *statbuf,
255 const char *mime_type);
257 static gboolean execute_callbacks (gpointer data);
259 static gboolean fill_in_names (GtkFileFolderUnix *folder_unix,
261 static void fill_in_stats (GtkFileFolderUnix *folder_unix);
262 static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
263 static void fill_in_hidden (GtkFileFolderUnix *folder_unix);
265 static gboolean cb_fill_in_stats (gpointer key,
268 static gboolean cb_fill_in_mime_type (gpointer key,
272 static char * get_parent_dir (const char *filename);
277 G_DEFINE_TYPE_WITH_CODE (GtkFileSystemUnix, gtk_file_system_unix, G_TYPE_OBJECT,
278 G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_SYSTEM,
279 gtk_file_system_unix_iface_init))
284 G_DEFINE_TYPE_WITH_CODE (GtkFileFolderUnix, _gtk_file_folder_unix, G_TYPE_OBJECT,
285 G_IMPLEMENT_INTERFACE (GTK_TYPE_FILE_FOLDER,
286 gtk_file_folder_unix_iface_init))
290 * gtk_file_system_unix_new:
292 * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
293 * implements the #GtkFileSystem interface with direct access to
294 * the filesystem using Unix/Linux API calls
296 * Return value: the new #GtkFileSystemUnix object
299 gtk_file_system_unix_new (void)
301 return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
305 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
307 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
309 gobject_class->dispose = gtk_file_system_unix_dispose;
310 gobject_class->finalize = gtk_file_system_unix_finalize;
314 gtk_file_system_unix_iface_init (GtkFileSystemIface *iface)
316 iface->list_volumes = gtk_file_system_unix_list_volumes;
317 iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
318 iface->get_folder = gtk_file_system_unix_get_folder;
319 iface->get_info = gtk_file_system_unix_get_info;
320 iface->create_folder = gtk_file_system_unix_create_folder;
321 iface->cancel_operation = gtk_file_system_unix_cancel_operation;
322 iface->volume_free = gtk_file_system_unix_volume_free;
323 iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
324 iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
325 iface->volume_mount = gtk_file_system_unix_volume_mount;
326 iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
327 iface->volume_get_icon_name = gtk_file_system_unix_volume_get_icon_name;
328 iface->get_parent = gtk_file_system_unix_get_parent;
329 iface->make_path = gtk_file_system_unix_make_path;
330 iface->parse = gtk_file_system_unix_parse;
331 iface->path_to_uri = gtk_file_system_unix_path_to_uri;
332 iface->path_to_filename = gtk_file_system_unix_path_to_filename;
333 iface->uri_to_path = gtk_file_system_unix_uri_to_path;
334 iface->filename_to_path = gtk_file_system_unix_filename_to_path;
335 iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
336 iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
337 iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
338 iface->get_bookmark_label = gtk_file_system_unix_get_bookmark_label;
339 iface->set_bookmark_label = gtk_file_system_unix_set_bookmark_label;
343 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
345 system_unix->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
347 if (stat ("/afs", &system_unix->afs_statbuf) == 0)
348 system_unix->have_afs = TRUE;
350 system_unix->have_afs = FALSE;
352 if (stat ("/net", &system_unix->net_statbuf) == 0)
353 system_unix->have_net = TRUE;
355 system_unix->have_net = FALSE;
357 system_unix->handles = g_hash_table_new (g_direct_hash, g_direct_equal);
359 system_unix->execute_callbacks_idle_id = 0;
360 system_unix->callbacks = NULL;
364 check_handle_fn (gpointer key, gpointer value, gpointer data)
366 GtkFileSystemHandle *handle;
367 int *num_live_handles;
370 num_live_handles = data;
372 (*num_live_handles)++;
374 g_warning ("file_system_unix=%p still has handle=%p at finalization which is %s!",
377 handle->cancelled ? "CANCELLED" : "NOT CANCELLED");
381 check_handles_at_finalization (GtkFileSystemUnix *system_unix)
383 int num_live_handles;
385 num_live_handles = 0;
387 g_hash_table_foreach (system_unix->handles, check_handle_fn, &num_live_handles);
388 #ifdef HANDLE_ME_HARDER
389 g_assert (num_live_handles == 0);
392 g_hash_table_destroy (system_unix->handles);
393 system_unix->handles = NULL;
396 #define GTK_TYPE_FILE_SYSTEM_HANDLE_UNIX (_gtk_file_system_handle_unix_get_type ())
398 typedef struct _GtkFileSystemHandle GtkFileSystemHandleUnix;
399 typedef struct _GtkFileSystemHandleClass GtkFileSystemHandleUnixClass;
401 G_DEFINE_TYPE (GtkFileSystemHandleUnix, _gtk_file_system_handle_unix, GTK_TYPE_FILE_SYSTEM_HANDLE)
404 _gtk_file_system_handle_unix_init (GtkFileSystemHandleUnix *handle)
409 _gtk_file_system_handle_unix_finalize (GObject *object)
411 GtkFileSystemHandleUnix *handle;
412 GtkFileSystemUnix *system_unix;
414 handle = (GtkFileSystemHandleUnix *)object;
416 system_unix = GTK_FILE_SYSTEM_UNIX (GTK_FILE_SYSTEM_HANDLE (handle)->file_system);
418 g_assert (g_hash_table_lookup (system_unix->handles, handle) != NULL);
419 g_hash_table_remove (system_unix->handles, handle);
421 if (G_OBJECT_CLASS (_gtk_file_system_handle_unix_parent_class)->finalize)
422 G_OBJECT_CLASS (_gtk_file_system_handle_unix_parent_class)->finalize (object);
426 _gtk_file_system_handle_unix_class_init (GtkFileSystemHandleUnixClass *class)
428 GObjectClass *gobject_class = (GObjectClass *) class;
430 gobject_class->finalize = _gtk_file_system_handle_unix_finalize;
434 gtk_file_system_unix_dispose (GObject *object)
436 GtkFileSystemUnix *system_unix;
438 system_unix = GTK_FILE_SYSTEM_UNIX (object);
440 if (system_unix->execute_callbacks_idle_id)
442 g_source_remove (system_unix->execute_callbacks_idle_id);
443 system_unix->execute_callbacks_idle_id = 0;
445 /* call pending callbacks */
446 execute_callbacks (system_unix);
449 G_OBJECT_CLASS (gtk_file_system_unix_parent_class)->dispose (object);
453 gtk_file_system_unix_finalize (GObject *object)
455 GtkFileSystemUnix *system_unix;
457 system_unix = GTK_FILE_SYSTEM_UNIX (object);
459 check_handles_at_finalization (system_unix);
461 /* FIXME: assert that the hash is empty? */
462 g_hash_table_destroy (system_unix->folder_hash);
464 G_OBJECT_CLASS (gtk_file_system_unix_parent_class)->finalize (object);
467 /* Returns our single root volume */
468 static GtkFileSystemVolume *
469 get_root_volume (void)
471 return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
475 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
477 return g_slist_append (NULL, get_root_volume ());
480 static GtkFileSystemVolume *
481 gtk_file_system_unix_get_volume_for_path (GtkFileSystem *file_system,
482 const GtkFilePath *path)
484 return get_root_volume ();
488 remove_trailing_slash (const char *filename)
492 len = strlen (filename);
494 if (len > 1 && filename[len - 1] == '/')
495 return g_strndup (filename, len - 1);
497 return g_memdup (filename, len + 1);
500 /* Delay callback dispatching
507 CALLBACK_CREATE_FOLDER,
508 CALLBACK_VOLUME_MOUNT
511 static void queue_callback (GtkFileSystemUnix *system_unix, enum callback_types type, gpointer data);
513 struct get_info_callback
515 GtkFileSystemGetInfoCallback callback;
516 GtkFileSystemHandle *handle;
517 GtkFileInfo *file_info;
523 dispatch_get_info_callback (struct get_info_callback *info)
525 (* info->callback) (info->handle, info->file_info, info->error, info->data);
528 gtk_file_info_free (info->file_info);
531 g_error_free (info->error);
533 g_object_unref (info->handle);
539 queue_get_info_callback (GtkFileSystemGetInfoCallback callback,
540 GtkFileSystemHandle *handle,
541 GtkFileInfo *file_info,
545 struct get_info_callback *info;
547 info = g_new (struct get_info_callback, 1);
548 info->callback = callback;
549 info->handle = handle;
550 info->file_info = file_info;
554 queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_GET_INFO, info);
558 struct get_folder_callback
560 GtkFileSystemGetFolderCallback callback;
561 GtkFileSystemHandle *handle;
562 GtkFileFolder *folder;
568 dispatch_get_folder_callback (struct get_folder_callback *info)
570 (* info->callback) (info->handle, info->folder, info->error, info->data);
573 g_error_free (info->error);
575 g_object_unref (info->handle);
581 queue_get_folder_callback (GtkFileSystemGetFolderCallback callback,
582 GtkFileSystemHandle *handle,
583 GtkFileFolder *folder,
587 struct get_folder_callback *info;
589 info = g_new (struct get_folder_callback, 1);
590 info->callback = callback;
591 info->handle = handle;
592 info->folder = folder;
596 queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_GET_FOLDER, info);
600 struct create_folder_callback
602 GtkFileSystemCreateFolderCallback callback;
603 GtkFileSystemHandle *handle;
610 dispatch_create_folder_callback (struct create_folder_callback *info)
612 (* info->callback) (info->handle, info->path, info->error, info->data);
615 g_error_free (info->error);
618 gtk_file_path_free (info->path);
620 g_object_unref (info->handle);
626 queue_create_folder_callback (GtkFileSystemCreateFolderCallback callback,
627 GtkFileSystemHandle *handle,
628 const GtkFilePath *path,
632 struct create_folder_callback *info;
634 info = g_new (struct create_folder_callback, 1);
635 info->callback = callback;
636 info->handle = handle;
637 info->path = gtk_file_path_copy (path);
641 queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_CREATE_FOLDER, info);
645 struct volume_mount_callback
647 GtkFileSystemVolumeMountCallback callback;
648 GtkFileSystemHandle *handle;
649 GtkFileSystemVolume *volume;
655 dispatch_volume_mount_callback (struct volume_mount_callback *info)
657 (* info->callback) (info->handle, info->volume, info->error, info->data);
660 g_error_free (info->error);
662 g_object_unref (info->handle);
668 queue_volume_mount_callback (GtkFileSystemVolumeMountCallback callback,
669 GtkFileSystemHandle *handle,
670 GtkFileSystemVolume *volume,
674 struct volume_mount_callback *info;
676 info = g_new (struct volume_mount_callback, 1);
677 info->callback = callback;
678 info->handle = handle;
679 info->volume = volume;
683 queue_callback (GTK_FILE_SYSTEM_UNIX (handle->file_system), CALLBACK_VOLUME_MOUNT, info);
689 enum callback_types type;
693 struct get_info_callback *get_info;
694 struct get_folder_callback *get_folder;
695 struct create_folder_callback *create_folder;
696 struct volume_mount_callback *volume_mount;
703 execute_callbacks (gpointer data)
706 gboolean unref_file_system = TRUE;
707 GtkFileSystemUnix *system_unix = GTK_FILE_SYSTEM_UNIX (data);
709 if (!system_unix->execute_callbacks_idle_id)
710 unref_file_system = FALSE;
712 g_object_ref (system_unix);
714 for (l = system_unix->callbacks; l; l = l->next)
716 struct callback_info *info = l->data;
720 case CALLBACK_GET_INFO:
721 dispatch_get_info_callback (info->info.get_info);
724 case CALLBACK_GET_FOLDER:
725 dispatch_get_folder_callback (info->info.get_folder);
728 case CALLBACK_CREATE_FOLDER:
729 dispatch_create_folder_callback (info->info.create_folder);
732 case CALLBACK_VOLUME_MOUNT:
733 dispatch_volume_mount_callback (info->info.volume_mount);
740 g_slist_free (system_unix->callbacks);
741 system_unix->callbacks = NULL;
743 if (unref_file_system)
744 g_object_unref (system_unix);
746 system_unix->execute_callbacks_idle_id = 0;
752 queue_callback (GtkFileSystemUnix *system_unix,
753 enum callback_types type,
756 struct callback_info *info;
758 info = g_new (struct callback_info, 1);
763 case CALLBACK_GET_INFO:
764 info->info.get_info = data;
767 case CALLBACK_GET_FOLDER:
768 info->info.get_folder = data;
771 case CALLBACK_CREATE_FOLDER:
772 info->info.create_folder = data;
775 case CALLBACK_VOLUME_MOUNT:
776 info->info.volume_mount = data;
780 system_unix->callbacks = g_slist_append (system_unix->callbacks, info);
782 if (!system_unix->execute_callbacks_idle_id)
783 system_unix->execute_callbacks_idle_id = gdk_threads_add_idle (execute_callbacks, system_unix);
786 static GtkFileSystemHandle *
787 create_handle (GtkFileSystem *file_system)
789 GtkFileSystemUnix *system_unix;
790 GtkFileSystemHandle *handle;
792 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
794 handle = g_object_new (GTK_TYPE_FILE_SYSTEM_HANDLE_UNIX, NULL);
795 handle->file_system = file_system;
797 g_assert (g_hash_table_lookup (system_unix->handles, handle) == NULL);
798 g_hash_table_insert (system_unix->handles, handle, handle);
805 static GtkFileSystemHandle *
806 gtk_file_system_unix_get_info (GtkFileSystem *file_system,
807 const GtkFilePath *path,
808 GtkFileInfoType types,
809 GtkFileSystemGetInfoCallback callback,
812 GError *error = NULL;
813 GtkFileSystemUnix *system_unix;
814 GtkFileSystemHandle *handle;
815 const char *filename;
819 const char *mime_type;
821 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
822 handle = create_handle (file_system);
824 filename = gtk_file_path_get_string (path);
825 g_return_val_if_fail (filename != NULL, NULL);
826 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
828 if (!stat_with_error (filename, &statbuf, &error))
830 g_object_ref (handle);
831 queue_get_info_callback (callback, handle, NULL, error, data);
835 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
836 mime_type = xdg_mime_get_mime_type_for_file (filename, &statbuf);
840 basename = g_path_get_basename (filename);
842 info = create_file_info (NULL, filename, basename, types, &statbuf,
845 g_object_ref (handle);
846 queue_get_info_callback (callback, handle, info, NULL, data);
852 load_folder (gpointer data)
854 GtkFileFolderUnix *folder_unix = data;
857 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
858 fill_in_stats (folder_unix);
860 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
861 fill_in_mime_type (folder_unix);
863 if (gtk_file_folder_unix_list_children (GTK_FILE_FOLDER (folder_unix), &children, NULL))
865 folder_unix->is_finished_loading = TRUE;
866 g_signal_emit_by_name (folder_unix, "files-added", children);
867 gtk_file_paths_free (children);
870 folder_unix->load_folder_id = 0;
872 g_signal_emit_by_name (folder_unix, "finished-loading", 0);
877 static GtkFileSystemHandle *
878 gtk_file_system_unix_get_folder (GtkFileSystem *file_system,
879 const GtkFilePath *path,
880 GtkFileInfoType types,
881 GtkFileSystemGetFolderCallback callback,
884 GError *error = NULL;
885 GtkFileSystemUnix *system_unix;
886 GtkFileFolderUnix *folder_unix;
887 GtkFileSystemHandle *handle;
888 const char *filename;
890 gboolean set_asof = FALSE;
892 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
894 filename = gtk_file_path_get_string (path);
895 g_return_val_if_fail (filename != NULL, NULL);
896 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
898 handle = create_handle (file_system);
900 filename_copy = remove_trailing_slash (filename);
901 folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename_copy);
905 g_free (filename_copy);
906 if (folder_unix->stat_info &&
907 time (NULL) - folder_unix->asof >= FOLDER_CACHE_LIFETIME)
910 g_print ("Cleaning out cached directory %s\n", filename);
912 g_hash_table_destroy (folder_unix->stat_info);
913 folder_unix->stat_info = NULL;
914 folder_unix->have_mime_type = FALSE;
915 folder_unix->have_stat = FALSE;
916 folder_unix->have_hidden = FALSE;
917 folder_unix->is_finished_loading = FALSE;
921 g_object_ref (folder_unix);
922 folder_unix->types |= types;
923 types = folder_unix->types;
932 code = my_errno = 0; /* shut up GCC */
934 result = stat (filename, &statbuf);
938 if (!S_ISDIR (statbuf.st_mode))
941 code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER;
949 if (my_errno == ENOENT)
950 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
952 code = GTK_FILE_SYSTEM_ERROR_FAILED;
957 gchar *display_name = g_filename_display_name (filename);
959 GTK_FILE_SYSTEM_ERROR,
961 _("Error getting information for '%s': %s"),
963 g_strerror (my_errno));
965 g_object_ref (handle);
966 queue_get_folder_callback (callback, handle, NULL, error, data);
968 g_free (display_name);
969 g_free (filename_copy);
973 folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
974 folder_unix->system_unix = system_unix;
975 folder_unix->filename = filename_copy;
976 folder_unix->types = types;
977 folder_unix->stat_info = NULL;
978 folder_unix->load_folder_id = 0;
979 folder_unix->have_mime_type = FALSE;
980 folder_unix->have_stat = FALSE;
981 folder_unix->have_hidden = FALSE;
982 folder_unix->is_finished_loading = FALSE;
985 if ((system_unix->have_afs &&
986 system_unix->afs_statbuf.st_dev == statbuf.st_dev &&
987 system_unix->afs_statbuf.st_ino == statbuf.st_ino) ||
988 (system_unix->have_net &&
989 system_unix->net_statbuf.st_dev == statbuf.st_dev &&
990 system_unix->net_statbuf.st_ino == statbuf.st_ino))
991 folder_unix->is_network_dir = TRUE;
993 folder_unix->is_network_dir = FALSE;
995 g_hash_table_insert (system_unix->folder_hash,
996 folder_unix->filename,
1001 folder_unix->asof = time (NULL);
1003 g_object_ref (handle);
1004 queue_get_folder_callback (callback, handle, GTK_FILE_FOLDER (folder_unix), NULL, data);
1006 /* Start loading the folder contents in an idle */
1007 if (!folder_unix->load_folder_id)
1008 folder_unix->load_folder_id =
1009 gdk_threads_add_idle ((GSourceFunc) load_folder, folder_unix);
1014 static GtkFileSystemHandle *
1015 gtk_file_system_unix_create_folder (GtkFileSystem *file_system,
1016 const GtkFilePath *path,
1017 GtkFileSystemCreateFolderCallback callback,
1020 GError *error = NULL;
1021 GtkFileSystemUnix *system_unix;
1022 GtkFileSystemHandle *handle;
1023 const char *filename;
1026 int save_errno = errno;
1028 system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
1030 filename = gtk_file_path_get_string (path);
1031 g_return_val_if_fail (filename != NULL, NULL);
1032 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
1034 handle = create_handle (file_system);
1036 tmp = remove_trailing_slash (filename);
1038 result = mkdir (tmp, 0777) == 0;
1044 gchar *display_name = g_filename_display_name (filename);
1045 g_set_error (&error,
1046 GTK_FILE_SYSTEM_ERROR,
1047 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1048 _("Error creating folder '%s': %s"),
1050 g_strerror (save_errno));
1052 g_object_ref (handle);
1053 queue_create_folder_callback (callback, handle, path, error, data);
1055 g_free (display_name);
1059 g_object_ref (handle);
1060 queue_create_folder_callback (callback, handle, path, NULL, data);
1062 parent = get_parent_dir (filename);
1065 GtkFileFolderUnix *folder_unix;
1067 folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
1072 struct stat_info_entry *entry;
1074 /* Make sure the new folder exists in the parent's folder */
1075 entry = g_new0 (struct stat_info_entry, 1);
1076 if (folder_unix->is_network_dir)
1078 entry->statbuf.st_mode = S_IFDIR;
1079 entry->mime_type = g_strdup ("x-directory/normal");
1082 basename = g_path_get_basename (filename);
1083 g_hash_table_insert (folder_unix->stat_info,
1087 if (folder_unix->have_stat)
1090 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
1091 cb_fill_in_stats (basename, entry, folder_unix);
1093 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
1094 cb_fill_in_mime_type (basename, entry, folder_unix);
1097 paths = g_slist_append (NULL, (GtkFilePath *) path);
1098 g_signal_emit_by_name (folder_unix, "files-added", paths);
1099 g_slist_free (paths);
1109 gtk_file_system_unix_cancel_operation (GtkFileSystemHandle *handle)
1111 /* We don't set "cancelled" to TRUE here, since the actual operation
1112 * is executed in the function itself and not in a callback. So
1113 * the operations can never be cancelled (since they will be already
1114 * completed at this point.
1119 gtk_file_system_unix_volume_free (GtkFileSystem *file_system,
1120 GtkFileSystemVolume *volume)
1124 path = (GtkFilePath *) volume;
1125 gtk_file_path_free (path);
1128 static GtkFilePath *
1129 gtk_file_system_unix_volume_get_base_path (GtkFileSystem *file_system,
1130 GtkFileSystemVolume *volume)
1132 return gtk_file_path_new_dup ("/");
1136 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem *file_system,
1137 GtkFileSystemVolume *volume)
1142 static GtkFileSystemHandle *
1143 gtk_file_system_unix_volume_mount (GtkFileSystem *file_system,
1144 GtkFileSystemVolume *volume,
1145 GtkFileSystemVolumeMountCallback callback,
1148 GError *error = NULL;
1149 GtkFileSystemHandle *handle = create_handle (file_system);
1151 g_set_error (&error,
1152 GTK_FILE_SYSTEM_ERROR,
1153 GTK_FILE_SYSTEM_ERROR_FAILED,
1154 _("This file system does not support mounting"));
1156 g_object_ref (handle);
1157 queue_volume_mount_callback (callback, handle, volume, error, data);
1163 gtk_file_system_unix_volume_get_display_name (GtkFileSystem *file_system,
1164 GtkFileSystemVolume *volume)
1166 return g_strdup (_("File System")); /* Same as Nautilus */
1170 get_icon_type_from_stat (struct stat *statp)
1172 if (S_ISBLK (statp->st_mode))
1173 return ICON_BLOCK_DEVICE;
1174 else if (S_ISLNK (statp->st_mode))
1175 return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
1176 else if (S_ISCHR (statp->st_mode))
1177 return ICON_CHARACTER_DEVICE;
1178 else if (S_ISDIR (statp->st_mode))
1179 return ICON_DIRECTORY;
1181 else if (S_ISFIFO (statp->st_mode))
1185 else if (S_ISSOCK (statp->st_mode))
1189 return ICON_REGULAR;
1193 get_icon_type (const char *filename,
1196 struct stat statbuf;
1198 /* If stat fails, try to fall back to lstat to catch broken links
1200 if (stat (filename, &statbuf) != 0)
1202 if (errno != ENOENT || lstat (filename, &statbuf) != 0)
1204 int save_errno = errno;
1205 gchar *display_name = g_filename_display_name (filename);
1207 GTK_FILE_SYSTEM_ERROR,
1208 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1209 _("Error getting information for '%s': %s"),
1211 g_strerror (save_errno));
1212 g_free (display_name);
1218 return get_icon_type_from_stat (&statbuf);
1221 /* Renders a fallback icon from the stock system */
1222 static const gchar *
1223 get_fallback_icon_name (IconType icon_type)
1225 const char *stock_name;
1229 case ICON_BLOCK_DEVICE:
1230 stock_name = GTK_STOCK_HARDDISK;
1233 case ICON_DIRECTORY:
1234 stock_name = GTK_STOCK_DIRECTORY;
1237 case ICON_EXECUTABLE:
1238 stock_name = GTK_STOCK_EXECUTE;
1242 stock_name = GTK_STOCK_FILE;
1250 gtk_file_system_unix_volume_get_icon_name (GtkFileSystem *file_system,
1251 GtkFileSystemVolume *volume,
1254 /* FIXME: maybe we just always want to return GTK_STOCK_HARDDISK here?
1255 * or the new tango icon name?
1257 return g_strdup ("gnome-dev-harddisk");
1261 get_parent_dir (const char *filename)
1265 len = strlen (filename);
1267 /* Ignore trailing slashes */
1268 if (len > 1 && filename[len - 1] == '/')
1272 tmp = g_strndup (filename, len - 1);
1274 parent = g_path_get_dirname (tmp);
1280 return g_path_get_dirname (filename);
1284 gtk_file_system_unix_get_parent (GtkFileSystem *file_system,
1285 const GtkFilePath *path,
1286 GtkFilePath **parent,
1289 const char *filename;
1291 filename = gtk_file_path_get_string (path);
1292 g_return_val_if_fail (filename != NULL, FALSE);
1293 g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
1295 if (filename_is_root (filename))
1301 gchar *parent_filename = get_parent_dir (filename);
1302 *parent = filename_to_path (parent_filename);
1303 g_free (parent_filename);
1309 static GtkFilePath *
1310 gtk_file_system_unix_make_path (GtkFileSystem *file_system,
1311 const GtkFilePath *base_path,
1312 const gchar *display_name,
1315 const char *base_filename;
1317 gchar *full_filename;
1318 GError *tmp_error = NULL;
1319 GtkFilePath *result;
1321 base_filename = gtk_file_path_get_string (base_path);
1322 g_return_val_if_fail (base_filename != NULL, NULL);
1323 g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
1325 if (strchr (display_name, G_DIR_SEPARATOR))
1328 GTK_FILE_SYSTEM_ERROR,
1329 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1330 _("The name \"%s\" is not valid because it contains the character \"%s\". "
1331 "Please use a different name."),
1337 filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
1341 GTK_FILE_SYSTEM_ERROR,
1342 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1344 tmp_error->message);
1346 g_error_free (tmp_error);
1351 full_filename = g_build_filename (base_filename, filename, NULL);
1352 result = filename_to_path (full_filename);
1354 g_free (full_filename);
1359 /* If this was a publically exported function, it should return
1360 * a dup'ed result, but we make it modify-in-place for efficiency
1361 * here, and because it works for us.
1364 canonicalize_filename (gchar *filename)
1367 gboolean last_was_slash = FALSE;
1374 if (*p == G_DIR_SEPARATOR)
1376 if (!last_was_slash)
1377 *q++ = G_DIR_SEPARATOR;
1379 last_was_slash = TRUE;
1383 if (last_was_slash && *p == '.')
1385 if (*(p + 1) == G_DIR_SEPARATOR ||
1388 if (*(p + 1) == '\0')
1393 else if (*(p + 1) == '.' &&
1394 (*(p + 2) == G_DIR_SEPARATOR ||
1397 if (q > filename + 1)
1400 while (q > filename + 1 &&
1401 *(q - 1) != G_DIR_SEPARATOR)
1405 if (*(p + 2) == '\0')
1413 last_was_slash = FALSE;
1419 last_was_slash = FALSE;
1426 if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
1432 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
1434 expand_tilde (const char *filename)
1436 const char *notilde;
1440 if (filename[0] != '~')
1441 return g_strdup (filename);
1443 notilde = filename + 1;
1445 slash = strchr (notilde, G_DIR_SEPARATOR);
1447 if (slash == notilde || !*notilde)
1449 home = g_get_home_dir ();
1452 return g_strdup (filename);
1457 struct passwd *passwd;
1460 username = g_strndup (notilde, slash - notilde);
1462 username = g_strdup (notilde);
1464 passwd = getpwnam (username);
1468 return g_strdup (filename);
1470 home = passwd->pw_dir;
1473 /* We put G_DIR_SEPARATOR_S so that empty basenames will make the resulting path end in a slash */
1475 return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
1477 return g_build_filename (home, G_DIR_SEPARATOR_S, NULL);
1481 gtk_file_system_unix_parse (GtkFileSystem *file_system,
1482 const GtkFilePath *base_path,
1484 GtkFilePath **folder,
1488 const char *base_filename;
1491 gboolean result = FALSE;
1493 base_filename = gtk_file_path_get_string (base_path);
1494 g_return_val_if_fail (base_filename != NULL, FALSE);
1495 g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
1497 filename = expand_tilde (str);
1501 GTK_FILE_SYSTEM_ERROR,
1502 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1503 "%s", ""); /* nothing for now, as we are string-frozen */
1507 last_slash = strrchr (filename, G_DIR_SEPARATOR);
1510 *folder = gtk_file_path_copy (base_path);
1511 *file_part = g_strdup (filename);
1518 GError *tmp_error = NULL;
1520 if (last_slash == filename)
1521 folder_part = g_strdup ("/");
1523 folder_part = g_filename_from_utf8 (filename, last_slash - filename,
1524 NULL, NULL, &tmp_error);
1529 GTK_FILE_SYSTEM_ERROR,
1530 GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1532 tmp_error->message);
1533 g_error_free (tmp_error);
1537 if (folder_part[0] == G_DIR_SEPARATOR)
1538 folder_path = folder_part;
1541 folder_path = g_build_filename (base_filename, folder_part, NULL);
1542 g_free (folder_part);
1545 canonicalize_filename (folder_path);
1547 *folder = filename_to_path (folder_path);
1548 *file_part = g_strdup (last_slash + 1);
1550 g_free (folder_path);
1562 gtk_file_system_unix_path_to_uri (GtkFileSystem *file_system,
1563 const GtkFilePath *path)
1565 return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
1569 gtk_file_system_unix_path_to_filename (GtkFileSystem *file_system,
1570 const GtkFilePath *path)
1572 return g_strdup (gtk_file_path_get_string (path));
1575 static GtkFilePath *
1576 gtk_file_system_unix_uri_to_path (GtkFileSystem *file_system,
1580 gchar *filename = g_filename_from_uri (uri, NULL, NULL);
1584 path = filename_to_path (filename);
1593 static GtkFilePath *
1594 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
1595 const gchar *filename)
1597 return filename_to_path (filename);
1600 /* Returns the name of the icon to be used for a path which is known to be a
1601 * directory. This can vary for Home, Desktop, etc.
1604 get_icon_name_for_directory (const char *path)
1606 if (!g_get_home_dir ())
1607 return "gnome-fs-directory";
1609 if (strcmp (g_get_home_dir (), path) == 0)
1610 return "gnome-fs-home";
1611 else if (strcmp (g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP), path) == 0)
1612 return "gnome-fs-desktop";
1614 return "gnome-fs-directory";
1619 /* Computes our internal icon type based on a path name; also returns the MIME
1620 * type in case we come up with ICON_REGULAR.
1623 get_icon_type_from_path (GtkFileFolderUnix *folder_unix,
1624 struct stat *statbuf,
1625 const char *filename,
1626 const char **mime_type)
1632 if (folder_unix && folder_unix->have_stat)
1635 struct stat_info_entry *entry;
1637 g_assert (folder_unix->stat_info != NULL);
1639 basename = g_path_get_basename (filename);
1640 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1644 if (entry->icon_type == ICON_UNDECIDED)
1646 entry->icon_type = get_icon_type_from_stat (&entry->statbuf);
1647 g_assert (entry->icon_type != ICON_UNDECIDED);
1649 icon_type = entry->icon_type;
1650 if (icon_type == ICON_REGULAR)
1652 fill_in_mime_type (folder_unix);
1653 *mime_type = entry->mime_type;
1661 return get_icon_type_from_stat (statbuf);
1663 icon_type = get_icon_type (filename, NULL);
1664 if (icon_type == ICON_REGULAR)
1665 *mime_type = xdg_mime_get_mime_type_for_file (filename, NULL);
1670 /* Renders an icon for a non-ICON_REGULAR file */
1671 static const gchar *
1672 get_special_icon_name (IconType icon_type,
1673 const gchar *filename)
1677 g_assert (icon_type != ICON_REGULAR);
1681 case ICON_BLOCK_DEVICE:
1682 name = "gnome-fs-blockdev";
1684 case ICON_BROKEN_SYMBOLIC_LINK:
1685 name = "gnome-fs-symlink";
1687 case ICON_CHARACTER_DEVICE:
1688 name = "gnome-fs-chardev";
1690 case ICON_DIRECTORY:
1691 /* get_icon_name_for_directory() returns a dupped string */
1692 return get_icon_name_for_directory (filename);
1693 case ICON_EXECUTABLE:
1694 name ="gnome-fs-executable";
1697 name = "gnome-fs-fifo";
1700 name = "gnome-fs-socket";
1703 g_assert_not_reached ();
1711 get_icon_name_for_mime_type (const char *mime_type)
1714 const char *separator;
1720 separator = strchr (mime_type, '/');
1722 return NULL; /* maybe we should return a GError with "invalid MIME-type" */
1724 /* FIXME: we default to the gnome icon naming for now. Some question
1725 * as below, how are we going to handle a second attempt?
1728 icon_name = g_string_new ("");
1729 g_string_append_len (icon_name, mime_type, separator - mime_type);
1730 g_string_append_c (icon_name, '-');
1731 g_string_append (icon_name, separator + 1);
1732 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1733 g_string_free (icon_name, TRUE);
1737 icon_name = g_string_new ("");
1738 g_string_append_len (icon_name, mime_type, separator - mime_type);
1739 g_string_append (icon_name, "-x-generic");
1740 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1741 g_string_free (icon_name, TRUE);
1746 icon_name = g_string_new ("gnome-mime-");
1747 g_string_append_len (icon_name, mime_type, separator - mime_type);
1748 g_string_append_c (icon_name, '-');
1749 g_string_append (icon_name, separator + 1);
1750 name = icon_name->str;
1751 g_string_free (icon_name, FALSE);
1755 /* FIXME: how are we going to implement a second attempt? */
1760 icon_name = g_string_new ("gnome-mime-");
1761 g_string_append_len (icon_name, mime_type, separator - mime_type);
1762 pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1763 g_string_free (icon_name, TRUE);
1770 bookmark_list_free (GSList *list)
1774 for (l = list; l; l = l->next)
1777 g_slist_free (list);
1780 /* Returns whether a URI is a local file:// */
1782 is_local_uri (const char *uri)
1788 /* This is rather crude, but hey */
1789 filename = g_filename_from_uri (uri, &hostname, NULL);
1791 result = (filename && !hostname);
1800 bookmark_get_filename (void)
1804 filename = g_build_filename (g_get_home_dir (),
1805 BOOKMARKS_FILENAME, NULL);
1806 g_assert (filename != NULL);
1811 bookmark_list_read (GSList **bookmarks, GError **error)
1815 gboolean result = FALSE;
1817 filename = bookmark_get_filename ();
1820 if (g_file_get_contents (filename, &contents, NULL, error))
1822 gchar **lines = g_strsplit (contents, "\n", -1);
1826 table = g_hash_table_new (g_str_hash, g_str_equal);
1828 for (i = 0; lines[i]; i++)
1830 if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1832 *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1833 g_hash_table_insert (table, lines[i], lines[i]);
1838 g_hash_table_destroy (table);
1841 *bookmarks = g_slist_reverse (*bookmarks);
1851 bookmark_list_write (GSList *bookmarks,
1857 GError *tmp_error = NULL;
1860 string = g_string_new ("");
1862 for (l = bookmarks; l; l = l->next)
1864 g_string_append (string, l->data);
1865 g_string_append_c (string, '\n');
1868 filename = bookmark_get_filename ();
1870 result = g_file_set_contents (filename, string->str, -1, &tmp_error);
1873 g_string_free (string, TRUE);
1878 GTK_FILE_SYSTEM_ERROR,
1879 GTK_FILE_SYSTEM_ERROR_FAILED,
1880 _("Bookmark saving failed: %s"),
1881 tmp_error->message);
1883 g_error_free (tmp_error);
1890 gtk_file_system_unix_insert_bookmark (GtkFileSystem *file_system,
1891 const GtkFilePath *path,
1903 if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1905 g_propagate_error (error, err);
1909 num_bookmarks = g_slist_length (bookmarks);
1910 g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1914 uri = gtk_file_system_unix_path_to_uri (file_system, path);
1916 for (l = bookmarks; l; l = l->next)
1918 char *bookmark, *space;
1922 space = strchr (bookmark, ' ');
1925 if (strcmp (bookmark, uri) != 0)
1933 GTK_FILE_SYSTEM_ERROR,
1934 GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1935 _("'%s' already exists in the bookmarks list"),
1941 bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1942 if (bookmark_list_write (bookmarks, error))
1945 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1951 bookmark_list_free (bookmarks);
1957 gtk_file_system_unix_remove_bookmark (GtkFileSystem *file_system,
1958 const GtkFilePath *path,
1966 if (!bookmark_list_read (&bookmarks, error))
1971 uri = gtk_file_system_path_to_uri (file_system, path);
1973 for (l = bookmarks; l; l = l->next)
1975 char *bookmark, *space;
1977 bookmark = (char *)l->data;
1978 space = strchr (bookmark, ' ');
1982 if (strcmp (bookmark, uri) != 0)
1990 bookmarks = g_slist_remove_link (bookmarks, l);
1993 if (bookmark_list_write (bookmarks, error))
1997 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
2005 GTK_FILE_SYSTEM_ERROR,
2006 GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
2007 _("'%s' does not exist in the bookmarks list"),
2013 bookmark_list_free (bookmarks);
2019 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
2025 if (!bookmark_list_read (&bookmarks, NULL))
2030 for (l = bookmarks; l; l = l->next)
2032 char *bookmark, *space;
2034 bookmark = (char *)l->data;
2035 space = strchr (bookmark, ' ');
2039 if (is_local_uri (bookmark))
2040 result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
2043 bookmark_list_free (bookmarks);
2045 result = g_slist_reverse (result);
2050 gtk_file_system_unix_get_bookmark_label (GtkFileSystem *file_system,
2051 const GtkFilePath *path)
2056 char *bookmark, *space, *uri;
2061 uri = gtk_file_system_path_to_uri (file_system, path);
2062 bookmark_list_read (&labels, NULL);
2064 for (l = labels; l && !label; l = l->next)
2066 bookmark = (char *)l->data;
2067 space = strchr (bookmark, ' ');
2073 if (strcmp (uri, bookmark) == 0)
2074 label = g_strdup (space + 1);
2077 bookmark_list_free (labels);
2084 gtk_file_system_unix_set_bookmark_label (GtkFileSystem *file_system,
2085 const GtkFilePath *path,
2090 gchar *bookmark, *space, *uri;
2095 uri = gtk_file_system_path_to_uri (file_system, path);
2096 bookmark_list_read (&labels, NULL);
2099 for (l = labels; l && !found; l = l->next)
2101 bookmark = (gchar *)l->data;
2102 space = strchr (bookmark, ' ');
2106 if (strcmp (bookmark, uri) != 0)
2115 if (label && *label)
2116 l->data = g_strdup_printf ("%s %s", uri, label);
2118 l->data = g_strdup (uri);
2127 if (bookmark_list_write (labels, NULL))
2128 g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
2131 bookmark_list_free (labels);
2136 _gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
2138 GObjectClass *gobject_class = G_OBJECT_CLASS (class);
2140 gobject_class->finalize = gtk_file_folder_unix_finalize;
2144 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
2146 iface->get_info = gtk_file_folder_unix_get_info;
2147 iface->list_children = gtk_file_folder_unix_list_children;
2148 iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;
2152 _gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
2157 gtk_file_folder_unix_finalize (GObject *object)
2159 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
2161 if (folder_unix->load_folder_id)
2163 g_source_remove (folder_unix->load_folder_id);
2164 folder_unix->load_folder_id = 0;
2167 g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
2169 if (folder_unix->stat_info)
2172 g_print ("Releasing information for directory %s\n", folder_unix->filename);
2174 g_hash_table_destroy (folder_unix->stat_info);
2177 g_free (folder_unix->filename);
2179 G_OBJECT_CLASS (_gtk_file_folder_unix_parent_class)->finalize (object);
2182 /* Creates a GtkFileInfo for "/" by stat()ing it */
2183 static GtkFileInfo *
2184 file_info_for_root_with_error (const char *root_name,
2187 struct stat statbuf;
2190 if (stat (root_name, &statbuf) != 0)
2194 saved_errno = errno;
2196 GTK_FILE_SYSTEM_ERROR,
2197 GTK_FILE_SYSTEM_ERROR_FAILED,
2198 _("Error getting information for '%s': %s"),
2199 "/", g_strerror (saved_errno));
2204 info = gtk_file_info_new ();
2205 gtk_file_info_set_display_name (info, "/");
2206 gtk_file_info_set_is_folder (info, TRUE);
2207 gtk_file_info_set_is_hidden (info, FALSE);
2208 gtk_file_info_set_mime_type (info, "x-directory/normal");
2209 gtk_file_info_set_modification_time (info, statbuf.st_mtime);
2210 gtk_file_info_set_size (info, statbuf.st_size);
2216 stat_with_error (const char *filename,
2217 struct stat *statbuf,
2220 if (stat (filename, statbuf) == -1 &&
2221 (errno != ENOENT || lstat (filename, statbuf) == -1))
2227 saved_errno = errno;
2229 if (saved_errno == ENOENT)
2230 code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
2232 code = GTK_FILE_SYSTEM_ERROR_FAILED;
2234 display_name = g_filename_display_name (filename);
2236 GTK_FILE_SYSTEM_ERROR,
2238 _("Error getting information for '%s': %s"),
2240 g_strerror (saved_errno));
2242 g_free (display_name);
2249 /* Creates a new GtkFileInfo from the specified data */
2250 static GtkFileInfo *
2251 create_file_info (GtkFileFolderUnix *folder_unix,
2252 const char *filename,
2253 const char *basename,
2254 GtkFileInfoType types,
2255 struct stat *statbuf,
2256 const char *mime_type)
2260 info = gtk_file_info_new ();
2262 if (types & GTK_FILE_INFO_DISPLAY_NAME)
2264 gchar *display_name = g_filename_display_basename (filename);
2265 gtk_file_info_set_display_name (info, display_name);
2266 g_free (display_name);
2269 if (types & GTK_FILE_INFO_IS_HIDDEN)
2273 if (file_is_hidden (folder_unix, basename))
2274 gtk_file_info_set_is_hidden (info, TRUE);
2278 if (get_is_hidden_for_file (filename, basename))
2279 gtk_file_info_set_is_hidden (info, TRUE);
2283 if (types & GTK_FILE_INFO_IS_FOLDER)
2284 gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode));
2286 if (types & GTK_FILE_INFO_MIME_TYPE)
2287 gtk_file_info_set_mime_type (info, mime_type);
2289 if (types & GTK_FILE_INFO_MODIFICATION_TIME)
2290 gtk_file_info_set_modification_time (info, statbuf->st_mtime);
2292 if (types & GTK_FILE_INFO_SIZE)
2293 gtk_file_info_set_size (info, (gint64) statbuf->st_size);
2295 if (types & GTK_FILE_INFO_ICON)
2298 gboolean free_icon_name = FALSE;
2299 const char *icon_name;
2300 const char *icon_mime_type;
2302 icon_type = get_icon_type_from_path (folder_unix, statbuf, filename, &icon_mime_type);
2307 icon_name = get_fallback_icon_name (icon_type);
2311 free_icon_name = TRUE;
2313 icon_name = get_icon_name_for_mime_type (icon_mime_type);
2315 icon_name = get_icon_name_for_mime_type (mime_type);
2319 icon_name = get_special_icon_name (icon_type, filename);
2323 gtk_file_info_set_icon_name (info, icon_name);
2326 g_free ((char *) icon_name);
2332 static struct stat_info_entry *
2333 create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix,
2334 const char *filename,
2335 const char *basename,
2336 struct stat *statbuf)
2340 struct stat_info_entry *entry;
2342 entry = g_new0 (struct stat_info_entry, 1);
2344 if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
2345 entry->statbuf = *statbuf;
2347 if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
2348 entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename, statbuf));
2350 g_hash_table_insert (folder_unix->stat_info,
2351 g_strdup (basename),
2354 path = gtk_file_path_new_dup (filename);
2355 paths = g_slist_append (NULL, path);
2356 g_signal_emit_by_name (folder_unix, "files-added", paths);
2357 gtk_file_path_free (path);
2358 g_slist_free (paths);
2363 static GtkFileInfo *
2364 gtk_file_folder_unix_get_info (GtkFileFolder *folder,
2365 const GtkFilePath *path,
2368 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2370 gchar *dirname, *basename;
2371 const char *filename;
2372 GtkFileInfoType types;
2373 struct stat statbuf;
2374 const char *mime_type;
2376 /* Get_info for "/" */
2379 g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL);
2380 return file_info_for_root_with_error (folder_unix->filename, error);
2383 /* Get_info for normal files */
2385 filename = gtk_file_path_get_string (path);
2386 g_return_val_if_fail (filename != NULL, NULL);
2387 g_return_val_if_fail (g_path_is_absolute (filename), NULL);
2389 dirname = get_parent_dir (filename);
2390 g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
2393 basename = g_path_get_basename (filename);
2394 types = folder_unix->types;
2396 if (folder_unix->have_stat)
2398 struct stat_info_entry *entry;
2400 g_assert (folder_unix->stat_info != NULL);
2401 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2405 if (!stat_with_error (filename, &statbuf, error))
2411 entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf);
2414 info = create_file_info (folder_unix, filename, basename, types, &entry->statbuf, entry->mime_type);
2420 if (!stat_with_error (filename, &statbuf, error))
2426 if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
2427 mime_type = xdg_mime_get_mime_type_for_file (filename, &statbuf);
2431 info = create_file_info (folder_unix, filename, basename, types, &statbuf, mime_type);
2439 cb_list_children (gpointer key, gpointer value, gpointer user_data)
2441 GSList **children = user_data;
2442 *children = g_slist_prepend (*children, key);
2446 gtk_file_folder_unix_list_children (GtkFileFolder *folder,
2450 GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2455 /* Get the list of basenames. */
2456 if (folder_unix->stat_info)
2457 g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
2459 /* Turn basenames into GFilePaths. */
2460 for (l = *children; l; l = l->next)
2462 const char *basename = l->data;
2463 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2464 l->data = filename_to_path (fullname);
2472 gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
2474 return GTK_FILE_FOLDER_UNIX (folder)->is_finished_loading;
2478 free_stat_info_entry (struct stat_info_entry *entry)
2480 g_free (entry->mime_type);
2485 fill_in_names (GtkFileFolderUnix *folder_unix, GError **error)
2489 if (folder_unix->stat_info)
2492 dir = g_dir_open (folder_unix->filename, 0, error);
2496 folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal,
2497 (GDestroyNotify) g_free,
2498 (GDestroyNotify) free_stat_info_entry);
2502 struct stat_info_entry *entry;
2503 const gchar *basename;
2505 basename = g_dir_read_name (dir);
2509 entry = g_new0 (struct stat_info_entry, 1);
2510 if (folder_unix->is_network_dir)
2512 entry->statbuf.st_mode = S_IFDIR;
2513 entry->mime_type = g_strdup ("x-directory/normal");
2516 g_hash_table_insert (folder_unix->stat_info,
2517 g_strdup (basename),
2523 folder_unix->asof = time (NULL);
2528 cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data)
2530 const char *basename = key;
2531 struct stat_info_entry *entry = value;
2532 GtkFileFolderUnix *folder_unix = user_data;
2533 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2536 if (stat (fullname, &entry->statbuf) == -1 &&
2537 (errno != ENOENT || lstat (fullname, &entry->statbuf) == -1))
2538 result = TRUE; /* Couldn't stat -- remove from hash. */
2548 fill_in_stats (GtkFileFolderUnix *folder_unix)
2550 if (folder_unix->have_stat)
2553 if (!fill_in_names (folder_unix, NULL))
2556 if (!folder_unix->is_network_dir)
2557 g_hash_table_foreach_remove (folder_unix->stat_info,
2561 folder_unix->have_stat = TRUE;
2566 cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data)
2568 const char *basename = key;
2569 struct stat_info_entry *entry = value;
2570 GtkFileFolderUnix *folder_unix = user_data;
2571 char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2572 struct stat *statbuf = NULL;
2573 const char *mime_type;
2575 if (folder_unix->have_stat)
2576 statbuf = &entry->statbuf;
2578 mime_type = xdg_mime_get_mime_type_for_file (fullname, statbuf);
2579 entry->mime_type = g_strdup (mime_type);
2587 fill_in_mime_type (GtkFileFolderUnix *folder_unix)
2589 if (folder_unix->have_mime_type)
2592 if (!folder_unix->have_stat)
2595 g_assert (folder_unix->stat_info != NULL);
2597 if (!folder_unix->is_network_dir)
2598 g_hash_table_foreach_remove (folder_unix->stat_info,
2599 cb_fill_in_mime_type,
2602 folder_unix->have_mime_type = TRUE;
2606 read_hidden_file (const char *dirname)
2608 gchar **lines = NULL;
2612 hidden_file = g_build_filename (dirname, HIDDEN_FILENAME, NULL);
2614 if (g_file_get_contents (hidden_file, &contents, NULL, NULL))
2616 lines = g_strsplit (contents, "\n", -1);
2620 g_free (hidden_file);
2626 fill_in_hidden (GtkFileFolderUnix *folder_unix)
2630 if (folder_unix->have_hidden)
2633 lines = read_hidden_file (folder_unix->filename);
2639 for (i = 0; lines[i]; i++)
2643 struct stat_info_entry *entry;
2645 entry = g_hash_table_lookup (folder_unix->stat_info, lines[i]);
2647 entry->hidden = TRUE;
2654 folder_unix->have_hidden = TRUE;
2657 static GtkFilePath *
2658 filename_to_path (const char *filename)
2662 tmp = remove_trailing_slash (filename);
2663 return gtk_file_path_new_steal (tmp);
2667 filename_is_root (const char *filename)
2669 const gchar *after_root;
2671 after_root = g_path_skip_root (filename);
2673 return (after_root != NULL && *after_root == '\0');
2677 get_is_hidden_for_file (const char *filename,
2678 const char *basename)
2682 gboolean hidden = FALSE;
2684 dirname = g_path_get_dirname (filename);
2685 lines = read_hidden_file (dirname);
2692 for (i = 0; lines[i]; i++)
2694 if (lines[i][0] && strcmp (lines[i], basename) == 0)
2708 file_is_hidden (GtkFileFolderUnix *folder_unix,
2709 const char *basename)
2711 struct stat_info_entry *entry;
2713 if (basename[0] == '.' || basename[strlen (basename) - 1] == '~')
2716 if (folder_unix->have_stat)
2718 fill_in_hidden (folder_unix);
2720 entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2723 return entry->hidden;
2729 #define __GTK_FILE_SYSTEM_UNIX_C__
2730 #include "gtkaliasdef.c"