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

adb: improve sorting features, sort installed-db package listing

parent e9caeff2
......@@ -60,55 +60,73 @@ void adb_reset(struct adb *db)
db->adb.len = 0;
}
int adb_m_map(struct adb *db, int fd, uint32_t expected_schema, struct adb_trust *t)
static int __adb_m_parse(struct adb *db, struct adb_trust *t)
{
struct stat st;
struct adb_header *hdr;
struct adb_block *blk;
struct adb_verify_ctx vfy = {};
struct adb_block *blk;
int r = -EBADMSG;
int trusted = t ? 0 : 1;
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 bad_msg;
if (expected_schema && expected_schema != le32toh(hdr->schema)) goto bad_msg;
db->hdr = *hdr;
db->data = APK_BLOB_PTR_LEN(db->mmap.ptr + sizeof *hdr, db->mmap.len - sizeof *hdr);
adb_foreach_block(blk, db->data) {
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
switch (ADB_BLOCK_TYPE(blk)) {
case ADB_BLOCK_ADB:
if (!APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
if (!APK_BLOB_IS_NULL(db->adb)) break;
db->adb = b;
break;
case ADB_BLOCK_SIG:
if (APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
if (APK_BLOB_IS_NULL(db->adb)) break;
if (!trusted &&
adb_trust_verify_signature(t, db, &vfy, b) == 0)
trusted = 1;
break;
default:
if (APK_BLOB_IS_NULL(db->adb)) goto bad_msg;
if (APK_BLOB_IS_NULL(db->adb)) break;
break;
}
}
if (!trusted) blk = ERR_PTR(-ENOKEY);
if (IS_ERR(blk)) goto err;
return 0;
if (IS_ERR(blk)) r = PTR_ERR(blk);
else if (!trusted) r = -ENOKEY;
else if (db->adb.ptr) r = 0;
bad_msg:
blk = ERR_PTR(-EBADMSG);
if (r != 0) {
db->adb = APK_BLOB_NULL;
}
return r;
}
int adb_m_blob(struct adb *db, apk_blob_t blob, struct adb_trust *t)
{
*db = (struct adb) { .data = blob };
return __adb_m_parse(db, t);
}
int adb_m_map(struct adb *db, int fd, uint32_t expected_schema, struct adb_trust *t)
{
struct stat st;
struct adb_header *hdr;
int r = -EBADMSG;
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);
if (r) goto err;
return 0;
err:
adb_free(db);
return PTR_ERR(blk);
return r;
}
int adb_w_init_dynamic(struct adb *db, uint32_t schema, void *buckets, size_t num_buckets)
......@@ -265,6 +283,28 @@ struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj *
return adb_r_obj(o->db, adb_ro_val(o, i), no, schema);
}
int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i)
{
assert(o1->schema->kind == ADB_KIND_OBJECT);
assert(o1->schema == o2->schema);
assert(i > 0 && i < o1->schema->num_fields);
switch (*o1->schema->fields[i-1].kind) {
case ADB_KIND_BLOB:
case ADB_KIND_INT:
return container_of(o1->schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare(
o1->db, adb_ro_val(o1, i),
o2->db, adb_ro_val(o2, i));
case ADB_KIND_OBJECT: {
struct adb_obj so1, so2;
adb_ro_obj(o1, i, &so1);
adb_ro_obj(o2, i, &so2);
return so1.schema->compare(&so1, &so2);
}
}
assert(0);
}
static struct adb *__db1, *__db2;
static const struct adb_object_schema *__schema;
......@@ -276,6 +316,17 @@ static int wacmp(const void *p1, const void *p2)
return o1.schema->compare(&o1, &o2);
}
static int wadbcmp(const void *p1, const void *p2)
{
struct adb a1, a2;
struct adb_obj o1, o2;
adb_m_blob(&a1, adb_r_blob(__db1, *(adb_val_t *)p1), 0);
adb_m_blob(&a2, adb_r_blob(__db2, *(adb_val_t *)p2), 0);
adb_r_rootobj(&a1, &o1, __schema);
adb_r_rootobj(&a2, &o2, __schema);
return __schema->compare(&o1, &o2);
}
int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val)
{
adb_val_t *ndx;
......@@ -635,23 +686,27 @@ adb_val_t adb_wo_int(struct adb_obj *o, unsigned i, uint32_t v)
adb_val_t adb_wo_blob(struct adb_obj *o, unsigned i, apk_blob_t b)
{
assert(o->schema->kind == ADB_KIND_OBJECT);
return adb_wo_val(o, i, adb_w_blob(o->db, b));
}
adb_val_t adb_wo_obj(struct adb_obj *o, unsigned i, struct adb_obj *no)
{
assert(o->schema->kind == ADB_KIND_OBJECT);
assert(o->db == no->db);
return adb_wo_val(o, i, adb_w_obj(no));
}
adb_val_t adb_wo_arr(struct adb_obj *o, unsigned i, struct adb_obj *no)
{
assert(o->schema->kind == ADB_KIND_OBJECT || o->schema->kind == ADB_KIND_ARRAY);
assert(o->db == no->db);
return adb_wo_val(o, i, adb_w_arr(no));
}
adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t v)
{
assert(o->schema->kind == ADB_KIND_ARRAY);
if (o->num >= o->obj[ADBI_NUM_ENTRIES]) return adb_w_error(o->db, E2BIG);
if (ADB_IS_ERROR(v)) return adb_w_error(o->db, ADB_VAL_VALUE(v));
o->obj[o->num++] = v;
......@@ -660,20 +715,33 @@ adb_val_t adb_wa_append(struct adb_obj *o, adb_val_t v)
adb_val_t adb_wa_append_obj(struct adb_obj *o, struct adb_obj *no)
{
assert(o->schema->kind == ADB_KIND_ARRAY);
assert(o->db == no->db);
return adb_wa_append(o, adb_w_obj(no));
}
adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t b)
{
assert(o->schema->kind == ADB_KIND_ARRAY);
return adb_wa_append(o, adb_w_fromstring(o->db, o->schema->fields[0].kind, b));
}
void adb_wa_sort(struct adb_obj *arr)
{
assert(arr->schema->kind == ADB_KIND_ARRAY);
__db1 = __db2 = arr->db;
switch (*arr->schema->fields[0].kind) {
case ADB_KIND_OBJECT:
__schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind);
qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp);
break;
case ADB_KIND_ADB:
__schema = container_of(arr->schema->fields[0].kind, struct adb_adb_schema, kind)->schema;
qsort(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wadbcmp);
break;
default:
assert(1);
}
}
void adb_wa_sort_unique(struct adb_obj *arr)
......
......@@ -102,7 +102,7 @@ struct adb_object_schema {
apk_blob_t (*tostring)(struct adb_obj *, char *, size_t);
int (*fromstring)(struct adb_obj *, apk_blob_t);
uint32_t (*get_default_int)(unsigned i);
int (*compare)(struct adb_obj *, struct adb_obj *);
int (*compare)(const struct adb_obj *, const struct adb_obj *);
void (*pre_commit)(struct adb_obj *);
struct {
......@@ -116,13 +116,13 @@ struct adb_scalar_schema {
apk_blob_t (*tostring)(struct adb*, adb_val_t, char *, size_t);
adb_val_t (*fromstring)(struct adb*, apk_blob_t);
int (*compare)(adb_val_t, adb_val_t);
int (*compare)(struct adb*, adb_val_t, struct adb*, adb_val_t);
};
struct adb_adb_schema {
uint8_t kind;
uint32_t schema_id;
struct adb_object_schema *obj;
const struct adb_object_schema *schema;
};
/* Database read interface */
......@@ -153,6 +153,7 @@ struct adb_obj {
int adb_free(struct adb *);
void adb_reset(struct adb *);
int adb_m_blob(struct adb *, apk_blob_t, struct adb_trust *);
int adb_m_map(struct adb *, int fd, uint32_t expected_schema, struct adb_trust *);
#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)
......@@ -174,6 +175,7 @@ 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 */
......
......@@ -90,10 +90,16 @@ static adb_val_t string_fromstring(struct adb *db, apk_blob_t val)
return adb_w_blob(db, val);
}
static int string_compare(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2)
{
return apk_blob_sort(adb_r_blob(db1, v1), adb_r_blob(db2, v2));
}
static struct adb_scalar_schema scalar_string = {
.kind = ADB_KIND_BLOB,
.tostring = string_tostring,
.fromstring = string_fromstring,
.compare = string_compare,
};
const struct adb_object_schema schema_string_array = {
......@@ -102,6 +108,23 @@ const struct adb_object_schema schema_string_array = {
.fields = ADB_ARRAY_ITEM(scalar_string),
};
static int version_compare(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2)
{
switch (apk_version_compare_blob(adb_r_blob(db1, v1), adb_r_blob(db2, v2))) {
case APK_VERSION_LESS: return -1;
case APK_VERSION_GREATER: return 1;
default: return 0;
}
}
static struct adb_scalar_schema scalar_version = {
.kind = ADB_KIND_BLOB,
.tostring = string_tostring,
.fromstring = string_fromstring,
.compare = version_compare,
};
static apk_blob_t hexblob_tostring(struct adb *db, adb_val_t val, char *buf, size_t bufsz)
{
apk_blob_t b = adb_r_blob(db, val), to = APK_BLOB_PTR_LEN(buf, bufsz);
......@@ -132,10 +155,20 @@ static adb_val_t int_fromstring(struct adb *db, apk_blob_t val)
return adb_w_int(db, n);
}
static int int_compare(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2)
{
uint32_t r1 = adb_r_int(db1, v1);
uint32_t r2 = adb_r_int(db1, v2);
if (r1 < r2) return -1;
if (r1 > r2) return 1;
return 0;
}
static struct adb_scalar_schema scalar_int = {
.kind = ADB_KIND_INT,
.tostring = int_tostring,
.fromstring = int_fromstring,
.compare = int_compare,
};
static apk_blob_t oct_tostring(struct adb *db, adb_val_t val, char *buf, size_t bufsz)
......@@ -160,6 +193,7 @@ static struct adb_scalar_schema scalar_hsize = {
.kind = ADB_KIND_INT,
.tostring = hsize_tostring,
.fromstring = int_fromstring,
.compare = int_compare,
};
static apk_blob_t dependency_tostring(struct adb_obj *obj, char *buf, size_t bufsz)
......@@ -247,11 +281,9 @@ fail:
return -EAPKDEPFORMAT;
}
static int dependency_cmp(struct adb_obj *o1, struct adb_obj *o2)
static int dependency_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
return apk_blob_sort(
adb_ro_blob(o1, ADBI_DEP_NAME),
adb_ro_blob(o2, ADBI_DEP_NAME));
return adb_ro_cmp(o1, o2, ADBI_DEP_NAME);
}
const struct adb_object_schema schema_dependency = {
......@@ -262,7 +294,7 @@ const struct adb_object_schema schema_dependency = {
.compare = dependency_cmp,
.fields = {
ADB_FIELD(ADBI_DEP_NAME, "name", scalar_string),
ADB_FIELD(ADBI_DEP_VERSION, "version", scalar_string),
ADB_FIELD(ADBI_DEP_VERSION, "version", scalar_version),
ADB_FIELD(ADBI_DEP_MATCH, "match", scalar_int),
},
};
......@@ -290,22 +322,14 @@ const struct adb_object_schema schema_dependency_array = {
.fields = ADB_ARRAY_ITEM(schema_dependency),
};
static int pkginfo_cmp(struct adb_obj *o1, struct adb_obj *o2)
static int pkginfo_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
int r;
r = apk_blob_sort(
adb_ro_blob(o1, ADBI_PI_NAME),
adb_ro_blob(o2, ADBI_PI_NAME));
r = adb_ro_cmp(o1, o2, ADBI_PI_NAME);
if (r) return r;
r = apk_version_compare_blob(
adb_ro_blob(o1, ADBI_PI_VERSION),
adb_ro_blob(o2, ADBI_PI_VERSION));
switch (r) {
case APK_VERSION_LESS: return -1;
case APK_VERSION_GREATER: return 1;
}
return 0;
r = adb_ro_cmp(o1, o2, ADBI_PI_VERSION);
if (r) return r;
return adb_ro_cmp(o1, o2, ADBI_PI_UNIQUE_ID);
}
const struct adb_object_schema schema_pkginfo = {
......@@ -314,7 +338,7 @@ const struct adb_object_schema schema_pkginfo = {
.compare = pkginfo_cmp,
.fields = {
ADB_FIELD(ADBI_PI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_PI_VERSION, "version", scalar_string),
ADB_FIELD(ADBI_PI_VERSION, "version", scalar_version),
ADB_FIELD(ADBI_PI_UNIQUE_ID, "unique-id", scalar_int),
ADB_FIELD(ADBI_PI_DESCRIPTION, "description", scalar_string),
ADB_FIELD(ADBI_PI_ARCH, "arch", scalar_string),
......@@ -363,11 +387,9 @@ static uint32_t file_get_default_int(unsigned i)
return -1;
}
static int file_cmp(struct adb_obj *o1, struct adb_obj *o2)
static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
return apk_blob_sort(
adb_ro_blob(o1, ADBI_FI_NAME),
adb_ro_blob(o2, ADBI_FI_NAME));
return adb_ro_cmp(o1, o2, ADBI_FI_NAME);
}
const struct adb_object_schema schema_file = {
......@@ -440,9 +462,15 @@ const struct adb_object_schema schema_scripts = {
},
};
static int package_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
return adb_ro_cmp(o1, o2, ADBI_PKG_PKGINFO);
}
const struct adb_object_schema schema_package = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_PKG_MAX,
.compare = package_cmp,
.fields = {
ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo),
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_path_array),
......@@ -455,10 +483,12 @@ const struct adb_object_schema schema_package = {
const struct adb_adb_schema schema_package_adb = {
.kind = ADB_KIND_ADB,
.schema_id = ADB_SCHEMA_PACKAGE,
.schema = &schema_package,
};
const struct adb_object_schema schema_package_adb_array = {
.kind = ADB_KIND_ARRAY,
.pre_commit = adb_wa_sort,
.num_fields = APK_MAX_INDEX_PACKAGES,
.fields = ADB_ARRAY_ITEM(schema_package_adb),
};
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment