[gvfs] Implement metadata setting for remote locations



commit b548be8088f83b8cdeb66198e6092edfa518613d
Author: Alexander Larsson <alexl redhat com>
Date:   Thu Jun 25 19:39:54 2009 +0200

    Implement metadata setting for remote locations

 client/gdaemonfile.c           |  159 ++++++++++++++++++++++++++++++++++++---
 client/gdaemonfile.h           |    8 ++
 client/gdaemonfileenumerator.c |   78 ++++++++++++++++++-
 client/gdaemonfileenumerator.h |    3 +-
 client/gdaemonvfs.c            |  162 ++++++++++++++++++++++++----------------
 client/gdaemonvfs.h            |   10 +++
 6 files changed, 338 insertions(+), 82 deletions(-)
---
diff --git a/client/gdaemonfile.c b/client/gdaemonfile.c
index 1ecc5b0..592b6d6 100644
--- a/client/gdaemonfile.c
+++ b/client/gdaemonfile.c
@@ -40,17 +40,10 @@
 #include "gdbusutils.h"
 #include "gmountoperationdbus.h"
 #include <gio/gio.h>
+#include "metatree.h"
 
 static void g_daemon_file_file_iface_init (GFileIface       *iface);
 
-struct _GDaemonFile
-{
-  GObject parent_instance;
-
-  GMountSpec *mount_spec;
-  char *path;
-};
-
 static void g_daemon_file_read_async (GFile *file,
 				      int io_priority,
 				      GCancellable *cancellable,
@@ -709,7 +702,7 @@ g_daemon_file_enumerate_children (GFile      *file,
   DBusConnection *connection;
   char *uri;
 
-  enumerator = g_daemon_file_enumerator_new (file);
+  enumerator = g_daemon_file_enumerator_new (file, attributes);
   obj_path = g_daemon_file_enumerator_get_object_path (enumerator);
 
 
@@ -746,6 +739,70 @@ g_daemon_file_enumerate_children (GFile      *file,
   return NULL;
 }
 
+
+static gboolean
+enumerate_keys_callback (const char *key,
+			 MetaKeyType type,
+			 gpointer value,
+			 gpointer user_data)
+{
+  GFileInfo  *info = user_data;
+  char *attr;
+
+  attr = g_strconcat ("metadata::", key, NULL);
+
+  if (type == META_KEY_TYPE_STRING)
+    g_file_info_set_attribute_string (info, attr, (char *)value);
+  else
+    g_file_info_set_attribute_stringv (info, attr, (char **)value);
+
+  g_free (attr);
+
+  return TRUE;
+}
+
+static void
+add_metadata (GFile *file,
+	      const char *attributes,
+	      GFileInfo *info)
+{
+  GDaemonFile *daemon_file;
+  GFileAttributeMatcher *matcher;
+  const char *first;
+  char *treename;
+  gboolean all;
+  MetaTree *tree;
+
+  daemon_file = G_DAEMON_FILE (file);
+
+  matcher = g_file_attribute_matcher_new (attributes);
+  all = g_file_attribute_matcher_enumerate_namespace (matcher, "metadata");
+
+  first = NULL;
+  if (!all)
+    {
+      first = g_file_attribute_matcher_enumerate_next (matcher);
+
+      if (first == NULL)
+	{
+	  g_file_attribute_matcher_unref (matcher);
+	  return; /* No match */
+	}
+    }
+
+  treename = g_mount_spec_to_string (daemon_file->mount_spec);
+  tree = meta_tree_lookup_by_name (treename, FALSE);
+  g_free (treename);
+
+  g_file_info_set_attribute_mask (info, matcher);
+  meta_tree_enumerate_keys (tree, daemon_file->path,
+			    enumerate_keys_callback, info);
+  g_file_info_unset_attribute_mask (info);
+
+  meta_tree_unref (tree);
+  g_file_attribute_matcher_unref (matcher);
+}
+
 static GFileInfo *
 g_daemon_file_query_info (GFile                *file,
 			  const char           *attributes,
@@ -790,6 +847,9 @@ g_daemon_file_query_info (GFile                *file,
 
   info = _g_dbus_get_file_info (&iter, error);
 
+  if (info)
+    add_metadata (file, attributes, info);
+
  out:
   dbus_message_unref (reply);
   return info;
@@ -802,9 +862,11 @@ query_info_async_cb (DBusMessage *reply,
 		     GCancellable *cancellable,
 		     gpointer callback_data)
 {
+  const char *attributes = callback_data;
   DBusMessageIter iter;
   GFileInfo *info;
   GError *error;
+  GFile *file;
 
   info = NULL;
   
@@ -828,6 +890,10 @@ query_info_async_cb (DBusMessage *reply,
       return;
     }
 
+  file = G_FILE (g_async_result_get_source_object (G_ASYNC_RESULT (result)));
+  add_metadata (file, attributes, info);
+  g_object_unref (file);
+
   g_simple_async_result_set_op_res_gpointer (result, info, g_object_unref);
   _g_simple_async_result_complete_with_cancellable (result, cancellable);
 }
@@ -851,7 +917,7 @@ g_daemon_file_query_info_async (GFile                      *file,
 		      G_VFS_DBUS_MOUNT_OP_QUERY_INFO,
 		      cancellable,
 		      callback, user_data,
-		      query_info_async_cb, NULL, NULL,
+		      query_info_async_cb, g_strdup (attributes), g_free,
 		      DBUS_TYPE_STRING, &attributes,
 		      DBUS_TYPE_UINT32, &dbus_flags,
 		      DBUS_TYPE_STRING, &uri,
@@ -1947,9 +2013,77 @@ g_daemon_file_query_writable_namespaces (GFile                      *file,
   list = _g_dbus_get_attribute_info_list (&iter, error);
   
   dbus_message_unref (reply);
+
+  if (list)
+    g_file_attribute_info_list_add (list,
+				    "metadata",
+				    G_FILE_ATTRIBUTE_TYPE_STRING, /* Also STRINGV, but no way express this ... */
+				    G_FILE_ATTRIBUTE_INFO_COPY_WITH_FILE |
+				    G_FILE_ATTRIBUTE_INFO_COPY_WHEN_MOVED);
   
   return list;
+}
 
+static gboolean
+set_metadata_attribute (GFile *file,
+			const char *attribute,
+			GFileAttributeType type,
+			gpointer value,
+			GCancellable *cancellable,
+			GError **error)
+{
+  GDaemonFile *daemon_file;
+  DBusMessage *message;
+  char *treename;
+  const char *metatreefile;
+  MetaTree *tree;
+  int appended;
+  gboolean res;
+
+  daemon_file = G_DAEMON_FILE (file);
+
+  treename = g_mount_spec_to_string (daemon_file->mount_spec);
+  tree = meta_tree_lookup_by_name (treename, FALSE);
+  g_free (treename);
+
+  message =
+    dbus_message_new_method_call (G_VFS_DBUS_METADATA_NAME,
+				  G_VFS_DBUS_METADATA_PATH,
+				  G_VFS_DBUS_METADATA_INTERFACE,
+				  G_VFS_DBUS_METADATA_OP_SET);
+  g_assert (message != NULL);
+  metatreefile = meta_tree_get_filename (tree);
+  _g_dbus_message_append_args (message,
+			       G_DBUS_TYPE_CSTRING, &metatreefile,
+			       G_DBUS_TYPE_CSTRING, &daemon_file->path,
+			       0);
+
+  appended = _g_daemon_vfs_append_metadata_for_set (message,
+						    tree,
+						    daemon_file->path,
+						    attribute,
+						    type,
+						    value);
+
+  res = TRUE;
+  if (appended == -1)
+    {
+      res = FALSE;
+      g_set_error (error, G_IO_ERROR,
+		   G_IO_ERROR_INVALID_ARGUMENT,
+		   _("Error setting file metadata: %s"),
+		   _("values must be string or list of strings"));
+    }
+  else if (appended > 0 &&
+      !_g_daemon_vfs_send_message_sync (message,
+					cancellable, error))
+    res = FALSE;
+
+  dbus_message_unref (message);
+
+  meta_tree_unref (tree);
+
+  return res;
 }
 
 static gboolean
@@ -1966,6 +2100,9 @@ g_daemon_file_set_attribute (GFile *file,
   dbus_uint32_t flags_dbus;
   GError *my_error;
 
+  if (g_str_has_prefix (attribute, "metadata::"))
+    return set_metadata_attribute (file, attribute, type, value_p, cancellable, error);
+
  retry:
   
   message = create_empty_message (file, G_VFS_DBUS_MOUNT_OP_SET_ATTRIBUTE, NULL, error);
@@ -2528,7 +2665,7 @@ g_daemon_file_enumerate_children_async (GFile                      *file,
   GDaemonFileEnumerator *enumerator;
   char *uri;
 
-  enumerator = g_daemon_file_enumerator_new (file);
+  enumerator = g_daemon_file_enumerator_new (file, attributes);
   obj_path = g_daemon_file_enumerator_get_object_path (enumerator);
 
   uri = g_file_get_uri (file);
diff --git a/client/gdaemonfile.h b/client/gdaemonfile.h
index 297066a..1c92e6e 100644
--- a/client/gdaemonfile.h
+++ b/client/gdaemonfile.h
@@ -44,6 +44,14 @@ struct _GDaemonFileClass
   GObjectClass parent_class;
 };
 
+struct _GDaemonFile
+{
+  GObject parent_instance;
+
+  GMountSpec *mount_spec;
+  char *path;
+};
+
 GType g_daemon_file_get_type (void) G_GNUC_CONST;
   
 GFile * g_daemon_file_new (GMountSpec *mount_spec,
diff --git a/client/gdaemonfileenumerator.c b/client/gdaemonfileenumerator.c
index b650eaf..7d5053a 100644
--- a/client/gdaemonfileenumerator.c
+++ b/client/gdaemonfileenumerator.c
@@ -30,6 +30,8 @@
 #include <gio/gio.h>
 #include <gvfsdaemondbus.h>
 #include <gvfsdaemonprotocol.h>
+#include "gdaemonfile.h"
+#include "metatree.h"
 
 #define OBJ_PATH_PREFIX "/org/gtk/vfs/client/enumerator/"
 
@@ -55,6 +57,9 @@ struct _GDaemonFileEnumerator
   gulong cancelled_tag;
   guint timeout_tag;
   GSimpleAsyncResult *async_res;
+
+  GFileAttributeMatcher *matcher;
+  MetaTree *metadata_tree;
 };
 
 G_DEFINE_TYPE (GDaemonFileEnumerator, g_daemon_file_enumerator, G_TYPE_FILE_ENUMERATOR)
@@ -107,6 +112,10 @@ g_daemon_file_enumerator_finalize (GObject *object)
 
   free_info_list (daemon->infos);
 
+  g_file_attribute_matcher_unref (daemon->matcher);
+  if (daemon->metadata_tree)
+    meta_tree_unref (daemon->metadata_tree);
+
   if (daemon->sync_connection)
     dbus_connection_unref (daemon->sync_connection);
   
@@ -145,17 +154,73 @@ g_daemon_file_enumerator_init (GDaemonFileEnumerator *daemon)
 }
 
 GDaemonFileEnumerator *
-g_daemon_file_enumerator_new (GFile *file)
+g_daemon_file_enumerator_new (GFile *file,
+			      const char *attributes)
 {
   GDaemonFileEnumerator *daemon;
+  char *treename;
 
   daemon = g_object_new (G_TYPE_DAEMON_FILE_ENUMERATOR,
                          "container", file,
                          NULL);
-  
+
+  daemon->matcher = g_file_attribute_matcher_new (attributes);
+  if (g_file_attribute_matcher_enumerate_namespace (daemon->matcher, "metadata") ||
+      g_file_attribute_matcher_enumerate_next (daemon->matcher) != NULL)
+    {
+      treename = g_mount_spec_to_string (G_DAEMON_FILE (file)->mount_spec);
+      daemon->metadata_tree = meta_tree_lookup_by_name (treename, FALSE);
+      g_free (treename);
+    }
+
   return daemon;
 }
 
+static gboolean
+enumerate_keys_callback (const char *key,
+			 MetaKeyType type,
+			 gpointer value,
+			 gpointer user_data)
+{
+  GFileInfo  *info = user_data;
+  char *attr;
+
+  attr = g_strconcat ("metadata::", key, NULL);
+
+  if (type == META_KEY_TYPE_STRING)
+    g_file_info_set_attribute_string (info, attr, (char *)value);
+  else
+    g_file_info_set_attribute_stringv (info, attr, (char **)value);
+
+  g_free (attr);
+
+  return TRUE;
+}
+
+static void
+add_metadata (GFileInfo *info,
+	      GDaemonFileEnumerator *daemon)
+{
+  GFile *container;
+  const char *name;
+  char *path;
+
+  if (!daemon->metadata_tree)
+    return;
+
+  name = g_file_info_get_name (info);
+  container = g_file_enumerator_get_container (G_FILE_ENUMERATOR (daemon));
+  path = g_build_filename (G_DAEMON_FILE (container)->path, name, NULL);
+
+  g_file_info_set_attribute_mask (info, daemon->matcher);
+  meta_tree_enumerate_keys (daemon->metadata_tree, path,
+			    enumerate_keys_callback, info);
+  g_file_info_unset_attribute_mask (info);
+
+  g_free (path);
+}
+
+
 /* Called with infos lock held */
 static void
 trigger_async_done (GDaemonFileEnumerator *daemon, gboolean ok)
@@ -187,7 +252,9 @@ trigger_async_done (GDaemonFileEnumerator *daemon, gboolean ok)
 	  rest->prev = NULL;
 	}
       daemon->infos = rest;
-      
+
+      g_list_foreach (l, add_metadata, daemon);
+
       g_simple_async_result_set_op_res_gpointer (daemon->async_res,
 						 l,
 						 (GDestroyNotify)free_info_list);
@@ -301,7 +368,10 @@ g_daemon_file_enumerator_next_file (GFileEnumerator *enumerator,
 	  done = TRUE;
 	  info = daemon->infos->data;
 	  if (info)
-	    g_assert (G_IS_FILE_INFO (info));
+	    {
+	      g_assert (G_IS_FILE_INFO (info));
+	      add_metadata (G_FILE_INFO (info), daemon);
+	    }
 	  daemon->infos = g_list_delete_link (daemon->infos, daemon->infos);
 	}
       else if (daemon->done)
diff --git a/client/gdaemonfileenumerator.h b/client/gdaemonfileenumerator.h
index 25f5195..90189c7 100644
--- a/client/gdaemonfileenumerator.h
+++ b/client/gdaemonfileenumerator.h
@@ -46,7 +46,8 @@ struct _GDaemonFileEnumeratorClass
 
 GType g_daemon_file_enumerator_get_type (void) G_GNUC_CONST;
 
-GDaemonFileEnumerator *g_daemon_file_enumerator_new                 (GFile *file);
+GDaemonFileEnumerator *g_daemon_file_enumerator_new                 (GFile *file,
+								     const char *attributes);
 char  *                g_daemon_file_enumerator_get_object_path     (GDaemonFileEnumerator *enumerator);
 void                   g_daemon_file_enumerator_set_sync_connection (GDaemonFileEnumerator *enumerator,
 								     DBusConnection        *connection);
diff --git a/client/gdaemonvfs.c b/client/gdaemonvfs.c
index 06afd6c..955019d 100644
--- a/client/gdaemonvfs.c
+++ b/client/gdaemonvfs.c
@@ -39,7 +39,6 @@
 #include "gdaemonvolumemonitor.h"
 #include "gvfsicon.h"
 #include "gvfsiconloadable.h"
-#include "metatree.h"
 #include <glib/gi18n-lib.h>
 #include <glib/gstdio.h>
 
@@ -1166,10 +1165,12 @@ send_message_oneway (DBusMessage *message)
   dbus_connection_flush (connection);
 }
 
-static gboolean
-send_message (DBusMessage *message,
-	      GCancellable *cancellable,
-	      GError **error)
+/* Sends a message on the session bus and blocks for the reply,
+   using the thread local connection */
+gboolean
+_g_daemon_vfs_send_message_sync (DBusMessage *message,
+				 GCancellable *cancellable,
+				 GError **error)
 {
   DBusConnection *connection;
   DBusError derror;
@@ -1218,6 +1219,69 @@ strv_equal (char **a, char **b)
   return TRUE;
 }
 
+/* -1 => error, otherwise number of added items */
+int
+_g_daemon_vfs_append_metadata_for_set (DBusMessage *message,
+				       MetaTree *tree,
+				       const char *path,
+				       const char *attribute,
+				       GFileAttributeType type,
+				       gpointer   value)
+{
+  const char *key;
+  int res;
+
+  key = attribute + strlen ("metadata::");
+
+  res = 0;
+  if (type == G_FILE_ATTRIBUTE_TYPE_STRING)
+    {
+      const char *current;
+      const char *val = (char *)value;
+
+      current = meta_tree_lookup_string (tree, path, key);
+      if (current == NULL || strcmp (current, val) != 0)
+	{
+	  res = 1;
+	  _g_dbus_message_append_args (message,
+				       DBUS_TYPE_STRING, &key,
+				       DBUS_TYPE_STRING, &val,
+				       0);
+	}
+    }
+  else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
+    {
+      char **current;
+      char **val = (char **)value;
+      current = meta_tree_lookup_stringv (tree, path, key);
+      if (current == NULL || !strv_equal (current, val))
+	{
+	  res = 1;
+	  _g_dbus_message_append_args (message,
+				       DBUS_TYPE_STRING, &key,
+				       DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &val, g_strv_length (val),
+				       0);
+	}
+    }
+  else if (type == G_FILE_ATTRIBUTE_TYPE_INVALID)
+    {
+      if (meta_tree_lookup_key_type (tree, path, key) != META_KEY_TYPE_NONE)
+	{
+	  char c = 0;
+	  res = 1;
+	  /* Byte => unset */
+	  _g_dbus_message_append_args (message,
+				       DBUS_TYPE_STRING, &key,
+				       DBUS_TYPE_BYTE, &c,
+				       0);
+	}
+    }
+  else
+    res = -1;
+
+  return res;
+}
+
 static gboolean
 g_daemon_vfs_local_file_set_attributes (GVfs       *vfs,
 					const char *filename,
@@ -1232,12 +1296,13 @@ g_daemon_vfs_local_file_set_attributes (GVfs       *vfs,
   struct stat statbuf;
   char **attributes;
   char *tree_path;
-  char *key;
   MetaTree *tree;
   int errsv;
   int i, num_set;
   DBusMessage *message;
   gboolean res;
+  int appended;
+  gpointer value;
 
   res = TRUE;
   if (g_file_info_has_namespace (info, "metadata"))
@@ -1283,75 +1348,40 @@ g_daemon_vfs_local_file_set_attributes (GVfs       *vfs,
 	  num_set = 0;
 	  for (i = 0; attributes[i] != NULL; i++)
 	    {
-	      key = attributes[i] + strlen ("metadata::");
-	      type = g_file_info_get_attribute_type (info, attributes[i]);
-	      if (type == G_FILE_ATTRIBUTE_TYPE_STRING)
+	      if (g_file_info_get_attribute_data (info, attributes[i], &type, &value, NULL))
 		{
-		  const char *current;
-		  const char *val = g_file_info_get_attribute_string (info, attributes[i]);
-
-		  current = meta_tree_lookup_string (tree, tree_path, key);
-		  if (current == NULL || strcmp (current, val) != 0)
+		  appended = _g_daemon_vfs_append_metadata_for_set (message,
+								    tree,
+								    tree_path,
+								    attributes[i],
+								    type,
+								    value);
+		  if (appended != -1)
 		    {
-		      num_set++;
-		      _g_dbus_message_append_args (message,
-						   DBUS_TYPE_STRING, &key,
-						   DBUS_TYPE_STRING, &val,
-						   0);
+		      num_set += appended;
+		      g_file_info_set_attribute_status (info, attributes[i],
+							G_FILE_ATTRIBUTE_STATUS_SET);
 		    }
-		  g_file_info_set_attribute_status (info, attributes[i],
-						    G_FILE_ATTRIBUTE_STATUS_SET);
-		}
-	      else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
-		{
-		  char **current;
-		  char **val = g_file_info_get_attribute_stringv (info, attributes[i]);
-		  current = meta_tree_lookup_stringv (tree, tree_path, key);
-		  if (current == NULL || !strv_equal (current, val))
-		    {
-		      num_set++;
-		      _g_dbus_message_append_args (message,
-						   DBUS_TYPE_STRING, &key,
-						   DBUS_TYPE_ARRAY, DBUS_TYPE_STRING, &val, g_strv_length (val),
-						   0);
-		    }
-		  g_file_info_set_attribute_status (info, attributes[i],
-						    G_FILE_ATTRIBUTE_STATUS_SET);
-		}
-	      else if (type == G_FILE_ATTRIBUTE_TYPE_INVALID)
-		{
-		  if (meta_tree_lookup_key_type (tree, tree_path, key) != META_KEY_TYPE_NONE)
+		  else
 		    {
-		      char c = 0;
-		      num_set++;
-		      /* Byte => unset */
-		      _g_dbus_message_append_args (message,
-						   DBUS_TYPE_STRING, &key,
-						   DBUS_TYPE_BYTE, &c,
-						   0);
+		      res = FALSE;
+		      g_set_error (error, G_IO_ERROR,
+				   G_IO_ERROR_INVALID_ARGUMENT,
+				   _("Error setting file metadata: %s"),
+				   _("values must be string or list of strings"));
+		      error = NULL; /* Don't set further errors */
+		      g_file_info_set_attribute_status (info, attributes[i],
+							G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
 		    }
-		  g_file_info_set_attribute_status (info, attributes[i],
-						    G_FILE_ATTRIBUTE_STATUS_SET);
 		}
-	      else
-		{
-		  res = FALSE;
-		  g_set_error (error, G_IO_ERROR,
-			       G_IO_ERROR_INVALID_ARGUMENT,
-			       _("Error setting file metadata: %s"),
-			       _("values must be string or list of strings"));
-		  error = NULL; /* Don't set further errors */
-		  g_file_info_set_attribute_status (info, attributes[i],
-						    G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
-		}
-
-	      meta_tree_unref (tree);
-	      g_free (tree_path);
 	    }
 
+	  meta_tree_unref (tree);
+	  g_free (tree_path);
+
 	  if (num_set > 0 &&
-	      !send_message (message,
-			     cancellable, error))
+	      !_g_daemon_vfs_send_message_sync (message,
+						cancellable, error))
 	    {
 	      res = FALSE;
 	      error = NULL; /* Don't set further errors */
diff --git a/client/gdaemonvfs.h b/client/gdaemonvfs.h
index fae0904..16d01a7 100644
--- a/client/gdaemonvfs.h
+++ b/client/gdaemonvfs.h
@@ -28,6 +28,7 @@
 #include "gmountspec.h"
 #include "gmounttracker.h"
 #include "gvfsuriutils.h"
+#include <metatree.h>
 
 G_BEGIN_DECLS
 
@@ -67,6 +68,15 @@ GMountSpec *    _g_daemon_vfs_get_mount_spec_for_path  (GMountSpec
 						        const char               *new_path);
 void            _g_daemon_vfs_invalidate_dbus_id       (const char               *dbus_id);
 DBusConnection *_g_daemon_vfs_get_async_bus            (void);
+gboolean        _g_daemon_vfs_send_message_sync        (DBusMessage              *message,
+							GCancellable             *cancellable,
+							GError                  **error);
+int             _g_daemon_vfs_append_metadata_for_set  (DBusMessage *message,
+							MetaTree *tree,
+							const char *path,
+							const char *attribute,
+							GFileAttributeType type,
+							gpointer   value);
 
 
 



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