mkndx, adb: fix index searching

Additioal logic is needed to search objects on array: the object
comparer needs separate modes to match index, template or exact
object template. This should fix mkndx to be able to use old index.

fixes #10828
cute-signatures
Timo Teräs 2022-03-21 12:48:16 +02:00
parent 950972a56b
commit c6b9297bcb
4 changed files with 97 additions and 78 deletions

122
src/adb.c
View File

@ -472,72 +472,109 @@ 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)
int adb_ro_cmpobj(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned mode)
{
assert(o1->schema->kind == ADB_KIND_OBJECT);
assert(o1->schema == o2->schema);
assert(i > 0 && i < o1->schema->num_fields);
const struct adb_object_schema *schema = obj->schema;
int is_set, r = 0;
switch (*o1->schema->fields[i-1].kind) {
assert(schema->kind == ADB_KIND_OBJECT);
assert(schema == tmpl->schema);
for (unsigned int i = ADBI_FIRST; i <= adb_ro_num(tmpl); i++) {
is_set = adb_ro_val(tmpl, i) != ADB_VAL_NULL;
if (mode == ADB_OBJCMP_EXACT || is_set) {
r = adb_ro_cmp(tmpl, obj, i, mode);
if (r) return r;
}
if (mode == ADB_OBJCMP_INDEX && !is_set)
return 0;
if (mode != ADB_OBJCMP_EXACT && i >= schema->num_compare)
return 0;
}
return 0;
}
int adb_ro_cmp(const struct adb_obj *tmpl, const struct adb_obj *obj, unsigned i, unsigned mode)
{
const struct adb_object_schema *schema = obj->schema;
assert(schema->kind == ADB_KIND_OBJECT);
assert(schema == tmpl->schema);
assert(i > 0 && i < schema->num_fields);
switch (*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));
return container_of(schema->fields[i-1].kind, struct adb_scalar_schema, kind)->compare(
tmpl->db, adb_ro_val(tmpl, i),
obj->db, adb_ro_val(obj, 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);
struct adb_obj stmpl, sobj;
adb_ro_obj(tmpl, i, &stmpl);
adb_ro_obj(obj, i, &sobj);
return adb_ro_cmpobj(&stmpl, &sobj, mode);
}
}
assert(0);
}
static struct adb *__db1, *__db2;
static const struct adb_object_schema *__schema;
static struct wacmp_param {
struct adb *db1, *db2;
const struct adb_object_schema *schema;
int mode;
} __wacmp_param;
static int wacmp(const void *p1, const void *p2)
{
struct wacmp_param *wp = &__wacmp_param;
struct adb_obj o1, o2;
adb_r_obj(__db1, *(adb_val_t *)p1, &o1, __schema);
adb_r_obj(__db2, *(adb_val_t *)p2, &o2, __schema);
return o1.schema->compare(&o1, &o2);
adb_r_obj(wp->db1, *(adb_val_t *)p1, &o1, wp->schema);
adb_r_obj(wp->db2, *(adb_val_t *)p2, &o2, wp->schema);
return adb_ro_cmpobj(&o1, &o2, wp->mode);
}
static int wadbcmp(const void *p1, const void *p2)
{
struct wacmp_param *wp = &__wacmp_param;
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);
adb_m_blob(&a1, adb_r_blob(wp->db1, *(adb_val_t *)p1), 0);
adb_m_blob(&a2, adb_r_blob(wp->db2, *(adb_val_t *)p2), 0);
adb_r_rootobj(&a1, &o1, wp->schema);
adb_r_rootobj(&a2, &o2, wp->schema);
return adb_ro_cmpobj(&o1, &o2, wp->mode);
}
int adb_ra_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val)
int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl)
{
adb_val_t *ndx;
const struct adb_object_schema *schema = arr->schema, *item_schema;
struct adb_obj obj;
__db1 = db;
__db2 = arr->db;
__schema = arr->schema;
assert(__schema->kind == ADB_KIND_ARRAY);
__schema = container_of(__schema->fields[0].kind, struct adb_object_schema, kind);
assert(schema->kind == ADB_KIND_ARRAY);
assert(*schema->fields[0].kind == ADB_KIND_OBJECT);
item_schema = container_of(schema->fields[0].kind, struct adb_object_schema, kind),
assert(item_schema == tmpl->schema);
if (cur == 0) {
ndx = bsearch(&val, &arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp);
if (!ndx) return -1;
cur = ndx - arr->obj;
while (cur > 1 && wacmp(&val, &arr->obj[cur-1]) == 0) cur--;
unsigned m, l = ADBI_FIRST, r = adb_ra_num(arr) + 1;
while (l < r) {
m = (l + r) / 2;
if (adb_ro_cmpobj(tmpl, adb_ro_obj(arr, m, &obj), ADB_OBJCMP_INDEX) < 0)
r = m;
else
l = m + 1;
}
cur = r - 1;
} else {
cur++;
if (wacmp(&val, &arr->obj[cur]) != 0)
return -1;
}
return cur;
for (; cur <= adb_ra_num(arr); cur++) {
adb_ro_obj(arr, cur, &obj);
if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_TEMPLATE) == 0) return cur;
if (adb_ro_cmpobj(tmpl, &obj, ADB_OBJCMP_INDEX) != 0) return -1;
}
return -1;
}
/* Write interface */
@ -939,15 +976,20 @@ adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t b)
void adb_wa_sort(struct adb_obj *arr)
{
assert(arr->schema->kind == ADB_KIND_ARRAY);
__db1 = __db2 = arr->db;
const struct adb_object_schema *schema = arr->schema;
assert(schema->kind == ADB_KIND_ARRAY);
__wacmp_param = (struct wacmp_param) {
.db1 = arr->db,
.db2 = arr->db,
.mode = ADB_OBJCMP_EXACT,
};
switch (*arr->schema->fields[0].kind) {
case ADB_KIND_OBJECT:
__schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind);
__wacmp_param.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;
__wacmp_param.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:

View File

@ -105,13 +105,17 @@ struct adb_sign_v0 {
#define ADB_ARRAY_ITEM(_t) { { .kind = &(_t).kind } }
#define ADB_FIELD(_i, _n, _t) [(_i)-1] = { .name = _n, .kind = &(_t).kind }
#define ADB_OBJCMP_EXACT 0 // match all fields
#define ADB_OBJCMP_TEMPLATE 1 // match fields set on template
#define ADB_OBJCMP_INDEX 2 // match fields until first non-set one
struct adb_object_schema {
uint8_t kind;
uint16_t num_fields;
uint16_t num_compare;
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 {
@ -192,8 +196,9 @@ 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);
int adb_ro_cmpobj(const struct adb_obj *o1, const struct adb_obj *o2, unsigned mode);
int adb_ro_cmp(const struct adb_obj *o1, const struct adb_obj *o2, unsigned i, unsigned mode);
int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl);
/* Primitive write */
void adb_w_root(struct adb *, adb_val_t);

View File

@ -341,17 +341,12 @@ fail:
return -APKE_DEPENDENCY_FORMAT;
}
static int dependency_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
return adb_ro_cmp(o1, o2, ADBI_DEP_NAME);
}
const struct adb_object_schema schema_dependency = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_DEP_MAX,
.num_compare = ADBI_DEP_NAME,
.tostring = dependency_tostring,
.fromstring = dependency_fromstring,
.compare = dependency_cmp,
.fields = {
ADB_FIELD(ADBI_DEP_NAME, "name", scalar_string),
ADB_FIELD(ADBI_DEP_VERSION, "version", scalar_version),
@ -383,20 +378,10 @@ const struct adb_object_schema schema_dependency_array = {
.fields = ADB_ARRAY_ITEM(schema_dependency),
};
static int pkginfo_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
int r;
r = adb_ro_cmp(o1, o2, ADBI_PI_NAME);
if (r) return r;
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 = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_PI_MAX,
.compare = pkginfo_cmp,
.num_compare = ADBI_PI_UNIQUE_ID,
.fields = {
ADB_FIELD(ADBI_PI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_PI_VERSION, "version", scalar_version),
@ -448,15 +433,10 @@ const struct adb_object_schema schema_acl = {
},
};
static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
{
return adb_ro_cmp(o1, o2, ADBI_FI_NAME);
}
const struct adb_object_schema schema_file = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_FI_MAX,
.compare = file_cmp,
.num_compare = ADBI_FI_NAME,
.fields = {
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_FI_ACL, "acl", schema_acl),
@ -477,7 +457,7 @@ const struct adb_object_schema schema_file_array = {
const struct adb_object_schema schema_dir = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_DI_MAX,
.compare = file_cmp,
.num_compare = ADBI_DI_NAME,
.fields = {
ADB_FIELD(ADBI_DI_NAME, "name", scalar_string),
ADB_FIELD(ADBI_DI_ACL, "acl", schema_acl),
@ -506,15 +486,10 @@ 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,
.num_compare = ADBI_PKG_PKGINFO,
.fields = {
ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo),
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_dir_array),

View File

@ -208,7 +208,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
adb_w_init_tmp(&tmpdb, 200);
adb_wo_alloca(&tmpl, &schema_pkginfo, &tmpdb);
adb_w_init_alloca(&ctx->db, ADB_SCHEMA_INDEX, 1000);
adb_w_init_alloca(&ctx->db, ADB_SCHEMA_INDEX, 8000);
adb_wo_alloca(&ndx, &schema_index, &ctx->db);
adb_wo_alloca(&ctx->pkgs, &schema_pkginfo_array, &ctx->db);
adb_wo_alloca(&ctx->pkginfo, &schema_pkginfo, &ctx->db);
@ -240,7 +240,6 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
if (index_mtime >= fi.mtime) {
char *fname, *fend;
apk_blob_t bname, bver;
adb_val_t match;
int i;
/* Check that it looks like a package name */
@ -260,15 +259,13 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
adb_wo_blob(&tmpl, ADBI_PI_NAME, bname);
adb_wo_blob(&tmpl, ADBI_PI_VERSION, bver);
adb_wo_int(&tmpl, ADBI_PI_FILE_SIZE, fi.size);
match = adb_w_obj(&tmpl);
if ((i = adb_ra_find(&opkgs, 0, &tmpdb, match)) > 0) {
if ((i = adb_ra_find(&opkgs, 0, &tmpl)) > 0) {
struct adb_obj pkg;
adb_ro_obj(&opkgs, i, &pkg);
val = adb_wa_append(&ctx->pkgs, adb_w_copy(&ctx->db, &odb, adb_ro_val(&opkgs, i)));
found = TRUE;
break;
}
}
if (!found) {