Add generic records and collections
This commit is contained in:
parent
e2d26e53cd
commit
85c23e49eb
|
|
@ -79,6 +79,14 @@ set(AMDUAT_ASL_LOG_STORE_SRCS
|
|||
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
|
||||
src/near_core/hash/asl1.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_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_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
|
||||
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_hash_asl1 amduat_util
|
||||
)
|
||||
|
|
|
|||
68
include/amduat/asl/collection.h
Normal file
68
include/amduat/asl/collection.h
Normal 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 */
|
||||
46
include/amduat/asl/record.h
Normal file
46
include/amduat/asl/record.h
Normal 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
483
src/core/asl_collection.c
Normal 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
268
src/core/asl_record.c
Normal 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;
|
||||
}
|
||||
|
|
@ -3459,6 +3459,461 @@ static int amduat_pel_cli_cmd_log(
|
|||
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) {
|
||||
(void)argc;
|
||||
(void)argv;
|
||||
|
|
@ -3549,6 +4004,12 @@ int main(int argc, char **argv) {
|
|||
if (strcmp(command, "log") == 0) {
|
||||
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) {
|
||||
return amduat_pel_cli_cmd_matcache(argc - i, argv + i, &global);
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in a new issue