From b548be8088f83b8cdeb66198e6092edfa518613d Mon Sep 17 00:00:00 2001 From: Alexander Larsson Date: Thu, 25 Jun 2009 19:39:54 +0200 Subject: 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 1ecc5b0b..592b6d61 100644 --- a/client/gdaemonfile.c +++ b/client/gdaemonfile.c @@ -40,17 +40,10 @@ #include "gdbusutils.h" #include "gmountoperationdbus.h" #include +#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 #include #include +#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 #include @@ -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 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); -- cgit v1.2.1