diff --git a/.gitignore b/.gitignore index 6d1d361..a1e3267 100644 --- a/.gitignore +++ b/.gitignore @@ -1,2 +1,3 @@ /hole +/cumxct *.o diff --git a/Makefile b/Makefile index 1d6f875..8cbe421 100644 --- a/Makefile +++ b/Makefile @@ -7,8 +7,12 @@ # .PHONY: all -all: core +all: core extractor .PHONY: core core: cd core/; $(MAKE) + +.PHONY: extractor +extractor: + cd extractor/; $(MAKE) diff --git a/extractor/Makefile b/extractor/Makefile new file mode 100644 index 0000000..1a7e189 --- /dev/null +++ b/extractor/Makefile @@ -0,0 +1,23 @@ +# +# Copyright (c) 2026, Chloe M. +# Provided under the BSD-3 clause +# +# Description: Cum extractor build script +# Author: Chloe M. +# + +include ../mk/global.mk +.SILENT: + +CFILES = $(shell find . -name "*.c") +OFILES = $(CFILES:.c=.o) + +.PHONY: all +all: ../cumxct + +.PHONY: hole +../cumxct: $(OFILES) + $(CC) $^ -o $@ + +%.o: %.c + $(CC) -c $(CFLAGS) $< -o $@ diff --git a/extractor/cum_xct.c b/extractor/cum_xct.c new file mode 100644 index 0000000..07da0ad --- /dev/null +++ b/extractor/cum_xct.c @@ -0,0 +1,140 @@ +/* + * Copyright (c) 2026, Chloe M. + * Provided under the BSD-3 clause. + * + * Description: CUMHOLE extraction module + * Author: Chloe M. + */ + +#include +#include +#include +#include +#include +#include + +#define REF_MAGIC "CUMHOLE" +#define REF_MAGIC_LEN 8 +#define REF_PATH_LEN 256 + +/* + * The offset table is made up of references, this + * structure represents a reference. + * + * @magic: Reference magic number + * @path: Path this reference refers to + * @size: Size of data being referenced + * @data_off: Offset to data being referenced + */ +struct hole_ref { + char magic[REF_MAGIC_LEN]; + char path[REF_PATH_LEN]; + size_t size; + size_t data_off; +} __attribute__((packed)); + +/* Globals */ +static char *input_path = NULL; + +static void +help(void) +{ + printf("usage: ./cumxct [flags]\n"); + printf("[-h] Display this help menu\n"); + printf("[-i] Input CUMHOLE bundle\n"); +} + +static void +do_parse(struct hole_ref *ref) +{ + if (ref == NULL) { + return; + } + + for (;;) { + if (memcmp(ref->magic, REF_MAGIC, REF_MAGIC_LEN) != 0) { + break; + } + + printf("found '%s' with size %ld\n", ref->path, ref->size); + ++ref; + } +} + +static void +input_parse(void) +{ + int fd; + char *data; + size_t archive_size; + ssize_t nret; + + fd = open(input_path, O_RDONLY); + if (fd < 0) { + printf("fatal: could not open input file\n"); + perror("open"); + return; + } + + /* Obtain the size of the buffer */ + archive_size = lseek(fd, 0, SEEK_END); + lseek(fd, 0, SEEK_SET); + + /* Allocate the actual buffer */ + data = malloc(archive_size); + if (data == NULL) { + printf("fatal: could not allocate archive buffer\n"); + close(fd); + return; + } + + /* Populate it with bytes */ + nret = read(fd, data, archive_size); + if (nret <= 0) { + printf("fatal: could not read archive\n"); + perror("read"); + return; + } + + do_parse((struct hole_ref *)data); + close(fd); + free(data); +} + +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, "hi:")) != -1) { + switch (opt) { + case 'h': + help(); + return -1; + case 'i': + input_path = strdup(optarg); + if (input_path == NULL) { + printf("fatal: out of memory\n"); + return -1; + } + + break; + } + } + + if (input_path == NULL) { + printf("fatal: expected input bundle\n"); + help(); + return -1; + } + + input_parse(); + free(input_path); + return 0; +}