Name of user not set #1004951 has uploaded this change for review. ( https://review.coreboot.org/c/coreboot/+/75129 )
Change subject: util/archive/archive.c: attempt 2 - add features to archive util Add "extract" and "list" options to the archive util ......................................................................
util/archive/archive.c: attempt 2 - add features to archive util Add "extract" and "list" options to the archive util
Change-Id: I1aab9a2ae76e1126f31db53ccffc1aa5f66ae189 Signed-off-by: BinBashBanana 51469593+BinBashBanana@users.noreply.github.com --- M util/archive/archive.c 1 file changed, 186 insertions(+), 6 deletions(-)
git pull ssh://review.coreboot.org:29418/coreboot refs/changes/29/75129/1
diff --git a/util/archive/archive.c b/util/archive/archive.c index f877632..f7d3e09 100644 --- a/util/archive/archive.c +++ b/util/archive/archive.c @@ -4,10 +4,12 @@ #include <endian.h> #include <errno.h> #include <libgen.h> +#include <stdbool.h> #include <stdint.h> #include <stdio.h> #include <stdlib.h> #include <string.h> +#include <sys/stat.h>
static struct directory *archive;
@@ -17,6 +19,8 @@ printf(" archive - concatenate files and create an archive\n"); printf("Usage:\n"); printf(" archive archive_name create file0 file1 ...\n"); + printf(" archive archive_name extract [dir] [file0 file1 ...]\n"); + printf(" archive archive_name list\n"); }
static int get_file_size(const char *file) @@ -145,7 +149,7 @@ size += s; }
- archive = calloc(size, 1); + archive = calloc(1, size); if (!archive) { fprintf(stderr, "Error: failed to allocate memory\n"); return -1; @@ -199,32 +203,171 @@ archive->count = htole32(archive->count); }
+static void convert_endian_rev(void) +{ + struct dentry *entry; + uint32_t i; + + archive->version = le32toh(archive->version); + archive->size = le32toh(archive->size); + archive->count = le32toh(archive->count); + + entry = get_first_dentry(archive); + for (i = 0; i < archive->count; i++) { + entry[i].offset = le32toh(entry[i].offset); + entry[i].size = le32toh(entry[i].size); + } +} + /* - * Write archive to file + * Write to a file + * + * return: 0 on success or -1 on error */ -static int output_archive(const char *path) +static int write_file(const char *path, void *content, size_t length) { FILE *fp;
- convert_endian(); - fp = fopen(path, "wb"); if (!fp) { fprintf(stderr, "Error: failed to open %s\n", path); fclose(fp); return -1; } - if (fwrite(archive, sizeof(char), archive->size, fp) != archive->size) { + if (fwrite(content, 1, length, fp) != length) { fprintf(stderr, "Error: failed to write to %s\n", path); fclose(fp); return -1; } fclose(fp); + + return 0; +} + +/* + * Write archive to file + */ +static int output_archive(const char *path) +{ + convert_endian(); + + if (write_file(path, archive, archive->size)) + return -1; + printf("Wrote archive to %s\n", path);
return 0; }
+/* + * Read archive from file + */ +static int read_archive(const char *path) +{ + FILE *fp; + int size; + + if (!path || !*path) { + fprintf(stderr, "Error: invalid path\n"); + return -1; + } + + size = get_file_size(path); + if (size < 0) + return -1; + + archive = calloc(1, size); + if (!archive) { + fprintf(stderr, "Error: failed to allocate memory\n"); + return -1; + } + + fp = fopen(path, "rb"); + if (!fp) { + fprintf(stderr, "Error: failed to open %s (%d: %s)\n", + path, errno, strerror(errno)); + return -1; + } + if (fread(archive, sizeof(char), size, fp) != (size_t)size) { + fprintf(stderr, "Error: failed to read %s\n", path); + fclose(fp); + return -1; + } + fclose(fp); + + convert_endian_rev(); + + // validation from https://source.chromium.org/chromiumos/chromiumos/codesearch/+/main:src/plat... + + /* Validate magic field */ + if (memcmp(archive->magic, CBAR_MAGIC, sizeof(CBAR_MAGIC))) { + fprintf(stderr, "Error: Invalid archive magic\n"); + return -1; + } + + /* Validate the total size */ + if (archive->size != (unsigned int)size) { + fprintf(stderr, "Error: Archive size does not match\n"); + return -1; + } + + /* Validate count field */ + if (get_first_offset(archive) > archive->size) { + fprintf(stderr, "Error: Invalid count\n"); + return -1; + } + + return 0; +} + +/* + * Extract files from archive + * + * dir: output directory (default .) + * count: length of array files below + * files: pointer to the array of file names to extract (default all) + */ +static void extract_archive(const char *dir, int count, const char **files) +{ + if (dir) { + // https://stackoverflow.com/a/7430262 + struct stat st = {0}; + if (stat(dir, &st) == -1) + mkdir(dir, 0700); + } else { + dir = "."; + } + + struct dentry *entry = get_first_dentry(archive); + for (unsigned int i = 0; i < archive->count; i++) { + if (count > 0) { + bool skip = 1; + for (int j = 0; j < count; j++) { + if (!strncmp(files[j], entry[i].name, sizeof(entry[i].name))) { + skip = 0; + break; + } + } + if (skip) + continue; + } + char path[128]; + snprintf(path, sizeof(path), "%s/%s", dir, entry[i].name); + write_file(path, (char *)archive + entry[i].offset, entry[i].size); + } +} + +/* + * List files in archive + */ +static void list_archive(void) +{ + struct dentry *entry = get_first_dentry(archive); + for (unsigned int i = 0; i < archive->count; i++) { + printf("%s\n", entry[i].name); + } +} + static int cmd_create(const char *archive_path, int count, const char **files) { if (count < 1 || !files) { @@ -244,6 +387,26 @@ return 0; }
+static int cmd_extract(const char *archive_path, const char *dir, int count, const char **files) +{ + if (read_archive(archive_path)) + return -1; + + extract_archive(dir, count, files); + + return 0; +} + +static int cmd_list(const char *archive_path) +{ + if (read_archive(archive_path)) + return -1; + + list_archive(); + + return 0; +} + int main(int argc, const char *argv[]) { const char *command; @@ -260,6 +423,12 @@ if (!strncmp(command, "create", sizeof("create"))) { if (cmd_create(argv[1], argc - 3, &argv[3])) return -1; + } else if (!strncmp(command, "extract", sizeof("extract"))) { + if (cmd_extract(argv[1], argv[3], argc - 4, &argv[4])) + return -1; + } else if (!strncmp(command, "list", sizeof("list"))) { + if (cmd_list(argv[1])) + return -1; } else { fprintf(stderr, "Error: invalid command: %s\n", command); return -1;