summaryrefslogtreecommitdiff
path: root/metadata/metatree.c
diff options
context:
space:
mode:
Diffstat (limited to 'metadata/metatree.c')
-rw-r--r--metadata/metatree.c128
1 files changed, 121 insertions, 7 deletions
diff --git a/metadata/metatree.c b/metadata/metatree.c
index 04993e6f..e6fa62b1 100644
--- a/metadata/metatree.c
+++ b/metadata/metatree.c
@@ -1049,6 +1049,28 @@ meta_journal_entry_new_setv (guint64 mtime,
}
static GString *
+meta_journal_entry_new_remove (guint64 mtime,
+ const char *path)
+{
+ GString *out;
+
+ out = meta_journal_entry_init (JOURNAL_OP_REMOVE_PATH, mtime, path);
+ return meta_journal_entry_finish (out);
+}
+
+static GString *
+meta_journal_entry_new_copy (guint64 mtime,
+ const char *src,
+ const char *dst)
+{
+ GString *out;
+
+ out = meta_journal_entry_init (JOURNAL_OP_COPY_PATH, mtime, dst);
+ append_string (out, src);
+ return meta_journal_entry_finish (out);
+}
+
+static GString *
meta_journal_entry_new_unset (guint64 mtime,
const char *path,
const char *key)
@@ -2446,6 +2468,83 @@ meta_tree_set_stringv (MetaTree *tree,
return res;
}
+gboolean
+meta_tree_remove (MetaTree *tree,
+ const char *path)
+{
+ GString *entry;
+ guint64 mtime;
+ gboolean res;
+
+ g_static_rw_lock_writer_lock (&metatree_lock);
+
+ if (tree->journal == NULL ||
+ !tree->journal->journal_valid)
+ {
+ res = FALSE;
+ goto out;
+ }
+
+ mtime = time (NULL);
+
+ entry = meta_journal_entry_new_remove (mtime, path);
+
+ res = TRUE;
+ retry:
+ if (!meta_journal_add_entry (tree->journal, entry))
+ {
+ if (meta_tree_flush_locked (tree))
+ goto retry;
+
+ res = FALSE;
+ }
+
+ g_string_free (entry, TRUE);
+
+ out:
+ g_static_rw_lock_writer_unlock (&metatree_lock);
+ return res;
+}
+
+gboolean
+meta_tree_copy (MetaTree *tree,
+ const char *src,
+ const char *dest)
+{
+ GString *entry;
+ guint64 mtime;
+ gboolean res;
+
+ g_static_rw_lock_writer_lock (&metatree_lock);
+
+ if (tree->journal == NULL ||
+ !tree->journal->journal_valid)
+ {
+ res = FALSE;
+ goto out;
+ }
+
+ mtime = time (NULL);
+
+ entry = meta_journal_entry_new_copy (mtime, src, dest);
+
+ res = TRUE;
+ retry:
+ if (!meta_journal_add_entry (tree->journal, entry))
+ {
+ if (meta_tree_flush_locked (tree))
+ goto retry;
+
+ res = FALSE;
+ }
+
+ g_string_free (entry, TRUE);
+
+ out:
+ g_static_rw_lock_writer_unlock (&metatree_lock);
+ return res;
+}
+
static char *
canonicalize_filename (const char *filename)
{
@@ -2622,6 +2721,7 @@ follow_symlink_recursively (char **path,
struct _MetaLookupCache {
char *last_parent;
char *last_parent_expanded;
+ dev_t last_parent_dev;
char *last_parent_mountpoint;
char *last_parent_mountpoint_extra_prefix;
@@ -3003,7 +3103,8 @@ find_mountpoint_for (MetaLookupCache *cache,
* Invariant: If path is canonical, so is result.
*/
static char *
-expand_all_symlinks (const char *path)
+expand_all_symlinks (const char *path,
+ dev_t *dev_out)
{
char *parent, *parent_expanded;
char *basename, *res;
@@ -3012,11 +3113,13 @@ expand_all_symlinks (const char *path)
path_copy = g_strdup (path);
follow_symlink_recursively (&path_copy, &dev);
+ if (dev_out)
+ *dev_out = dev;
parent = get_dirname (path_copy);
if (parent)
{
- parent_expanded = expand_all_symlinks (parent);
+ parent_expanded = expand_all_symlinks (parent, NULL);
basename = g_path_get_basename (path_copy);
res = g_build_filename (parent_expanded, basename, NULL);
g_free (parent_expanded);
@@ -3077,23 +3180,29 @@ struct HomedirData {
static char *
expand_parents (MetaLookupCache *cache,
- const char *path)
+ const char *path,
+ dev_t *parent_dev_out)
{
char *parent;
char *basename, *res;
char *path_copy;
+ dev_t parent_dev;
path_copy = canonicalize_filename (path);
parent = get_dirname (path_copy);
if (parent == NULL)
- return path_copy;
+ {
+ *parent_dev_out = 0;
+ 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);
+ cache->last_parent_expanded = expand_all_symlinks (parent, &parent_dev);
+ cache->last_parent_dev = parent_dev;
g_free (cache->last_parent_mountpoint);
cache->last_parent_mountpoint = NULL;
g_free (cache->last_parent_mountpoint_extra_prefix);
@@ -3102,6 +3211,7 @@ expand_parents (MetaLookupCache *cache,
else
g_free (parent);
+ *parent_dev_out = cache->last_parent_dev;
basename = g_path_get_basename (path_copy);
res = g_build_filename (cache->last_parent_expanded, basename, NULL);
g_free (basename);
@@ -3124,6 +3234,7 @@ meta_lookup_cache_lookup_path (MetaLookupCache *cache,
static gsize homedir_datap = 0;
struct HomedirData *homedir_data;
MetaTree *tree;
+ dev_t parent_dev;
if (g_once_init_enter (&homedir_datap))
{
@@ -3133,14 +3244,17 @@ meta_lookup_cache_lookup_path (MetaLookupCache *cache,
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);
+ homedir_data_storage.expanded_path = expand_all_symlinks (e, NULL);
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);
+ expanded = expand_parents (cache, filename, &parent_dev);
+
+ if (device == 0) /* Unknown, use same as parent */
+ device = parent_dev;
if (homedir_data->device == device &&
path_has_prefix (expanded, homedir_data->expanded_path))