Further refactor extract API to have separate ops vtable
This splits the callbacks by type, and further prepares the API to be usable for v3 files too.cute-signatures
parent
9c843e4ecd
commit
5843daf7a1
|
@ -14,6 +14,7 @@
|
||||||
#include "apk_print.h"
|
#include "apk_print.h"
|
||||||
#include "apk_io.h"
|
#include "apk_io.h"
|
||||||
|
|
||||||
|
struct adb;
|
||||||
struct apk_ctx;
|
struct apk_ctx;
|
||||||
struct apk_extract_ctx;
|
struct apk_extract_ctx;
|
||||||
|
|
||||||
|
@ -26,26 +27,31 @@ int apk_extract_file(int atfd, const struct apk_file_info *ae,
|
||||||
apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
|
apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
|
||||||
unsigned int extract_flags, struct apk_out *out);
|
unsigned int extract_flags, struct apk_out *out);
|
||||||
|
|
||||||
|
struct apk_extract_ops {
|
||||||
typedef int (*apk_extract_cb)(struct apk_extract_ctx *,
|
int (*v2index)(struct apk_extract_ctx *, apk_blob_t *desc, struct apk_istream *is);
|
||||||
const struct apk_file_info *ae,
|
int (*v2meta)(struct apk_extract_ctx *, struct apk_istream *is);
|
||||||
struct apk_istream *istream);
|
int (*v3index)(struct apk_extract_ctx *, struct adb *);
|
||||||
|
int (*v3meta)(struct apk_extract_ctx *, struct adb *);
|
||||||
|
int (*script)(struct apk_extract_ctx *, unsigned int script, size_t size, struct apk_istream *is);
|
||||||
|
int (*file)(struct apk_extract_ctx *, const struct apk_file_info *fi, struct apk_istream *is);
|
||||||
|
};
|
||||||
|
|
||||||
struct apk_extract_ctx {
|
struct apk_extract_ctx {
|
||||||
struct apk_ctx *ac;
|
struct apk_ctx *ac;
|
||||||
apk_extract_cb cb;
|
const struct apk_extract_ops *ops;
|
||||||
struct apk_checksum *identity;
|
struct apk_checksum *identity;
|
||||||
unsigned generate_identity : 1;
|
apk_blob_t desc;
|
||||||
unsigned metadata : 1;
|
|
||||||
unsigned metadata_verified : 1;
|
|
||||||
void *pctx;
|
void *pctx;
|
||||||
|
unsigned generate_identity : 1;
|
||||||
|
unsigned is_package : 1;
|
||||||
|
unsigned is_index : 1;
|
||||||
};
|
};
|
||||||
|
|
||||||
static inline void apk_extract_init(struct apk_extract_ctx *ectx, struct apk_ctx *ac, apk_extract_cb cb) {
|
static inline void apk_extract_init(struct apk_extract_ctx *ectx, struct apk_ctx *ac, const struct apk_extract_ops *ops) {
|
||||||
*ectx = (struct apk_extract_ctx){.ac = ac, .cb = cb};
|
*ectx = (struct apk_extract_ctx){.ac = ac, .ops = ops};
|
||||||
}
|
}
|
||||||
static inline void apk_extract_reset(struct apk_extract_ctx *ectx) {
|
static inline void apk_extract_reset(struct apk_extract_ctx *ectx) {
|
||||||
apk_extract_init(ectx, ectx->ac, ectx->cb);
|
apk_extract_init(ectx, ectx->ac, ectx->ops);
|
||||||
}
|
}
|
||||||
static inline void apk_extract_generate_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
|
static inline void apk_extract_generate_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
|
||||||
ctx->identity = id;
|
ctx->identity = id;
|
||||||
|
@ -58,6 +64,7 @@ int apk_extract(struct apk_extract_ctx *, struct apk_istream *is);
|
||||||
|
|
||||||
int apk_extract_v2(struct apk_extract_ctx *, struct apk_istream *is);
|
int apk_extract_v2(struct apk_extract_ctx *, struct apk_istream *is);
|
||||||
void apk_extract_v2_control(struct apk_extract_ctx *, apk_blob_t, apk_blob_t);
|
void apk_extract_v2_control(struct apk_extract_ctx *, apk_blob_t, apk_blob_t);
|
||||||
|
int apk_extract_v2_meta(struct apk_extract_ctx *ectx, struct apk_istream *is);
|
||||||
|
|
||||||
int apk_extract_v3(struct apk_extract_ctx *, struct apk_istream *is);
|
int apk_extract_v3(struct apk_extract_ctx *, struct apk_istream *is);
|
||||||
|
|
||||||
|
|
|
@ -11,11 +11,11 @@ struct conv_ctx {
|
||||||
struct adb_obj pkgs;
|
struct adb_obj pkgs;
|
||||||
struct adb dbi;
|
struct adb dbi;
|
||||||
struct apk_extract_ctx ectx;
|
struct apk_extract_ctx ectx;
|
||||||
int found;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
static void convert_index(struct conv_ctx *ctx, struct apk_istream *is)
|
static int convert_v2index(struct apk_extract_ctx *ectx, apk_blob_t *desc, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
|
struct conv_ctx *ctx = container_of(ectx, struct conv_ctx, ectx);
|
||||||
struct adb_obj pkginfo;
|
struct adb_obj pkginfo;
|
||||||
apk_blob_t token = APK_BLOB_STR("\n"), l;
|
apk_blob_t token = APK_BLOB_STR("\n"), l;
|
||||||
int i;
|
int i;
|
||||||
|
@ -30,30 +30,18 @@ static void convert_index(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
i = adb_pkg_field_index(l.ptr[0]);
|
i = adb_pkg_field_index(l.ptr[0]);
|
||||||
if (i > 0) adb_wo_pkginfo(&pkginfo, i, APK_BLOB_PTR_LEN(l.ptr+2, l.len-2));
|
if (i > 0) adb_wo_pkginfo(&pkginfo, i, APK_BLOB_PTR_LEN(l.ptr+2, l.len-2));
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
static int load_apkindex(struct apk_extract_ctx *ectx, const struct apk_file_info *fi,
|
|
||||||
struct apk_istream *is)
|
|
||||||
{
|
|
||||||
struct conv_ctx *ctx = container_of(ectx, struct conv_ctx, ectx);
|
|
||||||
|
|
||||||
if (strcmp(fi->name, "APKINDEX") == 0) {
|
|
||||||
ctx->found = 1;
|
|
||||||
convert_index(ctx, is);
|
|
||||||
return apk_istream_close(is);
|
return apk_istream_close(is);
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_convndx = {
|
||||||
|
.v2index = convert_v2index,
|
||||||
|
};
|
||||||
|
|
||||||
static int load_index(struct conv_ctx *ctx, struct apk_istream *is)
|
static int load_index(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
int r = 0;
|
|
||||||
if (IS_ERR(is)) return PTR_ERR(is);
|
if (IS_ERR(is)) return PTR_ERR(is);
|
||||||
ctx->found = 0;
|
apk_extract_init(&ctx->ectx, ctx->ac, &extract_convndx);
|
||||||
apk_extract_init(&ctx->ectx, ctx->ac, load_apkindex);
|
return apk_extract(&ctx->ectx, is);
|
||||||
r = apk_extract(&ctx->ectx, is);
|
|
||||||
if (r >= 0 && ctx->found == 0) r = -APKE_V2NDX_FORMAT;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
||||||
|
|
|
@ -65,14 +65,13 @@ struct manifest_file_ctx {
|
||||||
const char *prefix1, *prefix2;
|
const char *prefix1, *prefix2;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int read_file_entry(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
|
static int process_pkg_file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
struct manifest_file_ctx *mctx = container_of(ectx, struct manifest_file_ctx, ectx);
|
struct manifest_file_ctx *mctx = container_of(ectx, struct manifest_file_ctx, ectx);
|
||||||
struct apk_out *out = mctx->out;
|
struct apk_out *out = mctx->out;
|
||||||
char csum_buf[APK_BLOB_CHECKSUM_BUF];
|
char csum_buf[APK_BLOB_CHECKSUM_BUF];
|
||||||
apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf);
|
apk_blob_t csum_blob = APK_BLOB_BUF(csum_buf);
|
||||||
|
|
||||||
if (ectx->metadata) return 0;
|
|
||||||
if ((fi->mode & S_IFMT) != S_IFREG) return 0;
|
if ((fi->mode & S_IFMT) != S_IFREG) return 0;
|
||||||
|
|
||||||
memset(csum_buf, '\0', sizeof(csum_buf));
|
memset(csum_buf, '\0', sizeof(csum_buf));
|
||||||
|
@ -86,6 +85,11 @@ static int read_file_entry(struct apk_extract_ctx *ectx, const struct apk_file_i
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_manifest_ops = {
|
||||||
|
.v2meta = apk_extract_v2_meta,
|
||||||
|
.file = process_pkg_file,
|
||||||
|
};
|
||||||
|
|
||||||
static void process_file(struct apk_database *db, const char *match)
|
static void process_file(struct apk_database *db, const char *match)
|
||||||
{
|
{
|
||||||
struct apk_out *out = &db->ctx->out;
|
struct apk_out *out = &db->ctx->out;
|
||||||
|
@ -96,7 +100,7 @@ static void process_file(struct apk_database *db, const char *match)
|
||||||
};
|
};
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
apk_extract_init(&ctx.ectx, db->ctx, read_file_entry);
|
apk_extract_init(&ctx.ectx, db->ctx, &extract_manifest_ops);
|
||||||
if (apk_out_verbosity(out) > 1) {
|
if (apk_out_verbosity(out) > 1) {
|
||||||
ctx.prefix1 = match;
|
ctx.prefix1 = match;
|
||||||
ctx.prefix2 = ": ";
|
ctx.prefix2 = ": ";
|
||||||
|
|
|
@ -164,23 +164,22 @@ static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, s
|
||||||
return adb_w_obj(&pkginfo);
|
return adb_w_obj(&pkginfo);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int mkndx_parse_v2_tar(struct apk_extract_ctx *ectx, const struct apk_file_info *ae, struct apk_istream *is)
|
static int mkndx_parse_v2meta(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
struct mkndx_ctx *ctx = container_of(ectx, struct mkndx_ctx, ectx);
|
struct mkndx_ctx *ctx = container_of(ectx, struct mkndx_ctx, ectx);
|
||||||
|
|
||||||
if (ectx->metadata_verified) return -ECANCELED;
|
|
||||||
if (ectx->metadata && strcmp(ae->name, ".PKGINFO") == 0) {
|
|
||||||
adb_val_t o = adb_wa_append(
|
adb_val_t o = adb_wa_append(
|
||||||
&ctx->pkgs,
|
&ctx->pkgs,
|
||||||
mkndx_read_v2_pkginfo(
|
mkndx_read_v2_pkginfo(
|
||||||
&ctx->db, is, ctx->file_size, &ctx->ectx,
|
&ctx->db, is, ctx->file_size, &ctx->ectx,
|
||||||
ctx->rewrite_arch));
|
ctx->rewrite_arch));
|
||||||
if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o);
|
if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o);
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_ndxinfo_ops = {
|
||||||
|
.v2meta = mkndx_parse_v2meta,
|
||||||
|
};
|
||||||
|
|
||||||
static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
||||||
{
|
{
|
||||||
struct apk_out *out = &ac->out;
|
struct apk_out *out = &ac->out;
|
||||||
|
@ -199,7 +198,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
apk_extract_init(&ctx->ectx, ac, mkndx_parse_v2_tar);
|
apk_extract_init(&ctx->ectx, ac, &extract_ndxinfo_ops);
|
||||||
|
|
||||||
adb_init(&odb);
|
adb_init(&odb);
|
||||||
adb_w_init_tmp(&tmpdb, 200);
|
adb_w_init_tmp(&tmpdb, 200);
|
||||||
|
@ -275,7 +274,7 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
|
||||||
if (!found) {
|
if (!found) {
|
||||||
do_file:
|
do_file:
|
||||||
r = apk_extract(&ctx->ectx, apk_istream_from_file(AT_FDCWD, *parg));
|
r = apk_extract(&ctx->ectx, apk_istream_from_file(AT_FDCWD, *parg));
|
||||||
if (r < 0 && r != -ECANCELED) goto err_pkg;
|
if (r < 0) goto err_pkg;
|
||||||
newpkgs++;
|
newpkgs++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2163,37 +2163,29 @@ struct apkindex_ctx {
|
||||||
int repo, found;
|
int repo, found;
|
||||||
};
|
};
|
||||||
|
|
||||||
static int load_apkindex(struct apk_extract_ctx *ectx, const struct apk_file_info *fi,
|
static int load_v2index(struct apk_extract_ctx *ectx, apk_blob_t *desc, struct apk_istream *is)
|
||||||
struct apk_istream *is)
|
|
||||||
{
|
{
|
||||||
struct apkindex_ctx *ctx = container_of(ectx, struct apkindex_ctx, ectx);
|
struct apkindex_ctx *ctx = container_of(ectx, struct apkindex_ctx, ectx);
|
||||||
struct apk_repository *repo;
|
struct apk_repository *repo = &ctx->db->repos[ctx->repo];
|
||||||
|
|
||||||
repo = &ctx->db->repos[ctx->repo];
|
repo->description = *desc;
|
||||||
if (strcmp(fi->name, "DESCRIPTION") == 0) {
|
*desc = APK_BLOB_NULL;
|
||||||
repo->description = apk_blob_from_istream(is, fi->size);
|
|
||||||
} else if (strcmp(fi->name, "APKINDEX") == 0) {
|
|
||||||
ctx->found = 1;
|
|
||||||
return apk_db_index_read(ctx->db, is, ctx->repo);
|
return apk_db_index_read(ctx->db, is, ctx->repo);
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_index = {
|
||||||
|
.v2index = load_v2index,
|
||||||
|
};
|
||||||
|
|
||||||
static int load_index(struct apk_database *db, struct apk_istream *is, int repo)
|
static int load_index(struct apk_database *db, struct apk_istream *is, int repo)
|
||||||
{
|
{
|
||||||
struct apkindex_ctx ctx;
|
struct apkindex_ctx ctx = {
|
||||||
int r = 0;
|
.db = db,
|
||||||
|
.repo = repo,
|
||||||
|
};
|
||||||
if (IS_ERR(is)) return PTR_ERR(is);
|
if (IS_ERR(is)) return PTR_ERR(is);
|
||||||
|
apk_extract_init(&ctx.ectx, db->ctx, &extract_index);
|
||||||
ctx.db = db;
|
return apk_extract(&ctx.ectx, is);
|
||||||
ctx.repo = repo;
|
|
||||||
ctx.found = 0;
|
|
||||||
apk_extract_init(&ctx.ectx, db->ctx, load_apkindex);
|
|
||||||
r = apk_extract(&ctx.ectx, is);
|
|
||||||
if (r >= 0 && ctx.found == 0)
|
|
||||||
r = -APKE_V2NDX_FORMAT;
|
|
||||||
return r;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
|
int apk_db_index_read_file(struct apk_database *db, const char *file, int repo)
|
||||||
|
@ -2285,10 +2277,9 @@ static void extract_cb(void *_ctx, size_t bytes_done)
|
||||||
|
|
||||||
static void apk_db_run_pending_script(struct install_ctx *ctx)
|
static void apk_db_run_pending_script(struct install_ctx *ctx)
|
||||||
{
|
{
|
||||||
if (ctx->script_pending && ctx->ectx.metadata_verified) {
|
if (!ctx->script_pending) return;
|
||||||
ctx->script_pending = FALSE;
|
ctx->script_pending = FALSE;
|
||||||
apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args);
|
apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static int read_info_line(void *_ctx, apk_blob_t line)
|
static int read_info_line(void *_ctx, apk_blob_t line)
|
||||||
|
@ -2376,9 +2367,25 @@ static int contains_control_character(const char *str)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx,
|
static int apk_db_install_v2meta(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
const struct apk_file_info *ae,
|
{
|
||||||
struct apk_istream *is)
|
struct install_ctx *ctx = container_of(ectx, struct install_ctx, ectx);
|
||||||
|
apk_blob_t l, token = APK_BLOB_STR("\n");
|
||||||
|
while (apk_istream_get_delim(is, token, &l) == 0)
|
||||||
|
read_info_line(ctx, l);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apk_db_install_script(struct apk_extract_ctx *ectx, unsigned int type, size_t size, struct apk_istream *is)
|
||||||
|
{
|
||||||
|
struct install_ctx *ctx = container_of(ectx, struct install_ctx, ectx);
|
||||||
|
struct apk_package *pkg = ctx->pkg;
|
||||||
|
apk_ipkg_add_script(pkg->ipkg, is, type, size);
|
||||||
|
ctx->script_pending |= (type == ctx->script);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apk_db_install_file(struct apk_extract_ctx *ectx, const struct apk_file_info *ae, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
struct install_ctx *ctx = container_of(ectx, struct install_ctx, ectx);
|
struct install_ctx *ctx = container_of(ectx, struct install_ctx, ectx);
|
||||||
static const char dot1[] = "/./", dot2[] = "/../";
|
static const char dot1[] = "/./", dot2[] = "/../";
|
||||||
|
@ -2393,28 +2400,7 @@ static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx,
|
||||||
int ret = 0, r;
|
int ret = 0, r;
|
||||||
char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
|
char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
|
||||||
|
|
||||||
/* Package metainfo and script processing */
|
|
||||||
if (ectx->metadata) {
|
|
||||||
if (ae->name[0] != '.') return 0;
|
|
||||||
if (strcmp(ae->name, ".PKGINFO") == 0) {
|
|
||||||
apk_blob_t l, token = APK_BLOB_STR("\n");
|
|
||||||
while (apk_istream_get_delim(is, token, &l) == 0)
|
|
||||||
read_info_line(ctx, l);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
r = apk_script_type(&ae->name[1]);
|
|
||||||
if (r != APK_SCRIPT_INVALID) {
|
|
||||||
apk_ipkg_add_script(ipkg, is, r, ae->size);
|
|
||||||
ctx->script_pending |= (r == ctx->script);
|
|
||||||
apk_db_run_pending_script(ctx);
|
apk_db_run_pending_script(ctx);
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Handle script */
|
|
||||||
apk_db_run_pending_script(ctx);
|
|
||||||
|
|
||||||
/* Rest of files need to be inside data portion */
|
|
||||||
if (ae->name[0] == '.') return 0;
|
if (ae->name[0] == '.') return 0;
|
||||||
|
|
||||||
/* Sanity check the file name */
|
/* Sanity check the file name */
|
||||||
|
@ -2594,6 +2580,12 @@ static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx,
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_installer = {
|
||||||
|
.v2meta = apk_db_install_v2meta,
|
||||||
|
.script = apk_db_install_script,
|
||||||
|
.file = apk_db_install_file,
|
||||||
|
};
|
||||||
|
|
||||||
static void apk_db_purge_pkg(struct apk_database *db,
|
static void apk_db_purge_pkg(struct apk_database *db,
|
||||||
struct apk_installed_package *ipkg,
|
struct apk_installed_package *ipkg,
|
||||||
int is_installed)
|
int is_installed)
|
||||||
|
@ -2805,7 +2797,7 @@ static int apk_db_unpack_pkg(struct apk_database *db,
|
||||||
.cb = cb,
|
.cb = cb,
|
||||||
.cb_ctx = cb_ctx,
|
.cb_ctx = cb_ctx,
|
||||||
};
|
};
|
||||||
apk_extract_init(&ctx.ectx, db->ctx, apk_db_install_archive_entry);
|
apk_extract_init(&ctx.ectx, db->ctx, &extract_installer);
|
||||||
apk_extract_verify_identity(&ctx.ectx, &pkg->csum);
|
apk_extract_verify_identity(&ctx.ectx, &pkg->csum);
|
||||||
r = apk_extract(&ctx.ectx, is);
|
r = apk_extract(&ctx.ectx, is);
|
||||||
if (need_copy && r == 0) pkg->repos |= BIT(APK_REPOSITORY_CACHED);
|
if (need_copy && r == 0) pkg->repos |= BIT(APK_REPOSITORY_CACHED);
|
||||||
|
|
|
@ -278,31 +278,61 @@ update_digest:
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int apk_extract_verify_v2index(struct apk_extract_ctx *ectx, apk_blob_t *desc, struct apk_istream *is)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int apk_extract_verify_v2file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_v2verify_ops = {
|
||||||
|
.v2index = apk_extract_verify_v2index,
|
||||||
|
.v2meta = apk_extract_v2_meta,
|
||||||
|
.file = apk_extract_verify_v2file,
|
||||||
|
};
|
||||||
|
|
||||||
static int apk_extract_v2_entry(void *pctx, const struct apk_file_info *fi, struct apk_istream *is)
|
static int apk_extract_v2_entry(void *pctx, const struct apk_file_info *fi, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
struct apk_extract_ctx *ectx = pctx;
|
struct apk_extract_ctx *ectx = pctx;
|
||||||
struct apk_sign_ctx *sctx = ectx->pctx;
|
struct apk_sign_ctx *sctx = ectx->pctx;
|
||||||
int r;
|
int r, type;
|
||||||
|
|
||||||
r = apk_sign_ctx_process_file(sctx, fi, is);
|
r = apk_sign_ctx_process_file(sctx, fi, is);
|
||||||
if (r <= 0) return r;
|
if (r <= 0) return r;
|
||||||
|
|
||||||
ectx->metadata = sctx->control_started && !sctx->data_started;
|
if (!sctx->control_started) return 0;
|
||||||
ectx->metadata_verified = sctx->control_verified;
|
if (!sctx->data_started || !sctx->has_data_checksum) {
|
||||||
|
if (fi->name[0] == '.') {
|
||||||
r = ectx->cb ? ectx->cb(ectx, fi, is) : 0;
|
ectx->is_package = 1;
|
||||||
|
if (ectx->is_index) return -APKE_V2NDX_FORMAT;
|
||||||
if (ectx->metadata && strcmp(fi->name, ".PKGINFO") == 0) {
|
if (!ectx->ops->v2meta) return -APKE_FORMAT_NOT_SUPPORTED;
|
||||||
// Parse the .PKGINFO for the data, in case the callback did not do it.
|
if (strcmp(fi->name, ".PKGINFO") == 0) {
|
||||||
apk_blob_t l, r, token = APK_BLOB_STR("\n");
|
return ectx->ops->v2meta(ectx, is);
|
||||||
while (apk_istream_get_delim(is, token, &l) == 0) {
|
} else if (strcmp(fi->name, ".INSTALL") == 0) {
|
||||||
if (l.len < 1 || l.ptr[0] == '#') continue;
|
return -APKE_V2PKG_FORMAT;
|
||||||
if (apk_blob_split(l, APK_BLOB_STR(" = "), &l, &r))
|
} else if ((type = apk_script_type(&fi->name[1])) != APK_SCRIPT_INVALID) {
|
||||||
apk_extract_v2_control(ectx, l, r);
|
if (ectx->ops->script) return ectx->ops->script(ectx, type, fi->size, is);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
ectx->is_index = 1;
|
||||||
|
if (ectx->is_package) return -APKE_V2PKG_FORMAT;
|
||||||
|
if (!ectx->ops->v2index) return -APKE_FORMAT_NOT_SUPPORTED;
|
||||||
|
if (strcmp(fi->name, "DESCRIPTION") == 0) {
|
||||||
|
free(ectx->desc.ptr);
|
||||||
|
ectx->desc = apk_blob_from_istream(is, fi->size);
|
||||||
|
} else if (strcmp(fi->name, "APKINDEX") == 0) {
|
||||||
|
return ectx->ops->v2index(ectx, &ectx->desc, is);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
return r;
|
if (!sctx->control_verified) return 0;
|
||||||
|
if (!ectx->ops->file) return -ECANCELED;
|
||||||
|
return ectx->ops->file(ectx, fi, is);
|
||||||
}
|
}
|
||||||
|
|
||||||
int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
|
@ -319,13 +349,18 @@ int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
else
|
else
|
||||||
action = trust->allow_untrusted ? APK_SIGN_NONE : APK_SIGN_VERIFY;
|
action = trust->allow_untrusted ? APK_SIGN_NONE : APK_SIGN_VERIFY;
|
||||||
|
|
||||||
|
if (!ectx->ops) ectx->ops = &extract_v2verify_ops;
|
||||||
ectx->pctx = &sctx;
|
ectx->pctx = &sctx;
|
||||||
apk_sign_ctx_init(&sctx, action, ectx->identity, trust);
|
apk_sign_ctx_init(&sctx, action, ectx->identity, trust);
|
||||||
r = apk_tar_parse(
|
r = apk_tar_parse(
|
||||||
apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx),
|
apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx),
|
||||||
apk_extract_v2_entry, ectx, apk_ctx_get_id_cache(ac));
|
apk_extract_v2_entry, ectx, apk_ctx_get_id_cache(ac));
|
||||||
|
if (r == -ECANCELED) r = 0;
|
||||||
|
if (r == 0 && !ectx->is_package && !ectx->is_index)
|
||||||
|
r = ectx->ops->v2index ? -APKE_V2NDX_FORMAT : -APKE_V2PKG_FORMAT;
|
||||||
if (ectx->generate_identity) *ectx->identity = sctx.identity;
|
if (ectx->generate_identity) *ectx->identity = sctx.identity;
|
||||||
apk_sign_ctx_free(&sctx);
|
apk_sign_ctx_free(&sctx);
|
||||||
|
free(ectx->desc.ptr);
|
||||||
apk_extract_reset(ectx);
|
apk_extract_reset(ectx);
|
||||||
|
|
||||||
return r;
|
return r;
|
||||||
|
@ -345,3 +380,16 @@ void apk_extract_v2_control(struct apk_extract_ctx *ectx, apk_blob_t l, apk_blob
|
||||||
EVP_MD_size(sctx->md)));
|
EVP_MD_size(sctx->md)));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int apk_extract_v2_meta(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
|
{
|
||||||
|
apk_blob_t k, v, token = APK_BLOB_STRLIT("\n");
|
||||||
|
while (apk_istream_get_delim(is, token, &k) == 0) {
|
||||||
|
if (k.len < 1 || k.ptr[0] == '#') continue;
|
||||||
|
if (apk_blob_split(k, APK_BLOB_STRLIT(" = "), &k, &v)) {
|
||||||
|
apk_extract_v2_control(ectx, k, v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
|
@ -592,29 +592,19 @@ static int read_info_line(struct read_info_ctx *ri, apk_blob_t line)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int apk_pkg_parse_entry(struct apk_extract_ctx *ectx, const struct apk_file_info *ae,
|
static int apk_pkg_v2meta(struct apk_extract_ctx *ectx, struct apk_istream *is)
|
||||||
struct apk_istream *is)
|
|
||||||
{
|
{
|
||||||
struct read_info_ctx *ri = container_of(ectx, struct read_info_ctx, ectx);
|
struct read_info_ctx *ri = container_of(ectx, struct read_info_ctx, ectx);
|
||||||
struct apk_package *pkg = ri->pkg;
|
|
||||||
|
|
||||||
if (ectx->metadata_verified) return -ECANCELED;
|
|
||||||
if (!ectx->metadata) return 0;
|
|
||||||
|
|
||||||
if (strcmp(ae->name, ".PKGINFO") == 0) {
|
|
||||||
/* APK 2.0 format */
|
|
||||||
apk_blob_t l, token = APK_BLOB_STR("\n");
|
apk_blob_t l, token = APK_BLOB_STR("\n");
|
||||||
while (apk_istream_get_delim(is, token, &l) == 0)
|
while (apk_istream_get_delim(is, token, &l) == 0)
|
||||||
read_info_line(ri, l);
|
read_info_line(ri, l);
|
||||||
} else if (strcmp(ae->name, ".INSTALL") == 0) {
|
|
||||||
apk_warn(&ri->db->ctx->out,
|
|
||||||
"Package '%s-" BLOB_FMT "' contains deprecated .INSTALL",
|
|
||||||
pkg->name->name, BLOB_PRINTF(*pkg->version));
|
|
||||||
}
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static const struct apk_extract_ops extract_pkgmeta_ops = {
|
||||||
|
.v2meta = apk_pkg_v2meta,
|
||||||
|
};
|
||||||
|
|
||||||
int apk_pkg_read(struct apk_database *db, const char *file, struct apk_package **pkg)
|
int apk_pkg_read(struct apk_database *db, const char *file, struct apk_package **pkg)
|
||||||
{
|
{
|
||||||
struct read_info_ctx ctx;
|
struct read_info_ctx ctx;
|
||||||
|
@ -633,12 +623,11 @@ int apk_pkg_read(struct apk_database *db, const char *file, struct apk_package *
|
||||||
goto err;
|
goto err;
|
||||||
|
|
||||||
ctx.pkg->size = fi.size;
|
ctx.pkg->size = fi.size;
|
||||||
apk_extract_init(&ctx.ectx, db->ctx, apk_pkg_parse_entry);
|
apk_extract_init(&ctx.ectx, db->ctx, &extract_pkgmeta_ops);
|
||||||
apk_extract_generate_identity(&ctx.ectx, &ctx.pkg->csum);
|
apk_extract_generate_identity(&ctx.ectx, &ctx.pkg->csum);
|
||||||
|
|
||||||
r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, file));
|
r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, file));
|
||||||
if (r < 0 && r != -ECANCELED)
|
if (r < 0) goto err;
|
||||||
goto err;
|
|
||||||
if (ctx.pkg->name == NULL || ctx.pkg->uninstallable) {
|
if (ctx.pkg->name == NULL || ctx.pkg->uninstallable) {
|
||||||
r = -ENOTSUP;
|
r = -ENOTSUP;
|
||||||
goto err;
|
goto err;
|
||||||
|
|
Loading…
Reference in New Issue