[gvfs/metadata: 10/12] Initial work on libudev based tree picking
- From: Alexander Larsson <alexl src gnome org>
- To: svn-commits-list gnome org
- Subject: [gvfs/metadata: 10/12] Initial work on libudev based tree picking
- Date: Thu, 18 Jun 2009 11:38:50 -0400 (EDT)
commit 0cf6c541d82c652499f01b16497228c95f2c6354
Author: Alexander Larsson <alexl redhat com>
Date: Thu Jun 18 15:38:18 2009 +0200
Initial work on libudev based tree picking
configure.ac | 20 ++++
metadata/Makefile.am | 3 +-
metadata/meta-get-tree.c | 2 +-
metadata/metatree.c | 263 ++++++++++++++++++++++++++++++++++++++++++----
metadata/metatree.h | 10 +-
5 files changed, 272 insertions(+), 26 deletions(-)
---
diff --git a/configure.ac b/configure.ac
index 0caf9bd..ab64543 100644
--- a/configure.ac
+++ b/configure.ac
@@ -165,6 +165,26 @@ PKG_CHECK_MODULES(LIBXML, libxml-2.0,
AC_SUBST(LIBXML_CFLAGS)
AC_SUBST(LIBXML_LIBS)
+dnl *************************
+dnl *** Check for libudev ***
+dnl *************************
+AC_ARG_ENABLE(udev, [ --disable-udev build without libudev])
+msg_udev=no
+UDEV_CFLAGS=
+UDEV_LIBS=
+
+if test "x$enable_udev" != "xno"; then
+ PKG_CHECK_EXISTS(libudev >= 138, msg_udev=yes)
+
+ if test "x$msg_udev" = "xyes"; then
+ PKG_CHECK_MODULES(UDEV, libudev)
+ AC_DEFINE(HAVE_LIBUDEV, 1, [Define to 1 if libudev availible])
+ fi
+fi
+
+AC_SUBST(UDEV_CFLAGS)
+AC_SUBST(UDEV_LIBS)
+
dnl **********************
dnl *** Check for FUSE ***
dnl **********************
diff --git a/metadata/Makefile.am b/metadata/Makefile.am
index f38be18..2a2c742 100644
--- a/metadata/Makefile.am
+++ b/metadata/Makefile.am
@@ -18,6 +18,7 @@ noinst_PROGRAMS = $(APPS)
INCLUDES = -I$(top_srcdir) -I$(top_srcdir)/gvfs \
$(LIBXML_CFLAGS) $(GLIB_CFLAGS) $(DBUS_CFLAGS) \
+ $(UDEV_CFLAGS) \
-DG_LOG_DOMAIN=\"GVFS\" -DG_DISABLE_DEPRECATED \
-DDBUS_API_SUBJECT_TO_CHANGE
@@ -27,7 +28,7 @@ libmetadata_la_SOURCES = \
crc32.c crc32.h \
$(NULL)
-libmetadata_la_LIBADD = $(GLIB_LIBS)
+libmetadata_la_LIBADD = $(GLIB_LIBS) $(UDEV_LIBS)
meta_ls_LDADD = libmetadata.la
meta_ls_SOURCES = meta-ls.c
diff --git a/metadata/meta-get-tree.c b/metadata/meta-get-tree.c
index a5b0d92..fdb9513 100644
--- a/metadata/meta-get-tree.c
+++ b/metadata/meta-get-tree.c
@@ -42,7 +42,7 @@ main (int argc,
return 1;
}
- tree = meta_lookup_cache_lookup (cache, argv[i], statbuf.st_dev);
+ tree = meta_lookup_cache_lookup_path (cache, argv[i], statbuf.st_dev);
if (pause)
{
diff --git a/metadata/metatree.c b/metadata/metatree.c
index 744f54e..0b191fd 100644
--- a/metadata/metatree.c
+++ b/metadata/metatree.c
@@ -1,3 +1,4 @@
+#include "config.h"
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h>
@@ -14,6 +15,11 @@
#include <poll.h>
#include "crc32.h"
+#ifdef HAVE_LIBUDEV
+#define LIBUDEV_I_KNOW_THE_API_IS_SUBJECT_TO_CHANGE
+#include <libudev.h>
+#endif
+
#define MAGIC "\xda\x1ameta"
#define MAGIC_LEN 6
#define MAJOR_VERSION 1
@@ -1796,12 +1802,14 @@ split_filename (const char *path, char **basename)
if (strcmp (parent, ".") == 0 ||
strcmp (parent, path_copy) == 0)
{
- *basename = NULL;
+ if (basename)
+ *basename = NULL;
g_free (parent);
g_free (path_copy);
return NULL;
}
- *basename = g_path_get_basename (path_copy);
+ if (basename)
+ *basename = g_path_get_basename (path_copy);
g_free (path_copy);
return parent;
@@ -1845,12 +1853,13 @@ join_path_list (GList *list)
gsize len;
char *str;
- len = 0;
+ len = 2;
for (l = list; l != NULL; l = l->next)
len += strlen (l->data) + 1;
- str = malloc (len);
- *str = 0;
+ str = g_malloc (len);
+ str[0] = '/';
+ str[1] = 0;
for (l = list; l != NULL; l = l->next)
{
@@ -1871,8 +1880,72 @@ typedef struct {
struct _MetaLookupCache {
GList *mountpoint_cache;
+ char *last_parent;
+ char *last_parent_expanded;
+ dev_t last_device;
+ char *last_device_tree;
};
+#ifdef HAVE_LIBUDEV
+
+struct udev *udev;
+G_LOCK_DEFINE_STATIC (udev);
+
+static char *
+get_tree_from_udev (MetaLookupCache *cache,
+ dev_t devnum)
+{
+ struct udev_device *dev;
+ const char *uuid, *label;
+ char *res;
+
+ G_LOCK (udev);
+
+ if (udev == NULL)
+ udev = udev_new ();
+
+ dev = udev_device_new_from_devnum (udev, 'b', devnum);
+ uuid = udev_device_get_property_value (dev, "ID_FS_UUID_ENC");
+
+ res = NULL;
+ if (uuid)
+ {
+ res = g_strconcat ("uuid-", uuid, NULL);
+ }
+ else
+ {
+ label = udev_device_get_property_value (dev, "ID_FS_LABEL_ENC");
+
+ if (label)
+ res = g_strconcat ("label-", label, NULL);
+ }
+
+ udev_device_unref (dev);
+
+ G_UNLOCK (udev);
+
+ return res;
+}
+#endif
+
+static const char *
+get_tree_for_device (MetaLookupCache *cache,
+ dev_t device)
+{
+#ifdef HAVE_LIBUDEV
+ if (device != cache->last_device)
+ {
+ cache->last_device = device;
+ g_free (cache->last_device_tree);
+ cache->last_device_tree = get_tree_from_udev (cache, device);
+ }
+
+ return cache->last_device_tree;
+#endif
+ return NULL;
+}
+
+
#ifdef __linux__
typedef struct {
@@ -2071,7 +2144,7 @@ update_mountinfo (void)
mountinfo_roots = parse_mountinfo (contents);
}
-static const char *
+static char *
find_mountinfo_root_for_mountpoint (const char *mountpoint)
{
char *res;
@@ -2112,6 +2185,7 @@ get_extra_prefix_for_mount (const char *mountpoint)
return NULL;
}
+/* Expands symlinks for parents and look for a mountpoint */
static const char *
find_mountpoint_for (MetaLookupCache *cache,
const char *file,
@@ -2135,7 +2209,7 @@ find_mountpoint_for (MetaLookupCache *cache,
basename = NULL;
dir = g_strdup (first_dir);
- last = g_strdup (file);
+ last = strip_trailing_slashes (file);
while (1)
{
expand_all (&dir, &dir_dev);
@@ -2170,6 +2244,35 @@ find_mountpoint_for (MetaLookupCache *cache,
return c->mountpoint;
}
+/* Resolves all symlinks, including the ones for basename */
+static char *
+expand_all_symlinks (const char *path)
+{
+ char *parent, *parent_expanded;
+ char *basename, *res;
+ dev_t dev;
+ char *path_copy;
+
+ path_copy = g_strdup (path);
+ expand_all (&path_copy, &dev);
+
+ parent = split_filename (path_copy, &basename);
+
+ if (parent)
+ {
+ parent_expanded = expand_all_symlinks (parent);
+ res = g_build_filename (parent_expanded, basename, NULL);
+ g_free (parent_expanded);
+ }
+ else
+ res = path_copy;
+
+ g_free (parent);
+ g_free (basename);
+
+ return res;
+}
+
MetaLookupCache *
meta_lookup_cache_new (void)
{
@@ -2183,28 +2286,150 @@ meta_lookup_cache_new (void)
void
meta_lookup_cache_free (MetaLookupCache *cache)
{
+ g_free (cache->last_parent);
+ g_free (cache->last_parent_expanded);
g_free (cache);
}
+static gboolean
+path_has_prefix (const char *path,
+ const char *prefix)
+{
+ int prefix_len;
+
+ if (prefix == NULL)
+ return TRUE;
+
+ prefix_len = strlen (prefix);
+
+ if (strncmp (path, prefix, prefix_len) == 0 &&
+ (prefix_len == 0 || /* empty prefix always matches */
+ prefix[prefix_len - 1] == '/' || /* last char in prefix was a /, so it must be in path too */
+ path[prefix_len] == 0 ||
+ path[prefix_len] == '/'))
+ return TRUE;
+
+ return FALSE;
+}
+
+struct HomedirData {
+ dev_t device;
+ char *expanded_path;
+};
+
+static char *
+expand_parents (MetaLookupCache *cache,
+ const char *path)
+{
+ char *parent;
+ char *basename, *res;
+ char *path_copy;
+
+ path_copy = canonicalize_filename (path);
+ parent = g_path_get_dirname (path_copy);
+ if (strcmp (parent, ".") == 0 ||
+ strcmp (parent, path_copy) == 0)
+ {
+ g_free (parent);
+ return path_copy;
+ }
+
+ if (cache->last_parent == NULL ||
+ strcmp (cache->last_parent, parent) != 0)
+ {
+ g_free (cache->last_parent);
+ cache->last_parent = parent;
+ cache->last_parent_expanded = expand_all_symlinks (parent);
+ }
+ else
+ g_free (parent);
+
+ basename = g_path_get_basename (path_copy);
+ res = g_build_filename (cache->last_parent_expanded, basename, NULL);
+ g_free (basename);
+
+ return res;
+}
MetaTree *
-meta_lookup_cache_lookup (MetaLookupCache *cache,
- const char *filename,
- guint64 device)
+meta_lookup_cache_lookup_path (MetaLookupCache *cache,
+ const char *filename,
+ guint64 device)
{
const char *mountpoint;
+ const char *treename;
char *prefix;
+ char *expanded;
+ static struct HomedirData homedir_data_storage;
+ static gsize homedir_datap = 0;
+ struct HomedirData *homedir_data;
+ char *extra_prefix;
+
+ if (g_once_init_enter (&homedir_datap))
+ {
+ char *e;
+ struct stat statbuf;
+
+ g_stat (g_get_home_dir(), &statbuf);
+ homedir_data_storage.device = statbuf.st_dev;
+ e = canonicalize_filename (g_get_home_dir());
+ homedir_data_storage.expanded_path = expand_all_symlinks (e);
+ g_free (e);
+ g_once_init_leave (&homedir_datap, (gsize)&homedir_data_storage);
+ }
+ homedir_data = (struct HomedirData *)homedir_datap;
+
+ /* Canonicalized form with all symlinks expanded in parents */
+ expanded = expand_parents (cache, filename);
+
+ if (homedir_data->device == device &&
+ path_has_prefix (expanded, homedir_data->expanded_path))
+ {
+ treename = "home";
+ prefix = expanded + strlen (homedir_data->expanded_path);
+ if (*prefix == 0)
+ prefix = g_strdup ("/");
+ else
+ prefix = g_strdup (prefix);
+ goto found;
+ }
+
+ treename = get_tree_for_device (cache, device);
- mountpoint = find_mountpoint_for (cache,
- filename,
- device,
- &prefix);
+ if (treename)
+ {
+ mountpoint = find_mountpoint_for (cache,
+ filename,
+ device,
+ &prefix);
+
+ if (mountpoint == NULL ||
+ strcmp (mountpoint, "/") == 0)
+ {
+ /* Fall back to root */
+ g_free (prefix);
+ treename = NULL;
+ }
+ else
+ {
+ extra_prefix = get_extra_prefix_for_mount (mountpoint);
+ if (extra_prefix)
+ {
+ char *t = prefix;
+ prefix = g_build_filename (extra_prefix, prefix, NULL);
+ g_free (t);
+ }
+ }
+ }
+
+ if (!treename)
+ {
+ treename = "root";
+ prefix = g_strdup (expanded);
+ }
- /* TODO: more work */
- g_print ("mountpoint: %s, prefix: %s\n",
- mountpoint, prefix);
- g_print ("extra prefix: %s\n",
- get_extra_prefix_for_mount (mountpoint));
+ found:
+ g_print ("Found tree %s:%s\n", treename, prefix);
return NULL;
}
diff --git a/metadata/metatree.h b/metadata/metatree.h
index 84ac852..424f0e9 100644
--- a/metadata/metatree.h
+++ b/metadata/metatree.h
@@ -20,11 +20,11 @@ typedef gboolean (*meta_tree_keys_enumerate_callback) (const char *key,
gpointer value,
gpointer user_data);
-MetaLookupCache *meta_lookup_cache_new (void);
-void meta_lookup_cache_free (MetaLookupCache *cache);
-MetaTree *meta_lookup_cache_lookup (MetaLookupCache *cache,
- const char *filename,
- guint64 device);
+MetaLookupCache *meta_lookup_cache_new (void);
+void meta_lookup_cache_free (MetaLookupCache *cache);
+MetaTree *meta_lookup_cache_lookup_path (MetaLookupCache *cache,
+ const char *filename,
+ guint64 device);
void meta_tree_free (MetaTree *tree);
MetaTree *meta_tree_open (const char *filename,
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]