]> git.ipfire.org Git - thirdparty/FORT-validator.git/commitdiff
Tuesday
authorAlberto Leiva Popper <ydahhrk@gmail.com>
Tue, 23 Jul 2024 22:52:20 +0000 (16:52 -0600)
committerAlberto Leiva Popper <ydahhrk@gmail.com>
Tue, 23 Jul 2024 23:52:38 +0000 (17:52 -0600)
15 files changed:
src/cache/cachent.c
src/cache/cachent.h
src/cache/local_cache.c
src/config.c
src/config.h
src/print_file.c
src/rrdp.c
src/rsync/rsync.c
src/rsync/rsync.h
src/types/url.c
test/cache/cachent_test.c
test/cache/local_cache_test.c
test/cache/util.c
test/cache/util.h
test/types/url_test.c

index 190414e9a158e52a44f7df5b763cce4d3bcec9c1..7e12272493c753037796156bb0e3506df4251f95 100644 (file)
@@ -7,76 +7,57 @@
 #include "types/url.h"
 
 struct cache_node *
-cachent_create_root(char const *schema)
+cachent_create_root(bool https)
 {
        struct cache_node *root;
 
        root = pzalloc(sizeof(struct cache_node));
-       root->url = pstrdup(schema);
-       root->name = root->url;
+       root->url = pstrdup(https ? "https://" : "rsync://");
+       root->path = join_paths(config_get_local_repository(),
+          https ? "https" : "rsync");
+       root->name = strrchr(root->path, '/') + 1;
 
        return root;
 }
 
 /* Preorder. @cb returns whether the children should be traversed. */
 int
