#ifndef ADB_H #define ADB_H #include #include #include #include "apk_io.h" #include "apk_trust.h" struct adb; struct adb_obj; struct adb_verify_ctx; typedef uint32_t adb_val_t; #define ADB_TYPE_SPECIAL 0x00000000 #define ADB_TYPE_INT 0x10000000 #define ADB_TYPE_INT_32 0x20000000 #define ADB_TYPE_INT_64 0x30000000 #define ADB_TYPE_BLOB_8 0x80000000 #define ADB_TYPE_BLOB_16 0x90000000 #define ADB_TYPE_BLOB_32 0xa0000000 #define ADB_TYPE_ARRAY 0xd0000000 #define ADB_TYPE_OBJECT 0xe0000000 #define ADB_TYPE_ERROR 0xf0000000 #define ADB_TYPE_MASK 0xf0000000 #define ADB_VALUE_MASK 0x0fffffff #define ADB_VAL_TYPE(x) ((le32toh(x))&ADB_TYPE_MASK) #define ADB_VAL_VALUE(x) ((le32toh(x))&ADB_VALUE_MASK) #define ADB_IS_ERROR(x) (ADB_VAL_TYPE(x) == ADB_TYPE_ERROR) #define ADB_VAL(type, val) (htole32((type) | (val))) #define ADB_ERROR(val) ADB_VAL(ADB_TYPE_ERROR, val) /* ADB_TYPE_SPECIAL */ #define ADB_VAL_NULL 0x00000000 #define ADB_VAL_TRUE 0x00000001 #define ADB_VAL_FALSE 0x00000002 #define ADB_NULL ADB_VAL(ADB_TYPE_SPECIAL, ADB_VAL_NULL) /* Generic */ #define ADBI_NUM_ENTRIES 0x00 #define ADBI_FIRST 0x01 /* File Header */ #define ADB_FORMAT_MAGIC 0x2e424441 // ADB. #define ADB_SCHEMA_IMPLIED 0x80000000 struct adb_file_header { uint32_t magic; uint32_t schema; }; /* Blocks */ #define ADB_BLOCK_ALIGNMENT 8 #define ADB_BLOCK_ADB 0 #define ADB_BLOCK_SIG 1 #define ADB_BLOCK_DATA 2 #define ADB_BLOCK_DATAX 3 struct adb_block { uint32_t type_size; }; static inline struct adb_block adb_block_init(uint32_t type, uint32_t length) { return (struct adb_block) { .type_size = htole32((type << 30) + sizeof(struct adb_block) + length)}; } static inline uint32_t adb_block_type(struct adb_block *b) { return le32toh((b)->type_size) >> 30; } static inline uint32_t adb_block_rawsize(struct adb_block *b) { return le32toh((b)->type_size) & 0x3fffffff; } static inline uint32_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); } static inline uint32_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - sizeof(struct adb_block); } static inline uint32_t adb_block_padding(struct adb_block *b) { return adb_block_size(b) - adb_block_rawsize(b); } static inline void *adb_block_payload(struct adb_block *b) { return b + 1; } static inline apk_blob_t adb_block_blob(struct adb_block *b) { return APK_BLOB_PTR_LEN(adb_block_payload(b), adb_block_length(b)); } #define ADB_MAX_SIGNATURE_LEN 2048 struct adb_hdr { uint8_t adb_compat_ver; uint8_t adb_ver; uint16_t reserved; adb_val_t root; }; struct adb_sign_hdr { uint8_t sign_ver, hash_alg; }; struct adb_sign_v0 { struct adb_sign_hdr hdr; uint8_t id[16]; uint8_t sig[0]; }; /* Schema */ #define ADB_KIND_ADB 1 #define ADB_KIND_OBJECT 2 #define ADB_KIND_ARRAY 3 #define ADB_KIND_BLOB 4 #define ADB_KIND_INT 5 #define ADB_ARRAY_ITEM(_t) { { .kind = &(_t).kind } } #define ADB_FIELD(_i, _n, _t) [(_i)-1] = { .name = _n, .kind = &(_t).kind } struct adb_object_schema { uint8_t kind; uint16_t num_fields; apk_blob_t (*tostring)(struct adb_obj *, char *, size_t); int (*fromstring)(struct adb_obj *, apk_blob_t); int (*compare)(const struct adb_obj *, const struct adb_obj *); void (*pre_commit)(struct adb_obj *); struct { const char *name; const uint8_t *kind; } fields[]; }; struct adb_scalar_schema { uint8_t kind; uint8_t multiline : 1; apk_blob_t (*tostring)(struct adb*, adb_val_t, char *, size_t); adb_val_t (*fromstring)(struct adb*, apk_blob_t); int (*compare)(struct adb*, adb_val_t, struct adb*, adb_val_t); }; struct adb_adb_schema { uint8_t kind; uint32_t schema_id; const struct adb_object_schema *schema; }; /* Database read interface */ struct adb_w_bucket { struct list_head node; struct adb_w_bucket_entry { uint32_t hash; uint32_t offs; uint32_t len; } entries[40]; }; struct adb { struct apk_istream *is; apk_blob_t adb; uint32_t schema; uint32_t num_buckets; size_t alloc_len; struct list_head *bucket; }; struct adb_obj { struct adb *db; const struct adb_object_schema *schema; uint32_t num; adb_val_t *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_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); int adb_w_init_static(struct adb *db, void *buf, size_t bufsz); /* Primitive read */ adb_val_t adb_r_root(const struct adb *); struct adb_obj *adb_r_rootobj(struct adb *a, struct adb_obj *o, const struct adb_object_schema *); uint32_t adb_r_int(const struct adb *, adb_val_t); apk_blob_t adb_r_blob(const struct adb *, adb_val_t); struct adb_obj *adb_r_obj(struct adb *, adb_val_t, struct adb_obj *o, const struct adb_object_schema *); /* Object read */ static inline uint32_t adb_ro_num(const struct adb_obj *o) { return o->num; } static inline uint32_t adb_ra_num(const struct adb_obj *o) { return (o->num ?: 1) - 1; } const uint8_t *adb_ro_kind(const struct adb_obj *o, unsigned i); adb_val_t adb_ro_val(const struct adb_obj *o, unsigned i); uint32_t adb_ro_int(const struct adb_obj *o, unsigned i); apk_blob_t adb_ro_blob(const struct adb_obj *o, unsigned i); struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj *); int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i); int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val); /* Primitive write */ void adb_w_root(struct adb *, adb_val_t); void adb_w_rootobj(struct adb_obj *); adb_val_t adb_w_blob(struct adb *, apk_blob_t); adb_val_t adb_w_int(struct adb *, uint32_t); adb_val_t adb_w_copy(struct adb *, struct adb *, adb_val_t); adb_val_t adb_w_adb(struct adb *, struct adb *); adb_val_t adb_w_fromstring(struct adb *, const uint8_t *kind, apk_blob_t); /* Object write */ #define adb_wo_alloca(o, schema, db) adb_wo_init(o, alloca(sizeof(adb_val_t[(schema)->num_fields])), schema, db) struct adb_obj *adb_wo_init(struct adb_obj *, adb_val_t *, const struct adb_object_schema *, struct adb *); struct adb_obj *adb_wo_init_val(struct adb_obj *, adb_val_t *, const struct adb_obj *, unsigned i); void adb_wo_reset(struct adb_obj *); void adb_wo_resetdb(struct adb_obj *); adb_val_t adb_w_obj(struct adb_obj *); adb_val_t adb_w_arr(struct adb_obj *); adb_val_t adb_wo_fromstring(struct adb_obj *o, apk_blob_t); adb_val_t adb_wo_val(struct adb_obj *o, unsigned i, adb_val_t); adb_val_t adb_wo_val_fromstring(struct adb_obj *o, unsigned i, apk_blob_t); adb_val_t adb_wo_int(struct adb_obj *o, unsigned i, uint32_t); adb_val_t adb_wo_blob(struct adb_obj *o, unsigned i, apk_blob_t); adb_val_t adb_wo_obj(struct adb_obj *o, unsigned i, struct adb_obj *); adb_val_t adb_wo_arr(struct adb_obj *o, unsigned i, struct adb_obj *); adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t); adb_val_t adb_wa_append_obj(struct adb_obj *o, struct adb_obj *); adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t); void adb_wa_sort(struct adb_obj *); void adb_wa_sort_unique(struct adb_obj *); /* Schema helpers */ int adb_s_field_by_name_blob(const struct adb_object_schema *schema, apk_blob_t blob); int adb_s_field_by_name(const struct adb_object_schema *, const char *); /* Creation */ int adb_c_header(struct apk_ostream *os, struct adb *db); int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t); int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is); int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *); int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t); int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t); /* Trust */ struct adb_verify_ctx { uint32_t calc; struct apk_digest sha512; }; 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); /* SAX style event based handling of ADB */ struct adb_db_schema { unsigned long magic; const struct adb_object_schema *root; }; struct adb_walk; struct adb_walk_ops { int (*schema)(struct adb_walk *, uint32_t schema_id); int (*comment)(struct adb_walk *, apk_blob_t comment); int (*start_array)(struct adb_walk *, unsigned int num_items); int (*start_object)(struct adb_walk *); int (*end)(struct adb_walk *); int (*key)(struct adb_walk *, apk_blob_t key_name); int (*scalar)(struct adb_walk *, apk_blob_t scalar, int multiline); }; extern const struct adb_walk_ops adb_walk_gentext_ops, adb_walk_genadb_ops; struct adb_walk { const struct adb_walk_ops *ops; const struct adb_db_schema *schemas; }; struct adb_walk_gentext { struct adb_walk d; FILE *out; int nest; int line_started : 1; int key_printed : 1; }; #define ADB_WALK_GENADB_MAX_IDB 2 #define ADB_WALK_GENADB_MAX_NESTING 32 #define ADB_WALK_GENADB_MAX_VALUES 100000 struct adb_walk_genadb { struct adb_walk d; struct adb db; adb_val_t stored_object; struct adb idb[ADB_WALK_GENADB_MAX_IDB]; int nest, nestdb, num_vals; struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING]; unsigned int curkey[ADB_WALK_GENADB_MAX_NESTING]; adb_val_t vals[ADB_WALK_GENADB_MAX_VALUES]; }; 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 typedef unsigned int adb_comp_t; #define ADB_COMP_NONE 0 #define ADB_COMP_DEFLATE 1 struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compression); struct apk_ostream *adb_compress(struct apk_ostream *os, adb_comp_t compression); #endif