implement unwrap command to retrieve binary files from containers

This commit is contained in:
2025-02-15 12:36:57 +00:00
parent de99b88097
commit c2094e0211

168
src/unwrap.c Normal file
View File

@@ -0,0 +1,168 @@
#include "commands.h"
#include "misc.h"
#include "read.h"
#include <blue/cmd.h>
#include <blue/term.h>
#include <errno.h>
#include <stdlib.h>
enum {
ARG_CONTAINER,
OPT_TAG,
OPT_TAG_IDENT,
};
static int unwrap(
const b_command *self,
const b_arglist *opt,
const b_array *args)
{
const char *in_path = NULL;
b_arglist_get_string(
opt,
B_COMMAND_INVALID_ID,
ARG_CONTAINER,
0,
&in_path);
FILE *inp = fopen(in_path, "rb");
if (!inp) {
b_err("cannot open '%s'", in_path);
b_i("reason: %s", strerror(errno));
return -1;
}
struct ec3_reader *reader = NULL;
enum ec3_status status = ec3_reader_create(inp, &reader);
if (status != EC3_SUCCESS) {
fclose(inp);
b_err("cannot open '%s'", in_path);
b_i("reason: corrupted/unknown file format");
return -1;
}
const struct ec3_container_info *c_info
= ec3_reader_get_container_info(reader);
if (c_info->c_nr_tags == 0) {
ec3_reader_finish(reader);
fclose(inp);
b_i("container '%s' has no tags", in_path);
return -1;
}
uint64_t target_tag_ident = 0;
const char *target_tag_ident_str = NULL;
b_arglist_get_string(
opt,
OPT_TAG,
OPT_TAG_IDENT,
0,
&target_tag_ident_str);
if (target_tag_ident_str) {
ec3_identifier_from_string(
target_tag_ident_str,
&target_tag_ident);
} else {
const struct ec3_tag_info *tags = ec3_reader_get_tags(reader);
target_tag_ident = tags[0].tag_ident;
}
char ident_str[32];
ec3_identifier_to_string(target_tag_ident, ident_str, sizeof ident_str);
struct ec3_tag_reader *tag_reader = NULL;
status = ec3_reader_open_tag(reader, target_tag_ident, &tag_reader);
if (status != EC3_SUCCESS) {
b_i("container '%s' has no %s tag", in_path, ident_str);
ec3_reader_finish(reader);
fclose(inp);
return -1;
}
const struct ec3_tag_info *target_tag_info
= ec3_reader_get_tag_info(reader, target_tag_ident);
size_t tag_length = target_tag_info->tag_total_length;
printf("reading %zu bytes from tag %s...\n", tag_length, ident_str);
char *buf = malloc(c_info->c_cluster_size);
int ret = 0;
FILE *outp = fopen("data.bin", "wb");
for (size_t i = 0;; i++) {
size_t nr_read = 0;
enum ec3_status status
= ec3_tag_reader_read(tag_reader, i, 1, buf, &nr_read);
if (status != EC3_SUCCESS) {
b_err("I/O failure while reading from container",
in_path);
ret = -1;
break;
}
printf("read %zu bytes from cluster %zu\n", nr_read, i);
fwrite(buf, 1, nr_read, outp);
if (nr_read < c_info->c_cluster_size) {
break;
}
}
free(buf);
fclose(inp);
fclose(outp);
return ret;
}
B_COMMAND(CMD_UNWRAP, CMD_ROOT)
{
B_COMMAND_NAME("unwrap");
B_COMMAND_SHORT_NAME('U');
B_COMMAND_DESC(
"retrieve a binary or executable blob from an ec3 "
"container.");
B_COMMAND_FLAGS(B_COMMAND_SHOW_HELP_BY_DEFAULT);
B_COMMAND_FUNCTION(unwrap);
B_COMMAND_HELP_OPTION();
B_COMMAND_ARG(ARG_CONTAINER)
{
B_ARG_NAME("container");
B_ARG_DESC("the container to retrieve the blob from");
B_ARG_NR_VALUES(1);
}
B_COMMAND_OPTION(OPT_TAG)
{
B_OPTION_SHORT_NAME('T');
B_OPTION_LONG_NAME("tag");
B_OPTION_DESC("the identifier of the blob tag to retrieve");
B_OPTION_ARG(OPT_TAG_IDENT)
{
B_ARG_NAME("identifier");
B_ARG_DESC("the identifier");
B_ARG_NR_VALUES(1);
}
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_ARG(ARG_CONTAINER);
}
B_COMMAND_USAGE()
{
B_COMMAND_USAGE_OPT(OPT_TAG);
B_COMMAND_USAGE_ARG(ARG_CONTAINER);
}
}