-cachent_traverse(struct cache_node *root,
-    bool (*cb)(struct cache_node *, char const *))
+cachent_traverse(struct cache_node *root, bool (*cb)(struct cache_node *))
 {
        struct cache_node *iter_start;
        struct cache_node *parent, *child;
        struct cache_node *tmp;
-       struct path_builder pb;
        int error;
 
        if (!root)
                return 0;
 
-       pb_init(&pb);
-
-       error = pb_append(&pb, config_get_local_repository());
-       if (error)
-               goto end;
-
-       error = pb_append(&pb, root->name);
-       if (error)
-               goto end;
-       if (!cb(root, pb.string))
-               goto end;
+       if (!cb(root))
+               return error;
 
        parent = root;
        iter_start = parent->children;
        if (iter_start == NULL)
-               goto end;
+               return error;
 
 reloop:        /* iter_start must not be NULL */
        HASH_ITER(hh, iter_start, child, tmp) {
-               error = pb_append(&pb, child->name);
-               if (error)
-                       goto end;
-
-               if (cb(child, pb.string) && (child->children != NULL)) {
+               if (cb(child) && (child->children != NULL)) {
                        parent = child;
                        iter_start = parent->children;
                        goto reloop;
                }
-
-               pb_pop(&pb, true);
        }
 
        parent = iter_start->parent;
        do {
                if (parent == NULL)
-                       goto end;
-               pb_pop(&pb, true);
+                       return error;
                iter_start = parent->hh.next;
                parent = parent->parent;
        } while (iter_start == NULL);
 
        goto reloop;
-
-end:   pb_cleanup(&pb);
-       return error;
 }
 
 static struct cache_node *
@@ -124,6 +105,7 @@ provide(struct cache_node *parent, char const *url,
     char const *name, size_t namelen)
 {
        struct cache_node *child;
+       size_t pathlen;
 
        child = find_child(parent, name, namelen);
        if (child != NULL)
@@ -131,6 +113,12 @@ provide(struct cache_node *parent, char const *url,
 
        child = pzalloc(sizeof(struct cache_node));
        child->url = pstrndup(url, name - url + namelen);
+
+       pathlen = strlen(parent->path) + namelen + 2;
+       child->path = pmalloc(pathlen);
+       if (snprintf(child->path, pathlen, "%s/%.*s", parent->path, (int)namelen, name) >= pathlen)
+               pr_crit("aaaaaa"); // XXX
+
        child->name = child->url + (name - url);
        if ((parent->flags & RSYNC_INHERIT) == RSYNC_INHERIT)
                child->flags = RSYNC_INHERIT;
@@ -168,7 +156,7 @@ cachent_provide(struct cache_node *ancestor, char const *url)
        for (i = 0; ancestor->url[i] != 0; i++)
                if (ancestor->url[i] != normal[i])
                        goto fail;
-       if (normal[i] != '/' && normal[i] != '\0')
+       if (i != RPKI_SCHEMA_LEN && normal[i] != '/' && normal[i] != '\0')
                goto fail;
 
        token_init(&tkn, normal + i);
@@ -185,9 +173,11 @@ fail:      free(normal);
 static void __delete_node_cb(struct cache_node const *);
 #endif
 
-static void
+static int
 __delete_node(struct cache_node *node)
 {
+       int valid = node->flags & CNF_VALID;
+
 #ifdef UNIT_TESTING
        __delete_node_cb(node);
 #endif
@@ -195,17 +185,23 @@ __delete_node(struct cache_node *node)
        if (node->parent != NULL)
                HASH_DEL(node->parent->children, node);
        free(node->url);
-       free(node->tmpdir);
+       free(node->path);
+       free(node->tmppath);
        free(node);
+
+       return valid;
 }
 
-void
+int
 cachent_delete(struct cache_node *node)
 {
        struct cache_node *parent;
+       int valid;
 
        if (!node)
-               return;
+               return 0;
+
+       valid = node->flags & CNF_VALID;
 
        parent = node->parent;
        if (parent != NULL) {
@@ -218,9 +214,11 @@ cachent_delete(struct cache_node *node)
                        node = node->children;
 
                parent = node->parent;
-               __delete_node(node);
+               valid |= __delete_node(node);
                node = parent;
        } while (node != NULL);
+
+       return valid;
 }
 
 static void
@@ -241,7 +239,7 @@ print_node(struct cache_node *node, unsigned int tabs)
        printf("%s", (node->flags & CNF_VALID) ? "valid " : "");
        printf("%s", (node->flags & CNF_NOTIFICATION) ? "notification " : "");
        printf("%s", (node->flags & CNF_WITHDRAWN) ? "withdrawn " : "");
-       printf(" -- %s", node->tmpdir);
+       printf(" -- %s", node->tmppath);
 
        printf("\n");
        HASH_ITER(hh, node->children, child, tmp)
index 94beb66e34ad092068b9a9fb5177827faf84c9c0..26c514e5bb042ad6b892bcd869d3baebfddf1a01 100644 (file)
@@ -31,6 +31,8 @@
  * Did it validate successfully (at least once) during the current cycle?
  * (It's technically possible for two different repositories to map to the same
  * cache node. One of them is likely going to fail validation.)
+ * This only refers to the tmp path; The final path, if it exists, always
+ * contains valid objects (until expiration).
  */
 #define CNF_VALID              (1 << 5)
 /* Is the node an RRDP Update Notification? */
 
 // XXX rename to cache_entity or cachent
 struct cache_node {
-       char const *name;       /* Points to the last component of @url XXX redundant */
-       char *url;              /* Normalized */
-       int flags;
+       char *url;              /* rsync://a.b.c/d/e (normalized) */
+       char *path;             /* path/to/cache/rsync/a.b.c/d/e */
+       char const *name;       /* Points to the last component of @url or @path XXX redundant */
+       int flags;              /* CNF_* */
 
        int dlerr;              /* Result code of recent download attempt */
        time_t mtim;            /* Last successful download time, or zero */
 
        /*
-        * If flags & CNF_FRESH, path to the temporal directory where we
-        * downloaded the latest refresh.
+        * If download attempted, path to the temporal directory where the
+        * refresh was dumped.
         * (See --compare-dest at rsync(1). RRDP is basically the same.)
-        * Otherwise undefined.
-        *
-        * XXX this is not always a directory; rename to "tmppath"
+        * Otherwise NULL.
         */
-       char *tmpdir;
+       char *tmppath;          /* path/to/cache/tmp/1234 */
 
-       /* Only if flags & CNF_NOTIFICATION */
+//     /* Only if flags & CNF_NOTIFICATION */
 //     struct cachefile_notification notif;
 
        struct cache_node *parent;      /* Tree parent */
@@ -73,15 +74,14 @@ struct cache_node {
        UT_hash_handle hh;              /* Hash table hook */
 };
 
-struct cache_node *cachent_create_root(char const *);
+struct cache_node *cachent_create_root(bool);
 
-int cachent_traverse(struct cache_node *,
-    bool (*cb)(struct cache_node *, char const *));
+int cachent_traverse(struct cache_node *, bool (*cb)(struct cache_node *));
 
 struct cache_node *cachent_find(struct cache_node *, char const *,
     struct cache_node **);
 struct cache_node *cachent_provide(struct cache_node *, char const *);
-void cachent_delete(struct cache_node *);
+int cachent_delete(struct cache_node *);
 
 /* Recursive; tests only. */
 void cachent_print(struct cache_node *);
index d64ada599813a2ebdb72a7923df04e1917aaf22e..716d705caa44b612ea0fa7c0c8e3ca26fbe3825c 100644 (file)
@@ -339,8 +339,8 @@ cache_tmpfile(char **filename)
 static void
 load_tal_json(void)
 {
-       cache.rsync = cachent_create_root("rsync");
-       cache.https = cachent_create_root("https");
+       cache.rsync = cachent_create_root(false);
+       cache.https = cachent_create_root(true);
 
 //     char *filename;
 //     json_t *root;
@@ -525,7 +525,7 @@ static int
 dl_rsync(struct cache_node *rpp)
 {
        struct cache_node *module, *node;
-       char *path;
+       char *tmppath;
        int error;
 
        if (!config_get_rsync_enabled()) {
@@ -537,20 +537,20 @@ dl_rsync(struct cache_node *rpp)
        if (module == NULL)
                return -EINVAL; // XXX
 
-       error = cache_tmpfile(&path);
+       error = cache_tmpfile(&tmppath);
        if (error)
                return error;
 
-       // XXX looks like the third argument is redundant now.
-       error = rsync_download(module->url, path, true);
+       error = rsync_download(module->url, tmppath,
+           (module->flags & CNF_CACHED) ? module->path : NULL);
        if (error) {
-               free(path);
+               free(tmppath);
                return error;
        }
 
        module->flags |= CNF_RSYNC | CNF_CACHED | CNF_FRESH;
        module->mtim = time(NULL); // XXX catch -1
-       module->tmpdir = path;
+       module->tmppath = tmppath;
 
        for (node = rpp; node != module; node = node->parent) {
                node->flags |= RSYNC_INHERIT;
@@ -563,7 +563,7 @@ dl_rsync(struct cache_node *rpp)
 static int
 dl_http(struct cache_node *node)
 {
-       char *path;
+       char *tmppath;
        bool changed;
        int error;
 
@@ -572,13 +572,13 @@ dl_http(struct cache_node *node)
                return 1;
        }
 
-       error = cache_tmpfile(&path);
+       error = cache_tmpfile(&tmppath);
        if (error)
                return error;
 
-       error = http_download(node->url, path, node->mtim, &changed);
+       error = http_download(node->url, tmppath, node->mtim, &changed);
        if (error) {
-               free(path);
+               free(tmppath);
                return error;
        }
 
@@ -587,7 +587,7 @@ dl_http(struct cache_node *node)
                node->flags |= CNF_CHANGED;
                node->mtim = time(NULL); // XXX catch -1
        }
-       node->tmpdir = path;
+       node->tmppath = tmppath;
        return 0;
 }
 
@@ -727,7 +727,7 @@ prune_rsync(void)
                HASH_ITER(hh, domain->children, module, tmp2)
                        HASH_ITER(hh, module->children, child, tmp3) {
                                pr_op_debug("Removing leftover: %s", child->url);
-                               cachent_delete(child);
+                               module->flags |= cachent_delete(child);
                        }
 }
 
@@ -736,7 +736,7 @@ prune_rsync(void)
  * XXX result is redundant
  */
 static bool
-commit_rpp_delta(struct cache_node *node, char const *path)
+commit_rpp_delta(struct cache_node *node)
 {
        struct cache_node *child, *tmp;
        int error;
@@ -748,7 +748,7 @@ commit_rpp_delta(struct cache_node *node, char const *path)
                goto branch;
        }
 
-       if (node->tmpdir == NULL) {
+       if (node->tmppath == NULL) {
                if (node->children) {
                        pr_op_debug("Branch.");
                        goto branch;
@@ -760,7 +760,7 @@ commit_rpp_delta(struct cache_node *node, char const *path)
 
        if (node->flags & CNF_VALID) {
                pr_op_debug("Validation successful; committing.");
-               error = file_merge_into(node->tmpdir, path);
+               error = file_merge_into(node->tmppath, node->path);
                if (error)
                        printf("rename errno: %d\n", error); // XXX
                /* XXX Think more about the implications of this. */
@@ -769,17 +769,17 @@ commit_rpp_delta(struct cache_node *node, char const *path)
        } else {
                pr_op_debug("Validation unsuccessful; rollbacking.");
                /* XXX just do remove()? */
-               file_rm_f(node->tmpdir);
+               file_rm_f(node->tmppath);
        }
 
-       free(node->tmpdir);
-       node->tmpdir = NULL;
+       free(node->tmppath);
+       node->tmppath = NULL;
        return true;
 
 branch:        node->flags = 0;
-       if (node->tmpdir) {
-               free(node->tmpdir);
-               node->tmpdir = NULL;
+       if (node->tmppath) {
+               free(node->tmppath);
+               node->tmppath = NULL;
        }
        return true;
 }
@@ -1024,10 +1024,10 @@ remove_abandoned(void)
 }
 
 static bool
-remove_orphaned(struct cache_node *node, char const *path)
+remove_orphaned(struct cache_node *node)
 {
-       if (file_exists(path) == ENOENT) {
-               pr_op_debug("Missing file; deleting node: %s", path);
+       if (file_exists(node->path) == ENOENT) {
+               pr_op_debug("Missing file; deleting node: %s", node->path);
                cachent_delete(node);
                return false;
        }
index eb4d5e2d0bccbf079b65b9680373b3a6550d30c9..700677d68160fffd2102cb0dc108ea0be5c887b0 100644 (file)
@@ -88,10 +88,7 @@ struct rpki_config {
                        unsigned int interval;
                } retry;
                char *program;
-               struct {
-                       struct string_array flat; /* Deprecated */
-                       struct string_array recursive;
-               } args;
+               struct string_array args;
        } rsync;
 
        struct {
@@ -489,20 +486,17 @@ static const struct option_field options[] = {
                .id = 3006,
                .name = "rsync.arguments-recursive",
                .type = &gt_string_array,
-               .offset = offsetof(struct rpki_config, rsync.args.recursive),
-               .doc = "RSYNC program arguments",
+               .offset = offsetof(struct rpki_config, rsync.args),
+               .doc = "Deprecated; does nothing.",
                .availability = AVAILABILITY_JSON,
-               /* Unlimited */
-               .max = 0,
+               .deprecated = true,
        }, {
                .id = 3007,
                .name = "rsync.arguments-flat",
                .type = &gt_string_array,
-               .offset = offsetof(struct rpki_config, rsync.args.flat),
+               .offset = offsetof(struct rpki_config, rsync.args),
                .doc = "Deprecated; does nothing.",
                .availability = AVAILABILITY_JSON,
-               /* Unlimited */
-               .max = 0,
                .deprecated = true,
        },
 
@@ -929,18 +923,7 @@ print_config(void)
 static void
 set_default_values(void)
 {
-       static char const *recursive_rsync_args[] = {
-               "-rtz", "--delete", "--omit-dir-times",
-
-               "--contimeout=20", "--max-size=20MB", "--timeout=15",
-
-               "--include=*/", "--include=*.cer", "--include=*.crl",
-               "--include=*.gbr", "--include=*.mft", "--include=*.roa",
-               "--exclude=*",
-
-               "$REMOTE", "$LOCAL",
-       };
-       static char const *flat_rsync_args[] = { "<deprecated>" };
+       static char const *trash[] = { "<deprecated>" };
        static char const *addrs[] = {
 #ifdef __linux__
                "::"
@@ -978,10 +961,7 @@ set_default_values(void)
        rpki_config.rsync.retry.count = 1;
        rpki_config.rsync.retry.interval = 4;
        rpki_config.rsync.program = pstrdup("rsync");
-       string_array_init(&rpki_config.rsync.args.flat,
-           flat_rsync_args, ARRAY_LEN(flat_rsync_args));
-       string_array_init(&rpki_config.rsync.args.recursive,
-           recursive_rsync_args, ARRAY_LEN(recursive_rsync_args));
+       string_array_init(&rpki_config.rsync.args, trash, ARRAY_LEN(trash));
 
        rpki_config.http.enabled = true;
        /* Higher priority than rsync by default */
@@ -1382,12 +1362,6 @@ config_get_rsync_program(void)
        return rpki_config.rsync.program;
 }
 
-struct string_array const *
-config_get_rsync_args(void)
-{
-       return &rpki_config.rsync.args.recursive;
-}
-
 bool
 config_get_http_enabled(void)
 {
index 6f14fc40bce600dc7e64467628dc4483f24b6695..719bf54146f336ef9c81a33b499ad8e2c5c256d6 100644 (file)
@@ -48,7 +48,6 @@ unsigned int config_get_rsync_priority(void);
 unsigned int config_get_rsync_retry_count(void);
 unsigned int config_get_rsync_retry_interval(void);
 char *config_get_rsync_program(void);
-struct string_array const *config_get_rsync_args(void);
 bool config_get_http_enabled(void);
 unsigned int config_get_http_priority(void);
 unsigned int config_get_http_retry_count(void);
index 8e8e6e0a4f4ab7e827b4f2e2731dc785a65e43c1..3a80a158f12a9872ff91f6f3bc730d26b672ad83 100644 (file)
@@ -21,7 +21,8 @@ __rsync2bio(char const *src, char const *dst)
 {
        int error;
 
-       error = rsync_download(src, dst, false);
+       // XXX use the cache
+       error = rsync_download(src, dst, NULL);
        if (error) {
                pr_op_err("rysnc download failed: %s", strerror(abs(error)));
                return NULL;
index 2dc024cef87fd066cf5436158669dce747e7d200..3983176c0771e23e4a2fda973adc924e2a814167 100644 (file)
@@ -13,7 +13,7 @@
 #include "log.h"
 #include "thread_var.h"
 #include "http/http.h"
-#include "cache/cache_entity.h"
+#include "cache/cachent.h"
 #include "crypto/base64.h"
 #include "crypto/hash.h"
 #include "xml/relax_ng.h"
@@ -768,13 +768,13 @@ xml_read_notif(xmlTextReaderPtr reader, void *arg)
 }
 
 static int
-parse_notification(struct cache_node *node, struct update_notification *result)
+parse_notification(struct cache_node *notif, struct update_notification *result)
 {
        int error;
 
-       update_notification_init(result, node->url);
+       update_notification_init(result, notif->url);
 
-       error = relax_ng_parse(node->tmpdir, xml_read_notif, result);
+       error = relax_ng_parse(notif->tmppath, xml_read_notif, result);
        if (error)
                update_notification_cleanup(result);
 
@@ -1086,6 +1086,34 @@ update_notif(struct cachefile_notification *old, struct update_notification *new
        return 0;
 }
 
+static int
+dl_notif(struct cache_node *notif)
+{
+       char *tmppath;
+       bool changed;
+       int error;
+
+       error = cache_tmpfile(&tmppath);
+       if (error)
+               return error;
+
+       error = http_download(notif->url, tmppath, notif->mtim, &changed);
+       if (error) {
+               free(tmppath);
+               return error;
+       }
+
+       // XXX notif->flags |= CNF_CACHED | CNF_FRESH;
+       if (changed) {
+               notif->mtim = time(NULL); // XXX
+               notif->tmppath = tmppath;
+       } else {
+               free(tmppath);
+       }
+
+       return 0;
+}
+
 /*
  * Downloads the Update Notification @notif, and updates the cache accordingly.
  *
@@ -1095,7 +1123,6 @@ update_notif(struct cachefile_notification *old, struct update_notification *new
 int
 rrdp_update(struct cache_node *notif)
 {
-       char *path = NULL;
        struct cachefile_notification *old;
        struct update_notification new;
        int serial_cmp;
@@ -1104,25 +1131,37 @@ rrdp_update(struct cache_node *notif)
        fnstack_push(notif->url);
        pr_val_debug("Processing notification.");
 
-       error = http_download_cache_node(notif);
+       ///////////////////////////////////////////////////////////////////////
+
+       error = dl_notif(notif);
        if (error)
                goto end;
 
-       if (!(notif->flags & CNF_CHANGED)) {
+       if (!notif->tmppath) {
                pr_val_debug("The Notification has not changed.");
-               rpp->flags |= CNF_FRESH; /* Success */
                goto end;
        }
 
        error = parse_notification(notif, &new);
        if (error)
                goto end;
+
+       remove(notif->tmppath); // XXX
+       if (mkdir(notif->tmppath) == -1) {
+               error = errno;
+               pr_val_err("Can't create notification's temporal directory: %s",
+                   strerror(error));
+               goto clean_notif;
+       }
+
+       ///////////////////////////////////////////////////////////////////////
+
        pr_val_debug("New session/serial: %s/%s", new.session.session_id,
            new.session.serial.str);
 
        if (!(notif->flags & CNF_NOTIFICATION)) {
                pr_val_debug("This is a new Notification.");
-               error = handle_snapshot(&new, rpp);
+               error = handle_snapshot(&new, notif);
                if (error)
                        goto clean_notif;
 
@@ -1178,7 +1217,6 @@ clean_notif:
        update_notification_cleanup(&new);
 
 end:
-       free(path);
        fnstack_pop();
        return error;
 }
index 7359664b813cb8a2a99fbea8bc323a0126c3ca07..1b94076a48a5bede48fb933a9f71e305853e94ba 100644 (file)
@@ -32,48 +32,34 @@ duplicate_fds(int fds[2][2])
 }
 
 static void
-release_args(char **args, unsigned int size)
+prepare_rsync(char *args, char const *src, char const *dst, char const *cmpdst)
 {
-       unsigned int i;
-
-       /* args[0] wasn't allocated */
-       for (i = 1; i < size + 1; i++)
-               free(args[i]);
-       free(args);
-}
-
-static void
-prepare_rsync(char const *src, char const *dst, char ***args, size_t *args_len)
-{
-       struct string_array const *config_args;
-       char **copy_args;
-       unsigned int i;
-
-       config_args = config_get_rsync_args();
-       /*
-        * We need to work on a copy, because the config args are immutable,
-        * and we need to add the program name (for some reason) and NULL
-        * elements, and replace $REMOTE and $LOCAL.
-        */
-       copy_args = pcalloc(config_args->length + 2, sizeof(char *));
-
-       copy_args[0] = config_get_rsync_program();
-       copy_args[config_args->length + 1] = NULL;
-
-       memcpy(copy_args + 1, config_args->array,
-           config_args->length * sizeof(char *));
-
-       for (i = 0; i < config_args->length; i++) {
-               if (strcmp(config_args->array[i], "$REMOTE") == 0)
-                       copy_args[i + 1] = pstrdup(src);
-               else if (strcmp(config_args->array[i], "$LOCAL") == 0)
-                       copy_args[i + 1] = pstrdup(dst);
-               else
-                       copy_args[i + 1] = pstrdup(config_args->array[i]);
+       size_t i = 0;
+
+       /* XXX review */
+       args[i++] = config_get_rsync_program();
+       args[i++] = "-rtz";
+       args[i++] = "--omit-dir-times";
+       args[i++] = "--contimeout";
+       args[i++] = "20";
+       args[i++] = "--max-size";
+       args[i++] = "20MB";
+       args[i++] = "--timeout";
+       args[i++] = "15";
+       args[i++] = "--include=*/";
+       args[i++] = "--include=*.cer";
+       args[i++] = "--include=*.crl";
+       args[i++] = "--include=*.gbr";
+       args[i++] = "--include=*.mft";
+       args[i++] = "--include=*.roa";
+       args[i++] = "--exclude=*";
+       if (cmpdst) {
+               args[i++] = "--compare-dest";
+               args[i++] = cmpdst;
        }
-
-       *args = copy_args;
-       *args_len = config_args->length;
+       args[i++] = src;
+       args[i++] = dst;
+       args[i++] = NULL;
 }
 
 __dead static void
@@ -202,15 +188,11 @@ read_pipes(int fds[2][2])
        return read_pipe(fds, 1);
 }
 
-/*
- * Downloads @src @dst. @src is supposed to be an rsync URL, and @dst is
- * supposed to be a filesystem path.
- */
+/* rsync [--compare-dest @cmpdst] @src @dst */
 int
-rsync_download(char const *src, char const *dst, bool is_directory)
+rsync_download(char const *src, char const *dst, char const *cmpdst)
 {
-       char **args;
-       size_t args_len;
+       char *args[32];
        /* Descriptors to pipe stderr (first element) and stdout (second) */
        int fork_fds[2][2];
        pid_t child_pid;
@@ -220,20 +202,18 @@ rsync_download(char const *src, char const *dst, bool is_directory)
        int error;
 
        /* Prepare everything for the child exec */
-       args = NULL;
-       args_len = 0;
-       prepare_rsync(src, dst, &args, &args_len);
+       prepare_rsync(&args, src, dst, cmpdst);
 
        pr_val_info("rsync: %s", src);
        if (log_val_enabled(LOG_DEBUG)) {
                pr_val_debug("Executing rsync:");
-               for (i = 0; i < args_len + 1; i++)
+               for (i = 0; args[i] != NULL; i++)
                        pr_val_debug("    %s", args[i]);
        }
 
-       error = mkdir_p(dst, is_directory, 0777);
+       error = mkdir_p(dst, true, 0777);
        if (error)
-               goto release_args;
+               return error;
 
        retries = 0;
        do {
@@ -241,7 +221,7 @@ rsync_download(char const *src, char const *dst, bool is_directory)
 
                error = create_pipes(fork_fds);
                if (error)
-                       goto release_args;
+                       return error;
 
                /* Flush output (avoid locks between father and child) */
                log_flush();
@@ -270,7 +250,7 @@ rsync_download(char const *src, char const *dst, bool is_directory)
                        close(fork_fds[1][0]);
                        close(fork_fds[0][1]);
                        close(fork_fds[1][1]);
-                       goto release_args;
+                       return error;
                }
 
                /* This code is run by us. */
@@ -286,7 +266,7 @@ rsync_download(char const *src, char const *dst, bool is_directory)
                                    error, strerror(error));
                                if (child_status > 0)
                                        break;
-                               goto release_args;
+                               return error;
                        }
                } while (0);
 
@@ -296,14 +276,13 @@ rsync_download(char const *src, char const *dst, bool is_directory)
                        pr_val_debug("The rsync sub-process terminated with error code %d.",
                            error);
                        if (!error)
-                               goto release_args;
+                               return 0;
 
                        if (retries == config_get_rsync_retry_count()) {
                                if (retries > 0)
                                        pr_val_warn("Max RSYNC retries (%u) reached on '%s', won't retry again.",
                                            retries, src);
-                               error = EIO;
-                               goto release_args;
+                               return EIO;
                        }
                        pr_val_warn("Retrying RSYNC '%s' in %u seconds, %u attempts remaining.",
                            src,
@@ -316,8 +295,6 @@ rsync_download(char const *src, char const *dst, bool is_directory)
                break;
        } while (true);
 
-       release_args(args, args_len);
-
        if (WIFSIGNALED(child_status)) {
                switch (WTERMSIG(child_status)) {
                case SIGINT:
@@ -339,8 +316,4 @@ rsync_download(char const *src, char const *dst, bool is_directory)
 
        pr_op_err_st("The RSYNC command died in a way I don't have a handler for. Dunno; guess I'll die as well.");
        return -EINVAL;
-release_args:
-       /* The happy path also falls here */
-       release_args(args, args_len);
-       return error;
 }
index 3476c9c0de6c97c705fedd224e1fb626e9b14bd3..52781eed35e3a6ac00a31affa9dbdeb8672d6a51 100644 (file)
@@ -1,8 +1,6 @@
 #ifndef SRC_RSYNC_RSYNC_H_
 #define SRC_RSYNC_RSYNC_H_
 
-#include <stdbool.h>
-
-int rsync_download(char const *, char const *, bool);
+int rsync_download(char const *, char const *, char const *);
 
 #endif /* SRC_RSYNC_RSYNC_H_ */
index a8bab970fa6c57f891256aa7b3b5c1c154ce2e11..6d89f8b6332904ebd518adcbd63173fb687c0a18 100644 (file)
@@ -13,14 +13,14 @@ path_rewind(char const *root, char *cursor)
 }
 
 /*
- * Collapses '//', '.' and '..'. Also removes the colon from the schema.
+ * Collapses '//' (except from the schema), '.' and '..'.
  *
- * "rsync://a.b/./c//.././/d/." -> "rsync/a.b/d"
+ * "rsync://a.b/./c//.././/d/." -> "rsync://a.b/d"
  */
 char *
 url_normalize(char const *url)
 {
-       char *normal, *dst, *root;
+       char *normal, *dst;
        struct tokenizer tkn;
 
        if (strncmp(url, "rsync://", RPKI_SCHEMA_LEN) &&
@@ -28,16 +28,14 @@ url_normalize(char const *url)
                return NULL;
 
        normal = pstrdup(url);
-       root = normal + 5;
-       *root = '/';
-       dst = root + 1;
+       dst = normal + RPKI_SCHEMA_LEN;
        token_init(&tkn, url + RPKI_SCHEMA_LEN);
 
        while (token_next(&tkn)) {
                if (tkn.len == 1 && tkn.str[0] == '.')
                        continue;
                if (tkn.len == 2 && tkn.str[0] == '.' && tkn.str[1] == '.') {
-                       dst = path_rewind(root, dst);
+                       dst = path_rewind(normal + RPKI_SCHEMA_LEN, dst);
                        if (!dst)
                                goto fail;
                        continue;
@@ -48,7 +46,7 @@ url_normalize(char const *url)
        }
 
        /* Reject URL if there's nothing after the schema. Maybe unnecessary. */
-       if (dst == root + 1)
+       if (dst == normal + RPKI_SCHEMA_LEN)
                goto fail;
 
        dst[-1] = '\0';
index 16fa632a04d3995d0abbb80c3918e8417a16139f..9f4c9d49d8cba4ace0a6dd8002c11b2f3be6e873 100644 (file)
@@ -7,7 +7,7 @@
 #include "mock.c"
 #include "types/url.c"
 
-static char deleted[16][5];
+static char deleted[16][6];
 static unsigned int dn;
 
 static void
@@ -20,14 +20,14 @@ START_TEST(test_delete)
 {
        struct cache_node *root, *a, *b;
 
-       a = unode("a", NULL);
+       a = runode("a", NULL);
        dn = 0;
        cachent_delete(a);
        ck_assert_uint_eq(1, dn);
        ck_assert_str_eq("a", deleted[0]);
 
-       a = unode("a", NULL);
-       root = unode("root", a, NULL);
+       a = runode("a", NULL);
+       root = runode("", a, NULL);
        dn = 0;
        cachent_delete(a);
        ck_assert_ptr_eq(NULL, root->children);
@@ -37,25 +37,25 @@ START_TEST(test_delete)
        dn = 0;
        cachent_delete(root);
        ck_assert_uint_eq(1, dn);
-       ck_assert_str_eq("root", deleted[0]);
-
-       b = unode("b",
-                       unode("c", NULL),
-                       unode("d", NULL),
-                       unode("e", NULL),
-                       unode("f", NULL), NULL);
-       a = unode("a",
+       ck_assert_str_eq("rsync", deleted[0]);
+
+       b = runode("a/b",
+               runode("a/b/c", NULL),
+               runode("a/b/d", NULL),
+               runode("a/b/e", NULL),
+               runode("a/b/f", NULL), NULL);
+       a = runode("a",
                b,
-               unode("g",
-                       unode("h",
-                               unode("i", NULL), NULL),
-                       unode("j",
-                               unode("k", NULL), NULL),
-                       unode("l",
-                               unode("m", NULL), NULL),
-                       unode("n",
-                               unode("o", NULL), NULL), NULL), NULL);
-       root = unode("root", a, NULL);
+               runode("a/g",
+                       runode("a/g/h",
+                               runode("a/g/h/i", NULL), NULL),
+                       runode("a/g/j",
+                               runode("a/g/j/k", NULL), NULL),
+                       runode("a/g/l",
+                               runode("a/g/l/m", NULL), NULL),
+                       runode("a/g/n",
+                               runode("a/g/n/o", NULL), NULL), NULL), NULL);
+       root = runode("", a, NULL);
 
        dn = 0;
        cachent_delete(b);
@@ -83,7 +83,7 @@ START_TEST(test_delete)
        dn = 0;
        cachent_delete(root);
        ck_assert_uint_eq(1, dn);
-       ck_assert_str_eq("root", deleted[0]);
+       ck_assert_str_eq("rsync", deleted[0]);
 }
 END_TEST
 
@@ -91,9 +91,9 @@ static char const *expected[32];
 static unsigned int e;
 
 static bool
-ck_traverse_cb(struct cache_node *node, char const *path)
+ck_traverse_cb(struct cache_node *node)
 {
-       ck_assert_str_eq(expected[e++], path);
+       ck_assert_str_eq(expected[e++], node->path);
        return true;
 }
 
@@ -124,102 +124,102 @@ START_TEST(test_traverse)
        root = NULL;
        ck_traverse(root, NULL);
 
-       root =  unode("a", NULL);
-       ck_traverse(root, "tmp/a", NULL);
+       root =  runode("a", NULL);
+       ck_traverse(root, "tmp/rsync/a", NULL);
 
-       root =  unode("a",
-                       unode("b", NULL), NULL);
-       ck_traverse(root, "tmp/a", "tmp/a/b", NULL);
+       root =  runode("a",
+                       runode("a/b", NULL), NULL);
+       ck_traverse(root, "tmp/rsync/a", "tmp/rsync/a/b", NULL);
 
-       root =  unode("a",
-                       unode("b",
-                               unode("c", NULL), NULL), NULL);
+       root =  runode("a",
+                       runode("a/b",
+                               runode("a/b/c", NULL), NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/b/c", NULL);
-
-       root =  unode("a",
-                       unode("b",
-                               unode("c", NULL),
-                               unode("d", NULL), NULL), NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/b/c", NULL);
+
+       root =  runode("a",
+                       runode("a/b",
+                               runode("a/b/c", NULL),
+                               runode("a/b/d", NULL), NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/b/c",
-               "tmp/a/b/d", NULL);
-
-       root =  unode("a",
-                       unode("b",
-                               unode("c", NULL),
-                               unode("d", NULL), NULL),
-                       unode("e", NULL), NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/b/c",
+               "tmp/rsync/a/b/d", NULL);
+
+       root =  runode("a",
+                       runode("a/b",
+                               runode("a/b/c", NULL),
+                               runode("a/b/d", NULL), NULL),
+                       runode("a/e", NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/b/c",
-               "tmp/a/b/d",
-               "tmp/a/e", NULL);
-
-       root =  unode("a",
-                       unode("b", NULL),
-                       unode("c",
-                               unode("d", NULL),
-                               unode("e", NULL), NULL), NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/b/c",
+               "tmp/rsync/a/b/d",
+               "tmp/rsync/a/e", NULL);
+
+       root =  runode("a",
+                       runode("a/b", NULL),
+                       runode("a/c",
+                               runode("a/c/d", NULL),
+                               runode("a/c/e", NULL), NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/c",
-               "tmp/a/c/d",
-               "tmp/a/c/e", NULL);
-
-       root =  unode("a",
-                       unode("b",
-                               unode("c", NULL),
-                               unode("d", NULL), NULL),
-                       unode("e",
-                               unode("f", NULL),
-                               unode("g", NULL), NULL), NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/c",
+               "tmp/rsync/a/c/d",
+               "tmp/rsync/a/c/e", NULL);
+
+       root =  runode("a",
+                       runode("a/b",
+                               runode("a/b/c", NULL),
+                               runode("a/b/d", NULL), NULL),
+                       runode("a/e",
+                               runode("a/e/f", NULL),
+                               runode("a/e/g", NULL), NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/b/c",
-               "tmp/a/b/d",
-               "tmp/a/e",
-               "tmp/a/e/f",
-               "tmp/a/e/g", NULL);
-
-       root =  unode("a",
-                       unode("b",
-                               unode("c", NULL),
-                               unode("d", NULL),
-                               unode("e", NULL),
-                               unode("f", NULL), NULL),
-                       unode("g",
-                               unode("h",
-                                       unode("i", NULL), NULL),
-                               unode("j",
-                                       unode("k", NULL), NULL),
-                               unode("l",
-                                       unode("m", NULL), NULL),
-                               unode("n",
-                                       unode("o", NULL), NULL), NULL), NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/b/c",
+               "tmp/rsync/a/b/d",
+               "tmp/rsync/a/e",
+               "tmp/rsync/a/e/f",
+               "tmp/rsync/a/e/g", NULL);
+
+       root =  runode("a",
+                       runode("a/b",
+                               runode("a/b/c", NULL),
+                               runode("a/b/d", NULL),
+                               runode("a/b/e", NULL),
+                               runode("a/b/f", NULL), NULL),
+                       runode("a/g",
+                               runode("a/g/h",
+                                       runode("a/g/h/i", NULL), NULL),
+                               runode("a/g/j",
+                                       runode("a/g/j/k", NULL), NULL),
+                               runode("a/g/l",
+                                       runode("a/g/l/m", NULL), NULL),
+                               runode("a/g/n",
+                                       runode("a/g/n/o", NULL), NULL), NULL), NULL);
        ck_traverse(root,
-               "tmp/a",
-               "tmp/a/b",
-               "tmp/a/b/c",
-               "tmp/a/b/d",
-               "tmp/a/b/e",
-               "tmp/a/b/f",
-               "tmp/a/g",
-               "tmp/a/g/h",
-               "tmp/a/g/h/i",
-               "tmp/a/g/j",
-               "tmp/a/g/j/k",
-               "tmp/a/g/l",
-               "tmp/a/g/l/m",
-               "tmp/a/g/n",
-               "tmp/a/g/n/o", NULL);
+               "tmp/rsync/a",
+               "tmp/rsync/a/b",
+               "tmp/rsync/a/b/c",
+               "tmp/rsync/a/b/d",
+               "tmp/rsync/a/b/e",
+               "tmp/rsync/a/b/f",
+               "tmp/rsync/a/g",
+               "tmp/rsync/a/g/h",
+               "tmp/rsync/a/g/h/i",
+               "tmp/rsync/a/g/j",
+               "tmp/rsync/a/g/j/k",
+               "tmp/rsync/a/g/l",
+               "tmp/rsync/a/g/l/m",
+               "tmp/rsync/a/g/n",
+               "tmp/rsync/a/g/n/o", NULL);
 }
 END_TEST
 
@@ -227,26 +227,30 @@ START_TEST(test_provide)
 {
        struct cache_node *rsync, *abc, *d, *e, *f, *g, *h, *ee;
 
-       rsync = cachent_create_root("rsync");
+       rsync = cachent_create_root(false);
        ck_assert_ptr_ne(NULL, rsync);
        ck_assert_ptr_eq(NULL, rsync->parent);
-       ck_assert_str_eq("rsync", rsync->url);
+       ck_assert_str_eq("rsync://", rsync->url);
+       ck_assert_str_eq("tmp/rsync", rsync->path);
        ck_assert_str_eq("rsync", rsync->name);
 
        /* Create branch chain from root */
        e = cachent_provide(rsync, "rsync://a.b.c/d/e");
        ck_assert_ptr_ne(NULL, e);
-       ck_assert_str_eq("rsync/a.b.c/d/e", e->url);
+       ck_assert_str_eq("rsync://a.b.c/d/e", e->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/d/e", e->path);
        ck_assert_str_eq("e", e->name);
 
        d = e->parent;
        ck_assert_ptr_ne(NULL, d);
-       ck_assert_str_eq("rsync/a.b.c/d", d->url);
+       ck_assert_str_eq("rsync://a.b.c/d", d->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/d", d->path);
        ck_assert_str_eq("d", d->name);
 
        abc = d->parent;
        ck_assert_ptr_ne(NULL, abc);
-       ck_assert_str_eq("rsync/a.b.c", abc->url);
+       ck_assert_str_eq("rsync://a.b.c", abc->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c", abc->path);
        ck_assert_str_eq("a.b.c", abc->name);
 
        ck_assert_ptr_eq(rsync, abc->parent);
@@ -267,32 +271,36 @@ START_TEST(test_provide)
        /* Some not normalized noise */
        ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c/d/e////"));
        ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c///d/./e//"));
-       ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a/../z/../a.b.c/d/e/"));
+       ck_assert_ptr_eq(e, cachent_provide(e, "rsync://a.b.c/d/f/../e/"));
 
        /* Create sibling from root */
        f = cachent_provide(rsync, "rsync://a.b.c/f");
        ck_assert_ptr_ne(NULL, f);
        ck_assert_ptr_eq(abc, f->parent);
-       ck_assert_str_eq("rsync/a.b.c/f", f->url);
+       ck_assert_str_eq("rsync://a.b.c/f", f->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/f", f->path);
        ck_assert_str_eq("f", f->name);
 
        /* Create more than one descendant from root */
        h = cachent_provide(rsync, "rsync://a.b.c/f/g/h");
        ck_assert_ptr_ne(NULL, h);
-       ck_assert_str_eq("rsync/a.b.c/f/g/h", h->url);
+       ck_assert_str_eq("rsync://a.b.c/f/g/h", h->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/f/g/h", h->path);
        ck_assert_str_eq("h", h->name);
 
        g = h->parent;
        ck_assert_ptr_ne(NULL, g);
        ck_assert_ptr_eq(f, g->parent);
-       ck_assert_str_eq("rsync/a.b.c/f/g", g->url);
+       ck_assert_str_eq("rsync://a.b.c/f/g", g->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/f/g", g->path);
        ck_assert_str_eq("g", g->name);
 
        /* Try to create a conflict by prefix */
        ee = cachent_provide(rsync, "rsync://a.b.c/d/ee");
        ck_assert_ptr_ne(e, ee);
        ck_assert_ptr_eq(d, ee->parent);
-       ck_assert_str_eq("rsync/a.b.c/d/ee", ee->url);
+       ck_assert_str_eq("rsync://a.b.c/d/ee", ee->url);
+       ck_assert_str_eq("tmp/rsync/a.b.c/d/ee", ee->path);
        ck_assert_str_eq("ee", ee->name);
        ck_assert_ptr_eq(e, cachent_provide(abc, "rsync://a.b.c/d/e"));
        ck_assert_ptr_eq(ee, cachent_provide(abc, "rsync://a.b.c/d/ee"));
index be5371d03568d5b5b55322c499f772e1372df35f..3a9ff4886f802af47ed48afdee04d68936d55a79 100644 (file)
@@ -1,7 +1,4 @@
-/*
- * This test will create some temporal directories on "/tmp".
- * Needs permissions.
- */
+/* This will create some test files in "tmp/". Needs permissions. */
 
 #include <check.h>
 //#include <stdarg.h>
@@ -32,7 +29,7 @@ __delete_node_cb(struct cache_node const *node)
 }
 
 int
-rsync_download(char const *src, char const *dst, bool is_directory)
+rsync_download(char const *src, char const *dst, char const *cmpdir)
 {
        char cmd[64];
 
@@ -167,16 +164,17 @@ run_cleanup(void)
 }
 
 static bool
-ck_path(struct cache_node *node, char const *_)
+ck_path(struct cache_node *node)
 {
        int error;
 
-       if (!node->tmpdir)
+       if (!node->tmppath)
                return true;
 
-       error = file_exists(node->tmpdir);
+       error = file_exists(node->tmppath);
        if (error)
-               ck_abort_msg("Missing file in cache: %s (%s)", node->tmpdir, strerror(error));
+               ck_abort_msg("Missing file in cache: %s (%s)", node->tmppath,
+                   strerror(error));
 
        return true;
 }
@@ -189,12 +187,13 @@ ck_assert_cachent_eq(struct cache_node *expected, struct cache_node *actual)
        PR_DEBUG_MSG("Comparing %s vs %s", expected->url, actual->url);
 
        ck_assert_str_eq(expected->url, actual->url);
+       ck_assert_str_eq(expected->path, actual->path);
        ck_assert_str_eq(expected->name, actual->name);
        ck_assert_int_eq(expected->flags, actual->flags);
-       if (expected->tmpdir)
-               ck_assert_str_eq(expected->tmpdir, actual->tmpdir);
+       if (expected->tmppath)
+               ck_assert_str_eq(expected->tmppath, actual->tmppath);
        else
-               ck_assert_ptr_eq(NULL, actual->tmpdir);
+               ck_assert_ptr_eq(NULL, actual->tmppath);
 
        HASH_ITER(hh, expected->children, echild, tmp) {
                HASH_FIND(hh, actual->children, echild->name,
@@ -244,22 +243,22 @@ ck_cache(struct cache_node *rsync, struct cache_node *https)
 static void
 ck_cache_rsync(struct cache_node *rsync)
 {
-       ck_cache(rsync, unode("https", NULL));
+       ck_cache(rsync, hunode("", NULL));
 }
 
 static void
 ck_cache_https(struct cache_node *https)
 {
-       ck_cache(unode("rsync", NULL), https);
+       ck_cache(runode("", NULL), https);
 }
 
 static time_t epoch;
 
 static bool
-unfreshen(struct cache_node *node, char const *path)
+unfreshen(struct cache_node *node)
 {
        PR_DEBUG_MSG("Unfreshening %s.", node->url);
-       node->flags &= ~CNF_FRESH;
+       node->flags &= ~(CNF_FRESH | CNF_CHANGED | CNF_VALID);
        node->mtim = epoch;
        return true;
 }
@@ -316,7 +315,7 @@ cleanup_test(void)
 static const int DOWNLOADED = CNF_RSYNC | CNF_CACHED | CNF_FRESH;
 static const int VALIDATED = RSYNC_INHERIT | CNF_VALID;
 static const int FULL = DOWNLOADED | VALIDATED;
-static const int STALE = CNF_RSYNC | CNF_CACHED | CNF_VALID;
+static const int STALE = CNF_RSYNC | CNF_CACHED;
 /* Intermediary between a downloaded and a validated node */
 static const int BRANCH = RSYNC_INHERIT;
 static const int FAILED = CNF_FRESH;
@@ -325,29 +324,32 @@ START_TEST(test_cache_download_rsync)
 {
        setup_test();
 
+       printf("==== Startup ====\n");
        run_dl_rsync("rsync://a.b.c/d", 0, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
 
        /* Redownload same file, nothing should happen */
+       printf("==== Redownload sample file ====\n");
        run_dl_rsync("rsync://a.b.c/d", 0, 0);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL), NULL), NULL));
 
        /*
         * rsyncs are recursive, which means if we've been recently asked to
         * download d, we needn't bother redownloading d/e.
         */
+       printf("==== Don't redownload child ====\n");
        run_dl_rsync("rsync://a.b.c/d/e", 0, 0);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0",
-                                       ufnode("rsync/a.b.c/d/e", VALIDATED, NULL), NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0",
+                                       rufnode("a.b.c/d/e", VALIDATED, NULL), NULL), NULL), NULL));
 
        /*
         * rsyncs get truncated, because it results in much faster
@@ -355,30 +357,32 @@ START_TEST(test_cache_download_rsync)
         * This is not defined in any RFCs; it's an effective standard,
         * and there would be consequences for violating it.
         */
+       printf("==== rsync truncated ====\n");
        run_dl_rsync("rsync://x.y.z/m/n/o", 0, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0",
-                                       ufnode("rsync/a.b.c/d/e", VALIDATED, NULL), NULL), NULL),
-                       unode("rsync/x.y.z",
-                               uftnode("rsync/x.y.z/m", DOWNLOADED, "tmp/tmp/1",
-                                       ufnode("rsync/x.y.z/m/n", BRANCH,
-                                               ufnode("rsync/x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0",
+                                       rufnode("a.b.c/d/e", VALIDATED, NULL), NULL), NULL),
+                       runode("x.y.z",
+                               ruftnode("x.y.z/m", DOWNLOADED, "tmp/tmp/1",
+                                       rufnode("x.y.z/m/n", BRANCH,
+                                               rufnode("x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
 
        /* Sibling */
+       printf("==== Sibling ====\n");
        run_dl_rsync("rsync://a.b.c/e/f", 0, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0",
-                                       ufnode("rsync/a.b.c/d/e", VALIDATED, NULL), NULL),
-                               uftnode("rsync/a.b.c/e", DOWNLOADED, "tmp/tmp/2",
-                                       ufnode("rsync/a.b.c/e/f", VALIDATED, NULL), NULL), NULL),
-                       unode("rsync/x.y.z",
-                               uftnode("rsync/x.y.z/m", DOWNLOADED, "tmp/tmp/1",
-                                       ufnode("rsync/x.y.z/m/n", BRANCH,
-                                               ufnode("rsync/x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0",
+                                       rufnode("a.b.c/d/e", VALIDATED, NULL), NULL),
+                               ruftnode("a.b.c/e", DOWNLOADED, "tmp/tmp/2",
+                                       rufnode("a.b.c/e/f", VALIDATED, NULL), NULL), NULL),
+                       runode("x.y.z",
+                               ruftnode("x.y.z/m", DOWNLOADED, "tmp/tmp/1",
+                                       rufnode("x.y.z/m/n", BRANCH,
+                                               rufnode("x.y.z/m/n/o", VALIDATED, NULL), NULL), NULL), NULL), NULL));
 
        cleanup_test();
 }
@@ -393,27 +397,27 @@ START_TEST(test_cache_download_rsync_error)
        dl_error = -EINVAL;
        run_dl_rsync("rsync://a.b.c/e", -EINVAL, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL),
-                               ufnode("rsync/a.b.c/e", FAILED, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+                               rufnode("a.b.c/e", FAILED, NULL), NULL), NULL));
 
        /* Regardless of error, not reattempted because same iteration */
        dl_error = EINVAL;
        run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL),
-                               ufnode("rsync/a.b.c/e", FAILED, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+                               rufnode("a.b.c/e", FAILED, NULL), NULL), NULL));
 
        dl_error = 0;
        run_dl_rsync("rsync://a.b.c/e", -EINVAL, 0);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL),
-                               ufnode("rsync/a.b.c/e", FAILED, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+                               rufnode("a.b.c/e", FAILED, NULL), NULL), NULL));
 
        cleanup_test();
 }
@@ -433,10 +437,10 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL),
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", FULL, NULL),
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        /* One iteration with no changes, for paranoia */
        printf("==== No changes, for paranoia ====\n");
@@ -445,10 +449,10 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL),
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", FULL, NULL),
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        /* Add one sibling */
        printf("==== Add one sibling ====\n");
@@ -458,22 +462,22 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/f", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL),
-                               ufnode("rsync/a.b.c/e", FULL, NULL),
-                               ufnode("rsync/a.b.c/f", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", FULL, NULL),
+                               rufnode("a.b.c/e", FULL, NULL),
+                               rufnode("a.b.c/f", FULL, NULL), NULL), NULL));
 
        /* Nodes don't get updated, but they're still too young. */
        printf("==== Still too young ====\n");
        new_iteration(false);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", STALE, NULL),
-                               ufnode("rsync/a.b.c/e", STALE, NULL),
-                               ufnode("rsync/a.b.c/f", STALE, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", STALE, NULL),
+                               rufnode("a.b.c/e", STALE, NULL),
+                               rufnode("a.b.c/f", STALE, NULL), NULL), NULL));
 
        /* Remove some branches */
        printf("==== Remove some branches ====\n");
@@ -481,9 +485,9 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/d", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", FULL, NULL), NULL), NULL));
 
        /* Remove old branch and add sibling at the same time */
        printf("==== Remove old branch + add sibling ====\n");
@@ -491,9 +495,9 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        /* Try child */
        printf("==== Try child ====\n");
@@ -501,9 +505,9 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e/f/g", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        /* Parent again */
        printf("==== Parent again ====\n");
@@ -511,15 +515,15 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        /* Empty the tree */
        printf("==== Empty the tree ====\n");
        new_iteration(true);
        run_cleanup();
-       ck_cache_rsync(unode("rsync", NULL));
+       ck_cache_rsync(runode("", NULL));
 
 
        /* Node exists, but file doesn't */
@@ -528,22 +532,22 @@ START_TEST(test_cache_cleanup_rsync)
        run_dl_rsync("rsync://a.b.c/e", 0, 1);
        run_dl_rsync("rsync://a.b.c/f", 0, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/e", FULL, "tmp/tmp/B", NULL),
-                               uftnode("rsync/a.b.c/f", FULL, "tmp/tmp/C", NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/e", FULL, "tmp/tmp/B", NULL),
+                               ruftnode("a.b.c/f", FULL, "tmp/tmp/C", NULL), NULL), NULL));
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/e", FULL, NULL),
-                               ufnode("rsync/a.b.c/f", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/e", FULL, NULL),
+                               rufnode("a.b.c/f", FULL, NULL), NULL), NULL));
        ck_assert_int_eq(0, file_rm_rf("tmp/rsync/a.b.c/f"));
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/e", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/e", FULL, NULL), NULL), NULL));
 
        cleanup_test();
 }
@@ -554,45 +558,51 @@ START_TEST(test_cache_cleanup_rsync_error)
        setup_test();
 
        /* Set up */
+       printf("==== Set up ====\n");
        dl_error = 0;
        run_dl_rsync("rsync://a.b.c/d", 0, 1);
        dl_error = -EINVAL;
        run_dl_rsync("rsync://a.b.c/e", -EINVAL, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               uftnode("rsync/a.b.c/d", FULL, "tmp/tmp/0", NULL),
-                               ufnode("rsync/a.b.c/e", FAILED, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               ruftnode("a.b.c/d", FULL, "tmp/tmp/0", NULL),
+                               rufnode("a.b.c/e", FAILED, NULL), NULL), NULL));
 
        /* Node gets deleted because cached file doesn't exist */
+       printf("==== Node deleted because file not found ====\n");
        run_cleanup();
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", FULL, NULL), NULL), NULL));
 
        /*
         * Node and file do not get deleted, because the failure is still not
         * that old.
         * Deletion does not depend on success or failure.
         */
+       printf("==== Node and file preserved because young ====\n");
        new_iteration(false);
        dl_error = -EINVAL;
        run_dl_rsync("rsync://a.b.c/d", -EINVAL, 1);
        ck_cache_rsync(
-               unode("rsync",
-                       unode("rsync/a.b.c",
-                               ufnode("rsync/a.b.c/d", FULL, NULL), NULL), NULL));
+               runode("",
+                       runode("a.b.c",
+                               rufnode("a.b.c/d", DOWNLOADED, NULL), NULL), NULL));
 
        /* Error is old; gets deleted */
