diff --git a/src/apk_extract.h b/src/apk_extract.h index cc8bae7..94fc401 100644 --- a/src/apk_extract.h +++ b/src/apk_extract.h @@ -14,6 +14,7 @@ #include "apk_print.h" #include "apk_io.h" +struct adb; struct apk_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, unsigned int extract_flags, struct apk_out *out); - -typedef int (*apk_extract_cb)(struct apk_extract_ctx *, - const struct apk_file_info *ae, - struct apk_istream *istream); +struct apk_extract_ops { + int (*v2index)(struct apk_extract_ctx *, apk_blob_t *desc, struct apk_istream *is); + int (*v2meta)(struct apk_extract_ctx *, struct apk_istream *is); + 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_ctx *ac; - apk_extract_cb cb; + const struct apk_extract_ops *ops; struct apk_checksum *identity; - unsigned generate_identity : 1; - unsigned metadata : 1; - unsigned metadata_verified : 1; + apk_blob_t desc; 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) { - *ectx = (struct apk_extract_ctx){.ac = ac, .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, .ops = ops}; } 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) { 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); 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); diff --git a/src/app_convndx.c b/src/app_convndx.c index d405b03..f8f649e 100644 --- a/src/app_convndx.c +++ b/src/app_convndx.c @@ -11,11 +11,11 @@ struct conv_ctx { struct adb_obj pkgs; struct adb dbi; 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; apk_blob_t token = APK_BLOB_STR("\n"), l; 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]); if (i > 0) adb_wo_pkginfo(&pkginfo, i, APK_BLOB_PTR_LEN(l.ptr+2, l.len-2)); } + return apk_istream_close(is); } -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 0; -} +static const struct apk_extract_ops extract_convndx = { + .v2index = convert_v2index, +}; static int load_index(struct conv_ctx *ctx, struct apk_istream *is) { - int r = 0; if (IS_ERR(is)) return PTR_ERR(is); - ctx->found = 0; - apk_extract_init(&ctx->ectx, ctx->ac, load_apkindex); - r = apk_extract(&ctx->ectx, is); - if (r >= 0 && ctx->found == 0) r = -APKE_V2NDX_FORMAT; - return r; + apk_extract_init(&ctx->ectx, ctx->ac, &extract_convndx); + return apk_extract(&ctx->ectx, is); } static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args) diff --git a/src/app_manifest.c b/src/app_manifest.c index ff63d7c..b1cbb3f 100644 --- a/src/app_manifest.c +++ b/src/app_manifest.c @@ -65,14 +65,13 @@ struct manifest_file_ctx { 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 apk_out *out = mctx->out; char csum_buf[APK_BLOB_CHECKSUM_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; 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; } +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) { struct apk_out *out = &db->ctx->out; @@ -96,7 +100,7 @@ static void process_file(struct apk_database *db, const char *match) }; 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) { ctx.prefix1 = match; ctx.prefix2 = ": "; diff --git a/src/app_mkndx.c b/src/app_mkndx.c index c95c494..6e485b5 100644 --- a/src/app_mkndx.c +++ b/src/app_mkndx.c @@ -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); } -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); - - if (ectx->metadata_verified) return -ECANCELED; - if (ectx->metadata && strcmp(ae->name, ".PKGINFO") == 0) { - adb_val_t o = adb_wa_append( - &ctx->pkgs, - mkndx_read_v2_pkginfo( - &ctx->db, is, ctx->file_size, &ctx->ectx, - ctx->rewrite_arch)); - if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o); - } - + adb_val_t o = adb_wa_append( + &ctx->pkgs, + mkndx_read_v2_pkginfo( + &ctx->db, is, ctx->file_size, &ctx->ectx, + ctx->rewrite_arch)); + if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o); 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) { 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; } - apk_extract_init(&ctx->ectx, ac, mkndx_parse_v2_tar); + apk_extract_init(&ctx->ectx, ac, &extract_ndxinfo_ops); adb_init(&odb); 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) { do_file: 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++; } } diff --git a/src/database.c b/src/database.c index 9ed0085..980efcd 100644 --- a/src/database.c +++ b/src/database.c @@ -2163,37 +2163,29 @@ struct apkindex_ctx { int repo, found; }; -static int load_apkindex(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, - struct apk_istream *is) +static int load_v2index(struct apk_extract_ctx *ectx, apk_blob_t *desc, struct apk_istream *is) { 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]; - if (strcmp(fi->name, "DESCRIPTION") == 0) { - 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 0; + repo->description = *desc; + *desc = APK_BLOB_NULL; + return apk_db_index_read(ctx->db, is, ctx->repo); } +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) { - struct apkindex_ctx ctx; - int r = 0; - + struct apkindex_ctx ctx = { + .db = db, + .repo = repo, + }; if (IS_ERR(is)) return PTR_ERR(is); - - ctx.db = db; - 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; + apk_extract_init(&ctx.ectx, db->ctx, &extract_index); + return apk_extract(&ctx.ectx, is); } 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) { - if (ctx->script_pending && ctx->ectx.metadata_verified) { - ctx->script_pending = FALSE; - apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args); - } + if (!ctx->script_pending) return; + ctx->script_pending = FALSE; + apk_ipkg_run_script(ctx->ipkg, ctx->db, ctx->script, ctx->script_args); } 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; } -static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx, - const struct apk_file_info *ae, - struct apk_istream *is) +static int apk_db_install_v2meta(struct apk_extract_ctx *ectx, 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); 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; 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); - } - 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; /* Sanity check the file name */ @@ -2594,6 +2580,12 @@ static int apk_db_install_archive_entry(struct apk_extract_ctx *ectx, 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, struct apk_installed_package *ipkg, int is_installed) @@ -2805,7 +2797,7 @@ static int apk_db_unpack_pkg(struct apk_database *db, .cb = cb, .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); r = apk_extract(&ctx.ectx, is); if (need_copy && r == 0) pkg->repos |= BIT(APK_REPOSITORY_CACHED); diff --git a/src/extract_v2.c b/src/extract_v2.c index 217a07d..029a5e3 100644 --- a/src/extract_v2.c +++ b/src/extract_v2.c @@ -278,31 +278,61 @@ update_digest: 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) { struct apk_extract_ctx *ectx = pctx; struct apk_sign_ctx *sctx = ectx->pctx; - int r; + int r, type; r = apk_sign_ctx_process_file(sctx, fi, is); if (r <= 0) return r; - ectx->metadata = sctx->control_started && !sctx->data_started; - ectx->metadata_verified = sctx->control_verified; - - r = ectx->cb ? ectx->cb(ectx, fi, is) : 0; - - if (ectx->metadata && strcmp(fi->name, ".PKGINFO") == 0) { - // Parse the .PKGINFO for the data, in case the callback did not do it. - apk_blob_t l, r, token = APK_BLOB_STR("\n"); - while (apk_istream_get_delim(is, token, &l) == 0) { - if (l.len < 1 || l.ptr[0] == '#') continue; - if (apk_blob_split(l, APK_BLOB_STR(" = "), &l, &r)) - apk_extract_v2_control(ectx, l, r); + if (!sctx->control_started) return 0; + if (!sctx->data_started || !sctx->has_data_checksum) { + if (fi->name[0] == '.') { + ectx->is_package = 1; + if (ectx->is_index) return -APKE_V2NDX_FORMAT; + if (!ectx->ops->v2meta) return -APKE_FORMAT_NOT_SUPPORTED; + if (strcmp(fi->name, ".PKGINFO") == 0) { + return ectx->ops->v2meta(ectx, is); + } else if (strcmp(fi->name, ".INSTALL") == 0) { + return -APKE_V2PKG_FORMAT; + } else if ((type = apk_script_type(&fi->name[1])) != APK_SCRIPT_INVALID) { + 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) @@ -319,13 +349,18 @@ int apk_extract_v2(struct apk_extract_ctx *ectx, struct apk_istream *is) else action = trust->allow_untrusted ? APK_SIGN_NONE : APK_SIGN_VERIFY; + if (!ectx->ops) ectx->ops = &extract_v2verify_ops; ectx->pctx = &sctx; apk_sign_ctx_init(&sctx, action, ectx->identity, trust); r = apk_tar_parse( apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx), 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; apk_sign_ctx_free(&sctx); + free(ectx->desc.ptr); apk_extract_reset(ectx); 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))); } } + +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; +} + diff --git a/src/package.c b/src/package.c index 9e272b6..3b634d6 100644 --- a/src/package.c +++ b/src/package.c @@ -592,29 +592,19 @@ static int read_info_line(struct read_info_ctx *ri, apk_blob_t line) return 0; } -static int apk_pkg_parse_entry(struct apk_extract_ctx *ectx, const struct apk_file_info *ae, - struct apk_istream *is) +static int apk_pkg_v2meta(struct apk_extract_ctx *ectx, struct apk_istream *is) { 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"); - while (apk_istream_get_delim(is, token, &l) == 0) - 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)); - } - + apk_blob_t l, token = APK_BLOB_STR("\n"); + while (apk_istream_get_delim(is, token, &l) == 0) + read_info_line(ri, l); 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) { 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; 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); r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, file)); - if (r < 0 && r != -ECANCELED) - goto err; + if (r < 0) goto err; if (ctx.pkg->name == NULL || ctx.pkg->uninstallable) { r = -ENOTSUP; goto err;