~sircmpwn/koio

12652085bf2fa712c19b23c8a1f029888aeeb3a4 — Drew DeVault 4 years ago
Initial commit

Basic shit and support code
A  => .gitignore +1 -0
@@ 1,1 @@
build

A  => include/koio.h +23 -0
@@ 1,23 @@
#ifndef _KOIO_H
#define _KOIO_H
#include <stdio.h>

/** 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);

/**
 * See fopen(3)
 *
 * Attempts to open a file in the koio filesystem and falls back to the genuine
 * filesystem if not found.
 *
 * The koio filesystem only supports mode="r". If you specify anything else for
 * a file which _does_ exist in the koio filesystem, NULL will be returned and
 * errno set. If you specify anything else for a file which _does not_ exist in
 * the koio filesystem, the mode string will be passed directly to fopen(3).
 */
FILE *ko_fopen(const char *path, const char *mode);

#endif

A  => include/koio_private.h +28 -0
@@ 1,28 @@
#ifndef _KOIO_PRIVATE_H
#define _KOIO_PRIVATE_H
#include <stdbool.h>

struct hashtable_entry {
	struct hashtable_entry *next;
	unsigned int hash;
	char *key;
	void *value;
};

struct hashtable {
	unsigned int (*hash)(const void *);
	struct hashtable_entry *buckets[256];
};

extern struct hashtable koio_vfs;

void *hashtable_get(struct hashtable *table, const char *key);
void *hashtable_set(struct hashtable *table, const char *key, void *value);
void *hashtable_del(struct hashtable *table, const void *key);

struct file_entry {
	char *data;
	size_t len;
};

#endif

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

static const int buckets_size = sizeof(((struct hashtable *)0)->buckets) /
	sizeof(struct hashtable_entry );

static unsigned int djb2(const char *str) {
	unsigned int hash = 5381;
	char c;
	while ((c = *str++)) {
		hash = ((hash << 5) + hash) + c;
	}
	return hash;
}

void *hashtable_get(struct hashtable *table, const char *key) {
	unsigned int hash = djb2(key);
	unsigned int bucket = hash % buckets_size;
	struct hashtable_entry *entry = table->buckets[bucket];
	if (entry) {
		if (entry->hash != hash) {
			while (entry->next) {
				entry = entry->next;
				if (!entry || (entry->hash == hash &&
							strcmp(entry->key, key) == 0)) {
					break;
				}
			}
		}
	} else {
		return NULL;
	}
	return entry->value;
}

void *hashtable_set(struct hashtable *table, const char *key, void *value) {
	unsigned int hash = djb2(key);
	unsigned int bucket = hash % buckets_size;
	struct hashtable_entry *entry = table->buckets[bucket];
	struct hashtable_entry *previous = NULL;

	if (entry) {
		if (entry->hash != hash) {
			while (entry->next) {
				previous = entry;
				entry = entry->next;
				if (!entry || (entry->hash == hash &&
							strcmp(entry->key, key) == 0)) {
					break;
				}
			}
		}
	}

	if (entry == NULL) {
		entry = calloc(1, sizeof(struct hashtable_entry));
		entry->hash = hash;
		entry->key = strdup(key);
		table->buckets[bucket] = entry;
		if (previous) {
			previous->next = entry;
		}
	}

	void *old = entry->value;
	entry->value = value;
	return old;
}

void *hashtable_del(struct hashtable *table, const void *key) {
	unsigned int hash = djb2(key);
	unsigned int bucket = hash % buckets_size;
	struct hashtable_entry *entry = table->buckets[bucket];
	struct hashtable_entry *previous = NULL;

	if (entry) {
		if (entry->hash != hash) {
			while (entry->next) {
				previous = entry;
				entry = entry->next;
				if (!entry || (entry->hash == hash &&
							strcmp(entry->key, key) == 0)) {
					break;
				}
			}
		}
	}

	if (entry == NULL) {
		return NULL;
	} else {
		void *old = entry->value;
		if (previous) {
			previous->next = entry->next;
		} else {
			table->buckets[bucket] = NULL;
		}
		free(entry->key);
		free(entry);
		return old;
	}
}

A  => lib/ko_add_file.c +14 -0
@@ 1,14 @@
#include <stdlib.h>
#include "koio_private.h"

struct hashtable koio_vfs = {0};

void ko_add_file(const char *path, char *data, size_t len) {
	struct file_entry *entry = calloc(1, sizeof(struct file_entry));
	entry->data = data;
	entry->len = len;
	struct file_entry *prev = hashtable_set(&koio_vfs, path, entry);
	if (prev) {
		free(prev);
	}
}

A  => lib/ko_del_file.c +9 -0
@@ 1,9 @@
#include <stdlib.h>
#include "koio_private.h"

void ko_del_file(const char *path) {
	struct file_entry *prev = hashtable_del(&koio_vfs, path);
	if (prev) {
		free(prev);
	}
}

A  => lib/ko_fopen.c +17 -0
@@ 1,17 @@
#define _POSIX_C_SOURCE 200809L
#include <errno.h>
#include <stdlib.h>
#include <stdio.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;
		}
		return fmemopen(entry->data, entry->len, "r");
	}
	return fopen(path, mode);
}

A  => meson.build +36 -0
@@ 1,36 @@
project(
	'koio',
	'c',
	version: '0.0.1',
	license: 'MIT',
	meson_version: '>=0.43.0',
	default_options: [
		'c_std=c11',
		'warning_level=2',
		'werror=true',
	],
)

# Format of so_version is CURRENT, REVISION, AGE.
# See: https://autotools.io/libtool/version.html
# for a reference about clean library versioning.
so_version = ['0', '0', '0']

add_project_arguments('-Wno-unused-parameter', language: 'c')

koio_inc = include_directories('include')

#symbols_file = 'wlroots.syms'
#symbols_flag = '-Wl,--version-script,@0@/@1@'.format(meson.current_source_dir(), symbols_file)
lib_koio = library(meson.project_name(),
	[
		'lib/ko_add_file.c',
		'lib/ko_del_file.c',
		'lib/ko_fopen.c',
		'lib/hashtable.c'
	],
	version: '.'.join(so_version),
	include_directories: koio_inc,
	install: true,
	#link_args: symbols_flag,
)