+       printf("==== Error deleted because old ====\n");
        new_iteration(true);
        run_cleanup();
-       ck_cache_rsync(unode("rsync", NULL));
+       ck_cache_rsync(runode("", NULL));
 
        cleanup_test();
 }
 END_TEST
 
+/* XXX ================================================================ */
+
 static const int HDOWNLOADED = CNF_CACHED | CNF_FRESH | CNF_CHANGED;
 static const int HVALIDATED = CNF_CACHED | CNF_VALID;
 static const int HFULL = HDOWNLOADED | HVALIDATED;
@@ -605,30 +615,30 @@ START_TEST(test_cache_download_https)
        /* Download *file* e. */
        run_dl_https("https://a.b.c/d/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               unode("https/a.b.c/d",
-                                       uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hunode("a.b.c/d",
+                                       huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL), NULL), NULL));
 
        /* Download something else 1 */
        run_dl_https("https://a.b.c/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               unode("https/a.b.c/d",
-                                       uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hunode("a.b.c/d",
+                                       huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL));
 
        /* Download something else 2 */
        run_dl_https("https://x.y.z/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               unode("https/a.b.c/d",
-                                       uftnode("https/a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL),
-                       unode("https/x.y.z",
-                               uftnode("https/x.y.z/e", HFULL, "tmp/tmp/2", NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hunode("a.b.c/d",
+                                       huftnode("a.b.c/d/e", HFULL, "tmp/tmp/0", NULL), NULL),
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL),
+                       hunode("x.y.z",
+                               huftnode("x.y.z/e", HFULL, "tmp/tmp/2", NULL), NULL), NULL));
 
        cleanup_test();
 }
