Commit b6dde54a authored by Timo Teräs's avatar Timo Teräs

adb: introduce apk-tools database format, and few applets

This is a flat buffers inspired format that allows fast
mmaped access to the data with low overhead, signature support
and relatively good forward support.
parent 6d11ec36
Pipeline #7412 failed with stage
in 16 seconds
......@@ -31,12 +31,18 @@ apk-objs := apk.o \
app_index.o app_fetch.o app_verify.o app_dot.o \
app_audit.o
libapk.so-objs := common.o database.o package.o commit.o solver.o \
libapk.so-objs := adb.o adb_trust.o \
common.o database.o package.o commit.o solver.o \
version.o blob.o hash.o print.o \
io.o io_url.o io_gunzip.o io_archive.o
libapk.so-libs := libfetch/libfetch.a
ifeq ($(ADB),y)
libapk.so-objs += apk_adb.o
apk-objs += app_adbdump.o app_adbsign.o app_mkndx.o app_ndxconv.o
endif
ifeq ($(TEST),y)
progs-y += apk-test
apk-test-objs := apk-test.o $(filter-out apk.o, $(apk-objs))
......
This diff is collapsed.
#ifndef ADB_H
#define ADB_H
#include <endian.h>
#include <stdint.h>
#include <sys/types.h>
#include "apk_io.h"
struct adb_trust;
struct adb_verify_ctx;
typedef uint32_t adb_val_t;
typedef adb_val_t *adb_obj_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 0xe0000000
#define ADB_TYPE_OBJECT 0xf0000000
#define ADB_TYPE_MASK 0xf0000000
#define ADB_VALUE_MASK 0x0fffffff
#define ADB_VAL_TYPE(x) ((htole32(x))&ADB_TYPE_MASK)
#define ADB_VAL_VALUE(x) ((htole32(x))&ADB_VALUE_MASK)
/* ADB_TYPE_SPECIAL */
#define ADB_VAL_NULL 0x00000000
#define ADB_VAL_TRUE 0x00000001
#define ADB_VAL_FALSE 0x00000002
/* Generic */
#define ADBI_NUM_ENTRIES 0x00
#define ADBI_FIRST 0x01
#define ADB_FORMAT_MAGIC 0x2e424441 // ADB.
/* File Header */
struct adb_header {
uint32_t magic;
uint32_t schema;
};
/* Blocks */
#define ADB_BLOCK_END -1
#define ADB_BLOCK_ADB 0
#define ADB_BLOCK_SIG 2
#define ADB_BLOCK_TYPE(b) (letoh32((b)->type_size) >> 30)
#define ADB_BLOCK_SIZE(b) (letoh32((b)->type_size) & 0x3fffff)
struct adb_block {
uint32_t type_size;
};
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];
};
/* Hash algorithms */
#define ADB_HASH_NONE 0x00
#define ADB_HASH_SHA1 0x01
#define ADB_HASH_SHA256 0x02
#define ADB_HASH_SHA512 0x03
/* 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))
/* Database read interface */
struct adb_r {
apk_blob_t adb, mmap;
struct adb_header hdr;
};
adb_val_t adb_r_root(struct adb_r *);
adb_obj_t adb_r_obj(struct adb_r *, adb_val_t);
uint32_t adb_r_int(struct adb_r *, adb_val_t);
apk_blob_t adb_r_blob(struct adb_r *, adb_val_t);
static inline adb_obj_t adb_r_rootobj(struct adb_r *r) { return adb_r_obj(r, adb_r_root(r)); }
static inline size_t adb_ro_num(const adb_obj_t o) { return letoh32(o[ADBI_NUM_ENTRIES]); }
static inline size_t adb_ra_num(const adb_obj_t o) { uint32_t n = letoh32(o[ADBI_NUM_ENTRIES]); return n ? n - 1 : 0; }
static inline adb_val_t adb_ro_val(const adb_obj_t o, unsigned i) { return i < adb_ro_num(o) ? o[i] : ADB_VAL_NULL; }
static inline uint32_t adb_ro_int(struct adb_r *db, adb_obj_t o, unsigned i) { return adb_r_int(db, adb_ro_val(o, i)); }
static inline apk_blob_t adb_ro_blob(struct adb_r *db, adb_obj_t o, unsigned i) { return adb_r_blob(db, adb_ro_val(o, i)); }
static inline adb_obj_t adb_ro_obj(struct adb_r *db, adb_obj_t o, unsigned i) { return adb_r_obj(db, adb_ro_val(o, i)); }
/* Database write interface */
struct adb_w_bucket {
struct list_head node;
struct adb_w_bucket_entry {
uint32_t hash;
size_t offs;
uint32_t len;
} entries[40];
};
struct adb_w {
struct adb_r r;
size_t alloc_len;
struct list_head bucket[1024];
};
adb_val_t adb_w_blob(struct adb_w *, const void *, size_t);
adb_val_t adb_w_int(struct adb_w *, uint32_t);
adb_val_t adb_w_copy(struct adb_w *, struct adb_r *, adb_val_t);
adb_val_t __adb_w_obj(struct adb_w *, adb_obj_t, size_t, adb_val_t);
void adb_w_root(struct adb_w *, adb_val_t);
static inline adb_val_t adb_w_object(struct adb_w *w, adb_obj_t o, size_t n) {
return __adb_w_obj(w, o, n, ADB_TYPE_OBJECT);
}
static inline adb_val_t adb_w_array(struct adb_w *w, adb_obj_t o) {
return __adb_w_obj(w, o, letoh32(o[ADBI_NUM_ENTRIES]), ADB_TYPE_ARRAY);
}
static inline void adb_wa_init(adb_obj_t a) { a[ADBI_NUM_ENTRIES] = letoh32(1); }
static inline int adb_wa_append(adb_obj_t a, size_t n, adb_val_t v) {
size_t i = letoh32(a[ADBI_NUM_ENTRIES]);
if (!v || i >= n) return 0;
a[i] = v;
a[ADBI_NUM_ENTRIES] = htole32(i + 1);
return 1;
}
int adb_w_init(struct adb_w *);
int adb_w_free(struct adb_w *);
/* Container read interface */
int adb_m_map(struct adb_r *, int fd, uint32_t expected_schema, struct adb_trust *);
void adb_m_unmap(struct adb_r *);
/* Creation */
int adb_c_header(struct apk_ostream *os, uint32_t schema, struct adb_w *w);
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t);
int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *);
/* Trust */
#include <openssl/evp.h>
struct adb_pkey {
uint8_t id[16];
EVP_PKEY *key;
};
int adb_pkey_init(struct adb_pkey *pkey, EVP_PKEY *key);
void adb_pkey_free(struct adb_pkey *pkey);
int adb_pkey_load(struct adb_pkey *pkey, int dirfd, const char *fn);
struct adb_trust {
EVP_MD_CTX *mdctx;
struct list_head trusted_key_list;
struct list_head private_key_list;
};
struct adb_verify_ctx {
uint32_t calc;
uint8_t sha512[64];
};
int adb_trust_init(struct adb_trust *trust, int keysfd, struct apk_string_array *);
void adb_trust_free(struct adb_trust *trust);
int adb_trust_write_signatures(struct adb_trust *trust, struct adb_r *r, struct adb_verify_ctx *vfy, struct apk_ostream *os);
int adb_trust_verify_signature(struct adb_trust *trust, struct adb_r *r, 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_r r;
struct adb_verify_ctx vfy;
};
int adb_c_xfrm(struct adb_xfrm *, int (*cb)(struct adb_xfrm *, struct adb_block *, struct apk_istream *));
#endif
#include <errno.h>
#include <stdio.h>
#include <openssl/bio.h>
#include <openssl/pem.h>
#include <openssl/err.h>
#include "apk_defines.h"
#include "adb.h"
struct adb_trust_key {
struct list_head key_node;
struct adb_pkey key;
};
/* Trust */
int adb_pkey_init(struct adb_pkey *pkey, EVP_PKEY *key)
{
unsigned char dig[EVP_MAX_MD_SIZE], *pub = NULL;
unsigned int dlen = sizeof dig;
int len;
if ((len = i2d_PublicKey(key, &pub)) < 0) return -EIO;
EVP_Digest(pub, len, dig, &dlen, EVP_sha512(), NULL);
memcpy(pkey->id, dig, sizeof pkey->id);
OPENSSL_free(pub);
pkey->key = key;
return 0;
}
void adb_pkey_free(struct adb_pkey *pkey)
{
EVP_PKEY_free(pkey->key);
}
int adb_pkey_load(struct adb_pkey *pkey, int dirfd, const char *fn)
{
EVP_PKEY *key;
BIO *bio;
int fd;
fd = openat(dirfd, fn, O_RDONLY|O_CLOEXEC);
if (fd < 0) return -errno;
bio = BIO_new_fp(fdopen(fd, "r"), BIO_CLOSE);
if (!bio) return -ENOMEM;
key = PEM_read_bio_PUBKEY(bio, NULL, NULL, NULL);
if (!key) {
BIO_reset(bio);
key = PEM_read_bio_PrivateKey(bio, NULL, NULL, NULL);
}
ERR_clear_error();
BIO_free(bio);
if (!key) return -EBADMSG;
adb_pkey_init(pkey, key);
return 0;
}
static struct adb_trust_key *adb_trust_load_key(int dirfd, const char *filename)
{
struct adb_trust_key *key;
int r;
key = calloc(1, sizeof *key);
if (!key) return ERR_PTR(-ENOMEM);
r = adb_pkey_load(&key->key, dirfd, filename);
if (r) {
free(key);
return ERR_PTR(-ENOKEY);
}
list_init(&key->key_node);
return key;
}
static int __adb_trust_load_pubkey(void *pctx, int dirfd, const char *filename)
{
struct adb_trust *trust = pctx;
struct adb_trust_key *key = adb_trust_load_key(dirfd, filename);
if (!IS_ERR(key))
list_add_tail(&key->key_node, &trust->trusted_key_list);
return 0;
}
int adb_trust_init(struct adb_trust *trust, int dirfd, struct apk_string_array *pkey_files)
{
char **fn;
*trust = (struct adb_trust){
.mdctx = EVP_MD_CTX_new(),
};
if (!trust->mdctx) return -ENOMEM;
EVP_MD_CTX_set_flags(trust->mdctx, EVP_MD_CTX_FLAG_FINALISE);
list_init(&trust->trusted_key_list);
list_init(&trust->private_key_list);
apk_dir_foreach_file(dirfd, __adb_trust_load_pubkey, trust);
foreach_array_item(fn, pkey_files) {
struct adb_trust_key *key = adb_trust_load_key(AT_FDCWD, *fn);
if (IS_ERR(key)) return PTR_ERR(key);
list_add_tail(&key->key_node, &trust->private_key_list);
}
return 0;
}
static void __adb_trust_free_keys(struct list_head *h)
{
struct adb_trust_key *tkey, *n;
list_for_each_entry_safe(tkey, n, h, key_node) {
list_del(&tkey->key_node);
adb_pkey_free(&tkey->key);
free(tkey);
}
}
void adb_trust_free(struct adb_trust *trust)
{
__adb_trust_free_keys(&trust->trusted_key_list);
__adb_trust_free_keys(&trust->private_key_list);
EVP_MD_CTX_free(trust->mdctx);
}
static int adb_verify_ctx_calc(struct adb_verify_ctx *vfy, unsigned int hash_alg, apk_blob_t data, apk_blob_t *pmd)
{
const EVP_MD *evp;
apk_blob_t md;
switch (hash_alg) {
case ADB_HASH_SHA512:
evp = EVP_sha512();
*pmd = md = APK_BLOB_BUF(vfy->sha512);
break;
default:
return -ENOTSUP;
}
if (!(vfy->calc & (1 << hash_alg))) {
unsigned int sz = md.len;
if (APK_BLOB_IS_NULL(data)) return -ENOMSG;
if (EVP_Digest(data.ptr, data.len, (unsigned char*) md.ptr, &sz, evp, NULL) != 1 ||
sz != md.len)
return -EIO;
vfy->calc |= (1 << hash_alg);
}
return 0;
}
int adb_trust_write_signatures(struct adb_trust *trust, struct adb_r *ar, struct adb_verify_ctx *vfy, struct apk_ostream *os)
{
union {
struct adb_sign_hdr hdr;
struct adb_sign_v0 v0;
unsigned char buf[8192];
} sig;
struct adb_trust_key *tkey;
apk_blob_t md;
size_t siglen;
int r;
if (!vfy) {
vfy = alloca(sizeof *vfy);
memset(vfy, 0, sizeof *vfy);
}
r = adb_verify_ctx_calc(vfy, ADB_HASH_SHA512, ar->adb, &md);
if (r) return r;
list_for_each_entry(tkey, &trust->private_key_list, key_node) {
sig.v0 = (struct adb_sign_v0) {
.hdr.sign_ver = 0,
.hdr.hash_alg = ADB_HASH_SHA512,
};
memcpy(sig.v0.id, tkey->key.id, sizeof(sig.v0.id));
siglen = sizeof sig.buf - sizeof sig.v0;
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
EVP_DigestUpdate(trust->mdctx, &ar->hdr, sizeof ar->hdr) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) {
ERR_print_errors_fp(stdout);
goto err_io;
}
r = adb_c_block(os, ADB_BLOCK_SIG, APK_BLOB_PTR_LEN((char*) &sig, sizeof(sig.v0) + siglen));
if (r < 0) goto err;
}
return 0;
err_io:
r = -EIO;
err:
apk_ostream_cancel(os, r);
return r;
}
int adb_trust_verify_signature(struct adb_trust *trust, struct adb_r *ar, struct adb_verify_ctx *vfy, apk_blob_t sigb)
{
struct adb_trust_key *tkey;
struct adb_sign_hdr *sig;
struct adb_sign_v0 *sig0;
apk_blob_t md;
if (APK_BLOB_IS_NULL(ar->adb)) return -ENOMSG;
if (sigb.len < sizeof(struct adb_sign_hdr)) return -EBADMSG;
sig = (struct adb_sign_hdr *) sigb.ptr;
sig0 = (struct adb_sign_v0 *) sigb.ptr;
if (sig->sign_ver != 0) return -ENOSYS;
list_for_each_entry(tkey, &trust->trusted_key_list, key_node) {
if (memcmp(sig0->id, tkey->key.id, sizeof sig0->id) != 0) continue;
if (adb_verify_ctx_calc(vfy, sig->hash_alg, ar->adb, &md) != 0) continue;
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
EVP_DigestUpdate(trust->mdctx, &ar->hdr, sizeof ar->hdr) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig->sign_ver, sizeof sig->sign_ver) != 1 ||
EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) {
ERR_clear_error();
continue;
}
return 0;
}
return -EKEYREJECTED;
}
/* Command group for signing */
#include "apk_applet.h"
static int option_parse_signing(void *ctx, struct apk_db_options *dbopts, int optch, const char *optarg)
{
switch (optch) {
case 'K':
*apk_string_array_add(&dbopts->private_keys) = (char*) optarg;
break;
default:
return -ENOTSUP;
}
return 0;
}
static const struct apk_option options_signing[] = {
{ 'K', "sign-key", required_argument, "PKEYFILE" },
};
const struct apk_option_group optgroup_signing = {
.name = "Signing",
.options = options_signing,
.num_options = ARRAY_SIZE(options_signing),
.parse = option_parse_signing,
};
......@@ -478,6 +478,7 @@ int main(int argc, char **argv)
memset(&dbopts, 0, sizeof(dbopts));
list_init(&dbopts.repository_list);
apk_string_array_init(&dbopts.private_keys);
apk_atom_init();
umask(0);
setup_terminal();
......@@ -617,6 +618,7 @@ err:
fetchConnectionCacheClose();
apk_string_array_free(&args);
apk_string_array_free(&dbopts.private_keys);
free(apk_argv);
if (r < 0) r = 250;
......
#include "apk_adb.h"
#include "apk_version.h"
#define APK_VERSION_CONFLICT 16
adb_val_t adb_w_dependency(struct adb_w *adb, apk_blob_t *b)
{
extern const apk_spn_match_def apk_spn_dependency_comparer;
extern const apk_spn_match_def apk_spn_dependency_separator;
extern const apk_spn_match_def apk_spn_repotag_separator;
adb_val_t fields[ADBI_DEP_MAX] = {0};
apk_blob_t bdep, bname, bop, bver = APK_BLOB_NULL, btag;
int mask = APK_DEPMASK_ANY;
/* [!]name[<,<=,<~,=,~,>~,>=,>,><]ver */
if (APK_BLOB_IS_NULL(*b))
goto fail;
/* grap one token */
if (!apk_blob_cspn(*b, apk_spn_dependency_separator, &bdep, NULL))
bdep = *b;
b->ptr += bdep.len;
b->len -= bdep.len;
/* skip also all separator chars */
if (!apk_blob_spn(*b, apk_spn_dependency_separator, NULL, b)) {
b->ptr += b->len;
b->len = 0;
}
/* parse the version */
if (bdep.ptr[0] == '!') {
bdep.ptr++;
bdep.len--;
mask |= APK_VERSION_CONFLICT;
}
if (apk_blob_cspn(bdep, apk_spn_dependency_comparer, &bname, &bop)) {
int i;
if (mask == 0)
goto fail;
if (!apk_blob_spn(bop, apk_spn_dependency_comparer, &bop, &bver))
goto fail;
mask = 0;
for (i = 0; i < bop.len; i++) {
switch (bop.ptr[i]) {
case '<':
mask |= APK_VERSION_LESS;
break;
case '>':
mask |= APK_VERSION_GREATER;
break;
case '~':
mask |= APK_VERSION_FUZZY|APK_VERSION_EQUAL;
break;
case '=':
mask |= APK_VERSION_EQUAL;
break;
}
}
if ((mask & APK_DEPMASK_CHECKSUM) != APK_DEPMASK_CHECKSUM &&
!apk_version_validate(bver))
goto fail;
} else {
bname = bdep;
bop = APK_BLOB_NULL;
bver = APK_BLOB_NULL;
}
if (apk_blob_cspn(bname, apk_spn_repotag_separator, &bname, &btag))
; /* tag = repository tag */
fields[ADBI_DEP_NAME] = adb_w_blob(adb, bname.ptr, bname.len);
if (mask != APK_DEPMASK_ANY) {
fields[ADBI_DEP_VERSION] = adb_w_blob(adb, bver.ptr, bver.len);
if (mask != APK_VERSION_EQUAL)
fields[ADBI_DEP_MATCH] = adb_w_int(adb, mask);
}
return adb_w_object(adb, fields, ARRAY_SIZE(fields));
fail:
return ADB_VAL_NULL;
}
adb_val_t adb_w_pkginfo(struct adb_w *w, unsigned int f, apk_blob_t *val)
{
struct apk_checksum csum;
adb_val_t deps[512];
adb_wa_init(deps);
switch (f) {
case ADBI_PI_INSTALLED_SIZE:
case ADBI_PI_FILE_SIZE:
case ADBI_PI_BUILD_TIME:
return adb_w_int(w, apk_blob_pull_uint(val, 10));
case ADBI_PI_DEPENDS:
case ADBI_PI_INSTALL_IF:
case ADBI_PI_PROVIDES:
/* array of package names */
while (val->len)
adb_wa_append(deps, ARRAY_SIZE(deps), adb_w_dependency(w, val));
return adb_w_array(w, deps);
case ADBI_PI_IDENTITY_HASH:
apk_blob_pull_csum(val, &csum);
if (val->ptr) return adb_w_blob(w, csum.data, csum.type);
break;
case ADBI_PI_REPO_COMMIT:
if (val->len < 40) break;
csum.type = 20;
apk_blob_pull_hexdump(val, APK_BLOB_CSUM(csum));
if (val->ptr) return adb_w_blob(w, csum.data, csum.type);
break;
default:
return adb_w_blob(w, val->ptr, val->len);
}
return ADB_VAL_NULL;
}
static struct adb_r *__r;
static int sort_pkgs(const void *p1, const void *p2)
{
adb_obj_t o1 = adb_r_obj(__r, *(adb_val_t *)p1);
adb_obj_t o2 = adb_r_obj(__r, *(adb_val_t *)p2);
int r;
r = apk_blob_sort(
adb_ro_blob(__r, o1, ADBI_PI_NAME),
adb_ro_blob(__r, o2, ADBI_PI_NAME));
if (r) return r;
r = apk_version_compare_blob(
adb_ro_blob(__r, o1, ADBI_PI_VERSION),
adb_ro_blob(__r, o2, ADBI_PI_VERSION));
switch (r) {
case APK_VERSION_LESS: return -1;
case APK_VERSION_GREATER: return 1;
default: return 0;
}
}
adb_val_t adb_w_pkgindex(struct adb_w *w, adb_obj_t arr)
{
__r = &w->r;
qsort(&arr[ADBI_FIRST], adb_ra_num(arr), sizeof(arr[0]), sort_pkgs);
return adb_w_array(w, arr);
}
struct pkgi_key {
struct adb_r *r;
apk_blob_t pkgname, pkgver;
};
static inline int find_pkg(const void *pkey, const void *pobj)
{
const struct pkgi_key *key = pkey;
adb_obj_t obj = adb_r_obj(key->r, *(adb_val_t *)pobj);
int r;
r = apk_blob_sort(key->pkgname, adb_ro_blob(key->r, obj, ADBI_PI_NAME));
if (r) return r;
if (APK_BLOB_IS_NULL(key->pkgver)) return 0;
r = apk_version_compare_blob(key->pkgver, adb_ro_blob(key->r, obj, ADBI_PI_VERSION));
switch (r) {
case APK_VERSION_LESS: return -1;
case APK_VERSION_GREATER: return 1;
default: return 0;
}
}
int adb_r_pkgindex_find(struct adb_r *r, adb_obj_t arr, int cur, apk_blob_t pkgname, apk_blob_t pkgver)
{
struct pkgi_key key = { .r = r, .pkgname = pkgname, .pkgver = pkgver };
adb_val_t *ndx;
if (cur == 0) {
ndx = bsearch(&key, &arr[ADBI_FIRST], adb_ra_num(arr), sizeof(arr[0]), find_pkg);
if (!ndx) return -1;
cur = ndx - arr;
while (cur > 1 && find_pkg(&key, &arr[cur-1]) == 0) cur--;
return cur;
}
cur++;
if (find_pkg(&key, &arr[cur]) == 0)
return cur;
return -1;
}
#include "adb.h"
/* Schemas */
#define ADB_SCHEMA_INDEX 0x78646e69 // indx
#define ADB_SCHEMA_PACKAGE 0x676b6370 // pckg
/* Dependency */
#define ADBI_DEP_NAME 0x01
#define ADBI_DEP_VERSION 0x02
#define ADBI_DEP_MATCH 0x03
#define ADBI_DEP_MAX 0x04
/* Package Info */
#define ADBI_PI_NAME 0x01
#define ADBI_PI_VERSION 0x02
#define ADBI_PI_DESCRIPTION 0x03
#define ADBI_PI_ARCH 0x04
#define ADBI_PI_LICENSE 0x05
#define ADBI_PI_ORIGIN 0x06
#define ADBI_PI_MAINTAINER 0x07
#define ADBI_PI_URL 0x08
#define ADBI_PI_REPO_COMMIT 0x09
#define ADBI_PI_BUILD_TIME 0x0a
#define ADBI_PI_INSTALLED_SIZE 0x0b
#define ADBI_PI_FILE_SIZE 0x0c
#define ADBI_PI_DEPENDS 0x0d
#define ADBI_PI_INSTALL_IF 0x0e
#define ADBI_PI_PROVIDES 0x0f
#define ADBI_PI_IDENTITY_HASH 0x10
#define ADBI_PI_MAX 0x11
/* Package Manifest */
#define ADBI_PM_FILES 0x01
#define ADBI_PM_SCRIPT 0x02
#define ADBI_PM_REPLACES 0x03
#define ADBI_PM_PRIORITY 0x04
#define ADBI_PM_TRIGGERS 0x05
#define ADBI_PM_PASSWD 0x06
#define ADBI_PM_MAX 0x07
/* Package */
#define ADBI_P_INFO 0x01