/* GIO - GLib Input, Output and Streaming Library * * Copyright (C) 2006-2007 Red Hat, Inc. * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; either * version 2 of the License, or (at your option) any later version. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. * * You should have received a copy of the GNU Lesser General * Public License along with this library; if not, write to the * Free Software Foundation, Inc., 59 Temple Place, Suite 330, * Boston, MA 02111-1307, USA. * * Author: Alexander Larsson */ #include #include #include #include #include #include #include "gdaemonfile.h" #include "gvfsdaemondbus.h" #include "gdaemonmount.h" #include #include #include #include #include #include #include "gdbusutils.h" #include "gmountoperationdbus.h" #include static void g_daemon_file_file_iface_init (GFileIface *iface); struct _GDaemonFile { GObject parent_instance; GMountSpec *mount_spec; char *path; }; static void g_daemon_file_read_async (GFile *file, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data); G_DEFINE_TYPE_WITH_CODE (GDaemonFile, g_daemon_file, G_TYPE_OBJECT, G_IMPLEMENT_INTERFACE (G_TYPE_FILE, g_daemon_file_file_iface_init)) static void g_daemon_file_finalize (GObject *object) { GDaemonFile *daemon_file; daemon_file = G_DAEMON_FILE (object); g_mount_spec_unref (daemon_file->mount_spec); g_free (daemon_file->path); if (G_OBJECT_CLASS (g_daemon_file_parent_class)->finalize) (*G_OBJECT_CLASS (g_daemon_file_parent_class)->finalize) (object); } static void g_daemon_file_class_init (GDaemonFileClass *klass) { GObjectClass *gobject_class = G_OBJECT_CLASS (klass); gobject_class->finalize = g_daemon_file_finalize; } static void g_daemon_file_init (GDaemonFile *daemon_file) { } static char * canonicalize_path (const char *path) { char *canon, *start, *p, *q; if (*path != '/') canon = g_strconcat ("/", path, NULL); else canon = g_strdup (path); /* Skip initial slash */ start = canon + 1; p = start; while (*p != 0) { if (p[0] == '.' && (p[1] == 0 || p[1] == '/')) { memmove (p, p+1, strlen (p+1)+1); } else if (p[0] == '.' && p[1] == '.' && (p[2] == 0 || p[2] == '/')) { q = p + 2; /* Skip previous separator */ p = p - 2; if (p < start) p = start; while (p > start && *p != '/') p--; if (*p == '/') p++; memmove (p, q, strlen (q)+1); } else { /* Skip until next separator */ while (*p != 0 && *p != '/') p++; /* Keep one separator */ if (*p != 0) p++; } /* Remove additional separators */ q = p; while (*q && *q == '/') q++; if (p != q) memmove (p, q, strlen (q)+1); } /* Remove trailing slashes */ if (p > start && *(p-1) == '/') *(p-1) = 0; return canon; } GFile * g_daemon_file_new (GMountSpec *mount_spec, const char *path) { GDaemonFile *daemon_file; daemon_file = g_object_new (G_TYPE_DAEMON_FILE, NULL); daemon_file->mount_spec = g_mount_spec_get_unique_for (mount_spec); daemon_file->path = canonicalize_path (path); return G_FILE (daemon_file); } static gboolean g_daemon_file_is_native (GFile *file) { return FALSE; } static gboolean g_daemon_file_has_uri_scheme (GFile *file, const char *uri_scheme) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); const char *scheme; scheme = _g_daemon_vfs_mountspec_get_uri_scheme (daemon_file->mount_spec); return g_ascii_strcasecmp (scheme, uri_scheme) == 0; } static char * g_daemon_file_get_uri_scheme (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); const char *scheme; scheme = _g_daemon_vfs_mountspec_get_uri_scheme (daemon_file->mount_spec); return g_strdup (scheme); } static char * g_daemon_file_get_basename (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); char *last_slash; /* This code relies on the path being canonicalized */ last_slash = strrchr (daemon_file->path, '/'); /* If no slash, or only "/" fallback to full path */ if (last_slash == NULL || last_slash[1] == '\0') return g_strdup (daemon_file->path); return g_strdup (last_slash + 1); } static char * g_daemon_file_get_path (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); GMountInfo *mount_info; const char *rel_path; char *path; /* This is a sync i/o call, which is a bit unfortunate, as * this is supposed to be a fast call. However, in almost all * cases this will be cached. */ mount_info = _g_daemon_vfs_get_mount_info_sync (daemon_file->mount_spec, daemon_file->path, NULL); if (mount_info == NULL) return NULL; path = NULL; if (mount_info->fuse_mountpoint) { rel_path = daemon_file->path + strlen (mount_info->mount_spec->mount_prefix); path = g_build_filename (mount_info->fuse_mountpoint, rel_path, NULL); } g_mount_info_unref (mount_info); return path; } static char * g_daemon_file_get_uri (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); return _g_daemon_vfs_get_uri_for_mountspec (daemon_file->mount_spec, daemon_file->path, FALSE); } static char * g_daemon_file_get_parse_name (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); return _g_daemon_vfs_get_uri_for_mountspec (daemon_file->mount_spec, daemon_file->path, TRUE); } static GFile * g_daemon_file_get_parent (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); const char *path; GDaemonFile *parent; const char *base; char *parent_path; gsize len; path = daemon_file->path; base = strrchr (path, '/'); if (base == NULL || *(base+1) == 0) return NULL; while (base > path && *base == '/') base--; len = (guint) 1 + base - path; parent_path = g_new (gchar, len + 1); g_memmove (parent_path, path, len); parent_path[len] = 0; parent = g_object_new (G_TYPE_DAEMON_FILE, NULL); parent->mount_spec = g_mount_spec_ref (daemon_file->mount_spec); parent->path = parent_path; return G_FILE (parent); } static GFile * g_daemon_file_dup (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); return g_daemon_file_new (daemon_file->mount_spec, daemon_file->path); } static guint g_daemon_file_hash (GFile *file) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); return g_str_hash (daemon_file->path) ^ GPOINTER_TO_UINT (daemon_file->mount_spec); /* We have unique mount_spec objects so hash directly on it */ } static gboolean g_daemon_file_equal (GFile *file1, GFile *file2) { GDaemonFile *daemon_file1 = G_DAEMON_FILE (file1); GDaemonFile *daemon_file2 = G_DAEMON_FILE (file2); return daemon_file1->mount_spec == daemon_file2->mount_spec && g_str_equal (daemon_file1->path, daemon_file2->path); } static const char * match_prefix (const char *path, const char *prefix) { int prefix_len; prefix_len = strlen (prefix); if (strncmp (path, prefix, prefix_len) != 0) return NULL; /* Handle the case where prefix is the root, so that * the IS_DIR_SEPRARATOR check below works */ if (prefix_len > 0 && prefix[prefix_len-1] == '/') prefix_len--; return path + prefix_len; } static gboolean g_daemon_file_contains_file (GFile *parent, GFile *descendant) { GDaemonFile *parent_daemon = G_DAEMON_FILE (parent); GDaemonFile *descendant_daemon = G_DAEMON_FILE (descendant); const char *remainder; if (descendant_daemon->mount_spec != parent_daemon->mount_spec) return FALSE; remainder = match_prefix (descendant_daemon->path, parent_daemon->path); if (remainder != NULL && *remainder == '/') return TRUE; return FALSE; } static char * g_daemon_file_get_relative_path (GFile *parent, GFile *descendant) { GDaemonFile *parent_daemon = G_DAEMON_FILE (parent); GDaemonFile *descendant_daemon = G_DAEMON_FILE (descendant); const char *remainder; if (descendant_daemon->mount_spec != parent_daemon->mount_spec) return NULL; remainder = match_prefix (descendant_daemon->path, parent_daemon->path); if (remainder != NULL && *remainder == '/') return g_strdup (remainder + 1); return NULL; } static GFile * g_daemon_file_resolve_relative_path (GFile *file, const char *relative_path) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); char *path; GFile *child; if (*relative_path == '/') return g_daemon_file_new (daemon_file->mount_spec, relative_path); path = g_build_path ("/", daemon_file->path, relative_path, NULL); child = g_daemon_file_new (daemon_file->mount_spec, path); g_free (path); return child; } static DBusMessage * create_empty_message (GFile *file, const char *op, GMountInfo **mount_info_out, GError **error) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); DBusMessage *message; GMountInfo *mount_info; const char *path; mount_info = _g_daemon_vfs_get_mount_info_sync (daemon_file->mount_spec, daemon_file->path, error); if (mount_info == NULL) return NULL; if (mount_info_out) *mount_info_out = g_mount_info_ref (mount_info); message = dbus_message_new_method_call (mount_info->dbus_id, mount_info->object_path, G_VFS_DBUS_MOUNT_INTERFACE, op); path = g_mount_info_resolve_path (mount_info, daemon_file->path); _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path, 0); g_mount_info_unref (mount_info); return message; } static DBusMessage * do_sync_path_call (GFile *file, const char *op, GMountInfo **mount_info_out, DBusConnection **connection_out, GCancellable *cancellable, GError **error, int first_arg_type, ...) { DBusMessage *message, *reply; va_list var_args; message = create_empty_message (file, op, mount_info_out, error); if (!message) return NULL; va_start (var_args, first_arg_type); _g_dbus_message_append_args_valist (message, first_arg_type, var_args); va_end (var_args); reply = _g_vfs_daemon_call_sync (message, connection_out, NULL, NULL, NULL, cancellable, error); dbus_message_unref (message); return reply; } static DBusMessage * do_sync_2_path_call (GFile *file1, GFile *file2, const char *op, const char *callback_obj_path, DBusObjectPathMessageFunction callback, gpointer callback_user_data, DBusConnection **connection_out, GCancellable *cancellable, GError **error, int first_arg_type, ...) { GDaemonFile *daemon_file1 = G_DAEMON_FILE (file1); GDaemonFile *daemon_file2 = G_DAEMON_FILE (file2); DBusMessage *message, *reply; GMountInfo *mount_info1, *mount_info2; const char *path1, *path2; va_list var_args; mount_info1 = _g_daemon_vfs_get_mount_info_sync (daemon_file1->mount_spec, daemon_file1->path, error); if (mount_info1 == NULL) return NULL; mount_info2 = _g_daemon_vfs_get_mount_info_sync (daemon_file2->mount_spec, daemon_file2->path, error); if (mount_info2 == NULL) return NULL; if (mount_info1 != mount_info2) { /* For copy this will cause the fallback code to be involved */ g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, _("Operation not supported, files on different mounts")); return NULL; } message = dbus_message_new_method_call (mount_info1->dbus_id, mount_info1->object_path, G_VFS_DBUS_MOUNT_INTERFACE, op); path1 = g_mount_info_resolve_path (mount_info1, daemon_file1->path); _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path1, 0); path2 = g_mount_info_resolve_path (mount_info2, daemon_file2->path); _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path2, 0); va_start (var_args, first_arg_type); _g_dbus_message_append_args_valist (message, first_arg_type, var_args); va_end (var_args); reply = _g_vfs_daemon_call_sync (message, connection_out, callback_obj_path, callback, callback_user_data, cancellable, error); dbus_message_unref (message); g_mount_info_unref (mount_info1); g_mount_info_unref (mount_info2); return reply; } typedef void (*AsyncPathCallCallback) (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data); typedef struct { GSimpleAsyncResult *result; GFile *file; char *op; GCancellable *cancellable; DBusMessage *args; AsyncPathCallCallback callback; gpointer callback_data; GDestroyNotify notify; } AsyncPathCall; static void async_path_call_free (AsyncPathCall *data) { if (data->notify) data->notify (data->callback_data); if (data->result) g_object_unref (data->result); g_object_unref (data->file); g_free (data->op); if (data->cancellable) g_object_unref (data->cancellable); if (data->args) dbus_message_unref (data->args); g_free (data); } static void async_path_call_done (DBusMessage *reply, DBusConnection *connection, GError *io_error, gpointer _data) { AsyncPathCall *data = _data; GSimpleAsyncResult *result; if (io_error != NULL) { g_simple_async_result_set_from_error (data->result, io_error); g_simple_async_result_complete (data->result); async_path_call_free (data); } else { result = data->result; g_object_weak_ref (G_OBJECT (result), (GWeakNotify)async_path_call_free, data); data->result = NULL; data->callback (reply, connection, result, data->cancellable, data->callback_data); /* Free data here, or later if callback ref:ed the result */ g_object_unref (result); } } static void do_async_path_call_callback (GMountInfo *mount_info, gpointer _data, GError *error) { AsyncPathCall *data = _data; GDaemonFile *daemon_file = G_DAEMON_FILE (data->file); const char *path; DBusMessage *message; DBusMessageIter arg_source, arg_dest; if (error != NULL) { g_simple_async_result_set_from_error (data->result, error); g_simple_async_result_complete (data->result); async_path_call_free (data); return; } message = dbus_message_new_method_call (mount_info->dbus_id, mount_info->object_path, G_VFS_DBUS_MOUNT_INTERFACE, data->op); path = g_mount_info_resolve_path (mount_info, daemon_file->path); _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path, 0); /* Append more args from data->args */ if (data->args) { dbus_message_iter_init (data->args, &arg_source); dbus_message_iter_init_append (message, &arg_dest); _g_dbus_message_iter_copy (&arg_dest, &arg_source); } _g_vfs_daemon_call_async (message, async_path_call_done, data, data->cancellable); dbus_message_unref (message); } static void do_async_path_call (GFile *file, const char *op, GCancellable *cancellable, GAsyncReadyCallback op_callback, gpointer op_callback_data, AsyncPathCallCallback callback, gpointer callback_data, GDestroyNotify notify, int first_arg_type, ...) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); va_list var_args; GError *error; AsyncPathCall *data; data = g_new0 (AsyncPathCall, 1); data->result = g_simple_async_result_new (G_OBJECT (file), op_callback, op_callback_data, NULL); data->file = g_object_ref (file); data->op = g_strdup (op); if (data->cancellable) data->cancellable = g_object_ref (cancellable); data->callback = callback; data->callback_data = callback_data; data->notify = notify; error = NULL; if (first_arg_type != 0) { data->args = dbus_message_new (DBUS_MESSAGE_TYPE_METHOD_CALL); if (data->args == NULL) _g_dbus_oom (); va_start (var_args, first_arg_type); _g_dbus_message_append_args_valist (data->args, first_arg_type, var_args); va_end (var_args); } _g_daemon_vfs_get_mount_info_async (daemon_file->mount_spec, daemon_file->path, do_async_path_call_callback, data); } static GFileEnumerator * g_daemon_file_enumerate_children (GFile *file, const char *attributes, GFileQueryInfoFlags flags, GCancellable *cancellable, GError **error) { DBusMessage *reply; dbus_uint32_t flags_dbus; char *obj_path; GDaemonFileEnumerator *enumerator; DBusConnection *connection; enumerator = g_daemon_file_enumerator_new (); obj_path = g_daemon_file_enumerator_get_object_path (enumerator); if (attributes == NULL) attributes = ""; flags_dbus = flags; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_ENUMERATE, NULL, &connection, cancellable, error, DBUS_TYPE_STRING, &obj_path, DBUS_TYPE_STRING, &attributes, DBUS_TYPE_UINT32, &flags_dbus, 0); g_free (obj_path); if (reply == NULL) goto error; dbus_message_unref (reply); g_daemon_file_enumerator_set_sync_connection (enumerator, connection); return G_FILE_ENUMERATOR (enumerator); error: if (reply) dbus_message_unref (reply); g_object_unref (enumerator); return NULL; } static GFileInfo * g_daemon_file_query_info (GFile *file, const char *attributes, GFileQueryInfoFlags flags, GCancellable *cancellable, GError **error) { DBusMessage *reply; dbus_uint32_t flags_dbus; DBusMessageIter iter; GFileInfo *info; if (attributes == NULL) attributes = ""; flags_dbus = flags; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_QUERY_INFO, NULL, NULL, cancellable, error, DBUS_TYPE_STRING, &attributes, DBUS_TYPE_UINT32, &flags, 0); if (reply == NULL) return NULL; info = NULL; if (!dbus_message_iter_init (reply, &iter) || (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from get_info")); goto out; } info = _g_dbus_get_file_info (&iter, error); out: dbus_message_unref (reply); return info; } static void query_info_async_cb (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data) { DBusMessageIter iter; GFileInfo *info; GError *error; info = NULL; if (!dbus_message_iter_init (reply, &iter) || (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT)) { g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from query_info")); g_simple_async_result_complete (result); return; } error = NULL; info = _g_dbus_get_file_info (&iter, &error); if (info == NULL) { g_simple_async_result_set_from_error (result, error); g_error_free (error); g_simple_async_result_complete (result); return; } g_simple_async_result_set_op_res_gpointer (result, info, g_object_unref); g_simple_async_result_complete (result); } static void g_daemon_file_query_info_async (GFile *file, const char *attributes, GFileQueryInfoFlags flags, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { guint32 dbus_flags; dbus_flags = flags; do_async_path_call (file, G_VFS_DBUS_MOUNT_OP_QUERY_INFO, cancellable, callback, user_data, query_info_async_cb, NULL, NULL, DBUS_TYPE_STRING, &attributes, DBUS_TYPE_UINT32, &dbus_flags, 0); } static GFileInfo * g_daemon_file_query_info_finish (GFile *file, GAsyncResult *res, GError **error) { GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); GFileInfo *info; info = g_simple_async_result_get_op_res_gpointer (simple); if (info) return g_object_ref (info); return NULL; } typedef struct { GSimpleAsyncResult *result; gboolean can_seek; } GetFDData; static void read_async_get_fd_cb (int fd, gpointer callback_data) { GetFDData *data = callback_data; GFileInputStream *stream; if (fd == -1) { g_simple_async_result_set_error (data->result, G_IO_ERROR, G_IO_ERROR_FAILED, _("Couldn't get stream file descriptor")); } else { stream = g_daemon_file_input_stream_new (fd, data->can_seek); g_simple_async_result_set_op_res_gpointer (data->result, stream, g_object_unref); } g_simple_async_result_complete (data->result); g_object_unref (data->result); g_free (data); } static void read_async_cb (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data) { guint32 fd_id; dbus_bool_t can_seek; GetFDData *get_fd_data; if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &fd_id, DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_INVALID)) { g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from open")); g_simple_async_result_complete (result); return; } get_fd_data = g_new0 (GetFDData, 1); get_fd_data->result = g_object_ref (result); get_fd_data->can_seek = can_seek; _g_dbus_connection_get_fd_async (connection, fd_id, read_async_get_fd_cb, get_fd_data); } static void g_daemon_file_read_async (GFile *file, int io_priority, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer callback_data) { do_async_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_READ, cancellable, callback, callback_data, read_async_cb, NULL, NULL, 0); } static GFileInputStream * g_daemon_file_read_finish (GFile *file, GAsyncResult *res, GError **error) { GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (res); gpointer op; op = g_simple_async_result_get_op_res_gpointer (simple); if (op) return g_object_ref (op); return NULL; } static GFileInputStream * g_daemon_file_read (GFile *file, GCancellable *cancellable, GError **error) { DBusConnection *connection; int fd; DBusMessage *reply; guint32 fd_id; dbus_bool_t can_seek; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_READ, NULL, &connection, cancellable, error, 0); if (reply == NULL) return NULL; if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &fd_id, DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_INVALID)) { dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from open")); return NULL; } dbus_message_unref (reply); fd = _g_dbus_connection_get_fd_sync (connection, fd_id); if (fd == -1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Didn't get stream file descriptor")); return NULL; } return g_daemon_file_input_stream_new (fd, can_seek); } static GFileOutputStream * g_daemon_file_append_to (GFile *file, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { DBusConnection *connection; int fd; DBusMessage *reply; guint32 fd_id; dbus_bool_t can_seek; guint16 mode; guint64 initial_offset; dbus_bool_t make_backup; guint32 dbus_flags; char *etag; mode = 1; etag = ""; make_backup = FALSE; dbus_flags = flags; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, NULL, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &make_backup, DBUS_TYPE_UINT32, &dbus_flags, 0); if (reply == NULL) return NULL; if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &fd_id, DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_UINT64, &initial_offset, DBUS_TYPE_INVALID)) { dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from open")); return NULL; } dbus_message_unref (reply); fd = _g_dbus_connection_get_fd_sync (connection, fd_id); if (fd == -1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Didn't get stream file descriptor")); return NULL; } return g_daemon_file_output_stream_new (fd, can_seek, initial_offset); } static GFileOutputStream * g_daemon_file_create (GFile *file, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { DBusConnection *connection; int fd; DBusMessage *reply; guint32 fd_id; dbus_bool_t can_seek; guint16 mode; guint64 initial_offset; dbus_bool_t make_backup; char *etag; guint32 dbus_flags; mode = 0; etag = ""; make_backup = FALSE; dbus_flags = flags; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, NULL, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &make_backup, DBUS_TYPE_UINT32, &dbus_flags, 0); if (reply == NULL) return NULL; if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &fd_id, DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_UINT64, &initial_offset, DBUS_TYPE_INVALID)) { dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from open")); return NULL; } dbus_message_unref (reply); fd = _g_dbus_connection_get_fd_sync (connection, fd_id); if (fd == -1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Didn't get stream file descriptor")); return NULL; } return g_daemon_file_output_stream_new (fd, can_seek, initial_offset); } static GFileOutputStream * g_daemon_file_replace (GFile *file, const char *etag, gboolean make_backup, GFileCreateFlags flags, GCancellable *cancellable, GError **error) { DBusConnection *connection; int fd; DBusMessage *reply; guint32 fd_id; dbus_bool_t can_seek; guint16 mode; guint64 initial_offset; dbus_bool_t dbus_make_backup; guint32 dbus_flags; mode = 2; dbus_make_backup = make_backup; dbus_flags = flags; if (etag == NULL) etag = ""; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_OPEN_FOR_WRITE, NULL, &connection, cancellable, error, DBUS_TYPE_UINT16, &mode, DBUS_TYPE_STRING, &etag, DBUS_TYPE_BOOLEAN, &dbus_make_backup, DBUS_TYPE_UINT32, &dbus_flags, 0); if (reply == NULL) return NULL; if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_UINT32, &fd_id, DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_UINT64, &initial_offset, DBUS_TYPE_INVALID)) { dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from open")); return NULL; } dbus_message_unref (reply); fd = _g_dbus_connection_get_fd_sync (connection, fd_id); if (fd == -1) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Didn't get stream file descriptor")); return NULL; } return g_daemon_file_output_stream_new (fd, can_seek, initial_offset); } static void mount_mountable_location_mounted_cb (GObject *source_object, GAsyncResult *res, gpointer user_data) { GSimpleAsyncResult *result = user_data; GError *error = NULL; if (!g_file_mount_enclosing_volume_finish (G_FILE (source_object), res, &error)) { g_simple_async_result_set_from_error (result, error); g_error_free (error); } g_simple_async_result_complete (result); g_object_unref (result); } static void mount_mountable_async_cb (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data) { GMountOperation *mount_operation = callback_data; GMountSpec *mount_spec; char *path; DBusMessageIter iter; GFile *file; dbus_bool_t must_mount_location, is_uri; path = NULL; dbus_message_iter_init (reply, &iter); if (!_g_dbus_message_iter_get_args (&iter, NULL, DBUS_TYPE_BOOLEAN, &is_uri, G_DBUS_TYPE_CSTRING, &path, DBUS_TYPE_BOOLEAN, &must_mount_location, 0)) { g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from call")); g_simple_async_result_complete (result); return; } if (is_uri) { file = g_file_new_for_uri (path); } else { mount_spec = g_mount_spec_from_dbus (&iter); if (mount_spec == NULL) { g_simple_async_result_set_error (result, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from call")); g_simple_async_result_complete (result); return; } file = g_daemon_file_new (mount_spec, path); g_mount_spec_unref (mount_spec); } g_free (path); g_simple_async_result_set_op_res_gpointer (result, file, g_object_unref); if (must_mount_location) { g_file_mount_enclosing_volume (file, mount_operation, cancellable, mount_mountable_location_mounted_cb, g_object_ref (result)); } else g_simple_async_result_complete (result); } static void g_daemon_file_mount_mountable (GFile *file, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GMountSource *mount_source; const char *dbus_id, *obj_path; mount_source = g_mount_operation_dbus_wrap (mount_operation, _g_daemon_vfs_get_async_bus ()); dbus_id = g_mount_source_get_dbus_id (mount_source); obj_path = g_mount_source_get_obj_path (mount_source); if (mount_operation) g_object_ref (mount_operation); do_async_path_call (file, G_VFS_DBUS_MOUNT_OP_MOUNT_MOUNTABLE, cancellable, callback, user_data, mount_mountable_async_cb, mount_operation, mount_operation ? g_object_unref : NULL, DBUS_TYPE_STRING, &dbus_id, DBUS_TYPE_OBJECT_PATH, &obj_path, 0); g_object_unref (mount_source); } static GFile * g_daemon_file_mount_mountable_finish (GFile *file, GAsyncResult *result, GError **error) { GSimpleAsyncResult *simple = G_SIMPLE_ASYNC_RESULT (result); GFile *result_file; result_file = g_simple_async_result_get_op_res_gpointer (simple); if (result_file) return g_object_ref (result_file); return NULL; } static void eject_mountable_async_cb (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data) { g_simple_async_result_complete (result); } static void g_daemon_file_eject_mountable (GFile *file, GMountUnmountFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { guint32 dbus_flags; dbus_flags = flags; do_async_path_call (file, G_VFS_DBUS_MOUNT_OP_EJECT_MOUNTABLE, cancellable, callback, user_data, eject_mountable_async_cb, NULL, NULL, DBUS_TYPE_UINT32, &dbus_flags, 0); } static gboolean g_daemon_file_eject_mountable_finish (GFile *file, GAsyncResult *result, GError **error) { return TRUE; } static void unmount_mountable_async_cb (DBusMessage *reply, DBusConnection *connection, GSimpleAsyncResult *result, GCancellable *cancellable, gpointer callback_data) { g_simple_async_result_complete (result); } static void g_daemon_file_unmount_mountable (GFile *file, GMountUnmountFlags flags, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { guint32 dbus_flags; dbus_flags = flags; do_async_path_call (file, G_VFS_DBUS_MOUNT_OP_UNMOUNT_MOUNTABLE, cancellable, callback, user_data, eject_mountable_async_cb, NULL, NULL, DBUS_TYPE_UINT32, &dbus_flags, 0); } static gboolean g_daemon_file_unmount_mountable_finish (GFile *file, GAsyncResult *result, GError **error) { return TRUE; } typedef struct { GFile *file; GMountOperation *mount_operation; GAsyncReadyCallback callback; gpointer user_data; } MountData; static void g_daemon_file_mount_enclosing_volume (GFile *location, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data); static void mount_reply (DBusMessage *reply, GError *error, gpointer user_data) { MountData *data = user_data; GSimpleAsyncResult *res; if (reply == NULL) { res = g_simple_async_result_new_from_error (G_OBJECT (data->file), data->callback, data->user_data, error); } else { res = g_simple_async_result_new (G_OBJECT (data->file), data->callback, data->user_data, g_daemon_file_mount_enclosing_volume); } g_simple_async_result_complete (res); g_object_unref (data->file); if (data->mount_operation) g_object_unref (data->mount_operation); g_free (data); } static void g_daemon_file_mount_enclosing_volume (GFile *location, GMountOperation *mount_operation, GCancellable *cancellable, GAsyncReadyCallback callback, gpointer user_data) { GDaemonFile *daemon_file; DBusMessage *message; GMountSpec *spec; GMountSource *mount_source; DBusMessageIter iter; MountData *data; daemon_file = G_DAEMON_FILE (location); message = dbus_message_new_method_call (G_VFS_DBUS_DAEMON_NAME, G_VFS_DBUS_MOUNTTRACKER_PATH, G_VFS_DBUS_MOUNTTRACKER_INTERFACE, G_VFS_DBUS_MOUNTTRACKER_OP_MOUNT_LOCATION); spec = g_mount_spec_copy (daemon_file->mount_spec); g_mount_spec_set_mount_prefix (spec, daemon_file->path); dbus_message_iter_init_append (message, &iter); g_mount_spec_to_dbus (&iter, spec); g_mount_spec_unref (spec); mount_source = g_mount_operation_dbus_wrap (mount_operation, _g_daemon_vfs_get_async_bus ()); g_mount_source_to_dbus (mount_source, message); g_object_unref (mount_source); data = g_new0 (MountData, 1); data->callback = callback; data->user_data = user_data; data->file = g_object_ref (location); if (mount_operation) data->mount_operation = g_object_ref (mount_operation); /* TODO: Ignoring cancellable here */ _g_dbus_connection_call_async (_g_daemon_vfs_get_async_bus (), message, G_VFS_DBUS_MOUNT_TIMEOUT_MSECS, mount_reply, data); dbus_message_unref (message); } static gboolean g_daemon_file_mount_enclosing_volume_finish (GFile *location, GAsyncResult *result, GError **error) { /* Errors handled in generic code */ return TRUE; } static GFileInfo * g_daemon_file_query_filesystem_info (GFile *file, const char *attributes, GCancellable *cancellable, GError **error) { DBusMessage *reply; DBusMessageIter iter; GFileInfo *info; if (attributes == NULL) attributes = ""; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_QUERY_FILESYSTEM_INFO, NULL, NULL, cancellable, error, DBUS_TYPE_STRING, &attributes, 0); if (reply == NULL) return NULL; info = NULL; if (!dbus_message_iter_init (reply, &iter) || (dbus_message_iter_get_arg_type (&iter) != DBUS_TYPE_STRUCT)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from get_filesystem_info")); goto out; } info = _g_dbus_get_file_info (&iter, error); out: dbus_message_unref (reply); return info; } static GMount * g_daemon_file_find_enclosing_mount (GFile *file, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); GMountInfo *mount_info; GDaemonMount *mount; mount_info = _g_daemon_vfs_get_mount_info_sync (daemon_file->mount_spec, daemon_file->path, error); if (mount_info == NULL) return NULL; if (mount_info->user_visible) { mount = g_daemon_mount_new (mount_info, NULL); g_mount_info_unref (mount_info); if (mount) return G_MOUNT (mount); } g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_FOUND, /* translators: this is an error message when there is no user visible "mount" object corresponding to a particular path/uri */ _("Could not find enclosing mount")); return NULL; } static GFile * g_daemon_file_get_child_for_display_name (GFile *file, const char *display_name, GError **error) { GDaemonFile *daemon_file = G_DAEMON_FILE (file); GMountInfo *mount_info; char *basename; GFile *child; mount_info = _g_daemon_vfs_get_mount_info_sync (daemon_file->mount_spec, daemon_file->path, NULL); if (mount_info && mount_info->prefered_filename_encoding) { basename = g_convert (display_name, -1, mount_info->prefered_filename_encoding, "UTF-8", NULL, NULL, NULL); if (basename == NULL) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_INVALID_FILENAME, _("Invalid filename %s"), display_name); return NULL; } child = g_file_get_child (file, basename); g_free (basename); } else child = g_file_get_child (file, display_name); return child; } static GFile * g_daemon_file_set_display_name (GFile *file, const char *display_name, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file; DBusMessage *reply; DBusMessageIter iter; char *new_path; daemon_file = G_DAEMON_FILE (file); reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_SET_DISPLAY_NAME, NULL, NULL, cancellable, error, DBUS_TYPE_STRING, &display_name, 0); if (reply == NULL) return NULL; if (!dbus_message_iter_init (reply, &iter) || !_g_dbus_message_iter_get_args (&iter, NULL, G_DBUS_TYPE_CSTRING, &new_path, 0)) { g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from query_filesystem_info")); goto out; } file = g_daemon_file_new (daemon_file->mount_spec, new_path); g_free (new_path); out: dbus_message_unref (reply); return file; } static gboolean g_daemon_file_delete (GFile *file, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file; DBusMessage *reply; daemon_file = G_DAEMON_FILE (file); reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_DELETE, NULL, NULL, cancellable, error, 0); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static gboolean g_daemon_file_trash (GFile *file, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file; DBusMessage *reply; daemon_file = G_DAEMON_FILE (file); reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_TRASH, NULL, NULL, cancellable, error, 0); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static gboolean g_daemon_file_make_directory (GFile *file, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file; DBusMessage *reply; daemon_file = G_DAEMON_FILE (file); reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_MAKE_DIRECTORY, NULL, NULL, cancellable, error, 0); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static gboolean g_daemon_file_make_symbolic_link (GFile *file, const char *symlink_value, GCancellable *cancellable, GError **error) { DBusMessage *reply; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_MAKE_SYMBOLIC_LINK, NULL, NULL, cancellable, error, G_DBUS_TYPE_CSTRING, &symlink_value, 0); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static GFileAttributeInfoList * g_daemon_file_query_settable_attributes (GFile *file, GCancellable *cancellable, GError **error) { DBusMessage *reply; GFileAttributeInfoList *list; DBusMessageIter iter; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_QUERY_SETTABLE_ATTRIBUTES, NULL, NULL, cancellable, error, 0); if (reply == NULL) return NULL; dbus_message_iter_init (reply, &iter); list = _g_dbus_get_attribute_info_list (&iter, error); dbus_message_unref (reply); return list; } static GFileAttributeInfoList * g_daemon_file_query_writable_namespaces (GFile *file, GCancellable *cancellable, GError **error) { DBusMessage *reply; GFileAttributeInfoList *list; DBusMessageIter iter; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_QUERY_WRITABLE_NAMESPACES, NULL, NULL, cancellable, error, 0); if (reply == NULL) return NULL; dbus_message_iter_init (reply, &iter); list = _g_dbus_get_attribute_info_list (&iter, error); dbus_message_unref (reply); return list; } static gboolean g_daemon_file_set_attribute (GFile *file, const char *attribute, GFileAttributeType type, gpointer value_p, GFileQueryInfoFlags flags, GCancellable *cancellable, GError **error) { GDaemonFile *daemon_file; DBusMessage *message, *reply; DBusMessageIter iter; dbus_uint32_t flags_dbus; daemon_file = G_DAEMON_FILE (file); message = create_empty_message (file, G_VFS_DBUS_MOUNT_OP_SET_ATTRIBUTE, NULL, error); if (!message) return FALSE; dbus_message_iter_init_append (message, &iter); flags_dbus = flags; dbus_message_iter_append_basic (&iter, DBUS_TYPE_UINT32, &flags_dbus); _g_dbus_append_file_attribute (&iter, attribute, type, value_p); reply = _g_vfs_daemon_call_sync (message, NULL, NULL, NULL, NULL, cancellable, error); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } struct ProgressCallbackData { GFileProgressCallback progress_callback; gpointer progress_callback_data; }; static DBusHandlerResult progress_callback_message (DBusConnection *connection, DBusMessage *message, void *user_data) { struct ProgressCallbackData *data = user_data; dbus_uint64_t current_dbus, total_dbus; if (dbus_message_is_method_call (message, G_VFS_DBUS_PROGRESS_INTERFACE, G_VFS_DBUS_PROGRESS_OP_PROGRESS)) { if (dbus_message_get_args (message, NULL, DBUS_TYPE_UINT64, ¤t_dbus, DBUS_TYPE_UINT64, &total_dbus, 0)) data->progress_callback (current_dbus, total_dbus, data->progress_callback_data); } else g_warning ("Unknown progress callback message type\n"); /* TODO: demarshal args and call reall callback */ return DBUS_HANDLER_RESULT_HANDLED; } static gboolean g_daemon_file_copy (GFile *source, GFile *destination, GFileCopyFlags flags, GCancellable *cancellable, GFileProgressCallback progress_callback, gpointer progress_callback_data, GError **error) { GDaemonFile *daemon_source, *daemon_dest; DBusMessage *reply; char *obj_path, *dbus_obj_path; dbus_uint32_t flags_dbus; struct ProgressCallbackData data; daemon_source = G_DAEMON_FILE (source); daemon_dest = G_DAEMON_FILE (destination); if (progress_callback) { obj_path = g_strdup_printf ("/org/gtk/vfs/callback/%p", &obj_path); dbus_obj_path = obj_path; } else { obj_path = NULL; /* Can't pass NULL obj path as arg */ dbus_obj_path = "/org/gtk/vfs/void"; } data.progress_callback = progress_callback; data.progress_callback_data = progress_callback_data; flags_dbus = flags; reply = do_sync_2_path_call (source, destination, G_VFS_DBUS_MOUNT_OP_COPY, obj_path, progress_callback_message, &data, NULL, cancellable, error, DBUS_TYPE_UINT32, &flags_dbus, DBUS_TYPE_OBJECT_PATH, &dbus_obj_path, 0); g_free (obj_path); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static gboolean g_daemon_file_move (GFile *source, GFile *destination, GFileCopyFlags flags, GCancellable *cancellable, GFileProgressCallback progress_callback, gpointer progress_callback_data, GError **error) { GDaemonFile *daemon_source, *daemon_dest; DBusMessage *reply; char *obj_path, *dbus_obj_path; dbus_uint32_t flags_dbus; struct ProgressCallbackData data; daemon_source = G_DAEMON_FILE (source); daemon_dest = G_DAEMON_FILE (destination); if (progress_callback) { obj_path = g_strdup_printf ("/org/gtk/vfs/callback/%p", &obj_path); dbus_obj_path = obj_path; } else { obj_path = NULL; /* Can't pass NULL obj path as arg */ dbus_obj_path = "/org/gtk/vfs/void"; } data.progress_callback = progress_callback; data.progress_callback_data = progress_callback_data; flags_dbus = flags; reply = do_sync_2_path_call (source, destination, G_VFS_DBUS_MOUNT_OP_MOVE, obj_path, progress_callback_message, &data, NULL, cancellable, error, DBUS_TYPE_UINT32, &flags_dbus, DBUS_TYPE_OBJECT_PATH, &dbus_obj_path, 0); g_free (obj_path); if (reply == NULL) return FALSE; dbus_message_unref (reply); return TRUE; } static GFileMonitor* g_daemon_file_monitor_dir (GFile* file, GFileMonitorFlags flags, GCancellable *cancellable, GError **error) { GFileMonitor *monitor; char *obj_path; dbus_uint32_t flags_dbus; GMountInfo *mount_info; DBusMessage *reply; flags_dbus = flags; mount_info = NULL; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_CREATE_DIR_MONITOR, &mount_info, NULL, cancellable, error, DBUS_TYPE_UINT32, &flags_dbus, 0); if (reply == NULL) { if (mount_info) g_mount_info_unref (mount_info); return NULL; } if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &obj_path, DBUS_TYPE_INVALID)) { g_mount_info_unref (mount_info); dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from monitor_dir")); return NULL; } monitor = g_daemon_file_monitor_new (mount_info->dbus_id, obj_path); g_mount_info_unref (mount_info); dbus_message_unref (reply); return monitor; } static GFileMonitor* g_daemon_file_monitor_file (GFile* file, GFileMonitorFlags flags, GCancellable *cancellable, GError **error) { GFileMonitor *monitor; char *obj_path; dbus_uint32_t flags_dbus; GMountInfo *mount_info; DBusMessage *reply; flags_dbus = flags; mount_info = NULL; reply = do_sync_path_call (file, G_VFS_DBUS_MOUNT_OP_CREATE_FILE_MONITOR, &mount_info, NULL, cancellable, error, DBUS_TYPE_UINT32, &flags_dbus, 0); if (reply == NULL) { if (mount_info) g_mount_info_unref (mount_info); return NULL; } if (!dbus_message_get_args (reply, NULL, DBUS_TYPE_OBJECT_PATH, &obj_path, DBUS_TYPE_INVALID)) { g_mount_info_unref (mount_info); dbus_message_unref (reply); g_set_error (error, G_IO_ERROR, G_IO_ERROR_FAILED, _("Invalid return value from monitor_file")); return NULL; } monitor = g_daemon_file_monitor_new (mount_info->dbus_id, obj_path); g_mount_info_unref (mount_info); dbus_message_unref (reply); return monitor; } static void g_daemon_file_file_iface_init (GFileIface *iface) { iface->dup = g_daemon_file_dup; iface->hash = g_daemon_file_hash; iface->equal = g_daemon_file_equal; iface->is_native = g_daemon_file_is_native; iface->has_uri_scheme = g_daemon_file_has_uri_scheme; iface->get_uri_scheme = g_daemon_file_get_uri_scheme; iface->get_basename = g_daemon_file_get_basename; iface->get_path = g_daemon_file_get_path; iface->get_uri = g_daemon_file_get_uri; iface->get_parse_name = g_daemon_file_get_parse_name; iface->get_parent = g_daemon_file_get_parent; iface->contains_file = g_daemon_file_contains_file; iface->get_relative_path = g_daemon_file_get_relative_path; iface->resolve_relative_path = g_daemon_file_resolve_relative_path; iface->get_child_for_display_name = g_daemon_file_get_child_for_display_name; iface->enumerate_children = g_daemon_file_enumerate_children; iface->query_info = g_daemon_file_query_info; iface->query_info_async = g_daemon_file_query_info_async; iface->query_info_finish = g_daemon_file_query_info_finish; iface->find_enclosing_mount = g_daemon_file_find_enclosing_mount; iface->read_fn = g_daemon_file_read; iface->append_to = g_daemon_file_append_to; iface->create = g_daemon_file_create; iface->replace = g_daemon_file_replace; iface->read_async = g_daemon_file_read_async; iface->read_finish = g_daemon_file_read_finish; iface->mount_enclosing_volume = g_daemon_file_mount_enclosing_volume; iface->mount_enclosing_volume_finish = g_daemon_file_mount_enclosing_volume_finish; iface->mount_mountable = g_daemon_file_mount_mountable; iface->mount_mountable_finish = g_daemon_file_mount_mountable_finish; iface->unmount_mountable = g_daemon_file_unmount_mountable; iface->unmount_mountable_finish = g_daemon_file_unmount_mountable_finish; iface->eject_mountable = g_daemon_file_eject_mountable; iface->eject_mountable_finish = g_daemon_file_eject_mountable_finish; iface->query_filesystem_info = g_daemon_file_query_filesystem_info; iface->set_display_name = g_daemon_file_set_display_name; iface->delete_file = g_daemon_file_delete; iface->trash = g_daemon_file_trash; iface->make_directory = g_daemon_file_make_directory; iface->copy = g_daemon_file_copy; iface->move = g_daemon_file_move; iface->query_settable_attributes = g_daemon_file_query_settable_attributes; iface->query_writable_namespaces = g_daemon_file_query_writable_namespaces; iface->set_attribute = g_daemon_file_set_attribute; iface->make_symbolic_link = g_daemon_file_make_symbolic_link; iface->monitor_dir = g_daemon_file_monitor_dir; iface->monitor_file = g_daemon_file_monitor_file; }