Compare commits

...

10 Commits

18 changed files with 1936 additions and 676 deletions

View File

@@ -52,6 +52,12 @@ enum ec3_tag_flags {
EC3_TAG_F_NONE = 0x00000000u,
};
enum ec3_executable_format {
EC3_EXEC_NONE = 0x0000u,
EC3_EXEC_ELF = 0x0001u,
EC3_EXEC_OTHER = 0x1000u,
};
enum ec3_vnode_mode {
EC3_V_REG = 0x0001u,
EC3_V_DIR = 0x0002u,
@@ -126,6 +132,27 @@ PACK(struct ec3_cluster_group {
uint8_t g_padding[20];
});
struct ec3_executable {
b_i16 exe_format;
b_i16 exe_reserved;
union {
struct {
b_i32 elf_data_offset;
b_i32 elf_data_filesz, elf_data_memsz;
b_i32 elf_text_offset;
b_i32 elf_text_filesz, elf_text_memsz;
b_i32 elf_data_align, elf_text_align;
b_i64 elf_data_vaddr;
b_i64 elf_text_vaddr;
b_i64 elf_entry;
} exe_elf;
};
};
struct ec3_tag_table_entry {
b_i32 tag_type;
b_i32 tag_flags;
@@ -133,6 +160,11 @@ struct ec3_tag_table_entry {
b_i32 tag_reserved1;
b_i64 tag_ident;
b_i64 tag_length;
union {
struct ec3_executable tag_exe;
char tag_reserved2[96];
};
};
/* Extents serve two purposes:

603
src/builder.c Normal file
View File

@@ -0,0 +1,603 @@
#include "builder.h"
#include "fs-tree.h"
#include "image.h"
#include "tag.h"
#include "volume.h"
#include <blue/io/directory.h>
#include <blue/io/path.h>
#include <blue/object/list.h>
#include <stdlib.h>
#include <string.h>
struct capture_directory_ctx {
struct ec3_image_builder *ctx_builder;
struct ec3_volume *ctx_volume;
struct fs_tree ctx_tree;
};
static enum ec3_status init_string_table(struct ec3_image_builder *builder)
{
if (builder->b_flags & EC3_IMAGE_BUILDER_STRING_TABLE) {
return EC3_SUCCESS;
}
uint64_t stab_id;
ec3_identifier_from_string("_VOLSTR0", &stab_id);
enum ec3_status status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_STAB,
stab_id,
EC3_TAG_IO_WRITE | EC3_TAG_IO_SEQUENTIAL,
&builder->b_stab);
if (status != EC3_SUCCESS) {
return status;
}
string_table_init(&builder->b_strings);
builder->b_flags |= EC3_IMAGE_BUILDER_STRING_TABLE;
return EC3_SUCCESS;
}
static enum ec3_status init_chunk_table(struct ec3_image_builder *builder)
{
if (builder->b_flags & EC3_IMAGE_BUILDER_CHUNK_TABLE) {
return EC3_SUCCESS;
}
uint64_t ctab_id, cdat_id;
ec3_identifier_from_string("_CHKTAB0", &ctab_id);
ec3_identifier_from_string("_CHKDAT0", &cdat_id);
enum ec3_status status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_CTAB,
ctab_id,
EC3_TAG_IO_READWRITE,
&builder->b_ctab);
if (status != EC3_SUCCESS) {
return status;
}
status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_CDAT,
cdat_id,
EC3_TAG_IO_READWRITE,
&builder->b_cdat);
if (status != EC3_SUCCESS) {
ec3_tag_ioctx_close(builder->b_ctab);
builder->b_ctab = NULL;
return status;
}
status = chunk_table_init(
builder->b_ctab,
builder->b_cdat,
builder->b_param.p_cluster_size,
&builder->b_chunks);
if (status != EC3_SUCCESS) {
ec3_tag_ioctx_close(builder->b_ctab);
ec3_tag_ioctx_close(builder->b_cdat);
return status;
}
chunk_table_init_empty_table(&builder->b_chunks);
builder->b_flags |= EC3_IMAGE_BUILDER_CHUNK_TABLE;
return EC3_SUCCESS;
}
static enum ec3_status capture_directory_file(
struct capture_directory_ctx *ctx,
b_directory *dir,
const char *filename,
const b_path *filepath,
ec3_chunk_id out_chunk)
{
const struct ec3_image_info *image_info
= ec3_image_ioctx_get_info(ctx->ctx_builder->b_image);
size_t key = string_table_get(&ctx->ctx_builder->b_strings, filename);
size_t buf_len = image_info->img_cluster_size;
char *buf = malloc(buf_len);
if (!buf) {
return EC3_ERR_NO_MEMORY;
}
b_file *src = NULL;
b_status status = b_file_open(
dir,
filepath,
B_FILE_READ_ONLY | B_FILE_BINARY,
&src);
if (!B_OK(status)) {
free(buf);
return ec3_status_from_b_status(status, EC3_ERR_NO_ENTRY);
}
enum ec3_status s2 = EC3_SUCCESS;
chunk_table_begin_chunk(&ctx->ctx_builder->b_chunks);
size_t chunk_size = 0;
while (1) {
size_t nr_read = 0;
status = b_file_read(
src,
B_OFFSET_CURRENT,
buf_len,
buf,
&nr_read);
if (!B_OK(status)) {
s2 = ec3_status_from_b_status(
status,
EC3_ERR_IO_FAILURE);
break;
}
enum ec3_status s2 = chunk_table_put(
&ctx->ctx_builder->b_chunks,
buf,
nr_read);
if (s2 != EC3_SUCCESS) {
break;
}
chunk_size += nr_read;
if (nr_read < buf_len) {
break;
}
}
s2 = chunk_table_end_chunk(&ctx->ctx_builder->b_chunks, out_chunk);
if (s2 != EC3_SUCCESS) {
return s2;
}
char id_str[128];
ec3_chunk_id_to_string(out_chunk, id_str, sizeof id_str);
free(buf);
b_file_release(src);
return s2;
}
struct capture_directory_structure_args {
b_list *args_stack;
struct capture_directory_ctx *args_ctx;
};
static int capture_directory_structure_callback(
struct fs_tree *tree,
struct fs_tree_node *node,
unsigned int depth,
int direction,
void *arg)
{
if (direction != ITERATE_POSTORDER) {
return 0;
}
struct capture_directory_structure_args *args = arg;
b_list *stack = args->args_stack;
struct capture_directory_ctx *ctx = args->args_ctx;
if (node->n_type == FS_TREE_FILE) {
b_list_push_back(stack, node);
return 0;
}
size_t nr_children = fs_tree_node_get_nr_children(node);
struct ec3_directory_entry dent;
enum ec3_status status = EC3_SUCCESS;
chunk_table_begin_chunk(&ctx->ctx_builder->b_chunks);
for (size_t i = 0; i < nr_children; i++) {
struct fs_tree_node *child = b_list_pop_back(stack);
if (!child) {
return EC3_ERR_INTERNAL_FAILURE;
}
dent.d_name = b_i32_htob(string_table_get(
&ctx->ctx_builder->b_strings,
child->n_name));
dent.d_vnode = b_i32_htob(child->n_id);
status = chunk_table_put(
&ctx->ctx_builder->b_chunks,
&dent,
sizeof dent);
}
status = chunk_table_end_chunk(
&ctx->ctx_builder->b_chunks,
node->n_chunk);
if (status != EC3_SUCCESS) {
return status;
}
char id_str[128];
ec3_chunk_id_to_string(node->n_chunk, id_str, sizeof id_str);
#if 0
printf("[d %s / %zu] wrote %zu byte chunk %s\n",
node->n_name,
node->n_id,
nr_children * sizeof dent,
id_str);
#endif
struct ec3_vnode vnode = {
.v_id = node->n_id,
.v_mode = EC3_V_DIR,
};
memcpy(vnode.v_data, node->n_chunk, sizeof vnode.v_data);
ec3_volume_put_vnode(ctx->ctx_volume, &vnode);
b_list_push_back(stack, node);
return 0;
}
static enum ec3_status capture_directory_structure(
struct capture_directory_ctx *ctx)
{
b_list *stack = b_list_create();
struct capture_directory_structure_args args = {
.args_stack = stack,
.args_ctx = ctx,
};
fs_tree_iterate(
&ctx->ctx_tree,
capture_directory_structure_callback,
&args);
return EC3_SUCCESS;
}
enum ec3_status ec3_image_builder_capture_directory(
struct ec3_image_builder *builder,
uint64_t id,
const char *directory_path)
{
enum ec3_status status2 = init_string_table(builder);
if (status2 != EC3_SUCCESS) {
return status2;
}
status2 = init_chunk_table(builder);
if (status2 != EC3_SUCCESS) {
return status2;
}
b_path *path = b_path_create_from_cstr(directory_path);
b_directory *dir;
b_status status = b_directory_open(NULL, path, &dir);
b_path_release(path);
if (!B_OK(status)) {
return EC3_ERR_NO_ENTRY;
}
struct ec3_tag_ioctx *volu;
enum ec3_status s2 = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_VOLU,
id,
EC3_TAG_IO_READ | EC3_TAG_IO_WRITE,
&volu);
if (s2 != EC3_SUCCESS) {
b_directory_release(dir);
return s2;
}
struct capture_directory_ctx ctx = {.ctx_builder = builder};
s2 = ec3_volume_create(builder->b_image, volu, &ctx.ctx_volume);
if (s2 != EC3_SUCCESS) {
ec3_tag_ioctx_close(volu);
b_directory_release(dir);
return s2;
}
fs_tree_init(&ctx.ctx_tree);
struct ec3_vnode vnode = {0};
vnode.v_id = ctx.ctx_tree.fs_root->n_id;
ec3_volume_put_vnode(ctx.ctx_volume, &vnode);
status2 = EC3_SUCCESS;
b_directory_iterator it;
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST);
while (b_directory_iterator_is_valid(&it)) {
if (!b_directory_path_is_file(dir, it.filepath)) {
printf("dir: %s\n", b_path_ptr(it.filepath));
b_directory_iterator_next(&it);
continue;
}
ec3_vnode_from_file_info(&it.info, &vnode);
printf("file: %s\n", b_path_ptr(it.filepath));
status2 = capture_directory_file(
&ctx,
dir,
it.filename,
it.filepath,
vnode.v_data);
if (status2 != EC3_SUCCESS) {
#if 0
b_err("failed to capture file '%s'",
b_path_ptr(it.filepath));
b_i("error code: %s", ec3_status_to_string(status2));
#endif
break;
}
fs_tree_put(
&ctx.ctx_tree,
b_path_ptr(it.filepath),
&vnode.v_id,
vnode.v_data);
ec3_volume_put_vnode(ctx.ctx_volume, &vnode);
b_directory_iterator_next(&it);
}
// fs_tree_iterate(&ctx->ctx_tree, print_fs_tree_node, NULL);
capture_directory_structure(&ctx);
fs_tree_fini(&ctx.ctx_tree);
ec3_tag_ioctx_close(volu);
b_directory_release(dir);
return status2;
}
enum ec3_status ec3_image_builder_create(
const char *path,
const struct ec3_parameters *params,
struct ec3_image_builder **out)
{
struct ec3_image_builder *builder = malloc(sizeof *builder);
if (!builder) {
return EC3_ERR_NO_MEMORY;
}
memset(builder, 0x0, sizeof *builder);
b_path *image_path = b_path_create_from_cstr(path);
if (b_path_exists(image_path)) {
b_path_unlink(image_path);
}
b_path_release(image_path);
enum ec3_status status = ec3_image_ioctx_open(
path,
params,
EC3_IMAGE_IO_WRITE,
&builder->b_image);
if (status != EC3_SUCCESS) {
ec3_image_builder_destroy(builder);
return status;
}
memcpy(&builder->b_param, params, sizeof *params);
*out = builder;
return EC3_SUCCESS;
}
static enum ec3_status flush_strings(struct ec3_image_builder *builder)
{
enum ec3_status status = EC3_SUCCESS;
b_btree_iterator s_it;
b_btree_iterator_begin(&builder->b_strings.s_offset_tree, &s_it);
while (b_btree_iterator_is_valid(&s_it)) {
struct string_table_entry *entry = b_unbox(
struct string_table_entry,
s_it.node,
e_offset_node);
size_t len = strlen(entry->e_str) + 1;
size_t nr_written = 0;
status = ec3_tag_ioctx_write(
builder->b_stab,
entry->e_str,
len,
&nr_written);
b_btree_iterator_next(&s_it);
if (status != EC3_SUCCESS) {
break;
}
}
return status;
}
enum ec3_status ec3_image_builder_destroy(struct ec3_image_builder *builder)
{
enum ec3_status status = EC3_SUCCESS;
if (builder->b_flags & EC3_IMAGE_BUILDER_STRING_TABLE) {
status = flush_strings(builder);
string_table_finish(&builder->b_strings);
ec3_tag_ioctx_close(builder->b_stab);
}
/* TODO propagate status code from flush_strings */
if (builder->b_flags & EC3_IMAGE_BUILDER_CHUNK_TABLE) {
chunk_table_finish(&builder->b_chunks);
ec3_tag_ioctx_close(builder->b_ctab);
ec3_tag_ioctx_close(builder->b_cdat);
}
status = ec3_image_ioctx_close(builder->b_image);
free(builder);
return status;
}
enum ec3_status ec3_image_builder_add_blob_from_file(
struct ec3_image_builder *builder,
uint64_t id,
FILE *fp)
{
size_t cluster_size
= ec3_cluster_size_id_to_bytes(builder->b_param.p_cluster_size);
char *buf = malloc(cluster_size);
if (!buf) {
return EC3_ERR_NO_MEMORY;
}
struct ec3_tag_ioctx *tag = NULL;
enum ec3_status status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_BLOB,
id,
EC3_TAG_IO_WRITE | EC3_TAG_IO_SEQUENTIAL,
&tag);
if (status != EC3_SUCCESS) {
free(buf);
return status;
}
size_t i = 0;
while (1) {
size_t r = fread(buf, 1, cluster_size, fp);
if (r == 0) {
break;
}
size_t w;
status = ec3_tag_ioctx_write_cluster(tag, i++, buf, r, &w);
if (r < cluster_size) {
break;
}
}
free(buf);
ec3_tag_ioctx_close(tag);
return EC3_SUCCESS;
}
enum ec3_status ec3_image_builder_add_blob_from_buffer(
struct ec3_image_builder *builder,
uint64_t id,
const void *buf,
size_t len)
{
size_t cluster_size
= ec3_cluster_size_id_to_bytes(builder->b_param.p_cluster_size);
struct ec3_tag_ioctx *tag = NULL;
enum ec3_status status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_BLOB,
id,
EC3_TAG_IO_WRITE | EC3_TAG_IO_SEQUENTIAL,
&tag);
if (status != EC3_SUCCESS) {
return status;
}
size_t i = 0;
const unsigned char *bytes = buf;
size_t remaining = len;
while (remaining > 0) {
size_t to_copy = remaining;
if (to_copy > cluster_size) {
to_copy = cluster_size;
}
size_t w;
status = ec3_tag_ioctx_write_cluster(
tag,
i++,
bytes,
to_copy,
&w);
remaining -= to_copy;
bytes += to_copy;
}
ec3_tag_ioctx_close(tag);
return EC3_SUCCESS;
}
enum ec3_status ec3_image_builder_add_executable_from_file(
struct ec3_image_builder *builder,
uint64_t id,
const struct ec3_tag_executable_info *exe,
FILE *fp)
{
size_t cluster_size
= ec3_cluster_size_id_to_bytes(builder->b_param.p_cluster_size);
char *buf = malloc(cluster_size);
if (!buf) {
return EC3_ERR_NO_MEMORY;
}
struct ec3_tag_ioctx *tag = NULL;
enum ec3_status status = ec3_image_ioctx_create_tag(
builder->b_image,
EC3_TAG_EXEC,
id,
EC3_TAG_IO_WRITE | EC3_TAG_IO_SEQUENTIAL,
&tag);
if (status != EC3_SUCCESS) {
free(buf);
return status;
}
size_t i = 0;
while (1) {
size_t r = fread(buf, 1, cluster_size, fp);
if (r == 0) {
break;
}
size_t w;
status = ec3_tag_ioctx_write_cluster(tag, i++, buf, r, &w);
if (r < cluster_size) {
break;
}
}
memcpy(&tag->io_tag_info.tag_exe, exe, sizeof *exe);
free(buf);
ec3_tag_ioctx_close(tag);
return EC3_SUCCESS;
}

