summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2022-03-21 12:48:16 +0200
committerTimo Teräs <timo.teras@iki.fi>2022-03-21 14:09:06 +0200
commitc6b9297bcb1c9d5ff11fceb0a453ec4daa1ee6dd (patch)
treeb9fd2078b4eccc384f2fe06e5fab9f0e35be5e5e
parent950972a56b6c9ba6e33b33e60cab076f5a18daec (diff)
downloadapk-tools-c6b9297bcb1c9d5ff11fceb0a453ec4daa1ee6dd.tar.gz
apk-tools-c6b9297bcb1c9d5ff11fceb0a453ec4daa1ee6dd.tar.bz2
apk-tools-c6b9297bcb1c9d5ff11fceb0a453ec4daa1ee6dd.tar.xz
apk-tools-c6b9297bcb1c9d5ff11fceb0a453ec4daa1ee6dd.zip
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
-rw-r--r--src/adb.c122
-rw-r--r--src/adb.h11
-rw-r--r--src/apk_adb.c35
-rw-r--r--src/app_mkndx.c7
4 files changed, 97 insertions, 78 deletions
diff --git a/src/adb.c b/src/adb.c
index 560e19f..ed896ff 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -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:
diff --git a/src/adb.h b/src/adb.h
index 49509d4..3372c07 100644
--- a/src/adb.h
+++ b/src/adb.h
@@ -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);
diff --git a/src/apk_adb.c b/src/apk_adb.c
index 25508c1..febe359 100644
--- a/src/apk_adb.c
+++ b/src/apk_adb.c
@@ -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),
diff --git a/src/app_mkndx.c b/src/app_mkndx.c
index ba01878..9e6cd7b 100644
--- a/src/app_mkndx.c
+++ b/src/app_mkndx.c
@@ -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) {