Add ASL FS metadata and layout helper
This commit is contained in:
parent
428f657f4f
commit
c6f9c6a696
|
|
@ -96,6 +96,8 @@ set(AMDUAT_TGK_SRCS
|
||||||
|
|
||||||
set(AMDUAT_ASL_STORE_FS_SRCS
|
set(AMDUAT_ASL_STORE_FS_SRCS
|
||||||
src/adapters/asl_store_fs/asl_store_fs.c
|
src/adapters/asl_store_fs/asl_store_fs.c
|
||||||
|
src/adapters/asl_store_fs/asl_store_fs_layout.c
|
||||||
|
src/adapters/asl_store_fs/asl_store_fs_meta.c
|
||||||
)
|
)
|
||||||
|
|
||||||
set(AMDUAT_TGK_STORE_MEM_SRCS
|
set(AMDUAT_TGK_STORE_MEM_SRCS
|
||||||
|
|
|
||||||
42
include/amduat/asl/asl_store_fs_meta.h
Normal file
42
include/amduat/asl/asl_store_fs_meta.h
Normal file
|
|
@ -0,0 +1,42 @@
|
||||||
|
#ifndef AMDUAT_ASL_STORE_FS_META_H
|
||||||
|
#define AMDUAT_ASL_STORE_FS_META_H
|
||||||
|
|
||||||
|
#include "amduat/asl/core.h"
|
||||||
|
#include "amduat/asl/store.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum { AMDUAT_ASL_STORE_FS_STORE_ID_MAX = 256 };
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
amduat_asl_store_config_t config;
|
||||||
|
char store_id[AMDUAT_ASL_STORE_FS_STORE_ID_MAX + 1];
|
||||||
|
} amduat_asl_store_fs_config_t;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool has_snapshot;
|
||||||
|
amduat_reference_t snapshot;
|
||||||
|
} amduat_asl_store_fs_head_t;
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_init_root(
|
||||||
|
const char *root_path,
|
||||||
|
const amduat_asl_store_fs_config_t *cfg_in,
|
||||||
|
amduat_asl_store_fs_config_t *cfg_out);
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_load_config(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_fs_config_t *out_cfg);
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_load_head(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_fs_head_t *out_head);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AMDUAT_ASL_STORE_FS_META_H */
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
#include "amduat/asl/asl_store_fs.h"
|
#include "amduat/asl/asl_store_fs.h"
|
||||||
|
|
||||||
|
#include "asl_store_fs_layout.h"
|
||||||
#include "amduat/asl/core.h"
|
#include "amduat/asl/core.h"
|
||||||
#include "amduat/enc/asl1_core.h"
|
#include "amduat/enc/asl1_core.h"
|
||||||
#include "amduat/enc/asl1_core_codec.h"
|
#include "amduat/enc/asl1_core_codec.h"
|
||||||
|
|
@ -36,60 +37,6 @@ typedef enum {
|
||||||
AMDUAT_ASL_STORE_FS_READ_ERR = 2
|
AMDUAT_ASL_STORE_FS_READ_ERR = 2
|
||||||
} amduat_asl_store_fs_read_status_t;
|
} amduat_asl_store_fs_read_status_t;
|
||||||
|
|
||||||
static void amduat_asl_store_fs_format_hex(const uint8_t *bytes,
|
|
||||||
size_t count,
|
|
||||||
char *out) {
|
|
||||||
static const char k_hex[] = "0123456789abcdef";
|
|
||||||
size_t i;
|
|
||||||
|
|
||||||
for (i = 0; i < count; ++i) {
|
|
||||||
const uint8_t value = bytes[i];
|
|
||||||
out[i * 2u] = k_hex[value >> 4u];
|
|
||||||
out[i * 2u + 1u] = k_hex[value & 0x0fu];
|
|
||||||
}
|
|
||||||
out[count * 2u] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool amduat_asl_store_fs_join_path(const char *base,
|
|
||||||
const char *segment,
|
|
||||||
char **out_path) {
|
|
||||||
size_t base_len;
|
|
||||||
size_t seg_len;
|
|
||||||
bool needs_sep;
|
|
||||||
size_t total_len;
|
|
||||||
char *buffer;
|
|
||||||
size_t offset;
|
|
||||||
|
|
||||||
if (base == NULL || segment == NULL || out_path == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (base[0] == '\0' || segment[0] == '\0') {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
base_len = strlen(base);
|
|
||||||
seg_len = strlen(segment);
|
|
||||||
needs_sep = base[base_len - 1u] != '/';
|
|
||||||
total_len = base_len + (needs_sep ? 1u : 0u) + seg_len + 1u;
|
|
||||||
|
|
||||||
buffer = (char *)malloc(total_len);
|
|
||||||
if (buffer == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset = 0u;
|
|
||||||
memcpy(buffer + offset, base, base_len);
|
|
||||||
offset += base_len;
|
|
||||||
if (needs_sep) {
|
|
||||||
buffer[offset++] = '/';
|
|
||||||
}
|
|
||||||
memcpy(buffer + offset, segment, seg_len);
|
|
||||||
offset += seg_len;
|
|
||||||
buffer[offset] = '\0';
|
|
||||||
|
|
||||||
*out_path = buffer;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool amduat_asl_store_fs_require_directory(const char *path) {
|
static bool amduat_asl_store_fs_require_directory(const char *path) {
|
||||||
struct stat st;
|
struct stat st;
|
||||||
|
|
@ -313,97 +260,6 @@ static amduat_asl_store_fs_read_status_t amduat_asl_store_fs_read_file(
|
||||||
return AMDUAT_ASL_STORE_FS_READ_OK;
|
return AMDUAT_ASL_STORE_FS_READ_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool amduat_asl_store_fs_build_paths(
|
|
||||||
const amduat_asl_store_fs_t *fs,
|
|
||||||
const uint8_t *digest,
|
|
||||||
size_t digest_len,
|
|
||||||
char **out_profile_path,
|
|
||||||
char **out_hash_path,
|
|
||||||
char **out_level1_path,
|
|
||||||
char **out_level2_path,
|
|
||||||
char **out_object_path) {
|
|
||||||
char profile_hex[5];
|
|
||||||
char hash_hex[5];
|
|
||||||
char level1_segment[3];
|
|
||||||
char level2_segment[3];
|
|
||||||
char *digest_hex;
|
|
||||||
char *profile_path;
|
|
||||||
char *hash_path;
|
|
||||||
char *level1_path;
|
|
||||||
char *level2_path;
|
|
||||||
char *object_path;
|
|
||||||
bool ok;
|
|
||||||
|
|
||||||
if (fs == NULL || digest == NULL || out_profile_path == NULL ||
|
|
||||||
out_hash_path == NULL || out_level1_path == NULL ||
|
|
||||||
out_level2_path == NULL || out_object_path == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
*out_profile_path = NULL;
|
|
||||||
*out_hash_path = NULL;
|
|
||||||
*out_level1_path = NULL;
|
|
||||||
*out_level2_path = NULL;
|
|
||||||
*out_object_path = NULL;
|
|
||||||
|
|
||||||
if (digest_len < AMDUAT_ASL_STORE_FS_MIN_DIGEST_BYTES) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if (digest_len > (SIZE_MAX - 1u) / 2u) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
snprintf(profile_hex, sizeof(profile_hex), "%04x",
|
|
||||||
(unsigned int)fs->config.encoding_profile_id);
|
|
||||||
snprintf(hash_hex, sizeof(hash_hex), "%04x",
|
|
||||||
(unsigned int)fs->config.hash_id);
|
|
||||||
|
|
||||||
amduat_asl_store_fs_format_hex(digest, 1u, level1_segment);
|
|
||||||
amduat_asl_store_fs_format_hex(digest + 1u, 1u, level2_segment);
|
|
||||||
|
|
||||||
digest_hex = (char *)malloc(digest_len * 2u + 1u);
|
|
||||||
if (digest_hex == NULL) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
amduat_asl_store_fs_format_hex(digest, digest_len, digest_hex);
|
|
||||||
|
|
||||||
profile_path = NULL;
|
|
||||||
hash_path = NULL;
|
|
||||||
level1_path = NULL;
|
|
||||||
level2_path = NULL;
|
|
||||||
object_path = NULL;
|
|
||||||
|
|
||||||
ok = amduat_asl_store_fs_join_path(fs->root_path, profile_hex, &profile_path);
|
|
||||||
if (ok) {
|
|
||||||
ok = amduat_asl_store_fs_join_path(profile_path, hash_hex, &hash_path);
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
ok = amduat_asl_store_fs_join_path(hash_path, level1_segment, &level1_path);
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
ok =
|
|
||||||
amduat_asl_store_fs_join_path(level1_path, level2_segment, &level2_path);
|
|
||||||
}
|
|
||||||
if (ok) {
|
|
||||||
ok = amduat_asl_store_fs_join_path(level2_path, digest_hex, &object_path);
|
|
||||||
}
|
|
||||||
|
|
||||||
free(digest_hex);
|
|
||||||
if (!ok) {
|
|
||||||
free(profile_path);
|
|
||||||
free(hash_path);
|
|
||||||
free(level1_path);
|
|
||||||
free(level2_path);
|
|
||||||
free(object_path);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out_profile_path = profile_path;
|
|
||||||
*out_hash_path = hash_path;
|
|
||||||
*out_level1_path = level1_path;
|
|
||||||
*out_level2_path = level2_path;
|
|
||||||
*out_object_path = object_path;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static amduat_asl_store_error_t amduat_asl_store_fs_compare_existing(
|
static amduat_asl_store_error_t amduat_asl_store_fs_compare_existing(
|
||||||
const char *object_path,
|
const char *object_path,
|
||||||
|
|
@ -447,6 +303,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
amduat_octets_t artifact_bytes;
|
amduat_octets_t artifact_bytes;
|
||||||
uint8_t *digest;
|
uint8_t *digest;
|
||||||
bool ok;
|
bool ok;
|
||||||
|
char *objects_path;
|
||||||
char *profile_path;
|
char *profile_path;
|
||||||
char *hash_path;
|
char *hash_path;
|
||||||
char *level1_path;
|
char *level1_path;
|
||||||
|
|
@ -490,14 +347,17 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
|
return AMDUAT_ASL_STORE_ERR_INTEGRITY;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objects_path = NULL;
|
||||||
profile_path = NULL;
|
profile_path = NULL;
|
||||||
hash_path = NULL;
|
hash_path = NULL;
|
||||||
level1_path = NULL;
|
level1_path = NULL;
|
||||||
level2_path = NULL;
|
level2_path = NULL;
|
||||||
object_path = NULL;
|
object_path = NULL;
|
||||||
ok = amduat_asl_store_fs_build_paths(fs,
|
ok = amduat_asl_store_fs_layout_build_paths(fs->root_path,
|
||||||
|
fs->config,
|
||||||
digest,
|
digest,
|
||||||
hash_desc->digest_len,
|
hash_desc->digest_len,
|
||||||
|
&objects_path,
|
||||||
&profile_path,
|
&profile_path,
|
||||||
&hash_path,
|
&hash_path,
|
||||||
&level1_path,
|
&level1_path,
|
||||||
|
|
@ -510,12 +370,14 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!amduat_asl_store_fs_require_directory(fs->root_path) ||
|
if (!amduat_asl_store_fs_require_directory(fs->root_path) ||
|
||||||
|
!amduat_asl_store_fs_ensure_directory(objects_path) ||
|
||||||
!amduat_asl_store_fs_ensure_directory(profile_path) ||
|
!amduat_asl_store_fs_ensure_directory(profile_path) ||
|
||||||
!amduat_asl_store_fs_ensure_directory(hash_path) ||
|
!amduat_asl_store_fs_ensure_directory(hash_path) ||
|
||||||
!amduat_asl_store_fs_ensure_directory(level1_path) ||
|
!amduat_asl_store_fs_ensure_directory(level1_path) ||
|
||||||
!amduat_asl_store_fs_ensure_directory(level2_path)) {
|
!amduat_asl_store_fs_ensure_directory(level2_path)) {
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -531,6 +393,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
out_ref->hash_id = fs->config.hash_id;
|
out_ref->hash_id = fs->config.hash_id;
|
||||||
out_ref->digest = amduat_octets(digest, hash_desc->digest_len);
|
out_ref->digest = amduat_octets(digest, hash_desc->digest_len);
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -541,6 +404,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
if (cmp_err == AMDUAT_ASL_STORE_ERR_INTEGRITY) {
|
if (cmp_err == AMDUAT_ASL_STORE_ERR_INTEGRITY) {
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -560,6 +424,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
if (cmp_err != AMDUAT_ASL_STORE_OK) {
|
if (cmp_err != AMDUAT_ASL_STORE_OK) {
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -570,6 +435,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
} else if (write_status != AMDUAT_ASL_STORE_FS_WRITE_OK) {
|
} else if (write_status != AMDUAT_ASL_STORE_FS_WRITE_OK) {
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -582,6 +448,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
unlink(object_path);
|
unlink(object_path);
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -593,6 +460,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
unlink(object_path);
|
unlink(object_path);
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
free(digest);
|
free(digest);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -604,6 +472,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_put_impl(
|
||||||
out_ref->hash_id = fs->config.hash_id;
|
out_ref->hash_id = fs->config.hash_id;
|
||||||
out_ref->digest = amduat_octets(digest, hash_desc->digest_len);
|
out_ref->digest = amduat_octets(digest, hash_desc->digest_len);
|
||||||
free((void *)artifact_bytes.data);
|
free((void *)artifact_bytes.data);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -618,6 +487,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
amduat_artifact_t *out_artifact) {
|
amduat_artifact_t *out_artifact) {
|
||||||
amduat_asl_store_fs_t *fs;
|
amduat_asl_store_fs_t *fs;
|
||||||
const amduat_hash_asl1_desc_t *hash_desc;
|
const amduat_hash_asl1_desc_t *hash_desc;
|
||||||
|
char *objects_path;
|
||||||
char *profile_path;
|
char *profile_path;
|
||||||
char *hash_path;
|
char *hash_path;
|
||||||
char *level1_path;
|
char *level1_path;
|
||||||
|
|
@ -654,14 +524,17 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
return AMDUAT_ASL_STORE_ERR_UNSUPPORTED;
|
return AMDUAT_ASL_STORE_ERR_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
objects_path = NULL;
|
||||||
profile_path = NULL;
|
profile_path = NULL;
|
||||||
hash_path = NULL;
|
hash_path = NULL;
|
||||||
level1_path = NULL;
|
level1_path = NULL;
|
||||||
level2_path = NULL;
|
level2_path = NULL;
|
||||||
object_path = NULL;
|
object_path = NULL;
|
||||||
if (!amduat_asl_store_fs_build_paths(fs,
|
if (!amduat_asl_store_fs_layout_build_paths(fs->root_path,
|
||||||
|
fs->config,
|
||||||
ref.digest.data,
|
ref.digest.data,
|
||||||
ref.digest.len,
|
ref.digest.len,
|
||||||
|
&objects_path,
|
||||||
&profile_path,
|
&profile_path,
|
||||||
&hash_path,
|
&hash_path,
|
||||||
&level1_path,
|
&level1_path,
|
||||||
|
|
@ -675,6 +548,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
read_status =
|
read_status =
|
||||||
amduat_asl_store_fs_read_file(object_path, &stored_bytes, &stored_len);
|
amduat_asl_store_fs_read_file(object_path, &stored_bytes, &stored_len);
|
||||||
if (read_status == AMDUAT_ASL_STORE_FS_READ_NOT_FOUND) {
|
if (read_status == AMDUAT_ASL_STORE_FS_READ_NOT_FOUND) {
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -683,6 +557,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
return AMDUAT_ASL_STORE_ERR_NOT_FOUND;
|
return AMDUAT_ASL_STORE_ERR_NOT_FOUND;
|
||||||
}
|
}
|
||||||
if (read_status != AMDUAT_ASL_STORE_FS_READ_OK) {
|
if (read_status != AMDUAT_ASL_STORE_FS_READ_OK) {
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -694,6 +569,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
computed_digest = (uint8_t *)malloc(hash_desc->digest_len);
|
computed_digest = (uint8_t *)malloc(hash_desc->digest_len);
|
||||||
if (computed_digest == NULL) {
|
if (computed_digest == NULL) {
|
||||||
free(stored_bytes);
|
free(stored_bytes);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -709,6 +585,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
hash_desc->digest_len)) {
|
hash_desc->digest_len)) {
|
||||||
free(computed_digest);
|
free(computed_digest);
|
||||||
free(stored_bytes);
|
free(stored_bytes);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -720,6 +597,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
if (memcmp(computed_digest, ref.digest.data, hash_desc->digest_len) != 0) {
|
if (memcmp(computed_digest, ref.digest.data, hash_desc->digest_len) != 0) {
|
||||||
free(computed_digest);
|
free(computed_digest);
|
||||||
free(stored_bytes);
|
free(stored_bytes);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
@ -733,6 +611,7 @@ static amduat_asl_store_error_t amduat_asl_store_fs_get_impl(
|
||||||
amduat_octets(stored_bytes, stored_len),
|
amduat_octets(stored_bytes, stored_len),
|
||||||
out_artifact);
|
out_artifact);
|
||||||
free(stored_bytes);
|
free(stored_bytes);
|
||||||
|
free(objects_path);
|
||||||
free(profile_path);
|
free(profile_path);
|
||||||
free(hash_path);
|
free(hash_path);
|
||||||
free(level1_path);
|
free(level1_path);
|
||||||
|
|
|
||||||
193
src/adapters/asl_store_fs/asl_store_fs_layout.c
Normal file
193
src/adapters/asl_store_fs/asl_store_fs_layout.c
Normal file
|
|
@ -0,0 +1,193 @@
|
||||||
|
#include "asl_store_fs_layout.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
enum { AMDUAT_ASL_STORE_FS_LAYOUT_MIN_DIGEST_BYTES = 2 };
|
||||||
|
|
||||||
|
static void amduat_asl_store_fs_layout_format_hex(const uint8_t *bytes,
|
||||||
|
size_t count,
|
||||||
|
char *out) {
|
||||||
|
static const char k_hex[] = "0123456789abcdef";
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
for (i = 0; i < count; ++i) {
|
||||||
|
const uint8_t value = bytes[i];
|
||||||
|
out[i * 2u] = k_hex[value >> 4u];
|
||||||
|
out[i * 2u + 1u] = k_hex[value & 0x0fu];
|
||||||
|
}
|
||||||
|
out[count * 2u] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_layout_join_path(const char *base,
|
||||||
|
const char *segment,
|
||||||
|
char **out_path) {
|
||||||
|
size_t base_len;
|
||||||
|
size_t seg_len;
|
||||||
|
bool needs_sep;
|
||||||
|
size_t total_len;
|
||||||
|
char *buffer;
|
||||||
|
size_t offset;
|
||||||
|
|
||||||
|
if (base == NULL || segment == NULL || out_path == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (base[0] == '\0' || segment[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
base_len = strlen(base);
|
||||||
|
seg_len = strlen(segment);
|
||||||
|
needs_sep = base[base_len - 1u] != '/';
|
||||||
|
total_len = base_len + (needs_sep ? 1u : 0u) + seg_len + 1u;
|
||||||
|
|
||||||
|
buffer = (char *)malloc(total_len);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset = 0u;
|
||||||
|
memcpy(buffer + offset, base, base_len);
|
||||||
|
offset += base_len;
|
||||||
|
if (needs_sep) {
|
||||||
|
buffer[offset++] = '/';
|
||||||
|
}
|
||||||
|
memcpy(buffer + offset, segment, seg_len);
|
||||||
|
offset += seg_len;
|
||||||
|
buffer[offset] = '\0';
|
||||||
|
|
||||||
|
*out_path = buffer;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_config_path(const char *root_path,
|
||||||
|
char **out_path) {
|
||||||
|
return amduat_asl_store_fs_layout_join_path(root_path, "CONFIG", out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_head_path(const char *root_path,
|
||||||
|
char **out_path) {
|
||||||
|
return amduat_asl_store_fs_layout_join_path(root_path, "HEAD", out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_objects_path(const char *root_path,
|
||||||
|
char **out_path) {
|
||||||
|
return amduat_asl_store_fs_layout_join_path(root_path, "objects", out_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_paths(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_config_t config,
|
||||||
|
const uint8_t *digest,
|
||||||
|
size_t digest_len,
|
||||||
|
char **out_objects_path,
|
||||||
|
char **out_profile_path,
|
||||||
|
char **out_hash_path,
|
||||||
|
char **out_level1_path,
|
||||||
|
char **out_level2_path,
|
||||||
|
char **out_object_path) {
|
||||||
|
char profile_hex[5];
|
||||||
|
char hash_hex[5];
|
||||||
|
char level1_segment[3];
|
||||||
|
char level2_segment[3];
|
||||||
|
char *digest_hex;
|
||||||
|
char *objects_path;
|
||||||
|
char *profile_path;
|
||||||
|
char *hash_path;
|
||||||
|
char *level1_path;
|
||||||
|
char *level2_path;
|
||||||
|
char *object_path;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (root_path == NULL || digest == NULL || out_objects_path == NULL ||
|
||||||
|
out_profile_path == NULL || out_hash_path == NULL ||
|
||||||
|
out_level1_path == NULL || out_level2_path == NULL ||
|
||||||
|
out_object_path == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
*out_objects_path = NULL;
|
||||||
|
*out_profile_path = NULL;
|
||||||
|
*out_hash_path = NULL;
|
||||||
|
*out_level1_path = NULL;
|
||||||
|
*out_level2_path = NULL;
|
||||||
|
*out_object_path = NULL;
|
||||||
|
|
||||||
|
if (root_path[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (digest_len < AMDUAT_ASL_STORE_FS_LAYOUT_MIN_DIGEST_BYTES) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (digest_len > (SIZE_MAX - 1u) / 2u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
snprintf(profile_hex, sizeof(profile_hex), "%04x",
|
||||||
|
(unsigned int)config.encoding_profile_id);
|
||||||
|
snprintf(hash_hex, sizeof(hash_hex), "%04x", (unsigned int)config.hash_id);
|
||||||
|
|
||||||
|
amduat_asl_store_fs_layout_format_hex(digest, 1u, level1_segment);
|
||||||
|
amduat_asl_store_fs_layout_format_hex(digest + 1u, 1u, level2_segment);
|
||||||
|
|
||||||
|
digest_hex = (char *)malloc(digest_len * 2u + 1u);
|
||||||
|
if (digest_hex == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
amduat_asl_store_fs_layout_format_hex(digest, digest_len, digest_hex);
|
||||||
|
|
||||||
|
objects_path = NULL;
|
||||||
|
profile_path = NULL;
|
||||||
|
hash_path = NULL;
|
||||||
|
level1_path = NULL;
|
||||||
|
level2_path = NULL;
|
||||||
|
object_path = NULL;
|
||||||
|
|
||||||
|
ok = amduat_asl_store_fs_layout_build_objects_path(root_path, &objects_path);
|
||||||
|
if (ok) {
|
||||||
|
ok = amduat_asl_store_fs_layout_join_path(objects_path,
|
||||||
|
profile_hex,
|
||||||
|
&profile_path);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
ok = amduat_asl_store_fs_layout_join_path(profile_path,
|
||||||
|
hash_hex,
|
||||||
|
&hash_path);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
ok = amduat_asl_store_fs_layout_join_path(hash_path,
|
||||||
|
level1_segment,
|
||||||
|
&level1_path);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
ok = amduat_asl_store_fs_layout_join_path(level1_path,
|
||||||
|
level2_segment,
|
||||||
|
&level2_path);
|
||||||
|
}
|
||||||
|
if (ok) {
|
||||||
|
ok = amduat_asl_store_fs_layout_join_path(level2_path,
|
||||||
|
digest_hex,
|
||||||
|
&object_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
free(digest_hex);
|
||||||
|
if (!ok) {
|
||||||
|
free(objects_path);
|
||||||
|
free(profile_path);
|
||||||
|
free(hash_path);
|
||||||
|
free(level1_path);
|
||||||
|
free(level2_path);
|
||||||
|
free(object_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*out_objects_path = objects_path;
|
||||||
|
*out_profile_path = profile_path;
|
||||||
|
*out_hash_path = hash_path;
|
||||||
|
*out_level1_path = level1_path;
|
||||||
|
*out_level2_path = level2_path;
|
||||||
|
*out_object_path = object_path;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
39
src/adapters/asl_store_fs/asl_store_fs_layout.h
Normal file
39
src/adapters/asl_store_fs/asl_store_fs_layout.h
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
#ifndef AMDUAT_ASL_STORE_FS_LAYOUT_H
|
||||||
|
#define AMDUAT_ASL_STORE_FS_LAYOUT_H
|
||||||
|
|
||||||
|
#include "amduat/asl/store.h"
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_paths(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_config_t config,
|
||||||
|
const uint8_t *digest,
|
||||||
|
size_t digest_len,
|
||||||
|
char **out_objects_path,
|
||||||
|
char **out_profile_path,
|
||||||
|
char **out_hash_path,
|
||||||
|
char **out_level1_path,
|
||||||
|
char **out_level2_path,
|
||||||
|
char **out_object_path);
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_config_path(const char *root_path,
|
||||||
|
char **out_path);
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_head_path(const char *root_path,
|
||||||
|
char **out_path);
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_layout_build_objects_path(const char *root_path,
|
||||||
|
char **out_path);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
} /* extern "C" */
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* AMDUAT_ASL_STORE_FS_LAYOUT_H */
|
||||||
723
src/adapters/asl_store_fs/asl_store_fs_meta.c
Normal file
723
src/adapters/asl_store_fs/asl_store_fs_meta.c
Normal file
|
|
@ -0,0 +1,723 @@
|
||||||
|
#include "amduat/asl/asl_store_fs_meta.h"
|
||||||
|
|
||||||
|
#include "asl_store_fs_layout.h"
|
||||||
|
#include "amduat/enc/asl1_core.h"
|
||||||
|
#include "amduat/hash/asl1.h"
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <time.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
|
#ifndef O_DIRECTORY
|
||||||
|
#define O_DIRECTORY 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
AMDUAT_ASL_STORE_FS_META_READ_OK = 0,
|
||||||
|
AMDUAT_ASL_STORE_FS_META_READ_NOT_FOUND = 1,
|
||||||
|
AMDUAT_ASL_STORE_FS_META_READ_ERR = 2
|
||||||
|
} amduat_asl_store_fs_meta_read_status_t;
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_is_store_id_char(char c) {
|
||||||
|
if (c >= 'a' && c <= 'z') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (c >= 'A' && c <= 'Z') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return c == '.' || c == '_' || c == '-';
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_validate_store_id(const char *store_id) {
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (store_id == NULL || store_id[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
for (i = 0; store_id[i] != '\0'; ++i) {
|
||||||
|
if (i >= AMDUAT_ASL_STORE_FS_STORE_ID_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_store_fs_meta_is_store_id_char(store_id[i])) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_copy_store_id(
|
||||||
|
char out_id[AMDUAT_ASL_STORE_FS_STORE_ID_MAX + 1],
|
||||||
|
const char *store_id) {
|
||||||
|
size_t len;
|
||||||
|
|
||||||
|
if (out_id == NULL || store_id == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_store_fs_meta_validate_store_id(store_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
len = strlen(store_id);
|
||||||
|
if (len > AMDUAT_ASL_STORE_FS_STORE_ID_MAX) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
memcpy(out_id, store_id, len);
|
||||||
|
out_id[len] = '\0';
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_parse_hex4_lower(const char *value,
|
||||||
|
uint16_t *out) {
|
||||||
|
size_t i;
|
||||||
|
uint16_t accum;
|
||||||
|
|
||||||
|
if (value == NULL || out == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strlen(value) != 4u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
accum = 0u;
|
||||||
|
for (i = 0; i < 4u; ++i) {
|
||||||
|
char c = value[i];
|
||||||
|
uint8_t nibble;
|
||||||
|
if (c >= '0' && c <= '9') {
|
||||||
|
nibble = (uint8_t)(c - '0');
|
||||||
|
} else if (c >= 'a' && c <= 'f') {
|
||||||
|
nibble = (uint8_t)(c - 'a' + 10);
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
accum = (uint16_t)((accum << 4u) | nibble);
|
||||||
|
}
|
||||||
|
*out = accum;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_ensure_directory(const char *path) {
|
||||||
|
struct stat st;
|
||||||
|
|
||||||
|
if (path == NULL || path[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (stat(path, &st) == 0) {
|
||||||
|
return S_ISDIR(st.st_mode);
|
||||||
|
}
|
||||||
|
if (errno != ENOENT) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (mkdir(path, 0755) != 0) {
|
||||||
|
if (errno == EEXIST) {
|
||||||
|
return stat(path, &st) == 0 && S_ISDIR(st.st_mode);
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_fsync_directory(const char *path) {
|
||||||
|
int fd;
|
||||||
|
int fsync_errno;
|
||||||
|
|
||||||
|
if (path == NULL || path[0] == '\0') {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY | O_DIRECTORY);
|
||||||
|
if (fd < 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (fsync(fd) != 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
fsync_errno = errno;
|
||||||
|
close(fd);
|
||||||
|
errno = fsync_errno;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static amduat_asl_store_fs_meta_read_status_t
|
||||||
|
amduat_asl_store_fs_meta_read_file(const char *path,
|
||||||
|
char **out_bytes,
|
||||||
|
size_t *out_size) {
|
||||||
|
struct stat st;
|
||||||
|
size_t file_size;
|
||||||
|
char *buffer;
|
||||||
|
size_t total_read;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (path == NULL || out_bytes == NULL || out_size == NULL) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
*out_bytes = NULL;
|
||||||
|
*out_size = 0;
|
||||||
|
|
||||||
|
if (stat(path, &st) != 0) {
|
||||||
|
if (errno == ENOENT || errno == ENOTDIR) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
if (!S_ISREG(st.st_mode)) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
if (st.st_size <= 0) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
if ((uintmax_t)st.st_size > SIZE_MAX) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
file_size = (size_t)st.st_size;
|
||||||
|
buffer = (char *)malloc(file_size + 1u);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open(path, O_RDONLY);
|
||||||
|
if (fd < 0) {
|
||||||
|
free(buffer);
|
||||||
|
if (errno == ENOENT || errno == ENOTDIR) {
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_NOT_FOUND;
|
||||||
|
}
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
total_read = 0u;
|
||||||
|
while (total_read < file_size) {
|
||||||
|
ssize_t rc = read(fd, buffer + total_read, file_size - total_read);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
free(buffer);
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
close(fd);
|
||||||
|
free(buffer);
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
total_read += (size_t)rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close(fd) != 0) {
|
||||||
|
free(buffer);
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_ERR;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer[file_size] = '\0';
|
||||||
|
*out_bytes = buffer;
|
||||||
|
*out_size = file_size;
|
||||||
|
return AMDUAT_ASL_STORE_FS_META_READ_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_write_atomic(const char *dir_path,
|
||||||
|
const char *final_path,
|
||||||
|
const uint8_t *bytes,
|
||||||
|
size_t size) {
|
||||||
|
static const char suffix[] = "tmp.XXXXXX";
|
||||||
|
size_t dir_len;
|
||||||
|
bool need_sep;
|
||||||
|
size_t template_len;
|
||||||
|
char *template_path;
|
||||||
|
int temp_fd;
|
||||||
|
size_t written;
|
||||||
|
|
||||||
|
if (dir_path == NULL || final_path == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (size != 0u && bytes == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dir_len = strlen(dir_path);
|
||||||
|
if (dir_len == 0u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
need_sep = dir_path[dir_len - 1u] != '/';
|
||||||
|
template_len = dir_len + (need_sep ? 1u : 0u) + sizeof(suffix);
|
||||||
|
|
||||||
|
template_path = (char *)malloc(template_len);
|
||||||
|
if (template_path == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (need_sep) {
|
||||||
|
snprintf(template_path, template_len, "%s/%s", dir_path, suffix);
|
||||||
|
} else {
|
||||||
|
snprintf(template_path, template_len, "%s%s", dir_path, suffix);
|
||||||
|
}
|
||||||
|
|
||||||
|
temp_fd = mkstemp(template_path);
|
||||||
|
if (temp_fd < 0) {
|
||||||
|
free(template_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
written = 0u;
|
||||||
|
while (written < size) {
|
||||||
|
ssize_t rc = write(temp_fd, bytes + written, size - written);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
close(temp_fd);
|
||||||
|
unlink(template_path);
|
||||||
|
free(template_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
written += (size_t)rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fsync(temp_fd) != 0) {
|
||||||
|
close(temp_fd);
|
||||||
|
unlink(template_path);
|
||||||
|
free(template_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (close(temp_fd) != 0) {
|
||||||
|
unlink(template_path);
|
||||||
|
free(template_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rename(template_path, final_path) != 0) {
|
||||||
|
unlink(template_path);
|
||||||
|
free(template_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(template_path);
|
||||||
|
return amduat_asl_store_fs_meta_fsync_directory(dir_path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_random_bytes(uint8_t *out, size_t len) {
|
||||||
|
size_t read_total;
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if (out == NULL || len == 0u) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = open("/dev/urandom", O_RDONLY);
|
||||||
|
if (fd >= 0) {
|
||||||
|
read_total = 0u;
|
||||||
|
while (read_total < len) {
|
||||||
|
ssize_t rc = read(fd, out + read_total, len - read_total);
|
||||||
|
if (rc < 0) {
|
||||||
|
if (errno == EINTR) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if (rc == 0) {
|
||||||
|
close(fd);
|
||||||
|
fd = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
read_total += (size_t)rc;
|
||||||
|
}
|
||||||
|
if (fd >= 0) {
|
||||||
|
close(fd);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
unsigned int seed;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
seed = (unsigned int)time(NULL);
|
||||||
|
seed ^= (unsigned int)getpid();
|
||||||
|
seed ^= (unsigned int)(uintptr_t)out;
|
||||||
|
srand(seed);
|
||||||
|
for (i = 0; i < len; ++i) {
|
||||||
|
out[i] = (uint8_t)(rand() & 0xff);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char amduat_asl_store_fs_meta_hex_lower(uint8_t nibble) {
|
||||||
|
static const char k_hex[] = "0123456789abcdef";
|
||||||
|
return k_hex[nibble & 0x0fu];
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_generate_uuid(
|
||||||
|
char out_id[AMDUAT_ASL_STORE_FS_STORE_ID_MAX + 1]) {
|
||||||
|
uint8_t bytes[16];
|
||||||
|
char *out;
|
||||||
|
size_t i;
|
||||||
|
|
||||||
|
if (out_id == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_store_fs_meta_random_bytes(bytes, sizeof(bytes))) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bytes[6] = (uint8_t)((bytes[6] & 0x0fu) | 0x40u);
|
||||||
|
bytes[8] = (uint8_t)((bytes[8] & 0x3fu) | 0x80u);
|
||||||
|
|
||||||
|
out = out_id;
|
||||||
|
for (i = 0; i < sizeof(bytes); ++i) {
|
||||||
|
if (i == 4u || i == 6u || i == 8u || i == 10u) {
|
||||||
|
*out++ = '-';
|
||||||
|
}
|
||||||
|
*out++ = amduat_asl_store_fs_meta_hex_lower((uint8_t)(bytes[i] >> 4u));
|
||||||
|
*out++ = amduat_asl_store_fs_meta_hex_lower(bytes[i]);
|
||||||
|
}
|
||||||
|
*out = '\0';
|
||||||
|
|
||||||
|
return amduat_asl_store_fs_meta_validate_store_id(out_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_parse_config_text(
|
||||||
|
char *text,
|
||||||
|
amduat_asl_store_fs_config_t *out_cfg) {
|
||||||
|
char *saveptr;
|
||||||
|
char *token;
|
||||||
|
bool got_store_id;
|
||||||
|
bool got_profile;
|
||||||
|
bool got_hash;
|
||||||
|
|
||||||
|
if (text == NULL || out_cfg == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out_cfg, 0, sizeof(*out_cfg));
|
||||||
|
saveptr = NULL;
|
||||||
|
token = strtok_r(text, " \t\r\n", &saveptr);
|
||||||
|
if (token == NULL || strcmp(token, "amduat-asl-config-v1") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
got_store_id = false;
|
||||||
|
got_profile = false;
|
||||||
|
got_hash = false;
|
||||||
|
|
||||||
|
while ((token = strtok_r(NULL, " \t\r\n", &saveptr)) != NULL) {
|
||||||
|
if (strncmp(token, "store_id=", 9u) == 0) {
|
||||||
|
const char *value = token + 9u;
|
||||||
|
if (!amduat_asl_store_fs_meta_copy_store_id(out_cfg->store_id, value)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
got_store_id = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(token, "profile=", 8u) == 0) {
|
||||||
|
const char *value = token + 8u;
|
||||||
|
uint16_t profile_id;
|
||||||
|
if (!amduat_asl_store_fs_meta_parse_hex4_lower(value, &profile_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out_cfg->config.encoding_profile_id = profile_id;
|
||||||
|
got_profile = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (strncmp(token, "hash=", 5u) == 0) {
|
||||||
|
const char *value = token + 5u;
|
||||||
|
uint16_t hash_id;
|
||||||
|
if (!amduat_asl_store_fs_meta_parse_hex4_lower(value, &hash_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out_cfg->config.hash_id = hash_id;
|
||||||
|
got_hash = true;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return got_store_id && got_profile && got_hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_parse_head_text(
|
||||||
|
char *text,
|
||||||
|
amduat_asl_store_fs_head_t *out_head) {
|
||||||
|
char *saveptr;
|
||||||
|
char *token;
|
||||||
|
bool got_snapshot;
|
||||||
|
|
||||||
|
if (text == NULL || out_head == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
memset(out_head, 0, sizeof(*out_head));
|
||||||
|
saveptr = NULL;
|
||||||
|
token = strtok_r(text, " \t\r\n", &saveptr);
|
||||||
|
if (token == NULL || strcmp(token, "amduat-asl-head-v1") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
got_snapshot = false;
|
||||||
|
|
||||||
|
while ((token = strtok_r(NULL, " \t\r\n", &saveptr)) != NULL) {
|
||||||
|
if (strncmp(token, "snapshot=", 9u) == 0) {
|
||||||
|
const char *value = token + 9u;
|
||||||
|
if (strcmp(value, "none") != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
out_head->has_snapshot = false;
|
||||||
|
got_snapshot = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return got_snapshot;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool amduat_asl_store_fs_meta_write_config(
|
||||||
|
const char *root_path,
|
||||||
|
const amduat_asl_store_fs_config_t *cfg) {
|
||||||
|
char *config_path;
|
||||||
|
int needed;
|
||||||
|
size_t len;
|
||||||
|
char *buffer;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (root_path == NULL || cfg == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_path = NULL;
|
||||||
|
if (!amduat_asl_store_fs_layout_build_config_path(root_path, &config_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
needed = snprintf(NULL,
|
||||||
|
0,
|
||||||
|
"amduat-asl-config-v1\nstore_id=%s\nprofile=%04x\nhash=%04x\n",
|
||||||
|
cfg->store_id,
|
||||||
|
(unsigned int)cfg->config.encoding_profile_id,
|
||||||
|
(unsigned int)cfg->config.hash_id);
|
||||||
|
if (needed < 0) {
|
||||||
|
free(config_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
len = (size_t)needed;
|
||||||
|
|
||||||
|
buffer = (char *)malloc(len + 1u);
|
||||||
|
if (buffer == NULL) {
|
||||||
|
free(config_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
snprintf(buffer,
|
||||||
|
len + 1u,
|
||||||
|
"amduat-asl-config-v1\nstore_id=%s\nprofile=%04x\nhash=%04x\n",
|
||||||
|
cfg->store_id,
|
||||||
|
(unsigned int)cfg->config.encoding_profile_id,
|
||||||
|
(unsigned int)cfg->config.hash_id);
|
||||||
|
|
||||||
|
ok = amduat_asl_store_fs_meta_write_atomic(root_path,
|
||||||
|
config_path,
|
||||||
|
(const uint8_t *)buffer,
|
||||||
|
len);
|
||||||
|
free(buffer);
|
||||||
|
free(config_path);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_init_root(
|
||||||
|
const char *root_path,
|
||||||
|
const amduat_asl_store_fs_config_t *cfg_in,
|
||||||
|
amduat_asl_store_fs_config_t *cfg_out) {
|
||||||
|
char *objects_path;
|
||||||
|
char *config_path;
|
||||||
|
amduat_asl_store_fs_meta_read_status_t read_status;
|
||||||
|
char *config_text;
|
||||||
|
size_t config_size;
|
||||||
|
amduat_asl_store_fs_config_t loaded_cfg;
|
||||||
|
amduat_asl_store_fs_config_t new_cfg;
|
||||||
|
|
||||||
|
if (root_path == NULL || root_path[0] == '\0' || cfg_out == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduat_asl_store_fs_meta_ensure_directory(root_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
objects_path = NULL;
|
||||||
|
if (!amduat_asl_store_fs_layout_build_objects_path(root_path,
|
||||||
|
&objects_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!amduat_asl_store_fs_meta_ensure_directory(objects_path)) {
|
||||||
|
free(objects_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(objects_path);
|
||||||
|
|
||||||
|
config_path = NULL;
|
||||||
|
if (!amduat_asl_store_fs_layout_build_config_path(root_path,
|
||||||
|
&config_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_text = NULL;
|
||||||
|
config_size = 0u;
|
||||||
|
read_status =
|
||||||
|
amduat_asl_store_fs_meta_read_file(config_path,
|
||||||
|
&config_text,
|
||||||
|
&config_size);
|
||||||
|
(void)config_size;
|
||||||
|
if (read_status == AMDUAT_ASL_STORE_FS_META_READ_OK) {
|
||||||
|
bool ok = amduat_asl_store_fs_meta_parse_config_text(config_text,
|
||||||
|
&loaded_cfg);
|
||||||
|
free(config_text);
|
||||||
|
free(config_path);
|
||||||
|
if (!ok) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cfg_in != NULL) {
|
||||||
|
if (cfg_in->store_id[0] != '\0') {
|
||||||
|
if (!amduat_asl_store_fs_meta_validate_store_id(cfg_in->store_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (strcmp(cfg_in->store_id, loaded_cfg.store_id) != 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (cfg_in->config.encoding_profile_id != 0 &&
|
||||||
|
cfg_in->config.encoding_profile_id !=
|
||||||
|
loaded_cfg.config.encoding_profile_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (cfg_in->config.hash_id != 0 &&
|
||||||
|
cfg_in->config.hash_id != loaded_cfg.config.hash_id) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*cfg_out = loaded_cfg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (read_status != AMDUAT_ASL_STORE_FS_META_READ_NOT_FOUND) {
|
||||||
|
free(config_path);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
free(config_path);
|
||||||
|
|
||||||
|
memset(&new_cfg, 0, sizeof(new_cfg));
|
||||||
|
new_cfg.config.encoding_profile_id = AMDUAT_ENC_ASL1_CORE_V1;
|
||||||
|
new_cfg.config.hash_id = AMDUAT_HASH_ASL1_ID_SHA256;
|
||||||
|
|
||||||
|
if (cfg_in != NULL) {
|
||||||
|
if (cfg_in->config.encoding_profile_id != 0) {
|
||||||
|
new_cfg.config.encoding_profile_id =
|
||||||
|
cfg_in->config.encoding_profile_id;
|
||||||
|
}
|
||||||
|
if (cfg_in->config.hash_id != 0) {
|
||||||
|
new_cfg.config.hash_id = cfg_in->config.hash_id;
|
||||||
|
}
|
||||||
|
if (cfg_in->store_id[0] != '\0') {
|
||||||
|
if (!amduat_asl_store_fs_meta_copy_store_id(new_cfg.store_id,
|
||||||
|
cfg_in->store_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (new_cfg.store_id[0] == '\0') {
|
||||||
|
if (!amduat_asl_store_fs_meta_generate_uuid(new_cfg.store_id)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!amduat_asl_store_fs_meta_write_config(root_path, &new_cfg)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
*cfg_out = new_cfg;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_load_config(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_fs_config_t *out_cfg) {
|
||||||
|
char *config_path;
|
||||||
|
amduat_asl_store_fs_meta_read_status_t read_status;
|
||||||
|
char *config_text;
|
||||||
|
size_t config_size;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (root_path == NULL || root_path[0] == '\0' || out_cfg == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_path = NULL;
|
||||||
|
if (!amduat_asl_store_fs_layout_build_config_path(root_path, &config_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
config_text = NULL;
|
||||||
|
config_size = 0u;
|
||||||
|
read_status =
|
||||||
|
amduat_asl_store_fs_meta_read_file(config_path,
|
||||||
|
&config_text,
|
||||||
|
&config_size);
|
||||||
|
(void)config_size;
|
||||||
|
free(config_path);
|
||||||
|
if (read_status != AMDUAT_ASL_STORE_FS_META_READ_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = amduat_asl_store_fs_meta_parse_config_text(config_text, out_cfg);
|
||||||
|
free(config_text);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool amduat_asl_store_fs_load_head(
|
||||||
|
const char *root_path,
|
||||||
|
amduat_asl_store_fs_head_t *out_head) {
|
||||||
|
char *head_path;
|
||||||
|
amduat_asl_store_fs_meta_read_status_t read_status;
|
||||||
|
char *head_text;
|
||||||
|
size_t head_size;
|
||||||
|
bool ok;
|
||||||
|
|
||||||
|
if (root_path == NULL || root_path[0] == '\0' || out_head == NULL) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
head_path = NULL;
|
||||||
|
if (!amduat_asl_store_fs_layout_build_head_path(root_path, &head_path)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
head_text = NULL;
|
||||||
|
head_size = 0u;
|
||||||
|
read_status =
|
||||||
|
amduat_asl_store_fs_meta_read_file(head_path, &head_text, &head_size);
|
||||||
|
(void)head_size;
|
||||||
|
free(head_path);
|
||||||
|
if (read_status == AMDUAT_ASL_STORE_FS_META_READ_NOT_FOUND) {
|
||||||
|
memset(out_head, 0, sizeof(*out_head));
|
||||||
|
out_head->has_snapshot = false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (read_status != AMDUAT_ASL_STORE_FS_META_READ_OK) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
ok = amduat_asl_store_fs_meta_parse_head_text(head_text, out_head);
|
||||||
|
free(head_text);
|
||||||
|
return ok;
|
||||||
|
}
|
||||||
Loading…
Reference in a new issue