@@ -643,10 +653,10 @@ START_TEST(test_cache_download_https_error)
        dl_error = -EINVAL;
        run_dl_https("https://a.b.c/e", -EINVAL, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL),
-                               uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL),
+                               huftnode("a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
 
        /* Regardless of error, not reattempted because same iteration */
        dl_error = -EINVAL;
@@ -654,10 +664,10 @@ START_TEST(test_cache_download_https_error)
        dl_error = 0;
        run_dl_https("https://a.b.c/e", -EINVAL, 0);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/d", HFULL, "tmp/tmp/0", NULL),
-                               uftnode("https/a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL),
+                               huftnode("a.b.c/e", HFAILED, NULL, NULL), NULL), NULL));
 
        cleanup_test();
 }
@@ -675,39 +685,39 @@ START_TEST(test_cache_cleanup_https)
        run_dl_https("https://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/d", HFULL, NULL),
-                               ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/d", HFULL, NULL),
+                               hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
 
        /* Remove one branch */
        new_iteration(true);
        run_dl_https("https://a.b.c/d", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/d", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/d", HFULL, NULL), NULL), NULL));
 
        /* Change the one branch */
        new_iteration(true);
        run_dl_https("https://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
 
        /* Add a child to the same branch, do not update the old one */
        new_iteration(true);
        run_dl_https("https://a.b.c/e/f/g", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               unode("https/a.b.c/e",
-                                       unode("https/a.b.c/e/f",
-                                               ufnode("https/a.b.c/e/f/g", HFULL, NULL), NULL), NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hunode("a.b.c/e",
+                                       hunode("a.b.c/e/f",
+                                               hufnode("a.b.c/e/f/g", HFULL, NULL), NULL), NULL), NULL), NULL));
 
        /*
         * Download parent, do not update child.
@@ -717,154 +727,173 @@ START_TEST(test_cache_cleanup_https)
        run_dl_https("https://a.b.c/e/f", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               unode("https/a.b.c/e",
-                                       ufnode("https/a.b.c/e/f", HFULL, NULL), NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hunode("a.b.c/e",
+                                       hufnode("a.b.c/e/f", HFULL, NULL), NULL), NULL), NULL));
 
        /* Do it again. */
        new_iteration(true);
        run_dl_https("https://a.b.c/e", 0, 1);
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
 
 
        /* Empty the tree */
        new_iteration(true);
        run_cleanup();
