This diff changes the way the parser figures out which file to work on.
Until now the parent process sent a full path to the parser but that does
not work well with the idea of splitting the repo up into validated, rsync
and rrdp parts.

So this diff changes the way the parser opens a file. There are now three
bits of information passed in struct entity.
- repoid: id of the repository to use, can be zero to indicate no repo.
- path: relative path from the base repo to the working directory where
  file lives. Again this is optional and can be NULL.
- file: filename of the object to work on. This value has to be set.

To make this work struct mft needs to pass the path and repoid back to the
parent so that the parent can build the next round of files to parse based
on that information.

Right now the code should behave exactly the same as -current.
-- 
:wq Claudio

Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.100
diff -u -p -r1.100 extern.h
--- extern.h    29 Dec 2021 11:37:57 -0000      1.100
+++ extern.h    7 Jan 2022 14:37:05 -0000
@@ -162,14 +162,15 @@ struct mftfile {
  * manifest file.
  */
 struct mft {
-       char            *file; /* full path of MFT file */
+       char            *path; /* relative path to directory of the MFT */
        struct mftfile  *files; /* file and hash */
        size_t           filesz; /* number of filenames */
-       int              stale; /* if a stale manifest */
        char            *seqnum; /* manifestNumber */
        char            *aia; /* AIA */
        char            *aki; /* AKI */
        char            *ski; /* SKI */
+       unsigned int     repoid;
+       int              stale; /* if a stale manifest */
 };
 
 /*
@@ -292,6 +293,7 @@ enum rtype {
        RTYPE_CER,
        RTYPE_CRL,
        RTYPE_GBR,
+       RTYPE_REPO,
 };
 
 enum http_result {
@@ -337,9 +339,11 @@ enum publish_type {
  */
 struct entity {
        TAILQ_ENTRY(entity) entries;
-       char            *file;          /* local path to file */
+       char            *path;          /* path relative to repository */
+       char            *file;          /* filename */
        unsigned char   *data;          /* optional data blob */
        size_t           datasz;        /* length of optional data blob */
+       unsigned int     repoid;        /* repository identifier */
        int              talid;         /* tal identifier */
        enum rtype       type;          /* type of entity (not RTYPE_EOF) */
 };
@@ -500,9 +504,12 @@ int                 filepath_add(struct filepath_tree 
 void            rrdp_save_state(unsigned int, struct rrdp_session *);
 int             rrdp_handle_file(unsigned int, enum publish_type, char *,
                    char *, size_t, char *, size_t);
-char           *repo_filename(const struct repo *, const char *);
+char           *repo_basedir(const struct repo *);
+unsigned int    repo_id(const struct repo *);
+const char     *repo_uri(const struct repo *);
 struct repo    *ta_lookup(int, struct tal *);
 struct repo    *repo_lookup(int, const char *, const char *);
+struct repo    *repo_byid(unsigned int);
 int             repo_queued(struct repo *, struct entity *);
 void            repo_cleanup(struct filepath_tree *);
 void            repo_free(void);
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.172
diff -u -p -r1.172 main.c
--- main.c      6 Jan 2022 16:06:30 -0000       1.172
+++ main.c      10 Jan 2022 10:30:53 -0000
@@ -104,8 +104,9 @@ entity_free(struct entity *ent)
        if (ent == NULL)
                return;
 
-       free(ent->data);
+       free(ent->path);
        free(ent->file);
+       free(ent->data);
        free(ent);
 }
 
@@ -118,7 +119,9 @@ void
 entity_read_req(struct ibuf *b, struct entity *ent)
 {
        io_read_buf(b, &ent->type, sizeof(ent->type));
+       io_read_buf(b, &ent->repoid, sizeof(ent->repoid));
        io_read_buf(b, &ent->talid, sizeof(ent->talid));
+       io_read_str(b, &ent->path);
        io_read_str(b, &ent->file);
        io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz);
 }
@@ -134,12 +137,36 @@ entity_write_req(const struct entity *en
 
        b = io_new_buffer();
        io_simple_buffer(b, &ent->type, sizeof(ent->type));
+       io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid));
        io_simple_buffer(b, &ent->talid, sizeof(ent->talid));
