From 3b00c0dc808f4b6c3809c91a67709ca2d7bf8865 Mon Sep 17 00:00:00 2001 From: Timo Teräs Date: Fri, 16 Jul 2021 19:01:41 +0300 Subject: adb: unify various interfaces to adb_m_process Removes code duplication, and puts important checks in one place. Support seamless decompression in adbdump. --- src/Makefile | 2 +- src/adb.c | 175 ++++++++++++++++++++++++------------------------- src/adb.h | 32 ++++----- src/adb_walk_adb.c | 107 +++++++++++++++--------------- src/adb_walk_istream.c | 131 ------------------------------------ src/adb_walk_text.c | 131 ++++++++++++++++++++++++++++++++++++ src/apk_io.h | 7 +- src/app_adbdump.c | 30 +++------ src/app_adbsign.c | 51 ++++++++------ src/app_extract.c | 7 +- src/app_mkndx.c | 4 +- src/io.c | 53 ++++++++++++--- src/meson.build | 2 +- 13 files changed, 382 insertions(+), 350 deletions(-) delete mode 100644 src/adb_walk_istream.c create mode 100644 src/adb_walk_text.c diff --git a/src/Makefile b/src/Makefile index 79ff5d6..970354b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,7 +19,7 @@ ZLIB_LIBS := $(shell $(PKG_CONFIG) --libs zlib) libapk_soname := 2.99.0 libapk_so := $(obj)/libapk.so.$(libapk_soname) libapk.so.$(libapk_soname)-objs := \ - adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_istream.o apk_adb.o \ + adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_text.o apk_adb.o \ atom.o blob.o commit.o common.o context.o crypto_openssl.o database.o hash.o \ io.o io_archive.o io_gunzip.o io_url.o \ package.o pathbuilder.o print.o solver.o trust.o version.o diff --git a/src/adb.c b/src/adb.c index 77ceb63..3a7c684 100644 --- a/src/adb.c +++ b/src/adb.c @@ -26,22 +26,27 @@ static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_bl return blk; } -struct adb_block *adb_block_first(apk_blob_t b) +static struct adb_block *adb_block_first(apk_blob_t b) { return adb_block_validate((struct adb_block*)b.ptr, b); } -struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b) +static struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b) { return adb_block_validate((struct adb_block*)((char*)cur + adb_block_size(cur)), b); } +#define adb_foreach_block(__blk, __adb) \ + for (__blk = adb_block_first(__adb); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb)) + /* Init stuff */ int adb_free(struct adb *db) { - if (db->mmap.ptr) { - munmap(db->mmap.ptr, db->mmap.len); + if (db->is) { + // read-only adb + apk_istream_close(db->is); } else { + // writable adb struct adb_w_bucket *bucket, *nxt; int i; for (i = 0; i < db->num_buckets; i++) @@ -65,14 +70,16 @@ void adb_reset(struct adb *db) db->adb.len = 0; } -static int __adb_m_parse(struct adb *db, struct apk_trust *t) +static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t, + int (*cb)(struct adb *, struct adb_block *, struct apk_istream *)) { struct adb_verify_ctx vfy = {}; struct adb_block *blk; + struct apk_istream is; int r = -APKE_ADB_BLOCK; int trusted = t ? 0 : 1; - adb_foreach_block(blk, db->data) { + adb_foreach_block(blk, data) { apk_blob_t b = adb_block_blob(blk); switch (adb_block_type(blk)) { case ADB_BLOCK_ADB: @@ -89,12 +96,15 @@ static int __adb_m_parse(struct adb *db, struct apk_trust *t) if (APK_BLOB_IS_NULL(db->adb)) break; break; } + r = cb(db, blk, apk_istream_from_blob(&is, b)); + if (r < 0) goto err; } if (IS_ERR(blk)) r = PTR_ERR(blk); else if (!trusted) r = -APKE_SIGNATURE_UNTRUSTED; else if (db->adb.ptr) r = 0; if (r != 0) { + err: db->adb = APK_BLOB_NULL; } return r; @@ -102,31 +112,27 @@ static int __adb_m_parse(struct adb *db, struct apk_trust *t) int adb_m_blob(struct adb *db, apk_blob_t blob, struct apk_trust *t) { - *db = (struct adb) { .data = blob }; - return __adb_m_parse(db, t); + adb_init(db); + return __adb_m_parse(db, blob, t, 0); } -int adb_m_map(struct adb *db, int fd, uint32_t expected_schema, struct apk_trust *t) +static int __adb_m_mmap(struct adb *db, apk_blob_t mmap, uint32_t expected_schema, struct apk_trust *t, + int (*cb)(struct adb *, struct adb_block *, struct apk_istream *)) { - struct stat st; struct adb_header *hdr; int r = -APKE_ADB_HEADER; + apk_blob_t data = mmap; + + if (!(expected_schema & ADB_SCHEMA_IMPLIED)) { + if (mmap.len < sizeof *hdr) return -APKE_ADB_HEADER; + hdr = (struct adb_header *) mmap.ptr; + if (hdr->magic != htole32(ADB_FORMAT_MAGIC)) return -APKE_ADB_HEADER; + if (expected_schema && expected_schema != le32toh(hdr->schema)) return -APKE_ADB_SCHEMA; + db->hdr = *hdr; + data = APK_BLOB_PTR_LEN(mmap.ptr + sizeof *hdr, mmap.len - sizeof *hdr); + } - if (fstat(fd, &st) != 0) return -errno; - if (st.st_size < sizeof *hdr) return -EIO; - - memset(db, 0, sizeof *db); - db->mmap.ptr = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); - db->mmap.len = st.st_size; - if (db->mmap.ptr == MAP_FAILED) return -errno; - - hdr = (struct adb_header *) db->mmap.ptr; - if (hdr->magic != htole32(ADB_FORMAT_MAGIC)) goto err; - if (expected_schema && expected_schema != le32toh(hdr->schema)) goto err; - - db->hdr = *hdr; - db->data = APK_BLOB_PTR_LEN(db->mmap.ptr + sizeof *hdr, db->mmap.len - sizeof *hdr); - r = __adb_m_parse(db, t); + r = __adb_m_parse(db, data, t, cb); if (r) goto err; return 0; err: @@ -134,8 +140,8 @@ err: return r; } -int adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schema, - struct apk_trust *t, int (*datacb)(struct adb *, size_t, struct apk_istream *)) +static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schema, + struct apk_trust *t, int (*cb)(struct adb *, struct adb_block *, struct apk_istream *)) { struct adb_verify_ctx vfy = {}; struct adb_block blk; @@ -146,8 +152,18 @@ int adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schem size_t sz; if (IS_ERR(is)) return PTR_ERR(is); - if ((r = apk_istream_read(is, &db->hdr, sizeof db->hdr)) != sizeof db->hdr) goto err; - if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) goto bad_msg; + + if (!(expected_schema & ADB_SCHEMA_IMPLIED)) { + if ((r = apk_istream_read(is, &db->hdr, sizeof db->hdr)) != sizeof db->hdr) goto err; + if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) { + r = -APKE_ADB_HEADER; + goto err; + } + if (expected_schema && expected_schema != le32toh(db->hdr.schema)) { + r = -APKE_ADB_SCHEMA; + goto err; + } + } do { r = apk_istream_read(is, &blk, sizeof blk); @@ -168,10 +184,12 @@ int adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schem db->adb.ptr = malloc(sz); db->adb.len = adb_block_length(&blk); if ((r = apk_istream_read(is, db->adb.ptr, sz)) != sz) goto err; - break; + r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb)); + if (r < 0) goto err; + continue; case ADB_BLOCK_SIG: if (APK_BLOB_IS_NULL(db->adb)) goto bad_msg; - sig = apk_istream_get(is, sz); + sig = apk_istream_peek(is, sz); if (IS_ERR(sig)) { r = PTR_ERR(sig); goto err; @@ -186,17 +204,16 @@ int adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schem r = -APKE_SIGNATURE_UNTRUSTED; goto err; } - r = datacb(db, adb_block_length(&blk), - apk_istream_segment(&seg, is, adb_block_size(&blk) - sizeof blk, 0)); - if (r < 0) goto err; - if (seg.bytes_left) { - r = apk_istream_read(is, NULL, seg.bytes_left); - if (r < 0) goto err; - } break; default: goto bad_msg; } + + apk_istream_segment(&seg, is, adb_block_size(&blk) - sizeof blk, 0); + r = cb(db, &blk, &seg.is); + if (r < 0) goto err; + r = apk_istream_close(&seg.is); + if (r < 0) goto err; } while (1); bad_msg: r = -APKE_ADB_BLOCK; @@ -207,6 +224,30 @@ done: return r; } +static int __adb_dummy_cb(struct adb *db, struct adb_block *b, struct apk_istream *is) +{ + return 0; +} + +int adb_m_process(struct adb *db, struct apk_istream *is, uint32_t expected_schema, + struct apk_trust *t, int (*cb)(struct adb *, struct adb_block *, struct apk_istream *)) +{ + apk_blob_t mmap = apk_istream_mmap(is); + memset(db, 0, sizeof *db); + if (expected_schema & ADB_SCHEMA_IMPLIED) { + db->hdr = (struct adb_header) { + .magic = ADB_FORMAT_MAGIC, + .schema = expected_schema & ~ADB_SCHEMA_IMPLIED, + }; + } + if (!cb) cb = __adb_dummy_cb; + if (!APK_BLOB_IS_NULL(mmap)) { + db->is = is; + return __adb_m_mmap(db, mmap, expected_schema, t, cb); + } + return __adb_m_stream(db, is, expected_schema, t, cb); +} + int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets) { size_t i; @@ -231,7 +272,7 @@ int adb_w_init_static(struct adb *db, void *buf, size_t bufsz) *db = (struct adb) { .hdr.magic = htole32(ADB_FORMAT_MAGIC), .adb.ptr = buf, - .mmap.len = bufsz, + .alloc_len = bufsz, }; return 0; } @@ -488,12 +529,12 @@ static size_t adb_w_raw(struct adb *db, struct iovec *vec, size_t n, size_t len, db->adb.len += i; } - if (db->adb.len + len > db->mmap.len) { + if (db->adb.len + len > db->alloc_len) { assert(db->num_buckets); - if (!db->mmap.len) db->mmap.len = 8192; - while (db->adb.len + len > db->mmap.len) - db->mmap.len *= 2; - ptr = realloc(db->adb.ptr, db->mmap.len); + if (!db->alloc_len) db->alloc_len = 8192; + while (db->adb.len + len > db->alloc_len) + db->alloc_len *= 2; + ptr = realloc(db->adb.ptr, db->alloc_len); assert(ptr); db->adb.ptr = ptr; } @@ -1093,49 +1134,3 @@ int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct a return -APKE_SIGNATURE_UNTRUSTED; } - -/* Container transformation interface */ -int adb_c_xfrm(struct adb_xfrm *x, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *)) -{ - struct adb_block blk; - struct apk_segment_istream seg; - int r, block_no = 0; - size_t sz; - - r = apk_istream_read(x->is, &x->db.hdr, sizeof x->db.hdr); - if (r != sizeof x->db.hdr) goto err; - - if (x->db.hdr.magic != htole32(ADB_FORMAT_MAGIC)) goto bad_msg; - r = apk_ostream_write(x->os, &x->db.hdr, sizeof x->db.hdr); - if (r < 0) goto err; - - do { - r = apk_istream_read(x->is, &blk, sizeof blk); - if (r != sizeof blk) { - if (r != 0) goto err; - return cb(x, NULL, NULL); - } - - if ((block_no++ == 0) != (adb_block_type(&blk) == ADB_BLOCK_ADB)) goto bad_msg; - - sz = adb_block_size(&blk) - sizeof blk; - r = cb(x, &blk, apk_istream_segment(&seg, x->is, sz, 0)); - if (r < 0) goto err; - - if (r == 0 && seg.bytes_left == sz) { - r = apk_ostream_write(x->os, &blk, sizeof blk); - if (r < 0) goto err; - r = apk_stream_copy(x->is, x->os, sz, 0, 0, 0); - if (r < 0) goto err; - } else if (seg.bytes_left > 0) { - r = apk_istream_read(x->is, NULL, seg.bytes_left); - if (r != seg.bytes_left) goto err; - } - } while (1); -bad_msg: - r = -APKE_ADB_BLOCK; -err: - if (r >= 0) r = -APKE_ADB_BLOCK; - apk_ostream_cancel(x->os, r); - return r; -} diff --git a/src/adb.h b/src/adb.h index 9cb73b4..fd5462b 100644 --- a/src/adb.h +++ b/src/adb.h @@ -44,6 +44,7 @@ typedef uint32_t adb_val_t; /* File Header */ #define ADB_FORMAT_MAGIC 0x2e424441 // ADB. +#define ADB_SCHEMA_IMPLIED 0x80000000 struct adb_header { uint32_t magic; @@ -52,7 +53,6 @@ struct adb_header { /* Blocks */ #define ADB_BLOCK_ALIGNMENT 8 -#define ADB_BLOCK_END -1 #define ADB_BLOCK_ADB 0 #define ADB_BLOCK_SIG 2 #define ADB_BLOCK_DATA 3 @@ -86,12 +86,6 @@ struct adb_sign_v0 { uint8_t sig[0]; }; -/* Block enumeration */ -struct adb_block *adb_block_first(apk_blob_t b); -struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b); -#define adb_foreach_block(__blk, __adb) \ - for (__blk = adb_block_first(__adb); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb)) - /* Schema */ #define ADB_KIND_ADB 1 #define ADB_KIND_OBJECT 2 @@ -144,9 +138,11 @@ struct adb_w_bucket { }; struct adb { - apk_blob_t mmap, data, adb; + struct apk_istream *is; + apk_blob_t adb; struct adb_header hdr; size_t num_buckets; + size_t alloc_len; struct list_head *bucket; }; @@ -158,12 +154,15 @@ struct adb_obj { }; /* Container read interface */ +static inline void adb_init(struct adb *db) { memset(db, 0, sizeof *db); } int adb_free(struct adb *); void adb_reset(struct adb *); int adb_m_blob(struct adb *, apk_blob_t, struct apk_trust *); -int adb_m_map(struct adb *, int fd, uint32_t expected_schema, struct apk_trust *); -int adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expected_schema, struct apk_trust *trust, int (*datacb)(struct adb *, size_t, struct apk_istream *)); +int adb_m_process(struct adb *db, struct apk_istream *is, uint32_t expected_schema, struct apk_trust *trust, int (*cb)(struct adb *, struct adb_block *, struct apk_istream *)); +static inline int adb_m_open(struct adb *db, struct apk_istream *is, uint32_t expected_schema, struct apk_trust *trust) { + return adb_m_process(db, is, expected_schema, trust, 0); +} #define adb_w_init_alloca(db, schema, num_buckets) adb_w_init_dynamic(db, schema, alloca(sizeof(struct list_head[num_buckets])), num_buckets) #define adb_w_init_tmp(db, size) adb_w_init_static(db, alloca(size), size) int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets); @@ -240,15 +239,6 @@ struct adb_verify_ctx { int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, struct apk_ostream *os); int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct adb_verify_ctx *vfy, apk_blob_t sigb); -/* Transform existing file */ -struct adb_xfrm { - struct apk_istream *is; - struct apk_ostream *os; - struct adb db; - struct adb_verify_ctx vfy; -}; -int adb_c_xfrm(struct adb_xfrm *, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *)); - /* SAX style event based handling of ADB */ struct adb_db_schema { @@ -297,8 +287,8 @@ struct adb_walk_genadb { adb_val_t vals[ADB_WALK_GENADB_MAX_VALUES]; }; -int adb_walk_adb(struct adb_walk *d, struct adb *db, struct apk_trust *trust); -int adb_walk_istream(struct adb_walk *d, struct apk_istream *is); +int adb_walk_adb(struct adb_walk *d, struct apk_istream *is, struct apk_trust *trust); +int adb_walk_text(struct adb_walk *d, struct apk_istream *is); // Seamless compression support diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c index 2b3b34b..306c496 100644 --- a/src/adb_walk_adb.c +++ b/src/adb_walk_adb.c @@ -8,19 +8,21 @@ struct adb_walk_ctx { struct adb_walk *d; - struct adb *db; struct apk_trust *trust; + struct adb db; + struct adb_verify_ctx vfy; }; +static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istream *is); static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema *schema, adb_val_t v); -static int dump_adb(struct adb_walk_ctx *ctx); static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t *kind, adb_val_t v) { struct adb_walk *d = ctx->d; - struct adb db, *origdb; + struct adb origdb; struct adb_obj o; struct adb_object_schema *obj_schema; + struct apk_istream is; char tmp[256]; apk_blob_t b; @@ -31,7 +33,7 @@ static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t * switch (*kind) { case ADB_KIND_ARRAY: obj_schema = container_of(kind, struct adb_object_schema, kind); - adb_r_obj(ctx->db, v, &o, obj_schema); + adb_r_obj(&ctx->db, v, &o, obj_schema); //if (!adb_ra_num(&o)) return 0; d->ops->start_array(d, adb_ra_num(&o)); @@ -41,12 +43,12 @@ static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t * d->ops->end(d); break; case ADB_KIND_ADB: - db.hdr.schema = container_of(kind, struct adb_adb_schema, kind)->schema_id; - db.data = adb_r_blob(ctx->db, v); + apk_istream_from_blob(&is, adb_r_blob(&ctx->db, v)); origdb = ctx->db; - ctx->db = &db; d->ops->start_object(d); - dump_adb(ctx); + adb_m_process(&ctx->db, &is, + container_of(kind, struct adb_adb_schema, kind)->schema_id | ADB_SCHEMA_IMPLIED, + 0, adb_walk_block); d->ops->end(d); ctx->db = origdb; break; @@ -64,7 +66,7 @@ static int dump_item(struct adb_walk_ctx *ctx, const char *name, const uint8_t * case ADB_KIND_INT:; struct adb_scalar_schema *scalar = container_of(kind, struct adb_scalar_schema, kind); if (scalar->tostring) { - b = scalar->tostring(ctx->db, v, tmp, sizeof tmp); + b = scalar->tostring(&ctx->db, v, tmp, sizeof tmp); } else { b = APK_BLOB_STR("(unknown)"); } @@ -83,7 +85,7 @@ static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema apk_blob_t b; struct adb_walk *d = ctx->d; - adb_r_obj(ctx->db, v, &o, schema); + adb_r_obj(&ctx->db, v, &o, schema); if (schema) { if (schema->tostring) { b = schema->tostring(&o, tmp, sizeof tmp); @@ -104,63 +106,60 @@ static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema return 0; } -static int dump_adb(struct adb_walk_ctx *ctx) +static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istream *is) { + struct adb_walk_ctx *ctx = container_of(db, struct adb_walk_ctx, db); + struct adb_walk *d = ctx->d; char tmp[16+ADB_MAX_SIGNATURE_LEN*2]; - struct adb_block *blk; struct adb_sign_hdr *s; - struct adb_verify_ctx vfy = {}; - uint32_t schema_magic = ctx->db->hdr.schema; + uint32_t schema_magic = ctx->db.hdr.schema; const struct adb_db_schema *ds; - struct adb_walk *d = ctx->d; int r, len; + size_t sz = adb_block_length(b); + apk_blob_t data; - for (ds = d->schemas; ds->magic; ds++) - if (ds->magic == schema_magic) break; - - adb_foreach_block(blk, ctx->db->data) { - apk_blob_t b = adb_block_blob(blk); - switch (adb_block_type(blk)) { - case ADB_BLOCK_ADB: - len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", adb_block_length(blk)); - d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); - if (ds->root) { - ctx->db->adb = b; - dump_object(ctx, ds->root, adb_r_root(ctx->db)); - } - break; - case ADB_BLOCK_SIG: - s = (struct adb_sign_hdr*) b.ptr; - r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b); - len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg); - for (size_t j = sizeof *s; j < b.len; j++) - len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)b.ptr[j]); - len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK"); - d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); - break; - case ADB_BLOCK_DATA: - len = snprintf(tmp, sizeof tmp, "data block, size: %d", adb_block_length(blk)); - d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); - break; - default: - len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %d", - adb_block_type(blk), adb_block_length(blk)); - d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); - } - } - if (IS_ERR(blk)) { - d->ops->comment(d, APK_BLOB_STRLIT("block enumeration error: corrupt data area")); + switch (adb_block_type(b)) { + case ADB_BLOCK_ADB: + d->ops->schema(d, db->hdr.schema); + for (ds = d->schemas; ds->magic; ds++) + if (ds->magic == schema_magic) break; + len = snprintf(tmp, sizeof tmp, "ADB block, size: %zu", sz); + d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); + if (ds->root) dump_object(ctx, ds->root, adb_r_root(db)); + break; + case ADB_BLOCK_SIG: + s = (struct adb_sign_hdr*) apk_istream_get(is, sz); + data = APK_BLOB_PTR_LEN((char*)s, sz); + r = adb_trust_verify_signature(ctx->trust, db, &ctx->vfy, data); + len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg); + for (size_t j = sizeof *s; j < data.len; j++) + len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)data.ptr[j]); + len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK"); + d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); + break; + case ADB_BLOCK_DATA: + len = snprintf(tmp, sizeof tmp, "data block, size: %zu", sz); + d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); + break; + default: + len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %zu", + adb_block_type(b), sz); + d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len)); } return 0; } -int adb_walk_adb(struct adb_walk *d, struct adb *db, struct apk_trust *trust) +int adb_walk_adb(struct adb_walk *d, struct apk_istream *is, struct apk_trust *trust) { struct adb_walk_ctx ctx = { .d = d, - .db = db, .trust = trust, }; - d->ops->schema(d, db->hdr.schema); - return dump_adb(&ctx); + int r; + + if (IS_ERR(is)) return PTR_ERR(is); + + r = adb_m_process(&ctx.db, is, 0, 0, adb_walk_block); + adb_free(&ctx.db); + return r; } diff --git a/src/adb_walk_istream.c b/src/adb_walk_istream.c deleted file mode 100644 index b85565f..0000000 --- a/src/adb_walk_istream.c +++ /dev/null @@ -1,131 +0,0 @@ -#include -#include "adb.h" - -//#define DEBUG_PRINT -#ifdef DEBUG_PRINT -#include -#define dbg_printf(args...) fprintf(stderr, args) -#else -#define dbg_printf(args...) -#endif - -int adb_walk_istream(struct adb_walk *d, struct apk_istream *is) -{ - const apk_blob_t token = APK_BLOB_STR("\n"); - const apk_blob_t comment = APK_BLOB_STR(" #"); - const apk_blob_t key_sep = APK_BLOB_STR(": "); - char mblockdata[1024*4]; - apk_blob_t l, comm, mblock = APK_BLOB_BUF(mblockdata); - int r = 0, i, multi_line = 0, nesting = 0, new_item = 0; - uint8_t started[64] = {0}; - - if (IS_ERR_OR_NULL(is)) return PTR_ERR(is); - l = apk_istream_get_delim(is, token); - apk_blob_pull_blob_match(&l, APK_BLOB_STR("#%SCHEMA: ")); - if ((r = d->ops->schema(d, apk_blob_pull_uint(&l, 16))) != 0) goto err; - - started[0] = 1; - while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, token))) { - for (i = 0; l.len >= 2 && l.ptr[0] == ' ' && l.ptr[1] == ' '; i++, l.ptr += 2, l.len -= 2) - if (multi_line && i >= multi_line) break; - - for (; nesting > i; nesting--) { - if (multi_line) { - apk_blob_t data = apk_blob_pushed(APK_BLOB_BUF(mblockdata), mblock); - if (APK_BLOB_IS_NULL(data)) { - r = -E2BIG; - goto err; - } - if (data.len && data.ptr[data.len-1] == '\n') data.len--; - dbg_printf("Multiline-Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(data)); - if ((r = d->ops->scalar(d, data, 1)) != 0) goto err; - mblock = APK_BLOB_BUF(mblockdata); - multi_line = 0; - } - if (started[nesting]) { - dbg_printf("End %d\n", nesting); - if ((r = d->ops->end(d)) != 0) goto err; - } - } - if (l.ptr[0] == '-' && l.ptr[1] == ' ') { - l.ptr += 2, l.len -= 2; - if (!started[nesting]) { - dbg_printf("Array %d\n", nesting); - if ((r = d->ops->start_array(d, 0)) != 0) goto err; - started[nesting] = 1; - } - new_item = 1; - } - dbg_printf(" >%d/%d< >"BLOB_FMT"<\n", nesting, i, BLOB_PRINTF(l)); - - if (multi_line) { - dbg_printf("Scalar-Block:>%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(l)); - apk_blob_push_blob(&mblock, l); - apk_blob_push_blob(&mblock, APK_BLOB_STR("\n")); - new_item = 0; - continue; - } - - if (l.ptr[0] == '#') { - if ((r = d->ops->comment(d, l)) != 0) goto err; - continue; - } - - // contains ' #' -> comment - if (!apk_blob_split(l, comment, &l, &comm)) - comm.len = 0; - - if (l.len) { - apk_blob_t key = APK_BLOB_NULL, scalar = APK_BLOB_NULL; - int start = 0; - - if (apk_blob_split(l, key_sep, &key, &scalar)) { - // contains ': ' -> key + scalar - } else if (l.ptr[l.len-1] == ':') { - // ends ':' -> key + indented object/array - key = APK_BLOB_PTR_LEN(l.ptr, l.len-1); - start = 1; - } else { - scalar = l; - } - if (key.len) { - if (new_item) { - started[++nesting] = 0; - dbg_printf("Array-Object %d\n", nesting); - } - if (!started[nesting]) { - dbg_printf("Object %d\n", nesting); - if ((r = d->ops->start_object(d)) != 0) goto err; - started[nesting] = 1; - } - dbg_printf("Key >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(key)); - if ((r = d->ops->key(d, key)) != 0) goto err; - if (start) started[++nesting] = 0; - } - - if (scalar.len) { - if (scalar.ptr[0] == '|') { - dbg_printf("Scalar-block >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar)); - // scalar '|' -> starts string literal block - started[++nesting] = 0; - multi_line = nesting; - } else { - dbg_printf("Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar)); - if ((r = d->ops->scalar(d, scalar, 0)) != 0) goto err; - } - } - new_item = 0; - } - - if (comm.len) { - if ((r = d->ops->comment(d, comm)) != 0) goto err; - } - - //fprintf(stderr, ">%d> "BLOB_FMT"\n", indent, BLOB_PRINTF(l)); - } - d->ops->end(d); - -err: - if (r) apk_istream_error(is, r); - return apk_istream_close(is); -} diff --git a/src/adb_walk_text.c b/src/adb_walk_text.c new file mode 100644 index 0000000..b713f10 --- /dev/null +++ b/src/adb_walk_text.c @@ -0,0 +1,131 @@ +#include +#include "adb.h" + +//#define DEBUG_PRINT +#ifdef DEBUG_PRINT +#include +#define dbg_printf(args...) fprintf(stderr, args) +#else +#define dbg_printf(args...) +#endif + +int adb_walk_text(struct adb_walk *d, struct apk_istream *is) +{ + const apk_blob_t token = APK_BLOB_STR("\n"); + const apk_blob_t comment = APK_BLOB_STR(" #"); + const apk_blob_t key_sep = APK_BLOB_STR(": "); + char mblockdata[1024*4]; + apk_blob_t l, comm, mblock = APK_BLOB_BUF(mblockdata); + int r = 0, i, multi_line = 0, nesting = 0, new_item = 0; + uint8_t started[64] = {0}; + + if (IS_ERR_OR_NULL(is)) return PTR_ERR(is); + l = apk_istream_get_delim(is, token); + apk_blob_pull_blob_match(&l, APK_BLOB_STR("#%SCHEMA: ")); + if ((r = d->ops->schema(d, apk_blob_pull_uint(&l, 16))) != 0) goto err; + + started[0] = 1; + while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, token))) { + for (i = 0; l.len >= 2 && l.ptr[0] == ' ' && l.ptr[1] == ' '; i++, l.ptr += 2, l.len -= 2) + if (multi_line && i >= multi_line) break; + + for (; nesting > i; nesting--) { + if (multi_line) { + apk_blob_t data = apk_blob_pushed(APK_BLOB_BUF(mblockdata), mblock); + if (APK_BLOB_IS_NULL(data)) { + r = -E2BIG; + goto err; + } + if (data.len && data.ptr[data.len-1] == '\n') data.len--; + dbg_printf("Multiline-Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(data)); + if ((r = d->ops->scalar(d, data, 1)) != 0) goto err; + mblock = APK_BLOB_BUF(mblockdata); + multi_line = 0; + } + if (started[nesting]) { + dbg_printf("End %d\n", nesting); + if ((r = d->ops->end(d)) != 0) goto err; + } + } + if (l.ptr[0] == '-' && l.ptr[1] == ' ') { + l.ptr += 2, l.len -= 2; + if (!started[nesting]) { + dbg_printf("Array %d\n", nesting); + if ((r = d->ops->start_array(d, 0)) != 0) goto err; + started[nesting] = 1; + } + new_item = 1; + } + dbg_printf(" >%d/%d< >"BLOB_FMT"<\n", nesting, i, BLOB_PRINTF(l)); + + if (multi_line) { + dbg_printf("Scalar-Block:>%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(l)); + apk_blob_push_blob(&mblock, l); + apk_blob_push_blob(&mblock, APK_BLOB_STR("\n")); + new_item = 0; + continue; + } + + if (l.ptr[0] == '#') { + if ((r = d->ops->comment(d, l)) != 0) goto err; + continue; + } + + // contains ' #' -> comment + if (!apk_blob_split(l, comment, &l, &comm)) + comm.len = 0; + + if (l.len) { + apk_blob_t key = APK_BLOB_NULL, scalar = APK_BLOB_NULL; + int start = 0; + + if (apk_blob_split(l, key_sep, &key, &scalar)) { + // contains ': ' -> key + scalar + } else if (l.ptr[l.len-1] == ':') { + // ends ':' -> key + indented object/array + key = APK_BLOB_PTR_LEN(l.ptr, l.len-1); + start = 1; + } else { + scalar = l; + } + if (key.len) { + if (new_item) { + started[++nesting] = 0; + dbg_printf("Array-Object %d\n", nesting); + } + if (!started[nesting]) { + dbg_printf("Object %d\n", nesting); + if ((r = d->ops->start_object(d)) != 0) goto err; + started[nesting] = 1; + } + dbg_printf("Key >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(key)); + if ((r = d->ops->key(d, key)) != 0) goto err; + if (start) started[++nesting] = 0; + } + + if (scalar.len) { + if (scalar.ptr[0] == '|') { + dbg_printf("Scalar-block >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar)); + // scalar '|' -> starts string literal block + started[++nesting] = 0; + multi_line = nesting; + } else { + dbg_printf("Scalar >%d> "BLOB_FMT"\n", nesting, BLOB_PRINTF(scalar)); + if ((r = d->ops->scalar(d, scalar, 0)) != 0) goto err; + } + } + new_item = 0; + } + + if (comm.len) { + if ((r = d->ops->comment(d, comm)) != 0) goto err; + } + + //fprintf(stderr, ">%d> "BLOB_FMT"\n", indent, BLOB_PRINTF(l)); + } + d->ops->end(d); + +err: + if (r) apk_istream_error(is, r); + return apk_istream_close(is); +} diff --git a/src/apk_io.h b/src/apk_io.h index 61aee4f..b0971cd 100644 --- a/src/apk_io.h +++ b/src/apk_io.h @@ -87,11 +87,14 @@ typedef int (*apk_archive_entry_parser)(void *ctx, #define APK_ISTREAM_FORCE_REFRESH ((time_t) -1) -struct apk_istream *apk_istream_from_file(int atfd, const char *file); -struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file); +struct apk_istream *apk_istream_from_blob(struct apk_istream *, apk_blob_t); +struct apk_istream *__apk_istream_from_file(int atfd, const char *file, int try_mmap); +static inline struct apk_istream *apk_istream_from_file(int atfd, const char *file) { return __apk_istream_from_file(atfd, file, 0); } +static inline struct apk_istream *apk_istream_from_file_mmap(int atfd, const char *file) { return __apk_istream_from_file(atfd, file, 1); } struct apk_istream *apk_istream_from_fd(int fd); struct apk_istream *apk_istream_from_fd_url_if_modified(int atfd, const char *url, time_t since); static inline int apk_istream_error(struct apk_istream *is, int err) { if (!is->err) is->err = err; return err; } +apk_blob_t apk_istream_mmap(struct apk_istream *is); ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size); void *apk_istream_peek(struct apk_istream *is, size_t len); void *apk_istream_get(struct apk_istream *is, size_t len); diff --git a/src/app_adbdump.c b/src/app_adbdump.c index 39cc074..ce7b5d6 100644 --- a/src/app_adbdump.c +++ b/src/app_adbdump.c @@ -11,24 +11,6 @@ static const struct adb_db_schema dbschemas[] = { {}, }; -static int mmap_and_dump_adb(struct apk_trust *trust, int fd, struct apk_out *out) -{ - struct adb db; - struct adb_walk_gentext td = { - .d.ops = &adb_walk_gentext_ops, - .d.schemas = dbschemas, - .out = out->out, - }; - int r; - - r = adb_m_map(&db, fd, 0, NULL); - if (r) return r; - - adb_walk_adb(&td.d, &db, trust); - adb_free(&db); - return 0; -} - static int adbdump_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args) { struct apk_out *out = &ac->out; @@ -36,7 +18,15 @@ static int adbdump_main(void *pctx, struct apk_ctx *ac, struct apk_string_array int r; foreach_array_item(arg, args) { - r = mmap_and_dump_adb(apk_ctx_get_trust(ac), open(*arg, O_RDONLY), out); + struct adb_walk_gentext td = { + .d.ops = &adb_walk_gentext_ops, + .d.schemas = dbschemas, + .out = out->out, + }; + + r = adb_walk_adb(&td.d, + adb_decompress(apk_istream_from_file_mmap(AT_FDCWD, *arg), 0), + apk_ctx_get_trust(ac)); if (r) { apk_err(out, "%s: %s", *arg, apk_error_str(r)); return r; @@ -68,7 +58,7 @@ static int adbgen_main(void *pctx, struct apk_ctx *ac, struct apk_string_array * foreach_array_item(arg, args) { adb_reset(&genadb.db); adb_reset(&genadb.idb[0]); - r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg)); + r = adb_walk_text(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg)); if (!r) { adb_w_root(&genadb.db, genadb.stored_object); r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db, diff --git a/src/app_adbsign.c b/src/app_adbsign.c index 23bcc8b..82604cd 100644 --- a/src/app_adbsign.c +++ b/src/app_adbsign.c @@ -8,7 +8,12 @@ struct sign_ctx { struct apk_ctx *ac; - struct adb_xfrm xfrm; + + struct adb db; + struct apk_istream *is; + struct apk_ostream *os; + struct adb_verify_ctx vfy; + int reset_signatures : 1; int signatures_written : 1; }; @@ -37,27 +42,34 @@ static const struct apk_option_group optgroup_applet = { .parse = option_parse_applet, }; -static int update_signatures(struct adb_xfrm *xfrm, struct adb_block *blk, struct apk_istream *is) +static int process_signatures(struct sign_ctx *ctx) +{ + int r; + + if (ctx->signatures_written) return 0; + ctx->signatures_written = 1; + r = adb_trust_write_signatures(apk_ctx_get_trust(ctx->ac), &ctx->db, &ctx->vfy, ctx->os); + if (r < 0) apk_ostream_cancel(ctx->os, r); + return r; +} + +static int process_block(struct adb *db, struct adb_block *blk, struct apk_istream *is) { - struct sign_ctx *ctx = container_of(xfrm, struct sign_ctx, xfrm); - struct apk_trust *trust = apk_ctx_get_trust(ctx->ac); + struct sign_ctx *ctx = container_of(db, struct sign_ctx, db); int r; - switch (blk ? adb_block_type(blk) : -1) { + switch (adb_block_type(blk)) { case ADB_BLOCK_ADB: - return adb_c_block_copy(xfrm->os, blk, is, &xfrm->vfy); + adb_c_header(ctx->os, db); + return adb_c_block_copy(ctx->os, blk, is, &ctx->vfy); case ADB_BLOCK_SIG: if (ctx->reset_signatures) break; - return adb_c_block_copy(xfrm->os, blk, is, NULL); + return adb_c_block_copy(ctx->os, blk, is, NULL); default: - if (!ctx->signatures_written) { - ctx->signatures_written = 1; - r = adb_trust_write_signatures(trust, &xfrm->db, &xfrm->vfy, xfrm->os); - if (r) return r; - } - if (!blk) break; - return adb_c_block_copy(xfrm->os, blk, is, NULL); + r = process_signatures(ctx); + if (r < 0) return r; + return adb_c_block_copy(ctx->os, blk, is, NULL); } return 0; } @@ -72,11 +84,12 @@ static int adbsign_main(void *pctx, struct apk_ctx *ac, struct apk_string_array ctx->ac = ac; foreach_array_item(arg, args) { - ctx->xfrm.is = adb_decompress(apk_istream_from_file(AT_FDCWD, *arg), &comp); - ctx->xfrm.os = adb_compress(apk_ostream_to_file(AT_FDCWD, *arg, 0644), comp); - adb_c_xfrm(&ctx->xfrm, update_signatures); - apk_istream_close(ctx->xfrm.is); - r = apk_ostream_close(ctx->xfrm.os); + struct apk_istream *is = adb_decompress(apk_istream_from_file_mmap(AT_FDCWD, *arg), &comp); + ctx->os = adb_compress(apk_ostream_to_file(AT_FDCWD, *arg, 0644), comp); + adb_m_process(&ctx->db, is, 0, 0, process_block); + process_signatures(ctx); + adb_free(&ctx->db); + r = apk_ostream_close(ctx->os); if (r) apk_err(out, "%s: %s", *arg, apk_error_str(r)); } diff --git a/src/app_extract.c b/src/app_extract.c index a68cfbf..9de2bc2 100644 --- a/src/app_extract.c +++ b/src/app_extract.c @@ -287,12 +287,15 @@ static int apk_extract_next_file(struct extract_ctx *ctx) } while (1); } -static int apk_extract_data_block(struct adb *db, size_t sz, struct apk_istream *is) +static int apk_extract_data_block(struct adb *db, struct adb_block *b, struct apk_istream *is) { struct extract_ctx *ctx = container_of(db, struct extract_ctx, db); struct adb_data_package *hdr; + size_t sz = adb_block_length(b); int r; + if (adb_block_type(b) != ADB_BLOCK_DATA) return 0; + r = apk_extract_next_file(ctx); if (r != 0) { if (r > 0) r = -APKE_ADB_BLOCK; @@ -319,7 +322,7 @@ static int apk_extract_pkg(struct extract_ctx *ctx, const char *fn) struct apk_trust *trust = apk_ctx_get_trust(ac); int r; - r = adb_m_stream(&ctx->db, + r = adb_m_process(&ctx->db, adb_decompress(apk_istream_from_fd_url(AT_FDCWD, fn, apk_ctx_since(ac, 0)), 0), ADB_SCHEMA_PACKAGE, trust, apk_extract_data_block); if (r == 0) { diff --git a/src/app_mkndx.c b/src/app_mkndx.c index 4599fd3..bab6983 100644 --- a/src/app_mkndx.c +++ b/src/app_mkndx.c @@ -204,6 +204,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a return -1; } + adb_init(&odb); adb_w_init_tmp(&tmpdb, 200); adb_wo_alloca(&tmpl, &schema_pkginfo, &tmpdb); @@ -215,7 +216,8 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a apk_fileinfo_get(AT_FDCWD, ctx->index, 0, &fi, 0); index_mtime = fi.mtime; - r = adb_m_map(&odb, open(ctx->index, O_RDONLY), ADB_SCHEMA_INDEX, trust); + r = adb_m_open(&odb, apk_istream_from_file_mmap(AT_FDCWD, ctx->index), + ADB_SCHEMA_INDEX, trust); if (r) { apk_err(out, "%s: %s", ctx->index, apk_error_str(r)); return r; diff --git a/src/io.c b/src/io.c index 0ec278b..ccd2ec0 100644 --- a/src/io.c +++ b/src/io.c @@ -70,6 +70,13 @@ void apk_file_meta_to_fd(int fd, struct apk_file_meta *meta) futimens(fd, times); } +apk_blob_t apk_istream_mmap(struct apk_istream *is) +{ + if (is->flags & APK_ISTREAM_SINGLE_READ) + return APK_BLOB_PTR_LEN((char*)is->buf, is->buf_size); + return APK_BLOB_NULL; +} + ssize_t apk_istream_read(struct apk_istream *is, void *ptr, size_t size) { ssize_t left = size, r = 0; @@ -160,7 +167,7 @@ apk_blob_t apk_istream_get_max(struct apk_istream *is, size_t max) if (is->ptr != is->end) { apk_blob_t ret = APK_BLOB_PTR_LEN((char*)is->ptr, min((size_t)(is->end - is->ptr), max)); - is->ptr = is->end = 0; + is->ptr += ret.len; return ret; } @@ -193,6 +200,41 @@ apk_blob_t apk_istream_get_delim(struct apk_istream *is, apk_blob_t token) return (struct apk_blob) { .len = is->err < 0 ? is->err : 0 }; } +static void blob_get_meta(struct apk_istream *is, struct apk_file_meta *meta) +{ + *meta = (struct apk_file_meta) { }; +} + +static ssize_t blob_read(struct apk_istream *is, void *ptr, size_t size) +{ + return 0; +} + +static int blob_close(struct apk_istream *is) +{ + return is->err < 0 ? is->err : 0; +} + +static const struct apk_istream_ops blob_istream_ops = { + .get_meta = blob_get_meta, + .read = blob_read, + .close = blob_close, +}; + +struct apk_istream *apk_istream_from_blob(struct apk_istream *is, apk_blob_t blob) +{ + *is = (struct apk_istream) { + .ops = &blob_istream_ops, + .buf = (uint8_t*) blob.ptr, + .buf_size = blob.len, + .ptr = (uint8_t*) blob.ptr, + .end = (uint8_t*) blob.ptr + blob.len, + .flags = APK_ISTREAM_SINGLE_READ, + .err = 1, + }; + return is; +} + static void segment_get_meta(struct apk_istream *is, struct apk_file_meta *meta) { struct apk_segment_istream *sis = container_of(is, struct apk_segment_istream, is); @@ -493,14 +535,14 @@ struct apk_istream *apk_istream_from_fd(int fd) return &fis->is; } -struct apk_istream *apk_istream_from_file(int atfd, const char *file) +struct apk_istream *__apk_istream_from_file(int atfd, const char *file, int try_mmap) { int fd; fd = openat(atfd, file, O_RDONLY | O_CLOEXEC); if (fd < 0) return ERR_PTR(-errno); - if (0) { + if (try_mmap) { struct apk_istream *is = apk_mmap_istream_from_fd(fd); if (!IS_ERR_OR_NULL(is)) return is; } @@ -834,11 +876,6 @@ int apk_dir_foreach_file(int dirfd, apk_dir_file_cb cb, void *ctx) return ret; } -struct apk_istream *apk_istream_from_file_gz(int atfd, const char *file) -{ - return apk_istream_gunzip(apk_istream_from_file(atfd, file)); -} - struct apk_fd_ostream { struct apk_ostream os; int fd; diff --git a/src/meson.build b/src/meson.build index ff0b3cc..98b2461 100644 --- a/src/meson.build +++ b/src/meson.build @@ -5,7 +5,7 @@ libapk_src = [ 'adb_walk_adb.c', 'adb_walk_genadb.c', 'adb_walk_gentext.c', - 'adb_walk_istream.c', + 'adb_walk_text.c', 'apk_adb.c', 'atom.c', 'blob.c', -- cgit v1.2.3-70-g09d2