gvfs r2260 - in trunk: . client daemon test



Author: alexl
Date: Fri Feb 27 15:50:51 2009
New Revision: 2260
URL: http://svn.gnome.org/viewvc/gvfs?rev=2260&view=rev

Log:
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().



Added:
   trunk/daemon/gvfsjobqueryinfowrite.c
   trunk/daemon/gvfsjobqueryinfowrite.h
Modified:
   trunk/ChangeLog
   trunk/client/gdaemonfileoutputstream.c
   trunk/daemon/Makefile.am
   trunk/daemon/gvfsbackend.h
   trunk/daemon/gvfsbackendtest.c
   trunk/daemon/gvfswritechannel.c
   trunk/test/test-query-info-stream.c

Modified: trunk/client/gdaemonfileoutputstream.c
==============================================================================
--- trunk/client/gdaemonfileoutputstream.c	(original)
+++ trunk/client/gdaemonfileoutputstream.c	Fri Feb 27 15:50:51 2009
@@ -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 @@
   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 @@
   
 };
 
-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 @@
   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 @@
   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 @@
 	    }
 
 	  /* Got full header */
-
+	  
 	  {
 	    GVfsDaemonSocketProtocolReply reply;
 	    char *data;
@@ -975,24 +1010,165 @@
   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 @@
   /* 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);
+ 
+}

Modified: trunk/daemon/Makefile.am
==============================================================================
--- trunk/daemon/Makefile.am	(original)
+++ trunk/daemon/Makefile.am	Fri Feb 27 15:50:51 2009
@@ -135,6 +135,7 @@
 	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 \

Modified: trunk/daemon/gvfsbackend.h
==============================================================================
--- trunk/daemon/gvfsbackend.h	(original)
+++ trunk/daemon/gvfsbackend.h	Fri Feb 27 15:50:51 2009
@@ -43,35 +43,36 @@
 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 @@
 				 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,

Modified: trunk/daemon/gvfsbackendtest.c
==============================================================================
--- trunk/daemon/gvfsbackendtest.c	(original)
+++ trunk/daemon/gvfsbackendtest.c	Fri Feb 27 15:50:51 2009
@@ -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 @@
   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 @@
   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;
 }

Added: trunk/daemon/gvfsjobqueryinfowrite.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsjobqueryinfowrite.c	Fri Feb 27 15:50:51 2009
@@ -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);
+}

Added: trunk/daemon/gvfsjobqueryinfowrite.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsjobqueryinfowrite.h	Fri Feb 27 15:50:51 2009
@@ -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__ */

Modified: trunk/daemon/gvfswritechannel.c
==============================================================================
--- trunk/daemon/gvfswritechannel.c	(original)
+++ trunk/daemon/gvfswritechannel.c	Fri Feb 27 15:50:51 2009
@@ -39,6 +39,7 @@
 #include <gvfsjobwrite.h>
 #include <gvfsjobseekwrite.h>
 #include <gvfsjobclosewrite.h>
+#include <gvfsjobqueryinfowrite.h>
 
 struct _GVfsWriteChannel
 {
@@ -103,6 +104,7 @@
   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 @@
 				      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,

Modified: trunk/test/test-query-info-stream.c
==============================================================================
--- trunk/test/test-query-info-stream.c	(original)
+++ trunk/test/test-query-info-stream.c	Fri Feb 27 15:50:51 2009
@@ -86,29 +86,9 @@
 }
 
 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 @@
     }
   
   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 @@
   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 @@
     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 @@
       exit (1);
     }
 
-  check_query_info (in);
+  check_query_info (in, 100*1000);
 
   buffer = malloc (100*1000);
 
@@ -238,7 +271,7 @@
 
       read_size += res;
 
-      check_query_info (in);
+      check_query_info (in, 100*1000);
     }
   while (1);
 



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]