]> Pileus Git - ~andy/gtk/blob - gtk/gtkfilesystemunix.c
54e02aa3ef0840d0c5901bead67a6563ac78fe92
[~andy/gtk] / gtk / gtkfilesystemunix.c
1 /* GTK - The GIMP Toolkit
2  * gtkfilesystemunix.c: Default implementation of GtkFileSystem for UNIX-like systems
3  * Copyright (C) 2003, Red Hat, Inc.
4  *
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.
9  *
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.
14  *
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.
19  */
20
21 #include <config.h>
22
23 #include "gtkfilesystem.h"
24 #include "gtkfilesystemunix.h"
25 #include "gtkicontheme.h"
26 #include "gtkintl.h"
27 #include "gtkstock.h"
28 #include "gtkalias.h"
29
30 #define XDG_PREFIX _gtk_xdg
31 #include "xdgmime/xdgmime.h"
32
33 #include <errno.h>
34 #include <string.h>
35 #include <sys/stat.h>
36 #include <sys/types.h>
37 #include <pwd.h>
38 #ifdef HAVE_UNISTD_H
39 #include <unistd.h>
40 #endif
41 #include <stdio.h>
42 #include <time.h>
43
44 #define BOOKMARKS_FILENAME ".gtk-bookmarks"
45
46 #define FOLDER_CACHE_LIFETIME 2 /* seconds */
47
48 typedef struct _GtkFileSystemUnixClass GtkFileSystemUnixClass;
49
50 #define GTK_FILE_SYSTEM_UNIX_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
51 #define GTK_IS_FILE_SYSTEM_UNIX_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_SYSTEM_UNIX))
52 #define GTK_FILE_SYSTEM_UNIX_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_SYSTEM_UNIX, GtkFileSystemUnixClass))
53
54 struct _GtkFileSystemUnixClass
55 {
56   GObjectClass parent_class;
57 };
58
59 struct _GtkFileSystemUnix
60 {
61   GObject parent_instance;
62
63   GHashTable *folder_hash;
64
65   /* For /afs and /net */
66   struct stat afs_statbuf;
67   struct stat net_statbuf;
68
69   guint have_afs : 1;
70   guint have_net : 1;
71 };
72
73 /* Icon type, supplemented by MIME type
74  */
75 typedef enum {
76   ICON_UNDECIDED, /* Only used while we have not yet computed the icon in a struct stat_info_entry */
77   ICON_NONE,      /* "Could not compute the icon type" */
78   ICON_REGULAR,   /* Use mime type for icon */
79   ICON_BLOCK_DEVICE,
80   ICON_BROKEN_SYMBOLIC_LINK,
81   ICON_CHARACTER_DEVICE,
82   ICON_DIRECTORY,
83   ICON_EXECUTABLE,
84   ICON_FIFO,
85   ICON_SOCKET
86 } IconType;
87
88
89 #define GTK_TYPE_FILE_FOLDER_UNIX             (gtk_file_folder_unix_get_type ())
90 #define GTK_FILE_FOLDER_UNIX(obj)             (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnix))
91 #define GTK_IS_FILE_FOLDER_UNIX(obj)          (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_FILE_FOLDER_UNIX))
92 #define GTK_FILE_FOLDER_UNIX_CLASS(klass)     (G_TYPE_CHECK_CLASS_CAST ((klass), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
93 #define GTK_IS_FILE_FOLDER_UNIX_CLASS(klass)  (G_TYPE_CHECK_CLASS_TYPE ((klass), GTK_TYPE_FILE_FOLDER_UNIX))
94 #define GTK_FILE_FOLDER_UNIX_GET_CLASS(obj)   (G_TYPE_INSTANCE_GET_CLASS ((obj), GTK_TYPE_FILE_FOLDER_UNIX, GtkFileFolderUnixClass))
95
96 typedef struct _GtkFileFolderUnix      GtkFileFolderUnix;
97 typedef struct _GtkFileFolderUnixClass GtkFileFolderUnixClass;
98
99 struct _GtkFileFolderUnixClass
100 {
101   GObjectClass parent_class;
102 };
103
104 struct _GtkFileFolderUnix
105 {
106   GObject parent_instance;
107
108   GtkFileSystemUnix *system_unix;
109   GtkFileInfoType types;
110   gchar *filename;
111   GHashTable *stat_info;
112   guint have_stat : 1;
113   guint have_mime_type : 1;
114   guint is_network_dir : 1;
115   time_t asof;
116 };
117
118 struct stat_info_entry {
119   struct stat statbuf;
120   char *mime_type;
121   IconType icon_type;
122 };
123
124 static const GtkFileInfoType STAT_NEEDED_MASK = (GTK_FILE_INFO_IS_FOLDER |
125                                                  GTK_FILE_INFO_MODIFICATION_TIME |
126                                                  GTK_FILE_INFO_SIZE);
127
128 static GObjectClass *system_parent_class;
129 static GObjectClass *folder_parent_class;
130
131 static void gtk_file_system_unix_class_init   (GtkFileSystemUnixClass *class);
132 static void gtk_file_system_unix_iface_init   (GtkFileSystemIface     *iface);
133 static void gtk_file_system_unix_init         (GtkFileSystemUnix      *impl);
134 static void gtk_file_system_unix_finalize     (GObject                *object);
135
136 static GSList *             gtk_file_system_unix_list_volumes        (GtkFileSystem     *file_system);
137 static GtkFileSystemVolume *gtk_file_system_unix_get_volume_for_path (GtkFileSystem     *file_system,
138                                                                       const GtkFilePath *path);
139
140 static GtkFileFolder *gtk_file_system_unix_get_folder    (GtkFileSystem      *file_system,
141                                                           const GtkFilePath  *path,
142                                                           GtkFileInfoType     types,
143                                                           GError            **error);
144 static gboolean       gtk_file_system_unix_create_folder (GtkFileSystem      *file_system,
145                                                           const GtkFilePath  *path,
146                                                           GError            **error);
147
148 static void         gtk_file_system_unix_volume_free             (GtkFileSystem       *file_system,
149                                                                   GtkFileSystemVolume *volume);
150 static GtkFilePath *gtk_file_system_unix_volume_get_base_path    (GtkFileSystem       *file_system,
151                                                                   GtkFileSystemVolume *volume);
152 static gboolean     gtk_file_system_unix_volume_get_is_mounted   (GtkFileSystem       *file_system,
153                                                                   GtkFileSystemVolume *volume);
154 static gboolean     gtk_file_system_unix_volume_mount            (GtkFileSystem       *file_system,
155                                                                   GtkFileSystemVolume *volume,
156                                                                   GError             **error);
157 static gchar *      gtk_file_system_unix_volume_get_display_name (GtkFileSystem       *file_system,
158                                                                   GtkFileSystemVolume *volume);
159 static GdkPixbuf *  gtk_file_system_unix_volume_render_icon      (GtkFileSystem        *file_system,
160                                                                   GtkFileSystemVolume  *volume,
161                                                                   GtkWidget            *widget,
162                                                                   gint                  pixel_size,
163                                                                   GError              **error);
164
165 static gboolean       gtk_file_system_unix_get_parent    (GtkFileSystem      *file_system,
166                                                           const GtkFilePath  *path,
167                                                           GtkFilePath       **parent,
168                                                           GError            **error);
169 static GtkFilePath *  gtk_file_system_unix_make_path     (GtkFileSystem      *file_system,
170                                                           const GtkFilePath  *base_path,
171                                                           const gchar        *display_name,
172                                                           GError            **error);
173 static gboolean       gtk_file_system_unix_parse         (GtkFileSystem      *file_system,
174                                                           const GtkFilePath  *base_path,
175                                                           const gchar        *str,
176                                                           GtkFilePath       **folder,
177                                                           gchar             **file_part,
178                                                           GError            **error);
179
180 static gchar *      gtk_file_system_unix_path_to_uri      (GtkFileSystem     *file_system,
181                                                            const GtkFilePath *path);
182 static gchar *      gtk_file_system_unix_path_to_filename (GtkFileSystem     *file_system,
183                                                            const GtkFilePath *path);
184 static GtkFilePath *gtk_file_system_unix_uri_to_path      (GtkFileSystem     *file_system,
185                                                            const gchar       *uri);
186 static GtkFilePath *gtk_file_system_unix_filename_to_path (GtkFileSystem     *file_system,
187                                                            const gchar       *filename);
188
189 static GdkPixbuf *gtk_file_system_unix_render_icon (GtkFileSystem     *file_system,
190                                                     const GtkFilePath *path,
191                                                     GtkWidget         *widget,
192                                                     gint               pixel_size,
193                                                     GError           **error);
194
195 static gboolean gtk_file_system_unix_insert_bookmark (GtkFileSystem     *file_system,
196                                                       const GtkFilePath *path,
197                                                       gint               position,
198                                                       GError           **error);
199 static gboolean gtk_file_system_unix_remove_bookmark (GtkFileSystem     *file_system,
200                                                       const GtkFilePath *path,
201                                                       GError           **error);
202 static GSList * gtk_file_system_unix_list_bookmarks  (GtkFileSystem     *file_system);
203 static gchar  * gtk_file_system_unix_get_bookmark_label (GtkFileSystem     *file_system,
204                                                          const GtkFilePath *path);
205 static void     gtk_file_system_unix_set_bookmark_label (GtkFileSystem     *file_system,
206                                                          const GtkFilePath *path,
207                                                          const gchar       *label);
208
209 static GType gtk_file_folder_unix_get_type   (void);
210 static void  gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class);
211 static void  gtk_file_folder_unix_iface_init (GtkFileFolderIface     *iface);
212 static void  gtk_file_folder_unix_init       (GtkFileFolderUnix      *impl);
213 static void  gtk_file_folder_unix_finalize   (GObject                *object);
214
215 static GtkFileInfo *gtk_file_folder_unix_get_info      (GtkFileFolder  *folder,
216                                                         const GtkFilePath    *path,
217                                                         GError        **error);
218 static gboolean     gtk_file_folder_unix_list_children (GtkFileFolder  *folder,
219                                                         GSList        **children,
220                                                         GError        **error);
221
222 static gboolean     gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder);
223
224 static GtkFilePath *filename_to_path   (const gchar       *filename);
225
226 static gboolean     filename_is_root  (const char       *filename);
227
228 static gboolean fill_in_names (GtkFileFolderUnix *folder_unix, GError **error);
229 static void fill_in_stats (GtkFileFolderUnix *folder_unix);
230 static void fill_in_mime_type (GtkFileFolderUnix *folder_unix);
231
232 static char *       get_parent_dir    (const char       *filename);
233
234 /*
235  * GtkFileSystemUnix
236  */
237 GType
238 gtk_file_system_unix_get_type (void)
239 {
240   static GType file_system_unix_type = 0;
241
242   if (!file_system_unix_type)
243     {
244       static const GTypeInfo file_system_unix_info =
245       {
246         sizeof (GtkFileSystemUnixClass),
247         NULL,           /* base_init */
248         NULL,           /* base_finalize */
249         (GClassInitFunc) gtk_file_system_unix_class_init,
250         NULL,           /* class_finalize */
251         NULL,           /* class_data */
252         sizeof (GtkFileSystemUnix),
253         0,              /* n_preallocs */
254         (GInstanceInitFunc) gtk_file_system_unix_init,
255       };
256
257       static const GInterfaceInfo file_system_info =
258       {
259         (GInterfaceInitFunc) gtk_file_system_unix_iface_init, /* interface_init */
260         NULL,                                                 /* interface_finalize */
261         NULL                                                  /* interface_data */
262       };
263
264       file_system_unix_type = g_type_register_static (G_TYPE_OBJECT,
265                                                       "GtkFileSystemUnix",
266                                                       &file_system_unix_info, 0);
267       g_type_add_interface_static (file_system_unix_type,
268                                    GTK_TYPE_FILE_SYSTEM,
269                                    &file_system_info);
270     }
271
272   return file_system_unix_type;
273 }
274
275 /**
276  * gtk_file_system_unix_new:
277  *
278  * Creates a new #GtkFileSystemUnix object. #GtkFileSystemUnix
279  * implements the #GtkFileSystem interface with direct access to
280  * the filesystem using Unix/Linux API calls
281  *
282  * Return value: the new #GtkFileSystemUnix object
283  **/
284 GtkFileSystem *
285 gtk_file_system_unix_new (void)
286 {
287   return g_object_new (GTK_TYPE_FILE_SYSTEM_UNIX, NULL);
288 }
289
290 static void
291 gtk_file_system_unix_class_init (GtkFileSystemUnixClass *class)
292 {
293   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
294
295   system_parent_class = g_type_class_peek_parent (class);
296
297   gobject_class->finalize = gtk_file_system_unix_finalize;
298 }
299
300 static void
301 gtk_file_system_unix_iface_init   (GtkFileSystemIface *iface)
302 {
303   iface->list_volumes = gtk_file_system_unix_list_volumes;
304   iface->get_volume_for_path = gtk_file_system_unix_get_volume_for_path;
305   iface->get_folder = gtk_file_system_unix_get_folder;
306   iface->create_folder = gtk_file_system_unix_create_folder;
307   iface->volume_free = gtk_file_system_unix_volume_free;
308   iface->volume_get_base_path = gtk_file_system_unix_volume_get_base_path;
309   iface->volume_get_is_mounted = gtk_file_system_unix_volume_get_is_mounted;
310   iface->volume_mount = gtk_file_system_unix_volume_mount;
311   iface->volume_get_display_name = gtk_file_system_unix_volume_get_display_name;
312   iface->volume_render_icon = gtk_file_system_unix_volume_render_icon;
313   iface->get_parent = gtk_file_system_unix_get_parent;
314   iface->make_path = gtk_file_system_unix_make_path;
315   iface->parse = gtk_file_system_unix_parse;
316   iface->path_to_uri = gtk_file_system_unix_path_to_uri;
317   iface->path_to_filename = gtk_file_system_unix_path_to_filename;
318   iface->uri_to_path = gtk_file_system_unix_uri_to_path;
319   iface->filename_to_path = gtk_file_system_unix_filename_to_path;
320   iface->render_icon = gtk_file_system_unix_render_icon;
321   iface->insert_bookmark = gtk_file_system_unix_insert_bookmark;
322   iface->remove_bookmark = gtk_file_system_unix_remove_bookmark;
323   iface->list_bookmarks = gtk_file_system_unix_list_bookmarks;
324   iface->get_bookmark_label = gtk_file_system_unix_get_bookmark_label;
325   iface->set_bookmark_label = gtk_file_system_unix_set_bookmark_label;
326 }
327
328 static void
329 gtk_file_system_unix_init (GtkFileSystemUnix *system_unix)
330 {
331   system_unix->folder_hash = g_hash_table_new (g_str_hash, g_str_equal);
332
333   if (stat ("/afs", &system_unix->afs_statbuf) == 0)
334     system_unix->have_afs = TRUE;
335   else
336     system_unix->have_afs = FALSE;
337
338   if (stat ("/net", &system_unix->net_statbuf) == 0)
339     system_unix->have_net = TRUE;
340   else
341     system_unix->have_net = FALSE;
342 }
343
344 static void
345 gtk_file_system_unix_finalize (GObject *object)
346 {
347   GtkFileSystemUnix *system_unix;
348
349   system_unix = GTK_FILE_SYSTEM_UNIX (object);
350
351   /* FIXME: assert that the hash is empty? */
352   g_hash_table_destroy (system_unix->folder_hash);
353
354   system_parent_class->finalize (object);
355 }
356
357 /* Returns our single root volume */
358 static GtkFileSystemVolume *
359 get_root_volume (void)
360 {
361   return (GtkFileSystemVolume *) gtk_file_path_new_dup ("/");
362 }
363
364 static GSList *
365 gtk_file_system_unix_list_volumes (GtkFileSystem *file_system)
366 {
367   return g_slist_append (NULL, get_root_volume ());
368 }
369
370 static GtkFileSystemVolume *
371 gtk_file_system_unix_get_volume_for_path (GtkFileSystem     *file_system,
372                                           const GtkFilePath *path)
373 {
374   return get_root_volume ();
375 }
376
377 static char *
378 remove_trailing_slash (const char *filename)
379 {
380   int len;
381
382   len = strlen (filename);
383
384   if (len > 1 && filename[len - 1] == '/')
385     return g_strndup (filename, len - 1);
386   else
387     return g_memdup (filename, len + 1);
388 }
389
390 static GtkFileFolder *
391 gtk_file_system_unix_get_folder (GtkFileSystem     *file_system,
392                                  const GtkFilePath *path,
393                                  GtkFileInfoType    types,
394                                  GError           **error)
395 {
396   GtkFileSystemUnix *system_unix;
397   GtkFileFolderUnix *folder_unix;
398   const char *filename;
399   char *filename_copy;
400   time_t now = time (NULL);
401
402   system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
403
404   filename = gtk_file_path_get_string (path);
405   g_return_val_if_fail (filename != NULL, NULL);
406   g_return_val_if_fail (g_path_is_absolute (filename), NULL);
407
408   filename_copy = remove_trailing_slash (filename);
409   folder_unix = g_hash_table_lookup (system_unix->folder_hash, filename_copy);
410
411   if (folder_unix)
412     {
413       g_free (filename_copy);
414       if (now - folder_unix->asof >= FOLDER_CACHE_LIFETIME &&
415           folder_unix->stat_info)
416         {
417 #if 0
418           g_print ("Cleaning out cached directory %s\n", filename);
419 #endif
420           g_hash_table_destroy (folder_unix->stat_info);
421           folder_unix->stat_info = NULL;
422           folder_unix->have_mime_type = FALSE;
423           folder_unix->have_stat = FALSE;
424         }
425
426       g_object_ref (folder_unix);
427       folder_unix->types |= types;
428       types = folder_unix->types;
429     }
430   else
431     {
432       struct stat statbuf;
433       int result;
434       int code;
435       int my_errno;
436
437       code = my_errno = 0; /* shut up GCC */
438
439       result = stat (filename, &statbuf);
440
441       if (result == 0)
442         {
443           if (!S_ISDIR (statbuf.st_mode))
444             {
445               result = -1;
446               code = GTK_FILE_SYSTEM_ERROR_NOT_FOLDER;
447               my_errno = ENOTDIR;
448             }
449         }
450       else
451         {
452           my_errno = errno;
453
454           if (my_errno == ENOENT)
455             code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
456           else
457             code = GTK_FILE_SYSTEM_ERROR_FAILED;
458         }
459
460       if (result != 0)
461         {
462           gchar *display_name = g_filename_display_name (filename);
463           g_set_error (error,
464                        GTK_FILE_SYSTEM_ERROR,
465                        code,
466                        _("Error getting information for '%s': %s"),
467                        display_name,
468                        g_strerror (my_errno));
469
470           g_free (display_name);
471           g_free (filename_copy);
472           return NULL;
473         }
474
475       folder_unix = g_object_new (GTK_TYPE_FILE_FOLDER_UNIX, NULL);
476       folder_unix->system_unix = system_unix;
477       folder_unix->filename = filename_copy;
478       folder_unix->types = types;
479       folder_unix->stat_info = NULL;
480       folder_unix->asof = now;
481       folder_unix->have_mime_type = FALSE;
482       folder_unix->have_stat = FALSE;
483
484       if ((system_unix->have_afs &&
485            system_unix->afs_statbuf.st_dev == statbuf.st_dev &&
486            system_unix->afs_statbuf.st_ino == statbuf.st_ino) ||
487           (system_unix->have_net &&
488            system_unix->net_statbuf.st_dev == statbuf.st_dev &&
489            system_unix->net_statbuf.st_ino == statbuf.st_ino))
490         folder_unix->is_network_dir = TRUE;
491       else
492         folder_unix->is_network_dir = FALSE;
493
494       g_hash_table_insert (system_unix->folder_hash,
495                            folder_unix->filename,
496                            folder_unix);
497     }
498
499   if ((types & STAT_NEEDED_MASK) != 0)
500     fill_in_stats (folder_unix);
501
502   if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
503     fill_in_mime_type (folder_unix);
504
505   return GTK_FILE_FOLDER (folder_unix);
506 }
507
508 static gboolean
509 gtk_file_system_unix_create_folder (GtkFileSystem     *file_system,
510                                     const GtkFilePath *path,
511                                     GError           **error)
512 {
513   GtkFileSystemUnix *system_unix;
514   const char *filename;
515   gboolean result;
516   char *parent, *tmp;
517   int save_errno = errno;
518
519   system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
520
521   filename = gtk_file_path_get_string (path);
522   g_return_val_if_fail (filename != NULL, FALSE);
523   g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
524
525   tmp = remove_trailing_slash (filename);
526   errno = 0;
527   result = mkdir (tmp, 0777) == 0;
528   save_errno = errno;
529   g_free (tmp);
530
531   if (!result)
532     {
533       gchar *display_name = g_filename_display_name (filename);
534       g_set_error (error,
535                    GTK_FILE_SYSTEM_ERROR,
536                    GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
537                    _("Error creating directory '%s': %s"),
538                    display_name,
539                    g_strerror (save_errno));
540       g_free (display_name);
541       return FALSE;
542     }
543
544   if (filename_is_root (filename))
545     return TRUE; /* hmmm, but with no notification */
546
547   parent = get_parent_dir (filename);
548   if (parent)
549     {
550       GtkFileFolderUnix *folder_unix;
551
552       folder_unix = g_hash_table_lookup (system_unix->folder_hash, parent);
553       if (folder_unix)
554         {
555           GtkFileInfoType types;
556           GtkFilePath *parent_path;
557           GSList *paths;
558           GtkFileFolder *folder;
559
560           /* This is sort of a hack.  We re-get the folder, to ensure that the
561            * newly-created directory gets read into the folder's info hash table.
562            */
563
564           types = folder_unix->types;
565
566           parent_path = gtk_file_path_new_dup (parent);
567           folder = gtk_file_system_get_folder (file_system, parent_path, types, NULL);
568           gtk_file_path_free (parent_path);
569
570           if (folder)
571             {
572               paths = g_slist_append (NULL, (GtkFilePath *) path);
573               g_signal_emit_by_name (folder, "files-added", paths);
574               g_slist_free (paths);
575               g_object_unref (folder);
576             }
577         }
578
579       g_free (parent);
580     }
581
582   return TRUE;
583 }
584
585 static void
586 gtk_file_system_unix_volume_free (GtkFileSystem        *file_system,
587                                   GtkFileSystemVolume  *volume)
588 {
589   GtkFilePath *path;
590
591   path = (GtkFilePath *) volume;
592   gtk_file_path_free (path);
593 }
594
595 static GtkFilePath *
596 gtk_file_system_unix_volume_get_base_path (GtkFileSystem        *file_system,
597                                            GtkFileSystemVolume  *volume)
598 {
599   return gtk_file_path_new_dup ("/");
600 }
601
602 static gboolean
603 gtk_file_system_unix_volume_get_is_mounted (GtkFileSystem        *file_system,
604                                             GtkFileSystemVolume  *volume)
605 {
606   return TRUE;
607 }
608
609 static gboolean
610 gtk_file_system_unix_volume_mount (GtkFileSystem        *file_system,
611                                    GtkFileSystemVolume  *volume,
612                                    GError              **error)
613 {
614   g_set_error (error,
615                GTK_FILE_SYSTEM_ERROR,
616                GTK_FILE_SYSTEM_ERROR_FAILED,
617                _("This file system does not support mounting"));
618   return FALSE;
619 }
620
621 static gchar *
622 gtk_file_system_unix_volume_get_display_name (GtkFileSystem       *file_system,
623                                               GtkFileSystemVolume *volume)
624 {
625   return g_strdup (_("Filesystem")); /* Same as Nautilus */
626 }
627
628 static IconType
629 get_icon_type_from_stat (struct stat *statp)
630 {
631   if (S_ISBLK (statp->st_mode))
632     return ICON_BLOCK_DEVICE;
633   else if (S_ISLNK (statp->st_mode))
634     return ICON_BROKEN_SYMBOLIC_LINK; /* See get_icon_type */
635   else if (S_ISCHR (statp->st_mode))
636     return ICON_CHARACTER_DEVICE;
637   else if (S_ISDIR (statp->st_mode))
638     return ICON_DIRECTORY;
639 #ifdef S_ISFIFO
640   else if (S_ISFIFO (statp->st_mode))
641     return  ICON_FIFO;
642 #endif
643 #ifdef S_ISSOCK
644   else if (S_ISSOCK (statp->st_mode))
645     return ICON_SOCKET;
646 #endif
647   else
648     return ICON_REGULAR;
649 }
650
651 static IconType
652 get_icon_type (const char *filename,
653                GError    **error)
654 {
655   struct stat statbuf;
656
657   /* If stat fails, try to fall back to lstat to catch broken links
658    */
659   if (stat (filename, &statbuf) != 0)
660     {
661       if (errno != ENOENT || lstat (filename, &statbuf) != 0)
662         {
663           int save_errno = errno;
664           gchar *display_name = g_filename_display_name (filename);
665           g_set_error (error,
666                        GTK_FILE_SYSTEM_ERROR,
667                        GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
668                        _("Error getting information for '%s': %s"),
669                        display_name,
670                        g_strerror (save_errno));
671           g_free (display_name);
672
673           return ICON_NONE;
674         }
675     }
676
677   return get_icon_type_from_stat (&statbuf);
678 }
679
680 typedef struct
681 {
682   gint size;
683   GdkPixbuf *pixbuf;
684 } IconCacheElement;
685
686 static void
687 icon_cache_element_free (IconCacheElement *element)
688 {
689   if (element->pixbuf)
690     g_object_unref (element->pixbuf);
691   g_free (element);
692 }
693
694 static void
695 icon_theme_changed (GtkIconTheme *icon_theme)
696 {
697   GHashTable *cache;
698
699   /* Difference from the initial creation is that we don't
700    * reconnect the signal
701    */
702   cache = g_hash_table_new_full (g_str_hash, g_str_equal,
703                                  (GDestroyNotify)g_free,
704                                  (GDestroyNotify)icon_cache_element_free);
705   g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
706                           cache, (GDestroyNotify)g_hash_table_destroy);
707 }
708
709 static GdkPixbuf *
710 get_cached_icon (GtkWidget   *widget,
711                  const gchar *name,
712                  gint         pixel_size)
713 {
714   GtkIconTheme *icon_theme = gtk_icon_theme_get_for_screen (gtk_widget_get_screen (widget));
715   GHashTable *cache = g_object_get_data (G_OBJECT (icon_theme), "gtk-file-icon-cache");
716   IconCacheElement *element;
717
718   if (!cache)
719     {
720       cache = g_hash_table_new_full (g_str_hash, g_str_equal,
721                                      (GDestroyNotify)g_free,
722                                      (GDestroyNotify)icon_cache_element_free);
723
724       g_object_set_data_full (G_OBJECT (icon_theme), "gtk-file-icon-cache",
725                               cache, (GDestroyNotify)g_hash_table_destroy);
726       g_signal_connect (icon_theme, "changed",
727                         G_CALLBACK (icon_theme_changed), NULL);
728     }
729
730   element = g_hash_table_lookup (cache, name);
731   if (!element)
732     {
733       element = g_new0 (IconCacheElement, 1);
734       g_hash_table_insert (cache, g_strdup (name), element);
735     }
736
737   if (element->size != pixel_size)
738     {
739       if (element->pixbuf)
740         g_object_unref (element->pixbuf);
741       element->size = pixel_size;
742       element->pixbuf = gtk_icon_theme_load_icon (icon_theme, name,
743                                                   pixel_size, 0, NULL);
744     }
745
746   return element->pixbuf ? g_object_ref (element->pixbuf) : NULL;
747 }
748
749 /* Renders a fallback icon from the stock system */
750 static GdkPixbuf *
751 get_fallback_icon (GtkWidget *widget,
752                    IconType   icon_type,
753                    GError   **error)
754 {
755   const char *stock_name;
756   GdkPixbuf *pixbuf;
757
758   switch (icon_type)
759     {
760     case ICON_BLOCK_DEVICE:
761       stock_name = GTK_STOCK_HARDDISK;
762       break;
763
764     case ICON_DIRECTORY:
765       stock_name = GTK_STOCK_DIRECTORY;
766       break;
767
768     case ICON_EXECUTABLE:
769       stock_name = GTK_STOCK_EXECUTE;
770       break;
771
772     default:
773       stock_name = GTK_STOCK_FILE;
774       break;
775     }
776
777   pixbuf = gtk_widget_render_icon (widget, stock_name, GTK_ICON_SIZE_SMALL_TOOLBAR, NULL);
778   if (!pixbuf)
779     g_set_error (error,
780                  GTK_FILE_SYSTEM_ERROR,
781                  GTK_FILE_SYSTEM_ERROR_FAILED,
782                  _("Could not get a stock icon for %s"),
783                  stock_name);
784
785   return pixbuf;
786 }
787
788 static GdkPixbuf *
789 gtk_file_system_unix_volume_render_icon (GtkFileSystem        *file_system,
790                                          GtkFileSystemVolume  *volume,
791                                          GtkWidget            *widget,
792                                          gint                  pixel_size,
793                                          GError              **error)
794 {
795   GdkPixbuf *pixbuf;
796
797   pixbuf = get_cached_icon (widget, "gnome-fs-blockdev", pixel_size);
798   if (pixbuf)
799     return pixbuf;
800
801   pixbuf = get_fallback_icon (widget, ICON_BLOCK_DEVICE, error);
802   g_assert (pixbuf != NULL);
803
804   return pixbuf;
805 }
806
807 static char *
808 get_parent_dir (const char *filename)
809 {
810   int len;
811
812   len = strlen (filename);
813
814   /* Ignore trailing slashes */
815   if (len > 1 && filename[len - 1] == '/')
816     {
817       char *tmp, *parent;
818
819       tmp = g_strndup (filename, len - 1);
820
821       parent = g_path_get_dirname (tmp);
822       g_free (tmp);
823
824       return parent;
825     }
826   else
827     return g_path_get_dirname (filename);
828 }
829
830 static gboolean
831 gtk_file_system_unix_get_parent (GtkFileSystem     *file_system,
832                                  const GtkFilePath *path,
833                                  GtkFilePath      **parent,
834                                  GError           **error)
835 {
836   const char *filename;
837
838   filename = gtk_file_path_get_string (path);
839   g_return_val_if_fail (filename != NULL, FALSE);
840   g_return_val_if_fail (g_path_is_absolute (filename), FALSE);
841
842   if (filename_is_root (filename))
843     {
844       *parent = NULL;
845     }
846   else
847     {
848       gchar *parent_filename = get_parent_dir (filename);
849       *parent = filename_to_path (parent_filename);
850       g_free (parent_filename);
851     }
852
853   return TRUE;
854 }
855
856 static GtkFilePath *
857 gtk_file_system_unix_make_path (GtkFileSystem    *file_system,
858                                const GtkFilePath *base_path,
859                                const gchar       *display_name,
860                                GError           **error)
861 {
862   const char *base_filename;
863   gchar *filename;
864   gchar *full_filename;
865   GError *tmp_error = NULL;
866   GtkFilePath *result;
867
868   base_filename = gtk_file_path_get_string (base_path);
869   g_return_val_if_fail (base_filename != NULL, NULL);
870   g_return_val_if_fail (g_path_is_absolute (base_filename), NULL);
871
872   if (strchr (display_name, G_DIR_SEPARATOR))
873     {
874       g_set_error (error,
875                    GTK_FILE_SYSTEM_ERROR,
876                    GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
877                    _("The name \"%s\" is not valid because it contains the character \"%s\". "
878                      "Please use a different name."),
879                    display_name,
880                    G_DIR_SEPARATOR_S);
881       return NULL;
882     }
883
884   filename = g_filename_from_utf8 (display_name, -1, NULL, NULL, &tmp_error);
885   if (!filename)
886     {
887       g_set_error (error,
888                    GTK_FILE_SYSTEM_ERROR,
889                    GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
890                    "%s",
891                    tmp_error->message);
892
893       g_error_free (tmp_error);
894
895       return NULL;
896     }
897
898   full_filename = g_build_filename (base_filename, filename, NULL);
899   result = filename_to_path (full_filename);
900   g_free (filename);
901   g_free (full_filename);
902
903   return result;
904 }
905
906 /* If this was a publically exported function, it should return
907  * a dup'ed result, but we make it modify-in-place for efficiency
908  * here, and because it works for us.
909  */
910 static void
911 canonicalize_filename (gchar *filename)
912 {
913   gchar *p, *q;
914   gboolean last_was_slash = FALSE;
915
916   p = filename;
917   q = filename;
918
919   while (*p)
920     {
921       if (*p == G_DIR_SEPARATOR)
922         {
923           if (!last_was_slash)
924             *q++ = G_DIR_SEPARATOR;
925
926           last_was_slash = TRUE;
927         }
928       else
929         {
930           if (last_was_slash && *p == '.')
931             {
932               if (*(p + 1) == G_DIR_SEPARATOR ||
933                   *(p + 1) == '\0')
934                 {
935                   if (*(p + 1) == '\0')
936                     break;
937
938                   p += 1;
939                 }
940               else if (*(p + 1) == '.' &&
941                        (*(p + 2) == G_DIR_SEPARATOR ||
942                         *(p + 2) == '\0'))
943                 {
944                   if (q > filename + 1)
945                     {
946                       q--;
947                       while (q > filename + 1 &&
948                              *(q - 1) != G_DIR_SEPARATOR)
949                         q--;
950                     }
951
952                   if (*(p + 2) == '\0')
953                     break;
954
955                   p += 2;
956                 }
957               else
958                 {
959                   *q++ = *p;
960                   last_was_slash = FALSE;
961                 }
962             }
963           else
964             {
965               *q++ = *p;
966               last_was_slash = FALSE;
967             }
968         }
969
970       p++;
971     }
972
973   if (q > filename + 1 && *(q - 1) == G_DIR_SEPARATOR)
974     q--;
975
976   *q = '\0';
977 }
978
979 /* Takes a user-typed filename and expands a tilde at the beginning of the string */
980 static char *
981 expand_tilde (const char *filename)
982 {
983   const char *notilde;
984   const char *slash;
985   const char *home;
986
987   if (filename[0] != '~')
988     return g_strdup (filename);
989
990   notilde = filename + 1;
991
992   slash = strchr (notilde, G_DIR_SEPARATOR);
993   if (!slash)
994     return NULL;
995
996   if (slash == notilde)
997     {
998       home = g_get_home_dir ();
999
1000       if (!home)
1001         return g_strdup (filename);
1002     }
1003   else
1004     {
1005       char *username;
1006       struct passwd *passwd;
1007
1008       username = g_strndup (notilde, slash - notilde);
1009       passwd = getpwnam (username);
1010       g_free (username);
1011
1012       if (!passwd)
1013         return g_strdup (filename);
1014
1015       home = passwd->pw_dir;
1016     }
1017
1018   return g_build_filename (home, G_DIR_SEPARATOR_S, slash + 1, NULL);
1019 }
1020
1021 static gboolean
1022 gtk_file_system_unix_parse (GtkFileSystem     *file_system,
1023                             const GtkFilePath *base_path,
1024                             const gchar       *str,
1025                             GtkFilePath      **folder,
1026                             gchar            **file_part,
1027                             GError           **error)
1028 {
1029   const char *base_filename;
1030   gchar *filename;
1031   gchar *last_slash;
1032   gboolean result = FALSE;
1033
1034   base_filename = gtk_file_path_get_string (base_path);
1035   g_return_val_if_fail (base_filename != NULL, FALSE);
1036   g_return_val_if_fail (g_path_is_absolute (base_filename), FALSE);
1037
1038   filename = expand_tilde (str);
1039   if (!filename)
1040     {
1041       g_set_error (error,
1042                    GTK_FILE_SYSTEM_ERROR,
1043                    GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1044                    "%s", ""); /* nothing for now, as we are string-frozen */
1045       return FALSE;
1046     }
1047
1048   last_slash = strrchr (filename, G_DIR_SEPARATOR);
1049   if (!last_slash)
1050     {
1051       *folder = gtk_file_path_copy (base_path);
1052       *file_part = g_strdup (filename);
1053       result = TRUE;
1054     }
1055   else
1056     {
1057       gchar *folder_part;
1058       gchar *folder_path;
1059       GError *tmp_error = NULL;
1060
1061       if (last_slash == filename)
1062         folder_part = g_strdup ("/");
1063       else
1064         folder_part = g_filename_from_utf8 (filename, last_slash - filename,
1065                                             NULL, NULL, &tmp_error);
1066
1067       if (!folder_part)
1068         {
1069           g_set_error (error,
1070                        GTK_FILE_SYSTEM_ERROR,
1071                        GTK_FILE_SYSTEM_ERROR_BAD_FILENAME,
1072                        "%s",
1073                        tmp_error->message);
1074           g_error_free (tmp_error);
1075         }
1076       else
1077         {
1078           if (folder_part[0] == G_DIR_SEPARATOR)
1079             folder_path = folder_part;
1080           else
1081             {
1082               folder_path = g_build_filename (base_filename, folder_part, NULL);
1083               g_free (folder_part);
1084             }
1085
1086           canonicalize_filename (folder_path);
1087
1088           *folder = filename_to_path (folder_path);
1089           *file_part = g_strdup (last_slash + 1);
1090
1091           g_free (folder_path);
1092
1093           result = TRUE;
1094         }
1095     }
1096
1097   g_free (filename);
1098
1099   return result;
1100 }
1101
1102 static gchar *
1103 gtk_file_system_unix_path_to_uri (GtkFileSystem     *file_system,
1104                                   const GtkFilePath *path)
1105 {
1106   return g_filename_to_uri (gtk_file_path_get_string (path), NULL, NULL);
1107 }
1108
1109 static gchar *
1110 gtk_file_system_unix_path_to_filename (GtkFileSystem     *file_system,
1111                                        const GtkFilePath *path)
1112 {
1113   return g_strdup (gtk_file_path_get_string (path));
1114 }
1115
1116 static GtkFilePath *
1117 gtk_file_system_unix_uri_to_path (GtkFileSystem     *file_system,
1118                                   const gchar       *uri)
1119 {
1120   GtkFilePath *path;
1121   gchar *filename = g_filename_from_uri (uri, NULL, NULL);
1122
1123   if (filename)
1124     {
1125       path = filename_to_path (filename);
1126       g_free (filename);
1127     }
1128   else
1129     path = NULL;
1130
1131   return path;
1132 }
1133
1134 static GtkFilePath *
1135 gtk_file_system_unix_filename_to_path (GtkFileSystem *file_system,
1136                                        const gchar   *filename)
1137 {
1138   return filename_to_path (filename);
1139 }
1140
1141 /* Returns the name of the icon to be used for a path which is known to be a
1142  * directory.  This can vary for Home, Desktop, etc.
1143  */
1144 static const char *
1145 get_icon_name_for_directory (const char *path)
1146 {
1147   static char *desktop_path = NULL;
1148
1149   if (!g_get_home_dir ())
1150     return "gnome-fs-directory";
1151
1152   if (!desktop_path)
1153       desktop_path = g_build_filename (g_get_home_dir (), "Desktop", NULL);
1154
1155   if (strcmp (g_get_home_dir (), path) == 0)
1156     return "gnome-fs-home";
1157   else if (strcmp (desktop_path, path) == 0)
1158     return "gnome-fs-desktop";
1159   else
1160     return "gnome-fs-directory";
1161 }
1162
1163 /* Computes our internal icon type based on a path name; also returns the MIME
1164  * type in case we come up with ICON_REGULAR.
1165  */
1166 static IconType
1167 get_icon_type_from_path (GtkFileSystemUnix *system_unix,
1168                          const GtkFilePath *path,
1169                          const char       **mime_type)
1170 {
1171   const char *filename;
1172   char *dirname;
1173   GtkFileFolderUnix *folder_unix;
1174   IconType icon_type;
1175
1176   filename = gtk_file_path_get_string (path);
1177   dirname = g_path_get_dirname (filename);
1178   folder_unix = g_hash_table_lookup (system_unix->folder_hash, dirname);
1179   g_free (dirname);
1180
1181   *mime_type = NULL;
1182
1183   if (folder_unix && folder_unix->have_stat)
1184     {
1185       char *basename;
1186       struct stat_info_entry *entry;
1187
1188       g_assert (folder_unix->stat_info != NULL);
1189
1190       basename = g_path_get_basename (filename);
1191       entry = g_hash_table_lookup (folder_unix->stat_info, basename);
1192       g_free (basename);
1193       if (entry)
1194         {
1195           if (entry->icon_type == ICON_UNDECIDED)
1196             {
1197               entry->icon_type = get_icon_type_from_stat (&entry->statbuf);
1198               g_assert (entry->icon_type != ICON_UNDECIDED);
1199             }
1200           icon_type = entry->icon_type;
1201           if (icon_type == ICON_REGULAR)
1202             {
1203               fill_in_mime_type (folder_unix);
1204               *mime_type = entry->mime_type;
1205             }
1206
1207           return icon_type;
1208         }
1209     }
1210
1211   icon_type = get_icon_type (filename, NULL);
1212   if (icon_type == ICON_REGULAR)
1213     *mime_type = xdg_mime_get_mime_type_for_file (filename);
1214
1215   return icon_type;
1216 }
1217
1218 /* Renders an icon for a non-ICON_REGULAR file */
1219 static GdkPixbuf *
1220 get_special_icon (IconType           icon_type,
1221                   const GtkFilePath *path,
1222                   GtkWidget         *widget,
1223                   gint               pixel_size)
1224 {
1225   const char *name;
1226
1227   g_assert (icon_type != ICON_REGULAR);
1228
1229   switch (icon_type)
1230     {
1231     case ICON_BLOCK_DEVICE:
1232       name = "gnome-fs-blockdev";
1233       break;
1234     case ICON_BROKEN_SYMBOLIC_LINK:
1235       name = "gnome-fs-symlink";
1236       break;
1237     case ICON_CHARACTER_DEVICE:
1238       name = "gnome-fs-chardev";
1239       break;
1240     case ICON_DIRECTORY: {
1241       const char *filename;
1242
1243       filename = gtk_file_path_get_string (path);
1244       name = get_icon_name_for_directory (filename);
1245       break;
1246       }
1247     case ICON_EXECUTABLE:
1248       name ="gnome-fs-executable";
1249       break;
1250     case ICON_FIFO:
1251       name = "gnome-fs-fifo";
1252       break;
1253     case ICON_SOCKET:
1254       name = "gnome-fs-socket";
1255       break;
1256     default:
1257       g_assert_not_reached ();
1258       return NULL;
1259     }
1260
1261   return get_cached_icon (widget, name, pixel_size);
1262 }
1263
1264 static GdkPixbuf *
1265 get_icon_for_mime_type (GtkWidget  *widget,
1266                         const char *mime_type,
1267                         gint        pixel_size)
1268 {
1269   const char *separator;
1270   GString *icon_name;
1271   GdkPixbuf *pixbuf;
1272
1273   separator = strchr (mime_type, '/');
1274   if (!separator)
1275     return NULL; /* maybe we should return a GError with "invalid MIME-type" */
1276
1277   icon_name = g_string_new ("gnome-mime-");
1278   g_string_append_len (icon_name, mime_type, separator - mime_type);
1279   g_string_append_c (icon_name, '-');
1280   g_string_append (icon_name, separator + 1);
1281   pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1282   g_string_free (icon_name, TRUE);
1283   if (pixbuf)
1284     return pixbuf;
1285
1286   icon_name = g_string_new ("gnome-mime-");
1287   g_string_append_len (icon_name, mime_type, separator - mime_type);
1288   pixbuf = get_cached_icon (widget, icon_name->str, pixel_size);
1289   g_string_free (icon_name, TRUE);
1290
1291   return pixbuf;
1292 }
1293
1294 static GdkPixbuf *
1295 gtk_file_system_unix_render_icon (GtkFileSystem     *file_system,
1296                                   const GtkFilePath *path,
1297                                   GtkWidget         *widget,
1298                                   gint               pixel_size,
1299                                   GError           **error)
1300 {
1301   GtkFileSystemUnix *system_unix;
1302   IconType icon_type;
1303   const char *mime_type;
1304   GdkPixbuf *pixbuf;
1305
1306   system_unix = GTK_FILE_SYSTEM_UNIX (file_system);
1307
1308   icon_type = get_icon_type_from_path (system_unix, path, &mime_type);
1309
1310   switch (icon_type) {
1311   case ICON_NONE:
1312     goto fallback;
1313
1314   case ICON_REGULAR:
1315     pixbuf = get_icon_for_mime_type (widget, mime_type, pixel_size);
1316     break;
1317
1318   default:
1319     pixbuf = get_special_icon (icon_type, path, widget, pixel_size);
1320   }
1321
1322   if (pixbuf)
1323     goto out;
1324
1325  fallback:
1326
1327   pixbuf = get_cached_icon (widget, "gnome-fs-regular", pixel_size);
1328   if (pixbuf)
1329     goto out;
1330
1331   pixbuf = get_fallback_icon (widget, icon_type, error);
1332
1333  out:
1334
1335   return pixbuf;
1336 }
1337
1338 static void
1339 string_list_free (GSList *list)
1340 {
1341   GSList *l;
1342
1343   for (l = list; l; l = l->next)
1344     g_free (l->data);
1345
1346   g_slist_free (list);
1347 }
1348
1349 /* Returns whether a URI is a local file:// */
1350 static gboolean
1351 is_local_uri (const char *uri)
1352 {
1353   char *filename;
1354   char *hostname;
1355   gboolean result;
1356
1357   /* This is rather crude, but hey */
1358   filename = g_filename_from_uri (uri, &hostname, NULL);
1359
1360   result = (filename && !hostname);
1361
1362   g_free (filename);
1363   g_free (hostname);
1364
1365   return result;
1366 }
1367
1368 static char *
1369 bookmark_get_filename (void)
1370 {
1371   char *filename;
1372
1373   filename = g_build_filename (g_get_home_dir (), BOOKMARKS_FILENAME, NULL);
1374
1375   g_assert (filename != NULL);
1376
1377   return filename;
1378 }
1379
1380 static gboolean
1381 string_list_read (const gchar  *filename, 
1382                   GSList      **bookmarks, 
1383                   GError      **error)
1384 {
1385   gchar *contents;
1386   gboolean result = FALSE;
1387
1388   *bookmarks = NULL;
1389
1390   if (g_file_get_contents (filename, &contents, NULL, error))
1391     {
1392       gchar **lines = g_strsplit (contents, "\n", -1);
1393       int i;
1394       GHashTable *table;
1395
1396       table = g_hash_table_new (g_str_hash, g_str_equal);
1397
1398       for (i = 0; lines[i]; i++)
1399         {
1400           if (lines[i][0] && !g_hash_table_lookup (table, lines[i]))
1401             {
1402               *bookmarks = g_slist_prepend (*bookmarks, g_strdup (lines[i]));
1403               g_hash_table_insert (table, lines[i], lines[i]);
1404             }
1405         }
1406
1407       g_free (contents);
1408       g_hash_table_destroy (table);
1409       g_strfreev (lines);
1410
1411       *bookmarks = g_slist_reverse (*bookmarks);
1412       result = TRUE;
1413     }
1414
1415   return result;
1416 }
1417
1418 static gboolean
1419 string_list_write (gchar   *filename,
1420                    GSList  *bookmarks, 
1421                    GError **error)
1422 {
1423   char *tmp_filename;
1424   gboolean result = TRUE;
1425   FILE *file;
1426   int fd;
1427   int saved_errno;
1428
1429   /* First, write a temporary file */  
1430   tmp_filename = g_strdup_printf ("%s-XXXXXX", filename);
1431
1432   fd = g_mkstemp (tmp_filename);
1433   if (fd == -1)
1434     {
1435       saved_errno = errno;
1436       goto io_error;
1437     }
1438
1439   if ((file = fdopen (fd, "w")) != NULL)
1440     {
1441       GSList *l;
1442
1443       for (l = bookmarks; l; l = l->next)
1444         if (fputs (l->data, file) == EOF
1445             || fputs ("\n", file) == EOF)
1446           {
1447             saved_errno = errno;
1448             goto io_error;
1449           }
1450
1451       if (fclose (file) == EOF)
1452         {
1453           saved_errno = errno;
1454           goto io_error;
1455         }
1456
1457       if (rename (tmp_filename, filename) == -1)
1458         {
1459           saved_errno = errno;
1460           goto io_error;
1461         }
1462
1463       result = TRUE;
1464       goto out;
1465     }
1466   else
1467     {
1468       saved_errno = errno;
1469
1470       /* fdopen() failed, so we can't do much error checking here anyway */
1471       close (fd);
1472     }
1473
1474  io_error:
1475
1476   g_set_error (error,
1477                GTK_FILE_SYSTEM_ERROR,
1478                GTK_FILE_SYSTEM_ERROR_FAILED,
1479                _("Writing %s failed: %s"),
1480                filename,
1481                g_strerror (saved_errno));
1482   result = FALSE;
1483
1484   if (fd != -1)
1485     unlink (tmp_filename); /* again, not much error checking we can do here */
1486
1487  out:
1488
1489   g_free (tmp_filename);
1490
1491   return result;
1492 }
1493
1494 static gboolean
1495 bookmark_list_read (GSList **bookmarks, 
1496                     GError **error)
1497 {
1498   gchar *filename;
1499   gboolean result;
1500
1501   filename = bookmark_get_filename ();
1502   result = string_list_read (filename, bookmarks, error);
1503   g_free (filename);
1504
1505   return result;
1506 }
1507
1508 static gboolean
1509 bookmark_list_write (GSList  *bookmarks, 
1510                      GError **error)
1511 {
1512   gchar *filename;
1513   gboolean result;
1514
1515   filename = bookmark_get_filename ();
1516   result = string_list_write (filename, bookmarks, error);
1517   g_free (filename);
1518   
1519   return result;
1520 }
1521
1522 static gboolean
1523 gtk_file_system_unix_insert_bookmark (GtkFileSystem     *file_system,
1524                                       const GtkFilePath *path,
1525                                       gint               position,
1526                                       GError           **error)
1527 {
1528   GSList *bookmarks;
1529   int num_bookmarks;
1530   GSList *l;
1531   char *uri;
1532   gboolean result;
1533   GError *err;
1534
1535   err = NULL;
1536   if (!bookmark_list_read (&bookmarks, &err) && err->code != G_FILE_ERROR_NOENT)
1537     {
1538       g_propagate_error (error, err);
1539       return FALSE;
1540     }
1541
1542   num_bookmarks = g_slist_length (bookmarks);
1543   g_return_val_if_fail (position >= -1 && position <= num_bookmarks, FALSE);
1544
1545   result = FALSE;
1546
1547   uri = gtk_file_system_unix_path_to_uri (file_system, path);
1548
1549   for (l = bookmarks; l; l = l->next)
1550     {
1551       char *bookmark, *space;
1552
1553       bookmark = l->data;
1554       
1555       space = strchr (bookmark, ' ');
1556       if (space)
1557         *space = '\0';
1558       if (strcmp (bookmark, uri) != 0)
1559         {
1560           if (space)
1561             *space = ' ';
1562         }
1563       else
1564         {
1565           g_set_error (error,
1566                        GTK_FILE_SYSTEM_ERROR,
1567                        GTK_FILE_SYSTEM_ERROR_ALREADY_EXISTS,
1568                        _("'%s' already exists in the bookmarks list"),
1569                        uri);
1570           goto out;
1571         }
1572     }
1573
1574   bookmarks = g_slist_insert (bookmarks, g_strdup (uri), position);
1575   if (bookmark_list_write (bookmarks, error))
1576     {
1577       result = TRUE;
1578       g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1579     }
1580
1581  out:
1582
1583   g_free (uri);
1584   string_list_free (bookmarks);
1585
1586   return result;
1587 }
1588
1589 static gboolean
1590 gtk_file_system_unix_remove_bookmark (GtkFileSystem     *file_system,
1591                                       const GtkFilePath *path,
1592                                       GError           **error)
1593 {
1594   GSList *bookmarks;
1595   char *uri;
1596   GSList *l;
1597   gboolean result;
1598
1599   if (!bookmark_list_read (&bookmarks, error))
1600     return FALSE;
1601
1602   result = FALSE;
1603
1604   uri = gtk_file_system_path_to_uri (file_system, path);
1605
1606   for (l = bookmarks; l; l = l->next)
1607     {
1608       char *bookmark, *space;
1609
1610       bookmark = (char *)l->data;
1611       space = strchr (bookmark, ' ');
1612       if (space)
1613         *space = '\0';
1614
1615       if (strcmp (bookmark, uri) != 0)
1616         {
1617           if (space)
1618             *space = ' ';
1619         }
1620       else
1621         {
1622           g_free (l->data);
1623           bookmarks = g_slist_remove_link (bookmarks, l);
1624           g_slist_free_1 (l);
1625
1626           if (bookmark_list_write (bookmarks, error))
1627             {
1628               result = TRUE;
1629
1630               g_signal_emit_by_name (file_system, "bookmarks-changed", 0);            
1631             }
1632
1633           goto out;
1634         }
1635     }
1636
1637   g_set_error (error,
1638                GTK_FILE_SYSTEM_ERROR,
1639                GTK_FILE_SYSTEM_ERROR_NONEXISTENT,
1640                _("'%s' does not exist in the bookmarks list"),
1641                uri);
1642
1643  out:
1644
1645   g_free (uri);
1646   string_list_free (bookmarks);
1647
1648   return result;
1649 }
1650
1651 static GSList *
1652 gtk_file_system_unix_list_bookmarks (GtkFileSystem *file_system)
1653 {
1654   GSList *bookmarks;
1655   GSList *result;
1656   GSList *l;
1657
1658   if (!bookmark_list_read (&bookmarks, NULL))
1659     return NULL;
1660
1661   result = NULL;
1662
1663   for (l = bookmarks; l; l = l->next)
1664     {
1665       char *bookmark, *space;
1666
1667       bookmark = (char *)l->data;
1668       space = strchr (bookmark, ' ');
1669       if (space)
1670         *space = '\0';
1671
1672       if (is_local_uri (bookmark))
1673         result = g_slist_prepend (result, gtk_file_system_unix_uri_to_path (file_system, bookmark));
1674     }
1675
1676   string_list_free (bookmarks);
1677
1678   result = g_slist_reverse (result);
1679   return result;
1680 }
1681
1682 static gchar *
1683 gtk_file_system_unix_get_bookmark_label (GtkFileSystem     *file_system,
1684                                          const GtkFilePath *path)
1685 {
1686   GSList *labels;
1687   gchar *label;
1688   GSList *l;
1689   char *bookmark, *space, *uri;
1690   
1691   labels = NULL;
1692   label = NULL;
1693
1694   uri = gtk_file_system_path_to_uri (file_system, path);
1695   bookmark_list_read (&labels, NULL);
1696
1697   for (l = labels; l && !label; l = l->next) 
1698     {
1699       bookmark = (char *)l->data;
1700       space = strchr (bookmark, ' ');
1701       if (!space)
1702         continue;
1703
1704       *space = '\0';
1705
1706       if (strcmp (uri, bookmark) == 0)
1707         label = g_strdup (space + 1);
1708     }
1709
1710   string_list_free (labels);
1711   g_free (uri);
1712
1713   return label;
1714 }
1715
1716 static void
1717 gtk_file_system_unix_set_bookmark_label (GtkFileSystem     *file_system,
1718                                          const GtkFilePath *path,
1719                                          const gchar       *label)
1720 {
1721   GSList *labels;
1722   GSList *l;
1723   gchar *bookmark, *space, *uri;
1724   gboolean found;
1725
1726   labels = NULL;
1727
1728   uri = gtk_file_system_path_to_uri (file_system, path);
1729   bookmark_list_read (&labels, NULL);
1730
1731   found = FALSE;
1732   for (l = labels; l && !found; l = l->next) 
1733     {
1734       bookmark = (gchar *)l->data;
1735       space = strchr (bookmark, ' ');
1736       if (space)
1737         *space = '\0';
1738
1739       if (strcmp (bookmark, uri) != 0)
1740         {
1741           if (space)
1742             *space = ' ';
1743         }
1744       else
1745         {
1746           g_free (bookmark);
1747           
1748           if (label && *label)
1749             l->data = g_strdup_printf ("%s %s", uri, label);
1750           else
1751             l->data = g_strdup (uri);
1752
1753           found = TRUE;
1754           break;
1755         }
1756     }
1757
1758   if (found)
1759     {
1760       if (bookmark_list_write (labels, NULL))
1761         g_signal_emit_by_name (file_system, "bookmarks-changed", 0);
1762     }
1763   
1764   string_list_free (labels);
1765   g_free (uri);
1766 }
1767
1768 /*
1769  * GtkFileFolderUnix
1770  */
1771 static GType
1772 gtk_file_folder_unix_get_type (void)
1773 {
1774   static GType file_folder_unix_type = 0;
1775
1776   if (!file_folder_unix_type)
1777     {
1778       static const GTypeInfo file_folder_unix_info =
1779       {
1780         sizeof (GtkFileFolderUnixClass),
1781         NULL,           /* base_init */
1782         NULL,           /* base_finalize */
1783         (GClassInitFunc) gtk_file_folder_unix_class_init,
1784         NULL,           /* class_finalize */
1785         NULL,           /* class_data */
1786         sizeof (GtkFileFolderUnix),
1787         0,              /* n_preallocs */
1788         (GInstanceInitFunc) gtk_file_folder_unix_init,
1789       };
1790
1791       static const GInterfaceInfo file_folder_info =
1792       {
1793         (GInterfaceInitFunc) gtk_file_folder_unix_iface_init, /* interface_init */
1794         NULL,                                                 /* interface_finalize */
1795         NULL                                                  /* interface_data */
1796       };
1797
1798       file_folder_unix_type = g_type_register_static (G_TYPE_OBJECT,
1799                                                       "GtkFileFolderUnix",
1800                                                       &file_folder_unix_info, 0);
1801       g_type_add_interface_static (file_folder_unix_type,
1802                                    GTK_TYPE_FILE_FOLDER,
1803                                    &file_folder_info);
1804     }
1805
1806   return file_folder_unix_type;
1807 }
1808
1809 static void
1810 gtk_file_folder_unix_class_init (GtkFileFolderUnixClass *class)
1811 {
1812   GObjectClass *gobject_class = G_OBJECT_CLASS (class);
1813
1814   folder_parent_class = g_type_class_peek_parent (class);
1815
1816   gobject_class->finalize = gtk_file_folder_unix_finalize;
1817 }
1818
1819 static void
1820 gtk_file_folder_unix_iface_init (GtkFileFolderIface *iface)
1821 {
1822   iface->get_info = gtk_file_folder_unix_get_info;
1823   iface->list_children = gtk_file_folder_unix_list_children;
1824   iface->is_finished_loading = gtk_file_folder_unix_is_finished_loading;
1825 }
1826
1827 static void
1828 gtk_file_folder_unix_init (GtkFileFolderUnix *impl)
1829 {
1830 }
1831
1832 static void
1833 gtk_file_folder_unix_finalize (GObject *object)
1834 {
1835   GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (object);
1836
1837   g_hash_table_remove (folder_unix->system_unix->folder_hash, folder_unix->filename);
1838
1839   if (folder_unix->stat_info)
1840     {
1841 #if 0
1842       g_print ("Releasing information for directory %s\n", folder_unix->filename);
1843 #endif
1844       g_hash_table_destroy (folder_unix->stat_info);
1845     }
1846
1847   g_free (folder_unix->filename);
1848
1849   folder_parent_class->finalize (object);
1850 }
1851
1852 /* Creates a GtkFileInfo for "/" by stat()ing it */
1853 static GtkFileInfo *
1854 file_info_for_root_with_error (const char  *root_name,
1855                                GError     **error)
1856 {
1857   struct stat statbuf;
1858   GtkFileInfo *info;
1859
1860   if (stat (root_name, &statbuf) != 0)
1861     {
1862       int saved_errno;
1863
1864       saved_errno = errno; 
1865       g_set_error (error,
1866                    GTK_FILE_SYSTEM_ERROR,
1867                    GTK_FILE_SYSTEM_ERROR_FAILED,
1868                    _("Error getting information for '/': %s"),
1869                    g_strerror (saved_errno));
1870
1871       return NULL;
1872     }
1873
1874   info = gtk_file_info_new ();
1875   gtk_file_info_set_display_name (info, "/");
1876   gtk_file_info_set_is_folder (info, TRUE);
1877   gtk_file_info_set_is_hidden (info, FALSE);
1878   gtk_file_info_set_mime_type (info, "x-directory/normal");
1879   gtk_file_info_set_modification_time (info, statbuf.st_mtime);
1880   gtk_file_info_set_size (info, statbuf.st_size);
1881
1882   return info;
1883 }
1884
1885 static gboolean
1886 stat_with_error (const char   *filename,
1887                  struct stat  *statbuf,
1888                  GError      **error)
1889 {
1890   if (stat (filename, statbuf) == -1 &&
1891       (errno != ENOENT || lstat (filename, statbuf) == -1))
1892     {
1893       int saved_errno;
1894       int code;
1895       char *display_name;
1896
1897       saved_errno = errno;
1898
1899       if (saved_errno == ENOENT)
1900         code = GTK_FILE_SYSTEM_ERROR_NONEXISTENT;
1901       else
1902         code = GTK_FILE_SYSTEM_ERROR_FAILED;
1903
1904       display_name = g_filename_display_name (filename);
1905       g_set_error (error,
1906                    GTK_FILE_SYSTEM_ERROR,
1907                    code,
1908                    _("Error getting information for '%s': %s"),
1909                    display_name,
1910                    g_strerror (saved_errno));
1911
1912       g_free (display_name);
1913       return FALSE;
1914     }
1915
1916   return TRUE;
1917 }
1918
1919 /* Creates a new GtkFileInfo from the specified data */
1920 static GtkFileInfo *
1921 create_file_info (const char     *filename,
1922                   const char     *basename,
1923                   GtkFileInfoType types,
1924                   struct stat    *statbuf,
1925                   const char     *mime_type)
1926 {
1927   GtkFileInfo *info;
1928
1929   info = gtk_file_info_new ();
1930   
1931   if (types & GTK_FILE_INFO_DISPLAY_NAME)
1932     {
1933       gchar *display_name = g_filename_display_basename (filename);
1934       gtk_file_info_set_display_name (info, display_name);
1935       g_free (display_name);
1936     }
1937
1938   if (types & GTK_FILE_INFO_IS_HIDDEN)
1939     gtk_file_info_set_is_hidden (info, basename[0] == '.');
1940
1941   if (types & GTK_FILE_INFO_IS_FOLDER)
1942     gtk_file_info_set_is_folder (info, S_ISDIR (statbuf->st_mode));
1943
1944   if (types & GTK_FILE_INFO_MIME_TYPE)
1945     gtk_file_info_set_mime_type (info, mime_type);
1946
1947   if (types & GTK_FILE_INFO_MODIFICATION_TIME)
1948     gtk_file_info_set_modification_time (info, statbuf->st_mtime);
1949
1950   if (types & GTK_FILE_INFO_SIZE)
1951     gtk_file_info_set_size (info, (gint64) statbuf->st_size);
1952
1953   return info;
1954 }
1955
1956 static struct stat_info_entry *
1957 create_stat_info_entry_and_emit_add (GtkFileFolderUnix *folder_unix,
1958                                      const char        *filename,
1959                                      const char        *basename,
1960                                      struct stat       *statbuf)
1961 {
1962   GSList *paths;
1963   GtkFilePath *path;
1964   struct stat_info_entry *entry;
1965
1966   entry = g_new0 (struct stat_info_entry, 1);
1967
1968   if ((folder_unix->types & STAT_NEEDED_MASK) != 0)
1969     entry->statbuf = *statbuf;
1970
1971   if ((folder_unix->types & GTK_FILE_INFO_MIME_TYPE) != 0)
1972     entry->mime_type = g_strdup (xdg_mime_get_mime_type_for_file (filename));
1973
1974   g_hash_table_insert (folder_unix->stat_info,
1975                        g_strdup (basename),
1976                        entry);
1977
1978   path = gtk_file_path_new_dup (filename);
1979   paths = g_slist_append (NULL, path);
1980   g_signal_emit_by_name (folder_unix, "files-added", paths);
1981   gtk_file_path_free (path);
1982   g_slist_free (paths);
1983
1984   return entry;
1985 }
1986
1987 static GtkFileInfo *
1988 gtk_file_folder_unix_get_info (GtkFileFolder      *folder,
1989                                const GtkFilePath  *path,
1990                                GError            **error)
1991 {
1992   GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
1993   GtkFileInfo *info;
1994   gchar *dirname, *basename;
1995   const char *filename;
1996   GtkFileInfoType types;
1997   struct stat statbuf;
1998   const char *mime_type;
1999
2000   /* Get_info for "/" */
2001   if (!path)
2002     {
2003       g_return_val_if_fail (filename_is_root (folder_unix->filename), NULL);
2004       return file_info_for_root_with_error (folder_unix->filename, error);
2005     }
2006
2007   /* Get_info for normal files */
2008
2009   filename = gtk_file_path_get_string (path);
2010   g_return_val_if_fail (filename != NULL, NULL);
2011   g_return_val_if_fail (g_path_is_absolute (filename), NULL);
2012
2013   dirname = get_parent_dir (filename);
2014   g_return_val_if_fail (strcmp (dirname, folder_unix->filename) == 0, NULL);
2015   g_free (dirname);
2016
2017   basename = g_path_get_basename (filename);
2018   types = folder_unix->types;
2019
2020   if (folder_unix->have_stat)
2021     {
2022       struct stat_info_entry *entry;
2023
2024       g_assert (folder_unix->stat_info != NULL);
2025       entry = g_hash_table_lookup (folder_unix->stat_info, basename);
2026
2027       if (!entry)
2028         {
2029           if (!stat_with_error (filename, &statbuf, error))
2030             {
2031               g_free (basename);
2032               return NULL;
2033             }
2034
2035           entry = create_stat_info_entry_and_emit_add (folder_unix, filename, basename, &statbuf);
2036         }
2037
2038       info = create_file_info (filename, basename, types, &entry->statbuf, entry->mime_type);
2039       g_free (basename);
2040       return info;
2041     }
2042   else
2043     {
2044       if (!stat_with_error (filename, &statbuf, error))
2045         {
2046           g_free (basename);
2047           return NULL;
2048         }
2049
2050       if ((types & GTK_FILE_INFO_MIME_TYPE) != 0)
2051         mime_type = xdg_mime_get_mime_type_for_file (filename);
2052       else
2053         mime_type = NULL;
2054
2055       info = create_file_info (filename, basename, types, &statbuf, mime_type);
2056       g_free (basename);
2057       return info;
2058     }
2059 }
2060
2061
2062 static void
2063 cb_list_children (gpointer key, gpointer value, gpointer user_data)
2064 {
2065   GSList **children = user_data;
2066   *children = g_slist_prepend (*children, key);
2067 }
2068
2069 static gboolean
2070 gtk_file_folder_unix_list_children (GtkFileFolder  *folder,
2071                                     GSList        **children,
2072                                     GError        **error)
2073 {
2074   GtkFileFolderUnix *folder_unix = GTK_FILE_FOLDER_UNIX (folder);
2075   GSList *l;
2076
2077   if (!fill_in_names (folder_unix, error))
2078     return FALSE;
2079
2080   *children = NULL;
2081
2082   /* Get the list of basenames.  */
2083   g_hash_table_foreach (folder_unix->stat_info, cb_list_children, children);
2084
2085   /* Turn basenames into GFilePaths.  */
2086   for (l = *children; l; l = l->next)
2087     {
2088       const char *basename = l->data;
2089       char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2090       l->data = filename_to_path (fullname);
2091       g_free (fullname);
2092     }
2093
2094   return TRUE;
2095 }
2096
2097 static gboolean
2098 gtk_file_folder_unix_is_finished_loading (GtkFileFolder *folder)
2099 {
2100   /* Since we don't do asynchronous loads, we are always finished loading */
2101   return TRUE;
2102 }
2103
2104 static void
2105 free_stat_info_entry (struct stat_info_entry *entry)
2106 {
2107   g_free (entry->mime_type);
2108   g_free (entry);
2109 }
2110
2111 static gboolean
2112 fill_in_names (GtkFileFolderUnix *folder_unix, GError **error)
2113 {
2114   GDir *dir;
2115
2116   if (folder_unix->stat_info)
2117     return TRUE;
2118
2119   dir = g_dir_open (folder_unix->filename, 0, error);
2120   if (!dir)
2121     return FALSE;
2122
2123   folder_unix->stat_info = g_hash_table_new_full (g_str_hash, g_str_equal,
2124                                                   (GDestroyNotify) g_free,
2125                                                   (GDestroyNotify) free_stat_info_entry);
2126
2127   while (TRUE)
2128     {
2129       struct stat_info_entry *entry;
2130       const gchar *basename;
2131
2132       basename = g_dir_read_name (dir);
2133       if (!basename)
2134         break;
2135
2136       entry = g_new0 (struct stat_info_entry, 1);
2137       if (folder_unix->is_network_dir)
2138         entry->statbuf.st_mode = S_IFDIR;
2139
2140       g_hash_table_insert (folder_unix->stat_info,
2141                            g_strdup (basename),
2142                            entry);
2143     }
2144
2145   g_dir_close (dir);
2146
2147   folder_unix->asof = time (NULL);
2148   return TRUE;
2149 }
2150
2151 static gboolean
2152 cb_fill_in_stats (gpointer key, gpointer value, gpointer user_data)
2153 {
2154   const char *basename = key;
2155   struct stat_info_entry *entry = value;
2156   GtkFileFolderUnix *folder_unix = user_data;
2157   char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2158   gboolean result;
2159
2160   if (stat (fullname, &entry->statbuf) == -1 &&
2161       (errno != ENOENT || lstat (fullname, &entry->statbuf) == -1))
2162     result = TRUE;  /* Couldn't stat -- remove from hash.  */
2163   else
2164     result = FALSE;
2165
2166   g_free (fullname);
2167   return result;
2168 }
2169
2170
2171 static void
2172 fill_in_stats (GtkFileFolderUnix *folder_unix)
2173 {
2174   if (folder_unix->have_stat)
2175     return;
2176
2177   if (!fill_in_names (folder_unix, NULL))
2178     return;
2179
2180   if (!folder_unix->is_network_dir)
2181     g_hash_table_foreach_remove (folder_unix->stat_info,
2182                                  cb_fill_in_stats,
2183                                  folder_unix);
2184
2185   folder_unix->have_stat = TRUE;
2186 }
2187
2188
2189 static gboolean
2190 cb_fill_in_mime_type (gpointer key, gpointer value, gpointer user_data)
2191 {
2192   const char *basename = key;
2193   struct stat_info_entry *entry = value;
2194   GtkFileFolderUnix *folder_unix = user_data;
2195   char *fullname = g_build_filename (folder_unix->filename, basename, NULL);
2196
2197   /* FIXME: Should not need to re-stat.  */
2198   const char *mime_type = xdg_mime_get_mime_type_for_file (fullname);
2199   entry->mime_type = g_strdup (mime_type);
2200
2201   g_free (fullname);
2202   /* FIXME: free on NULL?  */
2203   return FALSE;
2204 }
2205
2206 static void
2207 fill_in_mime_type (GtkFileFolderUnix *folder_unix)
2208 {
2209   if (folder_unix->have_mime_type)
2210     return;
2211
2212   if (!folder_unix->have_stat)
2213     return;
2214
2215   g_assert (folder_unix->stat_info != NULL);
2216
2217   g_hash_table_foreach_remove (folder_unix->stat_info,
2218                                cb_fill_in_mime_type,
2219                                folder_unix);
2220
2221   folder_unix->have_mime_type = TRUE;
2222 }
2223
2224 static GtkFilePath *
2225 filename_to_path (const char *filename)
2226 {
2227   char *tmp;
2228
2229   tmp = remove_trailing_slash (filename);
2230   return gtk_file_path_new_steal (tmp);
2231 }
2232
2233 static gboolean
2234 filename_is_root (const char *filename)
2235 {
2236   const gchar *after_root;
2237
2238   after_root = g_path_skip_root (filename);
2239
2240   return (after_root != NULL && *after_root == '\0');
2241 }
2242
2243 #define __GTK_FILE_SYSTEM_UNIX_C__
2244 #include "gtkaliasdef.c"