summaryrefslogtreecommitdiff
path: root/core/rdar.c
diff options
context:
space:
mode:
authorChloe M <chloe@faracom.org>2026-08-19 21:54:30 -0500
committerChloe M <chloe@faracom.org>2026-08-19 21:55:30 -0500
commit6a65f0c024c56caa0a9f81db42f4881be6838f1d (patch)
tree990f0bbcd16763188952204ed935be74cfe45a10 /core/rdar.c
parent291945f30496d2c41960b98c75e61871358f40a2 (diff)
project: core -> packer
Signed-off-by: Chloe M <chloe@faracom.org>
Diffstat (limited to 'core/rdar.c')
-rw-r--r--core/rdar.c453
1 files changed, 0 insertions, 453 deletions
diff --git a/core/rdar.c b/core/rdar.c
deleted file mode 100644
index ba67c69..0000000
--- a/core/rdar.c
+++ /dev/null
@@ -1,453 +0,0 @@
-/*
- * Copyright (c) 2026, Chloe M.
- * Provided under the BSD-3 clause.
- */
-
-#define _DEFAULT_SOURCE
-#include <sys/stat.h>
-#include <sys/mman.h>
-#include <sys/queue.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stddef.h>
-#include <stdlib.h>
-#include <stdbool.h>
-#include <dirent.h>
-#include <string.h>
-
-/* Forward declarations */
-struct idata_desc;
-
-/* Data descriptor constants */
-#define RDAR_MAX_PATHLEN 32
-#define RDAR_MAGIC ">RDAR!"
-#define RDAR_MAGIC_LEN 6
-
-/* Data descriptor file flags */
-#define DATA_ROOT (1 << 0) /* Is root data descriptor */
-#define DATA_AVL (1 << 1) /* Available to consumer software; not touched by us */
-
-/* Version conversion macros */
-#define VERSION_U16(MAJOR, MINOR) \
- (((MINOR) << 8) | (MAJOR))
-#define VERSION_MAJOR(VERSION) \
- ((VERSION) & 0xFF)
-#define VERSION_MINOR(VERSION) \
- (((VERSION) >> 8) & 0xFF)
-
-/* Pushes idata descriptor to table */
-#define IDATA_PUSH(IDATA_P) \
- ++d_desc_count; \
- TAILQ_INSERT_TAIL(&d_desc_table, (IDATA_P), link);
-
-/*
- * Software version
- *
- * XXX: We encode it as a U16 so that we may bundle it
- * with the file data as binary.
- */
-#define RDAR_VERSION VERSION_U16(1, 0) /* v1.0 */
-
-/* Fallback path if '-o' is not specified */
-#define FALLBACK_OUTPUT_PATH "out.rdar"
-
-/* Globals */
-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 = 0;
-
-/*
- * 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
- *
- * @data: File data
- * @length: Length of data
- */
-struct file_view {
- char *data;
- size_t length;
-};
-
-/*
- * A data descriptor holds information about a specific
- * file along with an offset to which it is located at
- * in the offset.
- *
- * @magic: Format magic
- * @path: File path
- * @off: File data offset
- * @flags: File flags
- * @length: File length in bytes
- */
-struct data_desc {
- char magic[RDAR_MAGIC_LEN];
- char path[RDAR_MAX_PATHLEN];
- off_t off;
- uint16_t flags;
- size_t length;
-};
-
-/*
- * Internal data descriptor, used to hold data
- * before being flushed to the archive
- *
- * @data: Actual data descriptor
- * @file: File view this descriptor references
- * @link: TAILQ link
- */
-struct idata_desc {
- struct data_desc data;
- struct file_view file;
- TAILQ_ENTRY(idata_desc) link;
-};
-
-static void
-help(void)
-{
- printf("usage: ./rdar <... flags>\n");
- printf("[-h] Display this help menu\n");
- printf("[-v] Display the program version\n");
- printf("[-i] Input directory to pack\n");
- printf("[-o] Output path for archive file\n");
-}
-
-static void
-version(void)
-{
- uint16_t Major, Minor;
-
- Major = VERSION_MAJOR(RDAR_VERSION);
- Minor = VERSION_MINOR(RDAR_VERSION);
- printf("Version v%d.%d\n", Major, Minor);
-}
-
-/*
- * Destroy a file view
- *
- * @view: View to destory
- */
-static void
-view_destroy(struct file_view *view)
-{
- munmap(view->data, view->length);
- view->data = NULL;
- view->length = 0;
-}
-
-/*
- * Create a mapped file view from a file path
- */
-static int
-view_from_path(const char *path, struct file_view *result)
-{
- struct stat sb;
- int fd;
-
- if (path == NULL || result == NULL) {
- return -1;
- }
-
- fd = open(path, O_RDONLY);
- if (fd < 0) {
- printf("fatal: failed to open '%s'\n", path);
- perror("open");
- return -1;
- }
-
- if (stat(path, &sb) < 0) {
- printf("fatal: failed to stat '%s'\n", path);
- perror("stat");
- close(fd);
- return -1;
- }
-
- result->data = mmap(
- NULL,
- sb.st_size,
- PROT_READ,
- MAP_SHARED,
- fd,
- 0
- );
-
- if (result->data == NULL) {
- printf("fatal: failed to map '%s'\n", path);
- perror("mmap");
- close(fd);
- return -1;
- }
-
- result->length = sb.st_size;
- close(fd);
- return 0;
-}
-
-/*
- * Allocate an internal data descriptor
- *
- * @path: Path of file
- * @is_root: If set, don't create a view
- */
-static struct idata_desc *
-idata_from_file(const char *path, bool is_root)
-{
- struct idata_desc *idata_desc;
- struct data_desc *data_desc;
- size_t path_len;
- const char *p;
-
- path_len = strlen(path);
- if (path_len >= RDAR_MAX_PATHLEN - 1) {
- printf("fatal: path '%s' is too long!\n", path);
- return NULL;
- }
-
- idata_desc = malloc(sizeof(*idata_desc));
- if (idata_desc == NULL) {
- printf("fatal: failed to allocate idata_desc\n");
- printf("* last file processed: %s\n", path);
- return NULL;
- }
-
- if (!is_root) {
- if (view_from_path(path, &idata_desc->file) < 0) {
- free(idata_desc);
- return NULL;
- }
- }
-
- p = path;
-
- /* Strip leading path stuff */
- while (*p == '.' && *p != '\0')
- ++p;
- while (*p == '/' && *p != '\0')
- ++p;
-
- /* Initialize the data descriptor */
- data_desc = &idata_desc->data;
- memcpy(data_desc->magic, RDAR_MAGIC, RDAR_MAGIC_LEN);
- memcpy(data_desc->path, p, strlen(p));
- data_desc->path[path_len] = '\0';
- data_desc->flags = 0;
- data_desc->off = 0;
- return idata_desc;
-}
-
-/*
- * Push the root descriptor to the table.
- *
- * The root descriptor is to contain an offset into a special
- * %root% file entry which contains data (e.g., version, file count)
- * encoded within.
- */
-static int
-idata_push_root(void)
-{
- struct idata_desc *root;
- struct data_desc *desc;
-
- root = idata_from_file("%root%", true);
- if (root == NULL) {
- return -1;
- }
-
- desc = &root->data;
- desc->length = sizeof(struct root_data_region);
- desc->flags = DATA_ROOT;
- IDATA_PUSH(root);
- return 0;
-}
-
-static void
-idata_table_destroy(void)
-{
- struct idata_desc *desc, *next;
-
- desc = TAILQ_FIRST(&d_desc_table);
- while (desc != NULL) {
- view_destroy(&desc->file);
- next = TAILQ_NEXT(desc, link);
- TAILQ_REMOVE(&d_desc_table, desc, link);
- desc = next;
- }
-}
-
-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);
- d_desc->length = view->length;
- 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;
- struct dirent *dirent;
- struct idata_desc *idata_desc;
- char pathbuf[264];
-
- dir = opendir(dirpath);
- if (dir == NULL) {
- printf("fatal: failed to open '%s'\n", input_dir);
- perror("opendir");
- return;
- }
-
- while ((dirent = readdir(dir)) != NULL) {
- if (dirent->d_name[0] == '.') {
- continue;
- }
-
- switch (dirent->d_type) {
- case DT_REG:
- snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, dirent->d_name);
- printf("[f] %s\n", pathbuf);
-
- idata_desc = idata_from_file(pathbuf, false);
- if (idata_desc == NULL) {
- printf("warn: ignoring '%s'\n", pathbuf);
- break;
- }
-
- IDATA_PUSH(idata_desc);
- break;
- case DT_DIR:
- snprintf(pathbuf, sizeof(pathbuf), "%s/%s", dirpath, dirent->d_name);
- printf("[d] %s\n", pathbuf);
- recurse_dir(pathbuf);
- break;
- }
- }
-
- closedir(dir);
-}
-
-int
-main(int argc, char **argv)
-{
- int opt;
-
- if (argc < 2) {
- printf("fatal: too few arguments\n");
- help();
- return -1;
- }
-
- while ((opt = getopt(argc, argv, "hvi:o:")) != -1) {
- switch (opt) {
- case 'h':
- help();
- return -1;
- case 'v':
- version();
- return -1;
- case 'i':
- input_dir = strdup(optarg);
- if (input_dir == NULL) {
- printf("fatal: failed to allocate input_dir\n");
- return -1;
- }
-
- break;
- case 'o':
- output_path = strdup(optarg);
- if (output_path == NULL) {
- printf("fatal: failed to allocate output dir\n");
- return -1;
- }
-
- break;
- }
- }
-
- if (input_dir == NULL) {
- printf("fatal: input path not specified\n");
- help();
- return -1;
- }
-
- if (output_path == NULL) {
- output_path = FALLBACK_OUTPUT_PATH;
- }
-
- TAILQ_INIT(&d_desc_table);
- idata_push_root();
- recurse_dir(input_dir);
- idata_table_flush();
- idata_table_destroy();
- return 0;
-}