capture: update to use new builder interface
This commit is contained in:
403
src/capture.c
403
src/capture.c
@@ -1,12 +1,9 @@
|
|||||||
#include "bin.h"
|
#include "bin.h"
|
||||||
#include "chunk-table.h"
|
#include "builder.h"
|
||||||
#include "commands.h"
|
#include "commands.h"
|
||||||
#include "fs-tree.h"
|
|
||||||
#include "image.h"
|
#include "image.h"
|
||||||
#include "misc.h"
|
#include "misc.h"
|
||||||
#include "status.h"
|
#include "status.h"
|
||||||
#include "string-table.h"
|
|
||||||
#include "volume.h"
|
|
||||||
|
|
||||||
#include <blue/cmd.h>
|
#include <blue/cmd.h>
|
||||||
#include <blue/io/directory.h>
|
#include <blue/io/directory.h>
|
||||||
@@ -35,309 +32,6 @@ enum {
|
|||||||
OPT_VERBOSE,
|
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(
|
static int capture(
|
||||||
const b_command *self,
|
const b_command *self,
|
||||||
const b_arglist *opt,
|
const b_arglist *opt,
|
||||||
@@ -360,74 +54,19 @@ static int capture(
|
|||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct ec3_image_ioctx *image = NULL;
|
struct ec3_image_builder *image = NULL;
|
||||||
struct ec3_parameters param = {
|
struct ec3_parameters param = {
|
||||||
.p_cluster_size = EC3_CLUSTER_16K,
|
.p_cluster_size = EC3_CLUSTER_16K,
|
||||||
.p_compression_func = EC3_COMPRESSION_ZSTD,
|
.p_compression_func = EC3_COMPRESSION_ZSTD,
|
||||||
.p_ident = ident,
|
.p_ident = ident,
|
||||||
};
|
};
|
||||||
status = ec3_image_ioctx_open(
|
status = ec3_image_builder_create(out_path, ¶m, &image);
|
||||||
out_path,
|
|
||||||
¶m,
|
|
||||||
EC3_IMAGE_IO_WRITE | EC3_IMAGE_IO_TRUNCATE,
|
|
||||||
&image);
|
|
||||||
|
|
||||||
if (status != EC3_SUCCESS) {
|
if (status != EC3_SUCCESS) {
|
||||||
b_err("cannot initialise EC3 writer");
|
b_err("cannot initialise EC3 writer");
|
||||||
return -1;
|
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;
|
uint64_t next_auto_id = 0;
|
||||||
|
|
||||||
b_arglist_iterator it = {0};
|
b_arglist_iterator it = {0};
|
||||||
@@ -435,8 +74,8 @@ static int capture(
|
|||||||
{
|
{
|
||||||
printf("%s\n", it.value->val_str);
|
printf("%s\n", it.value->val_str);
|
||||||
|
|
||||||
status = capture_directory(
|
status = ec3_image_builder_capture_directory(
|
||||||
&ctx,
|
image,
|
||||||
next_auto_id,
|
next_auto_id,
|
||||||
it.value->val_str);
|
it.value->val_str);
|
||||||
next_auto_id++;
|
next_auto_id++;
|
||||||
@@ -482,7 +121,10 @@ static int capture(
|
|||||||
return -1;
|
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) {
|
if (status != EC3_SUCCESS) {
|
||||||
b_err("an error occurred while writing to the "
|
b_err("an error occurred while writing to the "
|
||||||
@@ -491,32 +133,7 @@ static int capture(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
b_btree_iterator s_it;
|
ec3_image_builder_destroy(image);
|
||||||
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);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user