[gvfs] Implement the metadata addition api in GVfs
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gvfs] Implement the metadata addition api in GVfs
- Date: Tue, 23 Jun 2009 11:12:14 -0400 (EDT)
commit bad7cc5631d046aafd00d3c22ab7486cef5e43e6
Author: Alexander Larsson <alexl redhat com>
Date: Thu Jun 18 09:10:33 2009 +0200
Implement the metadata addition api in GVfs
This uses the metadata library to add metadata to GFileInfo for
local files.
client/Makefile.am | 3 +-
client/gdaemonvfs.c | 358 ++++++++++++++++++++++++++++++++++++++++++++++++++-
2 files changed, 358 insertions(+), 3 deletions(-)
---
diff --git a/client/Makefile.am b/client/Makefile.am
index b2aea25..e6e7d85 100644
--- a/client/Makefile.am
+++ b/client/Makefile.am
@@ -2,6 +2,7 @@ NULL =
INCLUDES = -I$(top_srcdir) \
-I$(top_srcdir)/client \
+ -I$(top_srcdir)/metadata \
-I$(top_srcdir)/common \
$(GLIB_CFLAGS) $(DBUS_CFLAGS) \
-DG_LOG_DOMAIN=\"GVFS\" -DG_DISABLE_DEPRECATED \
@@ -51,7 +52,7 @@ giomodules_LTLIBRARIES = libgvfsdbus.la
libgvfsdbus_la_LDFLAGS = $(module_flags)
libgvfsdbus_la_SOURCES = $(vfssources)
-libgvfsdbus_la_LIBADD = $(vfslibs)
+libgvfsdbus_la_LIBADD = $(vfslibs) ../metadata/libmetadata.la
noinst_PROGRAMS = test-uri-utils
diff --git a/client/gdaemonvfs.c b/client/gdaemonvfs.c
index c9f2cc9..39ae56d 100644
--- a/client/gdaemonvfs.c
+++ b/client/gdaemonvfs.c
@@ -24,6 +24,7 @@
#include <string.h>
#include <signal.h>
#include <stdlib.h>
+#include <errno.h>
#include <dbus/dbus.h>
#include "gdaemonvfs.h"
#include "gvfsuriutils.h"
@@ -38,7 +39,9 @@
#include "gdaemonvolumemonitor.h"
#include "gvfsicon.h"
#include "gvfsiconloadable.h"
+#include "metatree.h"
#include <glib/gi18n-lib.h>
+#include <glib/gstdio.h>
typedef struct {
char *type;
@@ -1066,6 +1069,352 @@ g_daemon_vfs_parse_name (GVfs *vfs,
return file;
}
+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
+g_daemon_vfs_local_file_add_info (GVfs *vfs,
+ const char *filename,
+ guint64 device,
+ GFileAttributeMatcher *matcher,
+ GFileInfo *info,
+ GCancellable *cancellable,
+ gpointer *extra_data,
+ GDestroyNotify *extra_data_free)
+{
+ MetaLookupCache *cache;
+ const char *first;
+ char *tree_path;
+ gboolean all;
+ MetaTree *tree;
+
+ /* Filename may or may not be a symlink, but we should not follow it.
+ However, we want to follow symlinks for all parents that have the same
+ device node */
+ all = g_file_attribute_matcher_enumerate_namespace (matcher, "metadata");
+
+ first = NULL;
+ if (!all)
+ {
+ first = g_file_attribute_matcher_enumerate_next (matcher);
+
+ if (first == NULL)
+ return; /* No match */
+ }
+
+ if (*extra_data == NULL)
+ {
+ *extra_data = meta_lookup_cache_new ();
+ *extra_data_free = (GDestroyNotify)meta_lookup_cache_free;
+ }
+ cache = (MetaLookupCache *)*extra_data;
+
+ tree = meta_lookup_cache_lookup_path (cache,
+ filename,
+ device,
+ FALSE,
+ &tree_path);
+
+ if (tree)
+ {
+ meta_tree_enumerate_keys (tree, tree_path,
+ enumerate_keys_callback, info);
+ meta_tree_unref (tree);
+ g_free (tree_path);
+ }
+}
+
+static void
+g_daemon_vfs_add_writable_namespaces (GVfs *vfs,
+ GFileAttributeInfoList *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);
+}
+
+static void
+send_message_oneway (DBusMessage *message)
+{
+ DBusConnection *connection;
+
+ connection = _g_dbus_connection_get_sync (NULL, NULL);
+ if (connection == NULL)
+ return;
+
+ dbus_connection_send (connection, message, NULL);
+ dbus_connection_flush (connection);
+}
+
+static gboolean
+send_message (DBusMessage *message,
+ GCancellable *cancellable,
+ GError **error)
+{
+ DBusConnection *connection;
+ DBusError derror;
+ DBusMessage *reply;
+
+ connection = _g_dbus_connection_get_sync (NULL, NULL);
+ if (connection == NULL)
+ {
+ g_set_error (error, G_IO_ERROR,
+ G_IO_ERROR_FAILED,
+ _("Error setting file metadata: %s"),
+ _("Can't contact session bus"));
+ return FALSE;
+ }
+
+ dbus_error_init (&derror);
+ /* TODO: Handle cancellable */
+ reply = dbus_connection_send_with_reply_and_block (connection, message,
+ G_VFS_DBUS_TIMEOUT_MSECS,
+ &derror);
+ if (!reply)
+ {
+ _g_error_from_dbus (&derror, error);
+ dbus_error_free (&derror);
+ return FALSE;
+ }
+
+ dbus_message_unref (reply);
+
+ return TRUE;
+}
+
+static gboolean
+g_daemon_vfs_local_file_set_attributes (GVfs *vfs,
+ const char *filename,
+ GFileInfo *info,
+ GFileQueryInfoFlags flags,
+ GCancellable *cancellable,
+ GError **error)
+{
+ GFileAttributeType type;
+ MetaLookupCache *cache;
+ const char *metatreefile;
+ struct stat statbuf;
+ char **attributes;
+ char *tree_path;
+ char *key;
+ MetaTree *tree;
+ int errsv;
+ int i;
+ DBusMessage *message;
+ gboolean res;
+
+ res = TRUE;
+ if (g_file_info_has_namespace (info, "metadata"))
+ {
+ attributes = g_file_info_list_attributes (info, "metadata");
+
+ if (g_lstat (filename, &statbuf) != 0)
+ {
+ errsv = errno;
+ g_set_error (error, G_IO_ERROR,
+ g_io_error_from_errno (errsv),
+ _("Error setting file metadata: %s"),
+ g_strerror (errsv));
+ error = NULL; /* Don't set further errors */
+
+ for (i = 0; attributes[i] != NULL; i++)
+ g_file_info_set_attribute_status (info, attributes[i],
+ G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
+
+ res = FALSE;
+ }
+ else
+ {
+ cache = meta_lookup_cache_new ();
+ tree = meta_lookup_cache_lookup_path (cache,
+ filename,
+ statbuf.st_dev,
+ FALSE,
+ &tree_path);
+ 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, &tree_path,
+ 0);
+ meta_lookup_cache_free (cache);
+ meta_tree_unref (tree);
+ g_free (tree_path);
+
+ 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)
+ {
+ const char *val = g_file_info_get_attribute_string (info, attributes[i]);
+ _g_dbus_message_append_args (message,
+ DBUS_TYPE_STRING, &key,
+ DBUS_TYPE_STRING, &val,
+ 0);
+ g_file_info_set_attribute_status (info, attributes[i],
+ G_FILE_ATTRIBUTE_STATUS_SET);
+ }
+ else if (type == G_FILE_ATTRIBUTE_TYPE_STRINGV)
+ {
+ char **val = g_file_info_get_attribute_stringv (info, attributes[i]);
+ _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
+ {
+ 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);
+ }
+ }
+
+ if (!send_message (message,
+ cancellable, error))
+ {
+ res = FALSE;
+ error = NULL; /* Don't set further errors */
+ for (i = 0; attributes[i] != NULL; i++)
+ g_file_info_set_attribute_status (info, attributes[i],
+ G_FILE_ATTRIBUTE_STATUS_ERROR_SETTING);
+ }
+
+ dbus_message_unref (message);
+ }
+
+ g_strfreev (attributes);
+ }
+
+ return res;
+}
+
+static void
+g_daemon_vfs_local_file_removed (GVfs *vfs,
+ const char *filename)
+{
+ MetaLookupCache *cache;
+ DBusMessage *message;
+ const char *metatreefile;
+ MetaTree *tree;
+ char *tree_path;
+
+ cache = meta_lookup_cache_new ();
+ tree = meta_lookup_cache_lookup_path (cache,
+ filename,
+ 0,
+ FALSE,
+ &tree_path);
+ if (tree)
+ {
+ 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_REMOVE);
+ 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, &tree_path,
+ 0);
+ send_message_oneway (message);
+ dbus_message_unref (message);
+ meta_tree_unref (tree);
+ g_free (tree_path);
+ }
+
+ meta_lookup_cache_free (cache);
+}
+
+static void
+g_daemon_vfs_local_file_moved (GVfs *vfs,
+ const char *source,
+ const char *dest)
+{
+ MetaLookupCache *cache;
+ DBusMessage *message;
+ const char *metatreefile;
+ MetaTree *tree1, *tree2;
+ char *tree_path1, *tree_path2;
+
+ cache = meta_lookup_cache_new ();
+ tree1 = meta_lookup_cache_lookup_path (cache,
+ source,
+ 0,
+ FALSE,
+ &tree_path1);
+ tree2 = meta_lookup_cache_lookup_path (cache,
+ dest,
+ 0,
+ FALSE,
+ &tree_path2);
+ if (tree1 && tree2 && tree1 == tree2)
+ {
+ 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_MOVE);
+ g_assert (message != NULL);
+ metatreefile = meta_tree_get_filename (tree1);
+ _g_dbus_message_append_args (message,
+ G_DBUS_TYPE_CSTRING, &metatreefile,
+ G_DBUS_TYPE_CSTRING, &tree_path1,
+ G_DBUS_TYPE_CSTRING, &tree_path2,
+ 0);
+ send_message_oneway (message);
+ dbus_message_unref (message);
+ }
+
+ if (tree1)
+ {
+ meta_tree_unref (tree1);
+ g_free (tree_path1);
+ }
+
+ if (tree2)
+ {
+ meta_tree_unref (tree2);
+ g_free (tree_path2);
+ }
+
+ meta_lookup_cache_free (cache);
+}
+
DBusConnection *
_g_daemon_vfs_get_async_bus (void)
{
@@ -1089,11 +1438,11 @@ g_daemon_vfs_class_init (GDaemonVfsClass *class)
{
GObjectClass *object_class;
GVfsClass *vfs_class;
-
+
object_class = (GObjectClass *) class;
g_daemon_vfs_parent_class = g_type_class_peek_parent (class);
-
+
object_class->finalize = g_daemon_vfs_finalize;
vfs_class = G_VFS_CLASS (class);
@@ -1103,6 +1452,11 @@ g_daemon_vfs_class_init (GDaemonVfsClass *class)
vfs_class->get_file_for_uri = g_daemon_vfs_get_file_for_uri;
vfs_class->get_supported_uri_schemes = g_daemon_vfs_get_supported_uri_schemes;
vfs_class->parse_name = g_daemon_vfs_parse_name;
+ vfs_class->local_file_add_info = g_daemon_vfs_local_file_add_info;
+ vfs_class->add_writable_namespaces = g_daemon_vfs_add_writable_namespaces;
+ vfs_class->local_file_set_attributes = g_daemon_vfs_local_file_set_attributes;
+ vfs_class->local_file_removed = g_daemon_vfs_local_file_removed;
+ vfs_class->local_file_moved = g_daemon_vfs_local_file_moved;
}
/* Module API */
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]