13781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/* GIO - GLib Input, Output and Streaming Library
23781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
33781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Copyright (C) 2006-2007 Red Hat, Inc.
43781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
53781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * This library is free software; you can redistribute it and/or
63781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * modify it under the terms of the GNU Lesser General Public
73781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * License as published by the Free Software Foundation; either
83781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * version 2 of the License, or (at your option) any later version.
93781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * This library is distributed in the hope that it will be useful,
113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * but WITHOUT ANY WARRANTY; without even the implied warranty of
123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Lesser General Public License for more details.
143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * You should have received a copy of the GNU Lesser General
163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Public License along with this library; if not, write to the
173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Free Software Foundation, Inc., 59 Temple Place, Suite 330,
183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Boston, MA 02111-1307, USA.
193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Author: Alexander Larsson <alexl@redhat.com>
213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson */
223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
23761424465aaad736916b029383483b6ac419d831Johan Dahlin#include "config.h"
243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/types.h>
263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/stat.h>
273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <string.h>
283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <errno.h>
293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <fcntl.h>
30a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef HAVE_UNISTD_H
313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <unistd.h>
32a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if HAVE_SYS_STATFS_H
353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/statfs.h>
363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if HAVE_SYS_STATVFS_H
383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/statvfs.h>
393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if HAVE_SYS_VFS_H
413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/vfs.h>
423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif HAVE_SYS_MOUNT_H
433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if HAVE_SYS_PARAM_H
443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/param.h>
453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <sys/mount.h>
473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
49b221d1b36d0ed5ce22f21a986a352f6a92345c30Alexander Larsson#ifndef O_BINARY
50b221d1b36d0ed5ce22f21a986a352f6a92345c30Alexander Larsson#define O_BINARY 0
51b221d1b36d0ed5ce22f21a986a352f6a92345c30Alexander Larsson#endif
52b221d1b36d0ed5ce22f21a986a352f6a92345c30Alexander Larsson
533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if defined(HAVE_STATFS) && defined(HAVE_STATVFS)
543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/* Some systems have both statfs and statvfs, pick the
553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson   most "native" for these */
56563eb127486d337cf5aef58637328220a5c9fcc8Matthias Clasen# if !defined(HAVE_STRUCT_STATFS_F_BAVAIL)
57563eb127486d337cf5aef58637328220a5c9fcc8Matthias Clasen   /* on solaris and irix, statfs doesn't even have the
583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      f_bavail field */
593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#  define USE_STATVFS
603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson# else
613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* at least on linux, statfs is the actual syscall */
623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#  define USE_STATFS
633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson# endif
643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif defined(HAVE_STATFS)
663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson# define USE_STATFS
683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif defined(HAVE_STATVFS)
703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson# define USE_STATVFS
723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
753d93bf6968884d75dd2706ef85e2014305eb92f2Cody Russell#include "gfileattribute.h"
763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfile.h"
773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfileinfo.h"
783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfileenumerator.h"
793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfileinputstream.h"
803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfileoutputstream.h"
813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocaldirectorymonitor.h"
823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glocalfilemonitor.h"
833ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen#include "gmountprivate.h"
843d93bf6968884d75dd2706ef85e2014305eb92f2Cody Russell#include "gunixmounts.h"
853d93bf6968884d75dd2706ef85e2014305eb92f2Cody Russell#include "gioerror.h"
863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include <glib/gstdio.h>
873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#include "glibintl.h"
883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
89a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
901d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#define _WIN32_WINNT 0x0500
91a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#include <windows.h>
92a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#include <io.h>
93a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#include <direct.h>
94a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
9593bd705e78a4b224e0862e42a2384b5dad4f31a6Tor Lillqvist#ifndef FILE_READ_ONLY_VOLUME
9693bd705e78a4b224e0862e42a2384b5dad4f31a6Tor Lillqvist#define FILE_READ_ONLY_VOLUME           0x00080000
9793bd705e78a4b224e0862e42a2384b5dad4f31a6Tor Lillqvist#endif
9893bd705e78a4b224e0862e42a2384b5dad4f31a6Tor Lillqvist
99a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifndef S_ISDIR
100a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#define S_ISDIR(m) (((m) & _S_IFMT) == _S_IFDIR)
101a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
102a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifndef S_ISLNK
103a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#define S_ISLNK(m) (0)
104a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
105a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
106a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
1077f3280230bc9448a5750fc17a6eabef691ba25f4Alexander Larsson#include "gioalias.h"
1087f3280230bc9448a5750fc17a6eabef691ba25f4Alexander Larsson
10954300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasenstatic void g_local_file_file_iface_init (GFileIface *iface);
1103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1113781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileAttributeInfoList *local_writable_attributes = NULL;
1123781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileAttributeInfoList *local_writable_namespaces = NULL;
1133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1143781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstruct _GLocalFile
1153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GObject parent_instance;
1173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *filename;
1193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson};
1203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
121d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson#define g_local_file_get_type _g_local_file_get_type
1223781343738de4abddf56982325a77bd70a98cd26Alexander LarssonG_DEFINE_TYPE_WITH_CODE (GLocalFile, g_local_file, G_TYPE_OBJECT,
1233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			 G_IMPLEMENT_INTERFACE (G_TYPE_FILE,
1243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson						g_local_file_file_iface_init))
1253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12654300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasenstatic char *find_mountpoint_for (const char *file, dev_t dev);
1273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1283781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
1293781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_finalize (GObject *object)
1303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local;
1323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local = G_LOCAL_FILE (object);
1343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (local->filename);
136a4427bfff5d31499dc0b46fa3f734bc92f7d0dd5Michael Natterer
137a4427bfff5d31499dc0b46fa3f734bc92f7d0dd5Michael Natterer  G_OBJECT_CLASS (g_local_file_parent_class)->finalize (object);
1383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
1393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1403781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
1413781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_class_init (GLocalFileClass *klass)
1423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
1443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFileAttributeInfoList *list;
1453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gobject_class->finalize = g_local_file_finalize;
1473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Set up attribute lists */
1493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Writable attributes: */
1513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  list = g_file_attribute_info_list_new ();
1533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_UNIX_MODE,
1563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT32,
1578a9c5b6d3c25bbe2eddb815a1c95af3cc1d927dbAlexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
1584cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef HAVE_CHOWN
1613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_UNIX_UID,
1633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT32,
1644cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_UNIX_GID,
1673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT32,
1684cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
1703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef HAVE_SYMLINK
1723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
17371768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson				  G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET,
1743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_BYTE_STRING,
1753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  0);
1763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
1773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef HAVE_UTIMES
1793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TIME_MODIFIED,
1813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT64,
18239b3b4148456e596fa0ada24d47bcc76c1984172Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
1834cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TIME_MODIFIED_USEC,
1863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT32,
18739b3b4148456e596fa0ada24d47bcc76c1984172Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
1884cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
18939b3b4148456e596fa0ada24d47bcc76c1984172Alexander Larsson  /* When copying, the target file is accessed. Replicating
19039b3b4148456e596fa0ada24d47bcc76c1984172Alexander Larsson   * the source access time does not make sense in this case.
19139b3b4148456e596fa0ada24d47bcc76c1984172Alexander Larsson   */
1923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TIME_ACCESS,
1943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT64,
1954cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
1963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
1973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TIME_ACCESS_USEC,
1983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_UINT32,
1994cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
2003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
2013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local_writable_attributes = list;
2033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Writable namespaces: */
2053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  list = g_file_attribute_info_list_new ();
2073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef HAVE_XATTR
2093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
2103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  "xattr",
2113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_STRING,
2124cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
2134cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
2143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_info_list_add (list,
2151c57670f19012ac6ed8f4b0a0380ec0c304dd542Alexander Larsson				  "xattr-sys",
2163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				  G_FILE_ATTRIBUTE_TYPE_STRING,
2174cb6eab803662aebb2a81fe97832dd7576391331Alexander Larsson				  G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
2183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
2193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local_writable_namespaces = list;
2213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2233781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
2243781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_init (GLocalFile *local)
2253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2293781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
2303781343738de4abddf56982325a77bd70a98cd26Alexander Larssoncanonicalize_filename (const char *filename)
2313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *canon, *start, *p, *q;
2333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *cwd;
2342544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson  int i;
2353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (!g_path_is_absolute (filename))
2373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
2383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      cwd = g_get_current_dir ();
2393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      canon = g_build_filename (cwd, filename, NULL);
2403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (cwd);
2413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
2423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
2433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    canon = g_strdup (filename);
2443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  start = (char *)g_path_skip_root (canon);
2463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
24770a276eca32744525f06edc09e77aed07276abcaAlexander Larsson  if (start == NULL)
24870a276eca32744525f06edc09e77aed07276abcaAlexander Larsson    {
24970a276eca32744525f06edc09e77aed07276abcaAlexander Larsson      /* This shouldn't really happen, as g_get_current_dir() should
25070a276eca32744525f06edc09e77aed07276abcaAlexander Larsson	 return an absolute pathname, but bug 573843 shows this is
25170a276eca32744525f06edc09e77aed07276abcaAlexander Larsson	 not always happening */
25270a276eca32744525f06edc09e77aed07276abcaAlexander Larsson      g_free (canon);
25370a276eca32744525f06edc09e77aed07276abcaAlexander Larsson      return g_build_filename (G_DIR_SEPARATOR_S, filename, NULL);
25470a276eca32744525f06edc09e77aed07276abcaAlexander Larsson    }
25570a276eca32744525f06edc09e77aed07276abcaAlexander Larsson
2562544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson  /* POSIX allows double slashes at the start to
2572544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson   * mean something special (as does windows too).
2582544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson   * So, "//" != "/", but more than two slashes
2592544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson   * is treated as "/".
2602544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson   */
2612544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson  i = 0;
2622544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson  for (p = start - 1;
2632544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson       (p >= canon) &&
2642544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson	 G_IS_DIR_SEPARATOR (*p);
2652544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson       p--)
2662544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson    i++;
2672544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson  if (i > 2)
2682544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson    {
2692544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson      i -= 1;
2702544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson      start -= i;
2712544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson      memmove (start, start+i, strlen (start+i)+1);
2722544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson    }
2732544ae3cd69668ea578ac7c19a23dc7c2dcad396Alexander Larsson
2743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  p = start;
2753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (*p != 0)
2763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
2773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (p[0] == '.' && (p[1] == 0 || G_IS_DIR_SEPARATOR (p[1])))
2783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
2793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  memmove (p, p+1, strlen (p+1)+1);
2803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
2813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || G_IS_DIR_SEPARATOR (p[2])))
2823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
2833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  q = p + 2;
2843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  /* Skip previous separator */
2853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  p = p - 2;
2863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (p < start)
2873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    p = start;
2883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  while (p > start && !G_IS_DIR_SEPARATOR (*p))
2893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    p--;
2903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (G_IS_DIR_SEPARATOR (*p))
2913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    *p++ = G_DIR_SEPARATOR;
2923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  memmove (p, q, strlen (q)+1);
2933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
2943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
2953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
2963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  /* Skip until next separator */
2973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  while (*p != 0 && !G_IS_DIR_SEPARATOR (*p))
2983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    p++;
2993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (*p != 0)
3013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
3023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      /* Canonicalize one separator */
3033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      *p++ = G_DIR_SEPARATOR;
3043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
3053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
3063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      /* Remove additional separators */
3083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      q = p;
3093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      while (*q && G_IS_DIR_SEPARATOR (*q))
3103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	q++;
3113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (p != q)
3133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	memmove (p, q, strlen (q)+1);
3143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
3153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Remove trailing slashes */
3173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (p > start && G_IS_DIR_SEPARATOR (*(p-1)))
3183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    *(p-1) = 0;
3193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return canon;
3213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson/**
324d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson * _g_local_file_new:
3253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * @filename: filename of the file to create.
3263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson *
3273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson * Returns: new local #GFile.
3283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson **/
3293781343738de4abddf56982325a77bd70a98cd26Alexander LarssonGFile *
330d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson_g_local_file_new (const char *filename)
3313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local;
3333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local = g_object_new (G_TYPE_LOCAL_FILE, NULL);
3353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local->filename = canonicalize_filename (filename);
3363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return G_FILE (local);
3383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3403781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
3413781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_is_native (GFile *file)
3423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
3443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3463781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
347a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_has_uri_scheme (GFile      *file,
3483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			     const char *uri_scheme)
3493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_ascii_strcasecmp (uri_scheme, "file") == 0;
3513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3533781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
3543781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_uri_scheme (GFile *file)
3553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_strdup ("file");
3573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3593781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
3603781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_basename (GFile *file)
3613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_path_get_basename (G_LOCAL_FILE (file)->filename);
3633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3653781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
3663781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_path (GFile *file)
3673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_strdup (G_LOCAL_FILE (file)->filename);
3693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3713781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
3723781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_uri (GFile *file)
3733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_filename_to_uri (G_LOCAL_FILE (file)->filename, NULL, NULL);
3753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3773781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
3783781343738de4abddf56982325a77bd70a98cd26Alexander Larssonget_filename_charset (const gchar **filename_charset)
3793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const gchar **charsets;
3813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean is_utf8;
3823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  is_utf8 = g_get_filename_charsets (&charsets);
3843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (filename_charset)
3863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    *filename_charset = charsets[0];
3873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return is_utf8;
3893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
3903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
3913781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
3923781343738de4abddf56982325a77bd70a98cd26Alexander Larssonname_is_valid_for_display (const char *string,
393a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			   gboolean    is_valid_utf8)
3943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
3953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char c;
396b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson
3973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (!is_valid_utf8 &&
3983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      !g_utf8_validate (string, -1, NULL))
3993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return FALSE;
4003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while ((c = *string++) != 0)
4023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
40354300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen      if (g_ascii_iscntrl (c))
4043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	return FALSE;
4053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
4083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
4093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4103781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
4113781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_parse_name (GFile *file)
4123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
4133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *filename;
4143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *parse_name;
4153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const gchar *charset;
4163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *utf8_filename;
4173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *roundtripped_filename;
4183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean free_utf8_filename;
4193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean is_valid_utf8;
420b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson  char *escaped_path;
421b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson
4223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  filename = G_LOCAL_FILE (file)->filename;
4233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (get_filename_charset (&charset))
4243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
4253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      utf8_filename = (char *)filename;
4263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      free_utf8_filename = FALSE;
4273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      is_valid_utf8 = FALSE; /* Can't guarantee this */
4283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
4303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
4313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      utf8_filename = g_convert (filename, -1,
4323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				 "UTF-8", charset, NULL, NULL, NULL);
4333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      free_utf8_filename = TRUE;
4343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      is_valid_utf8 = TRUE;
4353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (utf8_filename != NULL)
4373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
4383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  /* Make sure we can roundtrip: */
4393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  roundtripped_filename = g_convert (utf8_filename, -1,
4403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					     charset, "UTF-8", NULL, NULL, NULL);
4413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (roundtripped_filename == NULL ||
4433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      strcmp (utf8_filename, roundtripped_filename) != 0)
4443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
4453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      g_free (utf8_filename);
4463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      utf8_filename = NULL;
4473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
4487b46b2a43bee252846d271483fdec6a55f59dea4Federico Mena Quintero
4497b46b2a43bee252846d271483fdec6a55f59dea4Federico Mena Quintero	  g_free (roundtripped_filename);
4503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
4513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (utf8_filename != NULL &&
4543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      name_is_valid_for_display (utf8_filename, is_valid_utf8))
4553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
4563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (free_utf8_filename)
4573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	parse_name = utf8_filename;
4583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
4593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	parse_name = g_strdup (utf8_filename);
4603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
4623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
463b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson      escaped_path = g_uri_escape_string (filename,
464b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson					  G_URI_RESERVED_CHARS_ALLOWED_IN_PATH_ELEMENT "/",
465b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson					  TRUE);
466b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson      parse_name = g_strconcat ("file://",
467b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson				(*escaped_path != '/') ? "/" : "",
468b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson				escaped_path,
469b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson				NULL);
470b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson
471b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson      g_free (escaped_path);
472b784923e9cb3e639616113cb43edffed7e63e3b6Alexander Larsson
4733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (free_utf8_filename)
4743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_free (utf8_filename);
4753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
4763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return parse_name;
4783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
4793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4803781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFile *
4813781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_parent (GFile *file)
4823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
4833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
4843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *non_root;
4853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *dirname;
4863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFile *parent;
4873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Check for root */
4893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  non_root = g_path_skip_root (local->filename);
4903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (*non_root == 0)
4913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return NULL;
4923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dirname = g_path_get_dirname (local->filename);
494d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  parent = _g_local_file_new (dirname);
4953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (dirname);
4963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return parent;
4973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
4983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
4993781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFile *
5003781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_dup (GFile *file)
5013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
5033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
504d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  return _g_local_file_new (local->filename);
5053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5073781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic guint
5083781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_hash (GFile *file)
5093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
5113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_str_hash (local->filename);
5133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5153781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
5163781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_equal (GFile *file1,
5173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		    GFile *file2)
5183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local1 = G_LOCAL_FILE (file1);
5203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local2 = G_LOCAL_FILE (file2);
5213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_str_equal (local1->filename, local2->filename);
5233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5253781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic const char *
526a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenmatch_prefix (const char *path,
527a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen              const char *prefix)
5283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int prefix_len;
5303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  prefix_len = strlen (prefix);
5323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (strncmp (path, prefix, prefix_len) != 0)
5333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return NULL;
534a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson
535a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson  /* Handle the case where prefix is the root, so that
536a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson   * the IS_DIR_SEPRARATOR check below works */
537a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson  if (prefix_len > 0 &&
538a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson      G_IS_DIR_SEPARATOR (prefix[prefix_len-1]))
539a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson    prefix_len--;
540a80b1120f1fa19cfb036e371313af8e73eaea049Alexander Larsson
5413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return path + prefix_len;
5423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5443781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
5456dc9b7ee0050c03e069d026c2c83136547a7d343Alexander Larssong_local_file_prefix_matches (GFile *parent,
5466dc9b7ee0050c03e069d026c2c83136547a7d343Alexander Larsson			     GFile *descendant)
5473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *parent_local = G_LOCAL_FILE (parent);
5493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *descendant_local = G_LOCAL_FILE (descendant);
5503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *remainder;
5513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  remainder = match_prefix (descendant_local->filename, parent_local->filename);
5533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
5543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return TRUE;
5553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return FALSE;
5563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5583781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
5593781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_relative_path (GFile *parent,
5603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				GFile *descendant)
5613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *parent_local = G_LOCAL_FILE (parent);
5633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *descendant_local = G_LOCAL_FILE (descendant);
5643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *remainder;
5653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  remainder = match_prefix (descendant_local->filename, parent_local->filename);
5673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (remainder != NULL && G_IS_DIR_SEPARATOR (*remainder))
5693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return g_strdup (remainder + 1);
5703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return NULL;
5713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5733781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFile *
574a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_resolve_relative_path (GFile      *file,
5753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				    const char *relative_path)
5763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
5783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *filename;
5793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFile *child;
5803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_path_is_absolute (relative_path))
582d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson    return _g_local_file_new (relative_path);
5833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  filename = g_build_filename (local->filename, relative_path, NULL);
585d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  child = _g_local_file_new (filename);
5863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (filename);
5873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return child;
5893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
5903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
5913781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileEnumerator *
592a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_enumerate_children (GFile                *file,
593a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 const char           *attributes,
594a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 GFileQueryInfoFlags   flags,
595a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 GCancellable         *cancellable,
596a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 GError              **error)
5973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
5983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
5993480685d4e5a022530a07464fc20d10b45b3b358Ross Burton  return _g_local_file_enumerator_new (local,
600d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson				       attributes, flags,
601d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson				       cancellable, error);
6023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
6033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
6043781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFile *
6053781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_get_child_for_display_name (GFile        *file,
6063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					 const char   *display_name,
6073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					 GError      **error)
6083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
609df719f749c9fa1f3966643eeba96eb5dd022b2caGrahame Bowland  GFile *new_file;
6103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *basename;
6113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
6123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  basename = g_filename_from_utf8 (display_name, -1, NULL, NULL, NULL);
6133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (basename == NULL)
6143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
6153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
6163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   G_IO_ERROR_INVALID_FILENAME,
6173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Invalid filename %s"), display_name);
6183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
6193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
6203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
6213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  new_file = g_file_get_child (file, basename);
6223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (basename);
6233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
6243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return new_file;
6253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
6263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
6273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef USE_STATFS
6283781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic const char *
6293781343738de4abddf56982325a77bd70a98cd26Alexander Larssonget_fs_type (long f_type)
6303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
6313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* filesystem ids taken from linux manpage */
632a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen  switch (f_type)
633a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    {
634a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xadf5:
635a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "adfs";
636a0c45852e1618b86ef6681b05333bb716febec56Matthias Clasen    case 0x5346414f:
637a0c45852e1618b86ef6681b05333bb716febec56Matthias Clasen      return "afs";
638a0c45852e1618b86ef6681b05333bb716febec56Matthias Clasen    case 0x0187:
639a0c45852e1618b86ef6681b05333bb716febec56Matthias Clasen      return "autofs";
640a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xADFF:
641a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "affs";
642a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x42465331:
643a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "befs";
644a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x1BADFACE:
645a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "bfs";
646f5483302757a9c03c43e25c86cea4a7bd5aaaf3fMatthias Clasen    case 0x9123683E:
647f5483302757a9c03c43e25c86cea4a7bd5aaaf3fMatthias Clasen      return "btrfs";
648a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xFF534D42:
649a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "cifs";
650a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x73757245:
651a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "coda";
652a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x012FF7B7:
653a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "coh";
654a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x28cd3d45:
655a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "cramfs";
656a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x1373:
657a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "devfs";
658a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x00414A53:
659a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "efs";
660a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x137D:
661a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "ext";
662a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xEF51:
663a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "ext2";
664a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xEF53:
66525ff8ee7486c7bdf1612d3554fc1d7d91daedfa6Matthias Clasen      return "ext3/ext4";
666a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x4244:
667a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "hfs";
668a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xF995E849:
669a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "hpfs";
670a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x958458f6:
671a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "hugetlbfs";
672a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x9660:
673a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "isofs";
674a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x72b6:
675a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "jffs2";
676a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x3153464a:
677a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "jfs";
678a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x137F:
679a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "minix";
680a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x138F:
681a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "minix2";
682a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x2468:
683a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "minix2";
684a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x2478:
685a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "minix22";
686a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x4d44:
687a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "msdos";
688a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x564c:
689a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "ncp";
690a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x6969:
691a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "nfs";
692a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x5346544e:
693a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "ntfs";
694a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x9fa1:
695a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "openprom";
696a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x9fa0:
697a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "proc";
698a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x002f:
699a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "qnx4";
700a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x52654973:
701a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "reiserfs";
702a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x7275:
703a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "romfs";
704a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x517B:
705a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "smb";
706f5483302757a9c03c43e25c86cea4a7bd5aaaf3fMatthias Clasen    case 0x73717368:
707f5483302757a9c03c43e25c86cea4a7bd5aaaf3fMatthias Clasen      return "squashfs";
708a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x012FF7B6:
709a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "sysv2";
710a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x012FF7B5:
711a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "sysv4";
712a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x01021994:
713a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "tmpfs";
714a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x15013346:
715a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "udf";
716a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x00011954:
717a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "ufs";
718a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x9fa2:
719a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "usbdevice";
720a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0xa501FCF5:
721a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "vxfs";
722a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x012FF7B4:
723a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "xenix";
724a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x58465342:
725a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "xfs";
726a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    case 0x012FD16D:
727a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return "xiafs";
728a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    default:
729a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      return NULL;
730a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    }
7313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
7323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
7333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
73483445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist#ifndef G_OS_WIN32
73583445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist
7363781343738de4abddf56982325a77bd70a98cd26Alexander LarssonG_LOCK_DEFINE_STATIC(mount_info_hash);
7373781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GHashTable *mount_info_hash = NULL;
73883445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqviststatic guint64 mount_info_hash_cache_time = 0;
7393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7403781343738de4abddf56982325a77bd70a98cd26Alexander Larssontypedef enum {
7413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  MOUNT_INFO_READONLY = 1<<0
7423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson} MountInfo;
7433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7443781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
7453781343738de4abddf56982325a77bd70a98cd26Alexander Larssondevice_equal (gconstpointer v1,
746a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen              gconstpointer v2)
7473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
74854300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen  return *(dev_t *)v1 == *(dev_t *)v2;
7493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
7503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7513781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic guint
752a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasendevice_hash (gconstpointer v)
7533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
7543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return (guint) *(dev_t *)v;
7553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
7563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7573781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
758a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenget_mount_info (GFileInfo             *fs_info,
759a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		const char            *path,
7603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		GFileAttributeMatcher *matcher)
7613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
7623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat buf;
7633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean got_info;
7643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gpointer info_as_ptr;
7653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  guint mount_info;
7663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *mountpoint;
7673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dev_t *dev;
7683ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GUnixMountEntry *mount;
7693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  guint64 cache_time;
7703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
771a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer  if (g_lstat (path, &buf) != 0)
7723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return;
7733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  G_LOCK (mount_info_hash);
7753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (mount_info_hash == NULL)
7773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    mount_info_hash = g_hash_table_new_full (device_hash, device_equal,
7783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					     g_free, NULL);
7793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_unix_mounts_changed_since (mount_info_hash_cache_time))
7823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    g_hash_table_remove_all (mount_info_hash);
7833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  got_info = g_hash_table_lookup_extended (mount_info_hash,
7853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   &buf.st_dev,
7863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   NULL,
7873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   &info_as_ptr);
7883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  G_UNLOCK (mount_info_hash);
7903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  mount_info = GPOINTER_TO_UINT (info_as_ptr);
7923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (!got_info)
7943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
7953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      mount_info = 0;
7963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
7973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      mountpoint = find_mountpoint_for (path, buf.st_dev);
7983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (mountpoint == NULL)
799d20bf1076b25fb436791e4ea9d656a8756d1cf61Cosimo Cecchi	mountpoint = g_strdup ("/");
8003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
801feb5258cf9ca9c3b3d9a58a98b1c6c75c822855aMatthias Clasen      mount = g_unix_mount_at (mountpoint, &cache_time);
8023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (mount)
8033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
8043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (g_unix_mount_is_readonly (mount))
8053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    mount_info |= MOUNT_INFO_READONLY;
8063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
8073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  g_unix_mount_free (mount);
8083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
8093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
810d20bf1076b25fb436791e4ea9d656a8756d1cf61Cosimo Cecchi      g_free (mountpoint);
811d20bf1076b25fb436791e4ea9d656a8756d1cf61Cosimo Cecchi
8123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      dev = g_new0 (dev_t, 1);
8133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      *dev = buf.st_dev;
8143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
8153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      G_LOCK (mount_info_hash);
8163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      mount_info_hash_cache_time = cache_time;
8173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_hash_table_insert (mount_info_hash, dev, GUINT_TO_POINTER (mount_info));
8183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      G_UNLOCK (mount_info_hash);
8193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
8203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
8213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (mount_info & MOUNT_INFO_READONLY)
82271768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson    g_file_info_set_attribute_boolean (fs_info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
8233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
8243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
82583445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist#endif
82683445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist
8271d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#ifdef G_OS_WIN32
8281d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8291d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonstatic gboolean
8301d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonis_xp_or_later (void)
8311d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson{
8321d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  static int result = -1;
8331d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8341d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  if (result == -1)
8351d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    {
836cc8adfaeb84d666aeb8afadb7501498a0c8970feTor Lillqvist#ifndef _MSC_VER
8371d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      OSVERSIONINFOEX ver_info = {0};
8381d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      DWORDLONG cond_mask = 0;
8391d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      int op = VER_GREATER_EQUAL;
8401d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8411d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      ver_info.dwOSVersionInfoSize = sizeof ver_info;
8421d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      ver_info.dwMajorVersion = 5;
8431d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      ver_info.dwMinorVersion = 1;
8441d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8451d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      VER_SET_CONDITION (cond_mask, VER_MAJORVERSION, op);
8461d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      VER_SET_CONDITION (cond_mask, VER_MINORVERSION, op);
8471d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8481d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      result = VerifyVersionInfo (&ver_info,
8491d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson				  VER_MAJORVERSION | VER_MINORVERSION,
8501d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson				  cond_mask) != 0;
851cc8adfaeb84d666aeb8afadb7501498a0c8970feTor Lillqvist#else
852cc8adfaeb84d666aeb8afadb7501498a0c8970feTor Lillqvist      result = ((DWORD)(LOBYTE (LOWORD (GetVersion ())))) >= 5;
853cc8adfaeb84d666aeb8afadb7501498a0c8970feTor Lillqvist#endif
8541d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    }
8551d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8561d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  return result;
8571d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson}
8581d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8591d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonstatic wchar_t *
8601d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonget_volume_for_path (const char *path)
8611d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson{
8621d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  long len;
8631d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wchar_t *wpath;
8641d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wchar_t *result;
8651d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
866801da1dfc1cf8f41be8a9e101c28b335af974f93Tor Lillqvist  wpath = g_utf8_to_utf16 (path, -1, NULL, NULL, NULL);
867801da1dfc1cf8f41be8a9e101c28b335af974f93Tor Lillqvist  result = g_new (wchar_t, MAX_PATH);
8681d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
869801da1dfc1cf8f41be8a9e101c28b335af974f93Tor Lillqvist  if (!GetVolumePathNameW (wpath, result, MAX_PATH))
8701d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    {
8711d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      char *msg = g_win32_error_message (GetLastError ());
8721d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      g_critical ("GetVolumePathName failed: %s", msg);
8731d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      g_free (msg);
8741d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      g_free (result);
8751d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      g_free (wpath);
8761d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      return NULL;
8771d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    }
8781d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8791d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  len = wcslen (result);
8801d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  if (len > 0 && result[len-1] != L'\\')
8811d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    {
8821d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      result = g_renew (wchar_t, result, len + 2);
8831d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      result[len] = L'\\';
8841d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      result[len + 1] = 0;
8851d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    }
8861d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8871d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  g_free (wpath);
8881d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  return result;
8891d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson}
8901d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8911d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonstatic char *
8921d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonfind_mountpoint_for (const char *file, dev_t dev)
8931d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson{
8941d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wchar_t *wpath;
8951d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  char *utf8_path;
8961d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
8971d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wpath = get_volume_for_path (file);
8981d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  if (!wpath)
8991d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    return NULL;
9001d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9011d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  utf8_path = g_utf16_to_utf8 (wpath, -1, NULL, NULL, NULL);
9021d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9031d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  g_free (wpath);
9041d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  return utf8_path;
9051d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson}
9061d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9071d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonstatic void
9081d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonget_filesystem_readonly (GFileInfo  *info,
9091d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson			 const char *path)
9101d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson{
9111d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wchar_t *rootdir;
9121d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9131d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  rootdir = get_volume_for_path (path);
9141d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9151d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  if (rootdir)
9161d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    {
9171d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      if (is_xp_or_later ())
9181d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson        {
9191d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson          DWORD flags;
9201d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson          if (GetVolumeInformationW (rootdir, NULL, 0, NULL, NULL, &flags, NULL, 0))
9211d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson	    g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY,
9221d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson					       (flags & FILE_READ_ONLY_VOLUME) != 0);
9231d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson        }
9241d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      else
9251d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson        {
9261d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson          if (GetDriveTypeW (rootdir) == DRIVE_CDROM)
9271d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson	    g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_FILESYSTEM_READONLY, TRUE);
9281d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson        }
9291d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    }
9301d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9311d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  g_free (rootdir);
9321d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson}
9331d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9341d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#endif /* G_OS_WIN32 */
9351d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
9363781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileInfo *
937a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_query_filesystem_info (GFile         *file,
938a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				    const char    *attributes,
939a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				    GCancellable  *cancellable,
940a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				    GError       **error)
9413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
9423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
9433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFileInfo *info;
944cc8adfaeb84d666aeb8afadb7501498a0c8970feTor Lillqvist  int statfs_result = 0;
9453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean no_size;
94683445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist#ifndef G_OS_WIN32
9473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  guint64 block_size;
94858e4b463431520d76ea750d31e14e38f8440c42esimon.zheng  const char *fstype;
9493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef USE_STATFS
9503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct statfs statfs_buffer;
9513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif defined(USE_STATVFS)
9523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct statvfs statfs_buffer;
9533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
95483445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist#endif
9553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFileAttributeMatcher *attribute_matcher;
9563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  no_size = FALSE;
9583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef USE_STATFS
9603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#if STATFS_ARGS == 2
9623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  statfs_result = statfs (local->filename, &statfs_buffer);
9633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif STATFS_ARGS == 4
9643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  statfs_result = statfs (local->filename, &statfs_buffer,
9653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			  sizeof (statfs_buffer), 0);
9663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
9673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  block_size = statfs_buffer.f_bsize;
9683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9690b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson  /* Many backends can't report free size (for instance the gvfs fuse
9700b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson     backend for backend not supporting this), and set f_bfree to 0,
9710b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson     but it can be 0 for real too. We treat the availible == 0 and
9720b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson     free == 0 case as "both of these are invalid".
9733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson   */
9740b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson#ifndef G_OS_WIN32
9750b9f24c1e15254da8e105c88290b4d53976e6d0eAlexander Larsson  if (statfs_buffer.f_bavail == 0 && statfs_buffer.f_bfree == 0)
9763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    no_size = TRUE;
9773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
9783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#elif defined(USE_STATVFS)
9803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  statfs_result = statvfs (local->filename, &statfs_buffer);
9813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  block_size = statfs_buffer.f_frsize;
9823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
9833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (statfs_result == -1)
9853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
98637ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
98737ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
9883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
98937ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
9903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Error getting filesystem info: %s"),
99137ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
9923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
9933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
9943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  info = g_file_info_new ();
9963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
9973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  attribute_matcher = g_file_attribute_matcher_new (attributes);
9983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
999a30f8df3c8bbfa877ec607a82b9057b4a3dd11b8Matthias Clasen  if (!no_size &&
1000a30f8df3c8bbfa877ec607a82b9057b4a3dd11b8Matthias Clasen      g_file_attribute_matcher_matches (attribute_matcher,
100171768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson					G_FILE_ATTRIBUTE_FILESYSTEM_FREE))
1002a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    {
1003a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
1004a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      gchar *localdir = g_path_get_dirname (local->filename);
1005a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
1006a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      ULARGE_INTEGER li;
1007a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
1008a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      g_free (localdir);
1009a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      if (GetDiskFreeSpaceExW (wdirname, &li, NULL, NULL))
101071768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson        g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, (guint64)li.QuadPart);
1011a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      g_free (wdirname);
1012a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#else
101371768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson      g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_FREE, block_size * statfs_buffer.f_bavail);
1014a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
1015a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    }
1016a30f8df3c8bbfa877ec607a82b9057b4a3dd11b8Matthias Clasen  if (!no_size &&
1017a30f8df3c8bbfa877ec607a82b9057b4a3dd11b8Matthias Clasen      g_file_attribute_matcher_matches (attribute_matcher,
101871768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson					G_FILE_ATTRIBUTE_FILESYSTEM_SIZE))
1019a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    {
1020a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
1021a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      gchar *localdir = g_path_get_dirname (local->filename);
1022a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      wchar_t *wdirname = g_utf8_to_utf16 (localdir, -1, NULL, NULL, NULL);
1023a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      ULARGE_INTEGER li;
1024a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
1025a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      g_free (localdir);
1026a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      if (GetDiskFreeSpaceExW (wdirname, NULL, &li, NULL))
102771768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson        g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE,  (guint64)li.QuadPart);
1028a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      g_free (wdirname);
1029a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#else
103071768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson      g_file_info_set_attribute_uint64 (info, G_FILE_ATTRIBUTE_FILESYSTEM_SIZE, block_size * statfs_buffer.f_blocks);
1031a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
1032a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    }
10333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef USE_STATFS
10347437486b3613a6bdf7f73334a4c4ceaf4539d8f8Alexander Larsson#if defined(HAVE_STRUCT_STATFS_F_FSTYPENAME)
10353cacbe8178316e0c98c12231b18e032818178497Alexander Larsson  fstype = g_strdup(statfs_buffer.f_fstypename);
10363cacbe8178316e0c98c12231b18e032818178497Alexander Larsson#else
10373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  fstype = get_fs_type (statfs_buffer.f_type);
10383cacbe8178316e0c98c12231b18e032818178497Alexander Larsson#endif
103958e4b463431520d76ea750d31e14e38f8440c42esimon.zheng
104058e4b463431520d76ea750d31e14e38f8440c42esimon.zheng#elif defined(USE_STATVFS) && defined(HAVE_STRUCT_STATVFS_F_BASETYPE)
104158e4b463431520d76ea750d31e14e38f8440c42esimon.zheng  fstype = g_strdup(statfs_buffer.f_basetype);
104258e4b463431520d76ea750d31e14e38f8440c42esimon.zheng#endif
104358e4b463431520d76ea750d31e14e38f8440c42esimon.zheng
104458e4b463431520d76ea750d31e14e38f8440c42esimon.zheng#ifndef G_OS_WIN32
10453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (fstype &&
10463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_file_attribute_matcher_matches (attribute_matcher,
104771768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson					G_FILE_ATTRIBUTE_FILESYSTEM_TYPE))
104871768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson    g_file_info_set_attribute_string (info, G_FILE_ATTRIBUTE_FILESYSTEM_TYPE, fstype);
10493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
10503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
10513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_file_attribute_matcher_matches (attribute_matcher,
105271768c8426f0d6c580368f6c1d3fc339d2041be0Alexander Larsson					G_FILE_ATTRIBUTE_FILESYSTEM_READONLY))
10533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
1054a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
10551d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      get_filesystem_readonly (info, local->filename);
1056a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#else
10573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      get_mount_info (info, local->filename, attribute_matcher);
1058a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
10593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
10603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
10613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_matcher_unref (attribute_matcher);
10623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
10633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return info;
10643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
10653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
10663ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthenstatic GMount *
10673ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeutheng_local_file_find_enclosing_mount (GFile         *file,
10683ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                   GCancellable  *cancellable,
10693ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen                                   GError       **error)
10703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
10713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
10723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat buf;
10733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *mountpoint;
10743ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  GMount *mount;
10753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1076a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer  if (g_lstat (local->filename, &buf) != 0)
10773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
10789c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
10798b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		      /* Translators: This is an error message when trying to
10808b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		       * find the enclosing (user visible) mount of a file, but
10818b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		       * none exists. */
10828b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		      _("Containing mount does not exist"));
10833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
10843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
10853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
10863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  mountpoint = find_mountpoint_for (local->filename, buf.st_dev);
10873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (mountpoint == NULL)
10883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
10899c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
10908b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		      /* Translators: This is an error message when trying to
10918b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		       * find the enclosing (user visible) mount of a file, but
10928b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		       * none exists. */
10938b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		      _("Containing mount does not exist"));
10943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
10953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
10963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1097c4e3cfbf4070d9bf255d08e23591e8a8dc476d72Alexander Larsson  mount = _g_mount_get_for_mount_path (mountpoint, cancellable);
10983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (mountpoint);
10993ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  if (mount)
11003ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen    return mount;
11013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11029c17697b56501d11b4c653432cc9e290347aa03eChristian Persch  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND,
11038b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		  /* Translators: This is an error message when trying to find
11048b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		   * the enclosing (user visible) mount of a file, but none
11058b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		   * exists. */
11068b294f1f9d4588f6ad68a61546d0e7391b3f09cfWouter Bolsterlee		  _("Containing mount does not exist"));
11073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return NULL;
11083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
11093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11103781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFile *
1111a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_set_display_name (GFile         *file,
1112a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			       const char    *display_name,
1113a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			       GCancellable  *cancellable,
1114a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			       GError       **error)
11153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
11163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local, *new_local;
11173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFile *new_file, *parent;
11183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat statbuf;
11193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int errsv;
11203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  parent = g_file_get_parent (file);
11223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (parent == NULL)
11233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
11249c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR,
11259c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           G_IO_ERROR_FAILED,
11269c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           _("Can't rename root directory"));
11273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
11283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
11293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
113054300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen  new_file = g_file_get_child_for_display_name (parent, display_name, error);
11313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_object_unref (parent);
11323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (new_file == NULL)
11343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return NULL;
11353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  local = G_LOCAL_FILE (file);
11363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  new_local = G_LOCAL_FILE (new_file);
11373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1138d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen  if (g_lstat (new_local->filename, &statbuf) == -1)
1139d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen    {
1140d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen      errsv = errno;
1141d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen
1142d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen      if (errsv != ENOENT)
1143d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen        {
1144d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen	  g_set_error (error, G_IO_ERROR,
1145d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen		       g_io_error_from_errno (errsv),
1146d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen		       _("Error renaming file: %s"),
1147d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen		       g_strerror (errsv));
1148d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen          return NULL;
1149d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen        }
1150d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen    }
1151d4d876846e62b613a1e5b80519e4a9a49eb905dcMatthias Clasen  else
11523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
11539c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR,
11549c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           G_IO_ERROR_EXISTS,
11559c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           _("Can't rename file, filename already exist"));
11563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
11573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
11583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11593b1b6a9722f40495762fbb115a43b39d495c3170Alexander Larsson  if (g_rename (local->filename, new_local->filename) == -1)
11603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
11613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      errsv = errno;
11623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (errsv == EINVAL)
11643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	/* We can't get a rename file into itself error herer,
11653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	   so this must be an invalid filename, on e.g. FAT */
11669c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	g_set_error_literal (error, G_IO_ERROR,
11679c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             G_IO_ERROR_INVALID_FILENAME,
11689c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             _("Invalid filename"));
11693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
11703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_set_error (error, G_IO_ERROR,
11713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_io_error_from_errno (errsv),
11723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     _("Error renaming file: %s"),
11733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_strerror (errsv));
11743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_object_unref (new_file);
11753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
11763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
11773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return new_file;
11793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
11803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11813781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileInfo *
11823781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_query_info (GFile                *file,
11833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			 const char           *attributes,
11843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			 GFileQueryInfoFlags   flags,
11853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			 GCancellable         *cancellable,
11863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			 GError              **error)
11873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
11883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
11893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFileInfo *info;
11903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GFileAttributeMatcher *matcher;
11913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *basename, *dirname;
11923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalParentFileInfo parent_info;
11933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  matcher = g_file_attribute_matcher_new (attributes);
11953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  basename = g_path_get_basename (local->filename);
11973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
11983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dirname = g_path_get_dirname (local->filename);
11993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  _g_local_file_info_get_parent_info (dirname, matcher, &parent_info);
12003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (dirname);
12013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  info = _g_local_file_info_get (basename, local->filename,
12033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				 matcher, flags, &parent_info,
12043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson				 error);
12053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (basename);
12073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_attribute_matcher_unref (matcher);
12093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return info;
12113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
12123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12133781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileAttributeInfoList *
1214a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_query_settable_attributes (GFile         *file,
1215a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen					GCancellable  *cancellable,
1216a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen					GError       **error)
12173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
12183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_file_attribute_info_list_ref (local_writable_attributes);
12193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
12203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12213781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileAttributeInfoList *
1222a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_query_writable_namespaces (GFile         *file,
1223a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen					GCancellable  *cancellable,
1224a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen					GError       **error)
12253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
12263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_file_attribute_info_list_ref (local_writable_namespaces);
12273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
12283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12293781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
123054300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Claseng_local_file_set_attribute (GFile                *file,
123154300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    const char           *attribute,
123254300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    GFileAttributeType    type,
123354300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    gpointer              value_p,
123454300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    GFileQueryInfoFlags   flags,
123554300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    GCancellable         *cancellable,
123654300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen			    GError              **error)
12373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
12383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
12393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return _g_local_file_info_set_attribute (local->filename,
12413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   attribute,
1242f5063650794c987868830241a630993e624eabd9Alexander Larsson					   type,
1243f5063650794c987868830241a630993e624eabd9Alexander Larsson					   value_p,
12443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   flags,
12453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   cancellable,
12463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   error);
12473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
12483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12493781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
1250a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_set_attributes_from_info (GFile                *file,
1251a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				       GFileInfo            *info,
1252a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				       GFileQueryInfoFlags   flags,
1253a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				       GCancellable         *cancellable,
1254a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				       GError              **error)
12553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
12563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
12573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int res, chained_res;
125854300dde6d77867aa53e60a2bdfd69cb9e644315Matthias Clasen  GFileIface *default_iface;
12593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  res = _g_local_file_info_set_attributes (local->filename,
12613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   info, flags,
12623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   cancellable,
12633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson					   error);
12643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (!res)
12663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    error = NULL; /* Don't write over error if further errors */
12673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  default_iface = g_type_default_interface_peek (G_TYPE_FILE);
12693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  chained_res = (default_iface->set_attributes_from_info) (file, info, flags, cancellable, error);
12713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return res && chained_res;
12733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
12743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12753781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileInputStream *
1276a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_read (GFile         *file,
1277a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GCancellable  *cancellable,
1278a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GError       **error)
12793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
12803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
12813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int fd;
12823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat buf;
12833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1284b221d1b36d0ed5ce22f21a986a352f6a92345c30Alexander Larsson  fd = g_open (local->filename, O_RDONLY|O_BINARY, 0);
12853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (fd == -1)
12863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
128737ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
128837ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
12893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
129037ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
12913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Error opening file: %s"),
129237ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
12933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
12943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
12953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
12963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (fstat(fd, &buf) == 0 && S_ISDIR (buf.st_mode))
12973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
12983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      close (fd);
12999c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR,
13009c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           G_IO_ERROR_IS_DIRECTORY,
13019c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           _("Can't open directory"));
13023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
13033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
13043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1305d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  return _g_local_file_input_stream_new (fd);
13063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
13073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13083781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileOutputStream *
1309a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_append_to (GFile             *file,
1310a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			GFileCreateFlags   flags,
1311a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			GCancellable      *cancellable,
1312a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			GError           **error)
13133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1314d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  return _g_local_file_output_stream_append (G_LOCAL_FILE (file)->filename,
1315d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson					     flags, cancellable, error);
13163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
13173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13183781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileOutputStream *
1319a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_create (GFile             *file,
1320a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     GFileCreateFlags   flags,
1321a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     GCancellable      *cancellable,
1322a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     GError           **error)
13233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1324d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  return _g_local_file_output_stream_create (G_LOCAL_FILE (file)->filename,
1325d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson					     flags, cancellable, error);
13263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
13273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13283781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileOutputStream *
1329a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_replace (GFile             *file,
1330a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		      const char        *etag,
1331a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		      gboolean           make_backup,
1332a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		      GFileCreateFlags   flags,
1333a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		      GCancellable      *cancellable,
1334a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		      GError           **error)
13353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
1336d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson  return _g_local_file_output_stream_replace (G_LOCAL_FILE (file)->filename,
1337d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson					      etag, make_backup, flags,
1338d9594f5709313d6e7a8a4f3e5f3b23fc72017417Alexander Larsson					      cancellable, error);
13393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
13403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13423781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
1343a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_delete (GFile         *file,
1344a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     GCancellable  *cancellable,
1345a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		     GError       **error)
13463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
13473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
13483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_remove (local->filename) == -1)
13503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
135137ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
135237ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
1353f0e54fd3280ab55f6226c4baba07047494db5885Alexander Larsson      /* Posix allows EEXIST too, but the more sane error
1354f5483302757a9c03c43e25c86cea4a7bd5aaaf3fMatthias Clasen	 is G_IO_ERROR_NOT_FOUND, and it's what nautilus
1355f0e54fd3280ab55f6226c4baba07047494db5885Alexander Larsson	 expects */
1356f0e54fd3280ab55f6226c4baba07047494db5885Alexander Larsson      if (errsv == EEXIST)
1357f0e54fd3280ab55f6226c4baba07047494db5885Alexander Larsson	errsv = ENOTEMPTY;
1358f0e54fd3280ab55f6226c4baba07047494db5885Alexander Larsson
13593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
136037ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
13613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Error removing file: %s"),
136237ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
13633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
13643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
13653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
13673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
13683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13693781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
13703781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstrip_trailing_slashes (const char *path)
13713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
13723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *path_copy;
13733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int len;
13743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  path_copy = g_strdup (path);
13763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  len = strlen (path_copy);
13773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (len > 1 && path_copy[len-1] == '/')
13783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    path_copy[--len] = 0;
13793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return path_copy;
13813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson }
13823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
13833781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
13843781343738de4abddf56982325a77bd70a98cd26Alexander Larssonexpand_symlink (const char *link)
13853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
13863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *resolved, *canonical, *parent, *link2;
13873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char symlink_value[4096];
1388a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
1389a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#else
13903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  ssize_t res;
1391a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
13923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1393a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#ifdef G_OS_WIN32
1394a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#else
13953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  res = readlink (link, symlink_value, sizeof (symlink_value) - 1);
1396a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
13973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (res == -1)
13983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return g_strdup (link);
13993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  symlink_value[res] = 0;
1400a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer#endif
14013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_path_is_absolute (symlink_value))
14033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return canonicalize_filename (symlink_value);
14043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
14053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
14063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      link2 = strip_trailing_slashes (link);
14073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      parent = g_path_get_dirname (link2);
14083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (link2);
14093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      resolved = g_build_filename (parent, symlink_value, NULL);
14113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (parent);
14123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      canonical = canonicalize_filename (resolved);
14143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (resolved);
14163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return canonical;
14183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
14193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
14203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14213781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
1422a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenget_parent (const char *path,
1423a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen            dev_t      *parent_dev)
14243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
14253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *parent, *tmp;
14263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat parent_stat;
14273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int num_recursions;
14283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *path_copy;
14293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  path_copy = strip_trailing_slashes (path);
14313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  parent = g_path_get_dirname (path_copy);
14333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (strcmp (parent, ".") == 0 ||
14343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      strcmp (parent, path_copy) == 0)
14353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
1436fe68fc74964a8bc79db8406a2f5efb823daaf25eAlexander Larsson      g_free (parent);
14373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (path_copy);
14383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return NULL;
14393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
14403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (path_copy);
14413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  num_recursions = 0;
14433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  do {
14443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    if (g_lstat (parent, &parent_stat) != 0)
14453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      {
14463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_free (parent);
14473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	return NULL;
14483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      }
14493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    if (S_ISLNK (parent_stat.st_mode))
14513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      {
14523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	tmp = parent;
14533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	parent = expand_symlink (parent);
14543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_free (tmp);
14553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      }
14563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    num_recursions++;
14583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    if (num_recursions > 12)
14593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      {
14603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_free (parent);
14613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	return NULL;
14623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      }
14633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  } while (S_ISLNK (parent_stat.st_mode));
14643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  *parent_dev = parent_stat.st_dev;
14663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return parent;
14683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
14693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14703781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
14713781343738de4abddf56982325a77bd70a98cd26Alexander Larssonexpand_all_symlinks (const char *path)
14723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
14733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *parent, *parent_expanded;
14743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *basename, *res;
14753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dev_t parent_dev;
14763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  parent = get_parent (path, &parent_dev);
14783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (parent)
14793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
14803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      parent_expanded = expand_all_symlinks (parent);
14813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (parent);
14823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      basename = g_path_get_basename (path);
14833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      res = g_build_filename (parent_expanded, basename, NULL);
14843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (basename);
14853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (parent_expanded);
14863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
14873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
14883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    res = g_strdup (path);
14893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return res;
14913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
14923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
14931d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#ifndef G_OS_WIN32
14941d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
14953781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
1496a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenfind_mountpoint_for (const char *file,
1497a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                     dev_t       dev)
14983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
14993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *dir, *parent;
15003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dev_t dir_dev, parent_dev;
15013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dir = g_strdup (file);
15033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dir_dev = dev;
15043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1505a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen  while (1)
1506a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    {
1507a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      parent = get_parent (dir, &parent_dev);
1508a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      if (parent == NULL)
1509a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen        return dir;
15103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1511a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      if (parent_dev != dir_dev)
1512a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen        {
1513a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen          g_free (parent);
1514a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen          return dir;
1515a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen        }
15163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1517a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      g_free (dir);
1518a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen      dir = parent;
1519a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen    }
15203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
15213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15223781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
15233781343738de4abddf56982325a77bd70a98cd26Alexander Larssonfind_topdir_for (const char *file)
15243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
15253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *dir;
15263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dev_t dir_dev;
15273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dir = get_parent (file, &dir_dev);
15293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (dir == NULL)
15303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return NULL;
15313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return find_mountpoint_for (dir, dir_dev);
15333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
15343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15353781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
1536a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenget_unique_filename (const char *basename,
1537a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                     int         id)
15383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
15393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *dot;
15403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (id == 1)
15423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return g_strdup (basename);
15433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  dot = strchr (basename, '.');
15453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (dot)
1546e4d018f1ddac53ac6f6161c8bb20bddf2c0f220fDan Winship    return g_strdup_printf ("%.*s.%d%s", (int)(dot - basename), basename, id, dot);
15473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
15483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return g_strdup_printf ("%s.%d", basename, id);
15493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
15503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15513781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
1552a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasenpath_has_prefix (const char *path,
1553a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                 const char *prefix)
15543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
15553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int prefix_len;
15563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (prefix == NULL)
15583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return TRUE;
15593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  prefix_len = strlen (prefix);
15613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (strncmp (path, prefix, prefix_len) == 0 &&
15633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      (prefix_len == 0 || /* empty prefix always matches */
15643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson       prefix[prefix_len - 1] == '/' || /* last char in prefix was a /, so it must be in path too */
15653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson       path[prefix_len] == 0 ||
15663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson       path[prefix_len] == '/'))
15673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return TRUE;
15683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return FALSE;
15703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
15713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15723781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
1573a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasentry_make_relative (const char *path,
1574a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen                   const char *base)
15753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
15763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *path2, *base2;
15773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *relative;
15783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  path2 = expand_all_symlinks (path);
15803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  base2 = expand_all_symlinks (base);
15813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  relative = NULL;
15833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (path_has_prefix (path2, base2))
15843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
15853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      relative = path2 + strlen (base2);
15863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      while (*relative == '/')
15873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	relative ++;
15883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      relative = g_strdup (relative);
15893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
15903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (path2);
15913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (base2);
15923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (relative)
15943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    return relative;
15953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
15963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Failed, use abs path */
15973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_strdup (path);
15983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
15993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16003781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic char *
16013781343738de4abddf56982325a77bd70a98cd26Alexander Larssonescape_trash_name (char *name)
16023781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
16033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GString *str;
16043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const gchar hex[16] = "0123456789ABCDEF";
16053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  str = g_string_new ("");
16073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  while (*name != 0)
16093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
16103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      char c;
16113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      c = *name++;
16133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (g_ascii_isprint (c))
16153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_string_append_c (str, c);
16163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
16173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
16183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_string_append_c (str, '%');
16193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_string_append_c (str, hex[((guchar)c) >> 4]);
16203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_string_append_c (str, hex[((guchar)c) & 0xf]);
16213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
16223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
16233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
16243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return g_string_free (str, FALSE);
16253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
16263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1627c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larssongboolean
1628c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson_g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
1629c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson{
163067b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen  static gsize home_dev_set = 0;
163167b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen  static dev_t home_dev;
1632c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  char *topdir, *globaldir, *trashdir, *tmpname;
1633c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  uid_t uid;
1634c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  char uid_str[32];
1635c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  struct stat global_stat, trash_stat;
1636c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  gboolean res;
1637c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  int statres;
1638c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
163967b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen  if (g_once_init_enter (&home_dev_set))
1640c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    {
1641c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      struct stat home_stat;
1642c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1643c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      g_stat (g_get_home_dir (), &home_stat);
164467b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen      home_dev = home_stat.st_dev;
164567b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen      g_once_init_leave (&home_dev_set, 1);
1646c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    }
1647c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1648c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  /* Assume we can trash to the home */
164967b2f9a99b3c6c060914633bff3e494d94d2a0f6Matthias Clasen  if (dir_dev == home_dev)
1650c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    return TRUE;
1651c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1652c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  topdir = find_mountpoint_for (dirname, dir_dev);
1653c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  if (topdir == NULL)
1654c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    return FALSE;
1655c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1656c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  globaldir = g_build_filename (topdir, ".Trash", NULL);
1657c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  statres = g_lstat (globaldir, &global_stat);
1658c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson if (g_lstat (globaldir, &global_stat) == 0 &&
1659c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      S_ISDIR (global_stat.st_mode) &&
1660c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      (global_stat.st_mode & S_ISVTX) != 0)
1661c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    {
1662c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      /* got a toplevel sysadmin created dir, assume we
1663c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson       * can trash to it (we should be able to create a dir)
1664c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson       * This fails for the FAT case where the ownership of
1665c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson       * that dir would be wrong though..
1666c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson       */
1667c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      g_free (globaldir);
1668c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      g_free (topdir);
1669c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      return TRUE;
1670c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    }
1671c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  g_free (globaldir);
1672c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1673c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  /* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */
1674c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  uid = geteuid ();
1675c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long) uid);
1676c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1677c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  tmpname = g_strdup_printf (".Trash-%s", uid_str);
1678c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  trashdir = g_build_filename (topdir, tmpname, NULL);
1679c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  g_free (tmpname);
1680c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1681c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  if (g_lstat (trashdir, &trash_stat) == 0)
1682c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    {
1683c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      g_free (topdir);
1684c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      g_free (trashdir);
1685c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson      return
1686c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson	S_ISDIR (trash_stat.st_mode) &&
1687c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson	trash_stat.st_uid == uid;
1688c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson    }
1689c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  g_free (trashdir);
1690c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1691c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  /* User specific trash didn't exist, can we create it? */
1692c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  res = g_access (topdir, W_OK) == 0;
1693c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1694c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  g_free (topdir);
1695c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1696c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson  return res;
1697c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson}
1698c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
1699c5a10d2650e11b9a700b605640a41275a4ee1a5dAlexander Larsson
17003781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
1701a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_trash (GFile         *file,
1702a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		    GCancellable  *cancellable,
1703a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		    GError       **error)
17043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
17053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
170683445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist  struct stat file_stat, home_stat;
17073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  const char *homedir;
170883445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist  char *trashdir, *topdir, *infodir, *filesdir;
17093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *basename, *trashname, *trashfile, *infoname, *infofile;
17103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *original_name, *original_name_escaped;
17113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int i;
17123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *data;
17133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean is_homedir_trash;
17143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char delete_time[32];
17153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int fd;
171683445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist  struct stat trash_stat, global_stat;
171783445755b3b2d315feadf94cefbb74afc8f142bdTor Lillqvist  char *dirname, *globaldir;
17183781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_lstat (local->filename, &file_stat) != 0)
17203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
172137ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
172237ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
17233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
172437ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
17253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Error trashing file: %s"),
172637ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
17273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
17283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
17293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  homedir = g_get_home_dir ();
17313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_stat (homedir, &home_stat);
17323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17333781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  is_homedir_trash = FALSE;
17343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  trashdir = NULL;
17353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (file_stat.st_dev == home_stat.st_dev)
17363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
17373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      is_homedir_trash = TRUE;
17383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      errno = 0;
17393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      trashdir = g_build_filename (g_get_user_data_dir (), "Trash", NULL);
17403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (g_mkdir_with_parents (trashdir, 0700) < 0)
17413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
17423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          char *display_name;
174337ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch          int errsv = errno;
17443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          display_name = g_filename_display_name (trashdir);
17463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_set_error (error, G_IO_ERROR,
174737ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch                       g_io_error_from_errno (errsv),
17483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson                       _("Unable to create trash dir %s: %s"),
174937ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch                       display_name, g_strerror (errsv));
17503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_free (display_name);
17513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          g_free (trashdir);
17523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson          return FALSE;
17533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
17543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      topdir = g_strdup (g_get_user_data_dir ());
17553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
17563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
17573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
1758a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      uid_t uid;
1759a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer      char uid_str[32];
1760a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer
17613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      uid = geteuid ();
17623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_snprintf (uid_str, sizeof (uid_str), "%lu", (unsigned long)uid);
17633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      topdir = find_topdir_for (local->filename);
17653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (topdir == NULL)
17663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
17679c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	  g_set_error_literal (error, G_IO_ERROR,
17689c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR_NOT_SUPPORTED,
17699c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               _("Unable to find toplevel directory for trash"));
17703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  return FALSE;
17713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
17723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      /* Try looking for global trash dir $topdir/.Trash/$uid */
17743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      globaldir = g_build_filename (topdir, ".Trash", NULL);
17753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (g_lstat (globaldir, &global_stat) == 0 &&
17763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  S_ISDIR (global_stat.st_mode) &&
17773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  (global_stat.st_mode & S_ISVTX) != 0)
17783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
17793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  trashdir = g_build_filename (globaldir, uid_str, NULL);
17803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (g_lstat (trashdir, &trash_stat) == 0)
17823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
17833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      if (!S_ISDIR (trash_stat.st_mode) ||
17843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  trash_stat.st_uid != uid)
17853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		{
17863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  /* Not a directory or not owned by user, ignore */
17873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  g_free (trashdir);
17883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  trashdir = NULL;
17893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		}
17903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
17913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  else if (g_mkdir (trashdir, 0700) == -1)
17923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
17933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      g_free (trashdir);
17943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      trashdir = NULL;
17953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
17963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
17973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (globaldir);
17983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
17993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (trashdir == NULL)
18003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
1801218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	  gboolean tried_create;
1802218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson
18033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  /* No global trash dir, or it failed the tests, fall back to $topdir/.Trash-$uid */
18043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  dirname = g_strdup_printf (".Trash-%s", uid_str);
18053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  trashdir = g_build_filename (topdir, dirname, NULL);
18063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  g_free (dirname);
1807218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson
1808218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	  tried_create = FALSE;
1809218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson
1810218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	retry:
18113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (g_lstat (trashdir, &trash_stat) == 0)
18123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
18133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      if (!S_ISDIR (trash_stat.st_mode) ||
18143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  trash_stat.st_uid != uid)
18153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		{
1816218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  /* Remove the failed directory */
1817218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  if (tried_create)
1818218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		    g_remove (trashdir);
1819218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson
18203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  /* Not a directory or not owned by user, ignore */
18213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  g_free (trashdir);
18223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		  trashdir = NULL;
18233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		}
18243781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
1825218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	  else
18263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
1827218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	      if (!tried_create &&
1828218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  g_mkdir (trashdir, 0700) != -1)
1829218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		{
1830218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  /* Ensure that the created dir has the right uid etc.
1831218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		     This might fail on e.g. a FAT dir */
1832218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  tried_create = TRUE;
1833218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  goto retry;
1834218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		}
1835218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson	      else
1836218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		{
1837218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  g_free (trashdir);
1838218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		  trashdir = NULL;
1839218573323514fc0d69929fa0d92a523c254a474eAlexander Larsson		}
18403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
18413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
18423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (trashdir == NULL)
18443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
18453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  g_free (topdir);
18469c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	  g_set_error_literal (error, G_IO_ERROR,
18479c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR_NOT_SUPPORTED,
18489c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               _("Unable to find or create trash directory"));
18493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  return FALSE;
18503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
18513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
18523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Trashdir points to the trash dir with the "info" and "files" subdirectories */
18543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  infodir = g_build_filename (trashdir, "info", NULL);
18563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  filesdir = g_build_filename (trashdir, "files", NULL);
18573781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (trashdir);
18583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Make sure we have the subdirectories */
18603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if ((g_mkdir (infodir, 0700) == -1 && errno != EEXIST) ||
18613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      (g_mkdir (filesdir, 0700) == -1 && errno != EEXIST))
18623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
18633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (topdir);
18643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (infodir);
18653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (filesdir);
18669c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR,
18679c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           G_IO_ERROR_NOT_SUPPORTED,
18689c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                           _("Unable to find or create trash directory"));
18693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
18703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
18713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  basename = g_path_get_basename (local->filename);
18733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  i = 1;
18743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  trashname = NULL;
18753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  infofile = NULL;
18763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  do {
18773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    g_free (trashname);
18783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    g_free (infofile);
18793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    trashname = get_unique_filename (basename, i++);
18813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    infoname = g_strconcat (trashname, ".trashinfo", NULL);
18823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    infofile = g_build_filename (infodir, infoname, NULL);
18833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    g_free (infoname);
18843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    fd = open (infofile, O_CREAT | O_EXCL, 0666);
18863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  } while (fd == -1 && errno == EEXIST);
18873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (basename);
18893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (infodir);
18903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
18913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (fd == -1)
18923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
189337ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
189437ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
18953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (filesdir);
18963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (topdir);
18973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (trashname);
18983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (infofile);
18993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19003781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
190137ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
1902af7645a49815d6427242d858ca779ce6bd5bb377Matthias Clasen		   _("Unable to create trashing info file: %s"),
190337ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
19043781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
19053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
19063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  close (fd);
19083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19093781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* TODO: Maybe we should verify that you can delete the file from the trash
19103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson     before moving it? OTOH, that is hard, as it needs a recursive scan */
19113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  trashfile = g_build_filename (filesdir, trashname, NULL);
19133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19143781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (filesdir);
19153781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19163781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (g_rename (local->filename, trashfile) == -1)
19173781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
191837ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
191937ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
19203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (topdir);
19213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (trashname);
19223781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (infofile);
19233781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (trashfile);
19241ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson
19251ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson      if (errsv == EXDEV)
19261ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson	/* The trash dir was actually on another fs anyway!?
19271ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson	   This can happen when the same device is mounted multiple
19281ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson	   times, or with bind mounts of the same fs. */
19291ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson	g_set_error (error, G_IO_ERROR,
19301ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     G_IO_ERROR_NOT_SUPPORTED,
19311ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     _("Unable to trash file: %s"),
19321ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     g_strerror (errsv));
19331ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson      else
19341ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson	g_set_error (error, G_IO_ERROR,
19351ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     g_io_error_from_errno (errsv),
19361ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     _("Unable to trash file: %s"),
19371ce74b0dd34222b201369e5aff53b27182db7b66Alexander Larsson		     g_strerror (errsv));
19383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
19393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
19403781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (trashfile);
19423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* TODO: Do we need to update mtime/atime here after the move? */
19443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Use absolute names for homedir */
19463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (is_homedir_trash)
19473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    original_name = g_strdup (local->filename);
19483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  else
19493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    original_name = try_make_relative (local->filename, topdir);
19503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  original_name_escaped = escape_trash_name (original_name);
19513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (original_name);
19533781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (topdir);
19543781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
1955a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer  {
1956a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    time_t t;
1957a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    struct tm now;
1958a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    t = time (NULL);
1959a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    localtime_r (&t, &now);
1960a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    delete_time[0] = 0;
1961a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer    strftime(delete_time, sizeof (delete_time), "%Y-%m-%dT%H:%M:%S", &now);
1962a33f8a7564cc649daf0dca0d67daac8430808cf9Hans Breuer  }
19633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  data = g_strdup_printf ("[Trash Info]\nPath=%s\nDeletionDate=%s\n",
19653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson			  original_name_escaped, delete_time);
19663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_file_set_contents (infofile, data, -1, NULL);
19683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (infofile);
19693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (data);
19703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (original_name_escaped);
19723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  g_free (trashname);
19733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
19743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
19753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
19761d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#else /* G_OS_WIN32 */
19775fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvistgboolean
19785fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvist_g_local_file_has_trash_dir (const char *dirname, dev_t dir_dev)
19795fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvist{
19805fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvist  return FALSE;			/* XXX ??? */
19815fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvist}
19825fe2e21960a2005ff0347266d4bd7aebf277456eTor Lillqvist
19831d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssonstatic gboolean
19841d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larssong_local_file_trash (GFile         *file,
19851d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		    GCancellable  *cancellable,
19861d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		    GError       **error)
19871d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson{
19881d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
19891d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  SHFILEOPSTRUCTW op = {0};
19901d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  gboolean success;
19911d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wchar_t *wfilename;
19921d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  long len;
19931d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
19941d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wfilename = g_utf8_to_utf16 (local->filename, -1, NULL, &len, NULL);
19951d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  /* SHFILEOPSTRUCT.pFrom is double-zero-terminated */
19961d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wfilename = g_renew (wchar_t, wfilename, len + 2);
19971d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  wfilename[len + 1] = 0;
19981d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
19991d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  op.wFunc = FO_DELETE;
20001d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  op.pFrom = wfilename;
20011d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  op.fFlags = FOF_ALLOWUNDO;
20021d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
20031d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  success = SHFileOperationW (&op) == 0;
20041d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
20051d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  if (success && op.fAnyOperationsAborted)
20061d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    {
20071d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      if (cancellable && !g_cancellable_is_cancelled (cancellable))
20081d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson	g_cancellable_cancel (cancellable);
20091d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      g_set_error (error, G_IO_ERROR,
20101d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		   G_IO_ERROR_CANCELLED,
20111d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		   _("Unable to trash file: %s"),
2012493cbfa6077850d2e134e3ac3dbe4cbf85a36e9bAlexander Larsson		   _("Operation was cancelled"));
20131d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson      success = FALSE;
20141d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    }
20151d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  else if (!success)
20161d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson    g_set_error (error, G_IO_ERROR,
20171d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		 G_IO_ERROR_FAILED,
20181d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson		 _("Unable to trash file: %s"),
2019493cbfa6077850d2e134e3ac3dbe4cbf85a36e9bAlexander Larsson		 _("internal error"));
20201d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson
20211d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  g_free (wfilename);
20221d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson  return success;
20231d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson}
20241d568f35d13d7cf0206439a7a94b7fd3abd92fa3Alexander Larsson#endif /* G_OS_WIN32 */
20253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20263781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
2027a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_make_directory (GFile         *file,
2028a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			     GCancellable  *cancellable,
2029a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			     GError       **error)
20303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
20313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
20323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
203383e4fb4f9b548ffb1eaf0eaeb5306c1aef06cd3cLoïc Minier  if (g_mkdir (local->filename, 0777) == -1)
20343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
20353781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      int errsv = errno;
20363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (errsv == EINVAL)
20383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	/* This must be an invalid filename, on e.g. FAT */
20399c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	g_set_error_literal (error, G_IO_ERROR,
20409c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             G_IO_ERROR_INVALID_FILENAME,
20419c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             _("Invalid filename"));
20423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
20433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_set_error (error, G_IO_ERROR,
20443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_io_error_from_errno (errsv),
20458b6fdb362f6b16016e556876b174e7f3d74a10d3Ross Burton		     _("Error creating directory: %s"),
20463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_strerror (errsv));
20473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
20483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
20493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
20513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
20523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20533781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
2054a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_make_symbolic_link (GFile         *file,
2055a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 const char    *symlink_value,
2056a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 GCancellable  *cancellable,
2057a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen				 GError       **error)
20583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
20593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#ifdef HAVE_SYMLINK
20603781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile *local = G_LOCAL_FILE (file);
20613781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (symlink (symlink_value, local->filename) == -1)
20633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
20643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      int errsv = errno;
20653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (errsv == EINVAL)
20673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	/* This must be an invalid filename, on e.g. FAT */
20689c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	g_set_error_literal (error, G_IO_ERROR,
20699c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             G_IO_ERROR_INVALID_FILENAME,
20709c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             _("Invalid filename"));
20713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
20723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_set_error (error, G_IO_ERROR,
20733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_io_error_from_errno (errsv),
20743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     _("Error making symbolic link: %s"),
20753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_strerror (errsv));
20763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
20773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
20783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
20793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#else
20809c17697b56501d11b4c653432cc9e290347aa03eChristian Persch  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Symlinks not supported");
20813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return FALSE;
20823781343738de4abddf56982325a77bd70a98cd26Alexander Larsson#endif
20833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
20843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
20863781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
2087a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_copy (GFile                  *source,
2088a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFile                  *destination,
2089a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFileCopyFlags          flags,
2090a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GCancellable           *cancellable,
2091a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFileProgressCallback   progress_callback,
2092a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   gpointer                progress_callback_data,
2093a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GError                **error)
20943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
20953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  /* Fall back to default copy */
20969c17697b56501d11b4c653432cc9e290347aa03eChristian Persch  g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Copy not supported");
20973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return FALSE;
20983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
20993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
21003781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic gboolean
2101a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_move (GFile                  *source,
2102a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFile                  *destination,
2103a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFileCopyFlags          flags,
2104a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GCancellable           *cancellable,
2105a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GFileProgressCallback   progress_callback,
2106a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   gpointer                progress_callback_data,
2107a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen		   GError                **error)
21083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
2109c6af0efb11b510806110f422d2aca5ee735d21a8Alexander Larsson  GLocalFile *local_source, *local_destination;
21103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  struct stat statbuf;
21113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  gboolean destination_exist, source_is_dir;
21123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  char *backup_name;
21133781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  int res;
21140026537f3711dc843075702345f748a21a45345eAlexander Larsson  off_t source_size;
21150026537f3711dc843075702345f748a21a45345eAlexander Larsson
21160026537f3711dc843075702345f748a21a45345eAlexander Larsson  if (!G_IS_LOCAL_FILE (source) ||
21170026537f3711dc843075702345f748a21a45345eAlexander Larsson      !G_IS_LOCAL_FILE (destination))
21180026537f3711dc843075702345f748a21a45345eAlexander Larsson    {
21190026537f3711dc843075702345f748a21a45345eAlexander Larsson      /* Fall back to default move */
21209c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Move not supported");
21210026537f3711dc843075702345f748a21a45345eAlexander Larsson      return FALSE;
21220026537f3711dc843075702345f748a21a45345eAlexander Larsson    }
21230026537f3711dc843075702345f748a21a45345eAlexander Larsson
21240026537f3711dc843075702345f748a21a45345eAlexander Larsson  local_source = G_LOCAL_FILE (source);
2125c6af0efb11b510806110f422d2aca5ee735d21a8Alexander Larsson  local_destination = G_LOCAL_FILE (destination);
21260026537f3711dc843075702345f748a21a45345eAlexander Larsson
21273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  res = g_lstat (local_source->filename, &statbuf);
21283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (res == -1)
21293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
213037ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch      int errsv = errno;
213137ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
21323781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_set_error (error, G_IO_ERROR,
213337ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_io_error_from_errno (errsv),
21343781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		   _("Error moving file: %s"),
213537ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		   g_strerror (errsv));
21363781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
21373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
21380026537f3711dc843075702345f748a21a45345eAlexander Larsson
21399dfce3a26a37c46cb00d323230ed0885c43b55f1Alexander Larsson  source_is_dir = S_ISDIR (statbuf.st_mode);
21400026537f3711dc843075702345f748a21a45345eAlexander Larsson  source_size = statbuf.st_size;
21413781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
21423781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  destination_exist = FALSE;
21433781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  res = g_lstat (local_destination->filename, &statbuf);
21443781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (res == 0)
21453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
21463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      destination_exist = TRUE; /* Target file exists */
21473781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
21483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (flags & G_FILE_COPY_OVERWRITE)
21493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
21503781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  /* Always fail on dirs, even with overwrite */
21513781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  if (S_ISDIR (statbuf.st_mode))
21523781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    {
21539dfce3a26a37c46cb00d323230ed0885c43b55f1Alexander Larsson	      if (source_is_dir)
21549c17697b56501d11b4c653432cc9e290347aa03eChristian Persch		g_set_error_literal (error,
21559c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     G_IO_ERROR,
21569c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     G_IO_ERROR_WOULD_MERGE,
21579c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     _("Can't move directory over directory"));
21589dfce3a26a37c46cb00d323230ed0885c43b55f1Alexander Larsson              else
21599c17697b56501d11b4c653432cc9e290347aa03eChristian Persch		g_set_error_literal (error,
21609c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     G_IO_ERROR,
21619c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     G_IO_ERROR_IS_DIRECTORY,
21629c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                                     _("Can't copy over directory"));
21633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	      return FALSE;
21643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	    }
21653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
21663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
21673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
21689c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	  g_set_error_literal (error,
21699c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR,
21709c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR_EXISTS,
21719c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               _("Target file exists"));
21723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  return FALSE;
21733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
21743781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
21753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
21763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (flags & G_FILE_COPY_BACKUP && destination_exist)
21773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
21783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      backup_name = g_strconcat (local_destination->filename, "~", NULL);
21793b1b6a9722f40495762fbb115a43b39d495c3170Alexander Larsson      if (g_rename (local_destination->filename, backup_name) == -1)
21803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
21819c17697b56501d11b4c653432cc9e290347aa03eChristian Persch      	  g_set_error_literal (error,
21829c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR,
21839c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               G_IO_ERROR_CANT_CREATE_BACKUP,
21849c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                               _("Backup file creation failed"));
21853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  g_free (backup_name);
21863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  return FALSE;
21873781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
21883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      g_free (backup_name);
21893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      destination_exist = FALSE; /* It did, but no more */
21903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
21913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
21923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  if (source_is_dir && destination_exist && (flags & G_FILE_COPY_OVERWRITE))
21933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
21943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      /* Source is a dir, destination exists (and is not a dir, because that would have failed
21953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	 earlier), and we're overwriting. Manually remove the target so we can do the rename. */
21963b1b6a9722f40495762fbb115a43b39d495c3170Alexander Larsson      res = g_unlink (local_destination->filename);
21973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      if (res == -1)
21983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	{
219937ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch          int errsv = errno;
220037ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch
22013781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  g_set_error (error, G_IO_ERROR,
220237ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		       g_io_error_from_errno (errsv),
22033781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		       _("Error removing target file: %s"),
220437ac644bd18168330f43f4d52be7e3cbb3415415Christian Persch		       g_strerror (errsv));
22053781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	  return FALSE;
22063781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	}
22073781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
22083781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
22093b1b6a9722f40495762fbb115a43b39d495c3170Alexander Larsson  if (g_rename (local_source->filename, local_destination->filename) == -1)
22103781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    {
22113781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      int errsv = errno;
22123781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
22136394ae6fdb445f71ca0c4ba0be6b942bbf097832Alexander Larsson      if (errsv == EXDEV)
22146394ae6fdb445f71ca0c4ba0be6b942bbf097832Alexander Larsson	/* This will cause the fallback code to run */
22159c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	g_set_error_literal (error, G_IO_ERROR,
22169c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             G_IO_ERROR_NOT_SUPPORTED,
22179c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             _("Move between mounts not supported"));
22186394ae6fdb445f71ca0c4ba0be6b942bbf097832Alexander Larsson      else if (errsv == EINVAL)
22193781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	/* This must be an invalid filename, on e.g. FAT, or
22203781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	   we're trying to move the file into itself...
22213781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	   We return invalid filename for both... */
22229c17697b56501d11b4c653432cc9e290347aa03eChristian Persch	g_set_error_literal (error, G_IO_ERROR,
22239c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             G_IO_ERROR_INVALID_FILENAME,
22249c17697b56501d11b4c653432cc9e290347aa03eChristian Persch                             _("Invalid filename"));
22253781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      else
22263781343738de4abddf56982325a77bd70a98cd26Alexander Larsson	g_set_error (error, G_IO_ERROR,
22273781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_io_error_from_errno (errsv),
22283781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     _("Error moving file: %s"),
22293781343738de4abddf56982325a77bd70a98cd26Alexander Larsson		     g_strerror (errsv));
22303781343738de4abddf56982325a77bd70a98cd26Alexander Larsson      return FALSE;
22313781343738de4abddf56982325a77bd70a98cd26Alexander Larsson    }
22320026537f3711dc843075702345f748a21a45345eAlexander Larsson
22330026537f3711dc843075702345f748a21a45345eAlexander Larsson  /* Make sure we send full copied size */
22340026537f3711dc843075702345f748a21a45345eAlexander Larsson  if (progress_callback)
22350026537f3711dc843075702345f748a21a45345eAlexander Larsson    progress_callback (source_size, source_size, progress_callback_data);
22360026537f3711dc843075702345f748a21a45345eAlexander Larsson
22373781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  return TRUE;
22383781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
22393781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
2240e23140cbb43c111fe9010b7f6c3a404db1aa152bAlexander Larssonstatic GFileMonitor*
2241a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_monitor_dir (GFile             *file,
2242a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			  GFileMonitorFlags  flags,
22433690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson			  GCancellable      *cancellable,
22443690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson			  GError           **error)
22453781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
22463781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile* local_file = G_LOCAL_FILE(file);
22473690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson  return _g_local_directory_monitor_new (local_file->filename, flags, error);
22483781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
22493781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
22503781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic GFileMonitor*
2251a2ca589703273fca80cb126430a8b058aba3eb52Matthias Claseng_local_file_monitor_file (GFile             *file,
2252a2ca589703273fca80cb126430a8b058aba3eb52Matthias Clasen			   GFileMonitorFlags  flags,
22533690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson			   GCancellable      *cancellable,
22543690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson			   GError           **error)
22553781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
22563781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  GLocalFile* local_file = G_LOCAL_FILE(file);
22573690cb75a67377a169264e226655d8fa3a5d003aAlexander Larsson  return _g_local_file_monitor_new (local_file->filename, flags, error);
22583781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
22593781343738de4abddf56982325a77bd70a98cd26Alexander Larsson
22603781343738de4abddf56982325a77bd70a98cd26Alexander Larssonstatic void
22613781343738de4abddf56982325a77bd70a98cd26Alexander Larssong_local_file_file_iface_init (GFileIface *iface)
22623781343738de4abddf56982325a77bd70a98cd26Alexander Larsson{
22633781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->dup = g_local_file_dup;
22643781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->hash = g_local_file_hash;
22653781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->equal = g_local_file_equal;
22663781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->is_native = g_local_file_is_native;
22673781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->has_uri_scheme = g_local_file_has_uri_scheme;
22683781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_uri_scheme = g_local_file_get_uri_scheme;
22693781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_basename = g_local_file_get_basename;
22703781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_path = g_local_file_get_path;
22713781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_uri = g_local_file_get_uri;
22723781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_parse_name = g_local_file_get_parse_name;
22733781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_parent = g_local_file_get_parent;
22746dc9b7ee0050c03e069d026c2c83136547a7d343Alexander Larsson  iface->prefix_matches = g_local_file_prefix_matches;
22753781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_relative_path = g_local_file_get_relative_path;
22763781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->resolve_relative_path = g_local_file_resolve_relative_path;
22773781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->get_child_for_display_name = g_local_file_get_child_for_display_name;
22783781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->set_display_name = g_local_file_set_display_name;
22793781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->enumerate_children = g_local_file_enumerate_children;
22803781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->query_info = g_local_file_query_info;
22813781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->query_filesystem_info = g_local_file_query_filesystem_info;
22823ca9fd4dbb134088bf70f2f6584f14a559e6820aDavid Zeuthen  iface->find_enclosing_mount = g_local_file_find_enclosing_mount;
22833781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->query_settable_attributes = g_local_file_query_settable_attributes;
22843781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->query_writable_namespaces = g_local_file_query_writable_namespaces;
22853781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->set_attribute = g_local_file_set_attribute;
22863781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->set_attributes_from_info = g_local_file_set_attributes_from_info;
22872c362b7f9eb7cc81f37970e24c5b5dcdc56ea6d5Alexander Larsson  iface->read_fn = g_local_file_read;
22883781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->append_to = g_local_file_append_to;
22893781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->create = g_local_file_create;
22903781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->replace = g_local_file_replace;
22913781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->delete_file = g_local_file_delete;
22923781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->trash = g_local_file_trash;
22933781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->make_directory = g_local_file_make_directory;
22943781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->make_symbolic_link = g_local_file_make_symbolic_link;
22953781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->copy = g_local_file_copy;
22963781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->move = g_local_file_move;
22973781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->monitor_dir = g_local_file_monitor_dir;
22983781343738de4abddf56982325a77bd70a98cd26Alexander Larsson  iface->monitor_file = g_local_file_monitor_file;
22993781343738de4abddf56982325a77bd70a98cd26Alexander Larsson}
2300