+       io_str_buffer(b, ent->path);
        io_str_buffer(b, ent->file);
        io_buf_buffer(b, ent->data, ent->datasz);
        io_close_buffer(&procq, b);
 }
 
+static void
+entity_write_repo(struct repo *rp)
+{
+       struct ibuf *b;
+       enum rtype type = RTYPE_REPO;
+       unsigned int repoid;
+       char *path;
+       int talid = 0;
+
+       repoid = repo_id(rp);
+       path = repo_basedir(rp);
+       b = io_new_buffer();
+       io_simple_buffer(b, &type, sizeof(type));
+       io_simple_buffer(b, &repoid, sizeof(repoid));
+       io_simple_buffer(b, &talid, sizeof(talid));
+       io_str_buffer(b, path);
+       io_str_buffer(b, NULL);
+       io_buf_buffer(b, NULL, 0);
+       io_close_buffer(&procq, b);
+       free(path);
+}
+
 /*
  * Scan through all queued requests and see which ones are in the given
  * repo, then flush those into the parser process.
@@ -149,20 +176,9 @@ entityq_flush(struct entityq *q, struct 
 {
        struct entity   *p, *np;
 
-       TAILQ_FOREACH_SAFE(p, q, entries, np) {
-               char *file = p->file;
-
-               /*
-                * XXX fixup path here since the repo may change
-                * during load because of fallback. In that case
-                * the file path changes as well since RRDP and RSYNC
-                * can not share a common repo.
-                */
-               p->file = repo_filename(rp, file);
-               if (p->file == NULL)
-                       err(1, "can't construct repo filename");
-               free(file);
+       entity_write_repo(rp);
 
