aboutsummaryrefslogtreecommitdiff
path: root/c_implementation/src
diff options
context:
space:
mode:
Diffstat (limited to 'c_implementation/src')
-rw-r--r--c_implementation/src/ak_datetime.c70
-rw-r--r--c_implementation/src/ak_fs.c383
-rw-r--r--c_implementation/src/ak_fs_defuse.c98
-rw-r--r--c_implementation/src/ak_fs_main.c51
-rw-r--r--c_implementation/src/ak_fs_map_v3.c213
-rw-r--r--c_implementation/src/ak_fs_map_v4.c8
-rw-r--r--c_implementation/src/ak_fs_maps_v3.c98
-rw-r--r--c_implementation/src/ak_fs_mt.c52
-rw-r--r--c_implementation/src/ak_fs_sha512sum.c221
-rw-r--r--c_implementation/src/ak_log.c246
-rw-r--r--c_implementation/src/ak_log_main.c32
-rw-r--r--c_implementation/src/ak_logcatter.c36
-rw-r--r--c_implementation/src/ak_settings.c153
-rw-r--r--c_implementation/src/ak_utils.c8
14 files changed, 1669 insertions, 0 deletions
diff --git a/c_implementation/src/ak_datetime.c b/c_implementation/src/ak_datetime.c
new file mode 100644
index 0000000..71dcb18
--- /dev/null
+++ b/c_implementation/src/ak_datetime.c
@@ -0,0 +1,70 @@
+#include <libakdatetime.h>
+#include <stdio.h>
+#include <time.h>
+#include <string.h>
+#include <stdbool.h>
+#include <ctype.h>
+#include <stdlib.h>
+
+// Returns Unix timestamp (seconds since epoch)
+long ak_datetime_unix() {
+ return time(NULL);
+}
+
+// Returns Unix timestamp with nanoseconds
+void ak_datetime_unix_nanosecs(char *buffer, size_t size) {
+ struct timespec ts;
+ clock_gettime(CLOCK_REALTIME, &ts);
+ snprintf(buffer, size, "%ld.%09ld", ts.tv_sec, ts.tv_nsec);
+}
+
+// Returns human-readable datetime in format YYYYMMDD_HHMMSS
+void ak_datetime_human(char *buffer, size_t size) {
+ time_t now = time(NULL);
+ const struct tm *tm = gmtime(&now);
+ strftime(buffer, size, "%Y%m%d_%H%M%S", tm);
+}
+
+// Returns human-readable date in format YYYYMMDD
+void ak_datetime_human_date_only(char *buffer, size_t size) {
+ time_t now = time(NULL);
+ const struct tm *tm = gmtime(&now);
+ strftime(buffer, size, "%Y%m%d", tm);
+}
+
+// Returns yesterday's date in format YYYYMMDD
+void ak_datetime_human_date_only_yesterday(char *buffer, size_t size) {
+ time_t now = time(NULL);
+ now -= 24 * 60 * 60; // Subtract one day
+ const struct tm *tm = gmtime(&now);
+ strftime(buffer, size, "%Y%m%d", tm);
+}
+
+// Checks if string contains only digits
+static bool is_digits_only(const char *str) {
+ while (*str) {
+ if (!isdigit(*str)) {
+ return false;
+ }
+ str++;
+ }
+ return true;
+}
+
+// Converts Unix timestamp to human-readable format YYYYMMDD_HHMMSS
+bool ak_datetime_unix_to_human(const char *timestamp_str, char *buffer, size_t size) {
+ // Check if input is valid (10-digit number)
+ if (timestamp_str == NULL || strlen(timestamp_str) != 10 || !is_digits_only(timestamp_str)) {
+ return false;
+ }
+
+ time_t timestamp = (time_t)atol(timestamp_str);
+ const struct tm *tm = gmtime(&timestamp);
+ if (tm == NULL) {
+ return false;
+ }
+
+ strftime(buffer, size, "%Y%m%d_%H%M%S", tm);
+ return true;
+}
+
diff --git a/c_implementation/src/ak_fs.c b/c_implementation/src/ak_fs.c
new file mode 100644
index 0000000..8ede3f6
--- /dev/null
+++ b/c_implementation/src/ak_fs.c
@@ -0,0 +1,383 @@
+#include <stdio.h>
+#include <unistd.h>
+#include <stdbool.h>
+#include <assert.h>
+#include <stdlib.h>
+#include <string.h>
+#include <libakfs.h>
+#include <libaklog.h>
+#include <libaksettings.h>
+#include <sys/stat.h>
+#include <dirent.h>
+
+char* ak_fs_return_hash_path(const char* str)
+{
+ if ( ak_fs_verify_input_is_hash(str, strlen(str)) )
+ {
+ unsigned int i = 0;
+ char *result = malloc((128*2)+1);
+ if ( result == NULL )
+ {
+ return "";
+ }
+ while ( str[i] != '\0' )
+ {
+ result[i*2] = str[i];
+ if ( (i*2) + 1 <= 254 )
+ {
+ result[(i*2)+1] = '/';
+ }
+ else
+ {
+ result[(i*2)+1] = '\0';
+ }
+ ++i;
+ }
+ return result;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+char* ak_fs_return_hash_dir(const char* str)
+{
+ if ( ak_fs_verify_input_is_hash(str, strlen(str)) )
+ {
+ unsigned int i = 0;
+ char *result = malloc((128*2)+1);
+ if ( result == NULL ) return "";
+ while ( str[i] != '\0' )
+ {
+ result[i*2] = str[i];
+ if ( (i*2) + 1 <= 254-2 )
+ {
+ result[(i*2)+1] = '/';
+ }
+ else
+ {
+ result[(i*2)+1] = '\0';
+ }
+ ++i;
+ }
+ return result;
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+bool ak_fs_verify_input_is_hash(const char* str, size_t len)
+{
+ size_t i = 0;
+ if (len != 128)
+ {
+ return false;
+ }
+ while ( str[i] != '\0' )
+ {
+ if (
+ i < 128 &&
+ !(
+ ( str[i] >= 0x30 ) &&
+ ( str[i] <= 0x39 || str[i] >= 0x61 ) &&
+ ( str[i] <= 0x66 )
+ )
+ )
+ {
+ return false;
+ }
+ else {
+ i++;
+ }
+ }
+ if ( i > 128 )
+ {
+ return false;
+ }
+ return true;
+}
+
+int ak_fs_create_dir_for_hash(const char* str)
+{
+ /* TODO
+ * Some aspects of this function
+ * 1. We need a "root" place to put our dirs into, this is not specified
+ * anywhere in this code but it is spartially specified in other files
+ * like lib/_ak_fs bash script and the rc/config file we currently source
+ * in $HOME/.bashrc
+ * 2. We might need to "lock" onto some version of glibc and be aware of
+ * other systems that do not use that one.
+ */
+ if ( ak_fs_verify_input_is_hash(str, strlen(str)) )
+ {
+ char* dir_path = ak_fs_return_hash_dir(str);
+ // We will need to separate the string so we can create the path one
+ // directory at the time
+ int len = strlen(dir_path);
+ for ( int i = 0; i < len+1; ++i)
+ {
+ if ( dir_path[i] == '/' )
+ {
+ //printf("%c\n", dir_path[i]);
+ //char* test = strndup(dir_path, i);
+ //printf("A: [i:%d] [c:%c] - %s\n", i, dir_path[i], test);
+ continue;
+ }
+ else
+ {
+ char* incremental_dir_path = strndup(dir_path, i+1);
+ // printf("B: [i:%d] [c:%c] - %s\n", i, dir_path[i], test);
+ struct stat sb;
+ if (stat(incremental_dir_path, &sb) == 0 && S_ISDIR(sb.st_mode))
+ {
+ continue;
+ }
+ else
+ {
+ int return_code = mkdir(incremental_dir_path, 0777);
+ if ( return_code == 0 )
+ {
+ continue;
+ }
+ else
+ {
+ // should be unreachable I guess since previous checks
+ // though it could be caused by some other kind of error
+ // like, no permission, or exists but is not a directory
+ // but a file, dev, char, pipe whatever this thing
+ // supports anyway
+ free(incremental_dir_path);
+ free(dir_path);
+ return -3;
+ }
+ }
+ free(incremental_dir_path);
+ }
+ }
+ free(dir_path);
+ return 0;
+ }
+ else
+ {
+ return -2;
+ }
+}
+
+int ak_fs_convert_map_v3_string_to_struct(const char *str, size_t ssize, akfs_map_v3* map)
+{
+ size_t sa[] = { -1, -1, -1, -1, -1 };
+ size_t na[] = { -1, -1, -1 };
+ int spaces_found = 0;
+ int newlines_found = 0;
+ char original_hash_str[129] = {0};
+ char root_hash_str[129] = {0};
+ char filename[256] = {0};
+ if ( map == 0x0 )
+ {
+ printf("FAILED IN %s! : %p \n", __func__, (void*)map);
+ return 1;
+ }
+ for ( size_t i = 0; i < ssize; ++i)
+ {
+ if ( str[i] == ' ' )
+ {
+ sa[++spaces_found] = i;
+ }
+ if ( str[i] == '\n' )
+ {
+ na[++newlines_found] = i;
+ }
+ }
+ int si = 0;
+ for ( size_t i = 0; i < sa[1]; ++i)
+ {
+ original_hash_str[si] = str[i];
+ si++;
+ }
+ original_hash_str[si] = '\0';
+ if( !ak_fs_verify_input_is_hash(original_hash_str, strlen(original_hash_str)) )
+ {
+ ak_log_error(__func__, "original_hash_str not a hash");
+ return 1;
+ }
+ if ( ak_fs_sha512sum_string_to_struct(original_hash_str, &(map->oh)) != 0 )
+ {
+ ak_log_error(__func__, "String convertion of original_hash_str");
+ return 1;
+ }
+ si = 0;
+ for ( size_t i = na[1]+1; i < sa[3]; ++i)
+ {
+ root_hash_str[si] = str[i];
+ si++;
+ }
+ root_hash_str[si] = '\0';
+ if( !ak_fs_verify_input_is_hash(root_hash_str, strlen(root_hash_str)) )
+ {
+ ak_log_error(__func__, "root_hash_str not a hash");
+ return 1;
+ }
+ if ( ak_fs_sha512sum_string_to_struct(root_hash_str, &(map->rh)) != 0 )
+ {
+ ak_log_error(__func__, "String convertion of root_hash_str");
+ return 1;
+ }
+ si = 0;
+ if ( sa[2] < na[1] )
+ {
+ for ( size_t i = sa[2]+1; i < na[1]; ++i)
+ {
+ filename[si] = str[i];
+ si++;
+ }
+ filename[si] = '\0';
+ }
+ strncpy(map->filename, filename, sizeof(map->filename));
+ return 0;
+}
+
+void ak_fs_maps_v3_get_from_fs(akfs_map_v3 **ma, size_t length)
+{
+ (void)length;
+ DIR *d;
+ d = opendir(ak_fs_maps_v3_get_dir());
+ akfs_map_v3 *ptr = NULL;
+ ptr = *ma;
+ if (d)
+ {
+ const struct dirent *dir;
+ while((dir = readdir(d)) != NULL )
+ {
+ if (!ak_fs_verify_input_is_hash(dir->d_name, 128)) continue;
+ ak_fs_sha512sum_string_to_struct(dir->d_name, &(ptr->mh));
+ ++ptr;
+ }
+ }
+ closedir(d);
+}
+
+void ak_fs_init_string(char *str, size_t len)
+{
+ for (size_t i = 0; i < len; ++i)
+ {
+ str[i] = '\0';
+ }
+}
+
+int ak_fs_ls()
+{
+ size_t len = ak_fs_maps_v3_found_in_fs();
+ akfs_map_v3 map_store[len];
+ akfs_map_v3* maps_ptr = &map_store[0];
+ ak_fs_maps_v3_init(&maps_ptr, len);
+ ak_fs_maps_v3_get_from_fs(&maps_ptr, len);
+ ak_fs_maps_v3_resolve(&maps_ptr, len);
+ ak_fs_maps_v3_print_bif(&maps_ptr, len);
+ return 0;
+}
+
+int ak_fs_cat_file_from_root_hash(const sha512sum* rh)
+{
+ const char* chunks_dir = getenv("AK_CHUNKSDIR");
+ if ( chunks_dir == NULL )
+ {
+ ak_log_error(__func__, "No directory for chunks found");
+ return -2;
+ }
+ const char* leafs_dir = getenv("AK_LEAFSDIR");
+ if ( leafs_dir == NULL )
+ {
+ ak_log_error(__func__, "No directory for leafs found");
+ return -3;
+ }
+ FILE *fd;
+ char *fullpath;
+ bool is_chunk = false;
+ char root_hash_str[129] = {0};
+ ak_fs_sha512sum_struct_to_string(rh, root_hash_str);
+ if ( asprintf(&fullpath, "%s/%s", leafs_dir, root_hash_str) == -1 ) return -1;
+ fd = fopen(fullpath, "r");
+ if ( fd == NULL )
+ {
+ free(fullpath);
+ if ( asprintf(&fullpath, "%s/%s", chunks_dir, ak_fs_sha512sum_struct_read_as_string(rh)) == -1 ) return -1;
+ fd = fopen(fullpath, "r");
+ if ( fd == NULL )
+ {
+ ak_log_error(__func__, "Could not be found");
+ free(fullpath);
+ return 1;
+ }
+ is_chunk = true;
+ }
+ if ( !is_chunk )
+ {
+ char buffer[258] = {0};
+ size_t bytes_read = fread(&buffer, 1, sizeof(buffer), fd);
+ if ( bytes_read < sizeof(buffer) )
+ {
+ ak_log_error(__func__, "File is smaller than expected. Wrong format?");
+ fclose(fd);
+ free(fullpath);
+ return 2;
+ }
+ if ( buffer[128] != '\n' || buffer[257] != '\n' )
+ {
+ ak_log_error(__func__, "Unknown format");
+ fclose(fd);
+ free(fullpath);
+ return 2;
+ }
+ char h_str[129] = {0};
+ char t_str[129] = {0};
+ mt_branch h0;
+ ak_fs_sha512sum_init(&h0.root);
+ ak_fs_sha512sum_init(&h0.head);
+ ak_fs_sha512sum_init(&h0.tail);
+ h0.root = *rh;
+ memcpy(h_str, buffer, 128);
+ h_str[128] = '\0';
+ memcpy(t_str, buffer + 129, 128);
+ t_str[128] = '\0';
+ fclose(fd);
+ // free(fullpath);
+ ak_fs_sha512sum_string_to_struct(h_str, &h0.head);
+ ak_fs_sha512sum_string_to_struct(t_str, &h0.tail);
+ ak_fs_cat_file_from_root_hash(&h0.head);
+ if ( !ak_fs_sha512sum_compare(&h0.head, &h0.tail) ) ak_fs_cat_file_from_root_hash(&h0.tail);
+ }
+ else
+ {
+ struct stat sb;
+ if (stat(fullpath, &sb) == -1) {
+ perror("stat");
+ fclose(fd);
+ free(fullpath);
+ return 2;
+ }
+ char buffer[(long long) sb.st_size+1];
+ fread(&buffer, sizeof(buffer), 1, fd);
+ fclose(fd);
+ buffer[sizeof(buffer)-1] = '\0';
+ printf("%s", buffer);
+ }
+ free(fullpath);
+ return 0;
+}
+
+int ak_fs_cfm(akfs_map_v3* map)
+{
+ sha512sum x;
+ ak_fs_sha512sum_init(&x);
+ const sha512sum *rh_ptr = ak_fs_map_v3_get_root_hash(map);
+ if ( rh_ptr == NULL )
+ {
+ ak_log_debug(__func__, "No root hash found on the map");
+ return -1;
+ }
+ x = *rh_ptr;
+ return ak_fs_cat_file_from_root_hash(&x);
+}
diff --git a/c_implementation/src/ak_fs_defuse.c b/c_implementation/src/ak_fs_defuse.c
new file mode 100644
index 0000000..76514f6
--- /dev/null
+++ b/c_implementation/src/ak_fs_defuse.c
@@ -0,0 +1,98 @@
+#define FUSE_USE_VERSION 31
+#include <fuse3/fuse.h>
+#include <libakfs.h>
+#include <libaklog.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <stdlib.h>
+
+// Called when a file is read
+static int akfs_fuse_read(const char *path, char *buf, size_t size, off_t offset,
+ struct fuse_file_info *fi)
+{
+ (void) fi; // Unused
+ const char *content = "Hello, World!\n";
+ size_t len = strlen(content);
+
+ if (strcmp(path, "/hello") != 0) // Only support "/hello"
+ return -ENOENT;
+
+ if (offset < 0 || (size_t)offset >= len)
+ return 0;
+
+ size = (size < len - offset) ? size : len - offset;
+ memcpy(buf, content + offset, size);
+ return size;
+}
+
+// Called to list files in the root directory
+static int akfs_fuse_readdir(const char *path, void *buf, fuse_fill_dir_t filler,
+ off_t offset, struct fuse_file_info *fi,
+ enum fuse_readdir_flags flags)
+{
+ (void) offset; (void) fi; (void) flags; // Unused
+
+ if (strcmp(path, "/") != 0) // Only support root dir
+ return -ENOENT;
+
+ filler(buf, ".", NULL, 0, 0);
+ filler(buf, "..", NULL, 0, 0);
+
+ // example file
+ filler(buf, "hello", NULL, 0, 0);
+
+ // ak fs integration
+ size_t ms_len = ak_fs_maps_v3_found_in_fs();
+ akfs_map_v3 map_store[ms_len];
+ akfs_map_v3* mps_ptr = &map_store[0];
+ void* mps_start = &map_store[0];
+ (void)mps_start;
+ ak_fs_maps_v3_init(&mps_ptr, ms_len);
+ ak_fs_maps_v3_resolve(&mps_ptr, ms_len);
+ akfs_map_v3 *ptr = NULL;
+ for (ptr = mps_ptr; ptr < mps_ptr + ms_len; ++ptr)
+ {
+ if ( ak_fs_map_v3_is_null(ptr) )
+ {
+ ak_fs_map_v3_print_filename(ptr);
+ filler(buf, ak_fs_map_v3_get_filename(ptr), NULL, 0, 0);
+ }
+ }
+
+ return 0;
+}
+
+// Called to get file attributes (metadata)
+static int akfs_fuse_getattr(const char *path, struct stat *st, struct fuse_file_info *fi)
+{
+ (void) fi;
+ st->st_uid = getuid();
+ st->st_gid = getgid();
+ st->st_atime = st->st_mtime = time(NULL);
+
+ if (strcmp(path, "/") == 0) {
+ st->st_mode = S_IFDIR | 0755; // Directory
+ st->st_nlink = 2;
+ } else if (strcmp(path, "/hello") == 0) {
+ st->st_mode = S_IFREG | 0644; // Regular file
+ st->st_nlink = 1;
+ st->st_size = strlen("Hello, World!\n");
+ } else {
+ return -ENOENT; // Not found
+ }
+ return 0;
+}
+
+// FUSE operations struct (only implementing needed functions)
+static struct fuse_operations akfs_fuse_ops = {
+ .getattr = akfs_fuse_getattr,
+ .readdir = akfs_fuse_readdir,
+ .read = akfs_fuse_read,
+};
+
+int main(int argc, char *argv[])
+{
+ return fuse_main(argc, argv, &akfs_fuse_ops, NULL);
+}
diff --git a/c_implementation/src/ak_fs_main.c b/c_implementation/src/ak_fs_main.c
new file mode 100644
index 0000000..e399544
--- /dev/null
+++ b/c_implementation/src/ak_fs_main.c
@@ -0,0 +1,51 @@
+#include <getopt.h>
+#include <stdio.h>
+#include <libaklog.h>
+#include <libakfs.h>
+
+static int ak_fs_usage()
+{
+ ak_log_debug(__func__, "Available commands:");
+ ak_log_debug(__func__, "akfs --list");
+ ak_log_debug(__func__, "akfs --cfm <map hash>");
+ return 1;
+}
+
+int ak_fs_main(int argc, char** argv)
+{
+ int option;
+ int logind = 0;
+ akfs_map_v3 map;
+ static struct option long_options[] = {
+ {"help", no_argument, 0, 'h'},
+ {"list", no_argument, 0, 'l'},
+ {"cfm", required_argument, 0, 'C'},
+ {0,0,0,0}
+ };
+ while(1)
+ {
+ option = getopt_long(argc, argv, "hlC:", long_options, &logind);
+ if ( option == -1 ) return ak_fs_usage();
+ switch(option)
+ {
+ case 'h':
+ return ak_fs_usage();
+ case 'l':
+ return ak_fs_ls();
+ case 'C':
+ ak_fs_map_v3_init(&map);
+ if ( ak_fs_sha512sum_string_to_struct(optarg, &map.mh) != 0 ) return -1;
+ if ( ak_fs_map_v3_open_from_file(&map) != 0 ) return -2;
+ return ak_fs_cfm(&map);
+ default:
+ printf("double lol\n");
+ return 4;
+ }
+ }
+ return 0;
+}
+
+int main(int argc, char **argv)
+{
+ return ak_fs_main(argc, argv);
+}
diff --git a/c_implementation/src/ak_fs_map_v3.c b/c_implementation/src/ak_fs_map_v3.c
new file mode 100644
index 0000000..1d3e37e
--- /dev/null
+++ b/c_implementation/src/ak_fs_map_v3.c
@@ -0,0 +1,213 @@
+#include <stdio.h>
+#include <string.h>
+#include <stdlib.h>
+#include <libakfs.h>
+#include <libaklog.h>
+#include <sys/stat.h>
+
+// const char maps_dir[] = "/home/kaotisk/.arching-kaos/akfs/maps/";
+
+void ak_fs_map_v3_init(akfs_map_v3 *map)
+{
+ ak_fs_sha512sum_init(&map->oh);
+ ak_fs_sha512sum_init(&map->rh);
+ ak_fs_sha512sum_init(&map->mh);
+ ak_fs_init_string(map->filename, 256);
+}
+
+bool ak_fs_map_v3_compare(akfs_map_v3* a, akfs_map_v3* b)
+{
+ return (
+ (ak_fs_sha512sum_compare(&a->oh, &b->oh) == true) &&
+ (ak_fs_sha512sum_compare(&a->rh, &b->rh) == true) &&
+ (ak_fs_sha512sum_compare(&a->mh, &b->mh) == true) &&
+ (strcmp(a->filename, b->filename) == 0)
+ );
+}
+
+
+bool ak_fs_map_v3_is_null(akfs_map_v3* m)
+{
+ akfs_map_v3 n;
+ ak_fs_map_v3_init(&n);
+ if ( ak_fs_map_v3_compare(m, &n) )
+ {
+ ak_log_debug(__func__, "true");
+ }
+ else
+ {
+ ak_log_debug(__func__, "false");
+ }
+ return ak_fs_map_v3_compare(m, &n);
+}
+
+void ak_fs_map_v3_print_map_hash(akfs_map_v3 *map)
+{
+ if( !ak_fs_sha512sum_is_null(&(map->mh)) )
+ {
+ char str[129] = {0};
+ char* s = &str[0];
+ ak_fs_sha512sum_struct_to_string(&(map->mh), s);
+ printf("%s", s);
+ }
+ else
+ {
+ ak_log_debug(__func__,"hash is null");
+ }
+}
+
+void ak_fs_map_v3_print_original_hash(akfs_map_v3 *map)
+{
+ if (!ak_fs_sha512sum_is_null(&(map->oh)))
+ {
+ printf("%s", ak_fs_sha512sum_struct_read_as_string(&(map->oh)));
+ }
+ else
+ {
+ ak_log_debug(__func__,"hash is null");
+ }
+}
+
+void ak_fs_map_v3_print_root_hash(akfs_map_v3 *map)
+{
+ if (!ak_fs_sha512sum_is_null(&(map->rh)))
+ {
+ printf("%s", ak_fs_sha512sum_struct_read_as_string(&(map->rh)));
+ }
+ else
+ {
+ ak_log_debug(__func__,"hash is null");
+ }
+}
+
+sha512sum* ak_fs_map_v3_get_map_hash(akfs_map_v3 *map)
+{
+ return &(map->mh);
+}
+
+sha512sum* ak_fs_map_v3_get_root_hash(akfs_map_v3 *map)
+{
+ if (!ak_fs_sha512sum_is_null(&(map->rh)))
+ {
+ return &(map->rh);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+sha512sum* ak_fs_map_v3_get_orig_hash(akfs_map_v3 *map)
+{
+ if (!ak_fs_sha512sum_is_null(&(map->oh)))
+ {
+ return &(map->oh);
+ }
+ else
+ {
+ return NULL;
+ }
+}
+
+char* ak_fs_map_v3_get_filename(akfs_map_v3 *map)
+{
+ return map->filename;
+}
+
+void ak_fs_map_v3_print_filename(akfs_map_v3 *map)
+{
+ printf("%s", ak_fs_map_v3_get_filename(map));
+}
+
+void ak_fs_map_v3_print(akfs_map_v3 *map)
+{
+ printf("map_v3 {");
+ printf("\n .mh: ");
+ ak_fs_map_v3_print_map_hash(map);
+ printf("\n .oh: ");
+ ak_fs_map_v3_print_original_hash(map);
+ printf("\n .rh: ");
+ ak_fs_map_v3_print_root_hash(map);
+ printf("\n .fn: ");
+ ak_fs_map_v3_print_filename(map);
+ printf("\n}\n");
+}
+
+void ak_fs_map_v3_print_as_json(akfs_map_v3 *map)
+{
+ printf("{\"type\":\"map_v3\",");
+ printf("\"map\":\"");
+ ak_fs_map_v3_print_map_hash(map);
+ printf("\",");
+ printf("\"original\":\"");
+ ak_fs_map_v3_print_original_hash(map);
+ printf("\",");
+ printf("\"root\":\"");
+ ak_fs_map_v3_print_root_hash(map);
+ printf("\",");
+ printf("\"filename\":\"");
+ ak_fs_map_v3_print_filename(map);
+ printf("\"");
+ printf("}\n");
+}
+
+void ak_fs_map_v3_print_bif(akfs_map_v3 *map)
+{
+ ak_fs_map_v3_print_map_hash(map);
+ printf(" ");
+ ak_fs_map_v3_print_root_hash(map);
+ printf(" ");
+ ak_fs_map_v3_print_filename(map);
+}
+
+int ak_fs_map_v3_open_from_file(akfs_map_v3 * map)
+{
+ if (map==0x0)
+ {
+ ak_log_debug(__func__, "Zeropointer");
+ return 1;
+ }
+ FILE *fd;
+ char *full_path = {0};
+ asprintf(&full_path,
+ "%s/%s",
+ ak_fs_maps_v3_get_dir(),
+ ak_fs_sha512sum_struct_read_as_string(ak_fs_map_v3_get_map_hash(map))
+ );
+ // printf("Trying path: %s\n", full_path);
+ fd = fopen(full_path, "rb");
+ if (!fd)
+ {
+ // perror("fopen");
+ ak_log_debug(__func__, "File not found or other error");
+ free(full_path);
+ return 1;
+ }
+ struct stat sb;
+ if (stat(full_path, &sb) == -1) {
+ perror("stat");
+ fclose(fd);
+ free(full_path);
+ return 2;
+ }
+ // File size: %lld in bytes: (long long) sb.st_size);
+ char buffer[(long long) sb.st_size+1];
+ fread(&buffer, sizeof(buffer), (long long) sb.st_size, fd);
+ // ak_fs_sha512sum_string_to_struct(maphash, &(map->mh));
+ if ( ak_fs_convert_map_v3_string_to_struct(buffer, strlen(buffer), map) != 0 )
+ {
+ ak_log_debug(__func__,"conversion failed");
+ fclose(fd);
+ free(full_path);
+ return 1;
+ }
+ fclose(fd);
+ free(full_path);
+ return 0;
+}
+
+int ak_fs_map_v3_to_file(akfs_map_v3 maphash)
+{
+ (void)maphash;
+ return 0;
+}
diff --git a/c_implementation/src/ak_fs_map_v4.c b/c_implementation/src/ak_fs_map_v4.c
new file mode 100644
index 0000000..3fea244
--- /dev/null
+++ b/c_implementation/src/ak_fs_map_v4.c
@@ -0,0 +1,8 @@
+#include <libaklog.h>
+#include <libakfs.h>
+
+void ak_fs_map_v4_init(akfs_map_v4* map)
+{
+ (void)map;
+ ak_log_debug(__func__, "Not implemented");
+}
diff --git a/c_implementation/src/ak_fs_maps_v3.c b/c_implementation/src/ak_fs_maps_v3.c
new file mode 100644
index 0000000..a5060b2
--- /dev/null
+++ b/c_implementation/src/ak_fs_maps_v3.c
@@ -0,0 +1,98 @@
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <dirent.h>
+#include "libakfs.h"
+
+const char* ak_fs_maps_v3_get_dir()
+{
+ return getenv("AK_MAPSDIR");
+}
+
+void ak_fs_maps_v3_init(akfs_map_v3** ms, size_t l)
+{
+ akfs_map_v3 *m = NULL;
+ for (m = *ms; m < *ms+l; ++m)
+ {
+ ak_fs_map_v3_init(m);
+ }
+}
+
+void ak_fs_maps_v3_print_map_hashes(akfs_map_v3** m, size_t s)
+{
+ akfs_map_v3 *ptr = NULL;
+ for (ptr = *m; ptr < *m+s; ++ptr)
+ {
+ if ( !ak_fs_map_v3_is_null(ptr) ) ak_fs_map_v3_print_map_hash(ptr);
+ }
+}
+
+void ak_fs_maps_v3_print_filenames(akfs_map_v3** m, size_t s)
+{
+ akfs_map_v3 *ptr = NULL;
+ for (ptr = *m; ptr < *m+s; ++ptr)
+ {
+ if ( ptr != NULL )
+ {
+ ak_fs_map_v3_print_filename(ptr);
+ printf("\n");
+ }
+ }
+}
+
+void ak_fs_maps_v3_print(akfs_map_v3 **map_store, size_t length)
+{
+ akfs_map_v3 *ptr = NULL;
+ for ( ptr = *map_store; ptr < *map_store + length; ++ptr)
+ {
+ ak_fs_map_v3_print(ptr);
+ printf("\n");
+ }
+}
+
+void ak_fs_maps_v3_print_as_json(akfs_map_v3 **map_store, size_t length)
+{
+ akfs_map_v3 *ptr = NULL;
+ for ( ptr = *map_store; ptr < *map_store + length; ++ptr)
+ {
+ ak_fs_map_v3_print_as_json(ptr);
+ }
+}
+
+void ak_fs_maps_v3_print_bif(akfs_map_v3 **map_store, size_t length)
+{
+ akfs_map_v3 *ptr = NULL;
+ for ( ptr = *map_store; ptr < *map_store + length; ++ptr)
+ {
+ ak_fs_map_v3_print_bif(ptr);
+ printf("\n");
+ }
+}
+
+size_t ak_fs_maps_v3_found_in_fs()
+{
+ DIR *d;
+ size_t counter = 0;
+ d = opendir(ak_fs_maps_v3_get_dir());
+ if (d)
+ {
+ const struct dirent *dir;
+ while ((dir = readdir(d)) != NULL )
+ {
+ if (ak_fs_verify_input_is_hash(dir->d_name, strlen(dir->d_name))) counter++;
+ }
+ }
+ closedir(d);
+ return counter;
+}
+
+int ak_fs_maps_v3_resolve(akfs_map_v3 **ms, size_t ms_len)
+{
+ akfs_map_v3 *ptr = NULL;
+ for ( ptr = *ms; ptr < *ms+ms_len; ++ptr)
+ {
+ if ( ak_fs_sha512sum_is_null(&(ptr->mh)) ) continue;
+ ak_fs_map_v3_open_from_file(ptr);
+ }
+ return 0;
+}
diff --git a/c_implementation/src/ak_fs_mt.c b/c_implementation/src/ak_fs_mt.c
new file mode 100644
index 0000000..2c3414b
--- /dev/null
+++ b/c_implementation/src/ak_fs_mt.c
@@ -0,0 +1,52 @@
+#include <stdio.h>
+#include <libakfs.h>
+#include <libaklog.h>
+#include <stdbool.h>
+
+bool ak_fs_mt_branch_is_null(mt_branch* n)
+{
+ if ( n == NULL )
+ {
+ ak_log_warning(__func__, "A NULL mt_branch* node was given");
+ return false;
+ }
+ if (
+ ak_fs_sha512sum_is_null(&n->root) &&
+ ak_fs_sha512sum_is_null(&n->head) &&
+ ak_fs_sha512sum_is_null(&n->tail)
+ )
+ {
+ return true;
+ }
+ return false;
+}
+
+bool ak_fs_mt_branch_compare(mt_branch *a, mt_branch *b)
+{
+ if ( a == NULL || b == NULL )
+ {
+ ak_log_warning(__func__, "One or two NULL mt_branch* node was given");
+ return false;
+ }
+ if (
+ ak_fs_sha512sum_compare(&a->root, &b->root) &&
+ ak_fs_sha512sum_compare(&a->head, &b->head) &&
+ ak_fs_sha512sum_compare(&a->tail, &b->tail)
+ )
+ {
+ return true;
+ }
+ return false;
+}
+
+void ak_fs_mt_branch_print(mt_branch *n)
+{
+ if ( n == NULL )
+ {
+ ak_log_warning(__func__, "NULL mt_branch* was given");
+ return;
+ }
+ printf("r: %s\n", ak_fs_sha512sum_struct_read_as_string(&n->root));
+ printf("h: %s\n", ak_fs_sha512sum_struct_read_as_string(&n->head));
+ printf("t: %s\n", ak_fs_sha512sum_struct_read_as_string(&n->tail));
+}
diff --git a/c_implementation/src/ak_fs_sha512sum.c b/c_implementation/src/ak_fs_sha512sum.c
new file mode 100644
index 0000000..619269f
--- /dev/null
+++ b/c_implementation/src/ak_fs_sha512sum.c
@@ -0,0 +1,221 @@
+#include <libakfs.h>
+#include <libaklog.h>
+#include <stdlib.h>
+#include <assert.h>
+#include <string.h>
+
+void ak_fs_sha512sum_init(sha512sum *hash)
+{
+ for (int i = 0; i < 8; ++i)
+ {
+ hash->sum[i] = 0x0;
+ }
+}
+
+bool ak_fs_sha512sum_compare(const sha512sum* a, const sha512sum* b)
+{
+ for ( int i = 0; i < 8; ++i )
+ {
+ if ( a->sum[i] != b->sum[i] ) return false;
+ }
+ return true;
+}
+
+void ak_fs_sha512sum_reset_struct(sha512sum* m)
+{
+ for (size_t i = 0; i < 8; ++i)
+ {
+ m->sum[i] = 0;
+ }
+}
+
+void ak_fs_sha512sum_init_avail(sha512sum** m, size_t s)
+{
+ sha512sum *ptr = NULL;
+ for (ptr = *m; ptr < *m+s; ++m)
+ {
+ ak_fs_sha512sum_reset_struct(ptr);
+ }
+}
+
+char* ak_fs_sha512sum_struct_read_as_string(const sha512sum *ptr)
+{
+ static char str[129] = {0}; // = malloc(129*sizeof(char));
+ ak_fs_sha512sum_struct_to_string(ptr, str);
+ // ak_log_debug(__func__, str);
+ return str;
+}
+
+bool ak_fs_sha512sum_is_null(const sha512sum *h)
+{
+ sha512sum n;
+ ak_fs_sha512sum_init(&n);
+ return ak_fs_sha512sum_compare(h,&n);
+}
+
+int ak_fs_sha512sum_string_to_struct(const char* str, sha512sum* hash)
+{
+ if ( ak_fs_verify_input_is_hash(str, strlen(str)) )
+ {
+ for (size_t l = 0; l < 8; ++l)
+ {
+ hash->sum[l]=0;