52
src/builder.h Normal file
View File

@@ -0,0 +1,52 @@
#ifndef BUILDER_H_
#define BUILDER_H_
#include "chunk-table.h"
#include "image.h"
#include "string-table.h"
enum ec3_image_builder_flags {
EC3_IMAGE_BUILDER_STRING_TABLE = 0x01u,
EC3_IMAGE_BUILDER_CHUNK_TABLE = 0x02u,
};
struct ec3_image_builder {
enum ec3_image_builder_flags b_flags;
struct ec3_parameters b_param;
struct ec3_image_ioctx *b_image;
struct string_table b_strings;
struct chunk_table b_chunks;
struct ec3_tag_ioctx *b_stab;
struct ec3_tag_ioctx *b_ctab, *b_cdat;
};
extern enum ec3_status ec3_image_builder_create(
const char *image_path,
const struct ec3_parameters *params,
struct ec3_image_builder **out);
extern enum ec3_status ec3_image_builder_destroy(
struct ec3_image_builder *builder);
extern enum ec3_status ec3_image_builder_capture_directory(
struct ec3_image_builder *builder,
uint64_t id,
const char *directory_path);
extern enum ec3_status ec3_image_builder_add_blob_from_file(
struct ec3_image_builder *builder,
uint64_t id,
FILE *fp);
extern enum ec3_status ec3_image_builder_add_blob_from_buffer(
struct ec3_image_builder *builder,
uint64_t id,
const void *buf,
size_t len);
extern enum ec3_status ec3_image_builder_add_executable_from_file(
struct ec3_image_builder *builder,
uint64_t id,
const struct ec3_tag_executable_info *exe,
FILE *fp);
#endif

View File

