Compare commits
10 Commits
10231ecb3e
...
7634e481cb
| Author | SHA1 | Date | |
|---|---|---|---|
| 7634e481cb | |||
| 809e4425bf | |||
| 54d5c081eb | |||
| 265b4ba574 | |||
| 349ef4460a | |||
| b588f860e1 | |||
| 06362e204a | |||
| 9d374598c8 | |||
| aa3bbad0c7 | |||
| d0d7eb05ac |
32
src/bin.h
32
src/bin.h
@@ -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
603
src/builder.c
Normal 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
52
src/builder.h
Normal 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
|
||||
403
src/capture.c
403
src/capture.c
@@ -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,
|
||||
¶m,
|
||||
EC3_IMAGE_IO_WRITE | EC3_IMAGE_IO_TRUNCATE,
|
||||
&image);
|
||||
status = ec3_image_builder_create(out_path, ¶m, &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;
|
||||
}
|
||||
|
||||
741
src/create.c
741
src/create.c
@@ -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),
|
||||
¶m->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, ¶m);
|
||||
if (status2 != EC3_SUCCESS) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
status2 = ec3_image_builder_create(
|
||||
out_path_cstr,
|
||||
¶m,
|
||||
&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
284
src/elf.h
Normal 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
79
src/exe.c
Normal 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
13
src/exe.h
Normal 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
|
||||
67
src/image.c
67
src/image.c
@@ -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(
|
||||
|
||||
47
src/query.c
47
src/query.c
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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
104
src/substitute.c
Normal 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
25
src/substitute.h
Normal 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
|
||||
27
src/tag.h
27
src/tag.h
@@ -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
|
||||
|
||||
22
src/vnode.c
22
src/vnode.c
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
28
src/volume.c
28
src/volume.c
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user