summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@src.gnome.org>2007-09-13 09:50:55 +0000
committerAlexander Larsson <alexl@src.gnome.org>2007-09-13 09:50:55 +0000
commitd6f1e3a1a699a8cc16062c2e5c2302c5024af4c1 (patch)
tree3824638b3c1d409e583e8507fd6bb7a8cee75433
parentfd8347bc624177853d1a3e85be93a09d6dc788da (diff)
downloadgvfs-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--TODO9
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gvfsbackend.c15
-rw-r--r--daemon/gvfsbackend.h23
-rw-r--r--daemon/gvfsbackendtest.c66
-rw-r--r--daemon/gvfsdaemon.c1
-rw-r--r--daemon/gvfsjob.h2
-rw-r--r--daemon/gvfsjobopenforread.c10
-rw-r--r--daemon/gvfsjobopenforread.h3
-rw-r--r--daemon/gvfsjobseekread.c99
-rw-r--r--daemon/gvfsjobseekread.h49
-rw-r--r--daemon/gvfsreadstream.c87
-rw-r--r--daemon/gvfsreadstream.h25
-rw-r--r--gvfs/ginputstream.c5
-rw-r--r--gvfs/gunixfileinputstream.c33
-rw-r--r--gvfs/test.c43
16 files changed, 423 insertions, 48 deletions
diff --git a/TODO b/TODO
index 1800d6a3..e05d6cdb 100644
--- a/TODO
+++ b/TODO
@@ -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) {