848b52f0a4
Signed-off-by: Chloe M. <chloe@mensia.org>
207 lines
4.0 KiB
C
207 lines
4.0 KiB
C
/*
|
|
* Copyright (c) 2026, Chloe M.
|
|
* Provided under the BSD-3 clause.
|
|
*
|
|
* Description: CUMHOLE extraction module
|
|
* Author: Chloe M.
|
|
*/
|
|
|
|
#include <sys/stat.h>
|
|
#include <stdio.h>
|
|
#include <unistd.h>
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
#include <fcntl.h>
|
|
#include <stddef.h>
|
|
#include <libgen.h>
|
|
|
|
#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
|
|
mkdir_recurse(const char *path)
|
|
{
|
|
char buf[256];
|
|
char *p = NULL;
|
|
size_t len;
|
|
|
|
snprintf(buf, sizeof(buf), "%s", path);
|
|
len = strlen(buf);
|
|
|
|
/* Strip trailing slash */
|
|
if (buf[len - 1] == '/')
|
|
buf[len - 1] = '\0';
|
|
|
|
/* Make directory of each component */
|
|
for (p = buf; *p != '\0'; ++p) {
|
|
if (*p == '/') {
|
|
*p = '\0';
|
|
mkdir(buf, S_IRWXU);
|
|
*p = '/';
|
|
}
|
|
}
|
|
|
|
mkdir(buf, S_IRWXU);
|
|
}
|
|
|
|
static void
|
|
help(void)
|
|
{
|
|
printf("usage: ./cumxct [flags]\n");
|
|
printf("[-h] Display this help menu\n");
|
|
printf("[-i] Input CUMHOLE bundle\n");
|
|
}
|
|
|
|
static int
|
|
push_file(const char *path, void *data, size_t size)
|
|
{
|
|
int fd;
|
|
|
|
if (path == NULL || data == NULL) {
|
|
return -1;
|
|
}
|
|
|
|
fd = open(path, O_RDWR | O_CREAT, 0777);
|
|
if (fd < 0) {
|
|
printf("fatal: failed to open '%s'\n", path);
|
|
perror("open");
|
|
return -1;
|
|
}
|
|
|
|
write(fd, data, size);
|
|
close(fd);
|
|
return 0;
|
|
}
|
|
|
|
static void
|
|
do_parse(struct hole_ref *ref)
|
|
{
|
|
const char *directory_name;
|
|
struct hole_ref *ref_base = ref;
|
|
char *path;
|
|
void *data;
|
|
|
|
if (ref == NULL) {
|
|
return;
|
|
}
|
|
|
|
for (;;) {
|
|
if (memcmp(ref->magic, REF_MAGIC, REF_MAGIC_LEN) != 0) {
|
|
break;
|
|
}
|
|
|
|
path = strdup(ref->path);
|
|
directory_name = dirname(path);
|
|
mkdir_recurse(directory_name);
|
|
|
|
printf("creating %s\n", ref->path);
|
|
data = (void *)((char *)ref_base + ref->data_off);
|
|
|
|
if (push_file(ref->path, data, ref->size) < 0) {
|
|
free(path);
|
|
return;
|
|
}
|
|
|
|
free(path);
|
|
++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;
|
|
}
|