summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2009-02-27 15:50:51 +0000
committerAlexander Larsson <alexl@src.gnome.org>2009-02-27 15:50:51 +0000
commitafc01fa5e7f0d4626f578f9d92e17f9ba05003f0 (patch)
tree6af7428db5e0d6877c8d9c30946a162f53a76703
parent415187aeda32a168c2270f93b9ebb7b07a785ba7 (diff)
downloadgvfs-afc01fa5e7f0d4626f578f9d92e17f9ba05003f0.tar.gz
Support query info on output streams
2009-02-27 Alexander Larsson <alexl@redhat.com> * client/gdaemonfileoutputstream.c: Support query info on output streams * daemon/Makefile.am: * daemon/gvfsbackend.h: * daemon/gvfsjobqueryinfowrite.[ch]: * daemon/gvfswritechannel.c: Add query info write support. * daemon/gvfsbackendtest.c: Implement writing to files in test backend. Implement query info on write * test/test-query-info-stream.c: Test g_file_output_stream_query_info(). svn path=/trunk/; revision=2260
-rw-r--r--ChangeLog18
-rw-r--r--client/gdaemonfileoutputstream.c367
-rw-r--r--daemon/Makefile.am1
-rw-r--r--daemon/gvfsbackend.h67
-rw-r--r--daemon/gvfsbackendtest.c203
-rw-r--r--daemon/gvfsjobqueryinfowrite.c144
-rw-r--r--daemon/gvfsjobqueryinfowrite.h67
-rw-r--r--daemon/gvfswritechannel.c11
-rw-r--r--test/test-query-info-stream.c89
9 files changed, 862 insertions, 105 deletions
diff --git a/ChangeLog b/ChangeLog
index 501e0c72..aceaa3e1 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,6 +1,24 @@
2009-02-27 Alexander Larsson <alexl@redhat.com>
* client/gdaemonfileoutputstream.c:
+ Support query info on output streams
+
+ * daemon/Makefile.am:
+ * daemon/gvfsbackend.h:
+ * daemon/gvfsjobqueryinfowrite.[ch]:
+ * daemon/gvfswritechannel.c:
+ Add query info write support.
+
+ * daemon/gvfsbackendtest.c:
+ Implement writing to files in test backend.
+ Implement query info on write
+
+ * test/test-query-info-stream.c:
+ Test g_file_output_stream_query_info().
+
+2009-02-27 Alexander Larsson <alexl@redhat.com>
+
+ * client/gdaemonfileoutputstream.c:
Add and use g_string_remove_in_front helper function.
2009-02-27 Alexander Larsson <alexl@redhat.com>
diff --git a/client/gdaemonfileoutputstream.c b/client/gdaemonfileoutputstream.c
index 558acd56..fc89d0d3 100644
--- a/client/gdaemonfileoutputstream.c
+++ b/client/gdaemonfileoutputstream.c
@@ -40,6 +40,7 @@
#include "gdaemonfileoutputstream.h"
#include "gvfsdaemondbus.h"
#include <gvfsdaemonprotocol.h>
+#include <gvfsfileinfo.h>
#define MAX_WRITE_SIZE (4*1024*1024)
@@ -116,6 +117,26 @@ typedef struct {
guint32 seq_nr;
} CloseOperation;
+typedef enum {
+ QUERY_STATE_INIT = 0,
+ QUERY_STATE_WROTE_REQUEST,
+ QUERY_STATE_HANDLE_INPUT,
+} QueryState;
+
+typedef struct {
+ QueryState state;
+
+ /* Input */
+ char *attributes;
+
+ /* Output */
+ GFileInfo *info;
+ GError *ret_error;
+
+ gboolean sent_cancel;
+
+ guint32 seq_nr;
+} QueryOperation;
typedef struct {
gboolean cancelled;
@@ -150,44 +171,55 @@ struct _GDaemonFileOutputStream {
};
-static gssize g_daemon_file_output_stream_write (GOutputStream *stream,
- const void *buffer,
- gsize count,
- GCancellable *cancellable,
- GError **error);
-static gboolean g_daemon_file_output_stream_close (GOutputStream *stream,
- GCancellable *cancellable,
- GError **error);
-static GFileInfo *g_daemon_file_output_stream_query_info (GFileOutputStream *stream,
- char *attributes,
- GCancellable *cancellable,
- GError **error);
-static char *g_daemon_file_output_stream_get_etag (GFileOutputStream *stream);
-static goffset g_daemon_file_output_stream_tell (GFileOutputStream *stream);
-static gboolean g_daemon_file_output_stream_can_seek (GFileOutputStream *stream);
-static gboolean g_daemon_file_output_stream_seek (GFileOutputStream *stream,
- goffset offset,
- GSeekType type,
- GCancellable *cancellable,
- GError **error);
-static void g_daemon_file_output_stream_write_async (GOutputStream *stream,
- const void *buffer,
- gsize count,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer data);
-static gssize g_daemon_file_output_stream_write_finish (GOutputStream *stream,
- GAsyncResult *result,
- GError **error);
-static void g_daemon_file_output_stream_close_async (GOutputStream *stream,
- int io_priority,
- GCancellable *cancellable,
- GAsyncReadyCallback callback,
- gpointer data);
-static gboolean g_daemon_file_output_stream_close_finish (GOutputStream *stream,
- GAsyncResult *result,
- GError **error);
+static gssize g_daemon_file_output_stream_write (GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ GCancellable *cancellable,
+ GError **error);
+static gboolean g_daemon_file_output_stream_close (GOutputStream *stream,
+ GCancellable *cancellable,
+ GError **error);
+static GFileInfo *g_daemon_file_output_stream_query_info (GFileOutputStream *stream,
+ char *attributes,
+ GCancellable *cancellable,
+ GError **error);
+static char *g_daemon_file_output_stream_get_etag (GFileOutputStream *stream);
+static goffset g_daemon_file_output_stream_tell (GFileOutputStream *stream);
+static gboolean g_daemon_file_output_stream_can_seek (GFileOutputStream *stream);
+static gboolean g_daemon_file_output_stream_seek (GFileOutputStream *stream,
+ goffset offset,
+ GSeekType type,
+ GCancellable *cancellable,
+ GError **error);
+static void g_daemon_file_output_stream_write_async (GOutputStream *stream,
+ const void *buffer,
+ gsize count,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data);
+static gssize g_daemon_file_output_stream_write_finish (GOutputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+static void g_daemon_file_output_stream_close_async (GOutputStream *stream,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer data);
+static gboolean g_daemon_file_output_stream_close_finish (GOutputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+static void g_daemon_file_output_stream_query_info_async (GFileOutputStream *stream,
+ char *attributes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data);
+static GFileInfo *g_daemon_file_output_stream_query_info_finish (GFileOutputStream *stream,
+ GAsyncResult *result,
+ GError **error);
+
+
G_DEFINE_TYPE (GDaemonFileOutputStream, g_daemon_file_output_stream,
G_TYPE_FILE_OUTPUT_STREAM)
@@ -246,6 +278,8 @@ g_daemon_file_output_stream_class_init (GDaemonFileOutputStreamClass *klass)
file_stream_class->seek = g_daemon_file_output_stream_seek;
file_stream_class->query_info = g_daemon_file_output_stream_query_info;
file_stream_class->get_etag = g_daemon_file_output_stream_get_etag;
+ file_stream_class->query_info_async = g_daemon_file_output_stream_query_info_async;
+ file_stream_class->query_info_finish = g_daemon_file_output_stream_query_info_finish;
}
static void
@@ -317,9 +351,10 @@ get_reply_header_missing_bytes (GString *buffer)
type = g_ntohl (reply->type);
arg2 = g_ntohl (reply->arg2);
- /* ERROR and CLOSED has extra data w/ len in arg2 */
+ /* ERROR, CLOSED and INFO has extra data w/ len in arg2 */
if (type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_ERROR ||
- type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_CLOSED)
+ type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_CLOSED ||
+ type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_INFO)
return G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_SIZE + arg2 - buffer->len;
return 0;
}
@@ -885,7 +920,7 @@ iterate_seek_state_machine (GDaemonFileOutputStream *file, IOOperationData *io_o
}
/* Got full header */
-
+
{
GVfsDaemonSocketProtocolReply reply;
char *data;
@@ -975,24 +1010,165 @@ g_daemon_file_output_stream_get_etag (GFileOutputStream *stream)
return g_strdup (file->etag);
}
+static StateOp
+iterate_query_state_machine (GDaemonFileOutputStream *file,
+ IOOperationData *io_op,
+ QueryOperation *op)
+{
+ gsize len;
+ guint32 request;
+
+ while (TRUE)
+ {
+ switch (op->state)
+ {
+ /* Initial state for read op */
+ case QUERY_STATE_INIT:
+ request = G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_QUERY_INFO;
+ append_request (file, request,
+ 0,
+ 0,
+ strlen (op->attributes),
+ &op->seq_nr);
+ g_string_append (file->output_buffer,
+ op->attributes);
+
+ op->state = QUERY_STATE_WROTE_REQUEST;
+ io_op->io_buffer = file->output_buffer->str;
+ io_op->io_size = file->output_buffer->len;
+ io_op->io_allow_cancel = TRUE; /* Allow cancel before first byte of request sent */
+ return STATE_OP_WRITE;
+
+ /* wrote parts of output_buffer */
+ case QUERY_STATE_WROTE_REQUEST:
+ if (io_op->io_cancelled)
+ {
+ op->info = NULL;
+ g_set_error_literal (&op->ret_error,
+ G_IO_ERROR,
+ G_IO_ERROR_CANCELLED,
+ _("Operation was cancelled"));
+ return STATE_OP_DONE;
+ }
+
+ if (io_op->io_res < file->output_buffer->len)
+ {
+ g_string_remove_in_front (file->output_buffer,
+ io_op->io_res);
+ io_op->io_buffer = file->output_buffer->str;
+ io_op->io_size = file->output_buffer->len;
+ io_op->io_allow_cancel = FALSE;
+ return STATE_OP_WRITE;
+ }
+ g_string_truncate (file->output_buffer, 0);
+
+ op->state = QUERY_STATE_HANDLE_INPUT;
+ break;
+
+ /* No op */
+ case QUERY_STATE_HANDLE_INPUT:
+ if (io_op->cancelled && !op->sent_cancel)
+ {
+ op->sent_cancel = TRUE;
+ append_request (file, G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_CANCEL,
+ op->seq_nr, 0, 0, NULL);
+ op->state = QUERY_STATE_WROTE_REQUEST;
+ io_op->io_buffer = file->output_buffer->str;
+ io_op->io_size = file->output_buffer->len;
+ io_op->io_allow_cancel = FALSE;
+ return STATE_OP_WRITE;
+ }
+
+
+ if (io_op->io_res > 0)
+ {
+ gsize unread_size = io_op->io_size - io_op->io_res;
+ g_string_set_size (file->input_buffer,
+ file->input_buffer->len - unread_size);
+ }
+
+ len = get_reply_header_missing_bytes (file->input_buffer);
+ if (len > 0)
+ {
+ gsize current_len = file->input_buffer->len;
+ g_string_set_size (file->input_buffer,
+ current_len + len);
+ io_op->io_buffer = file->input_buffer->str + current_len;
+ io_op->io_size = len;
+ io_op->io_allow_cancel = !op->sent_cancel;
+ return STATE_OP_READ;
+ }
+
+ /* Got full header */
+
+ {
+ GVfsDaemonSocketProtocolReply reply;
+ char *data;
+ data = decode_reply (file->input_buffer, &reply);
+
+ if (reply.type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_ERROR &&
+ reply.seq_nr == op->seq_nr)
+ {
+ op->info = NULL;
+ decode_error (&reply, data, &op->ret_error);
+ g_string_truncate (file->input_buffer, 0);
+ return STATE_OP_DONE;
+ }
+ else if (reply.type == G_VFS_DAEMON_SOCKET_PROTOCOL_REPLY_INFO)
+ {
+ op->info = gvfs_file_info_demarshal (data, reply.arg2);
+ g_string_truncate (file->input_buffer, 0);
+ return STATE_OP_DONE;
+ }
+ /* Ignore other reply types */
+ }
+
+ g_string_truncate (file->input_buffer, 0);
+
+ /* This wasn't interesting, read next reply */
+ op->state = SEEK_STATE_HANDLE_INPUT;
+ break;
+
+ default:
+ g_assert_not_reached ();
+ }
+
+ /* Clear io_op between non-op state switches */
+ io_op->io_size = 0;
+ io_op->io_res = 0;
+ io_op->io_cancelled = FALSE;
+ }
+}
+
static GFileInfo *
g_daemon_file_output_stream_query_info (GFileOutputStream *stream,
char *attributes,
GCancellable *cancellable,
GError **error)
{
-#if 0
- GDaemonFileOutputStream *file;
+ GDaemonFileOutputStream *file;
+ QueryOperation op;
file = G_DAEMON_FILE_OUTPUT_STREAM (stream);
-#endif
+
+ if (g_cancellable_set_error_if_cancelled (cancellable, error))
+ return NULL;
- g_set_error (error,
- G_IO_ERROR,
- G_IO_ERROR_NOT_SUPPORTED,
- _("Query info not supported on stream"));
+ memset (&op, 0, sizeof (op));
+ op.state = QUERY_STATE_INIT;
+ if (attributes)
+ op.attributes = attributes;
+ else
+ op.attributes = "";
+
+ if (!run_sync_state_machine (file, (state_machine_iterator)iterate_query_state_machine,
+ &op, cancellable, error))
+ return NULL; /* IO Error */
- return NULL;
+ if (op.info == NULL)
+ g_propagate_error (error, op.ret_error);
+
+ return op.info;
}
/************************************************************************
@@ -1374,3 +1550,96 @@ g_daemon_file_output_stream_close_finish (GOutputStream *stream,
/* Failures handled in generic close_finish code */
return TRUE;
}
+
+static void
+async_query_done (GOutputStream *stream,
+ gpointer op_data,
+ GAsyncReadyCallback callback,
+ gpointer user_data,
+ GError *io_error)
+{
+ GDaemonFileOutputStream *file;
+ GSimpleAsyncResult *simple;
+ QueryOperation *op;
+ GFileInfo *info;
+ GError *error;
+
+ file = G_DAEMON_FILE_OUTPUT_STREAM (stream);
+
+ op = op_data;
+
+ if (io_error)
+ {
+ info = NULL;
+ error = io_error;
+ }
+ else
+ {
+ info = op->info;
+ error = op->ret_error;
+ }
+
+ simple = g_simple_async_result_new (G_OBJECT (stream),
+ callback, user_data,
+ g_daemon_file_output_stream_query_info_async);
+
+ if (info == NULL)
+ g_simple_async_result_set_from_error (simple, error);
+ else
+ g_simple_async_result_set_op_res_gpointer (simple, info,
+ g_object_unref);
+
+ /* Complete immediately, not in idle, since we're already in a mainloop callout */
+ g_simple_async_result_complete (simple);
+ g_object_unref (simple);
+
+ if (op->ret_error)
+ g_error_free (op->ret_error);
+ g_free (op->attributes);
+ g_free (op);
+}
+
+static void
+g_daemon_file_output_stream_query_info_async (GFileOutputStream *stream,
+ char *attributes,
+ int io_priority,
+ GCancellable *cancellable,
+ GAsyncReadyCallback callback,
+ gpointer user_data)
+{
+ GDaemonFileOutputStream *file;
+ QueryOperation *op;
+
+ file = G_DAEMON_FILE_OUTPUT_STREAM (stream);
+
+ op = g_new0 (QueryOperation, 1);
+ op->state = QUERY_STATE_INIT;
+ if (attributes)
+ op->attributes = g_strdup (attributes);
+ else
+ op->attributes = g_strdup ("");
+
+ run_async_state_machine (file,
+ (state_machine_iterator)iterate_query_state_machine,
+ op, io_priority,
+ callback, user_data,
+ cancellable,
+ async_query_done);
+}
+
+static GFileInfo *
+g_daemon_file_output_stream_query_info_finish (GFileOutputStream *stream,
+ GAsyncResult *result,
+ GError **error)
+{
+ GSimpleAsyncResult *simple;
+ GFileInfo *info;
+
+ simple = G_SIMPLE_ASYNC_RESULT (result);
+ g_assert (g_simple_async_result_get_source_tag (simple) == g_daemon_file_output_stream_query_info_async);
+
+ info = g_simple_async_result_get_op_res_gpointer (simple);
+
+ return g_object_ref (info);
+
+}
diff --git a/daemon/Makefile.am b/daemon/Makefile.am
index dc21955d..58a32a5c 100644
--- a/daemon/Makefile.am
+++ b/daemon/Makefile.am
@@ -135,6 +135,7 @@ libdaemon_la_SOURCES = \
gvfsjobclosewrite.c gvfsjobclosewrite.h \
gvfsjobqueryinfo.c gvfsjobqueryinfo.h \
gvfsjobqueryinforead.c gvfsjobqueryinforead.h \
+ gvfsjobqueryinfowrite.c gvfsjobqueryinfowrite.h \
gvfsjobqueryfsinfo.c gvfsjobqueryfsinfo.h \
gvfsjobenumerate.c gvfsjobenumerate.h \
gvfsjobsetdisplayname.c gvfsjobsetdisplayname.h \
diff --git a/daemon/gvfsbackend.h b/daemon/gvfsbackend.h
index e1393aaf..243d978c 100644
--- a/daemon/gvfsbackend.h
+++ b/daemon/gvfsbackend.h
@@ -43,35 +43,36 @@ typedef struct _GVfsBackend GVfsBackend;
typedef struct _GVfsBackendPrivate GVfsBackendPrivate;
typedef struct _GVfsBackendClass GVfsBackendClass;
-typedef struct _GVfsJobMount GVfsJobMount;
-typedef struct _GVfsJobUnmount GVfsJobUnmount;
-typedef struct _GVfsJobMountMountable GVfsJobMountMountable;
+typedef struct _GVfsJobMount GVfsJobMount;
+typedef struct _GVfsJobUnmount GVfsJobUnmount;
+typedef struct _GVfsJobMountMountable GVfsJobMountMountable;
typedef struct _GVfsJobUnmountMountable GVfsJobUnmountMountable;
-typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead;
-typedef struct _GVfsJobOpenIconForRead GVfsJobOpenIconForRead;
-typedef struct _GVfsJobSeekRead GVfsJobSeekRead;
-typedef struct _GVfsJobCloseRead GVfsJobCloseRead;
-typedef struct _GVfsJobRead GVfsJobRead;
-typedef struct _GVfsJobOpenForWrite GVfsJobOpenForWrite;
-typedef struct _GVfsJobWrite GVfsJobWrite;
-typedef struct _GVfsJobSeekWrite GVfsJobSeekWrite;
-typedef struct _GVfsJobCloseWrite GVfsJobCloseWrite;
-typedef struct _GVfsJobQueryInfo GVfsJobQueryInfo;
-typedef struct _GVfsJobQueryInfoRead GVfsJobQueryInfoRead;
-typedef struct _GVfsJobQueryFsInfo GVfsJobQueryFsInfo;
-typedef struct _GVfsJobEnumerate GVfsJobEnumerate;
-typedef struct _GVfsJobSetDisplayName GVfsJobSetDisplayName;
-typedef struct _GVfsJobTrash GVfsJobTrash;
-typedef struct _GVfsJobDelete GVfsJobDelete;
-typedef struct _GVfsJobMakeDirectory GVfsJobMakeDirectory;
-typedef struct _GVfsJobMakeSymlink GVfsJobMakeSymlink;
-typedef struct _GVfsJobCopy GVfsJobCopy;
-typedef struct _GVfsJobMove GVfsJobMove;
-typedef struct _GVfsJobPush GVfsJobPush;
-typedef struct _GVfsJobPull GVfsJobPull;
-typedef struct _GVfsJobSetAttribute GVfsJobSetAttribute;
-typedef struct _GVfsJobQueryAttributes GVfsJobQueryAttributes;
-typedef struct _GVfsJobCreateMonitor GVfsJobCreateMonitor;
+typedef struct _GVfsJobOpenForRead GVfsJobOpenForRead;
+typedef struct _GVfsJobOpenIconForRead GVfsJobOpenIconForRead;
+typedef struct _GVfsJobSeekRead GVfsJobSeekRead;
+typedef struct _GVfsJobCloseRead GVfsJobCloseRead;
+typedef struct _GVfsJobRead GVfsJobRead;
+typedef struct _GVfsJobOpenForWrite GVfsJobOpenForWrite;
+typedef struct _GVfsJobWrite GVfsJobWrite;
+typedef struct _GVfsJobSeekWrite GVfsJobSeekWrite;
+typedef struct _GVfsJobCloseWrite GVfsJobCloseWrite;
+typedef struct _GVfsJobQueryInfo GVfsJobQueryInfo;
+typedef struct _GVfsJobQueryInfoRead GVfsJobQueryInfoRead;
+typedef struct _GVfsJobQueryInfoWrite GVfsJobQueryInfoWrite;
+typedef struct _GVfsJobQueryFsInfo GVfsJobQueryFsInfo;
+typedef struct _GVfsJobEnumerate GVfsJobEnumerate;
+typedef struct _GVfsJobSetDisplayName GVfsJobSetDisplayName;
+typedef struct _GVfsJobTrash GVfsJobTrash;
+typedef struct _GVfsJobDelete GVfsJobDelete;
+typedef struct _GVfsJobMakeDirectory GVfsJobMakeDirectory;
+typedef struct _GVfsJobMakeSymlink GVfsJobMakeSymlink;
+typedef struct _GVfsJobCopy GVfsJobCopy;
+typedef struct _GVfsJobMove GVfsJobMove;
+typedef struct _GVfsJobPush GVfsJobPush;
+typedef struct _GVfsJobPull GVfsJobPull;
+typedef struct _GVfsJobSetAttribute GVfsJobSetAttribute;
+typedef struct _GVfsJobQueryAttributes GVfsJobQueryAttributes;
+typedef struct _GVfsJobCreateMonitor GVfsJobCreateMonitor;
typedef gpointer GVfsBackendHandle;
@@ -248,6 +249,16 @@ struct _GVfsBackendClass
GVfsBackendHandle handle,
GFileInfo *info,
GFileAttributeMatcher *attribute_matcher);
+ void (*query_info_on_write)(GVfsBackend *backend,
+ GVfsJobQueryInfoWrite *job,
+ GVfsBackendHandle handle,
+ GFileInfo *info,
+ GFileAttributeMatcher *attribute_matcher);
+ gboolean (*try_query_info_on_write)(GVfsBackend *backend,
+ GVfsJobQueryInfoWrite *job,
+ GVfsBackendHandle handle,
+ GFileInfo *info,
+ GFileAttributeMatcher *attribute_matcher);
void (*query_fs_info) (GVfsBackend *backend,
GVfsJobQueryFsInfo *job,
const char *filename,
diff --git a/daemon/gvfsbackendtest.c b/daemon/gvfsbackendtest.c
index f6616696..ccc6e3af 100644
--- a/daemon/gvfsbackendtest.c
+++ b/daemon/gvfsbackendtest.c
@@ -39,6 +39,10 @@
#include "gvfsjobseekread.h"
#include "gvfsjobqueryinfo.h"
#include "gvfsjobenumerate.h"
+#include "gvfsjobwrite.h"
+#include "gvfsjobopenforwrite.h"
+#include "gvfsjobclosewrite.h"
+#include "gvfsjobqueryinfowrite.h"
G_DEFINE_TYPE (GVfsBackendTest, g_vfs_backend_test, G_VFS_TYPE_BACKEND)
@@ -334,6 +338,197 @@ do_query_info (GVfsBackend *backend,
g_object_unref (file);
}
+static void
+do_create (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags)
+{
+ GFile *file;
+ GFileOutputStream *out;
+ GError *error;
+
+ file = g_vfs_get_file_for_path (g_vfs_get_local (),
+ filename);
+
+ error = NULL;
+ out = g_file_create (file, flags, G_VFS_JOB (job)->cancellable, &error);
+ g_object_unref (file);
+ if (out)
+ {
+ g_vfs_job_open_for_write_set_can_seek (job, FALSE);
+ g_vfs_job_open_for_write_set_handle (job, out);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ else
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+}
+
+static void
+do_append_to (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ GFileCreateFlags flags)
+{
+ GFile *file;
+ GFileOutputStream *out;
+ GError *error;
+
+ file = g_vfs_get_file_for_path (g_vfs_get_local (),
+ filename);
+
+ error = NULL;
+ out = g_file_append_to (file, flags, G_VFS_JOB (job)->cancellable, &error);
+ g_object_unref (file);
+ if (out)
+ {
+ g_vfs_job_open_for_write_set_can_seek (job, FALSE);
+ g_vfs_job_open_for_write_set_handle (job, out);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ else
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+}
+
+static void
+do_replace (GVfsBackend *backend,
+ GVfsJobOpenForWrite *job,
+ const char *filename,
+ const char *etag,
+ gboolean make_backup,
+ GFileCreateFlags flags)
+{
+ GFile *file;
+ GFileOutputStream *out;
+ GError *error;
+
+ file = g_vfs_get_file_for_path (g_vfs_get_local (),
+ filename);
+
+ error = NULL;
+ out = g_file_replace (file,
+ etag, make_backup,
+ flags, G_VFS_JOB (job)->cancellable,
+ &error);
+ g_object_unref (file);
+ if (out)
+ {
+ g_vfs_job_open_for_write_set_can_seek (job, FALSE);
+ g_vfs_job_open_for_write_set_handle (job, out);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+ else
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+}
+
+static void
+do_close_write (GVfsBackend *backend,
+ GVfsJobCloseWrite *job,
+ GVfsBackendHandle handle)
+{
+ GFileOutputStream *out;
+ GError *error;
+ char *etag;
+
+ out = (GFileOutputStream *)handle;
+
+ error = NULL;
+ if (!g_output_stream_close (G_OUTPUT_STREAM (out),
+ G_VFS_JOB (job)->cancellable,
+ &error))
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+ else
+ {
+ etag = g_file_output_stream_get_etag (out);
+
+ if (etag)
+ {
+ g_vfs_job_close_write_set_etag (job, etag);
+ g_free (etag);
+ }
+
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+
+ g_object_unref (out);
+}
+
+static void
+do_write (GVfsBackend *backend,
+ GVfsJobWrite *job,
+ GVfsBackendHandle handle,
+ char *buffer,
+ gsize buffer_size)
+{
+ GFileOutputStream *out;
+ GError *error;
+ gssize res;
+
+ g_print ("do_write\n");
+
+ out = (GFileOutputStream *)handle;
+
+ error = NULL;
+ res = g_output_stream_write (G_OUTPUT_STREAM (out),
+ buffer, buffer_size,
+ G_VFS_JOB (job)->cancellable,
+ &error);
+ if (res < 0)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+ else
+ {
+ g_vfs_job_write_set_written_size (job, res);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+}
+
+static void
+do_query_info_on_write (GVfsBackend *backend,
+ GVfsJobQueryInfoWrite *job,
+ GVfsBackendHandle handle,
+ GFileInfo *info,
+ GFileAttributeMatcher *attribute_matcher)
+{
+ GFileOutputStream *out;
+ GError *error;
+ GFileInfo *info2;
+
+ g_print ("do_query_info_on_write\n");
+
+ out = (GFileOutputStream *)handle;
+
+ error = NULL;
+ info2 = g_file_output_stream_query_info (out, job->attributes,
+ G_VFS_JOB (job)->cancellable,
+ &error);
+ if (info2 == NULL)
+ {
+ g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+ g_error_free (error);
+ }
+ else
+ {
+ g_file_info_copy_into (info2, info);
+ g_object_unref (info2);
+ g_vfs_job_succeeded (G_VFS_JOB (job));
+ }
+}
+
static gboolean
try_enumerate (GVfsBackend *backend,
GVfsJobEnumerate *job,
@@ -384,6 +579,14 @@ g_vfs_backend_test_class_init (GVfsBackendTestClass *klass)
backend_class->seek_on_read = do_seek_on_read;
backend_class->query_info_on_read = do_query_info_on_read;
backend_class->close_read = do_close_read;
+
+ backend_class->replace = do_replace;
+ backend_class->create = do_create;
+ backend_class->append_to = do_append_to;
+ backend_class->write = do_write;
+ backend_class->query_info_on_write = do_query_info_on_write;
+ backend_class->close_write = do_close_write;
+
backend_class->query_info = do_query_info;
backend_class->try_enumerate = try_enumerate;
}
diff --git a/daemon/gvfsjobqueryinfowrite.c b/daemon/gvfsjobqueryinfowrite.c
new file mode 100644
index 00000000..7b454f35
--- /dev/null
+++ b/daemon/gvfsjobqueryinfowrite.c
@@ -0,0 +1,144 @@
+/* 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 <alexl@redhat.com>
+ */
+
+#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 "gvfswritechannel.h"
+#include "gvfsjobqueryinfowrite.h"
+#include "gvfsdaemonutils.h"
+
+G_DEFINE_TYPE (GVfsJobQueryInfoWrite, g_vfs_job_query_info_write, G_VFS_TYPE_JOB)
+
+static void run (GVfsJob *job);
+static gboolean try (GVfsJob *job);
+static void send_reply (GVfsJob *job);
+
+static void
+g_vfs_job_query_info_write_finalize (GObject *object)
+{
+ GVfsJobQueryInfoWrite *job;
+
+ job = G_VFS_JOB_QUERY_INFO_WRITE (object);
+ g_object_unref (job->channel);
+ g_object_unref (job->file_info);
+ g_free (job->attributes);
+ g_file_attribute_matcher_unref (job->attribute_matcher);
+
+ if (G_OBJECT_CLASS (g_vfs_job_query_info_write_parent_class)->finalize)
+ (*G_OBJECT_CLASS (g_vfs_job_query_info_write_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_query_info_write_class_init (GVfsJobQueryInfoWriteClass *klass)
+{
+ GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+ GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+
+ gobject_class->finalize = g_vfs_job_query_info_write_finalize;
+
+ job_class->run = run;
+ job_class->try = try;
+ job_class->send_reply = send_reply;
+}
+
+static void
+g_vfs_job_query_info_write_init (GVfsJobQueryInfoWrite *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_query_info_write_new (GVfsWriteChannel *channel,
+ GVfsBackendHandle handle,
+ const char *attrs,
+ GVfsBackend *backend)
+{
+ GVfsJobQueryInfoWrite *job;
+
+ job = g_object_new (G_VFS_TYPE_JOB_QUERY_INFO_WRITE,
+ NULL);
+
+ job->backend = backend;
+ job->channel = g_object_ref (channel);
+ job->handle = handle;
+ job->attributes = g_strdup (attrs);
+ job->attribute_matcher = g_file_attribute_matcher_new (attrs);
+
+ job->file_info = g_file_info_new ();
+ g_file_info_set_attribute_mask (job->file_info, job->attribute_matcher);
+
+ return G_VFS_JOB (job);
+}
+
+/* Might be called on an i/o thwrite */
+static void
+send_reply (GVfsJob *job)
+{
+ GVfsJobQueryInfoWrite *op_job = G_VFS_JOB_QUERY_INFO_WRITE (job);
+
+ if (job->failed)
+ g_vfs_channel_send_error (G_VFS_CHANNEL (op_job->channel), job->error);
+ else
+ g_vfs_channel_send_info (G_VFS_CHANNEL (op_job->channel), op_job->file_info);
+}
+
+static void
+run (GVfsJob *job)
+{
+ GVfsJobQueryInfoWrite *op_job = G_VFS_JOB_QUERY_INFO_WRITE (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+ if (class->query_info_on_write == NULL)
+ {
+ g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+ _("Operation not supported by backend"));
+ return;
+ }
+
+ class->query_info_on_write (op_job->backend,
+ op_job,
+ op_job->handle,
+ op_job->file_info,
+ op_job->attribute_matcher);
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+ GVfsJobQueryInfoWrite *op_job = G_VFS_JOB_QUERY_INFO_WRITE (job);
+ GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+ if (class->try_query_info_on_write == NULL)
+ return FALSE;
+
+ return class->try_query_info_on_write (op_job->backend,
+ op_job,
+ op_job->handle,
+ op_job->file_info,
+ op_job->attribute_matcher);
+}
diff --git a/daemon/gvfsjobqueryinfowrite.h b/daemon/gvfsjobqueryinfowrite.h
new file mode 100644
index 00000000..1a2ac4cf
--- /dev/null
+++ b/daemon/gvfsjobqueryinfowrite.h
@@ -0,0 +1,67 @@
+/* GIO - GLib Input, Output and Streaming Library
+ *
+ * Copyright (C) 2006-2009 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 <alexl@redhat.com>
+ */
+
+#ifndef __G_VFS_JOB_QUERY_INFO_WRITE_H__
+#define __G_VFS_JOB_QUERY_INFO_WRITE_H__
+
+#include <gvfsjob.h>
+#include <gvfsbackend.h>
+#include <gvfswritechannel.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_QUERY_INFO_WRITE (g_vfs_job_query_info_write_get_type ())
+#define G_VFS_JOB_QUERY_INFO_WRITE(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_QUERY_INFO_WRITE, GVfsJobQueryInfoWrite))
+#define G_VFS_JOB_QUERY_INFO_WRITE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_QUERY_INFO_WRITE, GVfsJobQueryInfoWriteClass))
+#define G_VFS_IS_JOB_QUERY_INFO_WRITE(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_QUERY_INFO_WRITE))
+#define G_VFS_IS_JOB_QUERY_INFO_WRITE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_QUERY_INFO_WRITE))
+#define G_VFS_JOB_QUERY_INFO_WRITE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_QUERY_INFO_WRITE, GVfsJobQueryInfoWriteClass))
+
+typedef struct _GVfsJobQueryInfoWriteClass GVfsJobQueryInfoWriteClass;
+
+struct _GVfsJobQueryInfoWrite
+{
+ GVfsJob parent_instance;
+
+ GVfsWriteChannel *channel;
+ GVfsBackend *backend;
+ GVfsBackendHandle handle;
+ char *attributes;
+ GFileAttributeMatcher *attribute_matcher;
+
+ GFileInfo *file_info;
+};
+
+struct _GVfsJobQueryInfoWriteClass
+{
+ GVfsJobClass parent_class;
+};
+
+GType g_vfs_job_query_info_write_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_query_info_write_new (GVfsWriteChannel *channel,
+ GVfsBackendHandle handle,
+ const char *attrs,
+ GVfsBackend *backend);
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_QUERY_INFO_WRITE_H__ */
diff --git a/daemon/gvfswritechannel.c b/daemon/gvfswritechannel.c
index e340914b..1646aceb 100644
--- a/daemon/gvfswritechannel.c
+++ b/daemon/gvfswritechannel.c
@@ -39,6 +39,7 @@
#include <gvfsjobwrite.h>
#include <gvfsjobseekwrite.h>
#include <gvfsjobclosewrite.h>
+#include <gvfsjobqueryinfowrite.h>
struct _GVfsWriteChannel
{
@@ -103,6 +104,7 @@ write_channel_handle_request (GVfsChannel *channel,
GVfsBackendHandle backend_handle;
GVfsBackend *backend;
GVfsWriteChannel *write_channel;
+ char *attrs;
write_channel = G_VFS_WRITE_CHANNEL (channel);
backend_handle = g_vfs_channel_get_backend_handle (channel);
@@ -136,6 +138,15 @@ write_channel_handle_request (GVfsChannel *channel,
backend);
break;
+ case G_VFS_DAEMON_SOCKET_PROTOCOL_REQUEST_QUERY_INFO:
+ attrs = g_strndup (data, data_len);
+ job = g_vfs_job_query_info_write_new (write_channel,
+ backend_handle,
+ attrs,
+ backend);
+ g_free (attrs);
+ break;
+
default:
g_set_error (error, G_IO_ERROR,
G_IO_ERROR_FAILED,
diff --git a/test/test-query-info-stream.c b/test/test-query-info-stream.c
index 401a6ea0..d1288900 100644
--- a/test/test-query-info-stream.c
+++ b/test/test-query-info-stream.c
@@ -86,29 +86,9 @@ allocate_block (gsize size)
}
static void
-create_file (GFile *file, gsize size)
-{
- guchar *data;
- GError *error;
-
- data = allocate_block (size);
-
- error = NULL;
- if (!g_file_replace_contents (file,
- (char *)data,
- size,
- NULL, FALSE, 0,
- NULL, NULL, &error))
- {
- g_print ("error creating file: %s\n", error->message);
- exit (1);
- }
- g_free (data);
-}
-
-static void
check_query_info_res (GFileInfo *info,
- GError *error)
+ GError *error,
+ gsize expected_size)
{
goffset file_size;
@@ -125,16 +105,69 @@ check_query_info_res (GFileInfo *info,
}
file_size = g_file_info_get_size (info);
- if (file_size != 100*1000)
+ if (file_size != expected_size)
{
g_print ("wrong file size\n");
exit (1);
}
}
+static void
+check_query_info_out (GFileOutputStream *out, gsize expected_size)
+{
+ GFileInfo *info;
+ GError *error;
+
+ error = NULL;
+ info = g_file_output_stream_query_info (out, "*", NULL, &error);
+
+ check_query_info_res (info, error, expected_size);
+}
+
+static void
+create_file (GFile *file, gsize size)
+{
+ GFileOutputStream *out;
+ guchar *data;
+ gsize written;
+ GError *error;
+
+ data = allocate_block (size);
+
+ error = NULL;
+ out = g_file_replace (file, NULL, FALSE, 0, NULL, &error);
+ if (out == NULL)
+ {
+ g_print ("error creating file: %s\n", error->message);
+ exit (1);
+ }
+
+ check_query_info_out (out, 0);
+
+ if (!g_output_stream_write_all (G_OUTPUT_STREAM (out),
+ data, size,
+ &written,
+ NULL, &error))
+ {
+ g_print ("error writing to file: %s\n", error->message);
+ exit (1);
+ }
+
+ check_query_info_out (out, written);
+
+ if (written != size)
+ {
+ g_print ("not all data written to file\n");
+ exit (1);
+ }
+
+ g_output_stream_close (G_OUTPUT_STREAM (out), NULL, NULL);
+
+ g_free (data);
+}
static void
-check_query_info (GFileInputStream *in)
+check_query_info (GFileInputStream *in, gsize expected_size)
{
GFileInfo *info;
GError *error;
@@ -142,7 +175,7 @@ check_query_info (GFileInputStream *in)
error = NULL;
info = g_file_input_stream_query_info (in, "*", NULL, &error);
- check_query_info_res (info, error);
+ check_query_info_res (info, error, expected_size);
}
static void
@@ -158,7 +191,7 @@ async_cb (GObject *source_object,
g_file_input_stream_query_info_finish (G_FILE_INPUT_STREAM (source_object),
res, &error);
- check_query_info_res (info, error);
+ check_query_info_res (info, error, 100*1000);
g_main_loop_quit (main_loop);
}
@@ -209,7 +242,7 @@ main (int argc, char *argv[])
exit (1);
}
- check_query_info (in);
+ check_query_info (in, 100*1000);
buffer = malloc (100*1000);
@@ -238,7 +271,7 @@ main (int argc, char *argv[])
read_size += res;
- check_query_info (in);
+ check_query_info (in, 100*1000);
}
while (1);