aboutsummaryrefslogtreecommitdiff
path: root/c_implementation
diff options
context:
space:
mode:
Diffstat (limited to 'c_implementation')
-rw-r--r--c_implementation/Makefile.am65
-rwxr-xr-xc_implementation/build_tree/ak_fs_build.sh17
-rw-r--r--c_implementation/include/libakdatetime.h14
-rw-r--r--c_implementation/include/libakfs.h347
-rw-r--r--c_implementation/include/libaklog.h23
-rw-r--r--c_implementation/include/libaksettings.h7
-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.c (renamed from c_implementation/src/aklogcatter.c)1
-rw-r--r--c_implementation/src/ak_settings.c (renamed from c_implementation/src/aksettings.c)42
-rw-r--r--c_implementation/src/ak_utils.c (renamed from c_implementation/src/akutils.c)0
-rw-r--r--c_implementation/src/akfs.c349
-rw-r--r--c_implementation/src/aklog.c287
-rw-r--r--c_implementation/tests/test_akfs.c210
-rw-r--r--c_implementation/tests/test_akfs_mkdir.c20
-rw-r--r--c_implementation/tests/test_aklog.c36
-rw-r--r--c_implementation/tests/test_aklogwrite.c2
-rw-r--r--c_implementation/tests/test_aksettings.c75
-rw-r--r--c_implementation/tests/test_aksettings_read.c2
-rw-r--r--c_implementation/tests/test_sha512_string.c8
29 files changed, 2203 insertions, 774 deletions
diff --git a/c_implementation/Makefile.am b/c_implementation/Makefile.am
index 87089cb..f1834d5 100644
--- a/c_implementation/Makefile.am
+++ b/c_implementation/Makefile.am
@@ -1,22 +1,67 @@
ACLOCAL_AMFLAGS = -I m4
-AM_CPPFLAGS = -I$(top_srcdir)/include
+AM_CPPFLAGS = -Wall -Werror -Wextra -Wpedantic -ggdb -I$(top_srcdir)/include
+#AM_CFLAGS = -Wall -Werror -Wextra -Wpedantic -ggdb -I$(top_srcdir)/include
-lib_LTLIBRARIES = libaklog.la libaksettings.la
-libaklog_la_SOURCES = $(top_srcdir)/src/aklog.c
-libaksettings_la_SOURCES = $(top_srcdir)/src/aksettings.c
-include_HEADERS = include/libaklog.h include/libaksettings.h
+lib_LTLIBRARIES = libaklog.la libaksettings.la libakfs.la libakdatetime.la libakutils.la
-bin_PROGRAMS = ak
-ak_LDADD = libaklog.la
-ak_SOURCES = src/ak.c
+libaklog_la_SOURCES = $(top_srcdir)/src/ak_log.c $(top_srcdir)/src/ak_log_main.c
-check_PROGRAMS = test_aklog
-test_aklog_SOURCES = ./tests/test_aklog.c
+libaksettings_la_SOURCES = $(top_srcdir)/src/ak_settings.c
+
+libakfs_LDADD = libaksettings.la libaklog.la
+libakfs_la_SOURCES = $(top_srcdir)/src/ak_fs.c \
+ $(top_srcdir)/src/ak_fs_main.c \
+ $(top_srcdir)/src/ak_fs_maps_v3.c \
+ $(top_srcdir)/src/ak_fs_map_v3.c \
+ $(top_srcdir)/src/ak_fs_map_v4.c \
+ $(top_srcdir)/src/ak_fs_mt.c \
+ $(top_srcdir)/src/ak_fs_sha512sum.c
+
+libakutils_la_SOURCES = $(top_srcdir)/src/ak_utils.c
+
+libakdatetime_la_SOURCES = $(top_srcdir)/src/ak_datetime.c
+
+#include_HEADERS = "$(wildcard include/*.h)"
+include_HEADERS = $(top_srcdir)/include/libaklog.h \
+ $(top_srcdir)/include/libaksettings.h \
+ $(top_srcdir)/include/libakfs.h \
+ $(top_srcdir)/include/libak.h
+
+bin_PROGRAMS = akfs akdefuse #akt akdefuse aklog
+akfs_LDADD = libaklog.la libakfs.la libaksettings.la
+akfs_SOURCES = src/ak_fs_main.c
+
+akt_LDADD = libaklog.la libakfs.la libaksettings.la
+akt_SOURCES = src/ak.c
+
+akdefuse_CFLAGS = -I/usr/include/fuse3 -lfuse3 -lpthread
+akdefuse_LDADD = libaklog.la libakfs.la
+akdefuse_SOURCES = src/ak_fs_defuse.c
+
+aklog_LDADD = libaklog.la
+aklog_SOURCES = src/ak_log_main.c
+
+check_PROGRAMS = test_aklog test_aksettings test_akfs test_akutils test_akdatetime
+test_akdatetime_SOURCES = ./tests/test_akdatetime.c ./src/ak_datetime.c
+test_akdatetime_LDADD = libakdatetime.la
+
+test_akutils_SOURCES = ./tests/test_akutils.c ./src/ak_utils.c
+test_akutils_LDADD = libakutils.la
+
+test_aklog_SOURCES = ./tests/test_aklog.c ./src/ak_log.c
test_aklog_LDADD = libaklog.la
+test_akfs_SOURCES = ./tests/test_akfs.c ./src/ak_fs.c
+test_akfs_LDADD = libakfs.la libaklog.la
+
+test_aksettings_SOURCES = ./tests/test_aksettings.c ./src/ak_settings.c ./src/ak_log.c
+test_aksettings_LDADD = libaksettings.la
+
tests_test_main_CPPFLAGS = -I$(top_srcdir)/include
TESTS = $(check_PROGRAMS)
CLEANFILES = $(TESTS)
+cppcheck:
+ cppcheck --std=c99 --force --enable=all --check-library -I $(top_srcdir)/include/*.h $(top_srcdir)/include/*.h $(top_srcdir)/src/*.c $(top_srcdir)/tests/test*.c
diff --git a/c_implementation/build_tree/ak_fs_build.sh b/c_implementation/build_tree/ak_fs_build.sh
index 11b4fde..7be2322 100755
--- a/c_implementation/build_tree/ak_fs_build.sh
+++ b/c_implementation/build_tree/ak_fs_build.sh
@@ -1,15 +1,16 @@
#!/usr/bin/env bash
echo "Building lib/akfs.so" && \
+gcc -c -shared -Wextra -Wall -Werror -pedantic -ggdb -fPIC -I./include ./src/aklog.c -o lib/libaklog.so && \
gcc -c -shared -Wextra -Wall -Werror -pedantic -ggdb -fPIC -I./include ./src/akfs.c -o lib/libakfs.so && \
echo "Building tests/test_akfs" && \
-gcc -Wextra -Wall -Werror -pedantic -ggdb -Wl,-rpath=lib -I./include tests/test_akfs.c lib/libakfs.so -o tests/test_akfs && \
+gcc -Wextra -Wall -Werror -pedantic -ggdb -Wl,-rpath=lib -I./include tests/test_akfs.c lib/libakfs.so lib/libaklog.so -o x_test_akfs && \
echo "Running test_akfs" && \
-time ./tests/test_akfs && \
-rm ./tests/test_akfs
+time ./x_test_akfs && \
+rm ./x_test_akfs
-echo "Building tests/test_akfs_mkdir.c" && \
-gcc -Wextra -Wall -Werror -pedantic -ggdb -Wl,-rpath=lib -I./include tests/test_akfs_mkdir.c lib/libakfs.so -o tests/test_akfs_mkdir && \
-echo "Running test_akfs_mkdir" && \
-time ./tests/test_akfs_mkdir && \
-rm ./tests/test_akfs_mkdir
+# echo "Building tests/test_akfs_mkdir.c" && \
+# gcc -Wextra -Wall -Werror -pedantic -ggdb -Wl,-rpath=lib -I./include tests/test_akfs_mkdir.c lib/libakfs.so -o tests/test_akfs_mkdir && \
+# echo "Running test_akfs_mkdir" && \
+# time ./tests/test_akfs_mkdir && \
+# rm ./tests/test_akfs_mkdir
diff --git a/c_implementation/include/libakdatetime.h b/c_implementation/include/libakdatetime.h
new file mode 100644
index 0000000..435c3d8
--- /dev/null
+++ b/c_implementation/include/libakdatetime.h
@@ -0,0 +1,14 @@
+#include <stdbool.h>
+#include <stddef.h>
+#ifndef AK_DATETIME_H
+#define AK_DATETIME_H
+
+long ak_datetime_unix();
+void ak_datetime_unix_nanosecs(char *buffer, size_t size);
+void ak_datetime_human(char *buffer, size_t size);
+void ak_datetime_human_date_only(char *buffer, size_t size);
+void ak_datetime_human_date_only_yesterday(char *buffer, size_t size);
+//static bool is_digits_only(const char *str);
+bool ak_datetime_unix_to_human(const char *timestamp_str, char *buffer, size_t size);
+
+#endif // AK_DATETIME_H
diff --git a/c_implementation/include/libakfs.h b/c_implementation/include/libakfs.h
index bc5703c..3eb0ba3 100644
--- a/c_implementation/include/libakfs.h
+++ b/c_implementation/include/libakfs.h
@@ -2,6 +2,7 @@
#define AKFS
#include <stdbool.h>
+#include <stddef.h>
/**
* This struct represents a HEX output of the SHA-512 algorithm.
@@ -20,10 +21,9 @@ typedef struct {
} sha512sum;
/**
- * This struct describes explicitly the structure of a root_hash. It is the root
- * of a hash merkle tree. Note, that this structure can be used for roots and
- * branches. Possibly, the name will change to something more generic in the
- * future.
+ * This struct describes explicitly the structure of a mt_branch. Note,
+ * that this structure can be used for roots and branches.
+ *
* Another note is that instead of approaching this as left and right, as seen
* in other codebases, we do a head-tail naming. That's because of the BASH
* implementation that you can find at lib/_ak_fs.
@@ -42,7 +42,7 @@ typedef struct {
* Hash of tail
*/
sha512sum tail;
-} root_hash;
+} mt_branch;
/**
* This is the current structure of an akfs_map. Due to potential short-comings
@@ -61,17 +61,22 @@ typedef struct {
* Original file's name
*
*/
- char* filename;
+ char filename[256];
/**
* Root hash
*
*/
sha512sum rh;
/**
+ * Map hash
+ *
+ */
+ sha512sum mh;
+ /**
* Should be "level.1.map" at all times
*
*/
- char* root_name;
+ char *root_name;
} akfs_map_v3;
/**
@@ -96,24 +101,334 @@ typedef struct {
*
*/
sha512sum rh;
+ /**
+ * Map hash
+ *
+ */
+ sha512sum mh;
} akfs_map_v4;
-//typedef char[64] sha512sum_as_string;
+/**
+ * Gets maps_dir
+ * return char*
+ */
+const char* ak_fs_maps_v3_get_dir();
+
+/**
+ * Experimental
+ */
+char* ak_fs_return_hash_path(const char*);
+
+/**
+ * Experimental
+ */
+char* ak_fs_return_hash_dir(const char*);
+
+/**
+ * Verify that string looks like a SHA512 hash
+ *
+ * param char* string to be checked
+ * @return boolean
+ */
+bool ak_fs_verify_input_is_hash(const char*, size_t);
+
+/**
+ * Unused
+ */
+int ak_fs_create_dir_for_hash(const char*);
+
+/**
+ * Converts string hash to struct
+ * @param char* Hash as string
+ * @param sha512sum* Pointer to a sha512sum
+ * @return int Status of exit
+ */
+int ak_fs_sha512sum_string_to_struct(const char*, sha512sum*);
+
+/**
+ * Returns struct from string hash
+ * @param char* Hash as string
+ * @return sha512sum* Pointer to a sha512sum
+ */
+sha512sum* ak_fs_sha512sum_from_string(char*);
+
+/**
+ * Converts hash struct to string
+ * @param sha512sum* Pointer to a sha512sum
+ * @param char* Hash as string
+ */
+void ak_fs_sha512sum_struct_to_string(const sha512sum*, char*);
+
+/**
+ * Opens a map file to an akfs_map_v3 struct
+ * @param akfs_map_v3*
+ * @return int
+ */
+int ak_fs_map_v3_open_from_file(akfs_map_v3*);
+
+/**
+ * Unused
+ */
+int ak_fs_map_v3_to_file(akfs_map_v3);
+
+/**
+ * Converts a string to an akfs_map_v3 struct
+ * @param char*
+ * @param size_t
+ * @param akfs_map_v3*
+ * @return int
+ */
+int ak_fs_convert_map_v3_string_to_struct(const char *, size_t, akfs_map_v3*);
+
+/**
+ * Prints an akfs_map_v3 in struct-like format
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print(akfs_map_v3*);
+
+/**
+ * Prints an array of akfs_map_v3 in struct-like format
+ * @param akfs_map_v3*
+ * @param size_t
+ */
+void ak_fs_maps_v3_print(akfs_map_v3**, size_t);
+
+/**
+ * Prints the map hash out of a akfs_map_v3
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_map_hash(akfs_map_v3*);
+
+/**
+ * Prints the original hash out of a akfs_map_v3
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_original_hash(akfs_map_v3*);
+
+/**
+ * Prints the root hash out of a akfs_map_v3
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_root_hash(akfs_map_v3*);
+
+/**
+ * Prints the filename out of a akfs_map_v3
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_filename(akfs_map_v3*);
+
+/**
+ * Prints the filenames out of an array of akfs_map_v3
+ * @param akfs_map_v3**
+ * @param size_t
+ */
+void ak_fs_maps_v3_print_filenames(akfs_map_v3**, size_t);
+
+/**
+ * Prints an array of akfs_map_v3 in JSON format
+ * @param akfs_map_v3**
+ * @param size_t
+ */
+void ak_fs_maps_v3_print_as_json(akfs_map_v3**, size_t);
+
+/**
+ * Prints an akfs_map_v3 in JSON format
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_as_json(akfs_map_v3*);
+
+/**
+ * Prints an array of akfs_map_v3 in bif format
+ * @param akfs_map_v3**
+ * @param size_t
+ */
+void ak_fs_maps_v3_print_bif(akfs_map_v3**, size_t);
+
+/**
+ * Prints an akfs_map_v3 in bif format
+ * @param akfs_map_v3*
+ */
+void ak_fs_map_v3_print_bif(akfs_map_v3*);
+
+/**
+ * Takes an array of sha512sums (maps) and puts it in an array of maps (v3)
+ * @param akfs_map_v3** Pointer to an array of akfs_map_v3
+ * @param size_t Length of the array
+ * @return int Exit code (0 on success)
+ */
+int ak_fs_maps_v3_resolve(akfs_map_v3**, size_t);
+
+/**
+ * Unused
+ */
+char* ak_fs_sha512sum_struct_read_as_string(const sha512sum *);
+
+/**
+ * Unused
+ */
+void ak_fs_init_string(char *, size_t);
-char* ak_fs_return_hash_path(char*);
+/**
+ * Compares two sha512sum structs
+ * @param sha512sum*
+ * @param sha512sum*
+ * @return bool
+ */
+bool ak_fs_sha512sum_compare(const sha512sum*, const sha512sum*);
+
+/**
+ * Checks if an sha512sum struct is NULL
+ * @param sha512sum*
+ * @return bool
+ */
+bool ak_fs_sha512sum_is_null(const sha512sum*);
-char* ak_fs_return_hash_dir(char*);
+/**
+ * Initializes a sha512sum struct
+ * @param sha512sum*
+ */
+void ak_fs_sha512sum_init(sha512sum*);
-bool ak_fs_verify_input_is_hash(char*);
+/**
+ * Unused
+ */
+void ak_fs_sha512sum_init_avail(sha512sum**, size_t);
-int ak_fs_create_dir_for_hash(char*);
+/**
+ * Initialize an akfs_map_v3
+ */
+void ak_fs_map_v3_init(akfs_map_v3*);
-sha512sum ak_fs_sha512sum_string_to_struct(char*);
+/**
+ * Initializes an array of akfs_map_v3
+ */
+void ak_fs_maps_v3_init(akfs_map_v3**, size_t);
-void ak_fs_sha512sum_struct_to_string(sha512sum, char*);
+/**
+ * @param akfs_map_v3
+ * @return boolean
+ */
+bool ak_fs_map_v3_is_null(akfs_map_v3*);
-int ak_fs_open_map_v3(char*);
-int ak_fs_from_map_v3_to_file(akfs_map_v3);
+/**
+ * Gets filename out of the akfs_map_v3
+ * @param akfs_map_v3*
+ * @return pointer to char
+ */
+char* ak_fs_map_v3_get_filename(akfs_map_v3*);
+
+/**
+ * Gets map hash out of the akfs_map_v3
+ * @param akfs_map_v3
+ * @return pointer to sha512sum
+ */
+sha512sum* ak_fs_map_v3_get_map_hash(akfs_map_v3*);
+
+/**
+ * Gets root hash out of the akfs_map_v3
+ * @param akfs_map_v3
+ * @return pointer to sha512sum
+ */
+sha512sum* ak_fs_map_v3_get_root_hash(akfs_map_v3*);
+
+/**
+ * Gets original hash out of the akfs_map_v3
+ * @param akfs_map_v3
+ * @return pointer to sha512sum
+ */
+sha512sum* ak_fs_map_v3_get_orig_hash(akfs_map_v3*);
+
+/**
+ * Compares two akfs_map_v3 structs
+ * @param akfs_map_v3*
+ * @param akfs_map_v3*
+ * @return bool
+ */
+bool ak_fs_map_v3_compare(akfs_map_v3*, akfs_map_v3*);
+
+/**
+ * Initializes an array of akfs_map_v4
+ */
+void ak_fs_init_map_v4_store(akfs_map_v4**, size_t);
+
+/**
+ * Unused
+ */
+void ak_fs_map_v4_init(akfs_map_v4*);
+
+/**
+ * Unused
+ */
+bool ak_fs_map_v4_compare(akfs_map_v4*, akfs_map_v4*);
+/**
+ * Unused
+ */
+bool ak_fs_map_v4_is_null(akfs_map_v4*);
+/**
+ * Unused
+ */
+char* ak_fs_map_v4_get_filename(akfs_map_v4*);
+/**
+ * Unused
+ */
+sha512sum* ak_fs_map_v4_get_map_hash(akfs_map_v4*);
+/**
+ * Unused
+ */
+sha512sum* ak_fs_map_v4_get_root_hash(akfs_map_v4*);
+/**
+ * Unused
+ */
+sha512sum* ak_fs_map_v4_get_orig_hash(akfs_map_v4*);
+
+/**
+ *
+ * @return size_t Number of files found in maps fs location
+ */
+size_t ak_fs_maps_v3_found_in_fs();
+
+/**
+ * Prints a list of the maps (version 3 format) available on the local fs along
+ * with their root hash and file name.
+ *
+ * @return int Status value
+ */
+int ak_fs_ls();
+
+/**
+ * Main function for call from other programs
+ *
+ * @return int Exit value
+ */
+int ak_fs_main(int, char**);
+
+/**
+ * Compares an mt_branch with a NULL one
+ * @param mt_branch*
+ * @return boolean
+ */
+bool ak_fs_mt_branch_is_null(mt_branch*);
+
+/**
+ * Compares two mt_branch between them
+ * @param mt_branch*
+ * @return boolean
+ */
+bool ak_fs_mt_branch_compare(mt_branch*, mt_branch*);
+
+/**
+ * Concatenates a file from a root hash.
+ * @param sha512sum*
+ * @return int status
+ */
+int ak_fs_cat_file_from_root_hash(const sha512sum*);
+
+/**
+ * Concatenates a file from a akfs_map_v3 map
+ * @param akfs_map_v3*
+ * @return int status
+ */
+int ak_fs_cfm(akfs_map_v3*);
#endif // AKFS
diff --git a/c_implementation/include/libaklog.h b/c_implementation/include/libaklog.h
index 31478a7..fa441a4 100644
--- a/c_implementation/include/libaklog.h
+++ b/c_implementation/include/libaklog.h
@@ -2,23 +2,26 @@
#define AKLOG
typedef enum {
+ TEST,
INFO,
WARNING,
ERROR,
EXIT,
- DEBUG
+ DEBUG,
} LogMessageType;
-void ak_log_print_log_line(char* line);
+void ak_log_print_log_line(const char*);
void ak_log_follow();
-void ak_log_grep(char* string);
+void ak_log_grep(char*);
void ak_log_rotate();
-int ak_log_write_to_file(char* message);
-void ak_log_message(const char* program, LogMessageType lmtype, char* message);
-void ak_log_exit(const char* program, char* message);
-void ak_log_warning(const char* program, char* message);
-void ak_log_debug(const char* program, char* message);
-void ak_log_error(const char* program, char* message);
-void ak_log_info(const char* program, char* message);
+int ak_log_write_to_file(const char*);
+void ak_log_message(const char*, LogMessageType, char*);
+void ak_log_exit(const char*, char*);
+void ak_log_warning(const char*, char*);
+void ak_log_debug(const char*, char*);
+void ak_log_error(const char*, char*);
+void ak_log_info(const char*, char*);
+void ak_log_test(const char*, char*);
+int ak_log_main(int, char**);
#endif // AKLOG
diff --git a/c_implementation/include/libaksettings.h b/c_implementation/include/libaksettings.h
index e95f37d..505e502 100644
--- a/c_implementation/include/libaksettings.h
+++ b/c_implementation/include/libaksettings.h
@@ -8,18 +8,19 @@ typedef struct {
char *value;
} AKSetting;
-int ak_settings();
void ak_settings_print_setting(AKSetting);
int ak_settings_from_file();
int ak_setting_to_file(AKSetting);
+AKSetting* ak_settings_get_all();
-const char *ak_settings_get_setting(const char *key);
-bool ak_settings_set_setting(const char *key, const char *value);
+char *ak_settings_get_setting(const char*);
+bool ak_settings_set_setting(const char*, const char*);
bool ak_settings_save_settings();
bool ak_settings_load_settings_binary();
int ak_settings_find_setting(const char *key);
void ak_settings_free_settings();
bool ak_settings_save_settings_binary();
+void ak_settings_import_from_environment();
#endif // AK_SETTINGS_H
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(a