#include <fcntl.h>
#include <zlib.h>
-
+#include <zstd.h>
#include "pool.h"
#include "repo.h"
#include "solv_xfopen.h"
#include "tarhead.h"
#include "repo_apk.h"
+#include "repo_apkv3.h"
+/* zlib decompression */
struct zstream {
int fd;
};
static struct zstream *
-apkz_open(int fd)
+apkz_open(int fd, int raw)
{
struct zstream *zstream = solv_calloc(1, sizeof(*zstream));
zstream->fd = fd;
- if (inflateInit2(&zstream->zs, 15 + 32) != Z_OK) /* 32: enable gzip */
+ if (inflateInit2(&zstream->zs, raw ? -15 : 15 + 32) != Z_OK) /* 32: enable gzip */
{
- solv_free(&zstream->zs);
+ solv_free(zstream);
return 0;
}
return zstream;
}
}
+/* zstd decompression */
+
+struct zstdstream {
+ int fd;
+ FILE *fp;
+ int eof;
+ ZSTD_DCtx *ctx;
+ ZSTD_inBuffer in;
+ unsigned char buf[65536];
+};
+
+static struct zstdstream *
+apkzstd_open(int fd)
+{
+ struct zstdstream *zstdstream = solv_calloc(1, sizeof(*zstdstream));
+ zstdstream->fd = fd;
+ zstdstream->in.src = zstdstream->buf;
+ zstdstream->in.size = zstdstream->in.pos = 0;
+ if (!(zstdstream->ctx = ZSTD_createDCtx()))
+ {
+ solv_free(zstdstream);
+ return 0;
+ }
+ return zstdstream;
+}
+
+static int
+apkzstd_close(void *cookie)
+{
+ struct zstdstream *zstdstream = cookie;
+ ZSTD_freeDCtx(zstdstream->ctx);
+ if (zstdstream->fd != -1)
+ close(zstdstream->fd);
+ solv_free(zstdstream);
+ return 0;
+}
+
+static inline ssize_t
+apkzstd_fillbuf(struct zstdstream *zstdstream)
+{
+ ssize_t rr;
+ if (zstdstream->fp)
+ {
+ rr = fread(zstdstream->buf, 1, sizeof(zstdstream->buf), zstdstream->fp);
+ if (rr <= 0 && ferror(zstdstream->fp))
+ rr = -1;
+ }
+ else
+ rr = read(zstdstream->fd, zstdstream->buf, sizeof(zstdstream->buf));
+ if (rr >= 0)
+ {
+ zstdstream->in.pos = 0;
+ zstdstream->in.size = rr;
+ }
+ return rr;
+}
+
+static ssize_t
+apkzstd_read(void *cookie, char *buf, size_t len)
+{
+ struct zstdstream *zstdstream = cookie;
+ ZSTD_outBuffer out;
+ int eof = 0;
+ size_t r;
+
+ if (!zstdstream)
+ return -1;
+ if (zstdstream->eof)
+ return 0;
+ out.dst = buf;
+ out.pos = 0;
+ out.size = len;
+ for (;;)
+ {
+ if (zstdstream->in.pos >= zstdstream->in.size)
+ {
+ ssize_t rr = apkzstd_fillbuf(zstdstream);
+ if (rr < 0)
+ return rr;
+ if (rr == 0)
+ eof = 1;
+ }
+ r = ZSTD_decompressStream(zstdstream->ctx, &out, &zstdstream->in);
+ if (ZSTD_isError(r))
+ return -1;
+ if (out.pos == out.size || eof)
+ return out.pos;
+ }
+}
+
+
+/* apkv3 handling */
+
+static FILE *
+open_apkv3_error(Pool *pool, int fd, const char *fn, const char *msg)
+{
+ pool_error(pool, -1, "%s: %s", fn, msg);
+ if (fd != -1)
+ close(fd);
+ return 0;
+}
+
+static FILE *
+open_apkv3(Pool *pool, int fd, FILE *fp, const char *fn, int adbchar)
+{
+ unsigned char comp[2];
+ char buf[4];
+ FILE *cfp;
+
+ comp[0] = comp[1] = 0;
+ if (adbchar == 'c')
+ {
+ ssize_t r;
+ if (fp)
+ r = fread(comp, 2, 1, fp) == 1 ? 2 : feof(fp) ? 0 : -1;
+ else
+ r = read(fd, comp, 2);
+ if (r != 2)
+ return open_apkv3_error(pool, fd, fn, "compression header read error");
+ }
+ else if (adbchar == 'd')
+ comp[0] = 1;
+ else if (adbchar != '.')
+ return open_apkv3_error(pool, fd, fn, "not an apkv3 file");
+ if (comp[0] == 0)
+ cfp = fp ? fp : fdopen(fd, "r");
+ else if (comp[0] == 1)
+ {
+ struct zstream *zstream = apkz_open(fd, 1);
+ if (!zstream)
+ return open_apkv3_error(pool, fd, fn, "zstream setup error");
+ if (fp)
+ zstream->fp = fp;
+ if ((cfp = solv_cookieopen(zstream, "r", apkz_read, 0, apkz_close)) == 0)
+ return open_apkv3_error(pool, fd, fn, "zstream cookie setup error");
+ }
+ else if (comp[0] == 2)
+ {
+ struct zstdstream *zstdstream = apkzstd_open(fd);
+ if (!zstdstream)
+ return open_apkv3_error(pool, fd, fn, "zstdstream setup error");
+ if (fp)
+ zstdstream->fp = fp;
+ if ((cfp = solv_cookieopen(zstdstream, "r", apkzstd_read, 0, apkzstd_close)) == 0)
+ return open_apkv3_error(pool, fd, fn, "zstdstream cookie setup error");
+ }
+ else
+ return open_apkv3_error(pool, fd, fn, "unsupported apkv3 compression");
+
+ if (adbchar != '.')
+ {
+ if (fread(buf, 4, 1, cfp) != 1 || buf[0] != 'A' || buf[1] != 'D' || buf[2] != 'B' || buf[3] != '.')
+ {
+ pool_error(pool, -1, "%s: not an apkv3 file", fn);
+ if (cfp != fp)
+ fclose(cfp);
+ return 0;
+ }
+ }
+ return cfp;
+}
+
+static Id
+add_apkv3_pkg(Repo *repo, Repodata *data, const char *fn, int flags, int fd, int adbchar)
+{
+ FILE *fp;
+ Id p;
+ if (!(fp = open_apkv3(repo->pool, fd, 0, fn, adbchar)))
+ return 0;
+ p = apkv3_add_pkg(repo, data, fn, fp, flags);
+ fclose(fp);
+ return p;
+}
+
+static int
+add_apkv3_idx(Repo *repo, Repodata *data, FILE *fp, int flags, int adbchar)
+{
+ FILE *cfp;
+ int r;
+ if (!(cfp = open_apkv3(repo->pool, -1, fp, (flags & APK_ADD_INDEX ? "installed db" : "package index"), adbchar)))
+ return -1;
+ r = apkv3_add_idx(repo, data, cfp, flags);
+ fclose(cfp);
+ return r;
+}
+
+
+/* apkv2 handling */
+
static void
add_deps(Repo *repo, Solvable *s, Id what, char *p)
{
char *line = 0;
size_t l, line_alloc = 0;
int haveorigin = 0;
+ char first[4];
data = repo_add_repodata(repo, flags);
if ((fd = open(flags & REPO_USE_ROOTDIR ? pool_prepend_rootdir_tmp(pool, fn) : fn, O_RDONLY)) == -1)
pool_error(pool, -1, "%s: %s", fn, strerror(errno));
return 0;
}
- zstream = apkz_open(fd);
+ if (read(fd, first, 4) == 4 && first[0] == 'A' && first[1] == 'D' && first[2] == 'B')
+ return add_apkv3_pkg(repo, data, fn, flags, fd, first[3]);
+ if (lseek(fd, 0, SEEK_SET))
+ {
+ pool_error(pool, -1, "%s: lseek: %s", fn, strerror(errno));
+ close(fd);
+ return 0;
+ }
+ zstream = apkz_open(fd, 0);
if (!zstream)
{
pool_error(pool, -1, "%s: %s", fn, strerror(errno));
fclose(fp);
return 0;
}
- if (flags & APK_ADD_WITH_HDRID)
+ if ((flags & APK_ADD_WITH_HDRID) != 0)
{
q1chk = solv_chksum_create(REPOKEY_TYPE_SHA1);
zstream->readcb_data = q1chk;
else if (!strncmp(line, "arch = ", 7))
s->arch = pool_str2id(pool, line + 7, 1);
else if (!strncmp(line, "license = ", 10))
- repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
+ repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_LICENSE, line + 10);
else if (!strncmp(line, "origin = ", 9))
{
if (s->name && !strcmp(line + 9, pool_id2str(pool, s->name)))
}
static void
-apk_process_index(Repo *repo, Repodata *data, struct tarhead *th)
+apk_process_index(Repo *repo, Repodata *data, struct tarhead *th, int flags)
{
Pool *pool = repo->pool;
Solvable *s = 0;
else if (line[0] == 'A')
s->arch = pool_str2id(pool, line + 2, 1);
else if (line[0] == 'L')
- repodata_add_poolstr_array(data, s - pool->solvables, SOLVABLE_LICENSE, line + 2);
+ repodata_set_poolstr(data, s - pool->solvables, SOLVABLE_LICENSE, line + 2);
else if (line[0] == 'o')
{
if (s->name && !strcmp(line + 2, pool_id2str(pool, s->name)))
add_deps(repo, s, SOLVABLE_PROVIDES, line + 2);
else if (line[0] == 'i')
add_deps(repo, s, SOLVABLE_SUPPLEMENTS, line + 2);
- else if (line[0] == 'C')
+ else if (line[0] == 'C' && (flags & APK_ADD_WITH_HDRID) != 0)
apk_add_hdrid(data, s - pool->solvables, line + 2);
}
solv_free(line);
int
repo_add_apk_repo(Repo *repo, FILE *fp, int flags)
{
+ char first[4];
struct tarhead th;
Repodata *data;
int c;
return (flags & APK_ADD_INDEX) != 0 ? 0 : -1; /* an empty file is allowed for the v2 index */
ungetc(c, fp);
+ if (c == 'A')
+ {
+ if (fread(first, 4, 1, fp) != 1)
+ return -1;
+ if (first[0] == 'A' && first[1] == 'D' && first[2] == 'B')
+ return add_apkv3_idx(repo, data, fp, flags, first[3]);
+ if ((flags & APK_ADD_INDEX) == 0)
+ return -1; /* not a tar file */
+ }
+
if (c == 0x1f)
{
struct zstream *zstream;
/* gzip compressed, setup decompression */
- zstream = apkz_open(-1);
+ zstream = apkz_open(-1, 0);
if (!zstream)
return -1;
zstream->fp = fp;
}
tarhead_init(&th, fp);
+ if (c == 'A')
+ {
+ /* initialize input buffer with 4 bytes we already read */
+ memcpy(th.blk, first, 4);
+ th.end = 4;
+ }
if ((flags & APK_ADD_INDEX) != 0)
- apk_process_index(repo, data, &th);
+ apk_process_index(repo, data, &th, flags);
else
{
while (tarhead_next(&th) > 0)
if (th.type != 1 || strcmp(th.path, "APKINDEX") != 0)
tarhead_skip(&th);
else
- apk_process_index(repo, data, &th);
+ apk_process_index(repo, data, &th, flags);
}
}
tarhead_free(&th);
--- /dev/null
+/*
+ * Copyright (c) 2024, SUSE LLC
+ *
+ * This program is licensed under the BSD license, read LICENSE.BSD
+ * for further information
+ */
+
+/*
+ * implement processing of uncompressed apkv3 data (without the leading "ADB.")
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+#include <fcntl.h>
+
+#include "pool.h"
+#include "repo.h"
+#include "util.h"
+#include "chksum.h"
+
+#include "repo_apk.h"
+#include "repo_apkv3.h"
+
+
+#define ADB_MAX_SIZE 0x10000000
+
+static inline unsigned int
+adb_u32(const unsigned char *p)
+{
+ return p[0] | p[1] << 8 | p[2] << 16 | p[3] << 24;
+}
+
+static int
+adb_read_blk_header(FILE *fp, unsigned long long *sizep)
+{
+ unsigned char buf[12];
+ unsigned int size;
+ unsigned long long lsize;
+ if (fread(buf, 4, 1, fp) != 1)
+ return -1;
+ size = buf[0] | buf[1] << 8 | buf[2] << 16 | (buf[3] & 0x3f) << 24;
+ if ((buf[3] & 0xc0) != 0xc0)
+ {
+ if (size < 4)
+ return -1;
+ *sizep = size - 4;
+ return (buf[3] & 0xc0) >> 3;
+ }
+ if (fread(buf, 12, 1, fp) != 1)
+ return -1;
+ lsize = adb_u32(buf + 4);
+ lsize |= (unsigned long long)adb_u32(buf + 8) << 32;
+ if (lsize < 16)
+ return -1;
+ *sizep = lsize - 16;
+ return size;
+}
+
+/* low level */
+
+static const unsigned char *
+adb_blob(const unsigned char *adb, size_t adblen, unsigned int v, size_t *bloblp)
+{
+ size_t blobl;
+ int type = (v >> 28) & 15;
+ v &= 0xfffffff;
+ if (type != 8 && type != 9 && type != 10)
+ return 0;
+ if (v + (type == 8 ? 1 : type == 9 ? 2 : 4) > adblen)
+ return 0;
+ blobl = adb[v++];
+ if (type > 8)
+ blobl |= adb[v++] << 8;
+ if (type > 9)
+ {
+ blobl |= adb[v++] << 16;
+ blobl |= adb[v++] << 24;
+ }
+ if (v + blobl > adblen)
+ return 0;
+ *bloblp = blobl;
+ return adb + v;
+}
+
+static int
+adb_num(const unsigned char *adb, size_t adblen, unsigned int v, unsigned long long *nump)
+{
+ unsigned long long num;
+ int type = (v >> 28) & 15;
+ v &= 0xfffffff;
+ if (type != 1 && type != 2 && type != 3)
+ return 0;
+ if (type == 1)
+ {
+ *nump = v;
+ return 1;
+ }
+ if (v + (type == 2 ? 4 : 8) > adblen)
+ return 0;
+ num = adb_u32(adb + v);
+ if (type == 3)
+ num |= (unsigned long long)adb_u32(adb + v + 4) << 32;
+ *nump = num;
+ return 1;
+}
+
+static unsigned int
+adb_arr(const unsigned char *adb, size_t adblen, unsigned int v)
+{
+ unsigned int cnt;
+ int type = (v >> 28) & 15;
+ v &= 0xfffffff;
+ if (type != 13 && type != 14)
+ return 0;
+ if (v + 4 > adblen)
+ return 0;
+ cnt = adb_u32(adb + v);
+ if (cnt == 0 || cnt >= 0x1000000 || v + 4 * cnt > adblen)
+ return 0;
+ return cnt;
+}
+
+static inline unsigned int
+adb_idx(const unsigned char *adb, unsigned int v, unsigned int cnt, unsigned int idx)
+{
+ if (idx >= cnt)
+ return 0;
+ v = (v & 0xfffffff) + idx * 4;
+ return adb_u32(adb + v);
+}
+
+/* high level */
+
+static Id
+adb_poolid(const unsigned char *adb, size_t adblen, unsigned int v, Pool *pool)
+{
+ size_t blobl;
+ const unsigned char *blob = adb_blob(adb, adblen, v, &blobl);
+ return blob && blobl < 0x1000000 ? pool_strn2id(pool, (const char *)blob, (unsigned int)blobl, 1) : 0;
+}
+
+static void
+adb_setstr(const unsigned char *adb, size_t adblen, unsigned int v, Repodata *data, Id p, Id key)
+{
+ size_t blobl;
+ const unsigned char *blob = adb_blob(adb, adblen, v, &blobl);
+ if (blob && blobl < 0x1000000)
+ {
+ char *space = pool_alloctmpspace(data->repo->pool, blobl + 1);
+ memcpy(space, blob, blobl);
+ space[blobl] = 0;
+ repodata_set_str(data, p, key, space);
+ pool_freetmpspace(data->repo->pool, space);
+ }
+}
+
+static void
+adb_setnum(const unsigned char *adb, size_t adblen, unsigned int v, Repodata *data, Id p, Id key)
+{
+ unsigned long long x;
+ if (adb_num(adb, adblen, v, &x))
+ repodata_set_num(data, p, key, x);
+}
+
+static void
+adb_setchksum(const unsigned char *adb, size_t adblen, unsigned int v, Repodata *data, Id p, Id key)
+{
+ size_t blobl;
+ const unsigned char *blob = adb_blob(adb, adblen, v, &blobl);
+ if (blob && blobl == 20)
+ repodata_set_bin_checksum(data, p, key, REPOKEY_TYPE_SHA1, blob);
+ else if (blob && blobl == 32)
+ repodata_set_bin_checksum(data, p, key, REPOKEY_TYPE_SHA256, blob);
+ else if (blob && blobl == 64)
+ repodata_set_bin_checksum(data, p, key, REPOKEY_TYPE_SHA512, blob);
+}
+
+
+static Id
+adb_get_dep(const unsigned char *adb, size_t adblen, unsigned int v, Pool *pool, Id *whatp)
+{
+ unsigned int cnt;
+ Id id, evr;
+ unsigned long long match;;
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ return 0;
+ id = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 1), pool);
+ if (!id)
+ return 0;
+ evr = cnt > 2 ? adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 2), pool) : 0;
+ match = cnt > 3 ? adb_num(adb, adblen, adb_idx(adb, v, cnt, 3), &match) : 1;
+ if (match & 16)
+ {
+ if (!whatp || *whatp != SOLVABLE_REQUIRES)
+ return 0;
+ *whatp = SOLVABLE_CONFLICTS;
+ }
+ if (evr)
+ {
+ int flags = 0;
+ if (match & 1)
+ flags |= REL_EQ;
+ if (match & 2)
+ flags |= REL_LT;
+ if (match & 4)
+ flags |= REL_GT;
+ if (match & 8)
+ {
+ /* fuzzy match, prepend ~ to evr */
+ char *space = pool_alloctmpspace(pool, strlen(pool_id2str(pool, evr)) + 2);
+ space[0] = '~';
+ strcpy(space, pool_id2str(pool, evr));
+ evr = pool_str2id(pool, space, 1);
+ pool_freetmpspace(pool, space);
+ }
+ id = pool_rel2id(pool, id, evr, flags, 1);
+ }
+ return id;
+}
+
+static void
+adb_add_deps(const unsigned char *adb, size_t adblen, unsigned int v, Repodata *data, Id p, Id what)
+{
+ Id supplements = 0;
+ Id id, oldwhat = what;
+ Repo *repo = data->repo;
+ Pool *pool = repo->pool;
+ Solvable *s = pool->solvables + p;
+ unsigned int cnt, idx;
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ return;
+ for (idx = 1; idx < cnt; idx++)
+ {
+ unsigned int vv = adb_idx(adb, v, cnt, idx);
+ if (!vv)
+ continue;
+ what = oldwhat;
+ id = adb_get_dep(adb, adblen, vv, pool, &what);
+ if (!id)
+ continue;
+ if (what == SOLVABLE_PROVIDES)
+ s->provides = repo_addid_dep(repo, s->provides, id, 0);
+ else if (what == SOLVABLE_REQUIRES)
+ s->requires = repo_addid_dep(repo, s->requires, id, 0);
+ else if (what == SOLVABLE_CONFLICTS)
+ s->conflicts = repo_addid_dep(repo, s->conflicts, id, 0);
+ else if (what == SOLVABLE_RECOMMENDS)
+ s->recommends = repo_addid_dep(repo, s->recommends, id, 0);
+ else if (what == SOLVABLE_SUPPLEMENTS)
+ supplements = supplements ? pool_rel2id(pool, id, supplements, REL_AND, 1) : id;
+ }
+ if (supplements)
+ s->supplements = repo_addid_dep(repo, s->supplements, supplements, 0);
+}
+
+static Id
+adb_add_pkg_info(Pool *pool, Repo *repo, Repodata *data, const unsigned char *adb, size_t adblen, unsigned int v, int flags)
+{
+ Solvable *s;
+ unsigned int cnt;
+ Id name, origin, license;
+
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ return 0;
+ name = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 1), pool);
+ if (!name)
+ return 0;
+ s = pool_id2solvable(pool, repo_add_solvable(repo));
+ s->name = name;
+ s->evr = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 2), pool);
+ adb_setstr(adb, adblen, adb_idx(adb, v, cnt, 4), data, s - pool->solvables, SOLVABLE_DESCRIPTION);
+ s->arch = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 5), pool);
+ license = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 6), pool);
+ if (license)
+ repodata_set_id(data, s - pool->solvables, SOLVABLE_LICENSE, license);
+ origin = adb_poolid(adb, adblen, adb_idx(adb, v, cnt, 7), pool);
+ if (origin && origin != s->name)
+ repodata_set_id(data, s - pool->solvables, SOLVABLE_SOURCENAME, origin);
+ else
+ repodata_set_void(data, s - pool->solvables, SOLVABLE_SOURCENAME);
+ adb_setstr(adb, adblen, adb_idx(adb, v, cnt, 9), data, s - pool->solvables, SOLVABLE_URL);
+ adb_setnum(adb, adblen, adb_idx(adb, v, cnt, 11), data, s - pool->solvables, SOLVABLE_BUILDTIME);
+ adb_setnum(adb, adblen, adb_idx(adb, v, cnt, 12), data, s - pool->solvables, SOLVABLE_INSTALLSIZE);
+ adb_setnum(adb, adblen, adb_idx(adb, v, cnt, 13), data, s - pool->solvables, SOLVABLE_DOWNLOADSIZE);
+ if ((flags & APK_ADD_WITH_HDRID) != 0)
+ adb_setchksum(adb, adblen, adb_idx(adb, v, cnt, 3), data, s - pool->solvables, SOLVABLE_HDRID);
+ adb_add_deps(adb, adblen, adb_idx(adb, v, cnt, 15), data, s - pool->solvables, SOLVABLE_REQUIRES);
+ adb_add_deps(adb, adblen, adb_idx(adb, v, cnt, 16), data, s - pool->solvables, SOLVABLE_PROVIDES);
+ adb_add_deps(adb, adblen, adb_idx(adb, v, cnt, 18), data, s - pool->solvables, SOLVABLE_SUPPLEMENTS);
+ adb_add_deps(adb, adblen, adb_idx(adb, v, cnt, 19), data, s - pool->solvables, SOLVABLE_RECOMMENDS);
+ if (!s->arch)
+ s->arch = ARCH_NOARCH;
+ if (!s->evr)
+ s->evr = ID_EMPTY;
+ s->provides = repo_addid_dep(repo, s->provides, pool_rel2id(pool, s->name, s->evr, REL_EQ, 1), 0);
+ return s - pool->solvables;
+}
+
+static Id
+add_add_idb_pkg(Pool *pool, Repo *repo, Repodata *data, const unsigned char *adb, size_t adblen, unsigned int v, int flags)
+{
+ unsigned int cnt;
+ size_t blobl;
+ const unsigned char *blob = adb_blob(adb, adblen, v, &blobl);
+ if (blobl < 4 + 2 + 4 || blobl >= ADB_MAX_SIZE || (blob[3] & 0xf0) != 0)
+ return 0;
+ adb = (unsigned char *)blob + 4;
+ adblen = blobl - 4;
+ v = adb_u32(adb + 4);
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ return 0;
+ return adb_add_pkg_info(pool, repo, data, adb, adblen, adb_idx(adb, v, cnt, 1), flags);
+}
+
+static const unsigned char *
+adb_read_adb_blk(Pool *pool, FILE *fp, const char *fn, size_t *adblenp)
+{
+ unsigned char *adb;
+ unsigned long long size;
+ if (adb_read_blk_header(fp, &size) != 0)
+ {
+ pool_error(pool, -1, "%s: missing adb block", fn);
+ return 0;
+ }
+ if (size > ADB_MAX_SIZE)
+ {
+ pool_error(pool, -1, "%s: oversized adb block", fn);
+ return 0;
+ }
+ adb = solv_malloc((size_t)size);
+ if (fread(adb, (size_t)size, 1, fp) != 1)
+ {
+ pool_error(pool, -1, "%s: adb block read error", fn);
+ return 0;
+ }
+ *adblenp = (size_t)size;
+ return adb;
+}
+
+Id
+apkv3_add_pkg(Repo *repo, Repodata *data, const char *fn, FILE *fp, int flags)
+{
+ Pool *pool = repo->pool;
+ char buf[4];
+ const unsigned char *adb;
+ size_t adblen;
+ unsigned int v, cnt;
+ Id p;
+
+ if (fread(buf, 4, 1, fp) != 1 || buf[0] != 'p' || buf[1] != 'c' || buf[2] != 'k' || buf[3] != 'g')
+ {
+ pool_error(pool, -1, "%s: not an apkv3 package", fn);
+ return 0;
+ }
+
+ adb = adb_read_adb_blk(pool, fp, fn, &adblen);
+ if (!adb)
+ return 0;
+
+ v = adb_u32(adb + 4);
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ {
+ solv_free((void *)adb);
+ return 0;
+ }
+ p = adb_add_pkg_info(pool, repo, data, adb, adblen, adb_idx(adb, v, cnt, 1), flags);
+ if (p && (flags & APK_ADD_WITH_PKGID) != 0)
+ {
+ unsigned char pkgid[16];
+ Chksum *pkgidchk = solv_chksum_create(REPOKEY_TYPE_MD5);
+ solv_chksum_add(pkgidchk, adb, adblen);
+ solv_chksum_free(pkgidchk, pkgid);
+ repodata_set_bin_checksum(data, p, SOLVABLE_PKGID, REPOKEY_TYPE_MD5, pkgid);
+ }
+ solv_free((void *)adb);
+ return p;
+}
+
+int
+apkv3_add_idx(Repo *repo, Repodata *data, FILE *fp, int flags)
+{
+ Pool *pool = repo->pool;
+ char buf[4];
+ const unsigned char *adb;
+ size_t adblen;
+ unsigned int v, cnt, idx;
+ int idb = flags & APK_ADD_INDEX ? 1 : 0;
+
+ if (fread(buf, 4, 1, fp) != 1 || memcmp(buf, (idb ? "idb" : "indx") , 4))
+ {
+ pool_error(pool, -1, (idb ? "not an apkv3 installed database" : "not an apkv3 index"));
+ return -1;
+ }
+
+ adb = adb_read_adb_blk(pool, fp, idb ? "installed database" : "index", &adblen);
+ if (!adb)
+ return -1;
+
+ v = adb_u32(adb + 4);
+ if (!(cnt = adb_arr(adb, adblen, v)))
+ {
+ solv_free((void *)adb);
+ return -1;
+ }
+ v = adb_idx(adb, v, cnt, idb ? 1 : 2);
+ if ((cnt = adb_arr(adb, adblen, v)) != 0)
+ {
+ for (idx = 1; idx < cnt; idx++)
+ {
+ if (idb)
+ add_add_idb_pkg(pool, repo, data, adb, adblen, adb_idx(adb, v, cnt, idx), flags);
+ else
+ adb_add_pkg_info(pool, repo, data, adb, adblen, adb_idx(adb, v, cnt, idx), flags);
+ }
+ }
+ solv_free((void *)adb);
+ return 0;
+}
+