@@ -1,12 +1,9 @@
#include "bin.h"
#include "chunk-table.h"
#include "builder.h"
#include "commands.h"
#include "fs-tree.h"
#include "image.h"
#include "misc.h"
#include "status.h"
#include "string-table.h"
#include "volume.h"
#include <blue/cmd.h>
#include <blue/io/directory.h>
@@ -35,309 +32,6 @@ enum {
OPT_VERBOSE,
};
struct capture_ctx {
struct fs_tree ctx_tree;
struct ec3_image_ioctx *ctx_image;
struct chunk_table ctx_chunks;
struct string_table ctx_strings;
struct ec3_volume *ctx_volume;
};
static enum ec3_status capture_file(
struct capture_ctx *ctx,
struct ec3_volume *vol,
b_directory *dir,
const char *filename,
const b_path *filepath,
ec3_chunk_id out_chunk)
{
const struct ec3_image_info *image_info
= ec3_image_ioctx_get_info(ctx->ctx_image);
size_t key = string_table_get(&ctx->ctx_strings, filename);
size_t buf_len = image_info->img_cluster_size;
char *buf = malloc(buf_len);
if (!buf) {
return EC3_ERR_NO_MEMORY;
}
b_file *src = NULL;
b_status status = b_file_open(
dir,
filepath,
B_FILE_READ_ONLY | B_FILE_BINARY,
&src);
if (!B_OK(status)) {
free(buf);
return ec3_status_from_b_status(status, EC3_ERR_NO_ENTRY);
}
enum ec3_status s2 = EC3_SUCCESS;
chunk_table_begin_chunk(&ctx->ctx_chunks);
size_t chunk_size = 0;
while (1) {
size_t nr_read = 0;
status = b_file_read(
src,
B_OFFSET_CURRENT,
buf_len,
buf,
&nr_read);
if (!B_OK(status)) {
s2 = ec3_status_from_b_status(
status,
EC3_ERR_IO_FAILURE);
break;
}
enum ec3_status s2
= chunk_table_put(&ctx->ctx_chunks, buf, nr_read);
if (s2 != EC3_SUCCESS) {
break;
}
chunk_size += nr_read;
if (nr_read < buf_len) {
break;
}
}
s2 = chunk_table_end_chunk(&ctx->ctx_chunks, out_chunk);
if (s2 != EC3_SUCCESS) {
return s2;
}
char id_str[128];
ec3_chunk_id_to_string(out_chunk, id_str, sizeof id_str);
// printf("wrote %zu byte chunk %s\n", chunk_size, id_str);
free(buf);
b_file_release(src);
return s2;
}
static int print_fs_tree_node(
struct fs_tree *tree,
struct fs_tree_node *node,
unsigned int depth,
int direction,
void *arg)
{
if (direction == ITERATE_POSTORDER) {
depth = 0;
}
for (unsigned int i = 0; i < depth; i++) {
fputs(" ", stdout);
}
printf("%s ", node->n_name);
char id_str[128];
switch (node->n_type) {
case FS_TREE_FILE:
ec3_chunk_id_to_string(node->n_chunk, id_str, sizeof id_str);
printf("[%s]", id_str);
break;
case FS_TREE_DIR:
printf("[d]");
break;
default:
break;
}
printf("\n");
return 0;
}
struct capture_directory_structure_args {
b_list *args_stack;
struct capture_ctx *args_ctx;
};
static int capture_directory_structure_callback(
struct fs_tree *tree,
struct fs_tree_node *node,
unsigned int depth,
int direction,
void *arg)
{
if (direction != ITERATE_POSTORDER) {
return 0;
}
struct capture_directory_structure_args *args = arg;
b_list *stack = args->args_stack;
struct capture_ctx *ctx = args->args_ctx;
if (node->n_type == FS_TREE_FILE) {
b_list_push_back(stack, node);
return 0;
}
size_t nr_children = fs_tree_node_get_nr_children(node);
struct ec3_directory_entry dent;
enum ec3_status status = EC3_SUCCESS;
chunk_table_begin_chunk(&ctx->ctx_chunks);
for (size_t i = 0; i < nr_children; i++) {
struct fs_tree_node *child = b_list_pop_back(stack);
if (!child) {
return EC3_ERR_INTERNAL_FAILURE;
}
dent.d_name = b_i32_htob(
string_table_get(&ctx->ctx_strings, child->n_name));
dent.d_vnode = b_i32_htob(child->n_id);
status = chunk_table_put(&ctx->ctx_chunks, &dent, sizeof dent);
}
status = chunk_table_end_chunk(&ctx->ctx_chunks, node->n_chunk);
if (status != EC3_SUCCESS) {
return status;
}
char id_str[128];
ec3_chunk_id_to_string(node->n_chunk, id_str, sizeof id_str);
printf("[d %s / %zu] wrote %zu byte chunk %s\n",
node->n_name,
node->n_id,
nr_children * sizeof dent,
id_str);
struct ec3_vnode vnode = {
.v_id = node->n_id,
.v_mode = EC3_V_DIR,
};
memcpy(vnode.v_data, node->n_chunk, sizeof vnode.v_data);
ec3_volume_put_vnode(ctx->ctx_volume, &vnode);
b_list_push_back(stack, node);
return 0;
}
static enum ec3_status capture_directory_structure(struct capture_ctx *ctx)
{
b_list *stack = b_list_create();
struct capture_directory_structure_args args = {
.args_stack = stack,
.args_ctx = ctx,
};
fs_tree_iterate(
&ctx->ctx_tree,
capture_directory_structure_callback,
&args);
return EC3_SUCCESS;
}
static enum ec3_status capture_directory(
struct capture_ctx *ctx,
uint64_t id,
const char *cpath)
{
b_path *path = b_path_create_from_cstr(cpath);
b_directory *dir;
b_status status = b_directory_open(NULL, path, &dir);
b_path_release(path);
if (!B_OK(status)) {
return EC3_ERR_NO_ENTRY;
}
struct ec3_tag_ioctx *volu;
enum ec3_status s2 = ec3_image_ioctx_create_tag(
ctx->ctx_image,
EC3_TAG_VOLU,
id,
EC3_TAG_IO_READ | EC3_TAG_IO_WRITE,
&volu);
if (s2 != EC3_SUCCESS) {
b_directory_release(dir);
return s2;
}
struct ec3_volume *volume;
s2 = ec3_volume_create(ctx->ctx_image, volu, &volume);
if (s2 != EC3_SUCCESS) {
ec3_tag_ioctx_close(volu);
b_directory_release(dir);
return s2;
}
ctx->ctx_volume = volume;
fs_tree_init(&ctx->ctx_tree);
struct ec3_vnode vnode = {0};
vnode.v_id = ctx->ctx_tree.fs_root->n_id;
ec3_volume_put_vnode(volume, &vnode);
enum ec3_status status2 = EC3_SUCCESS;
b_directory_iterator it;
b_directory_iterator_begin(dir, &it, B_DIRECTORY_ITERATE_PARENT_LAST);
while (b_directory_iterator_is_valid(&it)) {
if (!b_directory_path_is_file(dir, it.filepath)) {
printf("dir: %s\n", b_path_ptr(it.filepath));
b_directory_iterator_next(&it);
continue;
}
ec3_vnode_from_file_info(&it.info, &vnode);
printf("file: %s\n", b_path_ptr(it.filepath));
status2 = capture_file(
ctx,
volume,
dir,
it.filename,
it.filepath,
vnode.v_data);
if (status2 != EC3_SUCCESS) {
b_err("failed to capture file '%s'",
b_path_ptr(it.filepath));
b_i("error code: %s", ec3_status_to_string(status2));
break;
}
fs_tree_put(
&ctx->ctx_tree,
b_path_ptr(it.filepath),
&vnode.v_id,
vnode.v_data);
ec3_volume_put_vnode(volume, &vnode);
b_directory_iterator_next(&it);
}
// fs_tree_iterate(&ctx->ctx_tree, print_fs_tree_node, NULL);
capture_directory_structure(ctx);
fs_tree_fini(&ctx->ctx_tree);
ec3_tag_ioctx_close(volu);
b_directory_release(dir);
return status2;
}
static int capture(
const b_command *self,
const b_arglist *opt,
@@ -360,74 +54,19 @@ static int capture(
return -1;
}
struct ec3_image_ioctx *image = NULL;
struct ec3_image_builder *image = NULL;
struct ec3_parameters param = {
.p_cluster_size = EC3_CLUSTER_16K,
.p_compression_func = EC3_COMPRESSION_ZSTD,
.p_ident = ident,
};
status = ec3_image_ioctx_open(
out_path,
&param,
EC3_IMAGE_IO_WRITE | EC3_IMAGE_IO_TRUNCATE,
&image);
status = ec3_image_builder_create(out_path, &param, &image);
if (status != EC3_SUCCESS) {
b_err("cannot initialise EC3 writer");
return -1;
}
uint64_t ctab_id, cdat_id, stab_id;
ec3_identifier_from_string("_CHKTAB0", &ctab_id);
ec3_identifier_from_string("_CHKDAT0", &cdat_id);
ec3_identifier_from_string("_VOLSTR0", &stab_id);
struct ec3_tag_ioctx *ctab, *cdat, *stab;
status = ec3_image_ioctx_create_tag(
image,
EC3_TAG_CTAB,
ctab_id,
EC3_TAG_IO_READ | EC3_TAG_IO_WRITE,
&ctab);
if (status != EC3_SUCCESS) {
b_err("cannot create chunk table tag");
b_i("error code: %s", ec3_status_to_string(status));
return -1;
}
status = ec3_image_ioctx_create_tag(
image,
EC3_TAG_CDAT,
cdat_id,
EC3_TAG_IO_READ | EC3_TAG_IO_WRITE,
&cdat);
if (status != EC3_SUCCESS) {
b_err("cannot create chunk data tag");
b_i("error code: %s", ec3_status_to_string(status));
return -1;
}
status = ec3_image_ioctx_create_tag(
image,
EC3_TAG_STAB,
stab_id,
EC3_TAG_IO_WRITE | EC3_TAG_IO_SEQUENTIAL,
&stab);
if (status != EC3_SUCCESS) {
b_err("cannot create string table tag");
b_i("error code: %s", ec3_status_to_string(status));
return -1;
}
struct capture_ctx ctx = {0};
ctx.ctx_image = image;
chunk_table_init(ctab, cdat, param.p_cluster_size, &ctx.ctx_chunks);
chunk_table_init_empty_table(&ctx.ctx_chunks);
string_table_init(&ctx.ctx_strings);
uint64_t next_auto_id = 0;
b_arglist_iterator it = {0};
@@ -435,8 +74,8 @@ static int capture(
{
printf("%s\n", it.value->val_str);
status = capture_directory(
&ctx,
status = ec3_image_builder_capture_directory(
image,
next_auto_id,
it.value->val_str);
next_auto_id++;
@@ -482,7 +121,10 @@ static int capture(
return -1;
}
status = capture_directory(&ctx, id, path->val_str);
status = ec3_image_builder_capture_directory(
image,
id,
path->val_str);
if (status != EC3_SUCCESS) {
b_err("an error occurred while writing to the "
@@ -491,32 +133,7 @@ static int capture(
}
}
b_btree_iterator s_it;
b_btree_iterator_begin(&ctx.ctx_strings.s_offset_tree, &s_it);
while (b_btree_iterator_is_valid(&s_it)) {
struct string_table_entry *entry = b_unbox(
struct string_table_entry,
s_it.node,
e_offset_node);
size_t len = strlen(entry->e_str) + 1;
size_t nr_written = 0;
status = ec3_tag_ioctx_write(
stab,
entry->e_str,
len,
&nr_written);
b_btree_iterator_next(&s_it);
}
string_table_finish(&ctx.ctx_strings);
chunk_table_finish(&ctx.ctx_chunks);
ec3_tag_ioctx_close(stab);
ec3_tag_ioctx_close(ctab);
ec3_tag_ioctx_close(cdat);
ec3_image_ioctx_close(image);
ec3_image_builder_destroy(image);
return 0;
}

View File

@@ -1,250 +1,461 @@
#if 0
#include "b-tree.h"
#include "bin.h"
#include "builder.h"
#include "commands.h"
#include "exe.h"
#include "image.h"
#include "substitute.h"
#include <blue/cmd.h>
#include <blue/io/file.h>
#include <blue/io/path.h>
#include <blue/object/dict.h>
#include <blue/object/number.h>
#include <blue/object/string.h>
#include <blue/serial.h>
#include <blue/term/print.h>
#include <errno.h>
#include <inttypes.h>
#include <stdio.h>
#include <stdlib.h>
#include <zstd.h>
#define INVALID_NODE_PTR 0xFFFF
#define ORDER 6
#define MAX (ORDER - 1)
#define MIN (MAX / 2)
enum {
ARG_INPATH,
OPT_SPECIFICATION,
OPT_SPECIFICATION_PATH,
OPT_PARAMETER,
OPT_PARAMETER_NAME,
OPT_PARAMETER_VALUE,
OPT_OUTPATH,
OPT_OUTPATH_PATH,
};
struct entry {
uint32_t key;
uint32_t value;
struct create_ctx {
struct ec3_image_builder *ctx_builder;
struct substitution_list ctx_sub_list;
b_dict *ctx_specification;
};
struct node {
uint16_t nr_entries;
struct entry entries[MAX];
uint16_t children[ORDER];
};
struct data_tree {
struct b_tree base;
FILE *fp;
};
static int node_init(struct node *n)
static enum ec3_status create_ctx_init(
struct create_ctx *ctx,
const b_arglist *args)
{
memset(n, 0x0, sizeof *n);
enum ec3_status status = substitution_list_init(&ctx->ctx_sub_list);
for (int i = 0; i < ORDER; i++) {
n->children[i] = INVALID_NODE_PTR;
}
return 0;
}
static int tree_get_node(struct b_tree *p, unsigned long id, b_tree_node *n)
b_arglist_option_iterator it;
b_arglist_option_foreach_filtered(&it, args, OPT_PARAMETER)
{
struct data_tree *tree = (struct data_tree *)p;
size_t offset = (id * sizeof(struct node));
fseek(tree->fp, offset, SEEK_SET);
size_t r = fread(n, sizeof(struct node), 1, tree->fp);
return r == 1 ? 0 : -1;
b_arglist_value *name, *value;
b_arglist_option_get_value(
it.opt,
OPT_PARAMETER_NAME,
0,
&name);
b_arglist_option_get_value(
it.opt,
OPT_PARAMETER_VALUE,
0,
&value);
status = substitution_list_add_substitution(
&ctx->ctx_sub_list,
name->val_str,
value->val_str);
if (status != EC3_SUCCESS) {
return status;
}
}
static int tree_put_node(
struct b_tree *p,
unsigned long id,
const b_tree_node *n)
return EC3_SUCCESS;
}
static void create_ctx_finish(struct create_ctx *ctx)
{
struct data_tree *tree = (struct data_tree *)p;
size_t offset = (id * sizeof(struct node));
fseek(tree->fp, offset, SEEK_SET);
size_t r = fwrite(n, sizeof(struct node), 1, tree->fp);
return r == 1 ? 0 : -1;
if (ctx->ctx_builder) {
ec3_image_builder_destroy(ctx->ctx_builder);
}
static long tree_alloc_node(struct b_tree *p)
if (ctx->ctx_specification) {
b_dict_release(ctx->ctx_specification);
}
substitution_list_finish(&ctx->ctx_sub_list);
}
static enum ec3_status configure_image_parameters(
struct create_ctx *ctx,
struct ec3_parameters *param)
{
struct data_tree *tree = (struct data_tree *)p;
size_t pos = ftell(tree->fp);
fseek(tree->fp, 0, SEEK_END);
size_t len = ftell(tree->fp);
enum ec3_status status = EC3_SUCCESS;
struct node n;
node_init(&n);
fwrite(&n, sizeof n, 1, tree->fp);
fseek(tree->fp, pos, SEEK_SET);
len /= sizeof(struct node);
return (long)len;
b_string *ident = B_STRING(b_dict_at(ctx->ctx_specification, "id"));
if (ident) {
if (B_TYPEID(ident) != B_OBJECT_TYPE_STRING) {
return EC3_ERR_BAD_FORMAT;
}
static unsigned long node_get_nr_entries(b_tree_node *n)
status = substitution_list_substitute(
&ctx->ctx_sub_list,
ident);
if (status != EC3_SUCCESS) {
return status;
}
status = ec3_identifier_from_string(
b_string_ptr(ident),
&param->p_ident);
if (status != EC3_SUCCESS) {
return status;
}
}
b_number *cluster_size_p
= B_NUMBER(b_dict_at(ctx->ctx_specification, "clusterSize"));
if (B_TYPEID(cluster_size_p) != B_OBJECT_TYPE_NUMBER) {
return EC3_ERR_BAD_FORMAT;
}
param->p_cluster_size = ec3_cluster_size_bytes_to_id(
b_number_get_int(cluster_size_p));
if (param->p_cluster_size == -1) {
return EC3_ERR_NOT_SUPPORTED;
}
b_string *compression_p
= B_STRING(b_dict_at(ctx->ctx_specification, "compression"));
const char *compression = NULL;
if (compression_p) {
if (B_TYPEID(compression_p) != B_OBJECT_TYPE_STRING) {
return EC3_ERR_BAD_FORMAT;
}
compression = b_string_ptr(compression_p);
if (!strcmp(compression, "zstd")) {
param->p_compression_func = EC3_COMPRESSION_ZSTD;
} else {
return EC3_ERR_NOT_SUPPORTED;
}
}
b_string *encryption_p
= B_STRING(b_dict_at(ctx->ctx_specification, "encryption"));
const char *encryption = NULL;
if (encryption_p) {
if (B_TYPEID(encryption_p) != B_OBJECT_TYPE_STRING) {
return EC3_ERR_BAD_FORMAT;
}
encryption = b_string_ptr(encryption_p);
if (!strcmp(encryption, "aes256")) {
param->p_compression_func = EC3_ENCRYPTION_AES256;
} else {
return EC3_ERR_NOT_SUPPORTED;
}
}
return EC3_SUCCESS;
}
static b_status read_specification(const char *path_cstr, b_dict **out)
{
struct node *node = (struct node *)n;
return node->nr_entries;
b_path *path = b_path_create_from_cstr(path_cstr);
b_file *file = NULL;
b_status status = b_file_open(NULL, path, B_FILE_READ_ONLY, &file);
b_path_release(path);
if (!B_OK(status)) {
return status;
}
static void node_set_nr_entries(b_tree_node *n, unsigned long val)
b_stream *src = NULL;
status = b_file_open_stream(file, &src);
b_file_release(file);
if (!B_OK(status)) {
return status;
}
b_serial_ctx *ctx = NULL;
b_serial_ctx_create(&ctx);
b_object *data = NULL;
status = b_serial_ctx_deserialise(
ctx,
B_SERIAL_FORMAT_JSON,
src,
&data,
0);
if (!B_OK(status)) {
return status;
}
b_stream_close(src);
if (!B_OBJECT_IS(data, DICT)) {
b_release(data);
return B_ERR_BAD_FORMAT;
}
*out = B_DICT(data);
return B_SUCCESS;
}
#define ASSERT_OBJECT(object, status) \
if (!object) { \
return status; \
}
#define ASSERT_OBJECT_TYPE(object, type, status) \
if (!B_OBJECT_IS(object, type)) { \
return status; \
}
static enum ec3_status capture_volumes(struct create_ctx *ctx)
{
struct node *node = (struct node *)n;
node->nr_entries = val;
enum ec3_status status = EC3_SUCCESS;
b_array *volumes
= B_ARRAY(b_dict_at(ctx->ctx_specification, "volumes"));
if (!volumes) {
return EC3_SUCCESS;
}
static b_tree_node_entry *node_get_entry(b_tree_node *n, unsigned long index)
ASSERT_OBJECT_TYPE(volumes, ARRAY, EC3_ERR_BAD_FORMAT);
b_array_iterator it;
b_array_foreach(&it, volumes)
{
struct node *node = (struct node *)n;
return (b_tree_node_entry *)&node->entries[index];
b_dict *volume = B_DICT(it.value);
ASSERT_OBJECT_TYPE(volume, DICT, EC3_ERR_BAD_FORMAT);
uint64_t id = 0;
b_object *id_object = b_dict_at(volume, "id");
ASSERT_OBJECT(id_object, EC3_ERR_BAD_FORMAT);
if (B_OBJECT_IS(id_object, NUMBER)) {
id = (uint64_t)b_number_get_int64(B_NUMBER(id_object));
} else if (B_OBJECT_IS(id_object, STRING)) {
substitution_list_substitute(
&ctx->ctx_sub_list,
B_STRING(id_object));
status = ec3_identifier_from_string(
b_string_ptr(B_STRING(id_object)),
&id);
}
static void node_set_entry(
b_tree_node *n,
unsigned long index,
const b_tree_node_entry *entry)
if (status != EC3_SUCCESS) {
return status;
}
b_string *src_path = B_STRING(b_dict_at(volume, "sourcePath"));
ASSERT_OBJECT(src_path, EC3_ERR_BAD_FORMAT);
ASSERT_OBJECT_TYPE(src_path, STRING, EC3_ERR_BAD_FORMAT);
substitution_list_substitute(&ctx->ctx_sub_list, src_path);
char id_str[32];
ec3_identifier_to_string(id, id_str, sizeof id_str);
printf("adding volume 0x%" PRIx64 "(%s) -> %s\n",
id,
id_str,
b_string_ptr(src_path));
status = ec3_image_builder_capture_directory(
ctx->ctx_builder,
id,
b_string_ptr(src_path));
if (status != EC3_SUCCESS) {
b_err("cannot capture directory '%s'",
b_string_ptr(src_path));
b_i("reason: %s", ec3_status_to_string(status));
return status;
}
}
return EC3_SUCCESS;
}
static enum ec3_status capture_blobs(struct create_ctx *ctx)
{
struct node *node = (struct node *)n;
memmove(&node->entries[index], entry, sizeof(struct entry));
enum ec3_status status = EC3_SUCCESS;
b_array *blobs = B_ARRAY(b_dict_at(ctx->ctx_specification, "blobs"));
if (!blobs) {
return EC3_SUCCESS;
}
static unsigned long node_get_child(b_tree_node *n, unsigned long index)
ASSERT_OBJECT_TYPE(blobs, ARRAY, EC3_ERR_BAD_FORMAT);
b_array_iterator it;
b_array_foreach(&it, blobs)
{
struct node *node = (struct node *)n;
uint16_t child = node->children[index];
return child == INVALID_NODE_PTR ? B_TREE_INVALID_PTR : child;
b_dict *blob = B_DICT(it.value);
ASSERT_OBJECT_TYPE(blob, DICT, EC3_ERR_BAD_FORMAT);
uint64_t id = 0;
b_object *id_object = b_dict_at(blob, "id");
if (!id_object) {
return EC3_ERR_BAD_FORMAT;
}
static void node_set_child(
b_tree_node *n,
unsigned long index,
unsigned long ptr)
if (B_OBJECT_IS(id_object, NUMBER)) {
id = (uint64_t)b_number_get_int64(B_NUMBER(id_object));
} else if (B_OBJECT_IS(id_object, STRING)) {
substitution_list_substitute(
&ctx->ctx_sub_list,
B_STRING(id_object));
status = ec3_identifier_from_string(
b_string_ptr(B_STRING(id_object)),
&id);
}
if (status != EC3_SUCCESS) {
return status;
}
b_string *src_path = B_STRING(b_dict_at(blob, "sourcePath"));
ASSERT_OBJECT(src_path, EC3_ERR_BAD_FORMAT);
ASSERT_OBJECT_TYPE(src_path, STRING, EC3_ERR_BAD_FORMAT);
substitution_list_substitute(&ctx->ctx_sub_list, src_path);
char id_str[32];
ec3_identifier_to_string(id, id_str, sizeof id_str);
printf("adding blob 0x%" PRIx64 "(%s) -> %s\n",
id,
id_str,
b_string_ptr(src_path));
FILE *fp = fopen(b_string_ptr(src_path), "rb");
if (!fp) {
b_err("cannot open file '%s'", b_string_ptr(src_path));
b_i("reason: %s", strerror(errno));
return EC3_ERR_NO_ENTRY;
}
status = ec3_image_builder_add_blob_from_file(
ctx->ctx_builder,
id,
fp);
fclose(fp);
if (status != EC3_SUCCESS) {
b_err("cannot capture blob '%s'",
b_string_ptr(src_path));
b_i("reason: %s", ec3_status_to_string(status));
return status;
}
}
return EC3_SUCCESS;
}
static enum ec3_executable_format executable_format_string_to_id(const char *s)
{
struct node *node = (struct node *)n;
uint16_t child
= ptr == B_TREE_INVALID_PTR ? INVALID_NODE_PTR : (uint16_t)ptr;
node->children[index] = child;
if (!strcmp(s, "elf")) {
return EC3_EXEC_ELF;
}
static int entry_compare(
const b_tree_node_entry *e0,
const b_tree_node_entry *e1)
return EC3_EXEC_OTHER;
}
static enum ec3_status capture_executables(struct create_ctx *ctx)
{
struct entry *a = (struct entry *)e0, *b = (struct entry *)e1;
enum ec3_status status = EC3_SUCCESS;
if (a->key < b->key) {
return -1;
b_array *executables
= B_ARRAY(b_dict_at(ctx->ctx_specification, "executables"));
if (!executables) {
return EC3_SUCCESS;
}
if (a->key > b->key) {
return 1;
}
ASSERT_OBJECT_TYPE(executables, ARRAY, EC3_ERR_BAD_FORMAT);
return 0;
}
static const struct b_tree_ops ops = {
.tree_get_node = tree_get_node,
.tree_put_node = tree_put_node,
.tree_alloc_node = tree_alloc_node,
.node_get_nr_entries = node_get_nr_entries,
.node_set_nr_entries = node_set_nr_entries,
.node_get_entry = node_get_entry,
.node_set_entry = node_set_entry,
.node_get_child = node_get_child,
.node_set_child = node_set_child,
.entry_compare = entry_compare,
};
void indent(int depth)
b_array_iterator it;
b_array_foreach(&it, executables)
{
for (int i = 0; i < depth; i++) {
fputs(" ", stdout);
b_dict *executable = B_DICT(it.value);
ASSERT_OBJECT_TYPE(executable, DICT, EC3_ERR_BAD_FORMAT);
uint64_t id = 0;
b_object *id_object = b_dict_at(executable, "id");
if (!id_object) {
return EC3_ERR_BAD_FORMAT;
}
if (B_OBJECT_IS(id_object, NUMBER)) {
id = (uint64_t)b_number_get_int64(B_NUMBER(id_object));
} else if (B_OBJECT_IS(id_object, STRING)) {
substitution_list_substitute(
&ctx->ctx_sub_list,
B_STRING(id_object));
status = ec3_identifier_from_string(
b_string_ptr(B_STRING(id_object)),
&id);
}
if (status != EC3_SUCCESS) {
return status;
}
b_string *src_path
= B_STRING(b_dict_at(executable, "sourcePath"));
ASSERT_OBJECT(src_path, EC3_ERR_BAD_FORMAT);
ASSERT_OBJECT_TYPE(src_path, STRING, EC3_ERR_BAD_FORMAT);
substitution_list_substitute(&ctx->ctx_sub_list, src_path);
b_string *format = B_STRING(b_dict_at(executable, "format"));
ASSERT_OBJECT(format, EC3_ERR_BAD_FORMAT);
ASSERT_OBJECT_TYPE(format, STRING, EC3_ERR_BAD_FORMAT);
substitution_list_substitute(&ctx->ctx_sub_list, format);
b_string_tolower(format);
char id_str[32];
ec3_identifier_to_string(id, id_str, sizeof id_str);
printf("adding %s executable 0x%" PRIx64 "(%s) -> %s\n",
b_string_ptr(format),
id,
id_str,
b_string_ptr(src_path));
FILE *fp = fopen(b_string_ptr(src_path), "rb");
if (!fp) {
b_err("cannot open file '%s'", b_string_ptr(src_path));
b_i("reason: %s", strerror(errno));
return EC3_ERR_NO_ENTRY;
}
enum ec3_executable_format exe_format
= executable_format_string_to_id(b_string_ptr(format));
struct ec3_tag_executable_info exe_info = {0};
status = get_executable_info_from_file(
fp,
exe_format,
&exe_info);
if (status != EC3_SUCCESS) {
return status;
}
fseek(fp, 0, SEEK_SET);
status = ec3_image_builder_add_executable_from_file(
ctx->ctx_builder,
id,
&exe_info,
fp);
fclose(fp);
if (status != EC3_SUCCESS) {
b_err("cannot capture executable '%s'",
b_string_ptr(src_path));
b_i("reason: %s", ec3_status_to_string(status));
return status;
}
}
int node_print(struct b_tree *tree, struct node *n, int depth)
{
int c_before = (n->nr_entries + 1) / 2;
int c_after = n->nr_entries + 1 - c_before;
int i_before = 0;
int i_after = i_before + c_before;
int err = 0;
for (unsigned short i = 0; i < c_before; i++) {
struct node child;
int index = i_before + i;
if (n->children[index] == INVALID_NODE_PTR) {
// indent(depth + 1);
continue;
}
err = tree_get_node(
tree,
n->children[index],
(b_tree_node *)&child);
if (err != 0) {
printf("ERR: failed to read node %u\n",
n->children[index]);
continue;
}
node_print(tree, &child, depth + 1);
}
indent(depth);
printf("[");
for (unsigned short i = 0; i < n->nr_entries; i++) {
if (i > 0) {
printf(" ");
}
printf("%d", n->entries[i].key);
}
printf("]\n");
for (unsigned short i = 0; i < c_after; i++) {
struct node child;
int index = i_after + i;
if (n->children[index] == INVALID_NODE_PTR) {
// indent(depth + 1);
continue;
}
err = tree_get_node(
tree,
n->children[index],
(b_tree_node *)&child);
if (err != 0) {
printf("ERR: failed to read node %u\n",
n->children[index]);
continue;
}
node_print(tree, &child, depth + 1);
}
return 0;
}
int tree_print(struct b_tree *tree)
{
struct node root;
tree_get_node(tree, 0, (b_tree_node *)&root);
return node_print(tree, &root, 0);
return EC3_SUCCESS;
}
static int create(
@@ -252,48 +463,74 @@ static int create(
const b_arglist *opt,
const b_array *args)
{
printf("%zu\n", sizeof(struct ec3_cluster_group));
return 0;
const char *in_path = NULL, *out_path = NULL;
b_arglist_get_string(
const char *out_path_cstr = NULL;
const char *specification_path_cstr = NULL;
b_status status = b_arglist_get_string(
opt,
B_COMMAND_INVALID_ID,
ARG_INPATH,
OPT_SPECIFICATION,
OPT_SPECIFICATION_PATH,
0,
&in_path);
b_arglist_get_string(opt, OPT_OUTPATH, OPT_OUTPATH_PATH, 0, &out_path);
printf("in path: %s\n", in_path);
printf("out path: %s\n", out_path);
FILE *fp = fopen(out_path, "w+b");
struct node root;
node_init(&root);
fwrite(&root, sizeof root, 1, fp);
struct data_tree tree;
b_tree_init(
&tree.base,
&ops,
sizeof(struct node),
sizeof(struct entry),
ORDER);
tree.fp = fp;
for (int i = 1; i <= 32; i++) {
int key = rand() % 65535;
// int key = i;
// printf("%d: adding [%d]\n", i, key);
struct entry e = {.key = key, .value = key * 2};
b_tree_put(&tree.base, (b_tree_node_entry *)&e);
&specification_path_cstr);
if (!B_OK(status)) {
b_err("no specification file specified\n");
return -1;
}
tree_print(&tree.base);
status = b_arglist_get_string(
opt,
OPT_OUTPATH,
OPT_OUTPATH_PATH,
0,
&out_path_cstr);
if (!B_OK(status)) {
b_err("no output file path specified\n");
return -1;
}
fclose(fp);
struct create_ctx ctx = {0};
enum ec3_status status2 = create_ctx_init(&ctx, opt);
status = read_specification(
specification_path_cstr,
&ctx.ctx_specification);
if (!B_OK(status)) {
b_err("cannot read specification file.");
b_i("reason: %s", b_status_to_string(status));
return -1;
}
struct ec3_parameters param = {};
status2 = configure_image_parameters(&ctx, &param);
if (status2 != EC3_SUCCESS) {
return -1;
}
status2 = ec3_image_builder_create(
out_path_cstr,
&param,
&ctx.ctx_builder);
if (status2 != EC3_SUCCESS) {
b_err("cannot initialise EC3 writer");
return -1;
}
status2 = capture_volumes(&ctx);
if (status2 != EC3_SUCCESS) {
return -1;
}
status2 = capture_blobs(&ctx);
if (status2 != EC3_SUCCESS) {
return -1;
}
status2 = capture_executables(&ctx);
if (status2 != EC3_SUCCESS) {
return -1;
}
create_ctx_finish(&ctx);
return 0;
}
@@ -320,16 +557,50 @@ B_COMMAND(CMD_CREATE, CMD_ROOT)
}
}
B_COMMAND_ARG(ARG_INPATH)
B_COMMAND_OPTION(OPT_SPECIFICATION)
{
B_ARG_NAME("input file");
B_OPTION_SHORT_NAME('s');
B_OPTION_LONG_NAME("specification");
B_OPTION_DESC(
"the path to a specification file describing the "
"layout and parameters of the new file");
B_OPTION_ARG(OPT_SPECIFICATION_PATH)
{
B_ARG_NAME("path");
B_ARG_NR_VALUES(1);
}
}
B_COMMAND_OPTION(OPT_PARAMETER)
{
B_OPTION_SHORT_NAME('p');
B_OPTION_LONG_NAME("parameter");
B_OPTION_DESC("a parameter to use when creating the new file.");
B_OPTION_ARG(OPT_PARAMETER_NAME)
{
B_ARG_NAME("name");
B_ARG_NR_VALUES(1);
}
B_OPTION_ARG(OPT_PARAMETER_VALUE)
{
B_ARG_NAME("value");
B_ARG_NR_VALUES(1);
}
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_ARG(ARG_INPATH);
B_COMMAND_USAGE_OPT(OPT_SPECIFICATION);
B_COMMAND_USAGE_OPT(OPT_OUTPATH);
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_OPT(OPT_SPECIFICATION);
B_COMMAND_USAGE_OPT(OPT_PARAMETER);
B_COMMAND_USAGE_OPT(OPT_OUTPATH);
}
}
#endif

284
src/elf.h Normal file
View File

@@ -0,0 +1,284 @@
#ifndef ELF_H_
#define ELF_H_
#include <stddef.h>
#include <stdint.h>
#define ELF_MAG0 0x7f
#define ELF_MAG1 'E'
#define ELF_MAG2 'L'
#define ELF_MAG3 'F'
#define ELF_NIDENT 16
#define SHT_NONE 0
#define SHT_PROGBITS 1
#define SHT_SYMTAB 2
#define SHT_STRTAB 3
#define SHT_RELA 4
#define SHT_DYNAMIC 6
#define SHT_NOBITS 8
#define SHT_REL 9
#define SHT_DYNSYM 11
/** Little endian. */
#define ELFDATA2LSB (1)
/** 64-bit. */
#define ELFCLASS64 (2)
#define EM_386 (3)
#define EM_X86_64 (62)
/** ELF current version. */
#define EV_CURRENT (1)
/** Dynamic section tags. */
#define DT_NULL 0
#define DT_NEEDED 1
#define DT_PLTRELSZ 2
#define DT_PLTGOT 3
#define DT_HASH 4
#define DT_STRTAB 5
#define DT_SYMTAB 6
#define DT_RELA 7
#define DT_RELASZ 8
#define DT_RELAENT 9
#define DT_STRSZ 10
#define DT_SYMENT 11
#define DT_INIT 12
#define DT_FINI 13
#define DT_REL 17
#define DT_RELSZ 18
#define DT_RELENT 19
#define DT_PLTREL 20
#define DT_JMPREL 23
#define DT_GNU_HASH 0x6ffffef5
#define DT_AUXILIARY 0x7ffffffd
#define R_386_32 1
#define R_386_PC32 2
#define R_386_GOT32 3
#define R_386_PLT32 4
#define R_386_GOTOFF 9
#define R_386_GOTPC 10
#define R_386_GOT32X 43
#define R_X86_64_64 1
#define R_X86_64_PC32 2
#define R_X86_64_GOT32 3
#define R_X86_64_PLT32 4
#define R_X86_64_COPY 5
#define R_X86_64_GLOB_DAT 6
#define R_X86_64_JUMP_SLOT 7
#define R_X86_64_RELATIVE 8
#define R_X86_64_GOTPCREL 9
#define R_X86_64_32 10
#define STT_NOTYPE 0
#define STT_OBJECT 1
#define STT_FUNC 2
#define STT_SECTION 3
#define STT_FILE 4
#define STT_LOPROC 13
#define STT_HIPROC 15
/* Section flags */
#define SHF_WRITE 0x1
#define SHF_ALLOC 0x2
#define SHF_EXECINSTR 0x4
#define SHN_UNDEF 0
#define ELF64_R_SYM(i) ((i) >> 32)
#define ELF64_R_TYPE(i) ((elf_word_t)(i))
#define ELF64_ST_BIND(i) ((i) >> 4)
#define ELF64_ST_TYPE(i) ((i) & 0xf)
#define STB_LOCAL 0
#define STB_GLOBAL 1
#define STB_WEAK 2
#define STB_NUM 3
typedef uint64_t elf_addr_t;
typedef uint64_t elf_off_t;
typedef uint16_t elf_half_t;
typedef uint32_t elf_word_t;
typedef int32_t elf_sword_t;
typedef uint64_t elf_xword_t;
typedef int64_t elf_sxword_t;
/**
* ELF file header.
*/
typedef struct {
uint8_t e_ident[ELF_NIDENT];
elf_half_t e_type;
elf_half_t e_machine;
elf_word_t e_version;
elf_addr_t e_entry;
elf_off_t e_phoff;
elf_off_t e_shoff;
elf_word_t e_flags;
elf_half_t e_ehsize;
elf_half_t e_phentsize;
elf_half_t e_phnum;
elf_half_t e_shentsize;
elf_half_t e_shnum;
elf_half_t e_shstrndx;
} elf_ehdr_t;
/**
* ELF section header.
*/
typedef struct {
elf_word_t sh_name;
elf_word_t sh_type;
elf_xword_t sh_flags;
elf_addr_t sh_addr;
elf_off_t sh_offset;
elf_xword_t sh_size;
elf_word_t sh_link;
elf_word_t sh_info;
elf_xword_t sh_addralign;
elf_xword_t sh_entsize;
} elf_shdr_t;
/**
* ELF symbol.
*/
typedef struct {
elf_word_t st_name;
unsigned char st_info;
unsigned char st_other;
elf_half_t st_shndx;
elf_addr_t st_value;
elf_xword_t st_size;
} elf_sym_t;
/**
* ELF program header.
*/
typedef struct {
elf_word_t p_type;
elf_word_t p_flags;
elf_off_t p_offset;
elf_addr_t p_vaddr;
elf_addr_t p_paddr;
elf_xword_t p_filesz;
elf_xword_t p_memsz;
elf_xword_t p_align;
} elf_phdr_t;
/**
* Extended ELF relocation information.
*/
typedef struct {
elf_addr_t r_offset;
elf_xword_t r_info;
elf_sxword_t r_addend;
} elf_rela_t;
/**
* Dynamic section entries
*/
typedef struct {
elf_sxword_t d_tag;
union {
elf_xword_t d_val;
elf_addr_t d_ptr;
} d_un;
} elf_dyn_t;
/**
* Section header types.
*/
enum elf_stype {
ST_NONE = 0,
ST_PROGBITS = 1,
ST_SYMTAB = 2,
ST_STRTAB = 3,
ST_NOBITS = 8,
ST_REL = 9
};
/**
* Program header types.
*/
enum elf_ptype {
PT_NULL = 0,
PT_LOAD = 1,
PT_DYNAMIC = 2,
PT_INTERP = 3,
PT_NOTE = 4,
PT_SHLIB = 5,
PT_PHDR = 6,
PT_TLS = 7,
};
#define PF_X 0x1
#define PF_W 0x2
#define PF_R 0x4
#define PT_LOPROC 0x70000000
#define PT_HIPROC 0x7FFFFFFF
/**
* ELF identification byte locations.
*/
enum elf_ident {
EI_MAG0 = 0,
EI_MAG1 = 1,
EI_MAG2 = 2,
EI_MAG3 = 3,
EI_CLASS = 4,
EI_DATA = 5,
EI_VERSION = 6,
EI_OSABI = 7,
EI_ABIVERSION = 8,
EI_PAD = 9
};
enum elf_type {
ET_NONE = 0,
ET_REL = 1,
ET_EXEC = 2,
ET_DYN = 3,
};
#define AT_NULL 0
#define AT_IGNORE 1
#define AT_EXECFD 2
#define AT_PHDR 3
#define AT_PHENT 4
#define AT_PHNUM 5
#define AT_PAGESZ 6
#define AT_BASE 7
#define AT_FLAGS 8
#define AT_ENTRY 9
#define AT_NOTELF 10
#define AT_UID 11
#define AT_EUID 12
#define AT_GID 13
#define AT_EGID 14
#define AT_CLKTCK 17
#define AT_PLATFORM 15
#define AT_HWCAP 16
#define AT_FPUCW 18
#define AT_DCACHEBSIZE 19
#define AT_ICACHEBSIZE 20
#define AT_UCACHEBSIZE 21
#define AT_IGNOREPPC 22
#define AT_SECURE 23
#define AT_BASE_PLATFORM 24
#define AT_RANDOM 25
#define AT_HWCAP2 26
#define AT_EXECFN 31
#define AT_SYSINFO 32
#define AT_SYSINFO_EHDR 33
#define AT_L1I_CACHESHAPE 34
#define AT_L1D_CACHESHAPE 35
#define AT_L2_CACHESHAPE 36
#define AT_L3_CACHESHAPE 37
#define AT_ENTRY_COUNT 38
#endif

79
src/exe.c Normal file
View File

@@ -0,0 +1,79 @@
#include "exe.h"
#include "elf.h"
static enum ec3_status get_elf_executable_info(
FILE *fp,
struct ec3_tag_executable_info *out)
{
elf_ehdr_t hdr;
fseek(fp, 0, SEEK_SET);
size_t r = fread(&hdr, sizeof hdr, 1, fp);
if (r != 1) {
return EC3_ERR_IO_FAILURE;
}
out->exe_elf.elf_entry = hdr.e_entry;
bool text_found = false, data_found = false;
for (size_t i = 0; i < hdr.e_phnum; i++) {
elf_phdr_t phdr;
size_t offset = hdr.e_phoff + (i * hdr.e_phentsize);
fseek(fp, offset, SEEK_SET);
r = fread(&phdr, sizeof phdr, 1, fp);
if (r != 1) {
return EC3_ERR_IO_FAILURE;
}
if (phdr.p_type != PT_LOAD) {
continue;
}
if ((phdr.p_flags & (PF_R | PF_X)) == (PF_R | PF_X)) {
if (text_found) {
out->exe_format = EC3_EXEC_OTHER;
return EC3_SUCCESS;
}
out->exe_elf.elf_text_offset = phdr.p_offset;
out->exe_elf.elf_text_filesz = phdr.p_filesz;
out->exe_elf.elf_text_vaddr = phdr.p_vaddr;
out->exe_elf.elf_text_memsz = phdr.p_memsz;
out->exe_elf.elf_text_align = phdr.p_align;
text_found = true;
}
if ((phdr.p_flags & (PF_R | PF_W)) == (PF_R | PF_W)) {
if (data_found) {
out->exe_format = EC3_EXEC_OTHER;
return EC3_SUCCESS;
}
out->exe_elf.elf_data_offset = phdr.p_offset;
out->exe_elf.elf_data_filesz = phdr.p_filesz;
out->exe_elf.elf_data_vaddr = phdr.p_vaddr;
out->exe_elf.elf_data_memsz = phdr.p_memsz;
out->exe_elf.elf_data_align = phdr.p_align;
data_found = true;
}
}
return EC3_SUCCESS;
}
enum ec3_status get_executable_info_from_file(
FILE *fp,
enum ec3_executable_format format,
struct ec3_tag_executable_info *out)
{
out->exe_format = format;
switch (format) {
case EC3_EXEC_ELF:
return get_elf_executable_info(fp, out);
default:
return EC3_SUCCESS;
}
}

13
src/exe.h Normal file
View File

@@ -0,0 +1,13 @@
#ifndef EXE_H_
#define EXE_H_
#include "tag.h"
#include <stdio.h>
extern enum ec3_status get_executable_info_from_file(
FILE *fp,
enum ec3_executable_format format,
struct ec3_tag_executable_info *out);
#endif

View File

@@ -47,6 +47,43 @@ static enum ec3_status decode_header(
return EC3_SUCCESS;
}
static void decode_tag_executable_info(
const struct ec3_executable *in,
struct ec3_tag_executable_info *out)
{
out->exe_format = b_i16_btoh(in->exe_format);
switch (out->exe_format) {
case EC3_EXEC_ELF:
out->exe_elf.elf_data_offset
= b_i32_btoh(in->exe_elf.elf_data_offset);
out->exe_elf.elf_data_filesz
= b_i32_btoh(in->exe_elf.elf_data_filesz);
out->exe_elf.elf_data_memsz
= b_i32_btoh(in->exe_elf.elf_data_memsz);
out->exe_elf.elf_data_align
= b_i32_btoh(in->exe_elf.elf_data_align);
out->exe_elf.elf_text_offset
= b_i32_btoh(in->exe_elf.elf_text_offset);
out->exe_elf.elf_text_filesz
= b_i32_btoh(in->exe_elf.elf_text_filesz);
out->exe_elf.elf_text_memsz
= b_i32_btoh(in->exe_elf.elf_text_memsz);
out->exe_elf.elf_text_align
= b_i32_btoh(in->exe_elf.elf_text_align);
out->exe_elf.elf_data_vaddr
= b_i64_btoh(in->exe_elf.elf_data_vaddr);
out->exe_elf.elf_text_vaddr
= b_i64_btoh(in->exe_elf.elf_text_vaddr);
out->exe_elf.elf_entry = b_i64_btoh(in->exe_elf.elf_entry);
break;
default:
break;
}
}
static void decode_tag(
const struct ec3_tag_table_entry *in,
struct ec3_tag_info *out)
@@ -56,6 +93,10 @@ static void decode_tag(
out->tag_checksum = b_i32_btoh(in->tag_checksum);
out->tag_ident = b_i64_btoh(in->tag_ident);
out->tag_total_length = b_i64_btoh(in->tag_length);
if (out->tag_type) {
decode_tag_executable_info(&in->tag_exe, &out->tag_exe);
}
}
static void decode_extent(
@@ -179,6 +220,12 @@ static enum ec3_status create_ioctx(struct ec3_image_ioctx **out)
return EC3_SUCCESS;
}
static struct ec3_tag_info *image_ioctx_get_tag_info(
struct ec3_image_ioctx *image)
{
return b_buffer_ptr(image->io_tag_table);
}
static enum ec3_status open_image_ro(
b_path *image_path,
enum ec3_image_ioctx_mode mode,
@@ -430,7 +477,7 @@ enum ec3_status ec3_image_ioctx_close(struct ec3_image_ioctx *image)
return status;
}
const struct ec3_tag_info *tags = ec3_image_ioctx_get_tag_info(image);
struct ec3_tag_info *tags = image_ioctx_get_tag_info(image);
size_t nr_tags = image->io_header.img_nr_tags;
/* first set of tags to write are those that haven't been opened,
@@ -461,7 +508,7 @@ enum ec3_status ec3_image_ioctx_close(struct ec3_image_ioctx *image)
* read into memory, encoded, and written to the dest image
*/
for (size_t i = 0; i < nr_tags; i++) {
const struct ec3_tag_info *tag = &tags[i];
struct ec3_tag_info *tag = &tags[i];
struct ec3_tag_ioctx *tag_io = get_opened_tag(
&image->io_opened_tags,
@@ -478,6 +525,12 @@ enum ec3_status ec3_image_ioctx_close(struct ec3_image_ioctx *image)
continue;
}
if (tag->tag_type == EC3_TAG_EXEC) {
memcpy(&tag->tag_exe,
&tag_io->io_tag_info.tag_exe,
sizeof tag->tag_exe);
}
status = shadow_image_write_tag(image, tag, tag_io, &shadow);
if (status != EC3_SUCCESS) {
shadow_image_cancel(&shadow);
@@ -494,7 +547,7 @@ enum ec3_status ec3_image_ioctx_close(struct ec3_image_ioctx *image)
* the tag's cluster table with that of the dest image
*/
for (size_t i = 0; i < nr_tags; i++) {
const struct ec3_tag_info *tag = &tags[i];
struct ec3_tag_info *tag = &tags[i];
struct ec3_tag_ioctx *tag_io = get_opened_tag(
&image->io_opened_tags,
@@ -511,6 +564,12 @@ enum ec3_status ec3_image_ioctx_close(struct ec3_image_ioctx *image)
continue;
}
if (tag->tag_type == EC3_TAG_EXEC) {
memcpy(&tag->tag_exe,
&tag_io->io_tag_info.tag_exe,
sizeof tag->tag_exe);
}
status = shadow_image_write_tag(image, tag, tag_io, &shadow);
if (status != EC3_SUCCESS) {
shadow_image_cancel(&shadow);
@@ -586,7 +645,7 @@ static const struct ec3_tag_info *get_tag_info_by_id(
const struct ec3_tag_info *ec3_image_ioctx_get_tag_info(
struct ec3_image_ioctx *image)
{
return b_buffer_ptr(image->io_tag_table);
return image_ioctx_get_tag_info(image);
}
const struct ec3_tag_info *ec3_image_ioctx_get_tag_info_by_id(

View File

@@ -12,6 +12,7 @@
#include <blue/term.h>
#include <ctype.h>
#include <errno.h>
#include <inttypes.h>
#include <stdlib.h>
enum {
@@ -131,6 +132,52 @@ static void print_tag_info(struct ec3_image_ioctx *image)
printf(" %-8s: %llu bytes\n",
"size",
tags[i].tag_total_length);
if (tags[i].tag_type != EC3_TAG_EXEC) {
continue;
}
printf(" %-8s: ", "exec");
const struct ec3_tag_executable_info *exec = &tags[i].tag_exe;
switch (exec->exe_format) {
case EC3_EXEC_ELF:
printf("ELF\n");
printf(" entry = [%06" PRIx64 "]\n",
exec->exe_elf.elf_entry);
printf(" text = [0x%06" PRIx32
"-0x%06" PRIx32 "]->[0x%016" PRIx64
"-0x%016" PRIx64
"] "
"(align=0x%" PRIx32 ")\n",
exec->exe_elf.elf_text_offset,
exec->exe_elf.elf_text_offset
+ exec->exe_elf.elf_text_filesz,
exec->exe_elf.elf_text_vaddr,
exec->exe_elf.elf_text_vaddr
+ exec->exe_elf.elf_text_memsz,
exec->exe_elf.elf_text_align);
printf(" data = [0x%06" PRIx32
"-0x%06" PRIx32 "]->[0x%016" PRIx64
"-0x%016" PRIx64
"] "
"(align=0x%" PRIx32 ")\n",
exec->exe_elf.elf_data_offset,
exec->exe_elf.elf_data_offset
+ exec->exe_elf.elf_data_filesz,
exec->exe_elf.elf_data_vaddr,
exec->exe_elf.elf_data_vaddr
+ exec->exe_elf.elf_data_memsz,
exec->exe_elf.elf_data_align);
break;
case EC3_EXEC_OTHER:
printf("OTHER\n");
break;
case EC3_EXEC_NONE:
printf("NONE\n");
break;
}
}
}

View File

@@ -31,6 +31,43 @@ static void encode_header(
out->h_app_magic = b_i64_htob(in->img_id);
}
static void encode_tag_executable_info(
const struct ec3_tag_executable_info *in,
struct ec3_executable *out)
{
out->exe_format = b_i16_htob(in->exe_format);
switch (in->exe_format) {
case EC3_EXEC_ELF:
out->exe_elf.elf_data_offset
= b_i32_htob(in->exe_elf.elf_data_offset);
out->exe_elf.elf_data_filesz
= b_i32_htob(in->exe_elf.elf_data_filesz);
out->exe_elf.elf_data_memsz
= b_i32_htob(in->exe_elf.elf_data_memsz);
out->exe_elf.elf_data_align
= b_i32_htob(in->exe_elf.elf_data_align);
out->exe_elf.elf_text_offset
= b_i32_htob(in->exe_elf.elf_text_offset);
out->exe_elf.elf_text_filesz
= b_i32_htob(in->exe_elf.elf_text_filesz);
out->exe_elf.elf_text_memsz
= b_i32_htob(in->exe_elf.elf_text_memsz);
out->exe_elf.elf_text_align
= b_i32_htob(in->exe_elf.elf_text_align);
out->exe_elf.elf_data_vaddr
= b_i64_htob(in->exe_elf.elf_data_vaddr);
out->exe_elf.elf_text_vaddr
= b_i64_htob(in->exe_elf.elf_text_vaddr);
out->exe_elf.elf_entry = b_i64_htob(in->exe_elf.elf_entry);
break;
default:
break;
}
}
static void encode_tag(
const struct ec3_tag_info *in,
struct ec3_tag_table_entry *out)
@@ -42,6 +79,10 @@ static void encode_tag(
out->tag_checksum = b_i32_htob(in->tag_checksum);
out->tag_ident = b_i64_htob(in->tag_ident);
out->tag_length = b_i64_htob(in->tag_total_length);
if (in->tag_type == EC3_TAG_EXEC) {
encode_tag_executable_info(&in->tag_exe, &out->tag_exe);
}
}
static void encode_extent(
@@ -454,8 +495,8 @@ static enum ec3_status put_empty_cluster(
return EC3_SUCCESS;
}
/* retrieve a cached cluster from a tag io context, encode it, and write it
* to the shadow image */
/* retrieve a cached cluster from a tag io context, encode it, and write
* it to the shadow image */
static enum ec3_status copy_cached_cluster(
struct shadow_image *image,
struct ec3_tag_ioctx *tag,
@@ -521,10 +562,10 @@ static enum ec3_status copy_cached_cluster(
return EC3_SUCCESS;
}
/* read a range of clusters from the source image, delimited by an extent.
* write the clusters to the shadow image. the tag's cache is also checked for
* each cluster in the extent. of a cached version of the cluster's contents
* exists, that is used instead */
/* read a range of clusters from the source image, delimited by an
* extent. write the clusters to the shadow image. the tag's cache is
* also checked for each cluster in the extent. of a cached version of
* the cluster's contents exists, that is used instead */
static enum ec3_status copy_cluster_range(
struct ec3_image_ioctx *src,
struct shadow_image *dest,

View File

@@ -90,6 +90,7 @@ static int shell(
b_i("mount OK");
ec3_volume_close(volume);
ec3_tag_ioctx_close(volu);
ec3_tag_ioctx_close(ctab);
ec3_tag_ioctx_close(cdat);

104
src/substitute.c Normal file
View File

@@ -0,0 +1,104 @@
#include "substitute.h"
#define INVALID_INDEX ((size_t) - 1)
enum ec3_status substitution_list_init(struct substitution_list *list)
{
memset(list, 0x0, sizeof *list);
list->s_entries = b_dict_create();
return EC3_SUCCESS;
}
enum ec3_status substitution_list_finish(struct substitution_list *list)
{
b_dict_release(list->s_entries);
list->s_entries = NULL;
return EC3_SUCCESS;
}
enum ec3_status substitution_list_add_substitution(
struct substitution_list *list,
const char *find,
const char *replace_with)
{
b_string *sub = b_string_create_from_cstr(replace_with);
b_status status = b_dict_put(list->s_entries, find, B_OBJECT(sub));
b_string_release(sub);
if (!B_OK(status)) {
return ec3_status_from_b_status(
status,
EC3_ERR_INTERNAL_FAILURE);
}
return EC3_SUCCESS;
}
static enum ec3_status perform_substitution(
struct substitution_list *list,
b_string *base,
size_t sub_start,
size_t sub_end)
{
char sub[128];
const char *s = b_string_ptr(base);
size_t sub_name_length = sub_end - sub_start - 2;
memcpy(sub, s + sub_start + 2, sub_name_length);
sub[sub_name_length] = '\0';
b_string *value = B_STRING(b_dict_at(list->s_entries, sub));
if (value) {
b_string_replace(
base,
sub_start,
sub_end - sub_start + 1,
b_string_ptr(value));
} else {
b_string_remove(base, sub_start, sub_end - sub_start + 1);
}
return EC3_SUCCESS;
}
enum ec3_status substitution_list_substitute(
struct substitution_list *list,
b_string *str)
{
const char *s = b_string_ptr(str);
size_t sub_start = INVALID_INDEX;
enum ec3_status status = EC3_SUCCESS;
for (size_t i = 0; s[i]; i++) {
if (s[i] == '$' && s[i + 1] == '{') {
if (sub_start != INVALID_INDEX) {
status = EC3_ERR_BAD_FORMAT;
break;
}
sub_start = i;
} else if (s[i] == '}') {
if (sub_start == INVALID_INDEX) {
status = EC3_ERR_BAD_FORMAT;
break;
}
size_t sub_end = i;
status = perform_substitution(
list,
str,
sub_start,
sub_end);
if (status != EC3_SUCCESS) {
break;
}
sub_start = INVALID_INDEX;
s = b_string_ptr(str);
}
}
return status;
}

25
src/substitute.h Normal file
View File

@@ -0,0 +1,25 @@
#ifndef SUBSTITUTE_H_
#define SUBSTITUTE_H_
#include "status.h"
#include <blue/object/dict.h>
#include <blue/object/string.h>
struct substitution_list {
b_dict *s_entries;
};
extern enum ec3_status substitution_list_init(struct substitution_list *list);
extern enum ec3_status substitution_list_finish(struct substitution_list *list);
extern enum ec3_status substitution_list_add_substitution(
struct substitution_list *list,
const char *find,
const char *replace_with);
extern enum ec3_status substitution_list_substitute(
struct substitution_list *list,
b_string *str);
#endif

View File

@@ -14,18 +14,42 @@ struct b_file;
enum ec3_tag_ioctx_mode {
EC3_TAG_IO_READ = 0x01u,
EC3_TAG_IO_WRITE = 0x02u,
EC3_TAG_IO_READWRITE = 0x03u,
EC3_TAG_IO_READWRITE = EC3_TAG_IO_READ | EC3_TAG_IO_WRITE,
EC3_TAG_IO_SEQUENTIAL = 0x04u,
EC3_TAG_IO_CLOSED = 0x10u,
};
struct ec3_tag_executable_info {
unsigned int exe_format;
union {
struct {
uint32_t elf_data_offset;
uint32_t elf_data_filesz, elf_data_memsz;
uint32_t elf_text_offset;
uint32_t elf_text_filesz, elf_text_memsz;
uint32_t elf_data_align, elf_text_align;
uint64_t elf_data_vaddr;
uint64_t elf_text_vaddr;
uint64_t elf_entry;
} exe_elf;
};
};
struct ec3_tag_info {
unsigned long tag_type;
unsigned long tag_flags;
unsigned long tag_checksum;
unsigned long long tag_ident;
unsigned long long tag_total_length;
union {
struct ec3_tag_executable_info tag_exe;
};
};
struct ec3_tag_ioctx {
@@ -37,7 +61,6 @@ struct ec3_tag_ioctx {
/* temp buffer of cluster size, used for pipeline operations */
void *io_cluster_buf;
/* this points to memory belonging to ec3_image_ioctx */
struct ec3_tag_info io_tag_info;
/* io_f_rotag is a reference to the main image file. a data and cluster

View File

@@ -18,3 +18,25 @@ enum ec3_status ec3_vnode_from_file_info(
return EC3_SUCCESS;
}
void ec3_vnode_encode(const struct ec3_vnode *in, struct ec3_bin_vnode *out)
{
out->n_id = b_i32_htob(in->v_id);
out->n_ctime = b_i32_htob(in->v_ctime);
out->n_mtime = b_i32_htob(in->v_mtime);
out->n_mode = b_i16_htob(in->v_mode);
out->n_uid = b_i16_htob(in->v_uid);
out->n_gid = b_i16_htob(in->v_gid);
memcpy(out->n_data, in->v_data, sizeof in->v_data);
}
void ec3_vnode_decode(const struct ec3_bin_vnode *in, struct ec3_vnode *out)
{
out->v_id = b_i32_btoh(in->n_id);
out->v_ctime = b_i32_btoh(in->n_ctime);
out->v_mtime = b_i32_btoh(in->n_mtime);
out->v_mode = b_i16_btoh(in->n_mode);
out->v_uid = b_i16_btoh(in->n_uid);
out->v_gid = b_i16_btoh(in->n_gid);
memcpy(out->v_data, in->n_data, sizeof in->n_data);
}

View File

@@ -18,4 +18,11 @@ extern enum ec3_status ec3_vnode_from_file_info(
const struct b_file_info *file_info,
struct ec3_vnode *out);
extern void ec3_vnode_encode(
const struct ec3_vnode *in,
struct ec3_bin_vnode *out);
extern void ec3_vnode_decode(
const struct ec3_bin_vnode *in,
struct ec3_vnode *out);
#endif

View File

@@ -359,28 +359,6 @@ static const struct b_tree_ops vnode_table_ops = {
.entry_compare = entry_compare,
};
static void encode_vnode(const struct ec3_vnode *in, struct ec3_bin_vnode *out)
{
out->n_id = b_i32_htob(in->v_id);
out->n_ctime = b_i32_htob(in->v_ctime);
out->n_mtime = b_i32_htob(in->v_mtime);
out->n_mode = b_i16_htob(in->v_mode);
out->n_uid = b_i16_htob(in->v_uid);
out->n_gid = b_i16_htob(in->v_gid);
memcpy(out->n_data, in->v_data, sizeof in->v_data);
}
static void decode_vnode(const struct ec3_bin_vnode *in, struct ec3_vnode *out)
{
out->v_id = b_i32_btoh(in->n_id);
out->v_ctime = b_i32_btoh(in->n_ctime);
out->v_mtime = b_i32_btoh(in->n_mtime);
out->v_mode = b_i16_btoh(in->n_mode);
out->v_uid = b_i16_btoh(in->n_uid);
out->v_gid = b_i16_btoh(in->n_gid);
memcpy(out->v_data, in->n_data, sizeof in->n_data);
}
static enum ec3_status load_vnode(
struct ec3_volume *volume,
size_t id,
@@ -507,7 +485,7 @@ enum ec3_status ec3_volume_get_vnode(
return EC3_ERR_IO_FAILURE;
}
decode_vnode(&vnode, out);
ec3_vnode_decode(&vnode, out);
return EC3_SUCCESS;
}
@@ -516,13 +494,15 @@ enum ec3_status ec3_volume_put_vnode(
struct ec3_volume *volume,
const struct ec3_vnode *vnode)
{
#if 0
printf("put(%zu, %x%x)\n",
vnode->v_id,
vnode->v_data[0],
vnode->v_data[1]);
#endif
struct ec3_bin_vnode bin_vnode;
encode_vnode(vnode, &bin_vnode);
ec3_vnode_encode(vnode, &bin_vnode);
int err = b_tree_put(
&volume->v_vnode_table,
(b_tree_node_entry *)&bin_vnode);