summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--TODO4
-rw-r--r--daemon/Makefile.am5
-rw-r--r--daemon/gvfsdaemon.c152
-rw-r--r--daemon/gvfsdaemon.h9
-rw-r--r--daemon/gvfsdaemonbackend.h5
-rw-r--r--daemon/gvfsdaemonbackendtest.c57
-rw-r--r--daemon/gvfsdaemonutils.c164
-rw-r--r--daemon/gvfsdaemonutils.h7
-rw-r--r--daemon/gvfsjob.c93
-rw-r--r--daemon/gvfsjob.h34
-rw-r--r--daemon/gvfsjobopenforread.c177
-rw-r--r--daemon/gvfsjobopenforread.h47
-rw-r--r--daemon/gvfsreadhandle.c113
-rw-r--r--daemon/gvfsreadhandle.h54
-rw-r--r--daemon/gvfsreadrequest.c111
-rw-r--r--daemon/gvfsreadrequest.h54
-rw-r--r--daemon/main.c4
-rw-r--r--gvfs/gunixfileinputstream.c20
-rw-r--r--gvfs/gvfsunixdbus.c79
-rw-r--r--gvfs/gvfsunixdbus.h4
20 files changed, 896 insertions, 297 deletions
diff --git a/TODO b/TODO
index 47a31d72..79d95378 100644
--- a/TODO
+++ b/TODO
@@ -20,3 +20,7 @@ Add GFilterOutput/InputStream and derivates (buffered, data, charset conversion,
Make backend pluggable
local file access through the daemon for remote X clients?
+
+-------------
+
+continue on GVfsJobOpenForRead, especially the return part \ No newline at end of file
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index ecea9ff1..8ffac31b 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -19,9 +19,10 @@ gvfs_daemon_SOURCES = \
gvfsdaemon.c gvfsdaemon.h \
gvfsdaemonbackend.c gvfsdaemonbackend.h \
gvfsdaemonbackendtest.c gvfsdaemonbackendtest.h \
- gvfsreadrequest.c gvfsreadrequest.h \
+ gvfsreadhandle.c gvfsreadhandle.h \
gvfsdaemonutils.c gvfsdaemonutils.h \
- gvfsjob.c gvfsjob.g \
+ gvfsjob.c gvfsjob.h \
+ gvfsjobopenforread.c gvfsjobopenforread.h \
dbus-gmain.h dbus-gmain.c \
main.c
diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c
index 5819fd1e..19f5383b 100644
--- a/daemon/gvfsdaemon.c
+++ b/daemon/gvfsdaemon.c
@@ -11,6 +11,7 @@
#include <gvfsdaemon.h>
#include <gvfsdaemonprotocol.h>
#include <gvfsdaemonutils.h>
+#include <gvfsjobopenforread.h>
G_DEFINE_TYPE (GVfsDaemon, g_vfs_daemon, G_TYPE_OBJECT);
@@ -21,12 +22,15 @@ enum {
struct _GVfsDaemonPrivate
{
- GVfsDaemonBackend *backend;
+ GMutex *lock; /* protects the parts that are accessed by multiple threads */
char *mountpoint;
gboolean active;
-};
-static gint32 extra_fd_slot = -1;
+ GQueue *pending_jobs;
+ GQueue *jobs; /* protected by lock */
+ guint queued_job_start; /* protected by lock */
+ GList *read_handles; /* protected by lock */
+};
static void g_vfs_daemon_get_property (GObject *object,
guint prop_id,
@@ -60,8 +64,15 @@ g_vfs_daemon_finalize (GObject *object)
daemon = G_VFS_DAEMON (object);
+ g_assert (daemon->priv->jobs->head == NULL);
+ g_assert (daemon->priv->pending_jobs->head == NULL);
+ g_queue_free (daemon->priv->jobs);
+ g_queue_free (daemon->priv->pending_jobs);
+
+ g_object_unref (daemon->backend);
+ g_mutex_free (daemon->priv->lock);
+
g_free (daemon->priv->mountpoint);
- g_object_ref (daemon->priv->backend);
if (G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize)
(*G_OBJECT_CLASS (g_vfs_daemon_parent_class)->finalize) (object);
@@ -79,9 +90,6 @@ g_vfs_daemon_class_init (GVfsDaemonClass *klass)
gobject_class->get_property = g_vfs_daemon_get_property;
gobject_class->constructor = g_vfs_daemon_constructor;
- if (!dbus_connection_allocate_data_slot (&extra_fd_slot))
- g_error ("Unable to allocate data slot");
-
g_object_class_install_property (gobject_class,
PROP_MOUNTPOINT,
g_param_spec_string ("mountpoint",
@@ -90,7 +98,6 @@ g_vfs_daemon_class_init (GVfsDaemonClass *klass)
NULL,
G_PARAM_READWRITE |
G_PARAM_CONSTRUCT_ONLY));
-
}
static void
@@ -99,6 +106,9 @@ g_vfs_daemon_init (GVfsDaemon *daemon)
daemon->priv = G_TYPE_INSTANCE_GET_PRIVATE (daemon,
G_TYPE_VFS_DAEMON,
GVfsDaemonPrivate);
+ daemon->priv->lock = g_mutex_new ();
+ daemon->priv->jobs = g_queue_new ();
+ daemon->priv->pending_jobs = g_queue_new ();
}
static GObject*
@@ -199,11 +209,12 @@ g_vfs_daemon_new (const char *mountpoint,
daemon = g_object_new (G_TYPE_VFS_DAEMON,
"mountpoint", mountpoint,
NULL);
- daemon->priv->backend = g_object_ref (backend);
+ daemon->backend = g_object_ref (backend);
return daemon;
}
+#ifdef COMMENTED_OUT
static int
send_fd (int connection_fd,
int fd)
@@ -237,38 +248,6 @@ send_fd (int connection_fd,
return ret;
}
-static void
-daemon_handle_open_for_read (GVfsDaemon *daemon,
- DBusConnection *conn,
- DBusMessage *message)
-{
- GVfsDaemonClass *class;
- DBusMessage *reply;
- DBusError derror;
- const char *path_data;
- int path_len;
- char *path;
- int fd;
- GError *error;
- GVfsReadRequest *read_request;
-
- class = G_VFS_DAEMON_GET_CLASS (daemon);
-
- dbus_error_init (&derror);
-
- read_request = NULL;
-
- if (!dbus_message_get_args (message, &derror,
- DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
- &path_data, &path_len,
- 0))
- {
- reply = dbus_message_new_error (message,
- derror.name,
- derror.message);
- dbus_error_free (&derror);
- goto reply;
- }
error = NULL;
read_request = g_vfs_read_request_new (&error);
@@ -279,9 +258,6 @@ daemon_handle_open_for_read (GVfsDaemon *daemon,
}
else
{
- path = g_strndup (path_data, path_len);
- g_vfs_read_request_set_filename (read_request, path);
- g_free (path);
reply = dbus_message_new_method_return (message);
}
@@ -298,12 +274,69 @@ daemon_handle_open_for_read (GVfsDaemon *daemon,
/* TODO: Add request to table, etc */
}
+#endif
+
+static gboolean
+start_jobs_at_idle (gpointer data)
+{
+ GVfsDaemon *daemon = data;
+ GList *l, *next;
+ GVfsJob *job;
+
+ g_mutex_lock (daemon->priv->lock);
+ daemon->priv->queued_job_start = 0;
+ g_mutex_unlock (daemon->priv->lock);
+
+ l = daemon->priv->pending_jobs->head;
+ while (l != NULL)
+ {
+ job = l->data;
+ next = l->next;
+
+ if (g_vfs_job_start (job))
+ g_queue_delete_link (daemon->priv->pending_jobs, l);
+
+ l = next;
+ }
+
+ return FALSE;
+}
+
+/* Called with lock held */
+static void
+queue_start_jobs_at_idle (GVfsDaemon *daemon)
+{
+ if (daemon->priv->queued_job_start == 0)
+ daemon->priv->queued_job_start = g_idle_add (start_jobs_at_idle, daemon);
+}
+
+/* NOTE: Might be emitted on a thread */
+static void
+job_finished_callback (GVfsJob *job,
+ GVfsDaemon *daemon)
+{
+ g_mutex_lock (daemon->priv->lock);
+ g_queue_remove (daemon->priv->jobs, job);
+ queue_start_jobs_at_idle (daemon);
+ g_mutex_unlock (daemon->priv->lock);
+ g_object_unref (job);
}
static void
-close_wrapper (gpointer p)
+start_or_queue_job (GVfsDaemon *daemon,
+ GVfsJob *job)
{
- close (GPOINTER_TO_INT (p));
+ g_mutex_lock (daemon->priv->lock);
+ g_queue_push_tail (daemon->priv->jobs, job);
+ g_mutex_unlock (daemon->priv->lock);
+ g_signal_connect (job, "finished", (GCallback)job_finished_callback, daemon);
+
+ /* Can we start the job immediately */
+ if (!g_vfs_job_start (job))
+ {
+ /* Didn't start, queue as pending */
+ g_queue_push_tail (daemon->priv->pending_jobs, job);
+ }
}
static void
@@ -323,9 +356,7 @@ daemon_peer_connection_setup (GVfsDaemon *daemon,
g_printerr ("Failed to register object with new dbus peer connection.\n");
}
- if (!dbus_connection_set_data (dbus_conn, extra_fd_slot, GINT_TO_POINTER (extra_fd), close_wrapper))
- g_error ("Out of memory");
-
+ dbus_connection_add_fd_send_fd (dbus_conn, extra_fd);
}
#ifdef __linux__
@@ -620,6 +651,7 @@ daemon_handle_get_connection (DBusConnection *conn,
g_io_channel_unref (channel);
reply = dbus_message_new_method_return (message);
+ /* TODO: Check OOM */
dbus_message_append_args (reply,
DBUS_TYPE_STRING, &address1,
DBUS_TYPE_STRING, &address2,
@@ -656,7 +688,9 @@ daemon_message_func (DBusConnection *conn,
gpointer data)
{
GVfsDaemon *daemon = data;
-
+ GVfsJob *job;
+
+ job = NULL;
if (dbus_message_is_method_call (message,
G_VFS_DBUS_DAEMON_INTERFACE,
G_VFS_DBUS_OP_GET_CONNECTION))
@@ -664,10 +698,13 @@ daemon_message_func (DBusConnection *conn,
else if (dbus_message_is_method_call (message,
G_VFS_DBUS_DAEMON_INTERFACE,
G_VFS_DBUS_OP_OPEN_FOR_READ))
- daemon_handle_open_for_read (daemon, conn, message);
+ job = g_vfs_job_open_for_read_new (daemon, conn, message);
else
return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+ if (job)
+ start_or_queue_job (daemon, job);
+
return DBUS_HANDLER_RESULT_HANDLED;
}
@@ -676,3 +713,16 @@ gboolean
{
return daemon->priv->active;
}
+
+
+/* Calling this on a thread is allowed */
+void
+g_vfs_daemon_register_read_handle (GVfsDaemon *daemon,
+ GVfsReadHandle *handle)
+{
+ g_mutex_lock (daemon->priv->lock);
+ daemon->priv->read_handles = g_list_append (daemon->priv->read_handles,
+ handle);
+ g_mutex_unlock (daemon->priv->lock);
+}
+
diff --git a/daemon/gvfsdaemon.h b/daemon/gvfsdaemon.h
index 6cae46d4..825a1d77 100644
--- a/daemon/gvfsdaemon.h
+++ b/daemon/gvfsdaemon.h
@@ -2,7 +2,7 @@
#define __G_VFS_DAEMON_H__
#include <glib-object.h>
-#include <gvfsdaemonbackend.h>
+#include <gvfsreadhandle.h>
G_BEGIN_DECLS
@@ -17,10 +17,14 @@ typedef struct _GVfsDaemon GVfsDaemon;
typedef struct _GVfsDaemonClass GVfsDaemonClass;
typedef struct _GVfsDaemonPrivate GVfsDaemonPrivate;
+/* Placed here to fix circular ref problems in headers */
+typedef struct _GVfsDaemonBackend GVfsDaemonBackend;
+
struct _GVfsDaemon
{
GObject parent_instance;
+ GVfsDaemonBackend *backend;
GVfsDaemonPrivate *priv;
};
@@ -38,6 +42,9 @@ GVfsDaemon *g_vfs_daemon_new (const char *mountpoint,
GVfsDaemonBackend *backend);
gboolean g_vfs_daemon_is_active (GVfsDaemon *daemon);
+void g_vfs_daemon_register_read_handle (GVfsDaemon *daemon,
+ GVfsReadHandle *handle);
+
G_END_DECLS
diff --git a/daemon/gvfsdaemonbackend.h b/daemon/gvfsdaemonbackend.h
index 9cdb9816..842b6e63 100644
--- a/daemon/gvfsdaemonbackend.h
+++ b/daemon/gvfsdaemonbackend.h
@@ -1,8 +1,9 @@
#ifndef __G_VFS_DAEMON_BACKEND_H__
#define __G_VFS_DAEMON_BACKEND_H__
-#include <gvfsjob.h>
#include <gvfs/gvfstypes.h>
+#include <gvfsdaemon.h>
+#include <gvfsjob.h>
G_BEGIN_DECLS
@@ -13,7 +14,7 @@ G_BEGIN_DECLS
#define G_IS_VFS_DAEMON_BACKEND_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_DAEMON_BACKEND))
#define G_VFS_DAEMON_BACKEND_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_DAEMON_BACKEND, GVfsDaemonBackendClass))
-typedef struct _GVfsDaemonBackend GVfsDaemonBackend;
+/* GVfsDaemonBackend defined in gvfsdaemon.h to fix circular defines */
typedef struct _GVfsDaemonBackendClass GVfsDaemonBackendClass;
typedef gpointer GVfsHandle;
diff --git a/daemon/gvfsdaemonbackendtest.c b/daemon/gvfsdaemonbackendtest.c
index 3205c945..4c70549b 100644
--- a/daemon/gvfsdaemonbackendtest.c
+++ b/daemon/gvfsdaemonbackendtest.c
@@ -1,9 +1,21 @@
#include <config.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <string.h>
+
+#include <glib/gstdio.h>
+
#include "gvfsdaemonbackendtest.h"
+#include "gvfsjobopenforread.h"
G_DEFINE_TYPE (GVfsDaemonBackendTest, g_vfs_daemon_backend_test, G_TYPE_VFS_DAEMON_BACKEND);
+static gboolean open_for_read (GVfsDaemonBackend *backend,
+ GVfsJobOpenForRead *job,
+ char *filename);
+
static void
g_vfs_daemon_backend_test_finalize (GObject *object)
{
@@ -19,11 +31,11 @@ static void
g_vfs_daemon_backend_test_class_init (GVfsDaemonBackendTestClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
- //GVfsDaemonBackendClass *backend_class = G_VFS_DAEMON_BACKEND_CLASS (klass);
+ GVfsDaemonBackendClass *backend_class = G_VFS_DAEMON_BACKEND_CLASS (klass);
gobject_class->finalize = g_vfs_daemon_backend_test_finalize;
- //backend_class->open_for_read = open_for_read;
+ backend_class->open_for_read = open_for_read;
}
static void
@@ -40,3 +52,44 @@ g_vfs_daemon_backend_test_new (void)
return backend;
}
+static gboolean
+open_idle_cb (gpointer data)
+{
+ GVfsJobOpenForRead *job = data;
+ int fd;
+
+ fd = g_open (job->filename, O_RDONLY);
+ if (fd == -1)
+ {
+ g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ "Error opening file %s: %s",
+ job->filename, g_strerror (errno));
+ }
+ else
+ {
+ g_vfs_job_open_for_read_set_handle (job, GINT_TO_POINTER (fd));
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ return FALSE;
+}
+
+static gboolean
+open_for_read (GVfsDaemonBackend *backend,
+ GVfsJobOpenForRead *job,
+ char *filename)
+{
+ GError *error;
+
+ if (strcmp (filename, "/fail") == 0)
+ {
+ error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_IO, "Test error");
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ return TRUE;
+ }
+ else
+ {
+ g_idle_add (open_idle_cb, job);
+ return TRUE;
+ }
+}
diff --git a/daemon/gvfsdaemonutils.c b/daemon/gvfsdaemonutils.c
index 132bfd13..2dc3fa04 100644
--- a/daemon/gvfsdaemonutils.c
+++ b/daemon/gvfsdaemonutils.c
@@ -1,18 +1,168 @@
#include <config.h>
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib/gthread.h>
+#include <glib/gi18n.h>
#include "gvfsdaemonutils.h"
+static gint32 extra_fd_slot = -1;
+static GStaticMutex extra_lock = G_STATIC_MUTEX_INIT;
+
+typedef struct {
+ int extra_fd;
+ int fd_count;
+} ConnectionExtra;
+
+/* We use _ for escaping, so its not valid */
+#define VALID_INITIAL_NAME_CHARACTER(c) \
+ ( ((c) >= 'A' && (c) <= 'Z') || \
+ ((c) >= 'a' && (c) <= 'z') )
+#define VALID_NAME_CHARACTER(c) \
+ ( ((c) >= '0' && (c) <= '9') || \
+ ((c) >= 'A' && (c) <= 'Z') || \
+ ((c) >= 'a' && (c) <= 'z'))
+
+
+static void
+append_escaped_name (GString *s,
+ const char *unescaped)
+{
+ char c;
+ gboolean first;
+ static const gchar hex[16] = "0123456789ABCDEF";
+
+ while ((c = *unescaped++) != 0)
+ {
+ if (first)
+ {
+ if (VALID_INITIAL_NAME_CHARACTER (c))
+ {
+ g_string_append_c (s, c);
+ continue;
+ }
+ }
+ else
+ {
+ if (VALID_NAME_CHARACTER (c))
+ {
+ g_string_append_c (s, c);
+ continue;
+ }
+ }
+
+ first = FALSE;
+ g_string_append_c (s, '_');
+ g_string_append_c (s, hex[((guchar)c) >> 4]);
+ g_string_append_c (s, hex[((guchar)c) & 0xf]);
+ }
+}
+
DBusMessage *
dbus_message_new_error_from_gerror (DBusMessage *message,
GError *error)
{
- char *error_name;
DBusMessage *reply;
-
- error_name = g_strdup_printf ("org.glib.GError.%s.%d",
- g_quark_to_string (error->domain),
- error->code);
- reply = dbus_message_new_error (message, error_name, error->message);
- g_free (error_name);
+ GString *str;
+
+ str = g_string_new ("org.glib.GError.");
+ append_escaped_name (str, g_quark_to_string (error->domain));
+ g_string_append_printf (str, ".c%d", error->code);
+ reply = dbus_message_new_error (message, str->str, error->message);
+ g_string_free (str, TRUE);
return reply;
}
+
+static void
+free_extra (gpointer p)
+{
+ ConnectionExtra *extra = p;
+ close (extra->extra_fd);
+ g_free (extra);
+}
+
+void
+dbus_connection_add_fd_send_fd (DBusConnection *connection,
+ int extra_fd)
+{
+ ConnectionExtra *extra;
+
+ if (extra_fd_slot == -1 &&
+ !dbus_connection_allocate_data_slot (&extra_fd_slot))
+ g_error ("Unable to allocate data slot");
+
+ extra = g_new0 (ConnectionExtra, 1);
+ extra->extra_fd = extra_fd;
+
+ if (!dbus_connection_set_data (connection, extra_fd_slot, extra, free_extra))
+ g_error ("Out of memory");
+}
+
+static int
+send_fd (int connection_fd,
+ int fd)
+{
+ struct msghdr msg;
+ struct iovec vec;
+ char buf[1] = {'x'};
+ char ccmsg[CMSG_SPACE (sizeof (fd))];
+ struct cmsghdr *cmsg;
+ int ret;
+
+ msg.msg_name = NULL;
+ msg.msg_namelen = 0;
+
+ vec.iov_base = buf;
+ vec.iov_len = 1;
+ msg.msg_iov = &vec;
+ msg.msg_iovlen = 1;
+ msg.msg_control = ccmsg;
+ msg.msg_controllen = sizeof (ccmsg);
+ cmsg = CMSG_FIRSTHDR (&msg);
+ cmsg->cmsg_level = SOL_SOCKET;
+ cmsg->cmsg_type = SCM_RIGHTS;
+ cmsg->cmsg_len = CMSG_LEN (sizeof(fd));
+ *(int*)CMSG_DATA (cmsg) = fd;
+ msg.msg_controllen = cmsg->cmsg_len;
+ msg.msg_flags = 0;
+
+ ret = sendmsg (connection_fd, &msg, 0);
+ g_print ("sendmesg ret: %d\n", ret);
+ return ret;
+}
+
+gboolean
+dbus_connection_send_fd (DBusConnection *connection,
+ int fd,
+ int *fd_id,
+ GError **error)
+{
+ ConnectionExtra *extra;
+
+ g_assert (extra_fd_slot != -1);
+
+ extra = dbus_connection_get_data (connection, extra_fd_slot);
+
+ g_assert (extra != NULL);
+
+ g_static_mutex_lock (&extra_lock);
+
+ if (send_fd (extra->extra_fd, fd) == -1)
+ {
+ g_set_error (error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ _("Error sending fd: %s"),
+ g_strerror (errno));
+ return FALSE;
+ }
+
+ *fd_id = extra->fd_count++;
+
+ g_static_mutex_unlock (&extra_lock);
+
+ return TRUE;
+}
diff --git a/daemon/gvfsdaemonutils.h b/daemon/gvfsdaemonutils.h
index 7f205950..50654ab4 100644
--- a/daemon/gvfsdaemonutils.h
+++ b/daemon/gvfsdaemonutils.h
@@ -3,12 +3,17 @@
#include <glib-object.h>
#include <dbus/dbus.h>
-#include <gvfsreadrequest.h>
G_BEGIN_DECLS
DBusMessage *dbus_message_new_error_from_gerror (DBusMessage *message,
GError *error);
+void dbus_connection_add_fd_send_fd (DBusConnection *connection,
+ int extra_fd);
+gboolean dbus_connection_send_fd (DBusConnection *connection,
+ int fd,
+ int *fd_id,
+ GError **error);
G_END_DECLS
diff --git a/daemon/gvfsjob.c b/daemon/gvfsjob.c
index 4e488385..c140e922 100644
--- a/daemon/gvfsjob.c
+++ b/daemon/gvfsjob.c
@@ -10,10 +10,11 @@
#include <glib/gi18n.h>
#include "gvfsjob.h"
-G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_VFS_JOB);
+G_DEFINE_TYPE (GVfsJob, g_vfs_job, G_TYPE_OBJECT);
enum {
- CANCEL,
+ CANCELLED,
+ FINISHED,
LAST_SIGNAL
};
@@ -40,11 +41,19 @@ g_vfs_job_class_init (GVfsJobClass *klass)
gobject_class->finalize = g_vfs_job_finalize;
- signals[CANCEL] =
- g_signal_new ("done",
+ signals[CANCELLED] =
+ g_signal_new ("cancelled",
G_TYPE_FROM_CLASS (gobject_class),
G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GVfsJobClass, cancel),
+ G_STRUCT_OFFSET (GVfsJobClass, cancelled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+ signals[FINISHED] =
+ g_signal_new ("finished",
+ G_TYPE_FROM_CLASS (gobject_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GVfsJobClass, finished),
NULL, NULL,
g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0);
@@ -56,6 +65,15 @@ g_vfs_job_init (GVfsJob *job)
{
}
+gboolean
+g_vfs_job_start (GVfsJob *job)
+{
+ GVfsJobClass *class;
+
+ class = G_VFS_JOB_GET_CLASS (job);
+ return class->start (job);
+}
+
void
g_vfs_job_cancel (GVfsJob *job)
{
@@ -63,16 +81,75 @@ g_vfs_job_cancel (GVfsJob *job)
return;
job->cancelled = TRUE;
- g_signal_emit (job, signals[CANCEL], 0);
+ g_signal_emit (job, signals[CANCELLED], 0);
+}
+
+static void
+g_vfs_job_send_reply (GVfsJob *job)
+{
+ GVfsJobClass *class;
+
+ class = G_VFS_JOB_GET_CLASS (job);
+ class->send_reply (job);
+}
+
+void
+g_vfs_job_failed (GVfsJob *job,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...)
+{
+ va_list args;
+ char *message;
+
+ if (job->failed)
+ return;
+
+ job->failed = TRUE;
+
+ va_start (args, format);
+ message = g_strdup_vprintf (format, args);
+ va_end (args);
+
+ job->error = g_error_new (domain, code, message);
+ g_free (message);
+
+ g_vfs_job_send_reply (job);
}
void
-g_vfs_job_set_failed (GVfsJob *job,
- GError *error)
+g_vfs_job_failed_from_error (GVfsJob *job,
+ GError *error)
{
if (job->failed)
return;
job->failed = TRUE;
job->error = g_error_copy (error);
+ g_vfs_job_send_reply (job);
+}
+
+void
+g_vfs_job_succeeded (GVfsJob *job)
+{
+ job->failed = FALSE;
+ g_vfs_job_send_reply (job);
+}
+
+
+gboolean
+g_vfs_job_is_finished (GVfsJob *job)
+{
+ return job->finished;
+}
+
+/* Might be called on an i/o thread */
+void
+g_vfs_job_emit_finished (GVfsJob *job)
+{
+ g_assert (!job->finished);
+
+ job->finished = TRUE;
+ g_signal_emit (job, signals[FINISHED], 0);
}
diff --git a/daemon/gvfsjob.h b/daemon/gvfsjob.h
index 84f29409..9f9e86da 100644
--- a/daemon/gvfsjob.h
+++ b/daemon/gvfsjob.h
@@ -2,6 +2,7 @@
#define __G_VFS_JOB_H__
#include <glib-object.h>
+#include <gvfsdaemon.h>
G_BEGIN_DECLS
@@ -12,20 +13,22 @@ G_BEGIN_DECLS
#define G_IS_VFS_JOB_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB))
#define G_VFS_JOB_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB, GVfsJobClass))
-typedef struct _GVfsJob GVfsJob;
-typedef struct _GVfsJobClass GVfsJobClass;
+typedef struct _GVfsJob GVfsJob;
+typedef struct _GVfsJobClass GVfsJobClass;
-/* Temp typedefs */
-typedef GVfsJob GVfsJobOpenForRead;
-typedef GVfsJob GVfsJobRead;
-typedef GVfsJob GVfsJobReadSeek;
+/* Define these here to avoid circular includes */
+typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead;
+typedef struct _GVfsJobRead GVfsJobRead;
+typedef struct _GVfsJobReadSeek GVfsJobReadSeek;
struct _GVfsJob
{
GObject parent_instance;
+ GVfsDaemon *daemon;
guint failed : 1;
guint cancelled : 1;
+ guint finished : 1;
GError *error;
};
@@ -34,20 +37,29 @@ struct _GVfsJobClass
GObjectClass parent_class;
/* signals */
- void (*cancel) (GVfsJob *job);
+ void (*cancelled) (GVfsJob *job);
void (*finished) (GVfsJob *job);
/* vtable */
gboolean (*start) (GVfsJob *job);
-
+ void (*send_reply) (GVfsJob *job);
};
GType g_vfs_job_get_type (void) G_GNUC_CONST;
-void g_vfs_job_cancel (GVfsJob *job);
-void g_vfs_job_set_failed (GVfsJob *job,
- GError *error);
+gboolean g_vfs_job_is_finished (GVfsJob *job);
+void g_vfs_job_cancel (GVfsJob *job);
+gboolean g_vfs_job_start (GVfsJob *job);
+void g_vfs_job_emit_finished (GVfsJob *job);
+void g_vfs_job_failed (GVfsJob *job,
+ GQuark domain,
+ gint code,
+ const gchar *format,
+ ...) G_GNUC_PRINTF (4, 5);
+void g_vfs_job_failed_from_error (GVfsJob *job,
+ GError *error);
+void g_vfs_job_succeeded (GVfsJob *job);
G_END_DECLS
diff --git a/daemon/gvfsjobopenforread.c b/daemon/gvfsjobopenforread.c
new file mode 100644
index 00000000..43fcb7d9
--- /dev/null
+++ b/daemon/gvfsjobopenforread.c
@@ -0,0 +1,177 @@
+#include <config.h>
+
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <glib/gi18n.h>
+#include "gvfsreadhandle.h"
+#include "gvfsjobopenforread.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobOpenForRead, g_vfs_job_open_for_read, G_TYPE_VFS_JOB);
+
+static gboolean start (GVfsJob *job);
+static void send_reply (GVfsJob *job);
+
+static void
+g_vfs_job_open_for_read_finalize (GObject *object)
+{
+ GVfsJobOpenForRead *job;
+
+ job = G_VFS_JOB_OPEN_FOR_READ (object);
+
+ if (job->message)
+ dbus_message_unref (job->message);
+
+ /* TODO: manage backend_handle if not put in readhandle */
+
+ g_free (job->filename);
+
+ if (G_OBJECT_CLASS (g_vfs_job_open_for_read_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_job_open_for_read_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_open_for_read_class_init (GVfsJobOpenForReadClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_job_open_for_read_finalize;
+
+ job_class->start = start;
+ job_class->send_reply = send_reply;
+}
+
+static void
+g_vfs_job_open_for_read_init (GVfsJobOpenForRead *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_open_for_read_new (GVfsDaemon *daemon,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ GVfsJobOpenForRead *job;
+ DBusMessage *reply;
+ DBusError derror;
+ int path_len;
+ const char *path_data;
+
+ dbus_error_init (&derror);
+ if (!dbus_message_get_args (message, &derror,
+ DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+ &path_data, &path_len,
+ 0))
+ {
+ reply = dbus_message_new_error (message,
+ derror.name,
+ derror.message);
+ dbus_error_free (&derror);
+
+ dbus_connection_send (connection, reply, NULL);
+ return NULL;
+ }
+
+ job = g_object_new (G_TYPE_VFS_JOB_OPEN_FOR_READ, NULL);
+
+ G_VFS_JOB (job)->daemon = daemon;
+ job->connection = connection; /* TODO: ref? */
+ job->message = dbus_message_ref (message);
+ job->filename = g_strndup (path_data, path_len);
+
+ return G_VFS_JOB (job);
+}
+
+static gboolean
+start (GVfsJob *job)
+{
+ GVfsDaemonBackendClass *class;
+ GVfsJobOpenForRead *op_job = G_VFS_JOB_OPEN_FOR_READ (job);
+
+ class = G_VFS_DAEMON_BACKEND_GET_CLASS (job->daemon->backend);
+
+ return class->open_for_read (job->daemon->backend,
+ op_job,
+ op_job->filename);
+}
+
+void
+g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job,
+ GVfsHandle *handle)
+{
+ job->backend_handle = handle;
+}
+
+/* Might be called on an i/o thread */
+static DBusMessage *
+create_reply (GVfsJob *job,
+ DBusConnection *connection,
+ DBusMessage *message)
+{
+ GVfsJobOpenForRead *open_job = G_VFS_JOB_OPEN_FOR_READ (job);
+ GVfsReadHandle *handle;
+ DBusMessage *reply;
+ GError *error;
+ int fd_id;
+ gboolean res;
+
+ g_assert (open_job->backend_handle != NULL);
+
+ error = NULL;
+ handle = g_vfs_read_handle_new (&error);
+ if (handle == NULL)
+ {
+ reply = dbus_message_new_error_from_gerror (message, error);
+ g_error_free (error);
+ return reply;
+ }
+
+ if (!dbus_connection_send_fd (connection,
+ g_vfs_read_handle_get_remote_fd (handle),
+ &fd_id, &error))
+ {
+ reply = dbus_message_new_error_from_gerror (message, error);
+ g_error_free (error);
+ g_object_unref (handle);
+ return reply;
+ }
+
+ reply = dbus_message_new_method_return (message);
+ res = dbus_message_append_args (reply,
+ DBUS_TYPE_UINT32, &fd_id,
+ DBUS_TYPE_INVALID);
+
+ g_vfs_read_handle_close_remote_fd (handle);
+ g_vfs_read_handle_set_data (handle, open_job->backend_handle);
+ g_vfs_daemon_register_read_handle (job->daemon, handle);
+ open_job->backend_handle = NULL;
+
+ return reply;
+}
+
+/* Might be called on an i/o thread */
+static void
+send_reply (GVfsJob *job)
+{
+ GVfsJobOpenForRead *open_job = G_VFS_JOB_OPEN_FOR_READ (job);
+ DBusMessage *reply;
+
+ if (job->failed)
+ reply = dbus_message_new_error_from_gerror (open_job->message, job->error);
+ else
+ reply = create_reply (job, open_job->connection, open_job->message);
+
+ g_assert (reply != NULL);
+
+ /* Queues reply (threadsafely), actually sends it in mainloop */
+ dbus_connection_send (open_job->connection, reply, NULL);
+ dbus_message_unref (reply);
+
+ g_vfs_job_emit_finished (job);
+}
diff --git a/daemon/gvfsjobopenforread.h b/daemon/gvfsjobopenforread.h
new file mode 100644
index 00000000..f86cf0c1
--- /dev/null
+++ b/daemon/gvfsjobopenforread.h
@@ -0,0 +1,47 @@
+#ifndef __G_VFS_JOB_OPEN_FOR_READ_H__
+#define __G_VFS_JOB_OPEN_FOR_READ_H__
+
+#include <dbus/dbus.h>
+#include <gvfsjob.h>
+#include <gvfsdaemonbackend.h>
+
+
+G_BEGIN_DECLS
+
+#define G_TYPE_VFS_JOB_OPEN_FOR_READ (g_vfs_job_open_for_read_get_type ())
+#define G_VFS_JOB_OPEN_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForRead))
+#define G_VFS_JOB_OPEN_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForReadClass))
+#define G_IS_VFS_JOB_OPEN_FOR_READ(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ))
+#define G_IS_VFS_JOB_OPEN_FOR_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_OPEN_FOR_READ))
+#define G_VFS_JOB_OPEN_FOR_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_OPEN_FOR_READ, GVfsJobOpenForReadClass))
+
+/* GVfsJobOpenForRead declared in gvfsjob.h */
+typedef struct _GVfsJobOpenForReadClass GVfsJobOpenForReadClass;
+
+struct _GVfsJobOpenForRead
+{
+ GVfsJob parent_instance;
+
+ DBusConnection *connection;
+ DBusMessage *message;
+ char *filename;
+ GVfsHandle *backend_handle;
+};
+
+struct _GVfsJobOpenForReadClass
+{
+ GVfsJobClass parent_class;
+};
+
+GType g_vfs_job_open_for_read_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_open_for_read_new (GVfsDaemon *daemon,
+ DBusConnection *connection,
+ DBusMessage *message);
+
+void g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job,
+ GVfsHandle *handle);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_OPEN_FOR_READ_H__ */
diff --git a/daemon/gvfsreadhandle.c b/daemon/gvfsreadhandle.c
new file mode 100644
index 00000000..24e6aed6
--- /dev/null
+++ b/daemon/gvfsreadhandle.c
@@ -0,0 +1,113 @@
+#include <config.h>
+
+#include <unistd.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <glib-object.h>
+#include <glib/gi18n.h>
+#include <dbus-gmain.h>
+#include <gvfsreadhandle.h>
+
+G_DEFINE_TYPE (GVfsReadHandle, g_vfs_read_handle, G_TYPE_OBJECT);
+
+enum {
+ PROP_0,
+};
+
+struct _GVfsReadHandlePrivate
+{
+ int fd;
+ int remote_fd;
+
+ gpointer data;
+};
+
+static void
+g_vfs_read_handle_finalize (GObject *object)
+{
+ GVfsReadHandle *read_handle;
+
+ read_handle = G_VFS_READ_HANDLE (object);
+
+ if (read_handle->priv->fd != -1)
+ close (read_handle->priv->fd);
+
+ if (read_handle->priv->remote_fd != -1)
+ close (read_handle->priv->remote_fd);
+
+ if (G_OBJECT_CLASS (g_vfs_read_handle_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_read_handle_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_read_handle_class_init (GVfsReadHandleClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (GVfsReadHandlePrivate));
+
+ gobject_class->finalize = g_vfs_read_handle_finalize;
+}
+
+static void
+g_vfs_read_handle_init (GVfsReadHandle *handle)
+{
+ handle->priv = G_TYPE_INSTANCE_GET_PRIVATE (handle,
+ G_TYPE_VFS_READ_HANDLE,
+ GVfsReadHandlePrivate);
+ handle->priv->fd = -1;
+ handle->priv->remote_fd = -1;
+}
+
+GVfsReadHandle *
+g_vfs_read_handle_new (GError **error)
+{
+ GVfsReadHandle *handle;
+ int socket_fds[2];
+ int ret;
+
+ ret = socketpair (AF_UNIX, SOCK_STREAM, 0, socket_fds);
+ if (ret == -1)
+ {
+ g_set_error (error, G_FILE_ERROR,
+ g_file_error_from_errno (errno),
+ _("Error creating socket pair"));
+ return NULL;
+ }
+
+ handle = g_object_new (G_TYPE_VFS_READ_HANDLE, NULL);
+ handle->priv->fd = socket_fds[0];
+ handle->priv->remote_fd = socket_fds[1];
+
+ return handle;
+}
+
+int
+g_vfs_read_handle_get_fd (GVfsReadHandle *handle)
+{
+ return handle->priv->fd;
+}
+
+int
+ g_vfs_read_handle_get_remote_fd (GVfsReadHandle *handle)
+{
+ return handle->priv->remote_fd;
+}
+
+void
+ g_vfs_read_handle_close_remote_fd (GVfsReadHandle *handle)
+{
+ close (handle->priv->remote_fd);
+ handle->priv->remote_fd = -1;
+}
+
+void
+g_vfs_read_handle_set_data (GVfsReadHandle *read_handle,
+ gpointer data)
+{
+ read_handle->priv->data = data;
+}
diff --git a/daemon/gvfsreadhandle.h b/daemon/gvfsreadhandle.h
new file mode 100644
index 00000000..760c96d8
--- /dev/null
+++ b/daemon/gvfsreadhandle.h
@@ -0,0 +1,54 @@
+#ifndef __G_VFS_READ_HANDLE_H__
+#define __G_VFS_READ_HANDLE_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define G_TYPE_VFS_READ_HANDLE (g_vfs_read_handle_get_type ())
+#define G_VFS_READ_HANDLE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_READ_HANDLE, GVfsReadHandle))
+#define G_VFS_READ_HANDLE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_READ_HANDLE, GVfsReadHandleClass))
+#define G_IS_VFS_READ_HANDLE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_READ_HANDLE))
+#define G_IS_VFS_READ_HANDLE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_READ_HANDLE))
+#define G_VFS_READ_HANDLE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_READ_HANDLE, GVfsReadHandleClass))
+
+typedef struct _GVfsReadHandle GVfsReadHandle;
+typedef struct _GVfsReadHandleClass GVfsReadHandleClass;
+typedef struct _GVfsReadHandlePrivate GVfsReadHandlePrivate;
+
+struct _GVfsReadHandle
+{
+ GObject parent_instance;
+
+ GVfsReadHandlePrivate *priv;
+};
+
+struct _GVfsReadHandleClass
+{
+ GObjectClass parent_class;
+
+ /* vtable */
+
+ void (*wants_data) (GVfsReadHandle *handle);
+};
+
+GType g_vfs_read_handle_get_type (void) G_GNUC_CONST;
+
+GVfsReadHandle *g_vfs_read_handle_new (GError **error);
+int g_vfs_read_handle_get_fd (GVfsReadHandle *read_handle);
+int g_vfs_read_handle_get_remote_fd (GVfsReadHandle *read_handle);
+void g_vfs_read_handle_close_remote_fd (GVfsReadHandle *read_handle);
+void g_vfs_read_handle_set_data (GVfsReadHandle *read_handle,
+ gpointer data);
+
+gboolean g_vfs_read_handle_wants_data (GVfsReadHandle *read_handle);
+gsize g_vfs_read_handle_get_requested_size (GVfsReadHandle *read_handle);
+void g_vfs_read_handle_send_data (GVfsReadHandle *read_handle,
+ char *data,
+ gsize length);
+
+/* TODO: i/o priority? */
+
+G_END_DECLS
+
+#endif /* __G_VFS_READ_HANDLE_H__ */
diff --git a/daemon/gvfsreadrequest.c b/daemon/gvfsreadrequest.c
deleted file mode 100644
index eb3ca67a..00000000
--- a/daemon/gvfsreadrequest.c
+++ /dev/null
@@ -1,111 +0,0 @@
-#include <config.h>
-
-#include <unistd.h>
-#include <errno.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <glib.h>
-#include <glib-object.h>
-#include <glib/gi18n.h>
-#include <dbus-gmain.h>
-#include <gvfsreadrequest.h>
-
-G_DEFINE_TYPE (GVfsReadRequest, g_vfs_read_request, G_TYPE_OBJECT);
-
-enum {
- PROP_0,
-};
-
-struct _GVfsReadRequestPrivate
-{
- int fd;
- int remote_fd;
-};
-
-static void
-g_vfs_read_request_finalize (GObject *object)
-{
- GVfsReadRequest *read_request;
-
- read_request = G_VFS_READ_REQUEST (object);
-
- if (read_request->priv->fd != -1)
- close (read_request->priv->fd);
-
- if (read_request->priv->remote_fd != -1)
- close (read_request->priv->remote_fd);
-
- if (G_OBJECT_CLASS (g_vfs_read_request_parent_class)->finalize)
- (*G_OBJECT_CLASS (g_vfs_read_request_parent_class)->finalize) (object);
-}
-
-static void
-g_vfs_read_request_class_init (GVfsReadRequestClass *klass)
-{
- GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
-
- g_type_class_add_private (klass, sizeof (GVfsReadRequestPrivate));
-
- gobject_class->finalize = g_vfs_read_request_finalize;
-}
-
-static void
-g_vfs_read_request_init (GVfsReadRequest *request)
-{
- request->priv = G_TYPE_INSTANCE_GET_PRIVATE (request,
- G_TYPE_VFS_READ_REQUEST,
- GVfsReadRequestPrivate);
- request->priv->fd = -1;
- request->priv->remote_fd = -1;
-}
-
-GVfsReadRequest *
-g_vfs_read_request_new (GError **error)
-{
- GVfsReadRequest *request;
- int socket_fds[2];
- int ret;
-
- ret = socketpair (AF_UNIX, SOCK_STREAM, 0, socket_fds);
- if (ret == -1)
- {
- g_set_error (error, G_FILE_ERROR,
- g_file_error_from_errno (errno),
- _("Error creating socket pair"));
- return NULL;
- }
-
- request = g_object_new (G_TYPE_VFS_READ_REQUEST, NULL);
- request->priv->fd = socket_fds[0];
- request->priv->remote_fd = socket_fds[1];
-
- return request;
-}
-
-int
-g_vfs_read_request_get_fd (GVfsReadRequest *request)
-{
- return request->priv->fd;
-}
-
-int
- g_vfs_read_request_get_remote_fd (GVfsReadRequest *request)
-{
- return request->priv->remote_fd;
-}
-
-void
- g_vfs_read_request_close_remote_fd (GVfsReadRequest *request)
-{
- close (request->priv->remote_fd);
- request->priv->remote_fd = -1;
-}
-
-void
-g_vfs_read_request_set_filename (GVfsReadRequest *request,
- const char *filename)
-{
- g_error ("TODO");
-}
diff --git a/daemon/gvfsreadrequest.h b/daemon/gvfsreadrequest.h
deleted file mode 100644
index 3187bc97..00000000
--- a/daemon/gvfsreadrequest.h
+++ /dev/null
@@ -1,54 +0,0 @@
-#ifndef __G_VFS_READ_REQUEST_H__
-#define __G_VFS_READ_REQUEST_H__
-
-#include <glib-object.h>
-
-G_BEGIN_DECLS
-
-#define G_TYPE_VFS_READ_REQUEST (g_vfs_read_request_get_type ())
-#define G_VFS_READ_REQUEST(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_READ_REQUEST, GVfsReadRequest))
-#define G_VFS_READ_REQUEST_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_READ_REQUEST, GVfsReadRequestClass))
-#define G_IS_VFS_READ_REQUEST(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_READ_REQUEST))
-#define G_IS_VFS_READ_REQUEST_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_READ_REQUEST))
-#define G_VFS_READ_REQUEST_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_READ_REQUEST, GVfsReadRequestClass))
-
-typedef struct _GVfsReadRequest GVfsReadRequest;
-typedef struct _GVfsReadRequestClass GVfsReadRequestClass;
-typedef struct _GVfsReadRequestPrivate GVfsReadRequestPrivate;
-
-struct _GVfsReadRequest
-{
- GObject parent_instance;
-
- GVfsReadRequestPrivate *priv;
-};
-
-struct _GVfsReadRequestClass
-{
- GObjectClass parent_class;
-
- /* vtable */
-
- void (*wants_data) (GVfsReadRequest *request);
-};
-
-GType g_vfs_read_request_get_type (void) G_GNUC_CONST;
-
-GVfsReadRequest *g_vfs_read_request_new (GError **error);
-int g_vfs_read_request_get_fd (GVfsReadRequest *read_request);
-int g_vfs_read_request_get_remote_fd (GVfsReadRequest *read_request);
-void g_vfs_read_request_close_remote_fd (GVfsReadRequest *read_request);
-void g_vfs_read_request_set_filename (GVfsReadRequest *read_request,
- const char *filename);
-
-gboolean g_vfs_read_request_wants_data (GVfsReadRequest *read_request);
-gsize g_vfs_read_request_get_requested_size (GVfsReadRequest *read_request);
-void g_vfs_read_request_send_data (GVfsReadRequest *read_request,
- char *data,
- gsize length);
-
-/* TODO: i/o priority? */
-
-G_END_DECLS
-
-#endif /* __G_VFS_READ_REQUEST_H__ */
diff --git a/daemon/main.c b/daemon/main.c
index 55f7f579..243faec4 100644
--- a/daemon/main.c
+++ b/daemon/main.c
@@ -37,7 +37,9 @@ main (int argc, char *argv[])
GMainLoop *loop;
GVfsDaemon *daemon;
GVfsDaemonBackendTest *backend;
-
+
+ g_thread_init (NULL);
+
g_type_init ();
if (!init_dbus ())
diff --git a/gvfs/gunixfileinputstream.c b/gvfs/gunixfileinputstream.c
index 9a7d639f..ea44c2ef 100644
--- a/gvfs/gunixfileinputstream.c
+++ b/gvfs/gunixfileinputstream.c
@@ -144,6 +144,7 @@ g_unix_file_input_stream_open (GUnixFileInputStream *file,
int extra_fd;
DBusMessage *message, *reply;
DBusMessageIter iter;
+ guint32 fd_id;
if (file->priv->fd != -1)
return TRUE;
@@ -170,27 +171,18 @@ g_unix_file_input_stream_open (GUnixFileInputStream *file,
reply = dbus_connection_send_with_reply_and_block (connection, message, -1,
&derror);
dbus_message_unref (message);
-
if (!reply)
{
- g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO,
- "Error calling ReadFile: %s",
- derror.message);
+ _g_error_from_dbus (&derror, error);
dbus_error_free (&derror);
return FALSE;
}
- /* TODO: handle errors created with dbus_message_new_error?
- * dbus_message_is_error() ?
- */
- if (_g_error_from_dbus_message (reply, error))
- {
- dbus_message_unref (reply);
- return FALSE;
- }
-
/* No args in reply, only fd */
-
+ dbus_message_get_args (message, NULL,
+ DBUS_TYPE_UINT32, &fd_id,
+ DBUS_TYPE_INVALID);
+ /* TODO: verify fd id */
file->priv->fd = receive_fd (extra_fd);
g_print ("new fd: %d\n", file->priv->fd);
return TRUE;
diff --git a/gvfs/gvfsunixdbus.c b/gvfs/gvfsunixdbus.c
index 47c86473..f027b0c1 100644
--- a/gvfs/gvfsunixdbus.c
+++ b/gvfs/gvfsunixdbus.c
@@ -49,6 +49,29 @@ free_mount_connection (gpointer data)
dbus_connection_unref (conn);
}
+static void
+append_unescaped_dbus_name (GString *s,
+ const char *escaped,
+ const char *end)
+{
+ guchar c;
+
+ while (escaped < end)
+ {
+ c = *escaped++;
+ if (c == '_' &&
+ escaped < end)
+ {
+ c = g_ascii_xdigit_value (*escaped++) << 4;
+
+ if (escaped < end)
+ c |= g_ascii_xdigit_value (*escaped++);
+ }
+ g_string_append_c (s, c);
+ }
+}
+
+
/* We use _ for escaping */
#define VALID_INITIAL_BUS_NAME_CHARACTER(c) \
( ((c) >= 'A' && (c) <= 'Z') || \
@@ -273,48 +296,42 @@ _g_dbus_message_iter_append_filename (DBusMessageIter *iter, const char *filenam
return TRUE;
}
-gboolean
-_g_error_from_dbus_message (DBusMessage *message, GError **error)
+void
+_g_error_from_dbus (DBusError *derror,
+ GError **error)
{
- const char *str;
- const char *name;
- char *m, *gerror_name, *end;
+ const char *name, *end;;
+ char *m;
+ GString *str;
GQuark domain;
int code;
- if (dbus_message_get_type (message) != DBUS_MESSAGE_TYPE_ERROR)
- return FALSE;
-
- str = NULL;
- dbus_message_get_args (message, NULL,
- DBUS_TYPE_STRING, &str,
- DBUS_TYPE_INVALID);
-
-
- name = dbus_message_get_error_name (message);
- if (g_str_has_prefix (name, "org.glib.GError."))
+ if (g_str_has_prefix (derror->name, "org.glib.GError."))
{
- gerror_name = g_strdup (name + strlen ("org.glib.GError."));
- end = strchr (gerror_name, '.');
- if (end)
- *end++ = 0;
-
- domain = g_quark_from_string (gerror_name);
- g_free (gerror_name);
+ domain = 0;
+ code = 0;
+ name = derror->name + strlen ("org.glib.GError.");
+ end = strchr (name, '.');
if (end)
- code = atoi (end);
+ {
+ str = g_string_new (NULL);
+ append_unescaped_dbus_name (str, name, end);
+ domain = g_quark_from_string (str->str);
+ g_string_free (str, TRUE);
+
+ end++; /* skip . */
+ if (*end++ == 'c')
+ code = atoi (end);
+ }
- g_set_error (error, domain, code, str);
+ g_set_error (error, domain, code, "%s", derror->message);
}
/* TODO: Special case other types, like DBUS_ERROR_NO_MEMORY etc? */
else
{
- m = g_strdup_printf ("DBus error %s: %s", name, str);
- g_set_error (error, G_FILE_ERROR,
- G_FILE_ERROR_IO, m);
-
+ m = g_strdup_printf ("DBus error %s: %s", derror->name, derror->message);
+ g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO, "%s", m);
+ g_free (m);
}
-
- return TRUE;
}
diff --git a/gvfs/gvfsunixdbus.h b/gvfs/gvfsunixdbus.h
index cdfa3540..bfd6649d 100644
--- a/gvfs/gvfsunixdbus.h
+++ b/gvfs/gvfsunixdbus.h
@@ -11,7 +11,9 @@ DBusConnection *_g_vfs_unix_get_connection_sync (const char *mountpoint,
GError **error);
gboolean _g_dbus_message_iter_append_filename (DBusMessageIter *iter,
const char *filename);
-gboolean _g_error_from_dbus_message (DBusMessage *message,
+gboolean _g_error_from_dbus_message (DBusMessage *message,
+ GError **error);
+void _g_error_from_dbus (DBusError *derror,
GError **error);
G_END_DECLS