~sircmpwn/koio

71d6bbd846f33f0da8fb709b07408413f5d5eb07 — Drew DeVault 4 years ago 38ffd8e
Add aliasing and reorder ko_fopen priorities

This lets you permit users to override embedded files by specifying
alternative paths they may be loaded from. This also prioritizes files
on the genuine filesystem over files embedded in the executable.
6 files changed, 82 insertions(+), 7 deletions(-)

M cat/main.c
M include/koio.h
M include/koio_private.h
A lib/ko_add_alias.c
M lib/ko_fopen.c
M meson.build
M cat/main.c => cat/main.c +6 -0
@@ 1,4 1,5 @@
#include <koio.h>
#include <stdlib.h>

void koio_load_assets(void);



@@ 6,6 7,11 @@ int main(int argc, char **argv) {
	// This source file is embedded in the executable as //main.c
	koio_load_assets();

	char *alias = getenv("KOIO_ROOT");
	if (alias) {
		ko_add_alias("//", alias);
	}

	for (int i = 1; i < argc; ++i) {
		FILE *f = ko_fopen(argv[i], "r");
		if (!f) {

M include/koio.h => include/koio.h +13 -0
@@ 4,6 4,7 @@

/** Makes the given file available at the specified path. */
void ko_add_file(const char *path, char *data, size_t len);

/** Removes the file at the specified path. */
void ko_del_file(const char *path);



@@ 20,4 21,16 @@ void ko_del_file(const char *path);
 */
FILE *ko_fopen(const char *path, const char *mode);

/**
 * Adds a path alias to the ko filesystem. If ko_fopen is called with a path
 * beginning with `prefix`, the prefix will be replaced with the alias and
 * attempted first. Then, the normal behavior of ko_fopen will proceed.
 *
 * You may add several aliases for the same prefix, they will be attempted in
 * the order they are added.
 *
 * A trailing path separator is not added to `path`.
 */
void ko_add_alias(const char *prefix, const char *path);

#endif

M include/koio_private.h => include/koio_private.h +8 -0
@@ 25,4 25,12 @@ struct file_entry {
	size_t len;
};

struct path_alias {
	char *prefix;
	char *path;
	struct path_alias *next;
};

extern struct path_alias koio_aliases;

#endif

A lib/ko_add_alias.c => lib/ko_add_alias.c +18 -0
@@ 0,0 1,18 @@
#define _POSIX_C_SOURCE 200809L
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "koio_private.h"

struct path_alias koio_aliases = {0};

void ko_add_alias(const char *prefix, const char *path) {
	struct path_alias *alias = calloc(1, sizeof(struct path_alias));
	alias->prefix = strdup(prefix);
	alias->path = strdup(path);
	struct path_alias *list = &koio_aliases;
	while (list->next) {
		list = list->next;
	}
	list->next = alias;
}

M lib/ko_fopen.c => lib/ko_fopen.c +36 -7
@@ 2,16 2,45 @@
#include <errno.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "koio_private.h"

FILE *ko_fopen(const char *path, const char *mode) {
	struct file_entry *entry = hashtable_get(&koio_vfs, path);
	if (entry) {
		if (mode[0] != 'r' || mode[1] != '\0') {
			errno = ENOTSUP;
			return NULL;
	FILE *f;
	struct path_alias *alias = koio_aliases.next;
	while (alias) {
		size_t alias_len = strlen(alias->prefix);
		if (strncmp(path, alias->prefix, alias_len) == 0) {
			char *unaliased_path = malloc(strlen(path) - alias_len);
			strcpy(unaliased_path, &path[alias_len]);
			size_t new_path_size = snprintf(NULL, 0,
					"%s%s", alias->path, &path[alias_len]);
			char *new_path = malloc(new_path_size + 1);
			if (!new_path) {
				continue;
			}
			snprintf(new_path, new_path_size + 1,
					"%s%s", alias->path, &path[alias_len]);
			if ((f = fopen(new_path, mode))) {
				free(new_path);
				return f;
			}
			free(new_path);
		}
		return fmemopen(entry->data, entry->len, "r");
		alias = alias->next;
	}

	f = fopen(path, mode);
	if (f) {
		return f;
	}
	struct file_entry *entry = hashtable_get(&koio_vfs, path);
	if (!entry) {
		return NULL;
	}
	if (mode[0] != 'r' || mode[1] != '\0') {
		errno = ENOTSUP;
		return NULL;
	}
	return fopen(path, mode);
	return fmemopen(entry->data, entry->len, "r");
}

M meson.build => meson.build +1 -0
@@ 25,6 25,7 @@ symbols_flag = '-Wl,--version-script,@0@/@1@'.format(
	meson.current_source_dir(), symbols_file)
lib_koio = library(meson.project_name(),
	[
		'lib/ko_add_alias.c',
		'lib/ko_add_file.c',
		'lib/ko_del_file.c',
		'lib/ko_fopen.c',