gvfs r1143 - in trunk: . client common daemon



Author: alexl
Date: Thu Jan 17 11:02:17 2008
New Revision: 1143
URL: http://svn.gnome.org/viewvc/gvfs?rev=1143&view=rev

Log:
2008-01-17  Alexander Larsson  <alexl redhat com>

        * common/gvfsdaemonprotocol.h:
        * client/gdaemonfile.c:
	Add upload operation (requires latest glib)
	
        * daemon/gvfsbackend.[ch]:
        * daemon/gvfsjobupload.[ch]: Added.
	Implement upload in daemon
	
        * daemon/Makefile.am:
        * daemon/burn.mount.in: Added.
        * daemon/gvfsbackendburn.[ch]: Added.
	Added initial burn:/// implementation.
	Not fully implemented, but read works.
	
        * daemon/gvfsbackendcomputer.c:
	Ensure we set right mimetype for dirs




Added:
   trunk/daemon/burn.mount.in
   trunk/daemon/gvfsbackendburn.c
   trunk/daemon/gvfsbackendburn.h
   trunk/daemon/gvfsjobupload.c
   trunk/daemon/gvfsjobupload.h
Modified:
   trunk/ChangeLog
   trunk/client/gdaemonfile.c
   trunk/common/gvfsdaemonprotocol.h
   trunk/daemon/Makefile.am
   trunk/daemon/gvfsbackend.c
   trunk/daemon/gvfsbackend.h
   trunk/daemon/gvfsbackendcomputer.c

Modified: trunk/client/gdaemonfile.c
==============================================================================
--- trunk/client/gdaemonfile.c	(original)
+++ trunk/client/gdaemonfile.c	Thu Jan 17 11:02:17 2008
@@ -488,20 +488,28 @@
   if (mount_info1 == NULL)
     return NULL;
 
-  mount_info2 = _g_daemon_vfs_get_mount_info_sync (daemon_file2->mount_spec,
-						   daemon_file2->path,
-						   error);
-  if (mount_info2 == NULL)
-    return NULL;
-
-  if (mount_info1 != mount_info2)
+  mount_info2 = NULL;
+  if (daemon_file2)
     {
-      /* For copy this will cause the fallback code to be involved */
-      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
-		   _("Operation not supported, files on different mounts"));
-      return NULL;
+      mount_info2 = _g_daemon_vfs_get_mount_info_sync (daemon_file2->mount_spec,
+						       daemon_file2->path,
+						       error);
+      if (mount_info2 == NULL)
+	{
+	  g_mount_info_unref (mount_info1);
+	  return NULL;
+	}
+
+      if (mount_info1 != mount_info2)
+	{
+	  g_mount_info_unref (mount_info1);
+	  /* For copy this will cause the fallback code to be involved */
+	  g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+		       _("Operation not supported, files on different mounts"));
+	  return NULL;
+	}
     }
-  
+      
   message =
     dbus_message_new_method_call (mount_info1->dbus_id,
 				  mount_info1->object_path,
@@ -512,16 +520,19 @@
 				     daemon_file1->path);
   _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path1, 0);
 
-  path2 = g_mount_info_resolve_path (mount_info2,
-				     daemon_file2->path);
-  _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path2, 0);
-
+  if (daemon_file2)
+    {
+      path2 = g_mount_info_resolve_path (mount_info2,
+					 daemon_file2->path);
+      _g_dbus_message_append_args (message, G_DBUS_TYPE_CSTRING, &path2, 0);
+    }
+  
   va_start (var_args, first_arg_type);
   _g_dbus_message_append_args_valist (message,
 				      first_arg_type,
 				      var_args);
   va_end (var_args);
-
+  
   reply = _g_vfs_daemon_call_sync (message,
 				   connection_out,
 				   callback_obj_path,
@@ -531,7 +542,8 @@
   dbus_message_unref (message);
 
   g_mount_info_unref (mount_info1);
-  g_mount_info_unref (mount_info2);
+  if (mount_info2)
+    g_mount_info_unref (mount_info2);
   
   return reply;
 }
