libqaeda

Unnamed repository; edit this file 'description' to name the repository.
Info | Log | Files | Refs | README | LICENSE

commit 31981858daa0987be527d21cb5c7264b586e9267
parent 52e141c3b456e6a6179f56b3e1ab6597cdc44e56
Author: lash <dev@holbrook.no>
Date:   Sun,  4 May 2025 12:00:34 +0100

Add store query module

Diffstat:
Msrc/aux/liblash/src/llog/Makefile | 13+++++++------
Dsrc/aux/liblash/src/llog/hex.c | 21---------------------
Msrc/aux/liblash/src/llog/llog.c | 4+---
Msrc/aux/liblash/src/rerr/rerr.c | 1+
Msrc/aux/liblash/src/rerr/rerr.h | 1+
Msrc/io/std.c | 4+++-
Asrc/lq/query.h | 27+++++++++++++++++++++++++++
Msrc/store/file.c | 101+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--
Msrc/test/Makefile | 8+++++---
Asrc/test/test_query.c | 112+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Msrc/test/test_store.c | 14+++++++-------
11 files changed, 263 insertions(+), 43 deletions(-)

diff --git a/src/aux/liblash/src/llog/Makefile b/src/aux/liblash/src/llog/Makefile @@ -6,11 +6,14 @@ VERSION = 0.0.1 all: $(OBJS) -test: all - $(CC) $(CFLAGS) test.c llog.o hex.o -o test.out $(LDFLAGS) +hex: + make -C ../hex all + +test: hex all + $(CC) $(CFLAGS) test.c llog.o ../hex/hex.o -o test.out $(LDFLAGS) %.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ $(LDFLAGS) + $(CC) $(CFLAGS) -I../hex -c $< -o $@ $(LDFLAGS) clean: rm -vf *.o @@ -21,8 +24,6 @@ archive: git archive --format=tar.gz HEAD -o llog-$(VERSION).tar.gz %.so.o: %.c - $(CC) $(CFLAGS) -c $< -o $@ -fpic + $(CC) $(CFLAGS) -I../hex -c $< -o $@ -fpic shared: $(SOBJS) - - diff --git a/src/aux/liblash/src/llog/hex.c b/src/aux/liblash/src/llog/hex.c @@ -1,21 +0,0 @@ -#include <stdio.h> - -char *_x = "0123456789abcdef"; - -void b2h(const unsigned char *data, int l, unsigned char *zHex) { - unsigned int i; - - for (i = 0; i < l; i++) { - sprintf((char*)zHex+(i*2), "%02x", *(data+i)); - } -} - -char* c2h(char in, char *out) { - char i; - i = in & 0x0f; - *(out+1) = *(_x+i); - in >>= 4; - i = in & 0x0f; - *out = *(_x+i); - return out; -} diff --git a/src/aux/liblash/src/llog/llog.c b/src/aux/liblash/src/llog/llog.c @@ -1,7 +1,5 @@ #include "llog.h" - -extern void b2h(const unsigned char *b, int l, char *hx); -extern char* c2h(char in, char *out); +#include "hex.h" char lloglvl_str[][4] = { diff --git a/src/aux/liblash/src/rerr/rerr.c b/src/aux/liblash/src/rerr/rerr.c @@ -23,6 +23,7 @@ char *rerr_base[3] = { "Wrong byteorder", "Value too large", "Value too small", + "End of file", #endif }; #endif diff --git a/src/aux/liblash/src/rerr/rerr.h b/src/aux/liblash/src/rerr/rerr.h @@ -16,6 +16,7 @@ enum err_base_e { ERR_BYTEORDER, ERR_OVERFLOW, ERR_UNDERFLOW, + ERR_EOF, }; #ifndef RERR_N_PFX diff --git a/src/io/std.c b/src/io/std.c @@ -51,6 +51,7 @@ static int fltr_files(const struct dirent *d) { /** * \todo scandir calls malloc, so lq_alloc needs malloc alias that maps to it. + * \todo strdup doubles the mem needed for the iteration, instead need to keep scandir state and release after treatment */ int lq_files(const char *path, char **files, size_t files_len) { int r; @@ -66,7 +67,8 @@ int lq_files(const char *path, char **files, size_t files_len) { return -2; } for (i = 0; i < r; i++) { - *(files+i) = (*(ls+i))->d_name; + //*(files+i) = (*(ls+i))->d_name; + *(files+i) = strdup((*(ls+i))->d_name); } *(files+i+1) = NULL; lq_free(ls); diff --git a/src/lq/query.h b/src/lq/query.h @@ -0,0 +1,27 @@ +#ifndef LIBQAEDA_QUERY_H_ +#define LIBQAEDA_QUERY_H_ + +enum lq_query_state_e { + LQ_QUERY_EMPTY = 0, + LQ_QUERY_READY = 1, + LQ_QUERY_GONER = 2, + LQ_QUERY_EOF = 4, +}; + +typedef struct lq_query_t LQQuery; +struct lq_query_t { + LQStore *store; + enum payload_e typ; + int state; + char **files; + size_t files_len; + size_t files_cur; + char *value; + size_t value_len; +}; + +LQQuery* lq_query_new(enum payload_e typ, LQStore *store, const char *key, size_t key_len); +int lq_query_next(LQQuery *query); +void lq_query_free(LQQuery *query); + +#endif // LIBQAEDA_QUERY_H_ diff --git a/src/store/file.c b/src/store/file.c @@ -12,6 +12,7 @@ #include "lq/store.h" #include "lq/err.h" #include "lq/mem.h" +#include "lq/query.h" #include "debug.h" static const int store_typ_file = 3; @@ -20,7 +21,7 @@ static const int store_typ_file = 3; int lq_file_content_count(enum payload_e typ, LQStore *store, const char *key, size_t key_len) { int r; char **out; - char buf[LQ_DIGEST_LEN * 2 + 1]; + char buf[LQ_STORE_KEY_MAX * 2 + 1]; char pfx[1024]; out = lq_alloc(sizeof(char**) * LQ_DIRS_MAX); @@ -39,7 +40,7 @@ int lq_file_content_get(enum payload_e typ, LQStore *store, const char *key, siz int f; size_t l; size_t c; - char buf[LQ_DIGEST_LEN * 2 + 1]; + char buf[LQ_STORE_KEY_MAX * 2 + 1]; char path[1024]; char *p; @@ -129,6 +130,102 @@ void lq_file_content_free(LQStore *store) { lq_free(store); } +/** + * \todo DRY with lq_files_pfx + * \todo prefix mismatches leak? + */ +static int query_list(const char *path, char **files, size_t files_len, const char *prefix, char prefix_len) { + int r; + int i; + int c; + size_t l; + + c = 0; + r = lq_files(path, files, files_len); + for (i = 0; i < r; i++) { + l = strlen(*(files+i)); + if (l < prefix_len) { + lq_free(*(files+i)); + } + if (!lq_cmp(prefix, *(files+i), prefix_len)) { + // lq_free(*(files+c));// attempt at stopping mismatch leak. + *(files+c) = *(files+i); + c++; + } + } + return c; +} + +/// \todo DRY with lq_file_count +LQQuery* lq_query_new(enum payload_e typ, LQStore *store, const char *key, size_t key_len) { + LQQuery *query; + //char **out; + char buf[LQ_STORE_KEY_MAX * 2 + 1]; + char pfx[1024]; + + query = lq_alloc(sizeof(LQQuery)); + lq_zero(query, sizeof(LQQuery)); + query->files = lq_alloc(sizeof(char**) * LQ_DIRS_MAX); + pfx[0] = (char)typ + 0x30; + b2h((const unsigned char*)key, (int)key_len, (unsigned char*)buf); + lq_cpy(pfx+1, buf, strlen(buf) + 1); + + key_len *= 2; + query->typ = typ; + query->files_len = query_list(store->userdata, query->files, LQ_DIRS_MAX, pfx, key_len + 1); + if (query->files_len == 0) { + return NULL; + } + query->value = lq_alloc(LQ_STORE_VAL_MAX); + query->store = store; + query->state = LQ_QUERY_READY; + + return query; +} + +int lq_query_next(LQQuery *query) { + int r; + char *p; + char b[LQ_STORE_KEY_MAX]; + + if (query->state & LQ_QUERY_EOF) { + return ERR_EOF; + } + p = *(query->files + query->files_cur) + 1; + r = h2b(p, (char*)b); + if (r == 0) { + query->state = LQ_QUERY_GONER; + return ERR_ENCODING; + } + r = query->store->get(query->typ, query->store, b, r, query->value, &query->value_len); + if (r != ERR_OK) { + query->state = LQ_QUERY_GONER; + return ERR_FAIL; + } + if (query->files_cur++ == query->files_len) { + query->state = LQ_QUERY_EOF; + } + return ERR_OK; +} + +void lq_query_free(LQQuery *query) { + char *p; + int i; + + i = 0; + while(1) { + if (*((query->files)+i) != NULL) { + break; + } + lq_free(*((query->files)+i)); + *((query->files)+i) = NULL; + i++; + } + lq_free(query->files); + lq_free(query->value); + lq_free(query); +} + struct lq_store_t LQFileContent = { .store_typ = store_typ_file, .userdata = "", diff --git a/src/test/Makefile b/src/test/Makefile @@ -7,8 +7,8 @@ LIBS := ../asn1/defs_asn1_tab.o `pkg-config --libs libtasn1 libgcrypt` -L.. -L.. LDFLAGS := -lcheck $(LIBS) COMMONOBJS = ../mem/std.o ../lq/config.o ../lq/err.o ../lq/base.o ../debug.o -all: build all-tests -#all: build one-test +#all: build all-tests +all: build one-test all-tests: cK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_test_bin @@ -20,9 +20,10 @@ all-tests: CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_envelope_bin CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_trust_bin CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_store_bin + CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_query_bin one-test: build - CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_envelope_bin + CK_FORK=no LD_LIBRARY_PATH=`realpath ../aux/lib` ./test_query_bin test: all @@ -39,6 +40,7 @@ build: $(CC) $(CFLAGS) test_envelope.c -o test_envelope_bin $(COMMONOBJS) ../store/dummy.o $(LDFLAGS) -lgcrypt $(CC) $(CFLAGS) test_trust.c -o test_trust_bin $(COMMONOBJS) $(LDFLAGS) $(CC) $(CFLAGS) test_store.c -o test_store_bin $(COMMONOBJS) $(LDFLAGS) -lgcrypt + $(CC) $(CFLAGS) test_query.c -o test_query_bin $(COMMONOBJS) $(LDFLAGS) -lgcrypt clean: rm -vf test_*_bin diff --git a/src/test/test_query.c b/src/test/test_query.c @@ -0,0 +1,112 @@ +#include <check.h> +#include <stdlib.h> +#include <string.h> + +#include "lq/store.h" +#include "lq/mem.h" +#include "lq/query.h" +#include "lq/io.h" +#include "lq/err.h" + +extern LQStore LQFileContent; + +/** + * \todo DRY file store dir creation + */ +START_TEST(check_query_full) { + int r; + LQStore store; + char path[LQ_PATH_MAX]; + char *k; + char *v; + size_t kl; + size_t vl; + LQQuery *query; + + lq_cpy(&store, &LQFileContent, sizeof(LQStore)); + lq_cpy(path, "/tmp/lqstore_file_XXXXXX", 25); + store.userdata = mktempdir(path); + *((char*)(store.userdata+24)) = '/'; + *((char*)(store.userdata+25)) = 0x0; + + k = "aaa"; + v = "foo"; + kl = 3; + vl = 3; + store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl); + + k = "ab"; + v = "bar"; + kl = 2; + vl = 3; + store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl); + + k = "aaa"; + v = "inky"; + kl = 3; + vl = 4; + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); + + k = "aab"; + v = "pinky"; + kl = 3; + vl = 5; + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); + + k = "b"; + v = "blinky"; + kl = 1; + vl = 6; + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); + + k = "bbc"; + v = "clyde"; + kl = 3; + vl = 5; + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); + + k = "bbc"; + v = "clyde"; + kl = 3; + vl = 5; + store.put(LQ_CONTENT_CERT, &store, k, &kl, v, vl); + + query = lq_query_new(LQ_CONTENT_RAW, &store, "aa", 2); + ck_assert_ptr_nonnull(query); + + r = lq_query_next(query); + ck_assert_int_eq(r, ERR_OK); + r = lq_query_next(query); + ck_assert_int_eq(r, ERR_OK); + r = lq_query_next(query); + ck_assert_int_eq(r, ERR_EOF); +} +END_TEST + +Suite * common_suite(void) { + Suite *s; + TCase *tc; + + s = suite_create("query"); + tc = tcase_create("files"); + tcase_add_test(tc, check_query_full); + suite_add_tcase(s, tc); + + return s; +} + +int main(void) { + int n_fail; + + Suite *s; + SRunner *sr; + + s = common_suite(); + sr = srunner_create(s); + + srunner_run_all(sr, CK_VERBOSE); + n_fail = srunner_ntests_failed(sr); + srunner_free(sr); + + return (n_fail == 0) ? EXIT_SUCCESS : EXIT_FAILURE; +} diff --git a/src/test/test_store.c b/src/test/test_store.c @@ -28,43 +28,43 @@ START_TEST(check_store_count) { v = "foo"; kl = 3; vl = 3; - store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl); k = "ab"; v = "bar"; kl = 2; vl = 3; - store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_RAW, &store, k, &kl, v, vl); k = "aaa"; v = "inky"; kl = 3; vl = 4; - store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); k = "aab"; v = "pinky"; kl = 3; vl = 5; - store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); k = "b"; v = "blinky"; kl = 1; vl = 6; - store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); k = "bbc"; v = "clyde"; kl = 3; vl = 5; - store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_MSG, &store, k, &kl, v, vl); k = "bbc"; v = "clyde"; kl = 3; vl = 5; - store.put(LQ_CONTENT_CERT, &store, k, &kl, v, vl), + store.put(LQ_CONTENT_CERT, &store, k, &kl, v, vl); r = store.count(LQ_CONTENT_MSG, &store, "aa", 2);