aboutsummaryrefslogtreecommitdiffstats
path: root/src/apk_adb.c
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2019-12-13 15:22:33 +0200
committerTimo Teräs <timo.teras@iki.fi>2020-04-01 15:58:49 +0300
commite79226010a0641f701b6e12392e176cc2cf58d72 (patch)
treedec5311a1fc0cfb837b4af4038cab7bdedc2bb4c /src/apk_adb.c
parentd6c54f932054c58aee8f7a6d2bd49b115d804da1 (diff)
downloadaports-v3.0-wip.tar.bz2
aports-v3.0-wip.tar.xz
adb: introduce apk-tools database format, and few appletsv3.0-wip
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.
Diffstat (limited to 'src/apk_adb.c')
-rw-r--r--src/apk_adb.c203
1 files changed, 203 insertions, 0 deletions
diff --git a/src/apk_adb.c b/src/apk_adb.c
new file mode 100644
index 0000000000..7dc077f89b
--- /dev/null
+++ b/src/apk_adb.c
@@ -0,0 +1,203 @@
+#include "apk_adb.h"
+#include "apk_version.h"
+
+#define APK_VERSION_CONFLICT 16
+
+adb_val_t adb_w_dependency(struct adb *db, 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;
+ struct adb_obj obj;
+ apk_blob_t bdep, bname, bop, bver = APK_BLOB_NULL, btag;
+ int mask = APK_DEPMASK_ANY;
+
+ adb_wo_alloca(&obj, &schema_dependency, db);
+
+ /* [!]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 */
+
+ adb_wo_blob(&obj, ADBI_DEP_NAME, bname);
+ if (mask != APK_DEPMASK_ANY) {
+ adb_wo_blob(&obj, ADBI_DEP_VERSION, bver);
+ if (mask != APK_VERSION_EQUAL)
+ adb_wo_int(&obj, ADBI_DEP_MATCH, mask);
+ }
+ return adb_w_obj(&obj);
+
+fail:
+ return ADB_NULL;
+}
+
+adb_val_t adb_w_pkginfo(struct adb *db, unsigned int f, apk_blob_t *val)
+{
+ struct apk_checksum csum;
+ struct adb_obj deps;
+
+ switch (f) {
+ case ADBI_PI_INSTALLED_SIZE:
+ case ADBI_PI_FILE_SIZE:
+ case ADBI_PI_BUILD_TIME:
+ case ADBI_PI_PRIORITY:;
+ uint32_t n = apk_blob_pull_uint(val, 10);
+ if (!n) break;
+ return adb_w_int(db, n);
+
+ case ADBI_PI_DEPENDS:
+ case ADBI_PI_INSTALL_IF:
+ case ADBI_PI_PROVIDES:
+ case ADBI_PI_REPLACES:
+ /* array of package names */
+ adb_wo_alloca(&deps, &schema_dependency_array, db);
+ while (val->len)
+ adb_wa_append(&deps, adb_w_dependency(db, val));
+ return adb_w_arr(&deps);
+
+ case ADBI_PI_UNIQUE_ID:
+ if (!val->ptr || val->len < 4) break;
+ apk_blob_pull_csum(val, &csum);
+ return adb_w_int(db, get_unaligned32(csum.data) & ADB_VALUE_MASK);
+
+ 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(db, APK_BLOB_CSUM(csum));
+ break;
+ default:
+ if (!val->len) break;
+ return adb_w_blob(db, *val);
+ }
+
+ return ADB_ERROR(EAPKFORMAT);
+}
+
+static struct adb *__db1, *__db2;
+
+static int pkginfo_cmp(const void *p1, const void *p2)
+{
+ struct adb_obj o1, o2;
+ int r;
+
+ adb_r_obj(__db1, *(adb_val_t *)p1, &o1, &schema_pkginfo);
+ adb_r_obj(__db2, *(adb_val_t *)p2, &o2, &schema_pkginfo);
+
+ r = apk_blob_sort(
+ adb_ro_blob(&o1, ADBI_PI_NAME),
+ adb_ro_blob(&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;
+ default: return 0;
+ }
+}
+
+int adb_r_pkgindex_find(struct adb_obj *arr, int cur, struct adb *db, adb_val_t val)
+{
+ adb_val_t *ndx;
+
+ __db1 = db;
+ __db2 = arr->db;
+
+ if (cur == 0) {
+ ndx = bsearch(&val, &arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), pkginfo_cmp);
+ if (!ndx) return -1;
+ cur = ndx - arr->obj;
+ while (cur > 1 && pkginfo_cmp(&val, &arr->obj[cur-1]) == 0) cur--;
+ } else {
+ cur++;
+ if (pkginfo_cmp(&val, &arr->obj[cur]) != 0)
+ return -1;
+ }
+ return cur;
+
+}
+
+unsigned int adb_pkg_field_index(char f)
+{
+#define MAP(ch, ndx) [ch - 'A'] = ndx
+ static unsigned char map[] = {
+ MAP('C', ADBI_PI_UNIQUE_ID),
+ MAP('P', ADBI_PI_NAME),
+ MAP('V', ADBI_PI_VERSION),
+ MAP('T', ADBI_PI_DESCRIPTION),
+ MAP('U', ADBI_PI_URL),
+ MAP('I', ADBI_PI_INSTALLED_SIZE),
+ MAP('S', ADBI_PI_FILE_SIZE),
+ MAP('L', ADBI_PI_LICENSE),
+ MAP('A', ADBI_PI_ARCH),
+ MAP('D', ADBI_PI_DEPENDS),
+ MAP('i', ADBI_PI_INSTALL_IF),
+ MAP('p', ADBI_PI_PROVIDES),
+ MAP('o', ADBI_PI_ORIGIN),
+ MAP('m', ADBI_PI_MAINTAINER),
+ MAP('t', ADBI_PI_BUILD_TIME),
+ MAP('c', ADBI_PI_REPO_COMMIT),
+ MAP('r', ADBI_PI_REPLACES),
+ MAP('k', ADBI_PI_PRIORITY),
+ };
+ if (f < 'A' || f-'A' >= ARRAY_SIZE(map)) return 0;
+ return map[(unsigned char)f - 'A'];
+}