@@ -1858,13 +1870,38 @@
 {
   GDaemonFile *daemon_source, *daemon_dest;
   DBusMessage *reply;
+  char *local_path;
   char *obj_path, *dbus_obj_path;
   dbus_uint32_t flags_dbus;
   struct ProgressCallbackData data;
 
-  daemon_source = G_DAEMON_FILE (source);
+  if (!G_IS_DAEMON_FILE (destination))
+    {
+      /* Fall back to default move */
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Move not supported");
+      return FALSE;
+    }
   daemon_dest = G_DAEMON_FILE (destination);
 
+  if (G_IS_DAEMON_FILE (source))
+    {
+      daemon_source = G_DAEMON_FILE (source);
+      local_path = NULL;
+    }
+  else
+    {
+      daemon_source = NULL;
+      local_path = g_file_get_path (source);
+
+      if (local_path == NULL)
+	{
+	  /* This will cause the fallback code to be involved */
+	  g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+		       _("Operation not supported, files on different mounts"));
+	  return FALSE;
+	}
+    }
+  
   if (progress_callback)
     {
       obj_path = g_strdup_printf ("/org/gtk/vfs/callback/%p", &obj_path);
@@ -1881,13 +1918,29 @@
   data.progress_callback_data = progress_callback_data;
 
   flags_dbus = flags;
-  reply = do_sync_2_path_call (source, destination, 
-			       G_VFS_DBUS_MOUNT_OP_COPY,
-			       obj_path, progress_callback_message, &data,
-			       NULL, cancellable, error,
-			       DBUS_TYPE_UINT32, &flags_dbus,
-			       DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,
-			       0);
+  
+  if (daemon_source)
+    {
+      reply = do_sync_2_path_call (source, destination, 
+				   G_VFS_DBUS_MOUNT_OP_COPY,
+				   obj_path, progress_callback_message, &data,
+				   NULL, cancellable, error,
+				   DBUS_TYPE_UINT32, &flags_dbus,
+				   DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,
+				   0);
+    }
+  else
+    {
+      reply = do_sync_2_path_call (destination, NULL, 
+				   G_VFS_DBUS_MOUNT_OP_UPLOAD,
+				   obj_path, progress_callback_message, &data,
+				   NULL, cancellable, error,
+				   G_DBUS_TYPE_CSTRING, &local_path,
+				   DBUS_TYPE_UINT32, &flags_dbus,
+				   DBUS_TYPE_OBJECT_PATH, &dbus_obj_path,
+				   0);
+      g_free (local_path);
+    }
 
   g_free (obj_path);
 
@@ -1913,6 +1966,14 @@
   dbus_uint32_t flags_dbus;
   struct ProgressCallbackData data;
 
+  if (!G_DAEMON_FILE (source) ||
+      !G_DAEMON_FILE (destination))
+    {
+      /* Fall back to default move */
+      g_set_error (error, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED, "Move not supported");
+      return FALSE;
+    }
+  
   daemon_source = G_DAEMON_FILE (source);
   daemon_dest = G_DAEMON_FILE (destination);
 

Modified: trunk/common/gvfsdaemonprotocol.h
==============================================================================
--- trunk/common/gvfsdaemonprotocol.h	(original)
+++ trunk/common/gvfsdaemonprotocol.h	Thu Jan 17 11:02:17 2008
@@ -41,6 +41,7 @@
 #define G_VFS_DBUS_MOUNT_OP_MAKE_DIRECTORY "MakeDirectory"
 #define G_VFS_DBUS_MOUNT_OP_MAKE_SYMBOLIC_LINK "MakeSymbolicLink"
 #define G_VFS_DBUS_MOUNT_OP_COPY "Copy"
+#define G_VFS_DBUS_MOUNT_OP_UPLOAD "Upload"
 #define G_VFS_DBUS_MOUNT_OP_MOVE "Move"
 #define G_VFS_DBUS_MOUNT_OP_SET_ATTRIBUTE "SetAttribute"
 #define G_VFS_DBUS_MOUNT_OP_QUERY_SETTABLE_ATTRIBUTES "QuerySettableAttributes"

Modified: trunk/daemon/Makefile.am
==============================================================================
--- trunk/daemon/Makefile.am	(original)
+++ trunk/daemon/Makefile.am	Thu Jan 17 11:02:17 2008
@@ -30,10 +30,10 @@
 %.mount: %.mount.in ../config.log
 	sed -e "s|\ libexecdir\@|$(libexecdir)|" $< > $@
 
-libexec_PROGRAMS=gvfsd gvfsd-ftp gvfsd-sftp gvfsd-trash gvfsd-computer gvfsd-localtest
+libexec_PROGRAMS=gvfsd gvfsd-ftp gvfsd-sftp gvfsd-trash gvfsd-computer gvfsd-burn gvfsd-localtest
 
-mount_in_files = ftp.mount.in sftp.mount.in trash.mount.in computer.mount.in localtest.mount.in
-mount_DATA = ftp.mount sftp.mount trash.mount computer.mount localtest.mount
+mount_in_files = ftp.mount.in sftp.mount.in trash.mount.in computer.mount.in burn.mount.in localtest.mount.in
+mount_DATA = ftp.mount sftp.mount trash.mount computer.mount burn.mount localtest.mount
 
 if HAVE_HTTP
 mount_in_files += http.mount.in dav.mount.in 
@@ -92,6 +92,7 @@
 	gvfsjobtrash.c gvfsjobtrash.h \
 	gvfsjobdelete.c gvfsjobdelete.h \
 	gvfsjobcopy.c gvfsjobcopy.h \
+	gvfsjobupload.c gvfsjobupload.h \
 	gvfsjobmove.c gvfsjobmove.h \
 	gvfsjobmakedirectory.c gvfsjobmakedirectory.h \
 	gvfsjobmakesymlink.c gvfsjobmakesymlink.h \
@@ -212,6 +213,19 @@
 
 gvfsd_computer_LDADD = $(libraries)
 
+gvfsd_burn_SOURCES = \
+	gvfsbackendburn.c gvfsbackendburn.h \
+	daemon-main.c daemon-main.h \
+	daemon-main-generic.c 
+
+gvfsd_burn_CPPFLAGS = \
+	-DBACKEND_HEADER=gvfsbackendburn.h \
+	-DDEFAULT_BACKEND_TYPE=burn \
+	-DMAX_JOB_THREADS=1 \
+	-DBACKEND_TYPES='"burn", G_VFS_TYPE_BACKEND_BURN,'
+
+gvfsd_burn_LDADD = $(libraries)
+
 gvfsd_cdda_SOURCES = \
 	gvfsbackendcdda.c gvfsbackendcdda.h \
 	daemon-main.c daemon-main.h \

Added: trunk/daemon/burn.mount.in
==============================================================================
--- (empty file)
+++ trunk/daemon/burn.mount.in	Thu Jan 17 11:02:17 2008
@@ -0,0 +1,5 @@
+[Mount]
+Type=burn
+Exec= libexecdir@/gvfsd-burn
+AutoMount=true
+

Modified: trunk/daemon/gvfsbackend.c
==============================================================================
--- trunk/daemon/gvfsbackend.c	(original)
+++ trunk/daemon/gvfsbackend.c	Thu Jan 17 11:02:17 2008
@@ -440,6 +440,10 @@
     job = g_vfs_job_copy_new (connection, message, backend);
   else if (dbus_message_is_method_call (message,
 					G_VFS_DBUS_MOUNT_INTERFACE,
+					G_VFS_DBUS_MOUNT_OP_UPLOAD))
+    job = g_vfs_job_upload_new (connection, message, backend);
+  else if (dbus_message_is_method_call (message,
+					G_VFS_DBUS_MOUNT_INTERFACE,
 					G_VFS_DBUS_MOUNT_OP_MOVE))
     job = g_vfs_job_move_new (connection, message, backend);
   else if (dbus_message_is_method_call (message,

Modified: trunk/daemon/gvfsbackend.h
==============================================================================
--- trunk/daemon/gvfsbackend.h	(original)
+++ trunk/daemon/gvfsbackend.h	Thu Jan 17 11:02:17 2008
@@ -64,6 +64,7 @@
 typedef struct _GVfsJobMakeDirectory   GVfsJobMakeDirectory;
 typedef struct _GVfsJobMakeSymlink     GVfsJobMakeSymlink;
 typedef struct _GVfsJobCopy            GVfsJobCopy;
+typedef struct _GVfsJobUpload          GVfsJobUpload;
 typedef struct _GVfsJobMove            GVfsJobMove;
 typedef struct _GVfsJobSetAttribute    GVfsJobSetAttribute;
 typedef struct _GVfsJobQueryAttributes GVfsJobQueryAttributes;
@@ -296,6 +297,20 @@
 				 GFileCopyFlags flags,
 				 GFileProgressCallback progress_callback,
 				 gpointer progress_callback_data);
+  void     (*upload)            (GVfsBackend *backend,
+				 GVfsJobUpload *job,
+				 const char *destination,
+				 const char *local_path,
+				 GFileCopyFlags flags,
+				 GFileProgressCallback progress_callback,
+				 gpointer progress_callback_data);
+  gboolean (*try_upload)        (GVfsBackend *backend,
+				 GVfsJobUpload *job,
+				 const char *destination,
+				 const char *local_path,
+				 GFileCopyFlags flags,
+				 GFileProgressCallback progress_callback,
+				 gpointer progress_callback_data);
   void     (*move)              (GVfsBackend *backend,
 				 GVfsJobMove *job,
 				 const char *source,

Added: trunk/daemon/gvfsbackendburn.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsbackendburn.c	Thu Jan 17 11:02:17 2008
@@ -0,0 +1,964 @@
+/* -*- Mode: C; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* 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 <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <errno.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib/gstdio.h>
+#include <glib/gi18n.h>
+#include <gio/gio.h>
+#include <gio/gunixmounts.h>
+#include <glib/gurifuncs.h>
+
+#include "gvfsbackendburn.h"
+#include "gvfsmonitor.h"
+#include "gvfsjobopenforread.h"
+#include "gvfsjobread.h"
+#include "gvfsjobseekread.h"
+#include "gvfsjobopenforwrite.h"
+#include "gvfsjobwrite.h"
+#include "gvfsjobclosewrite.h"
+#include "gvfsjobseekwrite.h"
+#include "gvfsjobsetdisplayname.h"
+#include "gvfsjobmountmountable.h"
+#include "gvfsjobqueryinfo.h"
+#include "gvfsjobdelete.h"
+#include "gvfsjobqueryfsinfo.h"
+#include "gvfsjobqueryattributes.h"
+#include "gvfsjobenumerate.h"
+#include "gvfsjobcreatemonitor.h"
+#include "gvfsdaemonprotocol.h"
+
+/* TODO:
+ * Change notification
+ * 
+ */
+
+typedef enum {
+	VIRTUAL_NODE_FILE,
+	VIRTUAL_NODE_DIRECTORY
+} VirtualNodeType;
+
+typedef struct {
+	char           *filename;
+	VirtualNodeType type;
+
+	/* for files: */
+	char           *backing_file; /* local filename */
+	gboolean        owned_file;
+
+	GList          *subscriptions;
+
+	/* for directories: */
+	GList          *children;
+	volatile gint   ref_count;
+} VirtualNode;
+
+struct _GVfsBackendBurn
+{
+  GVfsBackend parent_instance;
+
+  char        *tempdir;
+  
+  VirtualNode *root_node;
+  
+  GMountSpec *mount_spec;
+};
+
+G_DEFINE_TYPE (GVfsBackendBurn, g_vfs_backend_burn, G_VFS_TYPE_BACKEND);
+
+
+static void virtual_node_unref (VirtualNode *node);
+
+static VirtualNode *
+virtual_node_new (const char     *filename,
+                  VirtualNodeType type)
+{
+  VirtualNode *node;
+  
+  node = g_slice_new0 (VirtualNode);
+  node->filename = g_strdup (filename);
+  node->type = type;
+  node->ref_count = 1;
+  
+  return node;
+}
+
+static void
+virtual_node_free (VirtualNode *node,
+                   gboolean     deep)
+{
+  GList *l;
+  
+  g_free (node->filename);
+  
+  switch (node->type)
+    {
+    case VIRTUAL_NODE_FILE:
+      if (node->backing_file != NULL)
+        {
+          if (node->owned_file)
+            g_unlink (node->backing_file);
+          g_free (node->backing_file);
+        }
+      break;
+    case VIRTUAL_NODE_DIRECTORY:
+      if (deep)
+        {
+          for (l = node->children; l != NULL; l = l->next)
+            virtual_node_unref ((VirtualNode *)l->data);
+        }
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+    }
+
+  /* 
+  while ((l = g_list_first (node->subscriptions)) != NULL) {
+    MappingSubscription *sub = l->data;
+    virtual_node_remove_subscription (node, sub);
+  }
+  */
+  
+  g_slice_free (VirtualNode, node);
+}
+
+static void
+virtual_node_unref (VirtualNode *node)
+{
+  g_return_if_fail (node != NULL);
+  g_return_if_fail (node->ref_count > 0);
+  
+  if (g_atomic_int_dec_and_test (&node->ref_count))
+    virtual_node_free (node, TRUE);
+}
+
+static VirtualNode *
+virtual_node_ref (VirtualNode *node)
+{
+  g_return_val_if_fail (node != NULL, NULL);
+  g_return_val_if_fail (node->ref_count > 0, NULL);
+  
+  g_atomic_int_inc (&node->ref_count);
+  return node;
+}
+
+
+static VirtualNode *
+virtual_dir_lookup (VirtualNode *dir,
+                    const char  *filename)
+{
+  GList       *l;
+  VirtualNode *node;
+  
+  g_assert (dir->type == VIRTUAL_NODE_DIRECTORY);
+  
+  for (l = dir->children; l != NULL; l = l->next)
+    {
+      node = l->data;
+      
+      if (strcmp (node->filename, filename) == 0)
+        return node;
+    }
+  
+  return NULL;
+}
+
+static VirtualNode *
+virtual_node_lookup (VirtualNode  *root_dir,
+                     const char   *path,
+                     VirtualNode **parent)
+{
+  char        *copy, *next, *copy_orig;
+  VirtualNode *node;
+  
+  copy_orig = g_strdup (path);
+  copy = copy_orig;
+  
+  if (parent != NULL) 
+    *parent = NULL;
+  
+  node = root_dir;
+  
+  while (copy != NULL)
+    {
+      /* Skip initial/multiple slashes */
+      while (G_IS_DIR_SEPARATOR (*copy))
+        ++copy;
+      
+      if (*copy == 0)
+        break;
+      
+      next = strchr (copy, G_DIR_SEPARATOR);
+      if (next)
+        {
+          *next = 0;
+          next++;
+        }
+      
+      if (node->type != VIRTUAL_NODE_DIRECTORY)
+        {
+          /* Found a file in the middle of the path */
+          node = NULL;
+          break;
+        }
+      
+      if (parent != NULL) 
+        *parent = node;
+      
+      node = virtual_dir_lookup (node, copy);
+      if (node == NULL) 
+        break;
+      
+      copy = next;
+    }
+  
+  g_free (copy_orig);
+  
+  return node;
+}
+
+static VirtualNode *
+virtual_mkdir (VirtualNode *node,
+               const char  *name)
+{
+  VirtualNode *subdir;
+  
+  g_assert (node->type == VIRTUAL_NODE_DIRECTORY);
+  
+  if (virtual_dir_lookup (node, name) != NULL)
+    return NULL;
+  
+  subdir = virtual_node_new (name, VIRTUAL_NODE_DIRECTORY);
+  
+  /* list takes ownership of ref */
+  node->children = g_list_append (node->children, subdir);
+  
+  return subdir;
+}
+
+static void
+virtual_unlink (VirtualNode *dir,
+                VirtualNode *node)
+{
+  g_assert (dir->type == VIRTUAL_NODE_DIRECTORY);
+  
+  dir->children = g_list_remove (dir->children, node);
+  virtual_node_unref (node);
+}
+
+static VirtualNode *
+virtual_create (GVfsBackendBurn *backend,
+                VirtualNode *dir,
+                const char  *name,
+                const char  *backing_file)
+{
+  VirtualNode *file;
+  char        *template;
+  int          fd;
+  
+  g_assert (dir->type == VIRTUAL_NODE_DIRECTORY);
+  
+  if (virtual_dir_lookup (dir, name) != NULL)
+    return NULL;
+  
+  file = virtual_node_new (name, VIRTUAL_NODE_FILE);
+  
+  if (backing_file != NULL)
+    {
+      file->backing_file = g_strdup (backing_file);
+      file->owned_file = FALSE;
+    }
+  else
+    {
+      template = g_build_filename (backend->tempdir, "file.XXXXXX", NULL);
+      
+      fd = g_mkstemp (template);
+      if (fd < 0)
+        {
+          g_free (template);
+          virtual_node_unref (file);
+          return NULL;
+          
+        }
+      close (fd);
+      g_unlink (template);
+      
+      file->backing_file = template;
+      file->owned_file = TRUE;
+    }
+  
+  /* list takes ownership of ref */
+  dir->children = g_list_append (dir->children, file);
+  
+  return file;
+}
+
+static void
+g_vfs_backend_burn_finalize (GObject *object)
+{
+  GVfsBackendBurn *backend;
+
+  backend = G_VFS_BACKEND_BURN (object);
+
+  g_mount_spec_unref (backend->mount_spec);
+
+  if (G_OBJECT_CLASS (g_vfs_backend_burn_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_vfs_backend_burn_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_backend_burn_init (GVfsBackendBurn *burn_backend)
+{
+  GVfsBackend *backend = G_VFS_BACKEND (burn_backend);
+  GMountSpec *mount_spec;
+  
+  g_vfs_backend_set_display_name (backend, _("Burn"));
+  g_vfs_backend_set_icon_name (backend, "gnome-fs-client");
+  g_vfs_backend_set_user_visible (backend, FALSE);
+
+  mount_spec = g_mount_spec_new ("burn");
+  g_vfs_backend_set_mount_spec (backend, mount_spec);
+  burn_backend->mount_spec = mount_spec;
+}
+
+static gboolean
+try_mount (GVfsBackend *backend,
+           GVfsJobMount *job,
+           GMountSpec *mount_spec,
+           GMountSource *mount_source,
+           gboolean is_automount)
+{
+  GVfsBackendBurn *burn_backend = G_VFS_BACKEND_BURN (backend);
+  char        *tempdir, *filename;
+  char        *dir;
+
+  filename = g_strdup_printf ("virtual-%s.XXXXXX", g_get_user_name ());
+  tempdir = g_build_filename (g_get_tmp_dir (), filename, NULL);
+  g_free (filename);
+
+  dir = mkdtemp (tempdir);
+  if (dir == NULL)
+    {
+      g_free (tempdir);
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR, G_IO_ERROR_FAILED,
+                        _("Unable to create temporary directory"));
+      return TRUE;
+    }
+
+  burn_backend->tempdir = dir;
+  burn_backend->root_node =
+    virtual_node_new (NULL, VIRTUAL_NODE_DIRECTORY);
+  
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  return TRUE;
+}
+
+static gboolean
+try_delete (GVfsBackend *backend,
+            GVfsJobDelete *job,
+            const char *filename)
+{
+  char *dirname, *basename;
+  VirtualNode *file, *dir;
+
+	dirname = g_path_get_dirname (filename);
+  dir = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, dirname, NULL);
+	g_free (dirname);
+
+  if (dir == NULL ||
+      dir->type != VIRTUAL_NODE_DIRECTORY)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+	basename = g_path_get_basename (filename);
+	file = virtual_dir_lookup (dir, basename);
+  g_free (basename);
+	if (file == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+  if (file->type == VIRTUAL_NODE_DIRECTORY &&
+      file->children != NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_EMPTY,
+                        _("Directory not empty"));
+      return TRUE;
+    }
+  
+  virtual_unlink (dir, file);
+  
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  return TRUE;
+}
+
+
+static gboolean
+try_open_for_read (GVfsBackend *backend,
+                   GVfsJobOpenForRead *job,
+                   const char *filename)
+{
+  VirtualNode *node;
+  GFileInputStream *stream;
+  GFile *file;
+  GError *error;
+
+  node = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, filename, NULL);
+  if (node == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+  if (node->type == VIRTUAL_NODE_DIRECTORY)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+                        _("Can't copy file over directory"));
+      return TRUE;
+    }
+
+  file = g_file_new_for_path (node->backing_file);
+  
+  error = NULL;
+  stream = g_file_read (file, G_VFS_JOB (job)->cancellable, &error);
+  g_object_unref (file);
+  
+  if (stream)
+    {
+      g_vfs_job_open_for_read_set_can_seek (job, g_file_input_stream_can_seek (stream));
+      g_vfs_job_open_for_read_set_handle (job, stream);
+      g_vfs_job_succeeded (G_VFS_JOB (job));
+    }
+  else
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
+    }
+
+  return TRUE;
+}
+
+
+static void
+do_read (GVfsBackend *backend,
+         GVfsJobRead *job,
+         GVfsBackendHandle _handle,
+         char *buffer,
+         gsize bytes_requested)
+{
+  GError *error;
+  GFileInputStream *stream = _handle;
+  gssize s;
+  
+  error = NULL;
+  s = g_input_stream_read (G_INPUT_STREAM(stream),
+                           buffer, bytes_requested,
+                           G_VFS_JOB (job)->cancellable, &error); 
+  if (s >= 0)
+    {
+      g_vfs_job_read_set_size (job, s);
+      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_seek_on_read (GVfsBackend *backend,
+                  GVfsJobSeekRead *job,
+                  GVfsBackendHandle _handle,
+                  goffset    offset,
+                  GSeekType  type)
+{
+  GError *error;
+  GFileInputStream *stream = _handle;
+  
+  error = NULL;
+  if (g_file_input_stream_seek (stream, offset, type,
+                                G_VFS_JOB (job)->cancellable, &error))
+    {
+      g_vfs_job_seek_read_set_offset (job, g_file_input_stream_tell(stream));
+      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_read (GVfsBackend *backend,
+               GVfsJobCloseRead *job,
+               GVfsBackendHandle _handle)
+{
+  GError *error;
+  GFileInputStream *stream = _handle;
+  
+  error = NULL;
+  if (g_input_stream_close (G_INPUT_STREAM(stream),
+                            G_VFS_JOB (job)->cancellable, &error))
+    {
+      g_vfs_job_succeeded (G_VFS_JOB (job));
+    }
+  else
+    {
+      g_vfs_job_failed_from_error (G_VFS_JOB (job), error);
+      g_error_free (error);
+    }
+  
+  g_object_unref (stream);
+}
+
+static char *
+make_valid_utf8 (const char *name)
+{
+  GString *string;
+  const gchar *remainder, *invalid;
+  gint remaining_bytes, valid_bytes;
+  
+  string = NULL;
+  remainder = name;
+  remaining_bytes = strlen (name);
+  
+  while (remaining_bytes != 0) 
+    {
+      if (g_utf8_validate (remainder, remaining_bytes, &invalid)) 
+        break;
+      valid_bytes = invalid - remainder;
+      
+      if (string == NULL) 
+        string = g_string_sized_new (remaining_bytes);
+      
+      g_string_append_len (string, remainder, valid_bytes);
+      /* append U+FFFD REPLACEMENT CHARACTER */
+      g_string_append (string, "\357\277\275");
+      
+      remaining_bytes -= valid_bytes + 1;
+      remainder = invalid + 1;
+    }
+  
+  if (string == NULL)
+    return g_strdup (name);
+  
+  g_string_append (string, remainder);
+  
+  g_warn_if_fail (g_utf8_validate (string->str, -1, NULL));
+  
+  return g_string_free (string, FALSE);
+}
+
+
+static void
+file_info_from_node (VirtualNode *node,
+                     GFileInfo *info,
+                     const char *attributes)
+{
+  GIcon *icon;
+  GFile *file;
+  GFileInfo *file_info;
+
+  if (node->type == VIRTUAL_NODE_DIRECTORY)
+    {
+      g_file_info_set_file_type (info, G_FILE_TYPE_DIRECTORY);
+      icon = g_themed_icon_new ("folder");
+      g_file_info_set_icon (info, icon);
+      g_object_unref (icon);
+      g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, TRUE);
+      g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, TRUE);
+      g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
+      g_file_info_set_content_type (info, "inode/directory"); 
+   }
+  else
+    {
+      file = g_file_new_for_path (node->backing_file);
+      file_info = g_file_query_info (file,
+                                     attributes,
+                                     0, /* Always follow symlinks */
+                                     NULL, NULL);
+      if (file_info)
+        {
+          g_file_info_copy_into (file_info, info);
+          g_object_unref (file_info);
+        }
+      
+      g_file_info_set_attribute_byte_string (info,
+                                             "burn::backing-file",
+                                             node->backing_file);
+    }
+
+  if (node->filename != NULL)
+    {
+      char *utf8;
+      
+      g_file_info_set_name (info, node->filename);
+      /* Ensure display name is utf8 */
+      utf8 = make_valid_utf8 (node->filename);
+      g_file_info_set_display_name (info, utf8);
+      g_free (utf8);
+    }
+  else
+    {
+      g_file_info_set_name (info, "/");
+      g_file_info_set_display_name (info, _("CD Burner"));
+    }
+}
+
+static gboolean
+try_enumerate (GVfsBackend *backend,
+               GVfsJobEnumerate *job,
+               const char *filename,
+               GFileAttributeMatcher *attribute_matcher,
+               GFileQueryInfoFlags flags)
+{
+  VirtualNode *node, *child;
+  GFileInfo *info;
+  GList *l;
+  
+  node = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, filename, NULL);
+ 
+  if (node == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+  
+  if (node->type != VIRTUAL_NODE_DIRECTORY)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_DIRECTORY,
+                        _("The file is not a directory"));
+      return TRUE;
+    }
+
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  
+  for (l = node->children; l != NULL; l = l->next)
+    {
+      child = l->data;
+      
+      info = g_file_info_new ();
+      file_info_from_node (child, info, job->attributes);
+      g_vfs_job_enumerate_add_info (job, info);
+      g_object_unref (info);
+    }
+
+  g_vfs_job_enumerate_done (job);
+ 
+  return TRUE;
+}
+
+static gboolean
+try_query_info (GVfsBackend *backend,
+                GVfsJobQueryInfo *job,
+                const char *filename,
+                GFileQueryInfoFlags flags,
+                GFileInfo *info,
+                GFileAttributeMatcher *matcher)
+{
+  VirtualNode *node;
+
+  g_print ("q_i: filename: %s\n", filename);
+  
+  node = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, filename, NULL);
+ 
+  if (node == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+  file_info_from_node (node, info, job->attributes);
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  
+  return TRUE;
+}
+
+static gboolean
+try_make_directory (GVfsBackend *backend,
+                    GVfsJobMakeDirectory *job,
+                    const char *filename)
+{
+  char *dirname, *basename;
+  VirtualNode *file, *dir;
+  
+	dirname = g_path_get_dirname (filename);
+  dir = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, dirname, NULL);
+	g_free (dirname);
+  
+	if (dir == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+	basename = g_path_get_basename (filename);
+	file = virtual_dir_lookup (dir, basename);
+	if (file != NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_EXISTS,
+                        _("File exists"));
+      g_free (basename);
+      return TRUE;
+    }
+
+	file = virtual_mkdir (dir, basename);
+	g_free (basename);
+
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+
+  return TRUE;
+}
+
+static gboolean
+try_set_display_name (GVfsBackend *backend,
+                      GVfsJobSetDisplayName *job,
+                      const char *filename,
+                      const char *display_name)
+{
+  VirtualNode *node, *dir;
+  char *target_path;
+  char *dirname;
+  
+  node = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, filename, &dir);
+  if (node == NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory"));
+      return TRUE;
+    }
+
+  if (virtual_dir_lookup (dir, display_name) != NULL)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_EXISTS,
+                        _("File exists"));
+      return TRUE;
+    }
+
+  /* We use UTF8 for filenames */
+  g_free (node->filename);
+  node->filename = g_strdup (display_name);
+
+  dirname = g_path_get_dirname (filename);
+  target_path = g_build_filename (dirname, display_name, NULL);
+  g_vfs_job_set_display_name_set_new_path (job, target_path);
+  g_free (dirname);
+  g_free (target_path);
+  
+  g_vfs_job_succeeded (G_VFS_JOB (job));
+  
+  return TRUE;
+  
+}
+
+static gboolean
+try_upload (GVfsBackend *backend,
+            GVfsJobUpload *job,
+            const char *destination,
+            const char *local_path,
+            GFileCopyFlags flags,
+            GFileProgressCallback progress_callback,
+            gpointer progress_callback_data)
+{
+  VirtualNode *file, *dir;
+  struct stat stat_buf;
+  char *dirname, *basename;
+  
+  if (g_stat (local_path, &stat_buf) == -1)
+    {
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR,
+                        g_io_error_from_errno (errno),
+                        g_strerror (errno));
+      return TRUE;
+    }
+
+	dirname = g_path_get_dirname (destination);
+  dir = virtual_node_lookup (G_VFS_BACKEND_BURN (backend)->root_node, dirname, NULL);
+	g_free (dirname);
+  file = NULL;
+
+  if (dir == NULL)
+    {
+      /* Parent of created file doesn't exist */
+      g_vfs_job_failed (G_VFS_JOB (job), G_IO_ERROR,
+                        G_IO_ERROR_NOT_FOUND,
+                        _("No such file or directory in target path"));
+      return TRUE;
+    }
+  
+  basename = g_path_get_basename (destination);
+  file = virtual_dir_lookup (dir, basename);
+  g_free (basename);
+  
+  if (S_ISDIR (stat_buf.st_mode))
+    {
+      /* The source is a directory, don't fail with WOULD_RECURSE immediately, 
+       * as that is less useful to the app. Better check for errors on the 
+       * target instead. 
+       */
+      
+      if (file != NULL)
+        {
+          if (flags & G_FILE_COPY_OVERWRITE)
+            {
+              if (file->type == VIRTUAL_NODE_DIRECTORY)
+                {
+                  g_vfs_job_failed (G_VFS_JOB (job),
+                                    G_IO_ERROR, G_IO_ERROR_WOULD_MERGE,
+                                    _("Can't copy directory over directory"));
+                  return TRUE;
+                }
+              /* continue to would_recurse error */
+            }
+          else
+            {
+              g_vfs_job_failed (G_VFS_JOB (job),
+                                G_IO_ERROR, G_IO_ERROR_EXISTS,
+                                _("Target file exists"));
+              return TRUE;
+            }
+        }
+      
+      g_vfs_job_failed (G_VFS_JOB (job),
+                        G_IO_ERROR, G_IO_ERROR_WOULD_RECURSE,
+                        _("Can't recursively copy directory"));
+      return TRUE;
+    }
+
+  g_print ("file: %p, overwrite: %d\n", file, flags & G_FILE_COPY_OVERWRITE);
+  if (file != NULL)
+    {
+      if (flags & G_FILE_COPY_OVERWRITE)
+        {
+          if (file->type == VIRTUAL_NODE_DIRECTORY)
+            {
+              g_vfs_job_failed (G_VFS_JOB (job),
+                                G_IO_ERROR, G_IO_ERROR_IS_DIRECTORY,
+                                _("Can't copy file over directory"));
+              return TRUE;
+            }
+          else
+            {
+              g_assert (file->type == VIRTUAL_NODE_FILE);
+              if (file->owned_file)
+                g_unlink (file->backing_file);
+              g_free (file->backing_file);
+              file->owned_file = FALSE;
+              file->backing_file = g_strdup (local_path);
+              
+              g_vfs_job_succeeded (G_VFS_JOB (job));
+              return TRUE;
+            }
+        }
+      else
+        {
+          g_vfs_job_failed (G_VFS_JOB (job),
+                            G_IO_ERROR, G_IO_ERROR_EXISTS,
+                            _("File exists"));
+          return TRUE;
+        }
+    }
+  else
+    {
+      basename = g_path_get_basename (destination);
+      file = virtual_create (G_VFS_BACKEND_BURN (backend),
+                             dir,
+                             basename,
+                             local_path);
+      g_free (basename);
+      
+      g_vfs_job_succeeded (G_VFS_JOB (job));
+      return TRUE;
+    }
+}
+
+static gboolean
+try_create_dir_monitor (GVfsBackend *backend,
+                        GVfsJobCreateMonitor *job,
+                        const char *filename,
+                        GFileMonitorFlags flags)
+{
+  g_vfs_job_failed (G_VFS_JOB (job),
+                    G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+                    _("Not supported"));
+  return TRUE;
+}
+
+static void
+g_vfs_backend_burn_class_init (GVfsBackendBurnClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GVfsBackendClass *backend_class = G_VFS_BACKEND_CLASS (klass);
+  
+  gobject_class->finalize = g_vfs_backend_burn_finalize;
+
+  backend_class->try_mount = try_mount;
+  backend_class->try_open_for_read = try_open_for_read;
+  backend_class->try_query_info = try_query_info;
+  backend_class->try_enumerate = try_enumerate;
+  backend_class->try_create_dir_monitor = try_create_dir_monitor;
+  backend_class->try_make_directory = try_make_directory;
+  backend_class->try_set_display_name = try_set_display_name;
+  backend_class->try_upload = try_upload;
+  backend_class->try_delete = try_delete;
+  backend_class->read = do_read;
+  backend_class->seek_on_read = do_seek_on_read;
+  backend_class->close_read = do_close_read;
+}