+       TAILQ_FOREACH_SAFE(p, q, entries, np) {
                entity_write_req(p);
                TAILQ_REMOVE(q, p, entries);
                entity_free(p);
@@ -173,7 +189,7 @@ entityq_flush(struct entityq *q, struct 
  * Add the heap-allocated file to the queue for processing.
  */
 static void
-entityq_add(char *file, enum rtype type, struct repo *rp,
+entityq_add(char *path, char *file, enum rtype type, struct repo *rp,
     unsigned char *data, size_t datasz, int talid)
 {
        struct entity   *p;
@@ -183,6 +199,9 @@ entityq_add(char *file, enum rtype type,
 
        p->type = type;
        p->talid = talid;
+       p->path = path;
+       if (rp != NULL)
+               p->repoid = repo_id(rp);
        p->file = file;
        p->data = data;
        p->datasz = (data != NULL) ? datasz : 0;
@@ -195,20 +214,6 @@ entityq_add(char *file, enum rtype type,
         */
 
        if (rp == NULL || !repo_queued(rp, p)) {
-               /*
-                * XXX fixup path here since for repo path the
-                * file path has not yet been fixed here.
-                * This is a quick way to make this work but in
-                * the long run repos need to be passed to the parser.
-                */
-               if (rp != NULL) {
-                       file = p->file;
-                       p->file = repo_filename(rp, file);
-                       if (p->file == NULL)
-                               err(1, "can't construct repo filename from %s",
-                                   file);
-                       free(file);
-               }
                entity_write_req(p);
                entity_free(p);
        }
@@ -320,23 +325,18 @@ rrdp_http_done(unsigned int id, enum htt
  * These are always relative to the directory in which "mft" sits.
  */
 static void
-queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype 
type)
+queue_add_from_mft(const char *path, const struct mftfile *file,
+    enum rtype type, struct repo *rp)
 {
-       char            *cp, *nfile;
+       char            *nfile, *npath = NULL;
 
-       /* Construct local path from filename. */
-       cp = strrchr(mft, '/');
-       assert(cp != NULL);
-       assert(cp - mft < INT_MAX);
-       if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1)
+       if (path != NULL)
+               if ((npath = strdup(path)) == NULL)
+                       err(1, NULL);
+       if ((nfile = strdup(file->file)) == NULL)
                err(1, NULL);
 
-       /*
-        * Since we're from the same directory as the MFT file, we know
-        * that the repository has already been loaded.
-        */
-
-       entityq_add(nfile, type, NULL, NULL, 0, -1);
+       entityq_add(npath, nfile, type, rp, NULL, 0, -1);
 }
 
 /*
@@ -348,7 +348,7 @@ queue_add_from_mft(const char *mft, cons
  * check the suffix anyway).
  */
 static void
-queue_add_from_mft_set(const struct mft *mft)
+queue_add_from_mft_set(const struct mft *mft, const char *name, struct repo 
*rp)
 {
        size_t                   i, sz;
        const struct mftfile    *f;
@@ -359,7 +359,7 @@ queue_add_from_mft_set(const struct mft 
                assert(sz > 4);
                if (strcasecmp(f->file + sz - 4, ".crl") != 0)
                        continue;
-               queue_add_from_mft(mft->file, f, RTYPE_CRL);
+               queue_add_from_mft(mft->path, f, RTYPE_CRL, rp);
        }
 
        for (i = 0; i < mft->filesz; i++) {
@@ -369,13 +369,13 @@ queue_add_from_mft_set(const struct mft 
                if (strcasecmp(f->file + sz - 4, ".crl") == 0)
                        continue;
                else if (strcasecmp(f->file + sz - 4, ".cer") == 0)
-                       queue_add_from_mft(mft->file, f, RTYPE_CER);
+                       queue_add_from_mft(mft->path, f, RTYPE_CER, rp);
                else if (strcasecmp(f->file + sz - 4, ".roa") == 0)
-                       queue_add_from_mft(mft->file, f, RTYPE_ROA);
+                       queue_add_from_mft(mft->path, f, RTYPE_ROA, rp);
                else if (strcasecmp(f->file + sz - 4, ".gbr") == 0)
-                       queue_add_from_mft(mft->file, f, RTYPE_GBR);
+                       queue_add_from_mft(mft->path, f, RTYPE_GBR, rp);
                else
-                       logx("%s: unsupported file type: %s", mft->file,
+                       logx("%s: unsupported file type: %s", name,
                            f->file);
        }
 }
@@ -399,7 +399,7 @@ queue_add_tal(const char *file, int tali
        if ((nfile = strdup(file)) == NULL)
                err(1, NULL);
        /* Not in a repository, so directly add to queue. */
-       entityq_add(nfile, RTYPE_TAL, NULL, buf, len, talid);
+       entityq_add(NULL, nfile, RTYPE_TAL, NULL, buf, len, talid);
 }
 
 /*
@@ -410,12 +410,19 @@ queue_add_from_tal(struct tal *tal)
 {
        struct repo     *repo;
        unsigned char   *data;
+       char            *nfile;
 
        assert(tal->urisz);
 
        if ((taldescs[tal->id] = strdup(tal->descr)) == NULL)
                err(1, NULL);
 
+       /* figure out the TA filename, must be done before repo lookup */
+       nfile = strrchr(tal->uri[0], '/');
+       assert(nfile != NULL);
+       if ((nfile = strdup(nfile + 1)) == NULL)
+               err(1, NULL);
+
        /* Look up the repository. */
        repo = ta_lookup(tal->id, tal);
        if (repo == NULL)
@@ -424,7 +431,7 @@ queue_add_from_tal(struct tal *tal)
        /* steal the pkey from the tal structure */
        data = tal->pkey;
        tal->pkey = NULL;
-       entityq_add(NULL, RTYPE_CER, repo, data, tal->pkeysz, tal->id);
+       entityq_add(NULL, nfile, RTYPE_CER, repo, data, tal->pkeysz, tal->id);
 }
 
 /*
@@ -434,16 +441,40 @@ static void
 queue_add_from_cert(const struct cert *cert)
 {
        struct repo     *repo;
-       char            *nfile;
+       char            *nfile, *npath;
+       const char      *uri, *repouri, *file;
+       size_t           repourisz;
 
        repo = repo_lookup(cert->talid, cert->repo,
            rrdpon ? cert->notify : NULL);
        if (repo == NULL)
                return;
 
-       if ((nfile = strdup(cert->mft)) == NULL)
-               err(1, NULL);
-       entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, -1);
+       /*
+        * Figure out the cert filename and path by chopping up the
+        * MFT URI in the cert based on the repo base URI.
+        */
+       uri = cert->mft;
+       repouri = repo_uri(repo);
+       repourisz = strlen(repouri);
+       if (strncmp(repouri, cert->mft, repourisz) != 0) {
+               warnx("%s: URI %s outside of repository", repouri, uri);
+               return;
+       }
+       uri += repourisz + 1;   /* skip base and '/' */
+       file = strrchr(uri, '/');
+       if (file == NULL) {
+               npath = NULL;
+               if ((nfile = strdup(uri)) == NULL)
+                       err(1, NULL);
+       } else {
+               if ((npath = strndup(uri, file - uri)) == NULL)
+                       err(1, NULL);
+               if ((nfile = strdup(file + 1)) == NULL)
+                       err(1, NULL);
+       }
+
+       entityq_add(npath, nfile, RTYPE_MFT, repo, NULL, 0, -1);
 }
 
 /*
@@ -519,7 +550,8 @@ entity_process(struct ibuf *b, struct st
                }
                mft = mft_read(b);
                if (!mft->stale)
-                       queue_add_from_mft_set(mft);
+                       queue_add_from_mft_set(mft, file,
+                           repo_byid(mft->repoid));
                else
                        st->mfts_stale++;
                mft_free(mft);
Index: mft.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/mft.c,v
retrieving revision 1.43
diff -u -p -r1.43 mft.c
--- mft.c       6 Jan 2022 16:06:30 -0000       1.43
+++ mft.c       7 Jan 2022 15:02:56 -0000
@@ -433,8 +433,6 @@ mft_parse(X509 **x509, const char *fn, c
 
        if ((p.res = calloc(1, sizeof(struct mft))) == NULL)
                err(1, NULL);
-       if ((p.res->file = strdup(fn)) == NULL)
-               err(1, NULL);
 
        p.res->aia = x509_get_aia(*x509, fn);
        p.res->aki = x509_get_aki(*x509, 0, fn);
@@ -517,7 +515,7 @@ mft_free(struct mft *p)
        free(p->aia);
        free(p->aki);
        free(p->ski);
-       free(p->file);
+       free(p->path);
        free(p->files);
        free(p->seqnum);
        free(p);
@@ -532,18 +530,19 @@ mft_buffer(struct ibuf *b, const struct 
 {
        size_t           i;
 
-       io_simple_buffer(b, &p->stale, sizeof(int));
-       io_str_buffer(b, p->file);
-       io_simple_buffer(b, &p->filesz, sizeof(size_t));
+       io_simple_buffer(b, &p->stale, sizeof(p->stale));
+       io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
+       io_str_buffer(b, p->path);
+
+       io_str_buffer(b, p->aia);
+       io_str_buffer(b, p->aki);
+       io_str_buffer(b, p->ski);
 
+       io_simple_buffer(b, &p->filesz, sizeof(size_t));
        for (i = 0; i < p->filesz; i++) {
                io_str_buffer(b, p->files[i].file);
                io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
        }
-
-       io_str_buffer(b, p->aia);
-       io_str_buffer(b, p->aki);
-       io_str_buffer(b, p->ski);
 }
 
 /*
@@ -559,11 +558,16 @@ mft_read(struct ibuf *b)
        if ((p = calloc(1, sizeof(struct mft))) == NULL)
                err(1, NULL);
 
-       io_read_buf(b, &p->stale, sizeof(int));
-       io_read_str(b, &p->file);
-       io_read_buf(b, &p->filesz, sizeof(size_t));
+       io_read_buf(b, &p->stale, sizeof(p->stale));
+       io_read_buf(b, &p->repoid, sizeof(p->repoid));
+       io_read_str(b, &p->path);
 
-       assert(p->file);
+       io_read_str(b, &p->aia);
+       io_read_str(b, &p->aki);
+       io_read_str(b, &p->ski);
+       assert(p->aia && p->aki && p->ski);
+
+       io_read_buf(b, &p->filesz, sizeof(size_t));
        if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL)
                err(1, NULL);
 
@@ -571,11 +575,6 @@ mft_read(struct ibuf *b)
                io_read_str(b, &p->files[i].file);
                io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
        }
-
-       io_read_str(b, &p->aia);
-       io_read_str(b, &p->aki);
-       io_read_str(b, &p->ski);
-       assert(p->aia && p->aki && p->ski);
 
        return p;
 }
Index: parser.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/parser.c,v
retrieving revision 1.33
diff -u -p -r1.33 parser.c
--- parser.c    5 Jan 2022 11:07:35 -0000       1.33
+++ parser.c    10 Jan 2022 11:11:18 -0000
@@ -46,6 +46,46 @@ static X509_STORE_CTX        *ctx;
 static struct auth_tree  auths = RB_INITIALIZER(&auths);
 static struct crl_tree  crlt = RB_INITIALIZER(&crlt);
 
+struct parse_repo {
+       RB_ENTRY(parse_repo)     entry;
+       char                    *path;
+       unsigned int             id;
+};
+
+static RB_HEAD(repo_tree, parse_repo)  repos = RB_INITIALIZER(&repos);
+
+static inline int
+repocmp(struct parse_repo *a, struct parse_repo *b)
+{
+       return a->id - b->id;
+}
+
+RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp);
+
+static struct parse_repo *
+repo_get(unsigned int id)
+{
+       struct parse_repo needle = { .id = id };
+
+       return RB_FIND(repo_tree, &repos, &needle);
+}
+
+static void
+repo_add(unsigned int id, char *path)
+{
+       struct parse_repo *rp;
+
+       if ((rp = malloc(sizeof(*rp))) == NULL)
+               err(1, NULL);
+       rp->id = id;
+       if ((rp->path = strdup(path)) == NULL)
+               err(1, NULL);
+
+       if (RB_INSERT(repo_tree, &repos, rp) != NULL)
+               errx(1, "repository already added to repo tree %d, %s", id, 
path);
+       warnx("repository added to repo tree %d, %s", id, path);
+}
+
 static int
 verify_cb(int ok, X509_STORE_CTX *store_ctx)
 {
@@ -192,7 +232,8 @@ proc_parser_roa(char *file, const unsign
  * Return the mft on success or NULL on failure.
  */
 static struct mft *
-proc_parser_mft(char *file, const unsigned char *der, size_t len)
+proc_parser_mft(char *file, const unsigned char *der, size_t len,
+    const char *path, unsigned int repoid)
 {
        struct mft              *mft;
        X509                    *x509;
@@ -235,6 +276,10 @@ proc_parser_mft(char *file, const unsign
                return NULL;
        }
 
+       if (path != NULL)
+               if ((mft->path = strdup(path)) == NULL)
+                       err(1, NULL);
+       mft->repoid = repoid;
        return mft;
 }
 
@@ -544,6 +589,37 @@ build_crls(const struct crl *crl, STACK_
                err(1, "sk_X509_CRL_push");
 }
 
+static char *
+parse_filepath(struct entity *entp)
+{
+       struct parse_repo *rp;
+       char            *file;
+
+       /* build file path based on repoid, entity path and filename */
+       rp = repo_get(entp->repoid);
+       if (rp == NULL) {
+               if (entp->path == NULL) {
+                       if ((file = strdup(entp->file)) == NULL)
+                                       err(1, NULL);
+               } else {
+                       if (asprintf(&file, "%s/%s", entp->path,
+                           entp->file) == -1)
+                               err(1, NULL);
+               }
+       } else {
+               if (entp->path == NULL) {
+                       if (asprintf(&file, "%s/%s", rp->path,
+                           entp->file) == -1)
+                               err(1, NULL);
+               } else {
+                       if (asprintf(&file, "%s/%s/%s", rp->path,
+                           entp->path, entp->file) == -1)
+                               err(1, NULL);
+               }
+       }
+       return file;
+}
+
 static void
 parse_entity(struct entityq *q, struct msgbuf *msgq)
 {
@@ -555,23 +631,31 @@ parse_entity(struct entityq *q, struct m
        struct ibuf     *b;
        unsigned char   *f;
        size_t           flen;
+       char            *file;
        int              c;
 
        while ((entp = TAILQ_FIRST(q)) != NULL) {
                TAILQ_REMOVE(q, entp, entries);
 
-               b = io_new_buffer();
+               /* handle RTYPE_REPO first */
+               if (entp->type == RTYPE_REPO) {
+                       repo_add(entp->repoid, entp->path);
+                       entity_free(entp);
+                       continue;
+               }
 
                f = NULL;
+               file = parse_filepath(entp);
                if (entp->type != RTYPE_TAL) {
-                       f = load_file(entp->file, &flen);
+                       f = load_file(file, &flen);
                        if (f == NULL)
-                               warn("%s", entp->file);
+                               warn("%s", file);
                }
 
                /* pass back at least type and filename */
+               b = io_new_buffer();
                io_simple_buffer(b, &entp->type, sizeof(entp->type));
-               io_str_buffer(b, entp->file);
+               io_str_buffer(b, file);
 
                switch (entp->type) {
                case RTYPE_TAL:
@@ -585,11 +669,11 @@ parse_entity(struct entityq *q, struct m
                        break;
                case RTYPE_CER:
                        if (entp->data != NULL)
-                               cert = proc_parser_root_cert(entp->file,
+                               cert = proc_parser_root_cert(file,
                                    f, flen, entp->data, entp->datasz,
                                    entp->talid);
                        else
-                               cert = proc_parser_cert(entp->file, f, flen);
+                               cert = proc_parser_cert(file, f, flen);
                        c = (cert != NULL);
                        io_simple_buffer(b, &c, sizeof(int));
                        if (cert != NULL)
@@ -601,10 +685,11 @@ parse_entity(struct entityq *q, struct m
                         */
                        break;
                case RTYPE_CRL:
-                       proc_parser_crl(entp->file, f, flen);
+                       proc_parser_crl(file, f, flen);
                        break;
                case RTYPE_MFT:
-                       mft = proc_parser_mft(entp->file, f, flen);
+                       mft = proc_parser_mft(file, f, flen,
+                           entp->path, entp->repoid);
                        c = (mft != NULL);
                        io_simple_buffer(b, &c, sizeof(int));
                        if (mft != NULL)
@@ -612,7 +697,7 @@ parse_entity(struct entityq *q, struct m
                        mft_free(mft);
                        break;
                case RTYPE_ROA:
-                       roa = proc_parser_roa(entp->file, f, flen);
+                       roa = proc_parser_roa(file, f, flen);
                        c = (roa != NULL);
                        io_simple_buffer(b, &c, sizeof(int));
                        if (roa != NULL)
@@ -620,13 +705,14 @@ parse_entity(struct entityq *q, struct m
                        roa_free(roa);
                        break;
                case RTYPE_GBR:
-                       proc_parser_gbr(entp->file, f, flen);
+                       proc_parser_gbr(file, f, flen);
                        break;
                default:
-                       abort();
+                       errx(1, "unhandled entity type %d", entp->type);
                }
 
                free(f);
+               free(file);
                io_close_buffer(msgq, b);
                entity_free(entp);
        }
Index: repo.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/repo.c,v
retrieving revision 1.19
diff -u -p -r1.19 repo.c
--- repo.c      4 Jan 2022 18:16:09 -0000       1.19
+++ repo.c      7 Jan 2022 14:41:47 -0000
@@ -64,7 +64,7 @@ struct rrdprepo {
        unsigned int             id;
        enum repo_state          state;
 };
-SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
+static SLIST_HEAD(, rrdprepo)  rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
 
 struct rsyncrepo {
        SLIST_ENTRY(rsyncrepo)   entry;
@@ -73,7 +73,7 @@ struct rsyncrepo {
        unsigned int             id;
        enum repo_state          state;
 };
-SLIST_HEAD(, rsyncrepo)        rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
+static SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
 
 struct tarepo {
        SLIST_ENTRY(tarepo)      entry;
@@ -86,7 +86,7 @@ struct tarepo {
        unsigned int             id;
        enum repo_state          state;
 };
-SLIST_HEAD(, tarepo)   tarepos = SLIST_HEAD_INITIALIZER(tarepos);
+static SLIST_HEAD(, tarepo)    tarepos = SLIST_HEAD_INITIALIZER(tarepos);
 
 struct repo {
        SLIST_ENTRY(repo)        entry;
@@ -100,7 +100,7 @@ struct repo {
        int                      talid;
        unsigned int             id;            /* identifier */
 };
-SLIST_HEAD(, repo)     repos = SLIST_HEAD_INITIALIZER(repos);
+static SLIST_HEAD(, repo)      repos = SLIST_HEAD_INITIALIZER(repos);
 
 /* counter for unique repo id */
 unsigned int           repoid;
@@ -152,9 +152,8 @@ filepath_add(struct filepath_tree *tree,
 static struct filepath *
 filepath_find(struct filepath_tree *tree, char *file)
 {
-       struct filepath needle;
+       struct filepath needle = { .file = file };
 
-       needle.file = file;
        return RB_FIND(filepath_tree, tree, &needle);
 }
 
@@ -1146,39 +1145,66 @@ repo_lookup(int talid, const char *uri, 
        if (rp->rrdp == NULL)
                rp->rsync = rsync_get(uri, nofetch);
 
+       if (repo_state(rp) != REPO_LOADING)
+               entityq_flush(&rp->queue, rp);
+
        return rp;
 }
 
 /*
- * Build local file name base on the URI and the repo info.
+ * Find repository by identifier.
  */
-char *
-repo_filename(const struct repo *rp, const char *uri)
+struct repo *
+repo_byid(unsigned int id)
 {
-       char *nfile;
-       char *dir, *repouri;
+       struct repo     *rp;
 
-       if (uri == NULL && rp->ta)
-               return ta_filename(rp->ta, 0);
+       SLIST_FOREACH(rp, &repos, entry) {
+               if (rp->id == id)
+                       return rp;
+       }
+       return NULL;
+}
 
-       assert(uri != NULL);
-       if (rp->rrdp)
-               return rrdp_filename(rp->rrdp, uri, 0);
+/*
+ * Return the repository base directory.
+ * Returned string must be freed by caller.
+ */
+char *
+repo_basedir(const struct repo *rp)
+{
+       char *path;
 
-       /* must be rsync */
-       dir = rp->rsync->basedir;
-       repouri = rp->rsync->repouri;
+       if (rp->ta) {
+               if ((path = strdup(rp->ta->basedir)) == NULL)
+                       err(1, NULL);
+       } else if (rp->rsync) {
+               if ((path = strdup(rp->rsync->basedir)) == NULL)
+                       err(1, NULL);
+       } else if (rp->rrdp) {
+               path = rrdp_filename(rp->rrdp, rp->repouri, 0);
+       } else
+               errx(1, "%s: bad repo", rp->repouri);
 
-       if (strstr(uri, repouri) != uri) {
-               warnx("%s: URI %s outside of repository", repouri, uri);
-               return NULL;
-       }
+       return path;
+}
 
-       uri += strlen(repouri) + 1;     /* skip base and '/' */
+/*
+ * Return the repository identifier.
+ */
+unsigned int
+repo_id(const struct repo *rp)
+{
+       return rp->id;
+}
 
-       if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
-               err(1, NULL);
-       return nfile;
+/*
+ * Return the repository URI.
+ */
+const char *
+repo_uri(const struct repo *rp)
+{
+       return rp->repouri;
 }
 
 int
@@ -1220,10 +1246,10 @@ repo_fail(struct repo *rp)
 
        if (rp->ta)
                http_finish(rp->ta->id, HTTP_FAILED, NULL);
-       else if (rp->rrdp)
-               rrdp_finish(rp->rrdp->id, 0);
        else if (rp->rsync)
                rsync_finish(rp->rsync->id, 0);
+       else if (rp->rrdp)
+               rrdp_finish(rp->rrdp->id, 0);
        else
                errx(1, "%s: bad repo", rp->repouri);
 }

Reply via email to