Removed unnecessary file
[platform/upstream/glib.git] / gio / glocalfile.c
1 /* GIO - GLib Input, Output and Streaming Library
2  * 
3  * Copyright (C) 2006-2007 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
16  * Public 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  * Author: Alexander Larsson <alexl@redhat.com>
21  */
22
23 #include <config.h>
24
25 #include <sys/types.h>
26 #include <sys/stat.h>
27 #include <string.h>
28 #include <errno.h>
29 #include <fcntl.h>
30 #include <unistd.h>
31
32 #if HAVE_SYS_STATFS_H
33 #include <sys/statfs.h>
34 #endif
35 #if HAVE_SYS_STATVFS_H
36 #include <sys/statvfs.h>
37 #endif
38 #if HAVE_SYS_VFS_H
39 #include <sys/vfs.h>
40 #elif HAVE_SYS_MOUNT_H
41 #if HAVE_SYS_PARAM_H
42 #include <sys/param.h>
43 #endif
44 #include <sys/mount.h>
45 #endif
46
47 #if defined(HAVE_STATFS) && defined(HAVE_STATVFS)
48 /* Some systems have both statfs and statvfs, pick the
49    most "native" for these */
50 # if defined(sun) && defined(__SVR4)
51    /* on solaris, statfs doesn't even have the
52       f_bavail field */
53 #  define USE_STATVFS
54 # else
55   /* at least on linux, statfs is the actual syscall */
56 #  define USE_STATFS
57 # endif
58
59 #elif defined(HAVE_STATFS)
60
61 # define USE_STATFS
62
63 #elif defined(HAVE_STATVFS)
64
65 # define USE_STATVFS
66
67 #endif
68
69 #include "glocalfile.h"
70 #include "glocalfileinfo.h"
71 #include "glocalfileenumerator.h"
72 #include "glocalfileinputstream.h"
73 #include "glocalfileoutputstream.h"
74 #include "glocaldirectorymonitor.h"
75 #include "glocalfilemonitor.h"
76 #include "gvolumeprivate.h"
77 #include <glib/gstdio.h>
78 #include "glibintl.h"
79
80 #include "gioalias.h"
81
82 static void g_local_file_file_iface_init (GFileIface       *iface);
83
84 static GFileAttributeInfoList *local_writable_attributes = NULL;
85 static GFileAttributeInfoList *local_writable_namespaces = NULL;
86
87 struct _GLocalFile
88 {
89   GObject parent_instance;
90
91   char *filename;
92 };
93
94 #define g_local_file_get_type _g_local_file_get_type
95 G_DEFINE_TYPE_WITH_CODE (GLocalFile, g_local_file, G_TYPE_OBJECT,
96                          G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
97                                                 g_local_file_file_iface_init))
98
99 static char * find_mountpoint_for (const char *file, dev_t dev);
100
101 static void
102 g_local_file_finalize (GObject *object)
103 {
104   GLocalFile *local;
105
106   local = G_LOCAL_FILE (object);
107
108   g_free (local->filename);
109   
110   if (G_OBJECT_CLASS (g_local_file_parent_class)->finalize)
111     (*G_OBJECT_CLASS (g_local_file_parent_class)->finalize) (object);
112 }
113
114 static void
115 g_local_file_class_init (GLocalFileClass *klass)
116 {
117   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
118   GFileAttributeInfoList *list;
119
120   gobject_class->finalize = g_local_file_finalize;
121
122   /* Set up attribute lists */
123
124   /* Writable attributes: */
125
126   list = g_file_attribute_info_list_new ();
127
128   g_file_attribute_info_list_add (list,
129                                   G_FILE_ATTRIBUTE_UNIX_MODE,
130                                   G_FILE_ATTRIBUTE_TYPE_UINT32,
131                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
132   
133 #ifdef HAVE_CHOWN
134   g_file_attribute_info_list_add (list,
135                                   G_FILE_ATTRIBUTE_UNIX_UID,
136                                   G_FILE_ATTRIBUTE_TYPE_UINT32,
137                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
138   g_file_attribute_info_list_add (list,
139                                   G_FILE_ATTRIBUTE_UNIX_GID,
140                                   G_FILE_ATTRIBUTE_TYPE_UINT32,
141                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
142 #endif
143   
144 #ifdef HAVE_SYMLINK
145   g_file_attribute_info_list_add (list,
146                                   G_FILE_ATTRIBUTE_STD_SYMLINK_TARGET,
147                                   G_FILE_ATTRIBUTE_TYPE_BYTE_STRING,
148                                   0);
149 #endif
150   
151 #ifdef HAVE_UTIMES
152   g_file_attribute_info_list_add (list,
153                                   G_FILE_ATTRIBUTE_TIME_MODIFIED,
154                                   G_FILE_ATTRIBUTE_TYPE_UINT64,
155                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
156   g_file_attribute_info_list_add (list,
157                                   G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
158                                   G_FILE_ATTRIBUTE_TYPE_UINT32,
159                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
160   g_file_attribute_info_list_add (list,
161                                   G_FILE_ATTRIBUTE_TIME_ACCESS,
162                                   G_FILE_ATTRIBUTE_TYPE_UINT64,
163                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
164   g_file_attribute_info_list_add (list,
165                                   G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
166                                   G_FILE_ATTRIBUTE_TYPE_UINT32,
167                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
168 #endif
169
170   local_writable_attributes = list;
171
172   /* Writable namespaces: */
173   
174   list = g_file_attribute_info_list_new ();
175
176 #ifdef HAVE_XATTR
177   g_file_attribute_info_list_add (list,
178                                   "xattr",
179                                   G_FILE_ATTRIBUTE_TYPE_STRING,
180                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WITH_FILE |
181                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
182   g_file_attribute_info_list_add (list,
183                                   "xattr_sys",
184                                   G_FILE_ATTRIBUTE_TYPE_STRING,
185                                   G_FILE_ATTRIBUTE_FLAGS_COPY_WHEN_MOVED);
186 #endif
187
188   local_writable_namespaces = list;
189 }
190
191 static void
192 g_local_file_init (GLocalFile *local)
193 {
194 }
195
196
197 static char *
198 canonicalize_filename (const char *filename)
199 {
200   char *canon, *start, *p, *q;
201   char *cwd;
202   
203   if (!g_path_is_absolute (filename))
204     {
205       cwd = g_get_current_dir ();
206       canon = g_build_filename (cwd, filename, NULL);
207       g_free (cwd);
208     }
209   else
210     canon = g_strdup (filename);
211
212   start = (char *)g_path_skip_root (canon);
213
214   p = start;
215   while (*p != 0)
216     {
217       if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1])))
218         {
219           memmove (p, p+1, strlen (p+1)+1);
220         }
221       else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2])))
222         {
223           q = p + 2;
224           /* Skip previous separator */
225           p = p - 2;
226           if (p < start)
227             p = start;
228           while (p > start && !G_IS_DIR_SEPARATOR (*p))
229             p--;
230           if (G_IS_DIR_SEPARATOR (*p))
231             *p++ = G_DIR_SEPARATOR;
232           memmove (p, q, strlen (q)+1);
233         }
234       else
235         {
236           /* Skip until next separator */
237           while (*p != 0 && !G_IS_DIR_SEPARATOR (*p))
238             p++;
239           
240           if (*p != 0)
241             {
242               /* Canonicalize one separator */
243               *p++ = G_DIR_SEPARATOR;
244             }
245         }
246
247       /* Remove additional separators */
248       q = p;
249       while (*q && G_IS_DIR_SEPARATOR (*q))
250         q++;
251
252       if (p != q)
253         memmove (p, q, strlen (q)+1);
254     }
255
256   /* Remove trailing slashes */
257   if (p > start && G_IS_DIR_SEPARATOR (*(p-1)))
258     *(p-1) = 0;
259   
260   return canon;
261 }
262
263 /**
264  * _g_local_file_new:
265  * @filename: filename of the file to create.
266  * 
267  * Returns: new local #GFile.
268  **/
269 GFile *
270 _g_local_file_new (const char *filename)
271 {
272   GLocalFile *local;
273
274   local = g_object_new (G_TYPE_LOCAL_FILE, NULL);
275   local->filename = canonicalize_filename (filename);
276   
277   return G_FILE (local);
278 }
279
280 static gboolean
281 g_local_file_is_native (GFile *file)
282 {
283   return TRUE;
284 }
285
286 static gboolean
287 g_local_file_has_uri_scheme (GFile *file,
288                              const char *uri_scheme)
289 {
290   return g_ascii_strcasecmp (uri_scheme, "file") == 0;
291 }
292
293 static char *
294 g_local_file_get_uri_scheme (GFile *file)
295 {
296   return g_strdup ("file");
297 }
298
299 static char *
300 g_local_file_get_basename (GFile *file)
301 {
302   return g_path_get_basename (G_LOCAL_FILE (file)->filename);
303 }
304
305 static char *
306 g_local_file_get_path (GFile *file)
307 {
308   return g_strdup (G_LOCAL_FILE (file)->filename);
309 }
310
311 static char *
312 g_local_file_get_uri (GFile *file)
313 {
314   return g_filename_to_uri (G_LOCAL_FILE (file)->filename, NULL, NULL);
315 }
316
317 static gboolean
318 get_filename_charset (const gchar **filename_charset)
319 {
320   const gchar **charsets;
321   gboolean is_utf8;
322   
323   is_utf8 = g_get_filename_charsets (&charsets);
324
325   if (filename_charset)
326     *filename_charset = charsets[0];
327   
328   return is_utf8;
329 }
330
331 static gboolean
332 name_is_valid_for_display (const char *string,
333                            gboolean is_valid_utf8)
334 {
335   char c;
336   
337   if (!is_valid_utf8 &&
338       !g_utf8_validate (string, -1, NULL))
339     return FALSE;
340
341   while ((c = *string++) != 0)
342     {
343       if (g_ascii_iscntrl(c))
344         return FALSE;
345     }
346
347   return TRUE;
348 }
349
350 static char *
351 g_local_file_get_parse_name (GFile *file)
352 {
353   const char *filename;
354   char *parse_name;
355   const gchar *charset;
356   char *utf8_filename;
357   char *roundtripped_filename;
358   gboolean free_utf8_filename;
359   gboolean is_valid_utf8;
360
361   filename = G_LOCAL_FILE (file)->filename;
362   if (get_filename_charset (&charset))
363     {
364       utf8_filename = (char *)filename;
365       free_utf8_filename = FALSE;
366       is_valid_utf8 = FALSE; /* Can't guarantee this */
367     }
368   else
369     {
370       utf8_filename = g_convert (filename, -1, 
371                                  "UTF-8", charset, NULL, NULL, NULL);
372       free_utf8_filename = TRUE;
373       is_valid_utf8 = TRUE;
374
375       if (utf8_filename != NULL)
376         {
377           /* Make sure we can roundtrip: */
378           roundtripped_filename = g_convert (utf8_filename, -1,
379                                              charset, "UTF-8", NULL, NULL, NULL);
380           
381           if (roundtripped_filename == NULL ||
382               strcmp (utf8_filename, roundtripped_filename) != 0)
383             {
384               g_free (utf8_filename);
385               utf8_filename = NULL;
386             }
387         }
388     }
389
390
391   if (utf8_filename != NULL &&
392       name_is_valid_for_display (utf8_filename, is_valid_utf8))
393     {
394       if (free_utf8_filename)
395         parse_name = utf8_filename;
396       else
397         parse_name = g_strdup (utf8_filename);
398     }
399   else
400     {
401       parse_name = g_filename_to_uri (filename, NULL, NULL);
402       if (free_utf8_filename)
403         g_free (utf8_filename);
404     }
405   
406   return parse_name;
407 }
408
409 static GFile *
410 g_local_file_get_parent (GFile *file)
411 {
412   GLocalFile *local = G_LOCAL_FILE (file);
413   const char *non_root;
414   char *dirname;
415   GFile *parent;
416
417   /* Check for root */
418   non_root = g_path_skip_root (local->filename);
419   if (*non_root == 0)
420     return NULL;
421
422   dirname = g_path_get_dirname (local->filename);
423   parent = _g_local_file_new (dirname);
424   g_free (dirname);
425   return parent;
426 }
427
428 static GFile *
429 g_local_file_dup (GFile *file)
430 {
431   GLocalFile *local = G_LOCAL_FILE (file);
432
433   return _g_local_file_new (local->filename);
434 }
435
436 static guint
437 g_local_file_hash (GFile *file)
438 {
439   GLocalFile *local = G_LOCAL_FILE (file);
440   
441   return g_str_hash (local->filename);
442 }
443
444 static gboolean
445 g_local_file_equal (GFile *file1,
446                     GFile *file2)
447 {
448   GLocalFile *local1 = G_LOCAL_FILE (file1);
449   GLocalFile *local2 = G_LOCAL_FILE (file2);
450
451   return g_str_equal (local1->filename, local2->filename);
452 }
453
454 static const char *
455 match_prefix (const char *path, const char *prefix)
456 {
457   int prefix_len;
458
459   prefix_len = strlen (prefix);
460   if (strncmp (path, prefix, prefix_len) != 0)
461     return NULL;
462   return path + prefix_len;
463 }
464
465 static gboolean
466 g_local_file_contains_file (GFile *parent,
467                             GFile *descendant)
468 {
469   GLocalFile *parent_local = G_LOCAL_FILE (parent);
470   GLocalFile *descendant_local = G_LOCAL_FILE (descendant);
471   const char *remainder;
472
473   remainder = match_prefix (descendant_local->filename, parent_local->filename);
474   if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
475     return TRUE;
476   return FALSE;
477 }
478
479 static char *
480 g_local_file_get_relative_path (GFile *parent,
481                                 GFile *descendant)
482 {
483   GLocalFile *parent_local = G_LOCAL_FILE (parent);
484   GLocalFile *descendant_local = G_LOCAL_FILE (descendant);
485   const char *remainder;
486
487   remainder = match_prefix (descendant_local->filename, parent_local->filename);
488   
489   if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
490     return g_strdup (remainder + 1);
491   return NULL;
492 }
493
494 static GFile *
495 g_local_file_resolve_relative_path (GFile *file,
496                                     const char *relative_path)
497 {
498   GLocalFile *local = G_LOCAL_FILE (file);
499   char *filename;
500   GFile *child;
501
502   if (g_path_is_absolute (relative_path))
503     return _g_local_file_new (relative_path);
504   
505   filename = g_build_filename (local->filename, relative_path, NULL);
506   child = _g_local_file_new (filename);
507   g_free (filename);
508   
509   return child;
510 }
511
512 static GFileEnumerator *
513 g_local_file_enumerate_children (GFile *file,
514                                  const char *attributes,
515                                  GFileQueryInfoFlags flags,
516                                  GCancellable *cancellable,
517                                  GError **error)
518 {
519   GLocalFile *local = G_LOCAL_FILE (file);
520   return _g_local_file_enumerator_new (local->filename,
521                                        attributes, flags,
522                                        cancellable, error);
523 }
524
525 static GFile *
526 g_local_file_get_child_for_display_name (GFile        *file,
527                                          const char   *display_name,
528                                          GError      **error)
529 {
530   GFile *parent, *new_file;
531   char *basename;
532
533   basename = g_filename_from_utf8 (display_name, -1, NULL, NULL, NULL);
534   if (basename == NULL)
535     {
536       g_set_error (error, G_IO_ERROR,
537                    G_IO_ERROR_INVALID_FILENAME,
538                    _("Invalid filename %s"), display_name);
539       return NULL;
540     }
541
542   parent = g_file_get_parent (file);
543   new_file = g_file_get_child (file, basename);
544   g_object_unref (parent);
545   g_free (basename);
546   
547   return new_file;
548 }
549
550 #ifdef USE_STATFS
551 static const char *
552 get_fs_type (long f_type)
553 {
554
555   /* filesystem ids taken from linux manpage */
556   switch (f_type) {
557   case 0xadf5:
558     return "adfs";
559   case 0xADFF:
560     return "affs";
561   case 0x42465331:
562     return "befs";
563   case 0x1BADFACE:
564     return "bfs";
565   case 0xFF534D42:
566     return "cifs";
567   case 0x73757245:
568     return "coda";
569   case 0x012FF7B7:
570     return "coh";
571   case 0x28cd3d45:
572     return "cramfs";
573   case 0x1373:
574     return "devfs";
575   case 0x00414A53:
576     return "efs";
577   case 0x137D:
578     return "ext";
579   case 0xEF51:
580     return "ext2";
581   case 0xEF53:
582     return "ext3";
583   case 0x4244:
584     return "hfs";
585   case 0xF995E849:
586     return "hpfs";
587   case 0x958458f6:
588     return "hugetlbfs";
589   case 0x9660:
590     return "isofs";
591   case 0x72b6:
592     return "jffs2";
593   case 0x3153464a:
594     return "jfs";
595   case 0x137F:
596     return "minix";
597   case 0x138F:
598     return "minix2";
599   case 0x2468:
600     return "minix2";
601   case 0x2478:
602     return "minix22";
603   case 0x4d44:
604     return "msdos";
605   case 0x564c:
606     return "ncp";
607   case 0x6969:
608     return "nfs";
609   case 0x5346544e:
610     return "ntfs";
611   case 0x9fa1:
612     return "openprom";
613   case 0x9fa0:
614     return "proc";
615   case 0x002f:
616     return "qnx4";
617   case 0x52654973:
618     return "reiserfs";
619   case 0x7275:
620     return "romfs";
621   case 0x517B:
622     return "smb";
623   case 0x012FF7B6:
624     return "sysv2";
625   case 0x012FF7B5:
626     return "sysv4";
627   case 0x01021994:
628     return "tmpfs";
629   case 0x15013346:
630     return "udf";
631   case 0x00011954:
632     return "ufs";
633   case 0x9fa2:
634     return "usbdevice";
635   case 0xa501FCF5:
636     return "vxfs";
637   case 0x012FF7B4:
638     return "xenix";
639   case 0x58465342:
640     return "xfs";
641   case 0x012FD16D:
642     return "xiafs";
643   default:
644     return NULL;
645   }
646 }
647 #endif
648
649 G_LOCK_DEFINE_STATIC(mount_info_hash);
650 static GHashTable *mount_info_hash = NULL;
651 guint64 mount_info_hash_cache_time = 0;
652
653 typedef enum {
654   MOUNT_INFO_READONLY = 1<<0
655 } MountInfo;
656
657 static gboolean
658 device_equal (gconstpointer v1,
659            gconstpointer v2)
660 {
661   return *(dev_t *)v1 == * (dev_t *)v2;
662 }
663
664 static guint
665 device_hash (gconstpointer  v)
666 {
667   return (guint) *(dev_t *)v;
668 }
669
670 static void
671 get_mount_info (GFileInfo *fs_info,
672                 const char *path,
673                 GFileAttributeMatcher *matcher)
674 {
675   struct stat buf;
676   gboolean got_info;
677   gpointer info_as_ptr;
678   guint mount_info;
679   char *mountpoint;
680   dev_t *dev;
681   GUnixMount *mount;
682   guint64 cache_time;
683
684   if (lstat (path, &buf) != 0)
685     return;
686
687   G_LOCK (mount_info_hash);
688
689   if (mount_info_hash == NULL)
690     mount_info_hash = g_hash_table_new_full (device_hash, device_equal,
691                                              g_free, NULL);
692
693
694   if (g_unix_mounts_changed_since (mount_info_hash_cache_time))
695     g_hash_table_remove_all (mount_info_hash);
696   
697   got_info = g_hash_table_lookup_extended (mount_info_hash,
698                                            &buf.st_dev,
699                                            NULL,
700                                            &info_as_ptr);
701   
702   G_UNLOCK (mount_info_hash);
703   
704   mount_info = GPOINTER_TO_UINT (info_as_ptr);
705   
706   if (!got_info)
707     {
708       mount_info = 0;
709
710       mountpoint = find_mountpoint_for (path, buf.st_dev);
711       if (mountpoint == NULL)
712         mountpoint = "/";
713
714       mount = g_get_unix_mount_at (mountpoint, &cache_time);
715       if (mount)
716         {
717           if (g_unix_mount_is_readonly (mount))
718             mount_info |= MOUNT_INFO_READONLY;
719           
720           g_unix_mount_free (mount);
721         }
722
723       dev = g_new0 (dev_t, 1);
724       *dev = buf.st_dev;
725       
726       G_LOCK (mount_info_hash);
727       mount_info_hash_cache_time = cache_time;
728       g_hash_table_insert (mount_info_hash, dev, GUINT_TO_POINTER (mount_info));
729       G_UNLOCK (mount_info_hash);
730     }
731
732   if (mount_info & MOUNT_INFO_READONLY)
733     g_file_info_set_attribute_boolean (fs_info, G_FILE_ATTRIBUTE_FS_READONLY, TRUE);
734 }
735
736 static GFileInfo *
737 g_local_file_query_filesystem_info (GFile                *file,
738                                     const char           *attributes,
739                                     GCancellable         *cancellable,
740                                     GError              **error)
741 {
742   GLocalFile *local = G_LOCAL_FILE (file);
743   GFileInfo *info;
744   int statfs_result;
745   gboolean no_size;
746   guint64 block_size;
747 #ifdef USE_STATFS
748   struct statfs statfs_buffer;
749   const char *fstype;
750 #elif defined(USE_STATVFS)
751   struct statvfs statfs_buffer;
752 #endif
753   GFileAttributeMatcher *attribute_matcher;
754         
755   no_size = FALSE;
756   
757 #ifdef USE_STATFS
758   
759 #if STATFS_ARGS == 2
760   statfs_result = statfs (local->filename, &statfs_buffer);
761 #elif STATFS_ARGS == 4
762   statfs_result = statfs (local->filename, &statfs_buffer,
763                           sizeof (statfs_buffer), 0);
764 #endif
765   block_size = statfs_buffer.f_bsize;
766   
767 #if defined(__linux__)
768   /* ncpfs does not know the amount of available and free space *
769    * assuming ncpfs is linux specific, if you are on a non-linux platform
770    * where ncpfs is available, please file a bug about it on bugzilla.gnome.org
771    */
772   if (statfs_buffer.f_bavail == 0 && statfs_buffer.f_bfree == 0 &&
773       /* linux/ncp_fs.h: NCP_SUPER_MAGIC == 0x564c */
774       statfs_buffer.f_type == 0x564c)
775     no_size = TRUE;
776 #endif
777   
778 #elif defined(USE_STATVFS)
779   statfs_result = statvfs (local->filename, &statfs_buffer);
780   block_size = statfs_buffer.f_frsize; 
781 #endif
782
783   if (statfs_result == -1)
784     {
785       g_set_error (error, G_IO_ERROR,
786                    g_io_error_from_errno (errno),
787                    _("Error getting filesystem info: %s"),
788                    g_strerror (errno));
789       return NULL;
790     }
791
792   info = g_file_info_new ();
793
794   attribute_matcher = g_file_attribute_matcher_new (attributes);
795   
796   if (g_file_attribute_matcher_matches (attribute_matcher,
797                                         G_FILE_ATTRIBUTE_FS_FREE))
798     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_FREE, block_size * statfs_buffer.f_bavail);
799   if (g_file_attribute_matcher_matches (attribute_matcher,
800                                         G_FILE_ATTRIBUTE_FS_SIZE))
801     g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FS_SIZE, block_size * statfs_buffer.f_blocks);
802
803 #ifdef USE_STATFS
804   fstype = get_fs_type (statfs_buffer.f_type);
805   if (fstype &&
806       g_file_attribute_matcher_matches (attribute_matcher,
807                                         G_FILE_ATTRIBUTE_FS_TYPE))
808     g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FS_TYPE, fstype);
809 #endif  
810
811   if (g_file_attribute_matcher_matches (attribute_matcher,
812                                         G_FILE_ATTRIBUTE_FS_READONLY))
813     {
814       get_mount_info (info, local->filename, attribute_matcher);
815     }
816   
817   g_file_attribute_matcher_unref (attribute_matcher);
818   
819   return info;
820 }
821
822 static GVolume *
823 g_local_file_find_enclosing_volume (GFile *file,
824                                     GCancellable *cancellable,
825                                     GError **error)
826 {
827   GLocalFile *local = G_LOCAL_FILE (file);
828   struct stat buf;
829   char *mountpoint;
830   GVolume *volume;
831
832   if (lstat (local->filename, &buf) != 0)
833     {
834       g_set_error (error, G_IO_ERROR,
835                    G_IO_ERROR_NOT_FOUND,
836                    _("Containing volume does not exist"));
837       return NULL;
838     }
839
840   mountpoint = find_mountpoint_for (local->filename, buf.st_dev);
841   if (mountpoint == NULL)
842     {
843       g_set_error (error, G_IO_ERROR,
844                    G_IO_ERROR_NOT_FOUND,
845                    _("Containing volume does not exist"));
846       return NULL;
847     }
848
849   volume = _g_volume_get_for_mount_path (mountpoint);
850   g_free (mountpoint);
851   if (volume)
852     return volume;
853
854   g_set_error (error, G_IO_ERROR,
855                G_IO_ERROR_NOT_FOUND,
856                _("Containing volume does not exist"));
857   return NULL;
858 }
859
860 static GFile *
861 g_local_file_set_display_name (GFile *file,
862                                const char *display_name,
863                                GCancellable *cancellable,
864                                GError **error)
865 {
866   GLocalFile *local, *new_local;
867   GFile *new_file, *parent;
868   struct stat statbuf;
869   int errsv;
870
871   parent = g_file_get_parent (file);
872   if (parent == NULL)
873     {
874       g_set_error (error, G_IO_ERROR,
875                    G_IO_ERROR_FAILED,
876                    _("Can't rename root directory"));
877       return NULL;
878     }
879   
880   new_file = g_file_get_child_for_display_name  (parent, display_name, error);
881   g_object_unref (parent);
882   
883   if (new_file == NULL)
884     return NULL;
885   
886   local = G_LOCAL_FILE (file);
887   new_local = G_LOCAL_FILE (new_file);
888
889   if (!(g_lstat (new_local->filename, &statbuf) == -1 &&
890         errno == ENOENT))
891     {
892       g_set_error (error, G_IO_ERROR,
893                    G_IO_ERROR_EXISTS,
894                    _("Can't rename file, filename already exist"));
895       return NULL;
896     }
897
898   if (rename (local->filename, new_local->filename) == -1)
899     {
900       errsv = errno;
901
902       if (errsv == EINVAL)
903         /* We can't get a rename file into itself error herer,
904            so this must be an invalid filename, on e.g. FAT */
905         g_set_error (error, G_IO_ERROR,
906                      G_IO_ERROR_INVALID_FILENAME,
907                      _("Invalid filename"));
908       else
909         g_set_error (error, G_IO_ERROR,
910                      g_io_error_from_errno (errsv),
911                      _("Error renaming file: %s"),
912                      g_strerror (errsv));
913       g_object_unref (new_file);
914       return NULL;
915     }
916   
917   return new_file;
918 }
919
920 static GFileInfo *
921 g_local_file_query_info (GFile                *file,
922                          const char           *attributes,
923                          GFileQueryInfoFlags   flags,
924                          GCancellable         *cancellable,
925                          GError              **error)
926 {
927   GLocalFile *local = G_LOCAL_FILE (file);
928   GFileInfo *info;
929   GFileAttributeMatcher *matcher;
930   char *basename, *dirname;
931   GLocalParentFileInfo parent_info;
932
933   matcher = g_file_attribute_matcher_new (attributes);
934   
935   basename = g_path_get_basename (local->filename);
936   
937   dirname = g_path_get_dirname (local->filename);
938   _g_local_file_info_get_parent_info (dirname, matcher, &parent_info);
939   g_free (dirname);
940   
941   info = _g_local_file_info_get (basename, local->filename,
942                                  matcher, flags, &parent_info,
943                                  error);
944   
945   g_free (basename);
946
947   g_file_attribute_matcher_unref (matcher);
948
949   return info;
950 }
951
952 static GFileAttributeInfoList *
953 g_local_file_query_settable_attributes (GFile                      *file,
954                                         GCancellable               *cancellable,
955                                         GError                    **error)
956 {
957   return g_file_attribute_info_list_ref (local_writable_attributes);
958 }
959
960 static GFileAttributeInfoList *
961 g_local_file_query_writable_namespaces (GFile *file,
962                                         GCancellable *cancellable,
963                                         GError **error)
964 {
965   return g_file_attribute_info_list_ref (local_writable_namespaces);
966 }
967
968 static gboolean
969 g_local_file_set_attribute (GFile *file,
970                             const char *attribute,
971                             const GFileAttributeValue *value,
972                             GFileQueryInfoFlags flags,
973                             GCancellable *cancellable,
974                             GError **error)
975 {
976   GLocalFile *local = G_LOCAL_FILE (file);
977
978   return _g_local_file_info_set_attribute (local->filename,
979                                            attribute,
980                                            value,
981                                            flags,
982                                            cancellable,
983                                            error);
984 }
985
986 static gboolean
987 g_local_file_set_attributes_from_info (GFile *file,
988                                        GFileInfo *info,
989                                        GFileQueryInfoFlags flags,
990                                        GCancellable *cancellable,
991                                        GError **error)
992 {
993   GLocalFile *local = G_LOCAL_FILE (file);
994   int res, chained_res;
995   GFileIface* default_iface;
996
997   res = _g_local_file_info_set_attributes (local->filename,
998                                            info, flags, 
999                                            cancellable,
1000                                            error);
1001
1002   if (!res)
1003     error = NULL; /* Don't write over error if further errors */
1004
1005   default_iface = g_type_default_interface_peek (G_TYPE_FILE);
1006
1007   chained_res = (default_iface->set_attributes_from_info) (file, info, flags, cancellable, error);
1008   
1009   return res && chained_res;
1010 }
1011
1012 static GFileInputStream *
1013 g_local_file_read (GFile *file,
1014                    GCancellable *cancellable,
1015                    GError **error)
1016 {
1017   GLocalFile *local = G_LOCAL_FILE (file);
1018   int fd;
1019   struct stat buf;
1020   
1021   fd = g_open (local->filename, O_RDONLY, 0);
1022   if (fd == -1)
1023     {
1024       g_set_error (error, G_IO_ERROR,
1025                    g_io_error_from_errno (errno),
1026                    _("Error opening file: %s"),
1027                    g_strerror (errno));
1028       return NULL;
1029     }
1030
1031   if (fstat(fd, &buf) == 0 && S_ISDIR (buf.st_mode))
1032     {
1033       close (fd);
1034       g_set_error (error, G_IO_ERROR,
1035                    G_IO_ERROR_IS_DIRECTORY,
1036                    _("Can't open directory"));
1037       return NULL;
1038     }
1039   
1040   return _g_local_file_input_stream_new (fd);
1041 }
1042
1043 static GFileOutputStream *
1044 g_local_file_append_to (GFile *file,
1045                         GFileCreateFlags flags,
1046                         GCancellable *cancellable,
1047                         GError **error)
1048 {
1049   return _g_local_file_output_stream_append (G_LOCAL_FILE (file)->filename,
1050                                              flags, cancellable, error);
1051 }
1052
1053 static GFileOutputStream *
1054 g_local_file_create (GFile *file,
1055                      GFileCreateFlags flags,
1056                      GCancellable *cancellable,
1057                      GError **error)
1058 {
1059   return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename,
1060                                              flags, cancellable, error);
1061 }
1062
1063 static GFileOutputStream *
1064 g_local_file_replace (GFile *file,
1065                       const char *etag,
1066                       gboolean make_backup,
1067                       GFileCreateFlags flags,
1068                       GCancellable *cancellable,
1069                       GError **error)
1070 {
1071   return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename,
1072                                               etag, make_backup, flags,
1073                                               cancellable, error);
1074 }
1075
1076
1077 static gboolean
1078 g_local_file_delete (GFile *file,
1079                      GCancellable *cancellable,
1080                      GError **error)
1081 {
1082   GLocalFile *local = G_LOCAL_FILE (file);
1083   
1084   if (g_remove (local->filename) == -1)
1085     {
1086       g_set_error (error, G_IO_ERROR,
1087                    g_io_error_from_errno (errno),
1088                    _("Error removing file: %s"),
1089                    g_strerror (errno));
1090       return FALSE;
1091     }
1092   
1093   return TRUE;
1094 }
1095
1096 static char *
1097 strip_trailing_slashes (const char *path)
1098 {
1099   char *path_copy;
1100   int len;
1101
1102   path_copy = g_strdup (path);
1103   len = strlen (path_copy);
1104   while (len > 1 && path_copy[len-1] == '/')
1105     path_copy[--len] = 0;
1106
1107   return path_copy;
1108  }
1109
1110 static char *
1111 expand_symlink (const char *link)
1112 {
1113   char *resolved, *canonical, *parent, *link2;
1114   char symlink_value[4096];
1115   ssize_t res;
1116   
1117   res = readlink (link, symlink_value, sizeof (symlink_value) - 1);
1118   if (res == -1)
1119     return g_strdup (link);
1120   symlink_value[res] = 0;
1121   
1122   if (g_path_is_absolute (symlink_value))
1123     return canonicalize_filename (symlink_value);
1124   else
1125     {
1126       link2 = strip_trailing_slashes (link);
1127       parent = g_path_get_dirname (link2);
1128       g_free (link2);
1129       
1130       resolved = g_build_filename (parent, symlink_value, NULL);
1131       g_free (parent);
1132       
1133       canonical = canonicalize_filename (resolved);
1134       
1135       g_free (resolved);
1136
1137       return canonical;
1138     }
1139 }
1140
1141 static char *
1142 get_parent (const char *path, dev_t *parent_dev)
1143 {
1144   char *parent, *tmp;
1145   struct stat parent_stat;
1146   int num_recursions;
1147   char *path_copy;
1148
1149   path_copy = strip_trailing_slashes (path);
1150   
1151   parent = g_path_get_dirname (path_copy);
1152   if (strcmp (parent, ".") == 0 ||
1153       strcmp (parent, path_copy) == 0)
1154     {
1155       g_free (path_copy);
1156       return NULL;
1157     }
1158   g_free (path_copy);
1159
1160   num_recursions = 0;
1161   do {
1162     if (g_lstat (parent, &parent_stat) != 0)
1163       {
1164         g_free (parent);
1165         return NULL;
1166       }
1167     
1168     if (S_ISLNK (parent_stat.st_mode))
1169       {
1170         tmp = parent;
1171         parent = expand_symlink (parent);
1172         g_free (tmp);
1173       }
1174     
1175     num_recursions++;
1176     if (num_recursions > 12)
1177       {
1178         g_free (parent);
1179         return NULL;
1180       }
1181   } while (S_ISLNK (parent_stat.st_mode));
1182
1183   *parent_dev = parent_stat.st_dev;
1184   
1185   return parent;
1186 }
1187
1188 static char *
1189 expand_all_symlinks (const char *path)
1190 {
1191   char *parent, *parent_expanded;
1192   char *basename, *res;
1193   dev_t parent_dev;
1194
1195   parent = get_parent (path, &parent_dev);
1196   if (parent)
1197     {
1198       parent_expanded = expand_all_symlinks (parent);
1199       g_free (parent);
1200       basename = g_path_get_basename (path);
1201       res = g_build_filename (parent_expanded, basename, NULL);
1202       g_free (basename);
1203       g_free (parent_expanded);
1204     }
1205   else
1206     res = g_strdup (path);
1207   
1208   return res;
1209 }
1210
1211 static char *
1212 find_mountpoint_for (const char *file, dev_t dev)
1213 {
1214   char *dir, *parent;
1215   dev_t dir_dev, parent_dev;
1216
1217   dir = g_strdup (file);
1218   dir_dev = dev;
1219
1220   while (1) {
1221     parent = get_parent (dir, &parent_dev);
1222     if (parent == NULL)
1223       return dir;
1224     
1225     if (parent_dev != dir_dev)
1226       {
1227         g_free (parent);
1228         return dir;
1229       }
1230     
1231     g_free (dir);
1232     dir = parent;
1233   }
1234 }
1235
1236 static char *
1237 find_topdir_for (const char *file)
1238 {
1239   char *dir;
1240   dev_t dir_dev;
1241
1242   dir = get_parent (file, &dir_dev);
1243   if (dir == NULL)
1244     return NULL;
1245
1246   return find_mountpoint_for (dir, dir_dev);
1247 }
1248
1249 static char *
1250 get_unique_filename (const char *basename, int id)
1251 {
1252   const char *dot;
1253       
1254   if (id == 1)
1255     return g_strdup (basename);
1256
1257   dot = strchr (basename, '.');
1258   if (dot)
1259     return g_strdup_printf ("%.*s.%d%s", dot - basename, basename, id, dot);
1260   else
1261     return g_strdup_printf ("%s.%d", basename, id);
1262 }
1263
1264 static gboolean
1265 path_has_prefix (const char *path, const char *prefix)
1266 {
1267   int prefix_len;
1268
1269   if (prefix == NULL)
1270     return TRUE;
1271
1272   prefix_len = strlen (prefix);
1273   
1274   if (strncmp (path, prefix, prefix_len) == 0 &&
1275       (prefix_len == 0 || /* empty prefix always matches */
1276        prefix[prefix_len - 1] == '/' || /* last char in prefix was a /, so it must be in path too */
1277        path[prefix_len] == 0 ||
1278        path[prefix_len] == '/'))
1279     return TRUE;
1280   
1281   return FALSE;
1282 }
1283
1284 static char *
1285 try_make_relative (const char *path, const char *base)
1286 {
1287   char *path2, *base2;
1288   char *relative;
1289
1290   path2 = expand_all_symlinks (path);
1291   base2 = expand_all_symlinks (base);
1292
1293   relative = NULL;
1294   if (path_has_prefix (path2, base2))
1295     {
1296       relative = path2 + strlen (base2);
1297       while (*relative == '/')
1298         relative ++;
1299       relative = g_strdup (relative);
1300     }
1301   g_free (path2);
1302   g_free (base2);
1303
1304   if (relative)
1305     return relative;
1306   
1307   /* Failed, use abs path */
1308   return g_strdup (path);
1309 }
1310
1311 static char *
1312 escape_trash_name (char *name)
1313 {
1314   GString *str;
1315   const gchar hex[16] = "0123456789ABCDEF";
1316   
1317   str = g_string_new ("");
1318
1319   while (*name != 0)
1320     {
1321       char c;
1322
1323       c = *name++;
1324
1325       if (g_ascii_isprint (c))
1326         g_string_append_c (str, c);
1327       else
1328         {
1329           g_string_append_c (str, '%');
1330           g_string_append_c (str, hex[((guchar)c) >> 4]);
1331           g_string_append_c (str, hex[((guchar)c) & 0xf]);
1332         }
1333     }
1334
1335   return g_string_free (str, FALSE);
1336 }
1337
1338 static gboolean
1339 g_local_file_trash (GFile *file,
1340                     GCancellable *cancellable,
1341                     GError **error)
1342 {
1343   GLocalFile *local = G_LOCAL_FILE (file);
1344   struct stat file_stat, home_stat, trash_stat, global_stat;
1345   const char *homedir;
1346   char *dirname;
1347   char *trashdir, *globaldir, *topdir, *infodir, *filesdir;
1348   char *basename, *trashname, *trashfile, *infoname, *infofile;
1349   char *original_name, *original_name_escaped;
1350   uid_t uid;
1351   char uid_str[32];
1352   int i;
1353   char *data;
1354   gboolean is_homedir_trash;
1355   time_t t;
1356   struct tm now;
1357   char delete_time[32];
1358   int fd;
1359   
1360   if (g_lstat (local->filename, &file_stat) != 0)
1361     {
1362       g_set_error (error, G_IO_ERROR,
1363                    g_io_error_from_errno (errno),
1364                    _("Error trashing file: %s"),
1365                    g_strerror (errno));
1366       return FALSE;
1367     }
1368     
1369   homedir = g_get_home_dir ();
1370   g_stat (homedir, &home_stat);
1371
1372   is_homedir_trash = FALSE;
1373   trashdir = NULL;
1374   if (file_stat.st_dev == home_stat.st_dev)
1375     {
1376       is_homedir_trash = TRUE;
1377       errno = 0;
1378       trashdir = g_build_filename (g_get_user_data_dir (), "Trash", NULL);
1379       if (g_mkdir_with_parents (trashdir, 0700) < 0)
1380         {
1381           char *display_name;
1382           int err;
1383
1384           err = errno;
1385           display_name = g_filename_display_name (trashdir);
1386           g_set_error (error, G_IO_ERROR,
1387                        g_io_error_from_errno (err),
1388                        _("Unable to create trash dir %s: %s"),
1389                        display_name, g_strerror (err));
1390           g_free (display_name);
1391           g_free (trashdir);
1392           return FALSE;
1393         }
1394       topdir = g_strdup (g_get_user_data_dir ());
1395     }
1396   else
1397     {
1398       uid = geteuid ();
1399       g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid);
1400       
1401       topdir = find_topdir_for (local->filename);
1402       if (topdir == NULL)
1403         {
1404           g_set_error (error, G_IO_ERROR,
1405                        G_IO_ERROR_NOT_SUPPORTED,
1406                        _("Unable to find toplevel directory for trash"));
1407           return FALSE;
1408         }
1409       
1410       /* Try looking for global trash dir $topdir/.Trash/$uid */
1411       globaldir = g_build_filename (topdir, ".Trash", NULL);
1412       if (g_lstat (globaldir, &global_stat) == 0 &&
1413           S_ISDIR (global_stat.st_mode) &&
1414           (global_stat.st_mode & S_ISVTX) != 0)
1415         {
1416           trashdir = g_build_filename (globaldir, uid_str, NULL);
1417
1418           if (g_lstat (trashdir, &trash_stat) == 0)
1419             {
1420               if (!S_ISDIR (trash_stat.st_mode) ||
1421                   trash_stat.st_uid != uid)
1422                 {
1423                   /* Not a directory or not owned by user, ignore */
1424                   g_free (trashdir);
1425                   trashdir = NULL;
1426                 }
1427             }
1428           else if (g_mkdir (trashdir, 0700) == -1)
1429             {
1430               g_free (trashdir);
1431               trashdir = NULL;
1432             }
1433         }
1434       g_free (globaldir);
1435
1436       if (trashdir == NULL)
1437         {
1438           /* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */
1439           dirname = g_strdup_printf (".Trash-%s", uid_str);
1440           trashdir = g_build_filename (topdir, dirname, NULL);
1441           g_free (dirname);
1442           
1443           if (g_lstat (trashdir, &trash_stat) == 0)
1444             {
1445               if (!S_ISDIR (trash_stat.st_mode) ||
1446                   trash_stat.st_uid != uid)
1447                 {
1448                   /* Not a directory or not owned by user, ignore */
1449                   g_free (trashdir);
1450                   trashdir = NULL;
1451                 }
1452             }
1453           else if (g_mkdir (trashdir, 0700) == -1)
1454             {
1455               g_free (trashdir);
1456               trashdir = NULL;
1457             }
1458         }
1459
1460       if (trashdir == NULL)
1461         {
1462           g_free (topdir);
1463           g_set_error (error, G_IO_ERROR,
1464                        G_IO_ERROR_NOT_SUPPORTED,
1465                        _("Unable to find or create trash directory"));
1466           return FALSE;
1467         }
1468     }
1469
1470   /* Trashdir points to the trash dir with the "info" and "files" subdirectories */
1471
1472   infodir = g_build_filename (trashdir, "info", NULL);
1473   filesdir = g_build_filename (trashdir, "files", NULL);
1474   g_free (trashdir);
1475
1476   /* Make sure we have the subdirectories */
1477   if ((g_mkdir (infodir, 0700) == -1 && errno != EEXIST) ||
1478       (g_mkdir (filesdir, 0700) == -1 && errno != EEXIST))
1479     {
1480       g_free (topdir);
1481       g_free (infodir);
1482       g_free (filesdir);
1483       g_set_error (error, G_IO_ERROR,
1484                    G_IO_ERROR_NOT_SUPPORTED,
1485                    _("Unable to find or create trash directory"));
1486       return FALSE;
1487     }  
1488
1489   basename = g_path_get_basename (local->filename);
1490   i = 1;
1491   trashname = NULL;
1492   infofile = NULL;
1493   do {
1494     g_free (trashname);
1495     g_free (infofile);
1496     
1497     trashname = get_unique_filename (basename, i++);
1498     infoname = g_strconcat (trashname, ".trashinfo", NULL);
1499     infofile = g_build_filename (infodir, infoname, NULL);
1500     g_free (infoname);
1501
1502     fd = open (infofile, O_CREAT | O_EXCL, 0666);
1503   } while (fd == -1 && errno == EEXIST);
1504
1505   g_free (basename);
1506   g_free (infodir);
1507
1508   if (fd == -1)
1509     {
1510       g_free (filesdir);
1511       g_free (topdir);
1512       g_free (trashname);
1513       g_free (infofile);
1514       
1515       g_set_error (error, G_IO_ERROR,
1516                    g_io_error_from_errno (errno),
1517                    _("Unable to create trashed file: %s"),
1518                    g_strerror (errno));
1519       return FALSE;
1520     }
1521
1522   close (fd);
1523
1524   /* TODO: Maybe we should verify that you can delete the file from the trash
1525      before moving it? OTOH, that is hard, as it needs a recursive scan */
1526
1527   trashfile = g_build_filename (filesdir, trashname, NULL);
1528
1529   g_free (filesdir);
1530
1531   if (g_rename (local->filename, trashfile) == -1)
1532     {
1533       g_free (topdir);
1534       g_free (trashname);
1535       g_free (infofile);
1536       g_free (trashfile);
1537       
1538       g_set_error (error, G_IO_ERROR,
1539                    g_io_error_from_errno (errno),
1540                    _("Unable to trash file: %s"),
1541                    g_strerror (errno));
1542       return FALSE;
1543     }
1544
1545   g_free (trashfile);
1546
1547   /* TODO: Do we need to update mtime/atime here after the move? */
1548
1549   /* Use absolute names for homedir */
1550   if (is_homedir_trash)
1551     original_name = g_strdup (local->filename);
1552   else
1553     original_name = try_make_relative (local->filename, topdir);
1554   original_name_escaped = escape_trash_name (original_name);
1555   
1556   g_free (original_name);
1557   g_free (topdir);
1558   
1559   t = time (NULL);
1560   localtime_r (&t, &now);
1561   delete_time[0] = 0;
1562   strftime(delete_time, sizeof (delete_time), "%Y-%m-%dT%H:%M:%S", &now);
1563
1564   data = g_strdup_printf ("[Trash Info]\nPath=%s\nDeletionDate=%s\n",
1565                           original_name_escaped, delete_time);
1566
1567   g_file_set_contents (infofile, data, -1, NULL);
1568   g_free (infofile);
1569   g_free (data);
1570   
1571   g_free (original_name_escaped);
1572   g_free (trashname);
1573   
1574   return TRUE;
1575 }
1576
1577 static gboolean
1578 g_local_file_make_directory (GFile *file,
1579                              GCancellable *cancellable,
1580                              GError **error)
1581 {
1582   GLocalFile *local = G_LOCAL_FILE (file);
1583   
1584   if (g_mkdir (local->filename, 0755) == -1)
1585     {
1586       int errsv = errno;
1587
1588       if (errsv == EINVAL)
1589         /* This must be an invalid filename, on e.g. FAT */
1590         g_set_error (error, G_IO_ERROR,
1591                      G_IO_ERROR_INVALID_FILENAME,
1592                      _("Invalid filename"));
1593       else
1594         g_set_error (error, G_IO_ERROR,
1595                      g_io_error_from_errno (errsv),
1596                      _("Error removing file: %s"),
1597                      g_strerror (errsv));
1598       return FALSE;
1599     }
1600   
1601   return TRUE;
1602 }
1603
1604 static gboolean
1605 g_local_file_make_symbolic_link (GFile *file,
1606                                  const char *symlink_value,
1607                                  GCancellable *cancellable,
1608                                  GError **error)
1609 {
1610 #ifdef HAVE_SYMLINK
1611   GLocalFile *local = G_LOCAL_FILE (file);
1612   
1613   if (symlink (symlink_value, local->filename) == -1)
1614     {
1615       int errsv = errno;
1616
1617       if (errsv == EINVAL)
1618         /* This must be an invalid filename, on e.g. FAT */
1619         g_set_error (error, G_IO_ERROR,
1620                      G_IO_ERROR_INVALID_FILENAME,
1621                      _("Invalid filename"));
1622       else
1623         g_set_error (error, G_IO_ERROR,
1624                      g_io_error_from_errno (errsv),
1625                      _("Error making symbolic link: %s"),
1626                      g_strerror (errsv));
1627       return FALSE;
1628     }
1629   return TRUE;
1630 #else
1631   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Symlinks not supported");
1632   return FALSE;
1633 #endif
1634 }
1635
1636
1637 static gboolean
1638 g_local_file_copy (GFile                *source,
1639                    GFile                *destination,
1640                    GFileCopyFlags        flags,
1641                    GCancellable         *cancellable,
1642                    GFileProgressCallback progress_callback,
1643                    gpointer              progress_callback_data,
1644                    GError              **error)
1645 {
1646   /* Fall back to default copy */
1647   g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Copy not supported");
1648   return FALSE;
1649 }
1650
1651 static gboolean
1652 g_local_file_move (GFile                *source,
1653                    GFile                *destination,
1654                    GFileCopyFlags        flags,
1655                    GCancellable         *cancellable,
1656                    GFileProgressCallback progress_callback,
1657                    gpointer              progress_callback_data,
1658                    GError              **error)
1659 {
1660   GLocalFile *local_source = G_LOCAL_FILE (source);
1661   GLocalFile *local_destination = G_LOCAL_FILE (destination);
1662   struct stat statbuf;
1663   gboolean destination_exist, source_is_dir;
1664   char *backup_name;
1665   int res;
1666
1667   res = g_lstat (local_source->filename, &statbuf);
1668   if (res == -1)
1669     {
1670       g_set_error (error, G_IO_ERROR,
1671                    g_io_error_from_errno (errno),
1672                    _("Error moving file: %s"),
1673                    g_strerror (errno));
1674       return FALSE;
1675     }
1676   else
1677     source_is_dir = S_ISDIR (statbuf.st_mode);
1678   
1679   destination_exist = FALSE;
1680   res = g_lstat (local_destination->filename, &statbuf);
1681   if (res == 0)
1682     {
1683       destination_exist = TRUE; /* Target file exists */
1684
1685       if (flags & G_FILE_COPY_OVERWRITE)
1686         {
1687           /* Always fail on dirs, even with overwrite */
1688           if (S_ISDIR (statbuf.st_mode))
1689             {
1690               g_set_error (error,
1691                            G_IO_ERROR,
1692                            G_IO_ERROR_WOULD_MERGE,
1693                            _("Can't move directory over directory"));
1694               return FALSE;
1695             }
1696         }
1697       else
1698         {
1699           g_set_error (error,
1700                        G_IO_ERROR,
1701                        G_IO_ERROR_EXISTS,
1702                        _("Target file already exists"));
1703           return FALSE;
1704         }
1705     }
1706   
1707   if (flags & G_FILE_COPY_BACKUP && destination_exist)
1708     {
1709       backup_name = g_strconcat (local_destination->filename, "~", NULL);
1710       if (rename (local_destination->filename, backup_name) == -1)
1711         {
1712           g_set_error (error,
1713                        G_IO_ERROR,
1714                        G_IO_ERROR_CANT_CREATE_BACKUP,
1715                        _("Backup file creation failed"));
1716           g_free (backup_name);
1717           return FALSE;
1718         }
1719       g_free (backup_name);
1720       destination_exist = FALSE; /* It did, but no more */
1721     }
1722
1723   if (source_is_dir && destination_exist && (flags & G_FILE_COPY_OVERWRITE))
1724     {
1725       /* Source is a dir, destination exists (and is not a dir, because that would have failed
1726          earlier), and we're overwriting. Manually remove the target so we can do the rename. */
1727       res = unlink (local_destination->filename);
1728       if (res == -1)
1729         {
1730           g_set_error (error, G_IO_ERROR,
1731                        g_io_error_from_errno (errno),
1732                        _("Error removing target file: %s"),
1733                        g_strerror (errno));
1734           return FALSE;
1735         }
1736     }
1737   
1738   if (rename (local_source->filename, local_destination->filename) == -1)
1739     {
1740       int errsv = errno;
1741       if (errsv == EXDEV)
1742         goto fallback;
1743
1744       if (errsv == EINVAL)
1745         /* This must be an invalid filename, on e.g. FAT, or
1746            we're trying to move the file into itself...
1747            We return invalid filename for both... */
1748         g_set_error (error, G_IO_ERROR,
1749                      G_IO_ERROR_INVALID_FILENAME,
1750                      _("Invalid filename"));
1751       else
1752         g_set_error (error, G_IO_ERROR,
1753                      g_io_error_from_errno (errsv),
1754                      _("Error moving file: %s"),
1755                      g_strerror (errsv));
1756       return FALSE;
1757
1758     }
1759   return TRUE;
1760
1761  fallback:
1762
1763   if (!g_file_copy (source, destination, G_FILE_COPY_OVERWRITE | G_FILE_COPY_ALL_METADATA, cancellable,
1764                     progress_callback, progress_callback_data,
1765                     error))
1766     return FALSE;
1767   
1768   return g_file_delete (source, cancellable, error);
1769 }
1770
1771
1772 static GDirectoryMonitor*
1773 g_local_file_monitor_dir (GFile* file,
1774                           GFileMonitorFlags flags,
1775                           GCancellable *cancellable)
1776 {
1777   GLocalFile* local_file = G_LOCAL_FILE(file);
1778   return _g_local_directory_monitor_new (local_file->filename, flags);
1779 }
1780
1781 static GFileMonitor*
1782 g_local_file_monitor_file (GFile* file,
1783                            GFileMonitorFlags flags,
1784                            GCancellable *cancellable)
1785 {
1786   GLocalFile* local_file = G_LOCAL_FILE(file);
1787   return _g_local_file_monitor_new (local_file->filename, flags);
1788 }
1789
1790 static void
1791 g_local_file_file_iface_init (GFileIface *iface)
1792 {
1793   iface->dup = g_local_file_dup;
1794   iface->hash = g_local_file_hash;
1795   iface->equal = g_local_file_equal;
1796   iface->is_native = g_local_file_is_native;
1797   iface->has_uri_scheme = g_local_file_has_uri_scheme;
1798   iface->get_uri_scheme = g_local_file_get_uri_scheme;
1799   iface->get_basename = g_local_file_get_basename;
1800   iface->get_path = g_local_file_get_path;
1801   iface->get_uri = g_local_file_get_uri;
1802   iface->get_parse_name = g_local_file_get_parse_name;
1803   iface->get_parent = g_local_file_get_parent;
1804   iface->contains_file = g_local_file_contains_file;
1805   iface->get_relative_path = g_local_file_get_relative_path;
1806   iface->resolve_relative_path = g_local_file_resolve_relative_path;
1807   iface->get_child_for_display_name = g_local_file_get_child_for_display_name;
1808   iface->set_display_name = g_local_file_set_display_name;
1809   iface->enumerate_children = g_local_file_enumerate_children;
1810   iface->query_info = g_local_file_query_info;
1811   iface->query_filesystem_info = g_local_file_query_filesystem_info;
1812   iface->find_enclosing_volume = g_local_file_find_enclosing_volume;
1813   iface->query_settable_attributes = g_local_file_query_settable_attributes;
1814   iface->query_writable_namespaces = g_local_file_query_writable_namespaces;
1815   iface->set_attribute = g_local_file_set_attribute;
1816   iface->set_attributes_from_info = g_local_file_set_attributes_from_info;
1817   iface->read = g_local_file_read;
1818   iface->append_to = g_local_file_append_to;
1819   iface->create = g_local_file_create;
1820   iface->replace = g_local_file_replace;
1821   iface->delete_file = g_local_file_delete;
1822   iface->trash = g_local_file_trash;
1823   iface->make_directory = g_local_file_make_directory;
1824   iface->make_symbolic_link = g_local_file_make_symbolic_link;
1825   iface->copy = g_local_file_copy;
1826   iface->move = g_local_file_move;
1827   iface->monitor_dir = g_local_file_monitor_dir;
1828   iface->monitor_file = g_local_file_monitor_file;
1829 }