Commit 6b471bb6 authored by Timo Teräs's avatar Timo Teräs

various: new style index generation

change the index generation to do old index, or the new style index
where package identity is sha1 of control block and it's contained
within an .tar.gz to allow signing in future.
parent 0f6d96a4
......@@ -118,7 +118,7 @@ static int add_main(void *ctx, int argc, char **argv)
if (strstr(argv[i], ".apk") != NULL) {
struct apk_package *pkg;
pkg = apk_db_pkg_add_file(&db, argv[i]);
pkg = apk_pkg_read(&db, argv[i], APK_SIGN_VERIFY);
if (pkg == NULL) {
apk_error("Unable to read '%s'", argv[i]);
goto err;
......
......@@ -20,8 +20,9 @@ typedef int (*apk_archive_entry_parser)(void *ctx,
const struct apk_file_info *ae,
struct apk_istream *istream);
int apk_parse_tar(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
int apk_write_tar_entry(struct apk_ostream *, const struct apk_file_info *ae, char *data);
int apk_tar_parse(struct apk_istream *, apk_archive_entry_parser parser, void *ctx);
int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae, char *data);
int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is,
......
......@@ -134,7 +134,6 @@ int apk_db_write_config(struct apk_database *db);
void apk_db_close(struct apk_database *db);
int apk_db_cache_active(struct apk_database *db);
struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *file);
struct apk_package *apk_db_pkg_add(struct apk_database *db, struct apk_package *pkg);
struct apk_package *apk_db_get_pkg(struct apk_database *db, struct apk_checksum *csum);
struct apk_package *apk_db_get_file_owner(struct apk_database *db, apk_blob_t filename);
......
......@@ -59,6 +59,7 @@ static inline struct apk_istream *apk_bstream_gunzip(struct apk_bstream *bs)
}
struct apk_ostream *apk_ostream_gzip(struct apk_ostream *);
struct apk_ostream *apk_ostream_counter(off_t *);
struct apk_istream *apk_istream_from_fd(int fd);
struct apk_istream *apk_istream_from_file(const char *file);
......
......@@ -30,6 +30,10 @@ struct apk_name;
#define APK_PKG_NOT_INSTALLED 0
#define APK_PKG_INSTALLED 1
#define APK_SIGN_VERIFY 0
#define APK_SIGN_GENERATE_V1 1
#define APK_SIGN_GENERATE 2
struct apk_script {
struct hlist_node script_list;
unsigned int type;
......@@ -80,7 +84,7 @@ int apk_deps_write(struct apk_dependency_array *deps, struct apk_ostream *os);
int apk_script_type(const char *name);
struct apk_package *apk_pkg_new(void);
struct apk_package *apk_pkg_read(struct apk_database *db, const char *name);
struct apk_package *apk_pkg_read(struct apk_database *db, const char *name, int indexstyle);
void apk_pkg_free(struct apk_package *pkg);
int apk_pkg_parse_name(apk_blob_t apkname, apk_blob_t *name, apk_blob_t *version);
......
......@@ -93,7 +93,7 @@ static size_t tar_entry_read(void *stream, void *ptr, size_t size)
return size;
}
int apk_parse_tar(struct apk_istream *is, apk_archive_entry_parser parser,
int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
void *ctx)
{
struct apk_file_info entry;
......@@ -205,11 +205,9 @@ err:
return r;
}
int apk_write_tar_entry(struct apk_ostream *os, const struct apk_file_info *ae, char *data)
int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae, char *data)
{
static char padding[512];
struct tar_header buf;
int pad;
memset(&buf, 0, sizeof(buf));
if (ae != NULL) {
......@@ -221,15 +219,17 @@ int apk_write_tar_entry(struct apk_ostream *os, const struct apk_file_info *ae,
else
return -1;
strncpy(buf.name, ae->name, sizeof(buf.name));
strncpy(buf.uname, ae->uname, sizeof(buf.uname));
strncpy(buf.gname, ae->gname, sizeof(buf.gname));
if (ae->name != NULL)
strncpy(buf.name, ae->name, sizeof(buf.name));
strncpy(buf.uname, ae->uname ?: "root", sizeof(buf.uname));
strncpy(buf.gname, ae->gname ?: "root", sizeof(buf.gname));
PUT_OCTAL(buf.size, ae->size);
PUT_OCTAL(buf.uid, ae->uid);
PUT_OCTAL(buf.gid, ae->gid);
PUT_OCTAL(buf.mode, ae->mode & 07777);
PUT_OCTAL(buf.mtime, ae->mtime);
PUT_OCTAL(buf.mtime, ae->mtime ?: time(NULL));
/* Checksum */
strcpy(buf.magic, "ustar ");
......@@ -243,18 +243,33 @@ int apk_write_tar_entry(struct apk_ostream *os, const struct apk_file_info *ae,
if (os->write(os, &buf, sizeof(buf)) != sizeof(buf))
return -1;
if (data != NULL) {
if (ae == NULL) {
/* End-of-archive is two empty headers */
if (os->write(os, &buf, sizeof(buf)) != sizeof(buf))
return -1;
} else if (data != NULL) {
if (os->write(os, data, ae->size) != ae->size)
return -1;
pad = 512 - (ae->size & 511);
if (pad != 512 &&
os->write(os, padding, pad) != pad)
if (apk_tar_write_padding(os, ae) != 0)
return -1;
}
return 0;
}
int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae)
{
static char padding[512];
int pad;
pad = 512 - (ae->size & 511);
if (pad != 512 &&
os->write(os, padding, pad) != pad)
return -1;
return 0;
}
int apk_archive_entry_extract(const struct apk_file_info *ae,
struct apk_istream *is,
const char *fn, apk_progress_cb cb,
......
......@@ -545,19 +545,14 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
struct apk_file_info fi;
char filename[256];
apk_blob_t bfn;
int r, i;
int r;
list_for_each_entry(pkg, &db->installed.packages, installed_pkgs_list) {
hlist_for_each_entry(script, c2, &pkg->scripts, script_list) {
fi = (struct apk_file_info) {
.name = filename,
.uname = "root",
.gname = "root",
.size = script->size,
.uid = 0,
.gid = 0,
.mode = 0755 | S_IFREG,
.mtime = time(NULL),
};
/* The scripts db expects file names in format:
* pkg-version.<hexdump of package checksum>.action */
......@@ -571,18 +566,13 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
apk_blob_push_blob(&bfn, APK_BLOB_STR(apk_script_types[script->type]));
apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1));
r = apk_write_tar_entry(os, &fi, script->script);
r = apk_tar_write_entry(os, &fi, script->script);
if (r < 0)
return r;
}
}
for (i = 0; i < 2; i++) {
r = apk_write_tar_entry(os, NULL, NULL);
if (r < 0)
return r;
}
return 0;
return apk_tar_write_entry(os, NULL, NULL);
}
static int apk_db_scriptdb_read_v1(struct apk_database *db, struct apk_istream *is)
......@@ -688,7 +678,7 @@ static int apk_db_read_state(struct apk_database *db, int flags)
if (!(flags & APK_OPENF_NO_SCRIPTS)) {
is = apk_istream_from_file("var/lib/apk/scripts.tar");
if (is != NULL) {
apk_parse_tar(is, apk_read_script_archive_entry, db);
apk_tar_parse(is, apk_read_script_archive_entry, db);
} else {
is = apk_istream_from_file("var/lib/apk/scripts");
if (is != NULL)
......@@ -970,16 +960,6 @@ struct apk_package *apk_db_get_file_owner(struct apk_database *db,
return dbf->diri->pkg;
}
struct apk_package *apk_db_pkg_add_file(struct apk_database *db, const char *file)
{
struct apk_package *info;
info = apk_pkg_read(db, file);
if (info != NULL)
info = apk_db_pkg_add(db, info);
return info;
}
struct index_write_ctx {
struct apk_ostream *os;
int count;
......@@ -1433,7 +1413,7 @@ static int apk_db_unpack_pkg(struct apk_database *db,
};
tar = apk_bstream_gunzip_mpart(bs, apk_db_gzip_part, &ctx);
if (apk_parse_tar(tar, apk_db_install_archive_entry, &ctx) != 0)
if (apk_tar_parse(tar, apk_db_install_archive_entry, &ctx) != 0)
goto err_close;
tar->close(tar);
......
......@@ -30,7 +30,7 @@ struct apk_gzip_istream {
void *cbctx;
};
static size_t gz_read(void *stream, void *ptr, size_t size)
static size_t gzi_read(void *stream, void *ptr, size_t size)
{
struct apk_gzip_istream *gis =
container_of(stream, struct apk_gzip_istream, is);
......@@ -78,11 +78,13 @@ static size_t gz_read(void *stream, void *ptr, size_t size)
EVP_DigestUpdate(&gis->mdctx, gis->mdblock,
(void *)gis->zs.next_in - gis->mdblock);
gis->mdblock = gis->zs.next_in;
gis->cb(gis->cbctx, &gis->mdctx,
APK_MPART_BOUNDARY);
if (gis->cb(gis->cbctx, &gis->mdctx,
APK_MPART_BOUNDARY)) {
gis->z_err = Z_STREAM_END;
break;
}
}
inflateEnd(&gis->zs);
if (inflateInit2(&gis->zs, 15+32) != Z_OK)
return -1;
gis->z_err = Z_OK;
......@@ -95,7 +97,7 @@ static size_t gz_read(void *stream, void *ptr, size_t size)
return size - gis->zs.avail_out;
}
static void gz_close(void *stream)
static void gzi_close(void *stream)
{
struct apk_gzip_istream *gis =
container_of(stream, struct apk_gzip_istream, is);
......@@ -117,11 +119,11 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs,
gis = malloc(sizeof(struct apk_gzip_istream));
if (gis == NULL)
return NULL;
goto err;
*gis = (struct apk_gzip_istream) {
.is.read = gz_read,
.is.close = gz_close,
.is.read = gzi_read,
.is.close = gzi_close,
.bs = bs,
.z_err = 0,
.cb = cb,
......@@ -130,7 +132,7 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs,
if (inflateInit2(&gis->zs, 15+32) != Z_OK) {
free(gis);
return NULL;
goto err;
}
if (gis->cb != NULL) {
......@@ -139,5 +141,83 @@ struct apk_istream *apk_bstream_gunzip_mpart(struct apk_bstream *bs,
}
return &gis->is;
err:
bs->close(bs, NULL);
return NULL;
}
struct apk_gzip_ostream {
struct apk_ostream os;
struct apk_ostream *output;
z_stream zs;
unsigned char buffer[8*1024];
};
static size_t gzo_write(void *stream, const void *ptr, size_t size)
{
struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream;
size_t have;
int r;
gos->zs.avail_in = size;
gos->zs.next_in = (void *) ptr;
while (gos->zs.avail_in) {
gos->zs.avail_out = sizeof(gos->buffer);
gos->zs.next_out = gos->buffer;
r = deflate(&gos->zs, Z_NO_FLUSH);
if (r == Z_STREAM_ERROR)
return -1;
have = sizeof(gos->buffer) - gos->zs.avail_out;
if (have != 0) {
r = gos->output->write(gos->output, gos->buffer, have);
if (r != have)
return -1;
}
}
return size;
}
static void gzo_close(void *stream)
{
struct apk_gzip_ostream *gos = (struct apk_gzip_ostream *) stream;
size_t have;
deflate(&gos->zs, Z_FINISH);
have = sizeof(gos->buffer) - gos->zs.avail_out;
gos->output->write(gos->output, gos->buffer, have);
gos->output->close(gos->output);
deflateEnd(&gos->zs);
free(stream);
}
struct apk_ostream *apk_ostream_gzip(struct apk_ostream *output)
{
struct apk_gzip_ostream *gos;
if (output == NULL)
return NULL;
gos = malloc(sizeof(struct apk_gzip_ostream));
if (gos == NULL)
goto err;
*gos = (struct apk_gzip_ostream) {
.os.write = gzo_write,
.os.close = gzo_close,
.output = output,
};
if (deflateInit2(&gos->zs, 9, Z_DEFLATED, 15 | 16, 8,
Z_DEFAULT_STRATEGY) != Z_OK) {
free(gos);
goto err;
}
return &gos->os;
err:
output->close(output);
return NULL;
}
......@@ -10,18 +10,23 @@
*/
#include <stdio.h>
#include <fcntl.h>
#include <unistd.h>
#include "apk_applet.h"
#include "apk_database.h"
#define INDEX_OLD_FORMAT 0x10000
struct counts {
int unsatisfied;
};
struct index_ctx {
const char *index;
const char *output;
time_t index_mtime;
int method;
};
static int index_parse(void *ctx, int optch, int optindex, const char *optarg)
......@@ -32,6 +37,12 @@ static int index_parse(void *ctx, int optch, int optindex, const char *optarg)
case 'x':
ictx->index = optarg;
break;
case 'o':
ictx->output = optarg;
break;
case INDEX_OLD_FORMAT:
ictx->method = APK_SIGN_GENERATE_V1;
break;
default:
return -1;
}
......@@ -83,6 +94,16 @@ static int index_main(void *ctx, int argc, char **argv)
int total, i, j, found, newpkgs = 0;
struct index_ctx *ictx = (struct index_ctx *) ctx;
if (isatty(STDOUT_FILENO) && ictx->output == NULL &&
!(apk_flags & APK_FORCE)) {
apk_error("Will not write binary index to console "
"without --force");
return -1;
}
if (ictx->method == 0)
ictx->method = APK_SIGN_GENERATE;
apk_db_open(&db, NULL, APK_OPENF_READ);
if (index_read_file(&db, ictx) < 0) {
apk_db_close(&db);
......@@ -137,13 +158,33 @@ static int index_main(void *ctx, int argc, char **argv)
} while (0);
if (!found) {
apk_db_pkg_add_file(&db, argv[i]);
newpkgs++;
if (apk_pkg_read(&db, argv[i], ictx->method) != NULL)
newpkgs++;
}
}
os = apk_ostream_to_fd(STDOUT_FILENO);
if (ictx->method == APK_SIGN_GENERATE) {
memset(&fi, 0, sizeof(fi));
fi.name = "APKINDEX";
fi.mode = 0755 | S_IFREG;
os = apk_ostream_counter(&fi.size);
apk_db_index_write(&db, os);
os->close(os);
}
if (ictx->output != NULL)
os = apk_ostream_to_file(ictx->output, 0755);
else
os = apk_ostream_to_fd(STDOUT_FILENO);
if (ictx->method == APK_SIGN_GENERATE) {
os = apk_ostream_gzip(os);
apk_tar_write_entry(os, &fi, NULL);
}
total = apk_db_index_write(&db, os);
if (ictx->method == APK_SIGN_GENERATE) {
apk_tar_write_padding(os, &fi);
apk_tar_write_entry(os, NULL, NULL);
}
os->close(os);
apk_hash_foreach(&db.available.names, warn_if_no_providers, &counts);
......@@ -160,9 +201,13 @@ static int index_main(void *ctx, int argc, char **argv)
}
static struct apk_option index_options[] = {
{ 'o', "output", "Write the generated index to FILE",
required_argument, "FILE" },
{ 'x', "index", "Read INDEX to speed up new index creation by reusing "
"the information from an old index",
required_argument, "INDEX" },
{ INDEX_OLD_FORMAT, "old-format",
"Specify to create old style index files" }
};
static struct apk_applet apk_index = {
......
......@@ -578,6 +578,45 @@ struct apk_ostream *apk_ostream_to_file(const char *file, mode_t mode)
return apk_ostream_to_fd(fd);
}
struct apk_counter_ostream {
struct apk_ostream os;
off_t *counter;
};
static size_t co_write(void *stream, const void *ptr, size_t size)
{
struct apk_counter_ostream *cos =
container_of(stream, struct apk_counter_ostream, os);
*cos->counter += size;
return size;
}
static void co_close(void *stream)
{
struct apk_counter_ostream *cos =
container_of(stream, struct apk_counter_ostream, os);
free(cos);
}
struct apk_ostream *apk_ostream_counter(off_t *counter)
{
struct apk_counter_ostream *cos;
cos = malloc(sizeof(struct apk_counter_ostream));
if (cos == NULL)
return NULL;
*cos = (struct apk_counter_ostream) {
.os.write = co_write,
.os.close = co_close,
.counter = counter,
};
return &cos->os;
}
size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
{
size_t len;
......
......@@ -257,8 +257,13 @@ int apk_script_type(const char *name)
struct read_info_ctx {
struct apk_database *db;
struct apk_package *pkg;
int version;
int has_install;
const EVP_MD *md;
int version, action;
int has_signature : 1;
int has_install : 1;
int has_data_checksum : 1;
int data_started : 1;
int in_signatures : 1;
};
int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
......@@ -325,12 +330,16 @@ static int read_info_line(void *ctx, apk_blob_t line)
return 0;
for (i = 0; i < ARRAY_SIZE(fields); i++) {
if (strncmp(fields[i].str, l.ptr, l.len) == 0) {
if (apk_blob_compare(APK_BLOB_STR(fields[i].str), l) == 0) {
apk_pkg_add_info(ri->db, ri->pkg, fields[i].field, r);
break;
return 0;
}
}
if (ri->data_started == 0 &&
apk_blob_compare(APK_BLOB_STR("sha256"), l) == 0)
ri->has_data_checksum = 1;
return 0;
}
......@@ -354,21 +363,27 @@ static int read_info_entry(void *ctx, const struct apk_file_info *ae,
int i;
/* Meta info and scripts */
if (ae->name[0] == '.') {
if (ri->in_signatures && strncmp(ae->name, ".SIGN.", 6) != 0)
ri->in_signatures = 0;
if (ri->data_started == 0 && ae->name[0] == '.') {
/* APK 2.0 format */
ri->version = 2;
if (strcmp(ae->name, ".PKGINFO") == 0) {
apk_blob_t blob = apk_blob_from_istream(is, ae->size);
apk_blob_for_each_segment(blob, "\n", read_info_line, ctx);
free(blob.ptr);
return 0;
}
if (strcmp(ae->name, ".INSTALL") == 0) {
ri->version = 2;
} else if (strncmp(ae->name, ".SIGN.", 6) == 0) {
ri->has_signature = 1;
} else if (strcmp(ae->name, ".INSTALL") == 0) {
apk_warning("Package '%s-%s' contains deprecated .INSTALL",
pkg->name->name, pkg->version);
return 0;
}
} else if (strncmp(ae->name, "var/db/apk/", 11) == 0) {
return 0;
}
ri->data_started = 1;
if (strncmp(ae->name, "var/db/apk/", 11) == 0) {
/* APK 1.0 format */
ri->version = 1;
if (!S_ISREG(ae->mode))
......@@ -399,10 +414,7 @@ static int read_info_entry(void *ctx, const struct apk_file_info *ae,
if (apk_script_type(slash+1) == APK_SCRIPT_POST_INSTALL ||
apk_script_type(slash+1) == APK_SCRIPT_PRE_INSTALL)
ri->has_install = 1;
} else if (ri->version == 2) {
/* All metdata of version 2.x package handled */
return 0;
} else {
} else if (ri->version < 2) {
/* Version 1.x packages do not contain installed size
* in metadata, so we calculate it here */
pkg->installed_size += apk_calc_installed_size(ae->size);
......@@ -417,29 +429,59 @@ static int apk_pkg_gzip_part(void *ctx, EVP_MD_CTX *mdctx, int part)
switch (part) {
case APK_MPART_BEGIN:
EVP_DigestInit_ex(mdctx, EVP_md5(), NULL);
EVP_DigestInit_ex(mdctx, ri->md, NULL);
break;
case APK_MPART_BOUNDARY:
if (ri->in_signatures) {
EVP_DigestFinal_ex(mdctx, ri->pkg->csum.data, NULL);
EVP_DigestInit_ex(mdctx, ri->md, NULL);
return 0;
}
if (ri->action == APK_SIGN_GENERATE_V1 ||
!ri->has_data_checksum)
break;
/* Fallthrough to calculate checksum */
case APK_MPART_END:
ri->pkg->csum.type = EVP_MD_CTX_size(mdctx);
EVP_DigestFinal_ex(mdctx, ri->pkg->csum.data, NULL);
break;
return 1;
}
return 0;
}
struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
struct apk_package *apk_pkg_read(struct apk_database *db, const char *file,
int action)
{
struct read_info_ctx ctx;
struct apk_file_info fi;
struct apk_bstream *bs;
struct apk_istream *tar;
char realfile[PATH_MAX];
int r;
if (realpath(file, realfile) < 0)
return NULL;
if (apk_file_get_info(realfile, APK_CHECKSUM_NONE, &fi) < 0)
return NULL;
memset(&ctx, 0, sizeof(ctx));
switch (action) {
case APK_SIGN_VERIFY:
ctx.in_signatures = 1;
ctx.md = EVP_md_null();
break;
case APK_SIGN_GENERATE:
ctx.in_signatures = 1;
ctx.md = EVP_sha1();
break;
case APK_SIGN_GENERATE_V1:
ctx.md = EVP_md5();
break;
default:
return NULL;
}
ctx.pkg = apk_pkg_new();
if (ctx.pkg == NULL)
return NULL;
......@@ -450,15 +492,22 @@ struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
ctx.db = db;
ctx.has_install = 0;
ctx.action = action;
ctx.pkg->size = fi.size;
tar = apk_bstream_gunzip_mpart(bs, apk_pkg_gzip_part, &ctx);
if (apk_parse_tar(tar, read_info_entry, &ctx) < 0) {
r = apk_tar_parse(tar, read_info_entry, &ctx);
tar->close(tar);
switch (r) {
case 0:
break;
case -2:
apk_error("File %s does not have a signature", file);
goto err;
default:
apk_error("File %s is not an APK archive", file);
bs->close(bs, NULL);
goto err;
}
tar->close(tar);
if (ctx.pkg->name == NULL) {
apk_error("File %s is corrupted", file);
......@@ -474,7 +523,7 @@ struct apk_package *apk_pkg_read(struct apk_database *db, const char *file)
}
ctx.pkg->filename = strdup(realfile);
return ctx.pkg;
return apk_db_pkg_add(db, ctx.pkg);
err:
apk_pkg_free(ctx.pkg);
return NULL;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment