Add generic records and collections

This commit is contained in:
Carl Niklas Rydberg 2026-01-23 19:15:16 +01:00
parent e2d26e53cd
commit 85c23e49eb
6 changed files with 1343 additions and 1 deletions

View file

@ -79,6 +79,14 @@ set(AMDUAT_ASL_LOG_STORE_SRCS
src/core/asl_log_store.c src/core/asl_log_store.c
) )
set(AMDUAT_ASL_RECORD_SRCS
src/core/asl_record.c
)
set(AMDUAT_ASL_COLLECTION_SRCS
src/core/asl_collection.c
)
set(AMDUAT_HASH_ASL1_SRCS set(AMDUAT_HASH_ASL1_SRCS
src/near_core/hash/asl1.c src/near_core/hash/asl1.c
src/near_core/hash/sha256.c src/near_core/hash/sha256.c
@ -215,6 +223,13 @@ target_compile_definitions(amduat_asl_pointer_fs_obj PRIVATE _POSIX_C_SOURCE=200
amduat_add_lib(asl_log_store SRCS ${AMDUAT_ASL_LOG_STORE_SRCS}) amduat_add_lib(asl_log_store SRCS ${AMDUAT_ASL_LOG_STORE_SRCS})
amduat_link(asl_log_store amduat_asl_pointer_fs amduat_asl amduat_enc amduat_util) amduat_link(asl_log_store amduat_asl_pointer_fs amduat_asl amduat_enc amduat_util)
amduat_add_lib(asl_record SRCS ${AMDUAT_ASL_RECORD_SRCS})
amduat_link(asl_record amduat_asl amduat_enc amduat_util)
amduat_add_lib(asl_collection SRCS ${AMDUAT_ASL_COLLECTION_SRCS})
amduat_link(asl_collection amduat_asl_log_store amduat_asl_record amduat_asl_pointer_fs
amduat_asl amduat_enc amduat_util)
amduat_add_lib(tgk_store_mem SRCS ${AMDUAT_TGK_STORE_MEM_SRCS}) amduat_add_lib(tgk_store_mem SRCS ${AMDUAT_TGK_STORE_MEM_SRCS})
amduat_link(tgk_store_mem amduat_tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util) amduat_link(tgk_store_mem amduat_tgk amduat_asl amduat_enc amduat_hash_asl1 amduat_util)
@ -268,7 +283,8 @@ target_include_directories(amduat_pel_cli
) )
target_link_libraries(amduat_pel_cli target_link_libraries(amduat_pel_cli
PRIVATE amduat_format amduat_pel amduat_asl_store_fs PRIVATE amduat_format amduat_pel amduat_asl_store_fs
amduat_asl_log_store amduat_asl_pointer_fs amduat_asl_collection amduat_asl_record amduat_asl_log_store
amduat_asl_pointer_fs
amduat_asl_derivation_index_fs amduat_asl amduat_enc amduat_asl_derivation_index_fs amduat_asl amduat_enc
amduat_hash_asl1 amduat_util amduat_hash_asl1 amduat_util
) )

View file

@ -0,0 +1,68 @@
#ifndef AMDUAT_ASL_COLLECTION_H
#define AMDUAT_ASL_COLLECTION_H
#include "amduat/asl/asl_pointer_fs.h"
#include "amduat/asl/core.h"
#include "amduat/asl/log_store.h"
#include "amduat/asl/record.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
typedef enum {
AMDUAT_ASL_COLLECTION_OK = 0,
AMDUAT_ASL_COLLECTION_ERR_INVALID_NAME = 1,
AMDUAT_ASL_COLLECTION_ERR_IO = 2,
AMDUAT_ASL_COLLECTION_ERR_INTEGRITY = 3,
AMDUAT_ASL_COLLECTION_ERR_CAS_MISMATCH = 4
} amduat_asl_collection_error_t;
typedef struct {
amduat_asl_store_t *store;
amduat_asl_log_store_t log_store;
amduat_asl_pointer_store_t pointer_store;
} amduat_asl_collection_store_t;
bool amduat_asl_collection_store_init(
amduat_asl_collection_store_t *collection_store,
const char *root_path,
amduat_asl_store_t *store);
amduat_asl_collection_error_t amduat_asl_collection_append(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
amduat_reference_t record_ref,
uint16_t kind,
amduat_octets_t actor,
uint64_t *out_offset);
amduat_asl_collection_error_t amduat_asl_collection_snapshot(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
uint64_t up_to_offset,
amduat_reference_t *out_snapshot_ref,
bool *out_swapped);
amduat_asl_collection_error_t amduat_asl_collection_read(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
uint64_t from_offset,
size_t limit,
amduat_reference_t **out_record_refs,
size_t *out_len,
uint64_t *out_next_offset,
bool *out_end);
void amduat_asl_collection_refs_free(amduat_reference_t *refs,
size_t refs_len);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_ASL_COLLECTION_H */

View file

@ -0,0 +1,46 @@
#ifndef AMDUAT_ASL_RECORD_H
#define AMDUAT_ASL_RECORD_H
#include "amduat/asl/core.h"
#include "amduat/asl/store.h"
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
enum { TYPE_TAG_ASL_RECORD_1 = 0x00000402u };
enum { AMDUAT_TYPE_TAG_ASL_RECORD_1 = TYPE_TAG_ASL_RECORD_1 };
typedef struct {
amduat_octets_t schema;
amduat_octets_t payload;
} amduat_asl_record_t;
bool amduat_asl_record_encode_v1(const amduat_asl_record_t *record,
amduat_octets_t *out_bytes);
bool amduat_asl_record_decode_v1(amduat_octets_t bytes,
amduat_asl_record_t *out_record);
void amduat_asl_record_free(amduat_asl_record_t *record);
amduat_asl_store_error_t amduat_asl_record_store_put(
amduat_asl_store_t *store,
amduat_octets_t schema,
amduat_octets_t payload,
amduat_reference_t *out_ref);
amduat_asl_store_error_t amduat_asl_record_store_get(
amduat_asl_store_t *store,
amduat_reference_t ref,
amduat_asl_record_t *out_record);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* AMDUAT_ASL_RECORD_H */

483
src/core/asl_collection.c Normal file
View file

@ -0,0 +1,483 @@
#include "amduat/asl/collection.h"
#include "amduat/enc/asl1_core_codec.h"
#include "amduat/util/log.h"
#include <limits.h>
#include <stdlib.h>
#include <string.h>
enum {
AMDUAT_ASL_COLLECTION_MAGIC_LEN = 8,
AMDUAT_ASL_COLLECTION_VERSION = 1,
AMDUAT_ASL_COLLECTION_READ_BATCH = 1024u
};
static const uint8_t k_amduat_asl_collection_magic[
AMDUAT_ASL_COLLECTION_MAGIC_LEN] = {
'A', 'S', 'L', 'C', 'O', 'L', '1', '\0'
};
static void amduat_asl_collection_store_u32_le(uint8_t *out, uint32_t value) {
out[0] = (uint8_t)(value & 0xffu);
out[1] = (uint8_t)((value >> 8) & 0xffu);
out[2] = (uint8_t)((value >> 16) & 0xffu);
out[3] = (uint8_t)((value >> 24) & 0xffu);
}
static void amduat_asl_collection_store_u64_le(uint8_t *out, uint64_t value) {
out[0] = (uint8_t)(value & 0xffu);
out[1] = (uint8_t)((value >> 8) & 0xffu);
out[2] = (uint8_t)((value >> 16) & 0xffu);
out[3] = (uint8_t)((value >> 24) & 0xffu);
out[4] = (uint8_t)((value >> 32) & 0xffu);
out[5] = (uint8_t)((value >> 40) & 0xffu);
out[6] = (uint8_t)((value >> 48) & 0xffu);
out[7] = (uint8_t)((value >> 56) & 0xffu);
}
static bool amduat_asl_collection_add_size(size_t *acc, size_t add) {
if (*acc > SIZE_MAX - add) {
return false;
}
*acc += add;
return true;
}
static bool amduat_asl_collection_build_log_name(const char *name,
char **out_name) {
size_t name_len;
size_t total_len;
char *buffer;
size_t offset;
if (name == NULL || out_name == NULL) {
return false;
}
if (!amduat_asl_pointer_name_is_valid(name)) {
return false;
}
name_len = strlen(name);
total_len = 11u + name_len + 4u + 1u;
buffer = (char *)malloc(total_len);
if (buffer == NULL) {
return false;
}
offset = 0u;
memcpy(buffer + offset, "collection/", 11u);
offset += 11u;
memcpy(buffer + offset, name, name_len);
offset += name_len;
memcpy(buffer + offset, "/log", 4u);
offset += 4u;
buffer[offset] = '\0';
*out_name = buffer;
return true;
}
static bool amduat_asl_collection_build_head_name(const char *name,
char **out_name) {
size_t name_len;
size_t total_len;
char *buffer;
size_t offset;
if (name == NULL || out_name == NULL) {
return false;
}
if (!amduat_asl_pointer_name_is_valid(name)) {
return false;
}
name_len = strlen(name);
total_len = 11u + name_len + 5u + 1u;
buffer = (char *)malloc(total_len);
if (buffer == NULL) {
return false;
}
offset = 0u;
memcpy(buffer + offset, "collection/", 11u);
offset += 11u;
memcpy(buffer + offset, name, name_len);
offset += name_len;
memcpy(buffer + offset, "/head", 5u);
offset += 5u;
buffer[offset] = '\0';
*out_name = buffer;
return true;
}
static bool amduat_asl_collection_encode_snapshot_payload(
uint64_t snapshot_offset,
const amduat_reference_t *refs,
size_t refs_len,
amduat_octets_t *out_payload) {
size_t total_len = 0u;
uint8_t *buffer;
size_t offset = 0u;
if (out_payload == NULL) {
return false;
}
out_payload->data = NULL;
out_payload->len = 0u;
if (refs_len > UINT32_MAX) {
return false;
}
if (!amduat_asl_collection_add_size(
&total_len, AMDUAT_ASL_COLLECTION_MAGIC_LEN + 4u + 8u + 4u)) {
return false;
}
for (size_t i = 0u; i < refs_len; ++i) {
amduat_octets_t ref_bytes = amduat_octets(NULL, 0u);
if (!amduat_enc_asl1_core_encode_reference_v1(refs[i], &ref_bytes)) {
return false;
}
if (!amduat_asl_collection_add_size(&total_len, 4u + ref_bytes.len)) {
free((void *)ref_bytes.data);
return false;
}
free((void *)ref_bytes.data);
}
buffer = (uint8_t *)malloc(total_len);
if (buffer == NULL) {
return false;
}
memcpy(buffer + offset, k_amduat_asl_collection_magic,
AMDUAT_ASL_COLLECTION_MAGIC_LEN);
offset += AMDUAT_ASL_COLLECTION_MAGIC_LEN;
amduat_asl_collection_store_u32_le(buffer + offset,
AMDUAT_ASL_COLLECTION_VERSION);
offset += 4u;
amduat_asl_collection_store_u64_le(buffer + offset, snapshot_offset);
offset += 8u;
amduat_asl_collection_store_u32_le(buffer + offset, (uint32_t)refs_len);
offset += 4u;
for (size_t i = 0u; i < refs_len; ++i) {
amduat_octets_t ref_bytes = amduat_octets(NULL, 0u);
if (!amduat_enc_asl1_core_encode_reference_v1(refs[i], &ref_bytes)) {
free(buffer);
return false;
}
amduat_asl_collection_store_u32_le(buffer + offset,
(uint32_t)ref_bytes.len);
offset += 4u;
memcpy(buffer + offset, ref_bytes.data, ref_bytes.len);
offset += ref_bytes.len;
free((void *)ref_bytes.data);
}
if (offset != total_len) {
free(buffer);
return false;
}
*out_payload = amduat_octets(buffer, total_len);
return true;
}
bool amduat_asl_collection_store_init(
amduat_asl_collection_store_t *collection_store,
const char *root_path,
amduat_asl_store_t *store) {
if (collection_store == NULL || root_path == NULL || store == NULL) {
return false;
}
collection_store->store = store;
if (!amduat_asl_pointer_store_init(&collection_store->pointer_store,
root_path)) {
return false;
}
if (!amduat_asl_log_store_init(&collection_store->log_store, root_path,
store, &collection_store->pointer_store)) {
return false;
}
return true;
}
amduat_asl_collection_error_t amduat_asl_collection_append(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
amduat_reference_t record_ref,
uint16_t kind,
amduat_octets_t actor,
uint64_t *out_offset) {
char *log_name = NULL;
amduat_asl_log_entry_t entry;
amduat_asl_store_error_t err;
if (collection_store == NULL || collection_store->store == NULL ||
collection_name == NULL) {
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
if (!amduat_asl_pointer_name_is_valid(collection_name)) {
return AMDUAT_ASL_COLLECTION_ERR_INVALID_NAME;
}
if (!amduat_asl_collection_build_log_name(collection_name, &log_name)) {
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
memset(&entry, 0, sizeof(entry));
entry.kind = kind;
entry.payload_ref = record_ref;
entry.has_actor = actor.len != 0u;
entry.actor = actor;
err = amduat_asl_log_append(&collection_store->log_store, log_name,
&entry, 1u, out_offset);
free(log_name);
if (err != AMDUAT_ASL_STORE_OK) {
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
return AMDUAT_ASL_COLLECTION_OK;
}
amduat_asl_collection_error_t amduat_asl_collection_snapshot(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
uint64_t up_to_offset,
amduat_reference_t *out_snapshot_ref,
bool *out_swapped) {
char *log_name = NULL;
char *head_name = NULL;
amduat_reference_t *refs = NULL;
size_t refs_len = 0u;
uint64_t from = 0u;
bool end = false;
uint64_t next_offset = 0u;
amduat_asl_record_t snapshot_record;
amduat_octets_t payload = amduat_octets(NULL, 0u);
amduat_reference_t snapshot_ref;
amduat_asl_pointer_error_t ptr_err;
bool head_exists = false;
amduat_reference_t head_ref;
bool swapped = false;
if (out_snapshot_ref != NULL) {
out_snapshot_ref->hash_id = 0u;
out_snapshot_ref->digest = amduat_octets(NULL, 0u);
}
if (out_swapped != NULL) {
*out_swapped = false;
}
if (collection_store == NULL || collection_store->store == NULL ||
collection_name == NULL) {
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
if (!amduat_asl_pointer_name_is_valid(collection_name)) {
return AMDUAT_ASL_COLLECTION_ERR_INVALID_NAME;
}
if (!amduat_asl_collection_build_log_name(collection_name, &log_name) ||
!amduat_asl_collection_build_head_name(collection_name, &head_name)) {
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
while (!end && (up_to_offset == UINT64_MAX || from <= up_to_offset)) {
size_t limit = AMDUAT_ASL_COLLECTION_READ_BATCH;
amduat_asl_log_entry_t *entries = NULL;
size_t entries_len = 0u;
amduat_asl_store_error_t err = amduat_asl_log_read(
&collection_store->log_store, log_name, from, limit, &entries,
&entries_len, &next_offset, &end);
if (err != AMDUAT_ASL_STORE_OK) {
free(log_name);
free(head_name);
amduat_asl_collection_refs_free(refs, refs_len);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
for (size_t i = 0u; i < entries_len; ++i) {
uint64_t offset = from + i;
if (up_to_offset != UINT64_MAX && offset > up_to_offset) {
end = true;
break;
}
amduat_reference_t *next =
(amduat_reference_t *)realloc(
refs, (refs_len + 1u) * sizeof(*refs));
if (next == NULL) {
amduat_asl_log_entries_free(entries, entries_len);
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
refs = next;
refs[refs_len] = entries[i].payload_ref;
if (!amduat_octets_clone(entries[i].payload_ref.digest,
&refs[refs_len].digest)) {
amduat_asl_log_entries_free(entries, entries_len);
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
refs_len++;
}
amduat_asl_log_entries_free(entries, entries_len);
from = next_offset;
if (entries_len == 0u) {
break;
}
}
{
uint64_t snapshot_offset = from;
if (up_to_offset != UINT64_MAX &&
up_to_offset < UINT64_MAX &&
snapshot_offset > up_to_offset + 1u) {
snapshot_offset = up_to_offset + 1u;
}
if (!amduat_asl_collection_encode_snapshot_payload(
snapshot_offset, refs, refs_len, &payload)) {
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
}
if (payload.len == 0u || payload.data == NULL) {
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
{
amduat_asl_store_error_t err = amduat_asl_record_store_put(
collection_store->store,
amduat_octets("collection/snapshot",
strlen("collection/snapshot")),
payload,
&snapshot_ref);
amduat_octets_free(&payload);
if (err != AMDUAT_ASL_STORE_OK) {
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
}
ptr_err = amduat_asl_pointer_get(&collection_store->pointer_store, head_name,
&head_exists, &head_ref);
if (ptr_err != AMDUAT_ASL_POINTER_OK) {
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
ptr_err = amduat_asl_pointer_cas(&collection_store->pointer_store, head_name,
head_exists,
head_exists ? &head_ref : NULL,
&snapshot_ref, &swapped);
if (head_exists) {
amduat_reference_free(&head_ref);
}
if (ptr_err != AMDUAT_ASL_POINTER_OK) {
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
if (out_swapped != NULL) {
*out_swapped = swapped;
}
if (out_snapshot_ref != NULL) {
*out_snapshot_ref = snapshot_ref;
}
if (!swapped) {
amduat_log(AMDUAT_LOG_DEBUG, "collection snapshot CAS mismatch");
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_ERR_CAS_MISMATCH;
}
amduat_asl_collection_refs_free(refs, refs_len);
free(log_name);
free(head_name);
return AMDUAT_ASL_COLLECTION_OK;
}
amduat_asl_collection_error_t amduat_asl_collection_read(
amduat_asl_collection_store_t *collection_store,
const char *collection_name,
uint64_t from_offset,
size_t limit,
amduat_reference_t **out_record_refs,
size_t *out_len,
uint64_t *out_next_offset,
bool *out_end) {
char *log_name = NULL;
amduat_asl_log_entry_t *entries = NULL;
size_t entries_len = 0u;
amduat_asl_store_error_t err;
if (out_record_refs == NULL || out_len == NULL ||
out_next_offset == NULL || out_end == NULL) {
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
*out_record_refs = NULL;
*out_len = 0u;
if (collection_store == NULL || collection_store->store == NULL ||
collection_name == NULL) {
return AMDUAT_ASL_COLLECTION_ERR_INTEGRITY;
}
if (!amduat_asl_pointer_name_is_valid(collection_name)) {
return AMDUAT_ASL_COLLECTION_ERR_INVALID_NAME;
}
if (!amduat_asl_collection_build_log_name(collection_name, &log_name)) {
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
err = amduat_asl_log_read(&collection_store->log_store, log_name,
from_offset, limit, &entries, &entries_len,
out_next_offset, out_end);
free(log_name);
if (err != AMDUAT_ASL_STORE_OK) {
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
if (entries_len != 0u) {
amduat_reference_t *refs =
(amduat_reference_t *)calloc(entries_len, sizeof(*refs));
if (refs == NULL) {
amduat_asl_log_entries_free(entries, entries_len);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
for (size_t i = 0u; i < entries_len; ++i) {
refs[i].hash_id = entries[i].payload_ref.hash_id;
if (!amduat_octets_clone(entries[i].payload_ref.digest,
&refs[i].digest)) {
amduat_asl_collection_refs_free(refs, i);
amduat_asl_log_entries_free(entries, entries_len);
return AMDUAT_ASL_COLLECTION_ERR_IO;
}
}
*out_record_refs = refs;
*out_len = entries_len;
}
amduat_asl_log_entries_free(entries, entries_len);
return AMDUAT_ASL_COLLECTION_OK;
}
void amduat_asl_collection_refs_free(amduat_reference_t *refs,
size_t refs_len) {
if (refs == NULL) {
return;
}
for (size_t i = 0u; i < refs_len; ++i) {
amduat_reference_free(&refs[i]);
}
free(refs);
}

268
src/core/asl_record.c Normal file
View file

@ -0,0 +1,268 @@
#include "amduat/asl/record.h"
#include <stdlib.h>
#include <string.h>
enum {
AMDUAT_ASL_RECORD_MAGIC_LEN = 8,
AMDUAT_ASL_RECORD_VERSION = 1
};
static const uint8_t k_amduat_asl_record_magic[AMDUAT_ASL_RECORD_MAGIC_LEN] = {
'A', 'S', 'L', 'R', 'E', 'C', '1', '\0'
};
static void amduat_asl_record_store_u32_le(uint8_t *out, uint32_t value) {
out[0] = (uint8_t)(value & 0xffu);
out[1] = (uint8_t)((value >> 8) & 0xffu);
out[2] = (uint8_t)((value >> 16) & 0xffu);
out[3] = (uint8_t)((value >> 24) & 0xffu);
}
static bool amduat_asl_record_read_u32_le(const uint8_t *data,
size_t len,
size_t *offset,
uint32_t *out) {
if (len - *offset < 4u) {
return false;
}
*out = (uint32_t)data[*offset] |
((uint32_t)data[*offset + 1u] << 8) |
((uint32_t)data[*offset + 2u] << 16) |
((uint32_t)data[*offset + 3u] << 24);
*offset += 4u;
return true;
}
static bool amduat_asl_record_add_size(size_t *acc, size_t add) {
if (*acc > SIZE_MAX - add) {
return false;
}
*acc += add;
return true;
}
static bool amduat_asl_record_schema_is_ascii(amduat_octets_t schema) {
if (schema.len == 0u || schema.data == NULL) {
return false;
}
for (size_t i = 0u; i < schema.len; ++i) {
uint8_t c = schema.data[i];
if (c < 0x20u || c > 0x7eu) {
return false;
}
}
return true;
}
bool amduat_asl_record_encode_v1(const amduat_asl_record_t *record,
amduat_octets_t *out_bytes) {
uint8_t *buffer;
size_t total_len = 0u;
size_t offset = 0u;
uint32_t schema_len;
uint32_t payload_len;
uint8_t flags = 0u;
if (out_bytes == NULL || record == NULL) {
return false;
}
out_bytes->data = NULL;
out_bytes->len = 0u;
if (!amduat_asl_record_schema_is_ascii(record->schema)) {
return false;
}
if (record->payload.len != 0u && record->payload.data == NULL) {
return false;
}
if (record->schema.len > UINT32_MAX || record->payload.len > UINT32_MAX) {
return false;
}
schema_len = (uint32_t)record->schema.len;
payload_len = (uint32_t)record->payload.len;
if (!amduat_asl_record_add_size(&total_len,
AMDUAT_ASL_RECORD_MAGIC_LEN + 4u) ||
!amduat_asl_record_add_size(&total_len, 4u + schema_len) ||
!amduat_asl_record_add_size(&total_len, 4u + payload_len) ||
!amduat_asl_record_add_size(&total_len, 1u)) {
return false;
}
buffer = (uint8_t *)malloc(total_len);
if (buffer == NULL) {
return false;
}
memcpy(buffer + offset, k_amduat_asl_record_magic,
AMDUAT_ASL_RECORD_MAGIC_LEN);
offset += AMDUAT_ASL_RECORD_MAGIC_LEN;
amduat_asl_record_store_u32_le(buffer + offset, AMDUAT_ASL_RECORD_VERSION);
offset += 4u;
amduat_asl_record_store_u32_le(buffer + offset, schema_len);
offset += 4u;
memcpy(buffer + offset, record->schema.data, schema_len);
offset += schema_len;
amduat_asl_record_store_u32_le(buffer + offset, payload_len);
offset += 4u;
if (payload_len != 0u) {
memcpy(buffer + offset, record->payload.data, payload_len);
offset += payload_len;
}
buffer[offset++] = flags;
if (offset != total_len) {
free(buffer);
return false;
}
out_bytes->data = buffer;
out_bytes->len = total_len;
return true;
}
bool amduat_asl_record_decode_v1(amduat_octets_t bytes,
amduat_asl_record_t *out_record) {
size_t offset = 0u;
uint32_t version;
uint32_t schema_len;
uint32_t payload_len;
uint8_t flags;
uint8_t *schema_bytes;
uint8_t *payload_bytes;
if (out_record == NULL) {
return false;
}
out_record->schema = amduat_octets(NULL, 0u);
out_record->payload = amduat_octets(NULL, 0u);
if (bytes.len < AMDUAT_ASL_RECORD_MAGIC_LEN + 4u + 1u) {
return false;
}
if (bytes.data == NULL) {
return false;
}
if (memcmp(bytes.data, k_amduat_asl_record_magic,
AMDUAT_ASL_RECORD_MAGIC_LEN) != 0) {
return false;
}
offset += AMDUAT_ASL_RECORD_MAGIC_LEN;
if (!amduat_asl_record_read_u32_le(bytes.data, bytes.len, &offset,
&version) ||
version != AMDUAT_ASL_RECORD_VERSION) {
return false;
}
if (!amduat_asl_record_read_u32_le(bytes.data, bytes.len, &offset,
&schema_len)) {
return false;
}
if (bytes.len - offset < schema_len) {
return false;
}
schema_bytes = NULL;
if (schema_len != 0u) {
schema_bytes = (uint8_t *)malloc(schema_len);
if (schema_bytes == NULL) {
return false;
}
memcpy(schema_bytes, bytes.data + offset, schema_len);
}
offset += schema_len;
if (!amduat_asl_record_read_u32_le(bytes.data, bytes.len, &offset,
&payload_len)) {
free(schema_bytes);
return false;
}
if (bytes.len - offset < payload_len + 1u) {
free(schema_bytes);
return false;
}
payload_bytes = NULL;
if (payload_len != 0u) {
payload_bytes = (uint8_t *)malloc(payload_len);
if (payload_bytes == NULL) {
free(schema_bytes);
return false;
}
memcpy(payload_bytes, bytes.data + offset, payload_len);
}
offset += payload_len;
flags = bytes.data[offset++];
(void)flags;
if (offset != bytes.len) {
free(schema_bytes);
free(payload_bytes);
return false;
}
out_record->schema = amduat_octets(schema_bytes, schema_len);
out_record->payload = amduat_octets(payload_bytes, payload_len);
return true;
}
void amduat_asl_record_free(amduat_asl_record_t *record) {
if (record == NULL) {
return;
}
amduat_octets_free(&record->schema);
amduat_octets_free(&record->payload);
}
amduat_asl_store_error_t amduat_asl_record_store_put(
amduat_asl_store_t *store,
amduat_octets_t schema,
amduat_octets_t payload,
amduat_reference_t *out_ref) {
amduat_asl_record_t record;
amduat_octets_t encoded = amduat_octets(NULL, 0u);
amduat_artifact_t artifact;
amduat_asl_store_error_t err;
if (store == NULL || out_ref == NULL) {
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
}
record.schema = schema;
record.payload = payload;
if (!amduat_asl_record_encode_v1(&record, &encoded)) {
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
}
artifact = amduat_artifact_with_type(
encoded, amduat_type_tag(AMDUAT_TYPE_TAG_ASL_RECORD_1));
err = amduat_asl_store_put(store, artifact, out_ref);
free((void *)encoded.data);
return err;
}
amduat_asl_store_error_t amduat_asl_record_store_get(
amduat_asl_store_t *store,
amduat_reference_t ref,
amduat_asl_record_t *out_record) {
amduat_artifact_t artifact;
amduat_asl_store_error_t err;
if (store == NULL || out_record == NULL) {
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
}
err = amduat_asl_store_get(store, ref, &artifact);
if (err != AMDUAT_ASL_STORE_OK) {
return err;
}
if (!artifact.has_type_tag ||
artifact.type_tag.tag_id != AMDUAT_TYPE_TAG_ASL_RECORD_1) {
amduat_artifact_free(&artifact);
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
}
if (!amduat_asl_record_decode_v1(artifact.bytes, out_record)) {
amduat_artifact_free(&artifact);
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
}
amduat_artifact_free(&artifact);
return AMDUAT_ASL_STORE_OK;
}

View file

@ -3459,6 +3459,461 @@ static int amduat_pel_cli_cmd_log(
return AMDUAT_PEL_CLI_EXIT_USAGE; return AMDUAT_PEL_CLI_EXIT_USAGE;
} }
static int amduat_pel_cli_cmd_rec_put(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
const char *schema_text = NULL;
const char *payload_arg = NULL;
uint8_t *payload_bytes = NULL;
size_t payload_len = 0u;
amduat_reference_t ref;
amduat_asl_store_t store;
amduat_asl_store_fs_t fs;
int i;
if (global == NULL) {
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--schema") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --schema requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
schema_text = argv[++i];
} else if (strcmp(argv[i], "--payload") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --payload requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
payload_arg = argv[++i];
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
amduat_pel_cli_print_usage(stdout);
return AMDUAT_PEL_CLI_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
}
if (schema_text == NULL || payload_arg == NULL) {
fprintf(stderr, "error: --schema and --payload are required\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (payload_arg[0] != '@' || payload_arg[1] == '\0') {
fprintf(stderr, "error: --payload must be @file\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_asl_read_path(payload_arg + 1, &payload_bytes, &payload_len)) {
fprintf(stderr, "error: failed to read payload file\n");
return AMDUAT_PEL_CLI_EXIT_IO;
}
if (!amduat_pel_cli_init_store(global->root, &store, &fs)) {
free(payload_bytes);
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_CLI_EXIT_CONFIG;
}
{
amduat_asl_store_error_t err = amduat_asl_record_store_put(
&store,
amduat_octets(schema_text, strlen(schema_text)),
amduat_octets(payload_bytes, payload_len),
&ref);
free(payload_bytes);
if (err != AMDUAT_ASL_STORE_OK) {
fprintf(stderr, "error: record put failed: %s\n",
amduat_pel_cli_store_error_str(err));
return amduat_pel_cli_map_store_error(err);
}
}
fputs("ref=", stdout);
if (!amduat_format_ref_write_text(stdout, ref, global->ref_format)) {
fprintf(stderr, "error: failed to format ref\n");
amduat_pel_cli_free_reference(&ref);
return AMDUAT_PEL_CLI_EXIT_CODEC;
}
fputc('\n', stdout);
amduat_pel_cli_free_reference(&ref);
return AMDUAT_PEL_CLI_EXIT_OK;
}
static int amduat_pel_cli_cmd_rec_get(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
const char *ref_text = NULL;
amduat_reference_t ref;
amduat_asl_record_t record;
amduat_asl_store_t store;
amduat_asl_store_fs_t fs;
bool stdin_used = false;
int i;
if (global == NULL) {
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--ref") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --ref requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
ref_text = argv[++i];
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
amduat_pel_cli_print_usage(stdout);
return AMDUAT_PEL_CLI_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
}
if (ref_text == NULL) {
fprintf(stderr, "error: --ref is required\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_ref_from_text(ref_text, global->ref_format,
&stdin_used, &ref)) {
fprintf(stderr, "error: invalid --ref\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_init_store(global->root, &store, &fs)) {
amduat_pel_cli_free_reference(&ref);
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_CLI_EXIT_CONFIG;
}
{
amduat_asl_store_error_t err = amduat_asl_record_store_get(
&store, ref, &record);
if (err != AMDUAT_ASL_STORE_OK) {
amduat_pel_cli_free_reference(&ref);
fprintf(stderr, "error: record get failed: %s\n",
amduat_pel_cli_store_error_str(err));
return amduat_pel_cli_map_store_error(err);
}
}
printf("schema=%.*s\n", (int)record.schema.len,
(const char *)record.schema.data);
{
char *payload_hex = NULL;
if (!amduat_hex_encode_alloc(record.payload.data, record.payload.len,
&payload_hex)) {
amduat_asl_record_free(&record);
amduat_pel_cli_free_reference(&ref);
fprintf(stderr, "error: failed to encode payload\n");
return AMDUAT_PEL_CLI_EXIT_CODEC;
}
printf("payload_hex=%s\n", payload_hex);
free(payload_hex);
}
amduat_asl_record_free(&record);
amduat_pel_cli_free_reference(&ref);
return AMDUAT_PEL_CLI_EXIT_OK;
}
static int amduat_pel_cli_cmd_rec(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
if (argc < 1) {
fprintf(stderr, "error: rec requires a subcommand\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (strcmp(argv[0], "put") == 0) {
return amduat_pel_cli_cmd_rec_put(argc - 1, argv + 1, global);
}
if (strcmp(argv[0], "get") == 0) {
return amduat_pel_cli_cmd_rec_get(argc - 1, argv + 1, global);
}
fprintf(stderr, "error: unknown rec subcommand: %s\n", argv[0]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
static int amduat_pel_cli_cmd_col_append(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
const char *name = NULL;
const char *ref_text = NULL;
const char *actor_text = NULL;
unsigned long kind = 0u;
amduat_reference_t ref;
amduat_asl_collection_store_t collection_store;
amduat_asl_store_t store;
amduat_asl_store_fs_t fs;
uint64_t offset = 0u;
bool stdin_used = false;
int i;
if (global == NULL) {
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--name") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --name requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
name = argv[++i];
} else if (strcmp(argv[i], "--record-ref") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --record-ref requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
ref_text = argv[++i];
} else if (strcmp(argv[i], "--kind") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --kind requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
kind = strtoul(argv[++i], NULL, 10);
} else if (strcmp(argv[i], "--actor") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --actor requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
actor_text = argv[++i];
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
amduat_pel_cli_print_usage(stdout);
return AMDUAT_PEL_CLI_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
}
if (name == NULL || ref_text == NULL) {
fprintf(stderr, "error: --name and --record-ref are required\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (kind > UINT16_MAX) {
fprintf(stderr, "error: --kind out of range\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_ref_from_text(ref_text, global->ref_format,
&stdin_used, &ref)) {
fprintf(stderr, "error: invalid --record-ref\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_init_store(global->root, &store, &fs) ||
!amduat_asl_collection_store_init(&collection_store, global->root,
&store)) {
amduat_pel_cli_free_reference(&ref);
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_CLI_EXIT_CONFIG;
}
{
amduat_asl_collection_error_t err = amduat_asl_collection_append(
&collection_store, name, ref, (uint16_t)kind,
actor_text ? amduat_octets(actor_text, strlen(actor_text))
: amduat_octets(NULL, 0u),
&offset);
amduat_pel_cli_free_reference(&ref);
if (err != AMDUAT_ASL_COLLECTION_OK) {
fprintf(stderr, "error: collection append failed\n");
return AMDUAT_PEL_CLI_EXIT_IO;
}
}
printf("offset=%" PRIu64 "\n", offset);
return AMDUAT_PEL_CLI_EXIT_OK;
}
static int amduat_pel_cli_cmd_col_snapshot(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
const char *name = NULL;
uint64_t up_to = UINT64_MAX;
amduat_reference_t snapshot_ref;
bool swapped = false;
amduat_asl_collection_store_t collection_store;
amduat_asl_store_t store;
amduat_asl_store_fs_t fs;
int i;
if (global == NULL) {
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--name") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --name requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
name = argv[++i];
} else if (strcmp(argv[i], "--up-to") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --up-to requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
up_to = (uint64_t)strtoull(argv[++i], NULL, 10);
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
amduat_pel_cli_print_usage(stdout);
return AMDUAT_PEL_CLI_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
}
if (name == NULL) {
fprintf(stderr, "error: --name is required\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_init_store(global->root, &store, &fs) ||
!amduat_asl_collection_store_init(&collection_store, global->root,
&store)) {
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_CLI_EXIT_CONFIG;
}
{
amduat_asl_collection_error_t err = amduat_asl_collection_snapshot(
&collection_store, name, up_to, &snapshot_ref, &swapped);
if (err == AMDUAT_ASL_COLLECTION_ERR_CAS_MISMATCH) {
fprintf(stderr, "error: snapshot CAS mismatch\n");
return 2;
}
if (err != AMDUAT_ASL_COLLECTION_OK) {
fprintf(stderr, "error: snapshot failed\n");
return AMDUAT_PEL_CLI_EXIT_IO;
}
}
fputs("snapshot_ref=", stdout);
if (!amduat_format_ref_write_text(stdout, snapshot_ref,
global->ref_format)) {
fprintf(stderr, "error: failed to format ref\n");
amduat_pel_cli_free_reference(&snapshot_ref);
return AMDUAT_PEL_CLI_EXIT_CODEC;
}
printf("\nswapped=%s\n", swapped ? "true" : "false");
amduat_pel_cli_free_reference(&snapshot_ref);
return AMDUAT_PEL_CLI_EXIT_OK;
}
static int amduat_pel_cli_cmd_col_read(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
const char *name = NULL;
uint64_t from = 0u;
size_t limit = 0u;
amduat_reference_t *refs = NULL;
size_t refs_len = 0u;
uint64_t next_offset = 0u;
bool end = false;
amduat_asl_collection_store_t collection_store;
amduat_asl_store_t store;
amduat_asl_store_fs_t fs;
int i;
if (global == NULL) {
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
for (i = 0; i < argc; ++i) {
if (strcmp(argv[i], "--name") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --name requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
name = argv[++i];
} else if (strcmp(argv[i], "--from") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --from requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
from = (uint64_t)strtoull(argv[++i], NULL, 10);
} else if (strcmp(argv[i], "--limit") == 0) {
if (i + 1 >= argc) {
fprintf(stderr, "error: --limit requires a value\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
limit = (size_t)strtoull(argv[++i], NULL, 10);
} else if (strcmp(argv[i], "--help") == 0 ||
strcmp(argv[i], "-h") == 0) {
amduat_pel_cli_print_usage(stdout);
return AMDUAT_PEL_CLI_EXIT_OK;
} else {
fprintf(stderr, "error: unknown option: %s\n", argv[i]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
}
if (name == NULL || limit == 0u) {
fprintf(stderr, "error: --name and --limit are required\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (!amduat_pel_cli_init_store(global->root, &store, &fs) ||
!amduat_asl_collection_store_init(&collection_store, global->root,
&store)) {
fprintf(stderr, "error: failed to initialize store\n");
return AMDUAT_PEL_CLI_EXIT_CONFIG;
}
{
amduat_asl_collection_error_t err = amduat_asl_collection_read(
&collection_store, name, from, limit,
&refs, &refs_len, &next_offset, &end);
if (err != AMDUAT_ASL_COLLECTION_OK) {
fprintf(stderr, "error: collection read failed\n");
return AMDUAT_PEL_CLI_EXIT_IO;
}
}
for (size_t iref = 0u; iref < refs_len; ++iref) {
printf("offset=%" PRIu64 " ref=", from + iref);
if (!amduat_format_ref_write_text(stdout, refs[iref],
global->ref_format)) {
fprintf(stderr, "error: failed to format ref\n");
amduat_asl_collection_refs_free(refs, refs_len);
return AMDUAT_PEL_CLI_EXIT_CODEC;
}
fputc('\n', stdout);
}
printf("next=%" PRIu64 " end=%s\n", next_offset, end ? "true" : "false");
amduat_asl_collection_refs_free(refs, refs_len);
return AMDUAT_PEL_CLI_EXIT_OK;
}
static int amduat_pel_cli_cmd_col(
int argc,
char **argv,
const amduat_pel_cli_global_opts_t *global) {
if (argc < 1) {
fprintf(stderr, "error: col requires a subcommand\n");
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
if (strcmp(argv[0], "append") == 0) {
return amduat_pel_cli_cmd_col_append(argc - 1, argv + 1, global);
}
if (strcmp(argv[0], "snapshot") == 0) {
return amduat_pel_cli_cmd_col_snapshot(argc - 1, argv + 1, global);
}
if (strcmp(argv[0], "read") == 0) {
return amduat_pel_cli_cmd_col_read(argc - 1, argv + 1, global);
}
fprintf(stderr, "error: unknown col subcommand: %s\n", argv[0]);
return AMDUAT_PEL_CLI_EXIT_USAGE;
}
static int amduat_pel_cli_cmd_help(int argc, char **argv) { static int amduat_pel_cli_cmd_help(int argc, char **argv) {
(void)argc; (void)argc;
(void)argv; (void)argv;
@ -3549,6 +4004,12 @@ int main(int argc, char **argv) {
if (strcmp(command, "log") == 0) { if (strcmp(command, "log") == 0) {
return amduat_pel_cli_cmd_log(argc - i, argv + i, &global); return amduat_pel_cli_cmd_log(argc - i, argv + i, &global);
} }
if (strcmp(command, "rec") == 0) {
return amduat_pel_cli_cmd_rec(argc - i, argv + i, &global);
}
if (strcmp(command, "col") == 0) {
return amduat_pel_cli_cmd_col(argc - i, argv + i, &global);
}
if (strcmp(command, "matcache") == 0) { if (strcmp(command, "matcache") == 0) {
return amduat_pel_cli_cmd_matcache(argc - i, argv + i, &global); return amduat_pel_cli_cmd_matcache(argc - i, argv + i, &global);
} }