commit:     fd4260699ea0e13e6d33d4e0f3730150c2b780b0
Author:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
AuthorDate: Mon Aug 25 13:27:36 2025 +0000
Commit:     Fabian Groffen <grobian <AT> gentoo <DOT> org>
CommitDate: Mon Aug 25 13:27:36 2025 +0000
URL:        https://gitweb.gentoo.org/proj/portage-utils.git/commit/?id=fd426069

q: turn gtree into tar

Like GLEP-78, turn container into an uncompressed tar, such that we can
store a signature right next to the compressed data.

Signed-off-by: Fabian Groffen <grobian <AT> gentoo.org>

 q.c | 60 ++++++++++++++++++++++++++++++++++++++++++++++++++++++------
 1 file changed, 54 insertions(+), 6 deletions(-)

diff --git a/q.c b/q.c
index 325d19c..9fffb8a 100644
--- a/q.c
+++ b/q.c
@@ -723,22 +723,26 @@ int q_main(int argc, char **argv)
                struct archive       *a;
                struct archive_entry *entry;
                struct q_cache_ctx    qcctx;
+               struct stat           st;
                char                  buf[BUFSIZ];
                size_t                len;
+               ssize_t               rlen;
                int                   dfd;
+               int                   tfd;
 
                memset(&qcctx, 0, sizeof(qcctx));
 
                array_for_each(overlays, n, overlay) {
                        if (verbose)
-                               printf("building cache for %s\n", overlay);
+                               printf("building cache for 
%s%s%s/metadata/repo.gtree.tar\n",
+                                          BLUE, overlay, NORM);
 
                        /* we store the cache inside the metadata dir, which 
means
                         * it gets wiped on portage sync (good because that 
would
                         * invalidate it) and tree_open can transparently 
locate and
                         * use it */
                        snprintf(buf, sizeof(buf),
-                                        "%s/metadata/repo.gtree.tar.zst", 
overlay);
+                                        "%s/metadata/repo.gtree.tar", overlay);
                        /* because we're building a new one here, make sure
                         * tree_open doesn't pick it up */
                        unlink(buf);
@@ -761,10 +765,8 @@ int q_main(int argc, char **argv)
 
                        a = archive_write_new();
                        archive_write_set_format_ustar(a);  /* GLEP-78, just to 
be safe */
-                       archive_write_add_filter_zstd(a); /* TODO: reuse func 
from qpkg */
                        archive_write_open_filename(a, buf);
 
-                       qcctx.archive   = a;
                        qcctx.buildtime = time(NULL);
 
                        /* add marker file, we populate with our version, 
although
@@ -780,6 +782,30 @@ int q_main(int argc, char **argv)
                        archive_write_data(a, buf, len);
                        archive_entry_free(entry);
 
+                       /* repo.tar.zst
+                        * the nested archive unfortunately cannot be written
+                        * straight to the archive stream above: its size needs 
to
+                        * be known before data can be written, hence we'll 
have to
+                        * produce the archive separately first, which sulks, 
but ok
+                        * in order to kind of protect it from being modified, 
we
+                        * make the file invisible */
+                       snprintf(buf, sizeof(buf),
+                                        "%s/metadata/gtree.XXXXXX", overlay);
+                       tfd = mkstemp(buf);
+                       if (tfd < 0) {
+                               warnp("failed to open temp file");
+                               tree_close(t);
+                               archive_write_close(a);
+                               archive_write_free(a);
+                               continue;
+                       }
+                       unlink(buf);  /* make invisible, drop on close */
+
+                       qcctx.archive = archive_write_new();
+                       archive_write_set_format_ustar(qcctx.archive);
+                       archive_write_add_filter_zstd(qcctx.archive);
+                       archive_write_open_fd(qcctx.archive, tfd);
+
                        /* write repo name, if any */
                        if (t->repo != 0) {
                                len = strlen(t->repo);
@@ -789,8 +815,8 @@ int q_main(int argc, char **argv)
                                archive_entry_set_mtime(entry, qcctx.buildtime, 
0);
                                archive_entry_set_filetype(entry, AE_IFREG);
                                archive_entry_set_perm(entry, 0644);
-                               archive_write_header(a, entry);
-                               archive_write_data(a, t->repo, len);
+                               archive_write_header(qcctx.archive, entry);
+                               archive_write_data(qcctx.archive, t->repo, len);
                                archive_entry_free(entry);
                        }
 
@@ -808,6 +834,28 @@ int q_main(int argc, char **argv)
                                close(dfd);
                        }
 
+                       archive_write_close(qcctx.archive);
+                       archive_write_free(qcctx.archive);
+
+                       /* now we got the size, put it in the main archive */
+                       fstat(tfd, &st);
+                       entry = archive_entry_new();
+                       archive_entry_set_pathname(entry, "repo.tar.zst");
+                       archive_entry_set_size(entry, st.st_size);
+                       archive_entry_set_mtime(entry, qcctx.buildtime, 0);
+                       archive_entry_set_filetype(entry, AE_IFREG);
+                       archive_entry_set_perm(entry, 0644);
+                       archive_write_header(a, entry);
+                       lseek(tfd, 0, SEEK_SET);  /* reposition at the start of 
file */
+                       while ((rlen = read(tfd, buf, sizeof(buf))) > 0)
+                               archive_write_data(a, buf, rlen);
+                       archive_entry_free(entry);
+
+                       /* TODO: compute and put .sig in here */
+
+                       /* cleanup repo archive */
+                       close(tfd);
+
                        tree_close(t);
                        archive_write_close(a);
                        archive_write_free(a);

Reply via email to