summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlexander Larsson <alexl@redhat.com>2009-06-25 19:39:54 +0200
committerAlexander Larsson <alexl@redhat.com>2009-06-25 21:00:38 +0200
commitb548be8088f83b8cdeb66198e6092edfa518613d (patch)
tree3cf60da1073aa50915b084702d95c4c79ab214b4
parent2eb9e35ccf5112a6f01225c97b05e90eca8c7ea9 (diff)
downloadgvfs-b548be8088f83b8cdeb66198e6092edfa518613d.tar.gz
Implement metadata setting for remote locations
-rw-r--r--client/gdaemonfile.c159
-rw-r--r--client/gdaemonfile.h8
-rw-r--r--client/gdaemonfileenumerator.c78
-rw-r--r--client/gdaemonfileenumerator.h3
-rw-r--r--client/gdaemonvfs.c162
-rw-r--r--client/gdaemonvfs.h10
6 files changed, 338 insertions, 82 deletions
diff --git a/client/gdaemonfile.c b/client/gdaemonfile.c
index 1ecc5b0b..592b6d61 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 297066a9..1c92e6ec 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 b650eafb..7d5053af 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 25f5195a..90189c7a 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 06afd6cd..955019db 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 fae0904c..16d01a70 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);