query: add support for querying chunk and vnode table contents
This commit is contained in:
370
src/query.c
370
src/query.c
@@ -1,8 +1,10 @@
|
||||
#include "bin.h"
|
||||
#include "chunk-table.h"
|
||||
#include "commands.h"
|
||||
#include "image.h"
|
||||
#include "misc.h"
|
||||
#include "status.h"
|
||||
#include "vnode.h"
|
||||
|
||||
#include <blue/cmd.h>
|
||||
#include <blue/core/endian.h>
|
||||
@@ -22,6 +24,9 @@ enum {
|
||||
OPT_INFO_EXTENTS,
|
||||
OPT_INFO_STRINGS,
|
||||
OPT_INFO_CHUNKS,
|
||||
OPT_INFO_VNODES,
|
||||
|
||||
OPT_IN_ORDER,
|
||||
};
|
||||
|
||||
enum info_type {
|
||||
@@ -31,6 +36,7 @@ enum info_type {
|
||||
INFO_EXTENTS = 0x04,
|
||||
INFO_CHUNKS = 0x08,
|
||||
INFO_STRINGS = 0x10,
|
||||
INFO_VNODES = 0x20,
|
||||
};
|
||||
|
||||
static void tag_type_string(unsigned long in, char out[5])
|
||||
@@ -217,6 +223,240 @@ static void print_strings_info(struct ec3_image_ioctx *image)
|
||||
free(cluster_buf);
|
||||
}
|
||||
|
||||
static enum ec3_status print_chunk_table(
|
||||
struct ec3_image_ioctx *img,
|
||||
struct ec3_tag_ioctx *ctab,
|
||||
size_t index,
|
||||
size_t depth)
|
||||
{
|
||||
if (depth > 1) {
|
||||
abort();
|
||||
}
|
||||
|
||||
const struct ec3_image_info *img_info = ec3_image_ioctx_get_info(img);
|
||||
unsigned char *cluster_buf = malloc(img_info->img_cluster_size);
|
||||
if (!cluster_buf) {
|
||||
return EC3_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
enum ec3_cluster_size cluster_size
|
||||
= ec3_cluster_size_bytes_to_id(img_info->img_cluster_size);
|
||||
|
||||
size_t nr_read;
|
||||
char chunk_id[100];
|
||||
enum ec3_status status = ec3_tag_ioctx_read_cluster(
|
||||
ctab,
|
||||
index,
|
||||
cluster_buf,
|
||||
&nr_read);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
free(cluster_buf);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct ec3_chunk_group *group = (struct ec3_chunk_group *)cluster_buf;
|
||||
struct ec3_chunk *chunks = NULL;
|
||||
b_i32 *children = NULL;
|
||||
size_t nr_chunks = b_i16_btoh(group->g_nr_chunks);
|
||||
|
||||
switch (cluster_size) {
|
||||
case EC3_CLUSTER_4K:
|
||||
chunks = group->g_4k.g_chunks;
|
||||
children = group->g_4k.g_child_offsets;
|
||||
break;
|
||||
case EC3_CLUSTER_8K:
|
||||
chunks = group->g_8k.g_chunks;
|
||||
children = group->g_8k.g_child_offsets;
|
||||
break;
|
||||
case EC3_CLUSTER_16K:
|
||||
chunks = group->g_16k.g_chunks;
|
||||
children = group->g_16k.g_child_offsets;
|
||||
break;
|
||||
case EC3_CLUSTER_32K:
|
||||
chunks = group->g_32k.g_chunks;
|
||||
children = group->g_32k.g_child_offsets;
|
||||
break;
|
||||
case EC3_CLUSTER_64K:
|
||||
chunks = group->g_64k.g_chunks;
|
||||
children = group->g_64k.g_child_offsets;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
size_t child = b_i32_btoh(children[0]);
|
||||
if (child == 0) {
|
||||
printf("child 0 of node %zu is 0\n", index);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (child != EC3_INVALID_OFFSET) {
|
||||
if (depth == 1) {
|
||||
printf("break\n");
|
||||
}
|
||||
|
||||
status = print_chunk_table(img, ctab, child, depth + 1);
|
||||
}
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
free(cluster_buf);
|
||||
return status;
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nr_chunks; i++) {
|
||||
ec3_chunk_id_to_string(
|
||||
chunks[i].c_id,
|
||||
chunk_id,
|
||||
sizeof chunk_id);
|
||||
|
||||
#if 1
|
||||
for (size_t d = 0; d < depth; d++) {
|
||||
printf(" ");
|
||||
}
|
||||
#endif
|
||||
|
||||
printf("[%zu:%s] start: %zu, count: %zu\n",
|
||||
depth,
|
||||
chunk_id,
|
||||
(size_t)b_i32_btoh(chunks[i].c_first_cluster),
|
||||
(size_t)b_i32_btoh(chunks[i].c_nr_clusters));
|
||||
|
||||
if (i > 0) {
|
||||
int cmp = memcmp(
|
||||
chunks[i].c_id,
|
||||
chunks[i - 1].c_id,
|
||||
sizeof(ec3_chunk_id));
|
||||
|
||||
if (cmp < 0) {
|
||||
fprintf(stderr, "nodes are out of order!\n");
|
||||
abort();
|
||||
}
|
||||
}
|
||||
|
||||
child = b_i32_btoh(children[i + 1]);
|
||||
if (child == 0) {
|
||||
printf("child %zu of node %zu is 0\n", i + 1, index);
|
||||
abort();
|
||||
}
|
||||
|
||||
if (child != EC3_INVALID_OFFSET) {
|
||||
if (depth == 1) {
|
||||
printf("break\n");
|
||||
}
|
||||
|
||||
status = print_chunk_table(img, ctab, child, depth + 1);
|
||||
}
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
free(cluster_buf);
|
||||
return EC3_SUCCESS;
|
||||
}
|
||||
|
||||
static void print_chunk_info_inorder(struct ec3_image_ioctx *image)
|
||||
{
|
||||
struct ec3_tag_ioctx *ctab;
|
||||
enum ec3_status status = ec3_image_ioctx_open_tag_by_type(
|
||||
image,
|
||||
EC3_TAG_CTAB,
|
||||
0,
|
||||
EC3_TAG_IO_READ,
|
||||
&ctab);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
return;
|
||||
}
|
||||
|
||||
printf("chunks:\n");
|
||||
print_chunk_table(image, ctab, 0, 0);
|
||||
|
||||
ec3_tag_ioctx_close(ctab);
|
||||
}
|
||||
|
||||
static enum ec3_status print_chunk_info(struct ec3_image_ioctx *img)
|
||||
{
|
||||
struct ec3_tag_ioctx *ctab;
|
||||
enum ec3_status status = ec3_image_ioctx_open_tag_by_type(
|
||||
img,
|
||||
EC3_TAG_CTAB,
|
||||
0,
|
||||
EC3_TAG_IO_READ,
|
||||
&ctab);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct ec3_image_info *img_info = ec3_image_ioctx_get_info(img);
|
||||
unsigned char *cluster_buf = malloc(img_info->img_cluster_size);
|
||||
if (!cluster_buf) {
|
||||
return EC3_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
size_t nr_clusters = 0;
|
||||
ec3_tag_ioctx_get_nr_clusters(ctab, &nr_clusters);
|
||||
enum ec3_cluster_size cluster_size
|
||||
= ec3_cluster_size_bytes_to_id(img_info->img_cluster_size);
|
||||
|
||||
for (size_t cluster = 0; cluster < nr_clusters; cluster++) {
|
||||
size_t nr_read;
|
||||
char chunk_id[100];
|
||||
status = ec3_tag_ioctx_read_cluster(
|
||||
ctab,
|
||||
cluster,
|
||||
cluster_buf,
|
||||
&nr_read);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
free(cluster_buf);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct ec3_chunk_group *group
|
||||
= (struct ec3_chunk_group *)cluster_buf;
|
||||
struct ec3_chunk *chunks = NULL;
|
||||
size_t nr_chunks = b_i16_btoh(group->g_nr_chunks);
|
||||
|
||||
switch (cluster_size) {
|
||||
case EC3_CLUSTER_4K:
|
||||
chunks = group->g_4k.g_chunks;
|
||||
break;
|
||||
case EC3_CLUSTER_8K:
|
||||
chunks = group->g_8k.g_chunks;
|
||||
break;
|
||||
case EC3_CLUSTER_16K:
|
||||
chunks = group->g_16k.g_chunks;
|
||||
break;
|
||||
case EC3_CLUSTER_32K:
|
||||
chunks = group->g_32k.g_chunks;
|
||||
break;
|
||||
case EC3_CLUSTER_64K:
|
||||
chunks = group->g_64k.g_chunks;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nr_chunks; i++) {
|
||||
ec3_chunk_id_to_string(
|
||||
chunks[i].c_id,
|
||||
chunk_id,
|
||||
sizeof chunk_id);
|
||||
printf(" [%s] start: %zu, count: %zu\n",
|
||||
chunk_id,
|
||||
(size_t)b_i32_btoh(chunks[i].c_first_cluster),
|
||||
(size_t)b_i32_btoh(chunks[i].c_nr_clusters));
|
||||
}
|
||||
}
|
||||
|
||||
free(cluster_buf);
|
||||
return EC3_SUCCESS;
|
||||
}
|
||||
|
||||
static enum info_type get_selected_info_types(const struct b_arglist *opt)
|
||||
{
|
||||
enum info_type type = INFO_NONE;
|
||||
@@ -249,9 +489,103 @@ static enum info_type get_selected_info_types(const struct b_arglist *opt)
|
||||
type |= INFO_STRINGS;
|
||||
}
|
||||
|
||||
if (b_arglist_get_count(opt, OPT_INFO_VNODES, B_COMMAND_INVALID_ID)
|
||||
> 0) {
|
||||
type |= INFO_VNODES;
|
||||
}
|
||||
|
||||
return type;
|
||||
}
|
||||
|
||||
static enum ec3_status print_vnode_info(struct ec3_image_ioctx *img)
|
||||
{
|
||||
struct ec3_tag_ioctx *volu;
|
||||
enum ec3_status status = ec3_image_ioctx_open_tag_by_type(
|
||||
img,
|
||||
EC3_TAG_VOLU,
|
||||
0,
|
||||
EC3_TAG_IO_READ,
|
||||
&volu);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
return status;
|
||||
}
|
||||
|
||||
const struct ec3_image_info *img_info = ec3_image_ioctx_get_info(img);
|
||||
unsigned char *cluster_buf = malloc(img_info->img_cluster_size);
|
||||
if (!cluster_buf) {
|
||||
return EC3_ERR_NO_MEMORY;
|
||||
}
|
||||
|
||||
size_t nr_clusters = 0;
|
||||
ec3_tag_ioctx_get_nr_clusters(volu, &nr_clusters);
|
||||
enum ec3_cluster_size cluster_size
|
||||
= ec3_cluster_size_bytes_to_id(img_info->img_cluster_size);
|
||||
|
||||
for (size_t cluster = 0; cluster < nr_clusters; cluster++) {
|
||||
size_t nr_read;
|
||||
char chunk_id[100];
|
||||
status = ec3_tag_ioctx_read_cluster(
|
||||
volu,
|
||||
cluster,
|
||||
cluster_buf,
|
||||
&nr_read);
|
||||
|
||||
if (status != EC3_SUCCESS) {
|
||||
free(cluster_buf);
|
||||
return status;
|
||||
}
|
||||
|
||||
struct ec3_vnode_group *group
|
||||
= (struct ec3_vnode_group *)cluster_buf;
|
||||
struct ec3_bin_vnode *vnodes = NULL;
|
||||
size_t nr_vnodes = b_i16_btoh(group->g_nr_vnodes);
|
||||
|
||||
switch (cluster_size) {
|
||||
case EC3_CLUSTER_4K:
|
||||
vnodes = group->g_4k.g_vnodes;
|
||||
break;
|
||||
case EC3_CLUSTER_8K:
|
||||
vnodes = group->g_8k.g_vnodes;
|
||||
break;
|
||||
case EC3_CLUSTER_16K:
|
||||
vnodes = group->g_16k.g_vnodes;
|
||||
break;
|
||||
case EC3_CLUSTER_32K:
|
||||
vnodes = group->g_32k.g_vnodes;
|
||||
break;
|
||||
case EC3_CLUSTER_64K:
|
||||
vnodes = group->g_64k.g_vnodes;
|
||||
break;
|
||||
default:
|
||||
abort();
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < nr_vnodes; i++) {
|
||||
struct ec3_vnode vnode;
|
||||
ec3_vnode_decode(&vnodes[i], &vnode);
|
||||
printf(" [%06lu] gid:%u, uid:%u, mode:0x%x, "
|
||||
"ctime:%lu, "
|
||||
"mtime:%lu\n",
|
||||
vnode.v_id,
|
||||
vnode.v_gid,
|
||||
vnode.v_uid,
|
||||
vnode.v_mode,
|
||||
vnode.v_ctime,
|
||||
vnode.v_mtime);
|
||||
|
||||
ec3_chunk_id_to_string(
|
||||
vnode.v_data,
|
||||
chunk_id,
|
||||
sizeof chunk_id);
|
||||
printf(" data:%s\n", chunk_id);
|
||||
}
|
||||
}
|
||||
|
||||
free(cluster_buf);
|
||||
return EC3_SUCCESS;
|
||||
}
|
||||
|
||||
static int query(
|
||||
const b_command *self,
|
||||
const b_arglist *opt,
|
||||
@@ -298,6 +632,23 @@ static int query(
|
||||
print_strings_info(reader);
|
||||
}
|
||||
|
||||
if (selected_info & INFO_CHUNKS) {
|
||||
bool in_order = b_arglist_get_count(
|
||||
opt,
|
||||
OPT_IN_ORDER,
|
||||
B_COMMAND_INVALID_ID)
|
||||
> 0;
|
||||
if (in_order) {
|
||||
print_chunk_info_inorder(reader);
|
||||
} else {
|
||||
print_chunk_info(reader);
|
||||
}
|
||||
}
|
||||
|
||||
if (selected_info & INFO_VNODES) {
|
||||
print_vnode_info(reader);
|
||||
}
|
||||
|
||||
ec3_image_ioctx_close(reader);
|
||||
fclose(fp);
|
||||
|
||||
@@ -326,7 +677,8 @@ B_COMMAND(CMD_QUERY, CMD_ROOT)
|
||||
B_OPTION_LONG_NAME("all");
|
||||
B_OPTION_SHORT_NAME('a');
|
||||
B_OPTION_DESC(
|
||||
"print all available information about the image.");
|
||||
"print all available information about the "
|
||||
"image.");
|
||||
}
|
||||
|
||||
B_COMMAND_OPTION(OPT_INFO_IMAGE)
|
||||
@@ -368,6 +720,22 @@ B_COMMAND(CMD_QUERY, CMD_ROOT)
|
||||
B_OPTION_DESC("print the contents of the image chunk table.");
|
||||
}
|
||||
|
||||
B_COMMAND_OPTION(OPT_INFO_VNODES)
|
||||
{
|
||||
B_OPTION_LONG_NAME("vnodes");
|
||||
B_OPTION_SHORT_NAME('v');
|
||||
B_OPTION_DESC("print the contents of a volume vnode table.");
|
||||
}
|
||||
|
||||
B_COMMAND_OPTION(OPT_IN_ORDER)
|
||||
{
|
||||
B_OPTION_LONG_NAME("in-order");
|
||||
B_OPTION_SHORT_NAME('i');
|
||||
B_OPTION_DESC(
|
||||
"sort the chunk table output by hash. this will "
|
||||
"make the process slower and more memory-intensive.");
|
||||
}
|
||||
|
||||
B_COMMAND_USAGE()
|
||||
{
|
||||
B_COMMAND_USAGE_ARG(ARG_CONTAINER);
|
||||
|
||||
Reference in New Issue
Block a user