-       ck_cache_https(unode("https", NULL));
+       ck_cache_https(hunode("", NULL));
 
        /* Node exists, but file doesn't */
        new_iteration(true);
        run_dl_https("https://a.b.c/e", 0, 1);
        run_dl_https("https://a.b.c/f/g/h", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/7", NULL),
-                               unode("https/a.b.c/f",
-                                       unode("https/a.b.c/f/g",
-                                               uftnode("https/a.b.c/f/g/h", HFULL, "tmp/tmp/8", NULL), NULL), NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/7", NULL),
+                               hunode("a.b.c/f",
+                                       hunode("a.b.c/f/g",
+                                               huftnode("a.b.c/f/g/h", HFULL, "tmp/tmp/8", NULL), NULL), NULL), NULL), NULL));
        run_cleanup(); /* Move from tmp/tmp to tmp/https */
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL),
-                               unode("https/a.b.c/f",
-                                       unode("https/a.b.c/f/g",
-                                               ufnode("https/a.b.c/f/g/h", HFULL, NULL), NULL), NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL),
+                               hunode("a.b.c/f",
+                                       hunode("a.b.c/f/g",
+                                               hufnode("a.b.c/f/g/h", HFULL, NULL), NULL), NULL), NULL), NULL));
        ck_assert_int_eq(0, file_rm_rf("tmp/https/a.b.c/f/g/h"));
        run_cleanup(); /* Actual test */
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
 
        /* Temporal version disappears before we get a commit */
        new_iteration(true);
        run_dl_https("https://a.b.c/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/9", NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/9", NULL), NULL), NULL));
        ck_assert_int_eq(0, file_rm_rf("tmp/tmp/9"));
        run_cleanup();
-       ck_cache_https(unode("https", NULL));
+       ck_cache_https(hunode("", NULL));
 
        /* Temporal version disappears after we get a commit */
        new_iteration(true);
        run_dl_https("https://a.b.c/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/A", NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/A", NULL), NULL), NULL));
        run_cleanup(); /* Commit */
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL, NULL), NULL), NULL));
        new_iteration(false);
        run_dl_https("https://a.b.c/e", 0, 1);
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               uftnode("https/a.b.c/e", HFULL, "tmp/tmp/B", NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/B", NULL), NULL), NULL));
        ck_assert_int_eq(0, file_rm_rf("tmp/tmp/B"));
        run_cleanup();
        ck_cache_https(
-               unode("https",
-                       unode("https/a.b.c",
-                               ufnode("https/a.b.c/e", HFULL, NULL), NULL), NULL));
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/e", HFULL, NULL), NULL), NULL));
 
        cleanup_test();
 }
 END_TEST
 
