From aab510aa98c13297dbe1b5b45a9c6deb498be6dc Mon Sep 17 00:00:00 2001 From: David Oberhollenzer Date: Mon, 28 Jan 2019 20:01:36 +0100 Subject: [PATCH] Add package header with dependency information Signed-off-by: David Oberhollenzer --- Makefile.am | 3 +- include/pkgformat.h | 15 +++++ main/cmd/pack/desc.c | 113 ++++++++++++++++++++++++++++++++++++++ main/cmd/pack/pack.c | 26 ++++++++- main/cmd/pack/pack.h | 16 ++++++ main/cmd/pack/write_hdr.c | 40 ++++++++++++++ main/pkgwriter.c | 31 ++++++++--- 7 files changed, 233 insertions(+), 11 deletions(-) create mode 100644 main/cmd/pack/desc.c create mode 100644 main/cmd/pack/write_hdr.c diff --git a/Makefile.am b/Makefile.am index e8856ab..13144f5 100644 --- a/Makefile.am +++ b/Makefile.am @@ -25,7 +25,8 @@ EXTRA_DIST = autogen.sh pkg_SOURCES += main/cmd/pack/filelist.c main/cmd/pack/filelist_read.c pkg_SOURCES += main/cmd/pack/write_toc.c main/cmd/pack/write_files.c pkg_SOURCES += main/cmd/pack/pack.h main/cmd/pack/pack.c -pkg_SOURCES += main/cmd/pack/input_file.c +pkg_SOURCES += main/cmd/pack/input_file.c main/cmd/pack/desc.c +pkg_SOURCES += main/cmd/pack/write_hdr.c # dump command pkg_SOURCES += main/cmd/dump/dump.c main/cmd/dump/dump.h main/cmd/dump/dump_toc.c diff --git a/include/pkgformat.h b/include/pkgformat.h index bdeadbb..416ef18 100644 --- a/include/pkgformat.h +++ b/include/pkgformat.h @@ -18,6 +18,10 @@ typedef enum { PKG_COMPRESSION_LZMA = 2, } PKG_COMPRESSION; +typedef enum { + PKG_DEPENDENCY_REQUIRES = 0, +} PKG_DEPENDENCY_TYPE; + typedef struct { uint32_t magic; uint8_t compression; @@ -54,4 +58,15 @@ typedef struct { /* uint8_t data[]; */ } file_data_t; +typedef struct { + uint16_t num_depends; + /* pkg_dependency_t depends[]; */ +} pkg_header_t; + +typedef struct { + uint8_t type; + uint8_t name_length; + /* uint8_t name[]; */ +} pkg_dependency_t; + #endif /* PKG_FORMAT_H */ diff --git a/main/cmd/pack/desc.c b/main/cmd/pack/desc.c new file mode 100644 index 0000000..5a0a004 --- /dev/null +++ b/main/cmd/pack/desc.c @@ -0,0 +1,113 @@ +#include "pack.h" + +static int handle_requires(input_file_t *f, pkg_desc_t *desc) +{ + char *ptr = f->line, *end; + dependency_t *dep; + size_t len; + + while (*ptr != '\0') { + while (isspace(*ptr)) + ++ptr; + end = ptr; + while (*end != '\0' && !isspace(*end)) + ++end; + + len = end - ptr; + if (len == 0) + break; + + if (len > 0xFF) { + fprintf(stderr, "%s: %zu: dependency name too long\n", + f->filename, f->linenum); + return -1; + } + + dep = calloc(1, sizeof(*dep) + len + 1); + if (dep == NULL) { + fprintf(stderr, "%s: %zu: out of memory\n", + f->filename, f->linenum); + return -1; + } + + memcpy(dep->name, ptr, len); + dep->type = PKG_DEPENDENCY_REQUIRES; + dep->next = desc->deps; + desc->deps = dep; + + ptr = end; + } + + return 0; +} + +static const struct { + const char *name; + int (*handle)(input_file_t *f, pkg_desc_t *desc); +} line_hooks[] = { + { "requires", handle_requires }, +}; + +#define NUM_LINE_HOOKS (sizeof(line_hooks) / sizeof(line_hooks[0])) + +int desc_read(const char *path, pkg_desc_t *desc) +{ + input_file_t f; + size_t i, len; + char *ptr; + int ret; + + memset(desc, 0, sizeof(*desc)); + + if (open_file(&f, path)) + return -1; + + for (;;) { + ret = prefetch_line(&f); + if (ret < 0) + goto fail; + if (ret > 0) + break; + + ptr = f.line; + + for (i = 0; i < NUM_LINE_HOOKS; ++i) { + len = strlen(line_hooks[i].name); + + if (strncmp(ptr, line_hooks[i].name, len) != 0) + continue; + if (!isspace(ptr[len]) && ptr[len] != '\0') + continue; + for (ptr += len; isspace(*ptr); ++ptr) + ; + memmove(f.line, ptr, strlen(ptr) + 1); + break; + } + + if (i == NUM_LINE_HOOKS) { + fprintf(stderr, "%s: %zu: unknown description field\n", + f.filename, f.linenum); + goto fail; + } + + ret = line_hooks[i].handle(&f, desc); + if (ret) + goto fail; + } + + return 0; +fail: + return -1; +} + +void desc_free(pkg_desc_t *desc) +{ + dependency_t *dep; + + while (desc->deps != NULL) { + dep = desc->deps; + desc->deps = dep->next; + + free(dep); + } +} diff --git a/main/cmd/pack/pack.c b/main/cmd/pack/pack.c index a2a55fd..360c5fd 100644 --- a/main/cmd/pack/pack.c +++ b/main/cmd/pack/pack.c @@ -3,12 +3,13 @@ static const struct option long_opts[] = { { "toc-compressor", required_argument, NULL, 't' }, { "file-compressor", required_argument, NULL, 'f' }, + { "description", required_argument, NULL, 'd' }, { "file-list", required_argument, NULL, 'l' }, { "output", required_argument, NULL, 'o' }, { NULL, 0, NULL, 0 }, }; -static const char *short_opts = "t:f:l:o:"; +static const char *short_opts = "t:f:l:o:d:"; static compressor_t *get_default_compressor(void) { @@ -61,10 +62,11 @@ static int alloc_file_ids(image_entry_t *list) static int cmd_pack(int argc, char **argv) { - const char *filelist = NULL, *filename = NULL; + const char *filelist = NULL, *filename = NULL, *descfile = NULL; compressor_t *cmp_toc, *cmp_files; image_entry_t *list; pkg_writer_t *wr; + pkg_desc_t desc; int i; cmp_toc = get_default_compressor(); @@ -97,12 +99,21 @@ static int cmd_pack(int argc, char **argv) case 'o': filename = optarg; break; + case 'd': + descfile = optarg; + break; default: tell_read_help(argv[0]); return EXIT_FAILURE; } } + if (descfile == NULL) { + fputs("missing argument: package description file\n", stderr); + tell_read_help(argv[0]); + return EXIT_FAILURE; + } + if (filename == NULL) { fputs("missing argument: output package file\n", stderr); tell_read_help(argv[0]); @@ -118,9 +129,12 @@ static int cmd_pack(int argc, char **argv) if (optind < argc) fputs("warning: ignoring extra arguments\n", stderr); + if (desc_read(descfile, &desc)) + return EXIT_FAILURE; + list = filelist_read(filelist); if (list == NULL) - return EXIT_FAILURE; + goto fail_desc; list = image_entry_sort(list); @@ -131,6 +145,9 @@ static int cmd_pack(int argc, char **argv) if (wr == NULL) goto fail_fp; + if (write_header_data(wr, &desc)) + goto fail; + if (write_toc(wr, list, cmp_toc)) goto fail; @@ -139,11 +156,14 @@ static int cmd_pack(int argc, char **argv) pkg_writer_close(wr); image_entry_free_list(list); + desc_free(&desc); return EXIT_SUCCESS; fail: pkg_writer_close(wr); fail_fp: image_entry_free_list(list); +fail_desc: + desc_free(&desc); return EXIT_FAILURE; } diff --git a/main/cmd/pack/pack.h b/main/cmd/pack/pack.h index 813271a..2accccf 100644 --- a/main/cmd/pack/pack.h +++ b/main/cmd/pack/pack.h @@ -28,6 +28,16 @@ typedef struct { size_t linenum; } input_file_t; +typedef struct dependency_t { + struct dependency_t *next; + int type; + char name[]; +} dependency_t; + +typedef struct { + dependency_t *deps; +} pkg_desc_t; + image_entry_t *filelist_mkdir(input_file_t *f); image_entry_t *filelist_mkslink(input_file_t *f); @@ -46,4 +56,10 @@ void cleanup_file(input_file_t *f); int open_file(input_file_t *f, const char *filename); +int desc_read(const char *path, pkg_desc_t *desc); + +void desc_free(pkg_desc_t *desc); + +int write_header_data(pkg_writer_t *wr, pkg_desc_t *desc); + #endif /* PACK_H */ diff --git a/main/cmd/pack/write_hdr.c b/main/cmd/pack/write_hdr.c new file mode 100644 index 0000000..b374d22 --- /dev/null +++ b/main/cmd/pack/write_hdr.c @@ -0,0 +1,40 @@ +#include "pack.h" + +int write_header_data(pkg_writer_t *wr, pkg_desc_t *desc) +{ + pkg_dependency_t pkgdep; + size_t dep_count = 0; + dependency_t *dep; + pkg_header_t hdr; + + for (dep = desc->deps; dep != NULL; dep = dep->next) + dep_count += 1; + + if (dep_count > 0xFFFF) { + fputs("too many package dependencies\n", stderr); + return -1; + } + + memset(&hdr, 0, sizeof(hdr)); + hdr.num_depends = htole16(dep_count); + + if (pkg_writer_write_payload(wr, &hdr, sizeof(hdr))) + return -1; + + for (dep = desc->deps; dep != NULL; dep = dep->next) { + memset(&pkgdep, 0, sizeof(pkgdep)); + + pkgdep.type = dep->type; + pkgdep.name_length = strlen(dep->name); + + if (pkg_writer_write_payload(wr, &pkgdep, sizeof(pkgdep))) + return -1; + + if (pkg_writer_write_payload(wr, dep->name, + pkgdep.name_length)) { + return -1; + } + } + + return pkg_writer_end_record(wr); +} diff --git a/main/pkgwriter.c b/main/pkgwriter.c index 3fda222..4ca9c8f 100644 --- a/main/pkgwriter.c +++ b/main/pkgwriter.c @@ -81,30 +81,47 @@ static int flush_to_file(pkg_writer_t *wr) pkg_writer_t *pkg_writer_open(const char *path) { pkg_writer_t *wr = calloc(1, sizeof(*wr)); + compressor_t *cmp; + + cmp = compressor_by_id(PKG_COMPRESSION_NONE); + if (cmp == NULL) { + fputs("missing built in dummy compessor\n", stderr); + return NULL; + } if (wr == NULL) { fputs("out of memory\n", stderr); return NULL; } + wr->stream = cmp->compression_stream(cmp); + if (wr->stream == NULL) { + fputs("error creating compressor stream for package header\n", + stderr); + goto fail; + } + wr->fd = open(path, O_WRONLY | O_CREAT | O_EXCL, 0644); if (wr->fd == -1) { perror(path); - free(wr); - return NULL; + goto fail_stream; } wr->path = path; wr->current.magic = PKG_MAGIC_HEADER; wr->current.compression = PKG_COMPRESSION_NONE; - if (write_header(wr)) { - close(wr->fd); - free(wr); - return NULL; - } + if (write_header(wr)) + goto fail_close; return wr; +fail_close: + close(wr->fd); +fail_stream: + wr->stream->destroy(wr->stream); +fail: + free(wr); + return NULL; } void pkg_writer_close(pkg_writer_t *wr)