summaryrefslogtreecommitdiff
path: root/core/rdar.c
diff options
context:
space:
mode:
authorChloe M. <chloe@faracom.org>2026-07-28 00:26:15 -0400
committerChloe M. <chloe@faracom.org>2026-07-28 00:26:15 -0400
commit4bda74184186dd0e1d4657a0e6ff5c869ff6492c (patch)
tree62816448bdeda14c2bb08e778e869aefee0e10ac /core/rdar.c
parent12ada77d1c0d62adb90409f25e4812f9ebf1ba7a (diff)
packer: Flush data descriptor table to output
Signed-off-by: Chloe M. <chloe@faracom.org>
Diffstat (limited to 'core/rdar.c')
-rw-r--r--core/rdar.c99
1 files 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 <stdint.h>
#include <stddef.h>
#include <stdlib.h>
+#include <stdbool.h>
#include <dirent.h>
#include <string.h>
@@ -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;
}
@@ -258,6 +276,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)
{
DIR *dir;
@@ -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;
}