Added: trunk/daemon/gvfsbackendburn.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsbackendburn.h	Thu Jan 17 11:02:17 2008
@@ -0,0 +1,50 @@
+/* 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>
+ */
+
+#ifndef __G_VFS_BACKEND_BURN_H__
+#define __G_VFS_BACKEND_BURN_H__
+
+#include <gvfsbackend.h>
+#include <gmountspec.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_BACKEND_BURN         (g_vfs_backend_burn_get_type ())
+#define G_VFS_BACKEND_BURN(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_BACKEND_BURN, GVfsBackendBurn))
+#define G_VFS_BACKEND_BURN_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_BACKEND_BURN, GVfsBackendBurnClass))
+#define G_VFS_IS_BACKEND_BURN(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_BACKEND_BURN))
+#define G_VFS_IS_BACKEND_BURN_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_BACKEND_BURN))
+#define G_VFS_BACKEND_BURN_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_BACKEND_BURN, GVfsBackendBurnClass))
+
+typedef struct _GVfsBackendBurn        GVfsBackendBurn;
+typedef struct _GVfsBackendBurnClass   GVfsBackendBurnClass;
+
+struct _GVfsBackendBurnClass
+{
+  GVfsBackendClass parent_class;
+};
+
+GType g_vfs_backend_burn_get_type (void) G_GNUC_CONST;
+
+G_END_DECLS
+
+#endif /* __G_VFS_BACKEND_BURN_H__ */

Modified: trunk/daemon/gvfsbackendcomputer.c
==============================================================================
--- trunk/daemon/gvfsbackendcomputer.c	(original)
+++ trunk/daemon/gvfsbackendcomputer.c	Thu Jan 17 11:02:17 2008
@@ -687,6 +687,7 @@
       g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_WRITE, FALSE);
       g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_DELETE, FALSE);
       g_file_info_set_attribute_boolean (info, G_FILE_ATTRIBUTE_ACCESS_CAN_TRASH, FALSE);
+      g_file_info_set_content_type (info, "inode/directory");
     }
   else if (file != NULL)
     file_info_from_file (file, info);

Added: trunk/daemon/gvfsjobupload.c
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsjobupload.c	Thu Jan 17 11:02:17 2008
@@ -0,0 +1,211 @@
+/* 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 <strings.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <glib/gi18n.h>
+#include "gvfsjobupload.h"
+#include "gdbusutils.h"
+#include "gvfsdaemonprotocol.h"
+
+G_DEFINE_TYPE (GVfsJobUpload, g_vfs_job_upload, G_VFS_TYPE_JOB_DBUS);
+
+static void         run          (GVfsJob        *job);
+static gboolean     try          (GVfsJob        *job);
+static DBusMessage *create_reply (GVfsJob        *job,
+				  DBusConnection *connection,
+				  DBusMessage    *message);
+
+static void
+g_vfs_job_upload_finalize (GObject *object)
+{
+  GVfsJobUpload *job;
+
+  job = G_VFS_JOB_UPLOAD (object);
+  
+  g_free (job->local_path);
+  g_free (job->destination);
+  g_free (job->callback_obj_path);
+  
+  if (G_OBJECT_CLASS (g_vfs_job_upload_parent_class)->finalize)
+    (*G_OBJECT_CLASS (g_vfs_job_upload_parent_class)->finalize) (object);
+}
+
+static void
+g_vfs_job_upload_class_init (GVfsJobUploadClass *klass)
+{
+  GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
+  GVfsJobClass *job_class = G_VFS_JOB_CLASS (klass);
+  GVfsJobDBusClass *job_dbus_class = G_VFS_JOB_DBUS_CLASS (klass);
+  
+  gobject_class->finalize = g_vfs_job_upload_finalize;
+  job_class->run = run;
+  job_class->try = try;
+  job_dbus_class->create_reply = create_reply;
+}
+
+static void
+g_vfs_job_upload_init (GVfsJobUpload *job)
+{
+}
+
+GVfsJob *
+g_vfs_job_upload_new (DBusConnection *connection,
+			DBusMessage *message,
+			GVfsBackend *backend)
+{
+  GVfsJobUpload *job;
+  DBusMessage *reply;
+  DBusError derror;
+  int path1_len, path2_len;
+  const char *path1_data, *path2_data, *callback_obj_path;
+  dbus_uint32_t flags;
+  
+  dbus_error_init (&derror);
+  if (!dbus_message_get_args (message, &derror, 
+			      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+			      &path1_data, &path1_len,
+			      DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
+			      &path2_data, &path2_len,
+                              DBUS_TYPE_UINT32, &flags,
+			      DBUS_TYPE_OBJECT_PATH, &callback_obj_path,
+			      0))
+    {
+      reply = dbus_message_new_error (message,
+				      derror.name,
+                                      derror.message);
+      dbus_error_free (&derror);
+
+      dbus_connection_send (connection, reply, NULL);
+      return NULL;
+    }
+
+  job = g_object_new (G_VFS_TYPE_JOB_UPLOAD,
+		      "message", message,
+		      "connection", connection,
+		      NULL);
+
+  job->destination = g_strndup (path1_data, path1_len);
+  job->local_path = g_strndup (path2_data, path2_len);
+  job->backend = backend;
+  job->flags = flags;
+  if (strcmp (callback_obj_path, "/org/gtk/vfs/void") != 0)
+    job->callback_obj_path = g_strdup (callback_obj_path);
+  
+  return G_VFS_JOB (job);
+}
+
+static void
+progress_callback (goffset current_num_bytes,
+		   goffset total_num_bytes,
+		   gpointer user_data)
+{
+  GVfsJob *job = G_VFS_JOB (user_data);
+  GVfsJobDBus *dbus_job = G_VFS_JOB_DBUS (job);
+  GVfsJobUpload *op_job = G_VFS_JOB_UPLOAD (job);
+  dbus_uint64_t current_dbus, total_dbus;
+  DBusMessage *message;
+
+  g_print ("progress_callback %d/%d\n", (int)current_num_bytes, (int)total_num_bytes);
+
+  if (op_job->callback_obj_path == NULL)
+    return;
+  
+  message =
+    dbus_message_new_method_call (dbus_message_get_sender (dbus_job->message),
+				  op_job->callback_obj_path,
+				  G_VFS_DBUS_PROGRESS_INTERFACE,
+				  G_VFS_DBUS_PROGRESS_OP_PROGRESS);
+  dbus_message_set_no_reply (message, TRUE);
+
+  current_dbus = current_num_bytes;
+  total_dbus = total_num_bytes;
+  dbus_message_append_args (message,
+			    DBUS_TYPE_UINT64, &current_dbus,
+			    DBUS_TYPE_UINT64, &total_dbus,
+			    0);
+
+  /* Queues reply (threadsafely), actually sends it in mainloop */
+  dbus_connection_send (dbus_job->connection, message, NULL);
+  dbus_message_unref (message);
+}
+
+static void
+run (GVfsJob *job)
+{
+  GVfsJobUpload *op_job = G_VFS_JOB_UPLOAD (job);
+  GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+  if (class->upload == NULL)
+    {
+      g_vfs_job_failed (job, G_IO_ERROR, G_IO_ERROR_NOT_SUPPORTED,
+			_("Operation not supported by backend"));
+      return;
+    }
+  
+  class->upload (op_job->backend,
+		 op_job,
+		 op_job->destination,
+		 op_job->local_path,
+		 op_job->flags,
+		 progress_callback,
+		 job);
+}
+
+static gboolean
+try (GVfsJob *job)
+{
+  GVfsJobUpload *op_job = G_VFS_JOB_UPLOAD (job);
+  GVfsBackendClass *class = G_VFS_BACKEND_GET_CLASS (op_job->backend);
+
+  if (class->try_upload == NULL)
+    return FALSE;
+  
+  return class->try_upload (op_job->backend,
+			    op_job,
+			    op_job->destination,
+			    op_job->local_path,
+			    op_job->flags,
+			    progress_callback,
+			    job);
+}
+
+/* Might be called on an i/o thread */
+static DBusMessage *
+create_reply (GVfsJob *job,
+	      DBusConnection *connection,
+	      DBusMessage *message)
+{
+  DBusMessage *reply;
+
+  reply = dbus_message_new_method_return (message);
+  
+  return reply;
+}

