diff options
author | Alexander Larsson <alexl@src.gnome.org> | 2007-09-13 09:50:55 +0000 |
---|---|---|
committer | Alexander Larsson <alexl@src.gnome.org> | 2007-09-13 09:50:55 +0000 |
commit | d6f1e3a1a699a8cc16062c2e5c2302c5024af4c1 (patch) | |
tree | 3824638b3c1d409e583e8507fd6bb7a8cee75433 | |
parent | fd8347bc624177853d1a3e85be93a09d6dc788da (diff) | |
download | gvfs-d6f1e3a1a699a8cc16062c2e5c2302c5024af4c1.tar.gz |
Implement seek
Original git commit by Alexander Larsson <alex@localhost.localdomain> at 1163674878 +0100
svn path=/trunk/; revision=156
-rw-r--r-- | TODO | 9 | ||||
-rw-r--r-- | daemon/Makefile.am | 1 | ||||
-rw-r--r-- | daemon/gvfsbackend.c | 15 | ||||
-rw-r--r-- | daemon/gvfsbackend.h | 23 | ||||
-rw-r--r-- | daemon/gvfsbackendtest.c | 66 | ||||
-rw-r--r-- | daemon/gvfsdaemon.c | 1 | ||||
-rw-r--r-- | daemon/gvfsjob.h | 2 | ||||
-rw-r--r-- | daemon/gvfsjobopenforread.c | 10 | ||||
-rw-r--r-- | daemon/gvfsjobopenforread.h | 3 | ||||
-rw-r--r-- | daemon/gvfsjobseekread.c | 99 | ||||
-rw-r--r-- | daemon/gvfsjobseekread.h | 49 | ||||
-rw-r--r-- | daemon/gvfsreadstream.c | 87 | ||||
-rw-r--r-- | daemon/gvfsreadstream.h | 25 | ||||
-rw-r--r-- | gvfs/ginputstream.c | 5 | ||||
-rw-r--r-- | gvfs/gunixfileinputstream.c | 33 | ||||
-rw-r--r-- | gvfs/test.c | 43 |
16 files changed, 423 insertions, 48 deletions
@@ -23,12 +23,9 @@ local file access through the daemon for remote X clients? Sometimes we handle the dbus socket before the extra_fd one, need synchronization -Do we really need g_output_stream_write, or will everyone want g_output_stream_write_all()? -For read its useful, to get whatever is availible for now (say for console input), but output? -Isn't it mainly useful to implement async writes, which we have a real API for? - figure out the right semantics for error or cancel of close() -------------- +Expose the seek operations on GInputStream also, not only via iface + +Better, shorter class names... -continue on GVfsJobOpenForRead, especially the return part diff --git a/daemon/Makefile.am b/daemon/Makefile.am index d71e7536..82670136 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -24,6 +24,7 @@ gvfs_daemon_SOURCES = \ gvfsjob.c gvfsjob.h \ gvfsjobopenforread.c gvfsjobopenforread.h \ gvfsjobread.c gvfsjobread.h \ + gvfsjobseekread.c gvfsjobseekread.h \ dbus-gmain.h dbus-gmain.c \ main.c diff --git a/daemon/gvfsbackend.c b/daemon/gvfsbackend.c index 9ec125c4..df64c2b9 100644 --- a/daemon/gvfsbackend.c +++ b/daemon/gvfsbackend.c @@ -62,3 +62,18 @@ g_vfs_backend_read (GVfsBackend *backend, return class->read (backend, job, handle, buffer, bytes_requested); } + +gboolean +g_vfs_backend_seek_on_read (GVfsBackend *backend, + GVfsJobSeekRead *job, + GVfsHandle *handle, + goffset offset, + GSeekType type) +{ + GVfsBackendClass *class; + + class = G_VFS_BACKEND_GET_CLASS (backend); + + return class->seek_on_read (backend, job, handle, + offset, type); +} diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h index 5bc23957..9f6ac618 100644 --- a/daemon/gvfsbackend.h +++ b/daemon/gvfsbackend.h @@ -47,7 +47,7 @@ struct _GVfsBackendClass char *buffer, gsize bytes_requested); gboolean (*seek_on_read) (GVfsBackend *backend, - GVfsJobReadSeek *job, + GVfsJobSeekRead *job, GVfsHandle *handle, goffset offset, GSeekType type); @@ -55,14 +55,19 @@ struct _GVfsBackendClass GType g_vfs_backend_get_type (void) G_GNUC_CONST; -gboolean g_vfs_backend_open_for_read (GVfsBackend *backend, - GVfsJobOpenForRead *job, - char *filename); -gboolean g_vfs_backend_read (GVfsBackend *backend, - GVfsJobRead *job, - GVfsHandle *handle, - char *buffer, - gsize bytes_requested); +gboolean g_vfs_backend_open_for_read (GVfsBackend *backend, + GVfsJobOpenForRead *job, + char *filename); +gboolean g_vfs_backend_read (GVfsBackend *backend, + GVfsJobRead *job, + GVfsHandle *handle, + char *buffer, + gsize bytes_requested); +gboolean g_vfs_backend_seek_on_read (GVfsBackend *backend, + GVfsJobSeekRead *job, + GVfsHandle *handle, + goffset offset, + GSeekType type); G_END_DECLS diff --git a/daemon/gvfsbackendtest.c b/daemon/gvfsbackendtest.c index bba791ff..89e15fd7 100644 --- a/daemon/gvfsbackendtest.c +++ b/daemon/gvfsbackendtest.c @@ -12,17 +12,23 @@ #include "gvfsbackendtest.h" #include "gvfsjobopenforread.h" #include "gvfsjobread.h" +#include "gvfsjobseekread.h" G_DEFINE_TYPE (GVfsBackendTest, g_vfs_backend_test, G_TYPE_VFS_BACKEND); -static gboolean do_open_for_read (GVfsBackend *backend, +static gboolean do_open_for_read (GVfsBackend *backend, GVfsJobOpenForRead *job, char *filename); -static gboolean do_read (GVfsBackend *backend, +static gboolean do_read (GVfsBackend *backend, GVfsJobRead *job, GVfsHandle *handle, char *buffer, gsize bytes_requested); +static gboolean do_seek_on_read (GVfsBackend *backend, + GVfsJobSeekRead *job, + GVfsHandle *handle, + goffset offset, + GSeekType type); static void g_vfs_backend_test_finalize (GObject *object) @@ -45,6 +51,7 @@ g_vfs_backend_test_class_init (GVfsBackendTestClass *klass) backend_class->open_for_read = do_open_for_read; backend_class->read = do_read; + backend_class->seek_on_read = do_seek_on_read; } static void @@ -66,7 +73,7 @@ open_idle_cb (gpointer data) { GVfsJobOpenForRead *job = data; int fd; - + fd = g_open (job->filename, O_RDONLY); if (fd == -1) { @@ -77,6 +84,7 @@ open_idle_cb (gpointer data) } else { + g_vfs_job_open_for_read_set_can_seek (job, TRUE); g_vfs_job_open_for_read_set_handle (job, GINT_TO_POINTER (fd)); g_vfs_job_succeeded (G_VFS_JOB (job)); } @@ -90,6 +98,8 @@ do_open_for_read (GVfsBackend *backend, { GError *error; + g_print ("open_for_read (%s)\n", filename); + if (strcmp (filename, "/fail") == 0) { error = g_error_new (G_FILE_ERROR, G_FILE_ERROR_IO, "Test error"); @@ -113,6 +123,8 @@ do_read (GVfsBackend *backend, int fd; ssize_t res; + g_print ("read (%d)\n", bytes_requested); + fd = GPOINTER_TO_INT (handle); res = read (fd, buffer, bytes_requested); @@ -132,3 +144,51 @@ do_read (GVfsBackend *backend, return TRUE; } + +static gboolean +do_seek_on_read (GVfsBackend *backend, + GVfsJobSeekRead *job, + GVfsHandle *handle, + goffset offset, + GSeekType type) +{ + int whence; + int fd; + off_t final_offset; + + g_print ("seek_on_read (%d, %d)\n", (int)offset, type); + + switch (type) + { + default: + case G_SEEK_SET: + whence = SEEK_SET; + break; + case G_SEEK_CUR: + whence = SEEK_CUR; + break; + case G_SEEK_END: + whence = SEEK_END; + break; + } + + + fd = GPOINTER_TO_INT (handle); + + final_offset = lseek (fd, offset, whence); + + if (final_offset == (off_t)-1) + { + g_vfs_job_failed (G_VFS_JOB (job), G_FILE_ERROR, + g_file_error_from_errno (errno), + "Error seeking in file: %s", + g_strerror (errno)); + } + else + { + g_vfs_job_seek_read_set_offset (job, offset); + g_vfs_job_succeeded (G_VFS_JOB (job)); + } + + return TRUE; +} diff --git a/daemon/gvfsdaemon.c b/daemon/gvfsdaemon.c index d3622767..c2c6c582 100644 --- a/daemon/gvfsdaemon.c +++ b/daemon/gvfsdaemon.c @@ -255,6 +255,7 @@ handle_new_job_callback (GVfsReadStream *stream, GVfsDaemon *daemon) { g_print ("handle_new_job_callback() job=%p daemon=%p\n", job, daemon); + g_object_ref (job); start_or_queue_job (daemon, job); } diff --git a/daemon/gvfsjob.h b/daemon/gvfsjob.h index 3b290bef..eed17c4b 100644 --- a/daemon/gvfsjob.h +++ b/daemon/gvfsjob.h @@ -19,7 +19,7 @@ typedef struct _GVfsJobClass GVfsJobClass; /* Define these here to avoid circular includes */ typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead; typedef struct _GVfsJobRead GVfsJobRead; -typedef struct _GVfsJobReadSeek GVfsJobReadSeek; +typedef struct _GVfsJobSeekRead GVfsJobSeekRead; struct _GVfsJob { diff --git a/daemon/gvfsjobopenforread.c b/daemon/gvfsjobopenforread.c index 45be66b9..04a9e5a9 100644 --- a/daemon/gvfsjobopenforread.c +++ b/daemon/gvfsjobopenforread.c @@ -106,6 +106,13 @@ g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job, job->backend_handle = handle; } +void +g_vfs_job_open_for_read_set_can_seek (GVfsJobOpenForRead *job, + gboolean can_seek) +{ + job->can_seek = can_seek; +} + /* Might be called on an i/o thread */ static DBusMessage * create_reply (GVfsJob *job, @@ -119,6 +126,7 @@ create_reply (GVfsJob *job, int remote_fd; int fd_id; gboolean res; + dbus_bool_t can_seek; g_assert (open_job->backend_handle != NULL); @@ -145,8 +153,10 @@ create_reply (GVfsJob *job, close (remote_fd); reply = dbus_message_new_method_return (message); + can_seek = open_job->can_seek; res = dbus_message_append_args (reply, DBUS_TYPE_UINT32, &fd_id, + DBUS_TYPE_BOOLEAN, &can_seek, DBUS_TYPE_INVALID); g_vfs_read_stream_set_user_data (stream, open_job->backend_handle); diff --git a/daemon/gvfsjobopenforread.h b/daemon/gvfsjobopenforread.h index 719ed5bf..2b26a33b 100644 --- a/daemon/gvfsjobopenforread.h +++ b/daemon/gvfsjobopenforread.h @@ -27,6 +27,7 @@ struct _GVfsJobOpenForRead DBusMessage *message; char *filename; GVfsHandle *backend_handle; + gboolean can_seek; GVfsReadStream *read_stream; }; @@ -41,6 +42,8 @@ GVfsJob * g_vfs_job_open_for_read_new (DBusConnection *connec DBusMessage *message); void g_vfs_job_open_for_read_set_handle (GVfsJobOpenForRead *job, GVfsHandle *handle); +void g_vfs_job_open_for_read_set_can_seek (GVfsJobOpenForRead *job, + gboolean can_seek); GVfsReadStream *g_vfs_job_open_for_read_steal_stream (GVfsJobOpenForRead *job); G_END_DECLS diff --git a/daemon/gvfsjobseekread.c b/daemon/gvfsjobseekread.c new file mode 100644 index 00000000..572d1460 --- /dev/null +++ b/daemon/gvfsjobseekread.c @@ -0,0 +1,99 @@ +#include <config.h> + +#include <unistd.h> +#include <sys/types.h> +#include <sys/socket.h> +#include <sys/un.h> + +#include <glib.h> +#include <glib/gi18n.h> +#include "gvfsreadstream.h" +#include "gvfsjobseekread.h" +#include "gvfsdaemonutils.h" + +G_DEFINE_TYPE (GVfsJobSeekRead, g_vfs_job_seek_read, G_TYPE_VFS_JOB); + +static gboolean start (GVfsJob *job); +static void send_reply (GVfsJob *job); + +static void +g_vfs_job_seek_read_finalize (GObject *object) +{ + GVfsJobSeekRead *job; + + job = G_VFS_JOB_SEEK_READ (object); + + if (G_OBJECT_CLASS (g_vfs_job_seek_read_parent_class)->finalize) + (*G_OBJECT_CLASS (g_vfs_job_seek_read_parent_class)->finalize) (object); +} + +static void +g_vfs_job_seek_read_class_init (GVfsJobSeekReadClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass); + + gobject_class->finalize = g_vfs_job_seek_read_finalize; + + job_class->start = start; + job_class->send_reply = send_reply; +} + +static void +g_vfs_job_seek_read_init (GVfsJobSeekRead *job) +{ +} + +GVfsJob * +g_vfs_job_seek_read_new (GVfsReadStream *stream, + gpointer handle, + GSeekType seek_type, + goffset offset) +{ + GVfsJobSeekRead *job; + + job = g_object_new (G_TYPE_VFS_JOB_SEEK_READ, NULL); + + job->stream = stream; /* TODO: ref? */ + job->handle = handle; + job->requested_offset = offset; + job->seek_type = seek_type; + + return G_VFS_JOB (job); +} + +/* Might be called on an i/o thread */ +static void +send_reply (GVfsJob *job) +{ + GVfsJobSeekRead *op_job = G_VFS_JOB_SEEK_READ (job); + + g_print ("job_seek_read send reply, pos %d\n", (int)op_job->final_offset); + + if (job->failed) + g_vfs_read_stream_send_error (op_job->stream, job->error); + else + { + g_vfs_read_stream_send_seek_offset (op_job->stream, + op_job->final_offset); + } +} + +static gboolean +start (GVfsJob *job) +{ + GVfsJobSeekRead *op_job = G_VFS_JOB_SEEK_READ (job); + + return g_vfs_backend_seek_on_read (job->backend, + op_job, + op_job->handle, + op_job->requested_offset, + op_job->seek_type); +} + +void +g_vfs_job_seek_read_set_offset (GVfsJobSeekRead *job, + goffset offset) +{ + job->final_offset = offset; +} diff --git a/daemon/gvfsjobseekread.h b/daemon/gvfsjobseekread.h new file mode 100644 index 00000000..a18ef494 --- /dev/null +++ b/daemon/gvfsjobseekread.h @@ -0,0 +1,49 @@ +#ifndef __G_VFS_JOB_SEEK_READ_H__ +#define __G_VFS_JOB_SEEK_READ_H__ + +#include <gvfsjob.h> +#include <gvfsbackend.h> +#include <gvfsreadstream.h> + +G_BEGIN_DECLS + +#define G_TYPE_VFS_JOB_SEEK_READ (g_vfs_job_seek_read_get_type ()) +#define G_VFS_JOB_SEEK_READ(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_TYPE_VFS_JOB_SEEK_READ, GVfsJobSeekRead)) +#define G_VFS_JOB_SEEK_READ_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_TYPE_VFS_JOB_SEEK_READ, GVfsJobSeekReadClass)) +#define G_IS_VFS_JOB_SEEK_READ(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_TYPE_VFS_JOB_SEEK_READ)) +#define G_IS_VFS_JOB_SEEK_READ_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_TYPE_VFS_JOB_SEEK_READ)) +#define G_VFS_JOB_SEEK_READ_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_TYPE_VFS_JOB_SEEK_READ, GVfsJobSeekReadClass)) + +/* GVfsJobSeekRead declared in gvfsjob.h */ +typedef struct _GVfsJobSeekReadClass GVfsJobSeekReadClass; + +struct _GVfsJobSeekRead +{ + GVfsJob parent_instance; + + GVfsReadStream *stream; + gpointer handle; + GSeekType seek_type; + goffset requested_offset; + goffset final_offset; +}; + +struct _GVfsJobSeekReadClass +{ + GVfsJobClass parent_class; +}; + +GType g_vfs_job_seek_read_get_type (void) G_GNUC_CONST; + +GVfsJob *g_vfs_job_seek_read_new (GVfsReadStream *stream, + gpointer handle, + GSeekType seek_type, + goffset offset); + +void g_vfs_job_seek_read_set_offset (GVfsJobSeekRead *job, + goffset offset); + + +G_END_DECLS + +#endif /* __G_VFS_JOB_SEEK_READ_H__ */ diff --git a/daemon/gvfsreadstream.c b/daemon/gvfsreadstream.c index d9968b19..15757a65 100644 --- a/daemon/gvfsreadstream.c +++ b/daemon/gvfsreadstream.c @@ -18,6 +18,7 @@ #include <gvfsdaemonprotocol.h> #include <gvfsdaemonutils.h> #include <gvfsjobread.h> +#include <gvfsjobseekread.h> G_DEFINE_TYPE (GVfsReadStream, g_vfs_read_stream, G_TYPE_OBJECT); @@ -37,9 +38,11 @@ struct _GVfsReadStreamPrivate GInputStream *command_stream; GOutputStream *reply_stream; int remote_fd; + int seek_generation; gpointer data; /* user data, i.e. GVfsHandle */ - guint32 seq_nr; + GVfsJob *current_job; + guint32 current_job_seq_nr; char command_buffer[G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SIZE]; int command_buffer_size; @@ -61,6 +64,10 @@ g_vfs_read_stream_finalize (GObject *object) GVfsReadStream *read_stream; read_stream = G_VFS_READ_STREAM (object); + + if (read_stream->priv->current_job) + g_object_unref (read_stream->priv->current_job); + read_stream->priv->current_job = NULL; if (read_stream->priv->reply_stream) g_object_unref (read_stream->priv->reply_stream); @@ -147,7 +154,8 @@ send_reply_cb (GOutputStream *output_stream, stream->priv->output_data_pos += bytes_written; /* Write more of output_data if needed */ - if (stream->priv->output_data_pos < stream->priv->output_data_size) + if (stream->priv->output_data != NULL && + stream->priv->output_data_pos < stream->priv->output_data_size) { g_output_stream_write_async (stream->priv->reply_stream, stream->priv->output_data + stream->priv->output_data_pos, @@ -161,13 +169,15 @@ send_reply_cb (GOutputStream *output_stream, /* Sent full reply */ g_free (stream->priv->output_data); stream->priv->output_data = NULL; - + + g_vfs_job_emit_finished (stream->priv->current_job); + g_object_unref (stream->priv->current_job); + stream->priv->current_job = NULL; g_print ("Sent reply\n"); - - request_command (stream); } -/* Takes ownership of data */ +/* Might be called on an i/o thread + * Takes ownership of data */ static void send_reply (GVfsReadStream *stream, gboolean use_header, @@ -213,14 +223,27 @@ got_command (GVfsReadStream *stream, { GVfsJob *job; GError *error; + GSeekType seek_type; g_print ("got_command %d %d %d %d\n", command, seq_nr, arg1, arg2); + + if (stream->priv->current_job != NULL) + { + if (command != G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_CANCEL) + { + g_warning ("Ignored non-cancel request with outstanding request"); + return; + } + + if (arg1 == stream->priv->current_job_seq_nr) + g_vfs_job_cancel (stream->priv->current_job); + return; + } job = NULL; switch (command) { case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_READ: - stream->priv->seq_nr = seq_nr; job = g_vfs_job_read_new (stream, stream->priv->data, arg1); @@ -228,9 +251,24 @@ got_command (GVfsReadStream *stream, case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SEEK_CUR: case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SEEK_END: case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SEEK_SET: + seek_type = G_SEEK_SET; + if (command == G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SEEK_END) + seek_type = G_SEEK_END; + else if (command == G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_SEEK_CUR) + seek_type = G_SEEK_CUR; + + stream->priv->seek_generation++; + job = g_vfs_job_seek_read_new (stream, + stream->priv->data, + seek_type, + ((goffset)arg1) | (((goffset)arg2) << 32)); + break; + case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_CANCEL: + /* Ignore cancel with no outstanding job */ + break; + default: - /* TODO */ error = NULL; g_set_error (&error, G_VFS_ERROR, G_VFS_ERROR_INTERNAL_ERROR, @@ -241,7 +279,11 @@ got_command (GVfsReadStream *stream, } if (job) - g_signal_emit (stream, signals[NEW_JOB], 0, job); + { + stream->priv->current_job = job; + stream->priv->current_job_seq_nr = seq_nr; + g_signal_emit (stream, signals[NEW_JOB], 0, job); + } } static void @@ -286,6 +328,9 @@ command_read_cb (GInputStream *input_stream, seq_nr = g_ntohl (cmd->seq_nr); stream->priv->command_buffer_size = 0; got_command (stream, command, seq_nr, arg1, arg2); + + /* Request more commands, so can get cancel requests */ + request_command (stream); } static void @@ -310,10 +355,28 @@ g_vfs_read_stream_send_error (GVfsReadStream *read_stream, char *data; gsize data_len; - data = g_error_to_daemon_reply (error, read_stream->priv->seq_nr, &data_len); + data = g_error_to_daemon_reply (error, read_stream->priv->current_job_seq_nr, &data_len); send_reply (read_stream, FALSE, data, data_len); } + +/* Might be called on an i/o thread + */ +void +g_vfs_read_stream_send_seek_offset (GVfsReadStream *read_stream, + goffset offset) +{ + GVfsDaemonSocketProtocolReply *reply; + + reply = (GVfsDaemonSocketProtocolReply *)read_stream->priv->reply_buffer; + reply->type = g_htonl (G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SEEK_POS); + reply->seq_nr = g_htonl (read_stream->priv->current_job_seq_nr); + reply->arg1 = g_htonl (offset & 0xffffffff); + reply->arg2 = g_htonl (offset >> 32); + + send_reply (read_stream, TRUE, NULL, 0); +} + /* Might be called on an i/o thread */ void @@ -325,9 +388,9 @@ g_vfs_read_stream_send_data (GVfsReadStream *read_stream, reply = (GVfsDaemonSocketProtocolReply *)read_stream->priv->reply_buffer; reply->type = g_htonl (G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_DATA); - reply->seq_nr = g_htonl (read_stream->priv->seq_nr); + reply->seq_nr = g_htonl (read_stream->priv->current_job_seq_nr); reply->arg1 = g_htonl (count); - reply->arg2 = g_htonl (0); /* TODO: seek generation */ + reply->arg2 = g_htonl (read_stream->priv->seek_generation); send_reply (read_stream, TRUE, buffer, count); } diff --git a/daemon/gvfsreadstream.h b/daemon/gvfsreadstream.h index 66c81d15..2c733725 100644 --- a/daemon/gvfsreadstream.h +++ b/daemon/gvfsreadstream.h @@ -3,6 +3,7 @@ #include <glib-object.h> #include <gvfsjob.h> +#include <gvfs/gvfstypes.h> G_BEGIN_DECLS @@ -36,17 +37,19 @@ struct _GVfsReadStreamClass GType g_vfs_read_stream_get_type (void) G_GNUC_CONST; -GVfsReadStream *g_vfs_read_stream_new (GError **error); -int g_vfs_read_stream_steal_remote_fd (GVfsReadStream *read_stream); -void g_vfs_read_stream_set_user_data (GVfsReadStream *read_stream, - gpointer data); -gboolean g_vfs_read_stream_has_job (GVfsReadStream *read_stream); -GVfsJob * g_vfs_read_stream_get_job (GVfsReadStream *read_stream); -void g_vfs_read_stream_send_data (GVfsReadStream *read_stream, - char *buffer, - gsize count); -void g_vfs_read_stream_send_error (GVfsReadStream *read_stream, - GError *error); +GVfsReadStream *g_vfs_read_stream_new (GError **error); +int g_vfs_read_stream_steal_remote_fd (GVfsReadStream *read_stream); +void g_vfs_read_stream_set_user_data (GVfsReadStream *read_stream, + gpointer data); +gboolean g_vfs_read_stream_has_job (GVfsReadStream *read_stream); +GVfsJob * g_vfs_read_stream_get_job (GVfsReadStream *read_stream); +void g_vfs_read_stream_send_data (GVfsReadStream *read_stream, + char *buffer, + gsize count); +void g_vfs_read_stream_send_error (GVfsReadStream *read_stream, + GError *error); +void g_vfs_read_stream_send_seek_offset (GVfsReadStream *read_stream, + goffset offset); /* TODO: i/o priority? */ diff --git a/gvfs/ginputstream.c b/gvfs/ginputstream.c index 091604c4..e62a0b1d 100644 --- a/gvfs/ginputstream.c +++ b/gvfs/ginputstream.c @@ -314,11 +314,14 @@ g_input_stream_real_skip (GInputStream *stream, GCancellable *cancellable, GError **error) { + GInputStreamClass *class; gssize ret; char *buffer; + class = G_INPUT_STREAM_GET_CLASS (stream); + buffer = g_malloc (count); - ret = g_input_stream_read (stream, buffer, count, cancellable, error); + ret = class->read (stream, buffer, count, cancellable, error); g_free (buffer); return ret; diff --git a/gvfs/gunixfileinputstream.c b/gvfs/gunixfileinputstream.c index d2302896..89895f3c 100644 --- a/gvfs/gunixfileinputstream.c +++ b/gvfs/gunixfileinputstream.c @@ -83,6 +83,7 @@ typedef struct { goffset ret_offset; gboolean sent_cancel; + gboolean sent_seek; guint32 seq_nr; } SeekOperation; @@ -296,10 +297,19 @@ g_unix_file_input_stream_open (GUnixFileInputStream *file, return FALSE; } - dbus_message_get_args (message, NULL, - DBUS_TYPE_UINT32, &fd_id, - DBUS_TYPE_BOOLEAN, &can_seek, - DBUS_TYPE_INVALID); + 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_FILE_ERROR, G_FILE_ERROR_IO, + _("Error in stream protocol: %s"), _("Invalid return value from open")); + return FALSE; + } + + dbus_message_unref (reply); + /* TODO: verify fd id */ file->priv->fd = receive_fd (extra_fd); file->priv->can_seek = can_seek; @@ -440,8 +450,9 @@ run_sync_state_machine (GUnixFileInputStream *file, } else { + g_print ("io_error: %s\n", io_error->message); g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_IO, - "Error in stream protocol: %s", io_error->message); + _("Error in stream protocol: %s"), io_error->message); g_error_free (io_error); return FALSE; } @@ -743,6 +754,9 @@ g_unix_file_input_stream_skip (GInputStream *stream, if (!g_unix_file_input_stream_open (file, error)) return -1; + /* TODO: .. */ + g_assert_not_reached (); + return 0; } @@ -815,6 +829,7 @@ iterate_seek_state_machine (GUnixFileInputStream *file, IOOperationData *io_op, op->offset >> 32, &op->seq_nr); op->state = SEEK_STATE_WROTE_REQUEST; + op->sent_seek = FALSE; io_op->io_buffer = priv->output_buffer->str; io_op->io_size = priv->output_buffer->len; io_op->io_allow_cancel = TRUE; /* Allow cancel before first byte of request sent */ @@ -831,6 +846,12 @@ iterate_seek_state_machine (GUnixFileInputStream *file, IOOperationData *io_op, _("Operation was cancelled")); return STATE_OP_DONE; } + + /* We weren't cancelled before first byte sent, so now we will send + * the seek request. Increase the seek generation now. */ + if (!op->sent_seek) + priv->seek_generation++; + op->sent_seek = TRUE; if (io_op->io_res < priv->output_buffer->len) { @@ -996,6 +1017,8 @@ g_unix_file_input_stream_seek (GFileInputStream *stream, file = G_UNIX_FILE_INPUT_STREAM (stream); + g_print ("g_unix_file_input_stream_seek\n"); + if (!g_unix_file_input_stream_open (file, error)) return -1; diff --git a/gvfs/test.c b/gvfs/test.c index 8ff62d01..3736c87f 100644 --- a/gvfs/test.c +++ b/gvfs/test.c @@ -3,6 +3,7 @@ #include <glib.h> #include "gfile.h" +#include "gseekable.h" #include "glocalfileinputstream.h" #include "glocalfileoutputstream.h" #include "gsocketinputstream.h" @@ -155,6 +156,45 @@ cancel_thread (gpointer data) return NULL; } +static void +test_seek (void) +{ + GInputStream *in; + char buffer1[1025]; + char buffer2[1025]; + gssize res; + gboolean close_res; + GFile *file; + GSeekable *seekable; + GError *error; + + file = g_file_get_for_uri ("foo:///etc/passwd"); + + error = NULL; + in = (GInputStream *)g_file_read (file); + seekable = G_SEEKABLE (in); + + g_print ("offset: %d\n", (int)g_seekable_tell (seekable)); + + res = g_input_stream_read (in, buffer1, 1024, NULL, NULL); + g_print ("read 1 res = %d\n", res); + + g_print ("offset: %d\n", (int)g_seekable_tell (seekable)); + + res = g_seekable_seek (seekable, 0, G_SEEK_SET, NULL, NULL); + g_print ("seek res = %d\n", res); + + res = g_input_stream_read (in, buffer2, 1024, NULL, &error); + g_print ("read 2 res = %d\n", res); + if (res == -1) + g_print ("error: %s\n", error->message); + + if (memcmp (buffer1, buffer2, 1024) != 0) + g_print ("Buffers differ\n"); + + close_res = g_input_stream_close (in, NULL, NULL); + g_print ("close res: %d\n", close_res); +} int main (int argc, char *argv[]) @@ -165,6 +205,9 @@ main (int argc, char *argv[]) g_type_init (); g_thread_init (NULL); + + test_seek (); + loop = g_main_loop_new (NULL, FALSE); if (1) { |