From 4bda74184186dd0e1d4657a0e6ff5c869ff6492c Mon Sep 17 00:00:00 2001 From: "Chloe M." Date: Tue, 28 Jul 2026 00:26:15 -0400 Subject: packer: Flush data descriptor table to output Signed-off-by: Chloe M. --- core/rdar.c | 99 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 91 insertions(+), 8 deletions(-) diff --git a/core/rdar.c b/core/rdar.c index b3a7c64..405bca0 100644 --- a/core/rdar.c +++ b/core/rdar.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include @@ -37,7 +38,8 @@ struct idata_desc; (((VERSION) >> 8) & 0xFF) /* Pushes idata descriptor to table */ -#define IDATA_PUSH(IDATA_P) \ +#define IDATA_PUSH(IDATA_P) \ + ++d_desc_count; \ TAILQ_INSERT_TAIL(&d_desc_table, (IDATA_P), link); /* @@ -55,6 +57,19 @@ struct idata_desc; static const char *input_dir = NULL; static const char *output_path = NULL; static TAILQ_HEAD(, idata_desc) d_desc_table; +static size_t d_desc_count = 1; + +/* + * The root data region (RDR) contains information about the + * entire archive. + * + * @desc_count: Number of descriptors + * @revision: Format revision + */ +struct root_data_region { + size_t desc_count; + uint16_t revision; +}; /* * Represents a file that has been mapped into memory @@ -182,10 +197,11 @@ view_from_path(const char *path, struct file_view *result) /* * Allocate an internal data descriptor * - * @path: Path of file + * @path: Path of file + * @is_root: If set, don't create a view */ static struct idata_desc * -idata_from_file(const char *path) +idata_from_file(const char *path, bool is_root) { struct idata_desc *idata_desc; struct data_desc *data_desc; @@ -204,9 +220,11 @@ idata_from_file(const char *path) return NULL; } - if (view_from_path(path, &idata_desc->file) < 0) { - free(idata_desc); - return NULL; + if (!is_root) { + if (view_from_path(path, &idata_desc->file) < 0) { + free(idata_desc); + return NULL; + } } /* Initialize the data descriptor */ @@ -231,7 +249,7 @@ idata_push_root(void) { struct idata_desc *root; - root = idata_from_file("%root%"); + root = idata_from_file("%root%", true); if (root == NULL) { return -1; } @@ -257,6 +275,70 @@ idata_table_destroy(void) } } +static void +flush_root_desc(struct data_desc *d_desc, int out_fd) +{ + struct root_data_region rdr = { + .desc_count = d_desc_count, + .revision = RDAR_VERSION + }; + + d_desc->off = lseek(out_fd, 0, SEEK_CUR); + write(out_fd, &rdr, sizeof(rdr)); +} + +static void +idata_table_flush(void) +{ + const struct file_view *view; + struct idata_desc *desc_iter; + struct data_desc *d_desc; + off_t new_off; + int fd; + + fd = open(output_path, O_WRONLY | O_TRUNC | O_CREAT, 0666); + if (fd < 0) { + printf("fatal: failed to open output path\n"); + perror("open"); + return; + } + + new_off = d_desc_count * sizeof(struct data_desc); + lseek(fd, new_off, SEEK_SET); + + /* First pass write the file data */ + TAILQ_FOREACH(desc_iter, &d_desc_table, link) { + view = &desc_iter->file; + d_desc = &desc_iter->data; + + /* + * Check if we need to flush the root descriptor, we ignore any files that start + * with the '%' modifier. + */ + if (d_desc->path[0] == '%') { + if (strcmp(d_desc->path, "%root%") == 0) + flush_root_desc(d_desc, fd); + + continue; + } + + d_desc->off = lseek(fd, 0, SEEK_CUR); + write(fd, view->data, view->length); + } + + /* Data descriptors go at the start */ + lseek(fd, 0, SEEK_SET); + + /* Second pass write the data descriptors */ + TAILQ_FOREACH(desc_iter, &d_desc_table, link) { + view = &desc_iter->file; + d_desc = &desc_iter->data; + write(fd, d_desc, sizeof(*d_desc)); + } + + close(fd); +} + static void recurse_dir(const char *dirpath) { @@ -282,7 +364,7 @@ recurse_dir(const char *dirpath) snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, dirent->d_name); printf("[f] %s\n", pathbuf); - idata_desc = idata_from_file(pathbuf); + idata_desc = idata_from_file(pathbuf, false); if (idata_desc == NULL) { printf("warn: ignoring '%s'\n", pathbuf); break; @@ -352,6 +434,7 @@ main(int argc, char **argv) TAILQ_INIT(&d_desc_table); idata_push_root(); recurse_dir(input_dir); + idata_table_flush(); idata_table_destroy(); return 0; } -- cgit v1.2.3