Added: trunk/daemon/gvfsjobupload.h
==============================================================================
--- (empty file)
+++ trunk/daemon/gvfsjobupload.h	Thu Jan 17 11:02:17 2008
@@ -0,0 +1,66 @@
+/* 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>
+ */
+
+#ifndef __G_VFS_JOB_UPLOAD_H__
+#define __G_VFS_JOB_UPLOAD_H__
+
+#include <gio/gio.h>
+#include <gvfsjob.h>
+#include <gvfsjobdbus.h>
+#include <gvfsbackend.h>
+
+G_BEGIN_DECLS
+
+#define G_VFS_TYPE_JOB_UPLOAD         (g_vfs_job_upload_get_type ())
+#define G_VFS_JOB_UPLOAD(o)           (G_TYPE_CHECK_INSTANCE_CAST ((o), G_VFS_TYPE_JOB_UPLOAD, GVfsJobUpload))
+#define G_VFS_JOB_UPLOAD_CLASS(k)     (G_TYPE_CHECK_CLASS_CAST((k), G_VFS_TYPE_JOB_UPLOAD, GVfsJobUploadClass))
+#define G_VFS_IS_JOB_UPLOAD(o)        (G_TYPE_CHECK_INSTANCE_TYPE ((o), G_VFS_TYPE_JOB_UPLOAD))
+#define G_VFS_IS_JOB_UPLOAD_CLASS(k)  (G_TYPE_CHECK_CLASS_TYPE ((k), G_VFS_TYPE_JOB_UPLOAD))
+#define G_VFS_JOB_UPLOAD_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), G_VFS_TYPE_JOB_UPLOAD, GVfsJobUploadClass))
+
+typedef struct _GVfsJobUploadClass   GVfsJobUploadClass;
+
+struct _GVfsJobUpload
+{
+  GVfsJobDBus parent_instance;
+
+  GVfsBackend *backend;
+  char *destination;
+  char *local_path;
+  GFileCopyFlags flags;
+  char *callback_obj_path;
+};
+
+struct _GVfsJobUploadClass
+{
+  GVfsJobDBusClass parent_class;
+};
+
+GType g_vfs_job_upload_get_type (void) G_GNUC_CONST;
+
+GVfsJob *g_vfs_job_upload_new (DBusConnection *connection,
+			       DBusMessage    *message,
+			       GVfsBackend    *backend);
+
+G_END_DECLS
+
+#endif /* __G_VFS_JOB_UPLOAD_H__ */



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