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
parent
69bcdd23b9
commit
3b00c0dc80
|
@ -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
173
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 (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;
|
||||
}
|
||||
|
|
32
src/adb.h
32
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
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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(" #");
|
|
@ -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);
|
||||
|
|
|
@ -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,
|
||||
|
|
|
@ -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));
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
|
|
53
src/io.c
53
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;
|
||||
|
|
|
@ -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',
|
||||
|
|
Loading…
Reference in New Issue