adb: unify various interfaces to adb_m_process

Removes code duplication, and puts important checks in one place.
Support seamless decompression in adbdump.
cute-signatures
Timo Teräs 2021-07-16 19:01:41 +03:00
parent 69bcdd23b9
commit 3b00c0dc80
12 changed files with 253 additions and 221 deletions

View File

@ -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

173
src/adb.c
View File

@ -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 (fstat(fd, &st) != 0) return -errno;
if (st.st_size < sizeof *hdr) return -EIO;
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);
}
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;
}

View File

@ -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

View File

@ -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)
{
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;
const struct adb_db_schema *ds;
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_sign_hdr *s;
uint32_t schema_magic = ctx->db.hdr.schema;
const struct adb_db_schema *ds;
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;
}

View File

@ -9,7 +9,7 @@
#define dbg_printf(args...)
#endif
int adb_walk_istream(struct adb_walk *d, struct apk_istream *is)
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(" #");

View File

@ -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);

View File

@ -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,

View File

@ -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)
{
struct sign_ctx *ctx = container_of(xfrm, struct sign_ctx, xfrm);
struct apk_trust *trust = apk_ctx_get_trust(ctx->ac);
int r;
switch (blk ? adb_block_type(blk) : -1) {
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(db, struct sign_ctx, db);
int r;
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));
}

View File

@ -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) {

View File

@ -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;

View File

@ -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;

View File

@ -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',