-//START_TEST(test_cache_cleanup_https_error)
-//{
-//     setup_test();
-//
-//     /* Set up */
-//     dl_error = false;
-//     run_dl_https("https://a.b.c/d", 0, 1);
-//     dl_error = true;
-//     run_dl_https("https://a.b.c/e", -EINVAL, 1);
-//     ck_cache(
-//         NODE("https://a.b.c/d", 0, 1, 1),
-//         NODE("https://a.b.c/e", -EINVAL, 0, 0),
-//         NULL);
-//
-//     /* Deleted because file ENOENT. */
-//     run_cleanup();
-//     ck_cache(
-//         NODE("https://a.b.c/d", 0, 1, 1),
-//         NULL);
-//
-//     /* Fail d */
-//     new_iteration(false);
-//     dl_error = true;
-//     run_dl_https("https://a.b.c/d", -EINVAL, 1);
-//     ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL);
-//
-//     /* Not deleted, because not old */
-//     new_iteration(false);
-//     run_cleanup();
-//     ck_cache(NODE("https://a.b.c/d", -EINVAL, 1, 1), NULL);
-//
-//     /* Become old */
-//     new_iteration(true);
-//     run_cleanup();
-//     ck_cache(NULL);
-//
-//     cleanup_test();
-//}
-//END_TEST
-//
-//START_TEST(test_dots)
-//{
-//     setup_test();
-//
-//     run_cache_download("https://a.b.c/d", 0, 0, 1);
-//     ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-//     run_cache_download("https://a.b.c/d/.", 0, 0, 0);
-//     ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-//     run_cache_download("https://a.b.c/d/e/..", 0, 0, 0);
-//     ck_cache(NODE("https://a.b.c/d", 0, 1, 1), NULL);
-//
-//     run_cache_download("https://a.b.c/./d/../e", 0, 0, 1);
-//     ck_cache(
-//         NODE("https://a.b.c/d", 0, 1, 1),
-//         NODE("https://a.b.c/./d/../e", 0, 1, 1),
-//         NULL);
-//
-//     cleanup_test();
-//}
-//END_TEST
+START_TEST(test_cache_cleanup_https_error)
+{
+       setup_test();
+
+       /* Set up */
+       dl_error = 0;
+       run_dl_https("https://a.b.c/d", 0, 1);
+       dl_error = -EINVAL;
+       run_dl_https("https://a.b.c/e", -EINVAL, 1);
+       PR_DEBUG;
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL),
+                               hufnode("a.b.c/e", HFAILED, NULL), NULL), NULL));
+
+       /* Deleted because file ENOENT. */
+       run_cleanup();
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/d", HFULL, NULL), NULL), NULL));
+
+       /* Fail d */
+       new_iteration(false);
+       dl_error = -EINVAL;
+       run_dl_https("https://a.b.c/d", -EINVAL, 1);
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/d", CNF_CACHED | CNF_FRESH, NULL), NULL), NULL));
+
+       /* Not deleted, because not old */
+       new_iteration(false);
+       run_cleanup();
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               hufnode("a.b.c/d", CNF_CACHED, NULL), NULL), NULL));
+
+       /* Become old */
+       new_iteration(true);
+       run_cleanup();
+       ck_cache_https(hunode("", NULL));
+
+       cleanup_test();
+}
+END_TEST
+
+START_TEST(test_dots)
+{
+       setup_test();
+
+       run_dl_https("https://a.b.c/d", 0, 1);
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL));
+
+       run_dl_https("https://a.b.c/d/.", 0, 0);
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL));
+
+       run_dl_https("https://a.b.c/d/e/..", 0, 0);
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL), NULL), NULL));
+
+       run_dl_https("https://a.b.c/./d/../e", 0, 1);
+       ck_cache_https(
+               hunode("",
+                       hunode("a.b.c",
+                               huftnode("a.b.c/d", HFULL, "tmp/tmp/0", NULL),
+                               huftnode("a.b.c/e", HFULL, "tmp/tmp/1", NULL), NULL), NULL));
+
+       cleanup_test();
+}
+END_TEST
 //
 //START_TEST(test_tal_json)
 //{
@@ -937,7 +966,7 @@ END_TEST
 //     }
 //     va_end(args);
 //}
-//
+
 //#define PREPARE_MAP_LIST(maps, ...) prepare_map_list(maps, ##__VA_ARGS__, NULL)
 //
 //START_TEST(test_recover)
@@ -1062,19 +1091,19 @@ static Suite *thread_pool_suite(void)
        TCase *rsync, *https, *dot, *meta, *recover;
 
        rsync = tcase_create("rsync");
-//     tcase_add_test(rsync, test_cache_download_rsync);
-//     tcase_add_test(rsync, test_cache_download_rsync_error);
-//     tcase_add_test(rsync, test_cache_cleanup_rsync);
-//     tcase_add_test(rsync, test_cache_cleanup_rsync_error);
+       tcase_add_test(rsync, test_cache_download_rsync);
+       tcase_add_test(rsync, test_cache_download_rsync_error);
+       tcase_add_test(rsync, test_cache_cleanup_rsync);
+       tcase_add_test(rsync, test_cache_cleanup_rsync_error);
 
        https = tcase_create("https");
-//     tcase_add_test(https, test_cache_download_https);
-//     tcase_add_test(https, test_cache_download_https_error);
+       tcase_add_test(https, test_cache_download_https);
+       tcase_add_test(https, test_cache_download_https_error);
        tcase_add_test(https, test_cache_cleanup_https);
-//     tcase_add_test(https, test_cache_cleanup_https_error);
+       tcase_add_test(https, test_cache_cleanup_https_error);
 
        dot = tcase_create("dot");
-//     tcase_add_test(dot, test_dots);
+       tcase_add_test(dot, test_dots);
 
        meta = tcase_create(TAL_METAFILE);
 //     tcase_add_test(meta, test_tal_json);
index 682383a820e87dac7935f3ebd2c2ebc90d7272da..6acbb829bd60010ca53a6d6451a1b56001b71894 100644 (file)
@@ -3,19 +3,27 @@
 #include <string.h>
 #include "data_structure/uthash.h"
 
-struct cache_node *
-vnode(char const *url, int flags, char const *tmpdir, va_list children)
+static struct cache_node *
+node(char const *schema, char const *path, int flags, char const *tmpdir,
+    va_list children)
 {
        struct cache_node *result;
        struct cache_node *child;
+       char buffer[64];
        char const *slash;
 
        result = pzalloc(sizeof(struct cache_node));
-       result->url = pstrdup(url);
-       slash = strrchr(url, '/');
-       result->name = slash ? (slash + 1) : result->url;
+
+       ck_assert(snprintf(buffer, 64, "%s://%s", schema, path) < 64);
+       result->url = pstrdup(buffer);
+       slash = (path[0] == 0) ? "" : "/";
+       ck_assert(snprintf(buffer, 64, "tmp/%s%s%s", schema, slash, path) < 64);
+       result->path = pstrdup(buffer);
+
+       result->name = strrchr(result->path, '/') + 1;
+       ck_assert_ptr_ne(NULL, result->name);
        result->flags = flags;
-       result->tmpdir = tmpdir ? pstrdup(tmpdir) : NULL;
+       result->tmppath = tmpdir ? pstrdup(tmpdir) : NULL;
 
        while ((child = va_arg(children, struct cache_node *)) != NULL) {
                HASH_ADD_KEYPTR(hh, result->children, child->name,
@@ -27,39 +35,78 @@ vnode(char const *url, int flags, char const *tmpdir, va_list children)
 }
 
 struct cache_node *
-uftnode(char const *url, int flags, char const *tmpdir, ...)
+ruftnode(char const *path, int flags, char const *tmpdir, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, tmpdir);
+       result = node("rsync", path, flags, tmpdir, children);
+       va_end(children);
+
+       return result;
+}
+
+struct cache_node *
+rufnode(char const *path, int flags, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, flags);
+       result = node("rsync", path, flags, NULL, children);
+       va_end(children);
+
+       return result;
+}
+
+struct cache_node *
+runode(char const *path, ...)
+{
+       struct cache_node *result;
+       va_list children;
+
+       va_start(children, path);
+       result = node("rsync", path, 0, NULL, children);
+       va_end(children);
+
+       return result;
+}
+
+struct cache_node *
+huftnode(char const *path, int flags, char const *tmpdir, ...)
 {
        struct cache_node *result;
        va_list children;
 
        va_start(children, tmpdir);
-       result = vnode(url, flags, tmpdir, children);
+       result = node("https", path, flags, tmpdir, children);
        va_end(children);
 
        return result;
 }
 
 struct cache_node *
-ufnode(char const *url, int flags, ...)
+hufnode(char const *path, int flags, ...)
 {
        struct cache_node *result;
        va_list children;
 
        va_start(children, flags);
-       result = vnode(url, flags, NULL, children);
+       result = node("https", path, flags, NULL, children);
        va_end(children);
 
        return result;
 }
 
 struct cache_node *
-unode(char const *url, ...)
+hunode(char const *path, ...)
 {
        struct cache_node *result;
        va_list children;
 
-       va_start(children, url);
-       result = vnode(url, 0, NULL, children);
+       va_start(children, path);
+       result = node("https", path, 0, NULL, children);
        va_end(children);
 
        return result;
index 4ff43efa054bb75b477d0c5d37fe311a9129be07..4e350c8d44042b768fb83933ac7844c9d15c5c84 100644 (file)
@@ -4,9 +4,12 @@
 #include <stdarg.h>
 #include "cache/cachent.h"
 
-struct cache_node *vnode(char const *, int, char const *, va_list);
-struct cache_node *uftnode(char const *, int , char const *, ...);
-struct cache_node *ufnode(char const *, int , ...);
-struct cache_node *unode(char const *, ...);
+struct cache_node *ruftnode(char const *, int , char const *, ...);
+struct cache_node *rufnode(char const *, int , ...);
+struct cache_node *runode(char const *, ...);
+
+struct cache_node *huftnode(char const *, int , char const *, ...);
+struct cache_node *hufnode(char const *, int , ...);
+struct cache_node *hunode(char const *, ...);
 
 #endif /* TEST_CACHE_UTIL_H_ */
index 763843b1b28898a9b33bfe09a31a79cd731a16c0..ec5d57a7c41cfc4e54d62501c4c698c7115f74ab 100644 (file)
@@ -15,19 +15,22 @@ START_TEST(test_normalize)
 {
        char *normal;
 
-       TEST_NORMALIZE("rsync://a.b.c", "rsync/a.b.c");
-       TEST_NORMALIZE("rsync://a.b.c/", "rsync/a.b.c");
-       TEST_NORMALIZE("rsync://a.b.c//////", "rsync/a.b.c");
-       TEST_NORMALIZE("rsync://a.b.c/d/e", "rsync/a.b.c/d/e");
-       TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync/a.b.c/d/e");
-       TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync/a.b.c/d/e");
-       TEST_NORMALIZE("rsync://a.b.c/d/./e/.", "rsync/a.b.c/d/e");
-       TEST_NORMALIZE("rsync://a.b.c/d/../d/../d/e/", "rsync/a.b.c/d/e");
-       TEST_NORMALIZE("rsync://a.b.c/../x/y/z", "rsync/x/y/z");
-       TEST_NORMALIZE("rsync://x//y/z/../../../m/./n/o", "rsync/m/n/o");
+       TEST_NORMALIZE("rsync://a.b.c", "rsync://a.b.c");
+       TEST_NORMALIZE("rsync://a.b.c/", "rsync://a.b.c");
+       TEST_NORMALIZE("rsync://a.b.c//////", "rsync://a.b.c");
+       TEST_NORMALIZE("rsync://a.b.c/d/e", "rsync://a.b.c/d/e");
+       TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync://a.b.c/d/e");
+       TEST_NORMALIZE("rsync://a.b.c/d/e/.", "rsync://a.b.c/d/e");
+       TEST_NORMALIZE("rsync://a.b.c/d/./e/.", "rsync://a.b.c/d/e");
+       TEST_NORMALIZE("rsync://a.b.c/x/../x/y/z", "rsync://a.b.c/x/y/z");
+       TEST_NORMALIZE("rsync://a.b.c/d/../d/../d/e/", "rsync://a.b.c/d/e");
+       TEST_NORMALIZE("rsync://x//y/z/../../m/./n/o", "rsync://x/m/n/o");
        ck_assert_ptr_eq(NULL, url_normalize("rsync://"));
+       ck_assert_ptr_eq(NULL, url_normalize("rsync://."));
        ck_assert_ptr_eq(NULL, url_normalize("rsync://.."));
        ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/.."));
+       ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/../x"));
+       ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/../x/y/z"));
        ck_assert_ptr_eq(NULL, url_normalize("rsync://a.b.c/d/e/../../.."));
        ck_assert_ptr_eq(NULL, url_normalize("abcde://a.b.c/d"));
 }