aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--doc/apk-list.8.scd2
-rw-r--r--libfetch/common.c24
-rw-r--r--libfetch/common.h12
-rw-r--r--libfetch/fetch.c15
-rw-r--r--libfetch/ftp.c18
-rw-r--r--libfetch/http.c62
-rw-r--r--src/Makefile2
-rw-r--r--src/adb.c46
-rw-r--r--src/adb.h1
-rw-r--r--src/adb_comp.c4
-rw-r--r--src/adb_walk_adb.c31
-rw-r--r--src/adb_walk_text.c2
-rw-r--r--src/apk_archive.h35
-rw-r--r--src/apk_blob.h2
-rw-r--r--src/apk_context.h1
-rw-r--r--src/apk_crypto.h2
-rw-r--r--src/apk_database.h3
-rw-r--r--src/apk_defines.h6
-rw-r--r--src/apk_extract.h71
-rw-r--r--src/apk_io.h8
-rw-r--r--src/apk_package.h42
-rw-r--r--src/apk_print.h8
-rw-r--r--src/apk_tar.h22
-rw-r--r--src/apk_trust.h5
-rw-r--r--src/app_add.c11
-rw-r--r--src/app_cache.c3
-rw-r--r--src/app_convdb.c1
-rw-r--r--src/app_convndx.c44
-rw-r--r--src/app_extract.c237
-rw-r--r--src/app_fetch.c6
-rw-r--r--src/app_index.c64
-rw-r--r--src/app_info.c2
-rw-r--r--src/app_list.c4
-rw-r--r--src/app_manifest.c80
-rw-r--r--src/app_mkndx.c59
-rw-r--r--src/app_mkpkg.c42
-rw-r--r--src/app_verify.c30
-rw-r--r--src/blob.c62
-rw-r--r--src/commit.c2
-rw-r--r--src/common.c15
-rw-r--r--src/context.c14
-rw-r--r--src/database.c295
-rw-r--r--src/extract.c147
-rw-r--r--src/extract_v2.c395
-rw-r--r--src/extract_v3.c262
-rw-r--r--src/io.c65
-rw-r--r--src/io_gunzip.c4
-rw-r--r--src/meson.build8
-rw-r--r--src/package.c349
-rw-r--r--src/print.c1
-rw-r--r--src/tar.c (renamed from src/io_archive.c)179
-rw-r--r--src/trust.c30
-rw-r--r--test/Makefile4
-rw-r--r--test/basic8.test1
-rwxr-xr-xtest/solver.sh4
-rwxr-xr-xtest/version.sh2
56 files changed, 1597 insertions, 1249 deletions
diff --git a/doc/apk-list.8.scd b/doc/apk-list.8.scd
index e011825..e09577d 100644
--- a/doc/apk-list.8.scd
+++ b/doc/apk-list.8.scd
@@ -27,7 +27,7 @@ globbing.
*-a, --available*
Consider only available packages.
-*-u, --upgradable*
+*-u, --upgradable, --upgradeable*
Consider only upgradable packages.
*-o, --origin*
diff --git a/libfetch/common.c b/libfetch/common.c
index bcba889..248b575 100644
--- a/libfetch/common.c
+++ b/libfetch/common.c
@@ -171,6 +171,30 @@ fetch_info(const char *fmt, ...)
/*** Network-related utility functions ***************************************/
+uintmax_t
+fetch_parseuint(const char *str, const char **endptr, int radix, uintmax_t max)
+{
+ uintmax_t val = 0, maxx = max / radix, d;
+ const char *p;
+
+ for (p = str; isxdigit((unsigned char)*p); p++) {
+ unsigned char ch = (unsigned char)*p;
+ if (isdigit(ch))
+ d = ch - '0';
+ else d = tolower(ch) - 'a' + 10;
+ if (d > radix || val > maxx) goto err;
+ val *= radix;
+ if (val > max-d) goto err;
+ val += d;
+ }
+ if (p == str || val > max) goto err;
+ *endptr = p;
+ return val;
+err:
+ *endptr = "\xff";
+ return 0;
+}
+
/*
* Return the default port for a scheme
*/
diff --git a/libfetch/common.h b/libfetch/common.h
index dd5c14c..2c16bf7 100644
--- a/libfetch/common.h
+++ b/libfetch/common.h
@@ -38,6 +38,8 @@
#define FTP_DEFAULT_PROXY_PORT 21
#define HTTP_DEFAULT_PROXY_PORT 3128
+#include <sys/types.h>
+#include <limits.h>
#include "openssl-compat.h"
#if defined(__GNUC__) && __GNUC__ >= 3
@@ -53,6 +55,14 @@
#define HAVE_SA_LEN
#endif
+#ifndef IPPORT_MAX
+# define IPPORT_MAX 65535
+#endif
+
+#ifndef OFF_MAX
+# define OFF_MAX (((((off_t)1 << (sizeof(off_t) * CHAR_BIT - 2)) - 1) << 1) + 1)
+#endif
+
/* Connection */
typedef struct fetchconn conn_t;
@@ -86,6 +96,7 @@ struct fetcherr {
void fetch_seterr(struct fetcherr *, int);
void fetch_syserr(void);
void fetch_info(const char *, ...) LIBFETCH_PRINTFLIKE(1, 2);
+uintmax_t fetch_parseuint(const char *p, const char **endptr, int radix, uintmax_t max);
int fetch_default_port(const char *);
int fetch_default_proxy_port(const char *);
int fetch_bind(int, int, const char *);
@@ -125,7 +136,6 @@ fetchIO *http_request(struct url *, const char *,
fetchIO *ftp_request(struct url *, const char *, const char *,
struct url_stat *, struct url *, const char *);
-
/*
* Check whether a particular flag is set
*/
diff --git a/libfetch/fetch.c b/libfetch/fetch.c
index a0d4dbd..45c92aa 100644
--- a/libfetch/fetch.c
+++ b/libfetch/fetch.c
@@ -473,15 +473,12 @@ find_user:
/* port */
if (*p == ':') {
- for (q = ++p; *q && (*q != '/'); q++)
- if (isdigit((unsigned char)*q))
- u->port = u->port * 10 + (*q - '0');
- else {
- /* invalid port */
- url_seterr(URL_BAD_PORT);
- goto ouch;
- }
- p = q;
+ u->port = fetch_parseuint(p + 1, &p, 10, IPPORT_MAX);
+ if (*p && *p != '/') {
+ /* invalid port */
+ url_seterr(URL_BAD_PORT);
+ goto ouch;
+ }
}
/* document */
diff --git a/libfetch/ftp.c b/libfetch/ftp.c
index 8f9f04f..77790aa 100644
--- a/libfetch/ftp.c
+++ b/libfetch/ftp.c
@@ -471,8 +471,7 @@ ftp_stat(conn_t *conn, const char *file, struct url_stat *us)
}
for (ln = conn->buf + 4; *ln && isspace((unsigned char)*ln); ln++)
/* nothing */ ;
- for (us->size = 0; *ln && isdigit((unsigned char)*ln); ln++)
- us->size = us->size * 10 + *ln - '0';
+ us->size = fetch_parseuint(ln, (const char **) &ln, 10, OFF_MAX);
if (*ln && !isspace((unsigned char)*ln)) {
ftp_seterr(FTP_PROTOCOL_ERROR);
us->size = -1;
@@ -700,7 +699,7 @@ retry_mode:
if (pasv) {
unsigned char addr[64];
- char *ln, *p;
+ const char *ln, *p;
unsigned int i;
int port;
@@ -737,10 +736,15 @@ retry_mode:
for (p = ln + 3; *p && !isdigit((unsigned char)*p); p++)
/* nothing */ ;
if (!*p) goto protocol_error;
- l = (e == FTP_PASSIVE_MODE ? 6 : 21);
- for (i = 0; *p && i < l; i++, p++)
- addr[i] = strtol(p, &p, 10);
- if (i < l) goto protocol_error;
+ l = (e == FTP_PASSIVE_MODE ? 6 : 21) - 1;
+ for (i = 0; *p && i < l; i++, p++) {
+ while (isspace((unsigned char)*p)) p++;
+ addr[i] = fetch_parseuint(p, &p, 10, UCHAR_MAX);
+ if (*p != ',') goto protocol_error;
+ }
+ while (isspace((unsigned char)*p)) p++;
+ addr[i] = fetch_parseuint(p, &p, 10, UCHAR_MAX);
+ if (*p && *p != ')') goto protocol_error;
break;
case FTP_EPASSIVE_MODE:
for (p = ln + 3; *p && *p != '('; p++)
diff --git a/libfetch/http.c b/libfetch/http.c
index 59d6292..abc3ae6 100644
--- a/libfetch/http.c
+++ b/libfetch/http.c
@@ -134,29 +134,19 @@ struct httpio
static int
http_new_chunk(struct httpio *io)
{
- char *p;
+ const char *p;
if (fetch_getln(io->conn) == -1)
- return (-1);
+ return -1;
- if (io->conn->buflen < 2 || !isxdigit((unsigned char)*io->conn->buf))
- return (-1);
+ if (io->conn->buflen < 2)
+ return -1;
- for (p = io->conn->buf; *p && !isspace((unsigned char)*p); ++p) {
- if (*p == ';')
- break;
- if (!isxdigit((unsigned char)*p))
- return (-1);
- if (isdigit((unsigned char)*p)) {
- io->chunksize = io->chunksize * 16 +
- *p - '0';
- } else {
- io->chunksize = io->chunksize * 16 +
- 10 + tolower((unsigned char)*p) - 'a';
- }
- }
+ io->chunksize = fetch_parseuint(io->conn->buf, &p, 16, SIZE_MAX);
+ if (*p && *p != ';' && !isspace(*p))
+ return -1;
- return (io->chunksize);
+ return io->chunksize;
}
/*
@@ -502,22 +492,6 @@ http_parse_mtime(const char *p, time_t *mtime)
}
/*
- * Parse a content-length header
- */
-static int
-http_parse_length(const char *p, off_t *length)
-{
- off_t len;
-
- for (len = 0; *p && isdigit((unsigned char)*p); ++p)
- len = len * 10 + (*p - '0');
- if (*p)
- return (-1);
- *length = len;
- return (0);
-}
-
-/*
* Parse a content-range header
*/
static int
@@ -532,17 +506,14 @@ http_parse_range(const char *p, off_t *offset, off_t *length, off_t *size)
first = last = -1;
++p;
} else {
- for (first = 0; *p && isdigit((unsigned char)*p); ++p)
- first = first * 10 + *p - '0';
+ first = fetch_parseuint(p, &p, 10, OFF_MAX);
if (*p != '-')
return (-1);
- for (last = 0, ++p; *p && isdigit((unsigned char)*p); ++p)
- last = last * 10 + *p - '0';
+ last = fetch_parseuint(p+1, &p, 10, OFF_MAX);
}
if (first > last || *p != '/')
return (-1);
- for (len = 0, ++p; *p && isdigit((unsigned char)*p); ++p)
- len = len * 10 + *p - '0';
+ len = fetch_parseuint(p+1, &p, 10, OFF_MAX);
if (*p || len < last - first + 1)
return (-1);
if (first == -1)
@@ -850,7 +821,7 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
int e, i, n;
off_t offset, clength, length, size;
time_t mtime;
- const char *p;
+ const char *p, *q;
fetchIO *f;
hdr_t h;
char hbuf[URL_HOSTLEN + 7], *host;
@@ -1050,13 +1021,16 @@ http_request(struct url *URL, const char *op, struct url_stat *us,
keep_alive = (strcasecmp(p, "keep-alive") == 0);
break;
case hdr_content_length:
- http_parse_length(p, &clength);
+ clength = fetch_parseuint(p, &q, 10, OFF_MAX);
+ if (*q) goto protocol_error;
break;
case hdr_content_range:
- http_parse_range(p, &offset, &length, &size);
+ if (http_parse_range(p, &offset, &length, &size) < 0)
+ goto protocol_error;
break;
case hdr_last_modified:
- http_parse_mtime(p, &mtime);
+ if (http_parse_mtime(p, &mtime) < 0)
+ goto protocol_error;
break;
case hdr_location:
if (!HTTP_REDIRECT(conn->err))
diff --git a/src/Makefile b/src/Makefile
index 970354b..f7ebb66 100644
--- a/src/Makefile
+++ b/src/Makefile
@@ -21,7 +21,7 @@ libapk_so := $(obj)/libapk.so.$(libapk_soname)
libapk.so.$(libapk_soname)-objs := \
adb.o adb_comp.o adb_walk_adb.o adb_walk_genadb.o adb_walk_gentext.o adb_walk_text.o apk_adb.o \
atom.o blob.o commit.o common.o context.o crypto_openssl.o database.o hash.o \
- io.o io_archive.o io_gunzip.o io_url.o \
+ extract.o extract_v2.o extract_v3.o io.o io_gunzip.o io_url.o tar.o \
package.o pathbuilder.o print.o solver.o trust.o version.o
libapk.so.$(libapk_soname)-libs := libfetch/libfetch.a
diff --git a/src/adb.c b/src/adb.c
index 1fc135c..6e63231 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -37,7 +37,7 @@ static struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b)
}
#define adb_foreach_block(__blk, __adb) \
- for (__blk = adb_block_first(__adb); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb))
+ for (__blk = adb_block_first(__adb); __blk && !IS_ERR(__blk); __blk = adb_block_next(__blk, __adb))
/* Init stuff */
int adb_free(struct adb *db)
@@ -82,7 +82,7 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t,
struct adb_verify_ctx vfy = {};
struct adb_block *blk;
struct apk_istream is;
- int r = 0, trusted = t ? 0 : 1;
+ int r = 0, trusted = (t && t->allow_untrusted) ? 1 : 0;
uint32_t type, allowed = BIT(ADB_BLOCK_ADB);
adb_foreach_block(blk, data) {
@@ -97,11 +97,11 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t,
allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
if (b.len < 16) {
r = -APKE_ADB_BLOCK;
- break;
+ goto err;
}
if (((struct adb_hdr*)b.ptr)->adb_compat_ver != 0) {
r = -APKE_ADB_VERSION;
- break;
+ goto err;
}
db->adb = b;
break;
@@ -112,11 +112,14 @@ static int __adb_m_parse(struct adb *db, apk_blob_t data, struct apk_trust *t,
break;
case ADB_BLOCK_DATA:
allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
- if (!trusted) goto err;
+ if (!trusted) {
+ r = -APKE_SIGNATURE_UNTRUSTED;
+ goto err;
+ }
break;
case ADB_BLOCK_DATAX:
r = -APKE_ADB_BLOCK;
- break;
+ goto err;
}
r = cb(db, blk, apk_istream_from_blob(&is, b));
if (r < 0) break;
@@ -170,7 +173,7 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
struct adb_block blk;
struct apk_segment_istream seg;
void *sig;
- int r = 0, trusted = t ? 0 : 1;
+ int r = 0, trusted = (t && t->allow_untrusted) ? 1 : 0;
uint32_t type, allowed = BIT(ADB_BLOCK_ADB);
size_t sz;
@@ -198,24 +201,25 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
r = -APKE_ADB_BLOCK;
break;
}
- sz = adb_block_size(&blk) - sizeof blk;
+
+ sz = adb_block_length(&blk);
switch (type) {
case ADB_BLOCK_ADB:
allowed = BIT(ADB_BLOCK_SIG) | BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
db->adb.ptr = malloc(sz);
- db->adb.len = adb_block_length(&blk);
+ db->adb.len = sz;
if (db->adb.len < 16) {
r = -APKE_ADB_BLOCK;
- break;
+ goto err;
}
if ((r = apk_istream_read(is, db->adb.ptr, sz)) < 0) goto err;
if (((struct adb_hdr*)db->adb.ptr)->adb_compat_ver != 0) {
r = -APKE_ADB_VERSION;
- break;
+ goto err;
}
r = cb(db, &blk, apk_istream_from_blob(&seg.is, db->adb));
if (r < 0) goto err;
- continue;
+ goto skip_padding;
case ADB_BLOCK_SIG:
sig = apk_istream_peek(is, sz);
if (IS_ERR(sig)) {
@@ -223,22 +227,28 @@ static int __adb_m_stream(struct adb *db, struct apk_istream *is, uint32_t expec
goto err;
}
if (!trusted &&
- adb_trust_verify_signature(t, db, &vfy, APK_BLOB_PTR_LEN(sig, adb_block_length(&blk))) == 0)
+ adb_trust_verify_signature(t, db, &vfy, APK_BLOB_PTR_LEN(sig, sz)) == 0)
trusted = 1;
break;
case ADB_BLOCK_DATA:
allowed = BIT(ADB_BLOCK_DATA) | BIT(ADB_BLOCK_DATAX);
- if (!trusted) goto err;
+ if (!trusted) {
+ r = -APKE_SIGNATURE_UNTRUSTED;
+ goto err;
+ }
break;
case ADB_BLOCK_DATAX:
r = -APKE_ADB_BLOCK;
- break;
+ goto err;
}
apk_istream_segment(&seg, is, sz, 0);
r = cb(db, &blk, &seg.is);
+ r = apk_istream_close_error(&seg.is, r);
if (r < 0) break;
- r = apk_istream_close(&seg.is);
+
+ skip_padding:
+ r = apk_istream_read(is, 0, adb_block_padding(&blk));
if (r < 0) break;
} while (1);
err:
@@ -456,7 +466,7 @@ struct adb_obj *adb_ro_obj(const struct adb_obj *o, unsigned i, struct adb_obj *
schema = container_of(o->schema->fields[0].kind, struct adb_object_schema, kind);
else if (i > 0 && i < o->schema->num_fields)
schema = container_of(o->schema->fields[i-1].kind, struct adb_object_schema, kind);
- assert(schema->kind == ADB_KIND_OBJECT || schema->kind == ADB_KIND_ARRAY);
+ assert(schema && (schema->kind == ADB_KIND_OBJECT || schema->kind == ADB_KIND_ARRAY));
}
return adb_r_obj(o->db, adb_ro_val(o, i), no, schema);
@@ -1099,8 +1109,6 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a
size_t siglen;
int r;
- if (IS_ERR_OR_NULL(trust)) return PTR_ERR(trust);
-
if (!vfy) {
vfy = alloca(sizeof *vfy);
memset(vfy, 0, sizeof *vfy);
diff --git a/src/adb.h b/src/adb.h
index e97068a..3dfd64c 100644
--- a/src/adb.h
+++ b/src/adb.h
@@ -44,6 +44,7 @@ typedef uint32_t adb_val_t;
/* File Header */
#define ADB_FORMAT_MAGIC 0x2e424441 // ADB.
+#define ADB_SCHEMA_ANY 0
#define ADB_SCHEMA_IMPLIED 0x80000000
struct adb_file_header {
diff --git a/src/adb_comp.c b/src/adb_comp.c
index 26fb50f..3baaac3 100644
--- a/src/adb_comp.c
+++ b/src/adb_comp.c
@@ -13,7 +13,7 @@ struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compressi
{
adb_comp_t c = -1;
- if (IS_ERR_OR_NULL(is)) return is;
+ if (IS_ERR(is)) return is;
uint8_t *buf = apk_istream_peek(is, 4);
if (IS_ERR(buf)) return ERR_PTR(apk_istream_close_error(is, PTR_ERR(buf)));
@@ -35,7 +35,7 @@ struct apk_istream *adb_decompress(struct apk_istream *is, adb_comp_t *compressi
struct apk_ostream *adb_compress(struct apk_ostream *os, adb_comp_t compression)
{
- if (IS_ERR_OR_NULL(os)) return os;
+ if (IS_ERR(os)) return os;
switch (compression) {
case ADB_COMP_NONE:
return os;
diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c
index 9a74e7e..1127487 100644
--- a/src/adb_walk_adb.c
+++ b/src/adb_walk_adb.c
@@ -110,14 +110,14 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea
{
struct adb_walk_ctx *ctx = container_of(db, struct adb_walk_ctx, db);
struct adb_walk *d = ctx->d;
- char tmp[16+ADB_MAX_SIGNATURE_LEN*2];
+ char tmp[160];
struct adb_hdr *hdr;
struct adb_sign_hdr *s;
uint32_t schema_magic = ctx->db.schema;
const struct adb_db_schema *ds;
- int r, len;
size_t sz = adb_block_length(b);
- apk_blob_t data;
+ apk_blob_t data, c = APK_BLOB_BUF(tmp);
+ int r;
switch (adb_block_type(b)) {
case ADB_BLOCK_ADB:
@@ -126,30 +126,29 @@ static int adb_walk_block(struct adb *db, struct adb_block *b, struct apk_istrea
if (ds->magic == schema_magic) break;
hdr = apk_istream_peek(is, sizeof *hdr);
if (IS_ERR(hdr)) return PTR_ERR(hdr);
- len = snprintf(tmp, sizeof tmp, "ADB block, size: %zu, compat: %d, ver: %d",
+ apk_blob_push_fmt(&c, "ADB block, size: %zu, compat: %d, ver: %d",
sz, hdr->adb_compat_ver, hdr->adb_ver);
- d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
+ d->ops->comment(d, apk_blob_pushed(APK_BLOB_BUF(tmp), c));
if (ds->root && hdr->adb_compat_ver == 0) dump_object(ctx, ds->root, adb_r_root(db));
- break;
+ return 0;
case ADB_BLOCK_SIG:
s = (struct adb_sign_hdr*) apk_istream_get(is, sz);
data = APK_BLOB_PTR_LEN((char*)s, sz);
r = adb_trust_verify_signature(ctx->trust, db, &ctx->vfy, data);
- len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
- for (size_t j = sizeof *s; j < data.len; j++)
- len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)data.ptr[j]);
- len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK");
- d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
+ apk_blob_push_fmt(&c, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
+ for (size_t j = sizeof *s; j < data.len && c.len > 40; j++)
+ apk_blob_push_fmt(&c, "%02x", (uint8_t)data.ptr[j]);
+ if (c.len <= 40) apk_blob_push_blob(&c, APK_BLOB_STRLIT(".."));
+ apk_blob_push_fmt(&c, ": %s", r ? apk_error_str(r) : "OK");
break;
case ADB_BLOCK_DATA:
- len = snprintf(tmp, sizeof tmp, "data block, size: %zu", sz);
- d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
+ apk_blob_push_fmt(&c, "data block, size: %zu", sz);
break;
default:
- len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %zu",
- adb_block_type(b), sz);
- d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
+ apk_blob_push_fmt(&c, "unknown block %d, size: %zu", adb_block_type(b), sz);
+ break;
}
+ d->ops->comment(d, apk_blob_pushed(APK_BLOB_BUF(tmp), c));
return 0;
}
diff --git a/src/adb_walk_text.c b/src/adb_walk_text.c
index 1b7f5cf..f1ec7ee 100644
--- a/src/adb_walk_text.c
+++ b/src/adb_walk_text.c
@@ -19,7 +19,7 @@ int adb_walk_text(struct adb_walk *d, struct apk_istream *is)
int r = 0, i, multi_line = 0, nesting = 0, new_item = 0;
uint8_t started[64] = {0};
- if (IS_ERR_OR_NULL(is)) return PTR_ERR(is);
+ if (IS_ERR(is)) return PTR_ERR(is);
if (apk_istream_get_delim(is, token, &l) != 0) goto err;
apk_blob_pull_blob_match(&l, APK_BLOB_STR("#%SCHEMA: "));
if ((r = d->ops->schema(d, apk_blob_pull_uint(&l, 16))) != 0) goto err;
diff --git a/src/apk_archive.h b/src/apk_archive.h
deleted file mode 100644
index 3dbd284..0000000
--- a/src/apk_archive.h
+++ /dev/null
@@ -1,35 +0,0 @@
-/* apk_archive.c - Alpine Package Keeper (APK)
- *
- * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
- * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
- * All rights reserved.
- *
- * SPDX-License-Identifier: GPL-2.0-only
- */
-
-#ifndef APK_ARCHIVE
-#define APK_ARCHIVE
-
-#include <sys/types.h>
-#include "apk_blob.h"
-#include "apk_print.h"
-#include "apk_io.h"
-
-int apk_tar_parse(struct apk_istream *,
- apk_archive_entry_parser parser, void *ctx,
- struct apk_id_cache *);
-int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
- const char *data);
-int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
-
-#define APK_EXTRACTF_NO_CHOWN 0x0001
-#define APK_EXTRACTF_NO_OVERWRITE 0x0002
-
-int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
- const char *extract_name, const char *hardlink_name,
- struct apk_istream *is,
- apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
- unsigned int extract_flags,
- struct apk_out *out);
-
-#endif
diff --git a/src/apk_blob.h b/src/apk_blob.h
index 2220a75..97f5503 100644
--- a/src/apk_blob.h
+++ b/src/apk_blob.h
@@ -116,6 +116,8 @@ void apk_blob_push_uint(apk_blob_t *to, unsigned int value, int radix);
void apk_blob_push_csum(apk_blob_t *to, struct apk_checksum *csum);
void apk_blob_push_base64(apk_blob_t *to, apk_blob_t binary);
void apk_blob_push_hexdump(apk_blob_t *to, apk_blob_t binary);
+void apk_blob_push_fmt(apk_blob_t *to, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
void apk_blob_pull_char(apk_blob_t *b, int expected);
unsigned int apk_blob_pull_uint(apk_blob_t *b, int radix);
diff --git a/src/apk_context.h b/src/apk_context.h
index 3a6f2f2..1bec2b9 100644
--- a/src/apk_context.h
+++ b/src/apk_context.h
@@ -66,7 +66,6 @@ struct apk_ctx {
const char *repositories_file;
const char *uvol;
struct apk_string_array *repository_list;
- struct apk_string_array *private_keys;
struct apk_trust trust;
struct apk_id_cache id_cache;
diff --git a/src/apk_crypto.h b/src/apk_crypto.h
index d3ce24b..4eab130 100644
--- a/src/apk_crypto.h
+++ b/src/apk_crypto.h
@@ -82,9 +82,9 @@ static inline int apk_digest_calc(struct apk_digest *d, uint8_t alg, const void
}
static inline int apk_digest_ctx_init(struct apk_digest_ctx *dctx, uint8_t alg) {
+ dctx->alg = alg;
dctx->mdctx = EVP_MD_CTX_new();
if (!dctx->mdctx) return -ENOMEM;
- dctx->alg = alg;
#ifdef EVP_MD_CTX_FLAG_FINALISE
EVP_MD_CTX_set_flags(dctx->mdctx, EVP_MD_CTX_FLAG_FINALISE);
#endif
diff --git a/src/apk_database.h b/src/apk_database.h
index 94507bc..e65a1de 100644
--- a/src/apk_database.h
+++ b/src/apk_database.h
@@ -13,7 +13,6 @@
#include "apk_version.h"
#include "apk_hash.h"
#include "apk_atom.h"
-#include "apk_archive.h"
#include "apk_package.h"
#include "apk_io.h"
#include "apk_context.h"
@@ -221,7 +220,7 @@ unsigned int apk_db_get_pinning_mask_repos(struct apk_database *db, unsigned sho
int apk_db_cache_active(struct apk_database *db);
int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
- struct apk_package *pkg, int verify, int autoupdate,
+ struct apk_package *pkg, int autoupdate,
apk_progress_cb cb, void *cb_ctx);
typedef void (*apk_cache_item_cb)(struct apk_database *db,
diff --git a/src/apk_defines.h b/src/apk_defines.h
index f1b0f8d..395958b 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -43,6 +43,7 @@ enum {
APKE_SIGNATURE_FAIL,
APKE_SIGNATURE_UNTRUSTED,
APKE_SIGNATURE_INVALID,
+ APKE_FORMAT_NOT_SUPPORTED,
APKE_ADB_COMPRESSION,
APKE_ADB_HEADER,
APKE_ADB_VERSION,
@@ -68,7 +69,6 @@ static inline void *ERR_PTR(long error) { return (void*) error; }
static inline void *ERR_CAST(const void *ptr) { return (void*) ptr; }
static inline int PTR_ERR(const void *ptr) { return (int)(long) ptr; }
static inline int IS_ERR(const void *ptr) { return (unsigned long)ptr >= (unsigned long)-4095; }
-static inline int IS_ERR_OR_NULL(const void *ptr) { return IS_ERR(ptr) || !ptr; }
#if defined __GNUC__ && __GNUC__ == 2 && __GNUC_MINOR__ < 96
#define __builtin_expect(x, expected_value) (x)
@@ -177,6 +177,8 @@ static inline uint32_t get_unaligned32(const void *ptr)
typedef void (*apk_progress_cb)(void *cb_ctx, size_t);
+time_t apk_get_build_time(void);
+
void *apk_array_resize(void *array, size_t new_size, size_t elem_size);
#define APK_ARRAY(array_type_name, elem_type_name) \
@@ -209,7 +211,7 @@ void *apk_array_resize(void *array, size_t new_size, size_t elem_size);
static inline elem_type_name * \
array_type_name##_add(struct array_type_name **a) \
{ \
- int size = 1 + (*a)->num; \
+ int size = 1 + ((*a) ? (*a)->num : 0); \
*a = apk_array_resize(*a, size, sizeof(elem_type_name));\
return &(*a)->item[size-1]; \
}
diff --git a/src/apk_extract.h b/src/apk_extract.h
new file mode 100644
index 0000000..c44ed87
--- /dev/null
+++ b/src/apk_extract.h
@@ -0,0 +1,71 @@
+/* apk_extract.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2021 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#ifndef APK_EXTRACT
+#define APK_EXTRACT
+
+#include "apk_crypto.h"
+#include "apk_print.h"
+#include "apk_io.h"
+
+struct adb_obj;
+struct apk_ctx;
+struct apk_extract_ctx;
+
+#define APK_EXTRACTF_NO_CHOWN 0x0001
+#define APK_EXTRACTF_NO_OVERWRITE 0x0002
+
+int apk_extract_file(int atfd, const struct apk_file_info *ae,
+ const char *extract_name, const char *hardlink_name,
+ struct apk_istream *is,
+ apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
+ unsigned int extract_flags, struct apk_out *out);
+
+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_obj *);
+ int (*v3meta)(struct apk_extract_ctx *, struct adb_obj *);
+ 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;
+ const struct apk_extract_ops *ops;
+ struct apk_checksum *identity;
+ 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, 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->ops);
+}
+static inline void apk_extract_generate_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
+ ctx->identity = id;
+ ctx->generate_identity = 1;
+}
+static inline void apk_extract_verify_identity(struct apk_extract_ctx *ctx, struct apk_checksum *id) {
+ ctx->identity = id;
+}
+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);
+
+#endif
diff --git a/src/apk_io.h b/src/apk_io.h
index 3ad0790..762f9e0 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -135,6 +135,14 @@ struct apk_segment_istream {
};
struct apk_istream *apk_istream_segment(struct apk_segment_istream *sis, struct apk_istream *is, size_t len, time_t mtime);
+struct apk_digest_istream {
+ struct apk_istream is;
+ struct apk_istream *pis;
+ struct apk_digest *digest;
+ struct apk_digest_ctx dctx;
+};
+struct apk_istream *apk_istream_verify(struct apk_digest_istream *dis, struct apk_istream *is, struct apk_digest *d);
+
#define APK_ISTREAM_TEE_COPY_META 1
#define APK_ISTREAM_TEE_OPTIONAL 2
diff --git a/src/apk_package.h b/src/apk_package.h
index 0f7542c..c6545c2 100644
--- a/src/apk_package.h
+++ b/src/apk_package.h
@@ -30,12 +30,6 @@ struct apk_trust;
#define APK_SCRIPT_TRIGGER 6
#define APK_SCRIPT_MAX 7
-#define APK_SIGN_NONE 0
-#define APK_SIGN_VERIFY 1
-#define APK_SIGN_VERIFY_IDENTITY 2
-#define APK_SIGN_GENERATE 4
-#define APK_SIGN_VERIFY_AND_GENERATE 5
-
#define APK_DEP_IRRELEVANT 0x01
#define APK_DEP_SATISFIES 0x02
#define APK_DEP_CONFLICTS 0x04
@@ -45,28 +39,6 @@ struct apk_trust;
#define APK_FOREACH_DEP 0x80
#define APK_FOREACH_GENID_MASK 0xffffff00
-struct apk_sign_ctx {
- struct apk_trust *trust;
- int action;
- const EVP_MD *md;
- int num_signatures;
- int control_started : 1;
- int data_started : 1;
- int has_data_checksum : 1;
- int control_verified : 1;
- int data_verified : 1;
- int allow_untrusted : 1;
- char data_checksum[EVP_MAX_MD_SIZE];
- struct apk_checksum identity;
- EVP_MD_CTX *mdctx;
-
- struct {
- apk_blob_t data;
- EVP_PKEY *pkey;
- char *identity;
- } signature;
-};
-
struct apk_dependency {
struct apk_name *name;
apk_blob_t *version;
@@ -132,17 +104,6 @@ APK_ARRAY(apk_package_array, struct apk_package *);
extern const char *apk_script_types[];
-void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
- struct apk_checksum *identity, struct apk_trust *trust);
-void apk_sign_ctx_free(struct apk_sign_ctx *ctx);
-int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
- const struct apk_file_info *fi,
- struct apk_istream *is);
-int apk_sign_ctx_parse_pkginfo_line(void *ctx, apk_blob_t line);
-int apk_sign_ctx_verify_tar(void *ctx, const struct apk_file_info *fi,
- struct apk_istream *is);
-int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t blob);
-
void apk_dep_from_pkg(struct apk_dependency *dep, struct apk_database *db,
struct apk_package *pkg);
int apk_dep_is_materialized(struct apk_dependency *dep, struct apk_package *pkg);
@@ -165,8 +126,7 @@ int apk_script_type(const char *name);
struct apk_package *apk_pkg_get_installed(struct apk_name *name);
struct apk_package *apk_pkg_new(void);
-int apk_pkg_read(struct apk_database *db, const char *name,
- struct apk_sign_ctx *ctx, struct apk_package **pkg);
+int apk_pkg_read(struct apk_database *db, const char *name, struct apk_package **pkg);
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);
diff --git a/src/apk_print.h b/src/apk_print.h
index a8e734a..e97247b 100644
--- a/src/apk_print.h
+++ b/src/apk_print.h
@@ -26,7 +26,7 @@ struct apk_url_print {
void apk_url_parse(struct apk_url_print *, const char *);
#define URL_FMT "%.*s%s%s"
-#define URL_PRINTF(u) u.len_before_pw, u.url, u.pwmask, u.url_or_host
+#define URL_PRINTF(u) (int)u.len_before_pw, u.url, u.pwmask, u.url_or_host
struct apk_out {
int verbosity;
@@ -48,7 +48,8 @@ static inline int apk_out_verbosity(struct apk_out *out) { return out->verbosity
#define apk_dbg2(out, args...) do { if (apk_out_verbosity(out) >= 3) { apk_out_fmt(out, NULL, args); } } while (0)
void apk_out_reset(struct apk_out *);
-void apk_out_fmt(struct apk_out *, const char *prefix, const char *format, ...);
+void apk_out_fmt(struct apk_out *, const char *prefix, const char *format, ...)
+ __attribute__ ((format (printf, 3, 4)));
void apk_out_log_argv(struct apk_out *, char **argv);
struct apk_progress {
@@ -68,6 +69,7 @@ struct apk_indent {
int apk_print_indented(struct apk_indent *i, apk_blob_t blob);
void apk_print_indented_words(struct apk_indent *i, const char *text);
-void apk_print_indented_fmt(struct apk_indent *i, const char *fmt, ...);
+void apk_print_indented_fmt(struct apk_indent *i, const char *fmt, ...)
+ __attribute__ ((format (printf, 2, 3)));
#endif
diff --git a/src/apk_tar.h b/src/apk_tar.h
new file mode 100644
index 0000000..c3d951c
--- /dev/null
+++ b/src/apk_tar.h
@@ -0,0 +1,22 @@
+/* apk_tar.h - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#ifndef APK_TAR
+#define APK_TAR
+
+#include "apk_io.h"
+
+int apk_tar_parse(struct apk_istream *,
+ apk_archive_entry_parser parser, void *ctx,
+ struct apk_id_cache *);
+int apk_tar_write_entry(struct apk_ostream *, const struct apk_file_info *ae,
+ const char *data);
+int apk_tar_write_padding(struct apk_ostream *, const struct apk_file_info *ae);
+
+#endif
diff --git a/src/apk_trust.h b/src/apk_trust.h
index 0f612f9..6e6f6b8 100644
--- a/src/apk_trust.h
+++ b/src/apk_trust.h
@@ -24,11 +24,12 @@ struct apk_trust {
struct list_head trusted_key_list;
struct list_head private_key_list;
int allow_untrusted : 1;
- int initialized : 1;
+ int keys_loaded : 1;
};
-int apk_trust_init(struct apk_trust *trust, int keysfd, struct apk_string_array *);
+void apk_trust_init(struct apk_trust *trust);
void apk_trust_free(struct apk_trust *trust);
+int apk_trust_load_keys(struct apk_trust *trust, int keysfd);
struct apk_pkey *apk_trust_key_by_name(struct apk_trust *trust, const char *filename);
#endif
diff --git a/src/app_add.c b/src/app_add.c
index 559475e..214bf67 100644
--- a/src/app_add.c
+++ b/src/app_add.c
@@ -14,6 +14,7 @@
#include "apk_database.h"
#include "apk_print.h"
#include "apk_solver.h"
+#include "apk_extract.h"
struct add_ctx {
const char *virtpkg;
@@ -132,7 +133,7 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args
if (APK_BLOB_IS_NULL(b) || virtdep.conflict ||
virtdep.result_mask != APK_DEPMASK_ANY ||
virtdep.version != &apk_atom_null) {
- apk_err(out, "%s: bad package specifier");
+ apk_err(out, "%s: bad package specifier", actx->virtpkg);
return -1;
}
if (virtdep.name->name[0] != '.' && non_repository_check(db))
@@ -146,6 +147,8 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args
virtdep.result_mask = APK_VERSION_EQUAL;
virtdep.version = virtpkg->version;
+
+ if (!args->num) apk_warn(out, "creating empty virtual package");
}
foreach_array_item(parg, args) {
@@ -153,15 +156,11 @@ static int add_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args
if (strstr(*parg, ".apk") != NULL) {
struct apk_package *pkg = NULL;
- struct apk_sign_ctx sctx;
if (non_repository_check(db))
return -1;
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY_AND_GENERATE,
- NULL, apk_ctx_get_trust(ac));
- r = apk_pkg_read(db, *parg, &sctx, &pkg);
- apk_sign_ctx_free(&sctx);
+ r = apk_pkg_read(db, *parg, &pkg);
if (r != 0) {
apk_err(out, "%s: %s", *parg, apk_error_str(r));
return -1;
diff --git a/src/app_cache.c b/src/app_cache.c
index db562cb..b744f25 100644
--- a/src/app_cache.c
+++ b/src/app_cache.c
@@ -98,8 +98,7 @@ static int cache_download(struct cache_ctx *cctx, struct apk_database *db)
if (repo == NULL)
continue;
- r = apk_cache_download(db, repo, pkg, APK_SIGN_VERIFY_IDENTITY, 0,
- progress_cb, &prog);
+ r = apk_cache_download(db, repo, pkg, 0, progress_cb, &prog);
if (r && r != -EALREADY) {
apk_err(out, PKG_VER_FMT ": %s", PKG_VER_PRINTF(pkg), apk_error_str(r));
ret++;
diff --git a/src/app_convdb.c b/src/app_convdb.c
index f30d0f7..5e60115 100644
--- a/src/app_convdb.c
+++ b/src/app_convdb.c
@@ -5,6 +5,7 @@
#include "apk_adb.h"
#include "apk_applet.h"
+#include "apk_tar.h"
struct conv_script {
struct list_head script_node;
diff --git a/src/app_convndx.c b/src/app_convndx.c
index 21015cb..f8f649e 100644
--- a/src/app_convndx.c
+++ b/src/app_convndx.c
@@ -4,17 +4,18 @@
#include "apk_adb.h"
#include "apk_applet.h"
+#include "apk_extract.h"
struct conv_ctx {
struct apk_ctx *ac;
struct adb_obj pkgs;
struct adb dbi;
- struct apk_sign_ctx sctx;
- int found;
+ struct apk_extract_ctx ectx;
};
-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;
@@ -29,41 +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(void *sctx, const struct apk_file_info *fi,
- struct apk_istream *is)
-{
- struct conv_ctx *ctx = sctx;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, fi, is);
- if (r <= 0) return r;
-
- 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_OR_NULL(is)) return is ? PTR_ERR(is) : -EINVAL;
-
- ctx->found = 0;
- apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(ctx->ac));
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx->sctx),
- load_apkindex, ctx, apk_ctx_get_id_cache(ctx->ac));
- apk_sign_ctx_free(&ctx->sctx);
- if (r >= 0 && ctx->found == 0) r = -APKE_V2NDX_FORMAT;
-
- return r;
+ if (IS_ERR(is)) return PTR_ERR(is);
+ 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_extract.c b/src/app_extract.c
index aa5d8aa..c2836da 100644
--- a/src/app_extract.c
+++ b/src/app_extract.c
@@ -16,21 +16,15 @@
#include "apk_applet.h"
#include "apk_print.h"
-#include "apk_adb.h"
-#include "apk_pathbuilder.h"
+#include "apk_extract.h"
struct extract_ctx {
const char *destination;
unsigned int extract_flags;
+ struct apk_extract_ctx ectx;
struct apk_ctx *ac;
- struct adb db;
int root_fd;
-
- struct adb_obj pkg, paths, path, files, file;
- unsigned int cur_path, cur_file;
-
- struct apk_pathbuilder pb;
};
@@ -62,22 +56,6 @@ static const struct apk_option_group optgroup_applet = {
.parse = option_parse_applet,
};
-static void apk_extract_acl(struct apk_file_info *fi, struct adb_obj *o, struct apk_id_cache *idc)
-{
- fi->mode = adb_ro_int(o, ADBI_ACL_MODE);
- fi->uid = apk_id_cache_resolve_uid(idc, adb_ro_blob(o, ADBI_ACL_USER), 65534);
- fi->gid = apk_id_cache_resolve_gid(idc, adb_ro_blob(o, ADBI_ACL_GROUP), 65534);
-}
-
-static const char *uvol_detect(struct apk_ctx *ac, const char *path)
-{
- if (!apk_ctx_get_uvol(ac)) return 0;
- if (strncmp(path, "uvol", 4) != 0) return 0;
- if (path[4] == 0) return path;
- if (path[4] == '/') return &path[5];
- return 0;
-}
-
static int uvol_run(struct apk_ctx *ac, char *action, const char *volname, char *arg1, char *arg2)
{
struct apk_out *out = &ac->out;
@@ -102,7 +80,7 @@ static int uvol_run(struct apk_ctx *ac, char *action, const char *volname, char
return 0;
}
-static int uvol_extract(struct apk_ctx *ac, const char *volname, char *arg1, off_t sz, struct apk_istream *is, struct apk_digest_ctx *dctx)
+static int uvol_extract(struct apk_ctx *ac, const char *volname, char *arg1, off_t sz, struct apk_istream *is)
{
struct apk_out *out = &ac->out;
struct apk_ostream *os;
@@ -123,7 +101,7 @@ static int uvol_extract(struct apk_ctx *ac, const char *volname, char *arg1, off
}
close(pipefds[0]);
os = apk_ostream_to_fd(pipefds[1]);
- apk_stream_copy(is, os, sz, 0, 0, dctx);
+ apk_stream_copy(is, os, sz, 0, 0, 0);
r = apk_ostream_close(os);
if (r != 0) {
if (r >= 0) r = -APKE_UVOL;
@@ -140,7 +118,7 @@ static int uvol_extract(struct apk_ctx *ac, const char *volname, char *arg1, off
return 0;
}
-static int apk_extract_volume(struct apk_ctx *ac, struct apk_file_info *fi, struct apk_istream *is, struct apk_digest_ctx *dctx)
+static int apk_extract_volume(struct apk_ctx *ac, const struct apk_file_info *fi, struct apk_istream *is)
{
char size[64];
int r;
@@ -148,203 +126,51 @@ static int apk_extract_volume(struct apk_ctx *ac, struct apk_file_info *fi, stru
snprintf(size, sizeof size, "%ju", fi->size);
r = uvol_run(ac, "create", fi->uvol_name, size, "ro");
if (r != 0) return r;
- return uvol_extract(ac, fi->uvol_name, size, fi->size, is, dctx);
-}
-
-static int apk_extract_file(struct extract_ctx *ctx, off_t sz, struct apk_istream *is)
-{
- struct apk_ctx *ac = ctx->ac;
- struct apk_out *out = &ac->out;
- const char *path_name = apk_pathbuilder_cstr(&ctx->pb);
- struct apk_file_info fi = {
- .name = path_name,
- .uvol_name = uvol_detect(ac, path_name),
- .size = adb_ro_int(&ctx->file, ADBI_FI_SIZE),
- .mtime = adb_ro_int(&ctx->file, ADBI_FI_MTIME),
- };
- struct adb_obj acl;
- struct apk_digest_ctx dctx;
- struct apk_digest d;
- apk_blob_t target;
- int r;
- apk_extract_acl(&fi, adb_ro_obj(&ctx->file, ADBI_FI_ACL, &acl), apk_ctx_get_id_cache(ctx->ac));
-
- target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
- if (!APK_BLOB_IS_NULL(target)) {
- char *target_path;
- uint16_t mode;
-
- if (target.len < 2) return -APKE_ADB_SCHEMA;
- mode = *(uint16_t*)target.ptr;
- target.ptr += 2;
- target.len -= 2;
- switch (mode) {
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- if (target.len != sizeof(uint64_t)) return -APKE_ADB_SCHEMA;
- struct unaligned64 {
- uint64_t value;
- } __attribute__((packed));
- fi.device = ((struct unaligned64 *)target.ptr)->value;
- break;
- case S_IFLNK:
- target_path = alloca(target.len + 1);
- memcpy(target_path, target.ptr, target.len);
- target_path[target.len] = 0;
- fi.link_target = target_path;
- break;
- default:
- return -APKE_ADB_SCHEMA;
- }
- fi.mode |= mode;
- return apk_archive_entry_extract(
- ctx->root_fd, &fi, 0, 0, is, 0, 0, 0,
- ctx->extract_flags, out);
- }
-
- apk_digest_from_blob(&fi.digest, adb_ro_blob(&ctx->file, ADBI_FI_HASHES));
- if (fi.digest.alg == APK_DIGEST_NONE) return -APKE_ADB_SCHEMA;
-
- fi.mode |= S_IFREG;
- apk_digest_ctx_init(&dctx, fi.digest.alg);
- if (fi.uvol_name) {
- r = apk_extract_volume(ac, &fi, is, &dctx);
- } else {
- r = apk_archive_entry_extract(
- ctx->root_fd, &fi, 0, 0, is, 0, 0, &dctx,
- ctx->extract_flags, out);
- }
- apk_digest_ctx_final(&dctx, &d);
- apk_digest_ctx_free(&dctx);
- if (r == 0 && apk_digest_cmp(&fi.digest, &d) != 0)
- r = -APKE_FILE_INTEGRITY;
- if (fi.uvol_name) {
- if (r == 0)
- r = uvol_run(ac, "up", fi.uvol_name, 0, 0);
- else
- uvol_run(ac, "remove", fi.uvol_name, 0, 0);
- } else if (r != 0)
- unlinkat(ctx->root_fd, fi.name, 0);
+ r = uvol_extract(ac, fi->uvol_name, size, fi->size, is);
+ if (r == 0) r = uvol_run(ac, "up", fi->uvol_name, 0, 0);
+ if (r != 0) uvol_run(ac, "remove", fi->uvol_name, 0, 0);
return r;
}
-static int apk_extract_directory(struct extract_ctx *ctx)
-{
- struct apk_ctx *ac = ctx->ac;
- struct apk_out *out = &ac->out;
- struct apk_file_info fi = {
- .name = apk_pathbuilder_cstr(&ctx->pb),
- };
- struct adb_obj acl;
-
- if (uvol_detect(ac, fi.name)) return 0;
-
- apk_extract_acl(&fi, adb_ro_obj(&ctx->path, ADBI_DI_ACL, &acl), apk_ctx_get_id_cache(ctx->ac));
- fi.mode |= S_IFDIR;
-
- return apk_archive_entry_extract(
- ctx->root_fd, &fi, 0, 0, 0, 0, 0, 0,
- ctx->extract_flags, out);
-}
-
-static int apk_extract_next_file(struct extract_ctx *ctx)
+static int extract_v3_meta(struct apk_extract_ctx *ectx, struct adb_obj *pkg)
{
- apk_blob_t target;
- int r;
-
- if (!ctx->cur_path) {
- // one time init
- ctx->cur_path = ADBI_FIRST;
- ctx->cur_file = 0;
- adb_r_rootobj(&ctx->db, &ctx->pkg, &schema_package);
- adb_ro_obj(&ctx->pkg, ADBI_PKG_PATHS, &ctx->paths);
- adb_ro_obj(&ctx->paths, ctx->cur_path, &ctx->path);
- adb_ro_obj(&ctx->path, ADBI_DI_FILES, &ctx->files);
- }
-
- do {
- ctx->cur_file++;
- while (ctx->cur_file > adb_ra_num(&ctx->files)) {
- ctx->cur_path++;
- ctx->cur_file = ADBI_FIRST;
- if (ctx->cur_path > adb_ra_num(&ctx->paths)) return 1;
- adb_ro_obj(&ctx->paths, ctx->cur_path, &ctx->path);
- apk_pathbuilder_setb(&ctx->pb, adb_ro_blob(&ctx->path, ADBI_DI_NAME));
- adb_ro_obj(&ctx->path, ADBI_DI_FILES, &ctx->files);
- r = apk_extract_directory(ctx);
- if (r != 0) return r;
- }
- adb_ro_obj(&ctx->files, ctx->cur_file, &ctx->file);
- apk_pathbuilder_setb(&ctx->pb, adb_ro_blob(&ctx->path, ADBI_DI_NAME));
- apk_pathbuilder_pushb(&ctx->pb, adb_ro_blob(&ctx->file, ADBI_FI_NAME));
- target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
- if (adb_ro_int(&ctx->file, ADBI_FI_SIZE) != 0 &&
- APK_BLOB_IS_NULL(target)) {
- return 0;
- }
- r = apk_extract_file(ctx, 0, 0);
- if (r != 0) return r;
- } while (1);
+ return 0;
}
-static int apk_extract_data_block(struct adb *db, struct adb_block *b, struct apk_istream *is)
+static int extract_file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
{
- struct extract_ctx *ctx = container_of(db, struct extract_ctx, db);
- struct adb_data_package *hdr;
- size_t sz = adb_block_length(b);
+ struct extract_ctx *ctx = container_of(ectx, struct extract_ctx, ectx);
+ struct apk_out *out = &ctx->ac->out;
int r;
- if (adb_block_type(b) != ADB_BLOCK_DATA) return 0;
+ apk_dbg2(out, "%s", fi->name);
- r = apk_extract_next_file(ctx);
- if (r != 0) {
- if (r > 0) r = -APKE_ADB_BLOCK;
- return r;
- }
-
- hdr = apk_istream_get(is, sizeof *hdr);
- sz -= sizeof *hdr;
- if (IS_ERR(hdr)) return PTR_ERR(hdr);
-
- if (hdr->path_idx != ctx->cur_path ||
- hdr->file_idx != ctx->cur_file ||
- sz != adb_ro_int(&ctx->file, ADBI_FI_SIZE)) {
- // got data for some unexpected file
- return -APKE_ADB_BLOCK;
- }
-
- return apk_extract_file(ctx, sz, is);
-}
-
-static int apk_extract_pkg(struct extract_ctx *ctx, const char *fn)
-{
- struct apk_ctx *ac = ctx->ac;
- struct apk_trust *trust = apk_ctx_get_trust(ac);
- int r;
-
- r = adb_m_process(&ctx->db,
- adb_decompress(apk_istream_from_fd_url(AT_FDCWD, fn, apk_ctx_since(ac, 0)), 0),
- ADB_SCHEMA_PACKAGE, trust, apk_extract_data_block);
- if (r == 0) {
- r = apk_extract_next_file(ctx);
- if (r == 0) r = -APKE_ADB_BLOCK;
- if (r == 1) r = 0;
+ if (fi->uvol_name && is) {
+ r = apk_extract_volume(ectx->ac, fi, is);
+ } else {
+ r = apk_extract_file(ctx->root_fd, fi, 0, 0, is, 0, 0, 0,
+ ctx->extract_flags, &ectx->ac->out);
}
- adb_free(&ctx->db);
+ if (is) r = apk_istream_close_error(is, r);
return r;
}
+static const struct apk_extract_ops extract_ops = {
+ .v2meta = apk_extract_v2_meta,
+ .v3meta = extract_v3_meta,
+ .file = extract_file,
+};
+
static int extract_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct extract_ctx *ctx = pctx;
struct apk_out *out = &ac->out;
char **parg;
- int r;
+ int r = 0;
ctx->ac = ac;
- ctx->extract_flags |= APK_EXTRACTF_NO_OVERWRITE;
+ if (!(ac->force & APK_FORCE_OVERWRITE)) ctx->extract_flags |= APK_EXTRACTF_NO_OVERWRITE;
if (!ctx->destination) ctx->destination = ".";
ctx->root_fd = openat(AT_FDCWD, ctx->destination, O_RDONLY);
if (ctx->root_fd < 0) {
@@ -354,9 +180,10 @@ static int extract_main(void *pctx, struct apk_ctx *ac, struct apk_string_array
return r;
}
+ apk_extract_init(&ctx->ectx, ac, &extract_ops);
foreach_array_item(parg, args) {
apk_out(out, "Extracting %s...", *parg);
- r = apk_extract_pkg(ctx, *parg);
+ r = apk_extract(&ctx->ectx, apk_istream_from_fd_url(AT_FDCWD, *parg, apk_ctx_since(ac, 0)));
if (r != 0) {
apk_err(out, "%s: %s", *parg, apk_error_str(r));
break;
@@ -366,12 +193,12 @@ static int extract_main(void *pctx, struct apk_ctx *ac, struct apk_string_array
return r;
}
-static struct apk_applet apk_extract = {
+static struct apk_applet app_extract = {
.name = "extract",
.context_size = sizeof(struct extract_ctx),
.optgroups = { &optgroup_global, &optgroup_applet },
.main = extract_main,
};
-APK_DEFINE_APPLET(apk_extract);
+APK_DEFINE_APPLET(app_extract);
diff --git a/src/app_fetch.c b/src/app_fetch.c
index c54a8e0..556ec49 100644
--- a/src/app_fetch.c
+++ b/src/app_fetch.c
@@ -171,8 +171,8 @@ static int fetch_package(apk_hash_item item, void *pctx)
}
is = apk_istream_from_fd_url(urlfd, url, apk_db_url_since(db, 0));
- if (IS_ERR_OR_NULL(is)) {
- r = PTR_ERR(is) ?: -EIO;
+ if (IS_ERR(is)) {
+ r = PTR_ERR(is);
goto err;
}
@@ -219,7 +219,7 @@ static void mark_name_flags(struct apk_database *db, const char *match, struct a
.result_mask = APK_DEPMASK_ANY,
};
- if (!IS_ERR_OR_NULL(name)) {
+ if (name) {
name->auto_select_virtual = 1;
apk_deps_add(&ctx->world, &dep);
} else {
diff --git a/src/app_index.c b/src/app_index.c
index cc37fa4..741bcf9 100644
--- a/src/app_index.c
+++ b/src/app_index.c
@@ -16,6 +16,7 @@
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_print.h"
+#include "apk_tar.h"
#define APK_INDEXF_NO_WARNINGS 0x0001
@@ -30,7 +31,6 @@ struct index_ctx {
const char *description;
const char *rewrite_arch;
time_t index_mtime;
- int method;
unsigned short index_flags;
};
@@ -110,7 +110,7 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
struct apk_out *out = &ac->out;
struct apk_database *db = ac->db;
struct counts counts = { .out = out };
- struct apk_ostream *os;
+ struct apk_ostream *os, *counter;
struct apk_file_info fi;
int total, r, found, newpkgs = 0, errors = 0;
struct index_ctx *ictx = (struct index_ctx *) ctx;
@@ -126,9 +126,6 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
return -1;
}
- if (ictx->method == 0)
- ictx->method = APK_SIGN_GENERATE;
-
if ((r = index_read_file(db, ictx)) < 0) {
apk_err(out, "%s: %s", ictx->index, apk_error_str(r));
return r;
@@ -185,9 +182,7 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
} while (0);
if (!found) {
- struct apk_sign_ctx sctx;
- apk_sign_ctx_init(&sctx, ictx->method, NULL, apk_ctx_get_trust(ac));
- r = apk_pkg_read(db, *parg, &sctx, &pkg);
+ r = apk_pkg_read(db, *parg, &pkg);
if (r < 0) {
apk_err(out, "%s: %s", *parg, apk_error_str(r));
errors++;
@@ -195,7 +190,6 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
newpkgs++;
if (rewrite_arch) pkg->arch = rewrite_arch;
}
- apk_sign_ctx_free(&sctx);
}
}
if (errors)
@@ -205,37 +199,31 @@ static int index_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *ar
os = apk_ostream_to_file(AT_FDCWD, ictx->output, 0644);
else
os = apk_ostream_to_fd(STDOUT_FILENO);
- if (IS_ERR_OR_NULL(os)) return -1;
-
- if (ictx->method == APK_SIGN_GENERATE) {
- struct apk_ostream *counter;
-
- memset(&fi, 0, sizeof(fi));
- fi.mode = 0644 | S_IFREG;
- fi.name = "APKINDEX";
- counter = apk_ostream_counter(&fi.size);
- r = apk_db_index_write(db, counter);
- apk_ostream_close(counter);
-
- if (r >= 0) {
- os = apk_ostream_gzip(os);
- if (ictx->description != NULL) {
- struct apk_file_info fi_desc;
- memset(&fi_desc, 0, sizeof(fi));
- fi_desc.mode = 0644 | S_IFREG;
- fi_desc.name = "DESCRIPTION";
- fi_desc.size = strlen(ictx->description);
- apk_tar_write_entry(os, &fi_desc, ictx->description);
- }
-
- apk_tar_write_entry(os, &fi, NULL);
- r = apk_db_index_write(db, os);
- apk_tar_write_padding(os, &fi);
-
- apk_tar_write_entry(os, NULL, NULL);
+ if (IS_ERR(os)) return PTR_ERR(os);
+
+ memset(&fi, 0, sizeof(fi));
+ fi.mode = 0644 | S_IFREG;
+ fi.name = "APKINDEX";
+ counter = apk_ostream_counter(&fi.size);
+ r = apk_db_index_write(db, counter);
+ apk_ostream_close(counter);
+
+ if (r >= 0) {
+ os = apk_ostream_gzip(os);
+ if (ictx->description != NULL) {
+ struct apk_file_info fi_desc;
+ memset(&fi_desc, 0, sizeof(fi));
+ fi_desc.mode = 0644 | S_IFREG;
+ fi_desc.name = "DESCRIPTION";
+ fi_desc.size = strlen(ictx->description);
+ apk_tar_write_entry(os, &fi_desc, ictx->description);
}
- } else {
+
+ apk_tar_write_entry(os, &fi, NULL);
r = apk_db_index_write(db, os);
+ apk_tar_write_padding(os, &fi);
+
+ apk_tar_write_entry(os, NULL, NULL);
}
apk_ostream_close(os);
diff --git a/src/app_info.c b/src/app_info.c
index beb32d9..509798d 100644
--- a/src/app_info.c
+++ b/src/app_info.c
@@ -132,7 +132,7 @@ static void info_who_owns(struct info_ctx *ctx, struct apk_database *db,
}
if (verbosity < 1 && deps->num != 0) {
os = apk_ostream_to_fd(STDOUT_FILENO);
- if (!IS_ERR_OR_NULL(os)) {
+ if (!IS_ERR(os)) {
apk_deps_write(db, deps, os, APK_BLOB_PTR_LEN(" ", 1));
apk_ostream_write(os, "\n", 1);
apk_ostream_close(os);
diff --git a/src/app_list.c b/src/app_list.c
index 620c3ad..5e14fe1 100644
--- a/src/app_list.c
+++ b/src/app_list.c
@@ -179,7 +179,8 @@ static void print_result(struct apk_database *db, const char *match, struct apk_
OPT(OPT_LIST_origin, APK_OPT_SH("o") "origin") \
OPT(OPT_LIST_orphaned, APK_OPT_SH("O") "orphaned") \
OPT(OPT_LIST_providers, APK_OPT_SH("P") "providers") \
- OPT(OPT_LIST_upgradeable, APK_OPT_SH("u") "upgradeable")
+ OPT(OPT_LIST_upgradable, APK_OPT_SH("u") "upgradable") \
+ OPT(OPT_LIST_upgradeable, "upgradeable")
APK_OPT_APPLET(option_desc, LIST_OPTIONS);
@@ -208,6 +209,7 @@ static int option_parse_applet(void *pctx, struct apk_ctx *ac, int opt, const ch
case OPT_LIST_providers:
ctx->match_providers = 1;
break;
+ case OPT_LIST_upgradable:
case OPT_LIST_upgradeable:
ctx->available = 1;
ctx->orphaned = 0;
diff --git a/src/app_manifest.c b/src/app_manifest.c
index 86164f6..5c2e085 100644
--- a/src/app_manifest.c
+++ b/src/app_manifest.c
@@ -14,8 +14,11 @@
#include "apk_defines.h"
#include "apk_applet.h"
#include "apk_database.h"
+#include "apk_extract.h"
#include "apk_version.h"
#include "apk_print.h"
+#include "apk_adb.h"
+#include "apk_pathbuilder.h"
/* TODO: support package files as well as generating manifest from the installed DB. */
static char *csum_types[APK_CHECKSUM_SHA1 + 1] = {
@@ -60,62 +63,91 @@ static void process_package(struct apk_database *db, struct apk_package *pkg)
struct manifest_file_ctx {
struct apk_out *out;
- struct apk_sign_ctx *sctx;
+ struct apk_extract_ctx ectx;
const char *prefix1, *prefix2;
};
-static int read_file_entry(void *ctx, const struct apk_file_info *ae, 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 = ctx;
+ 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);
- int r;
-
- r = apk_sign_ctx_verify_tar(mctx->sctx, ae, is);
- if (r != 0)
- return r;
-
- if (!mctx->sctx->data_started)
- return 0;
- if ((ae->mode & S_IFMT) != S_IFREG)
- return 0;
+ if ((fi->mode & S_IFMT) != S_IFREG) return 0;
memset(csum_buf, '\0', sizeof(csum_buf));
- apk_blob_push_hexdump(&csum_blob, APK_DIGEST_BLOB(ae->digest));
+ apk_blob_push_hexdump(&csum_blob, APK_DIGEST_BLOB(fi->digest));
apk_out(out, "%s%s%s:%s %s",
mctx->prefix1, mctx->prefix2,
- apk_digest_alg_str(ae->digest.alg), csum_buf,
- ae->name);
+ apk_digest_alg_str(fi->digest.alg), csum_buf,
+ fi->name);
return 0;
}
+static int process_v3_meta(struct apk_extract_ctx *ectx, struct adb_obj *pkg)
+{
+ struct manifest_file_ctx *mctx = container_of(ectx, struct manifest_file_ctx, ectx);
+ struct apk_out *out = mctx->out;
+ struct adb_obj paths, path, files, file;
+ struct apk_digest digest;
+ struct apk_pathbuilder pb;
+ char buf[APK_DIGEST_MAX_LENGTH*2+1];
+ apk_blob_t hex;
+ int i, j;
+
+ adb_ro_obj(pkg, ADBI_PKG_PATHS, &paths);
+
+ for (i = ADBI_FIRST; i <= adb_ra_num(&paths); i++) {
+ adb_ro_obj(&paths, i, &path);
+ adb_ro_obj(&path, ADBI_DI_FILES, &files);
+ apk_pathbuilder_setb(&pb, adb_ro_blob(&path, ADBI_DI_NAME));
+
+ for (j = ADBI_FIRST; j <= adb_ra_num(&files); j++) {
+ adb_ro_obj(&files, j, &file);
+ apk_pathbuilder_pushb(&pb, adb_ro_blob(&file, ADBI_FI_NAME));
+ apk_digest_from_blob(&digest, adb_ro_blob(&file, ADBI_FI_HASHES));
+
+ hex = APK_BLOB_BUF(buf);
+ apk_blob_push_hexdump(&hex, APK_DIGEST_BLOB(digest));
+ apk_blob_push_blob(&hex, APK_BLOB_STRLIT("\0"));
+
+ apk_out(out, "%s%s%s:%s %s",
+ mctx->prefix1, mctx->prefix2,
+ apk_digest_alg_str(digest.alg), buf,
+ apk_pathbuilder_cstr(&pb));
+ apk_pathbuilder_pop(&pb);
+ }
+ }
+
+ return -ECANCELED;
+}
+
+static const struct apk_extract_ops extract_manifest_ops = {
+ .v2meta = apk_extract_v2_meta,
+ .v3meta = process_v3_meta,
+ .file = process_pkg_file,
+};
+
static void process_file(struct apk_database *db, const char *match)
{
- struct apk_id_cache *idc = apk_ctx_get_id_cache(db->ctx);
struct apk_out *out = &db->ctx->out;
- struct apk_sign_ctx sctx;
struct manifest_file_ctx ctx = {
.out = out,
- .sctx = &sctx,
.prefix1 = "",
.prefix2 = "",
};
int r;
+ apk_extract_init(&ctx.ectx, db->ctx, &extract_manifest_ops);
if (apk_out_verbosity(out) > 1) {
ctx.prefix1 = match;
ctx.prefix2 = ": ";
}
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, match), apk_sign_ctx_mpart_cb, &sctx),
- read_file_entry, &ctx, idc);
- apk_sign_ctx_free(&sctx);
+ r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, match));
if (r < 0) apk_err(out, "%s: %s", match, apk_error_str(r));
}
diff --git a/src/app_mkndx.c b/src/app_mkndx.c
index 3316de5..a68e18b 100644
--- a/src/app_mkndx.c
+++ b/src/app_mkndx.c
@@ -18,6 +18,7 @@
#include "apk_adb.h"
#include "apk_applet.h"
#include "apk_database.h"
+#include "apk_extract.h"
#include "apk_print.h"
struct mkndx_ctx {
@@ -31,7 +32,7 @@ struct mkndx_ctx {
struct adb_obj pkgs;
time_t index_mtime;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
size_t file_size;
};
@@ -83,7 +84,7 @@ static int cmpfield(const void *pa, const void *pb)
return apk_blob_sort(a->str, b->str);
}
-static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, size_t file_size, struct apk_sign_ctx *sctx, apk_blob_t rewrite_arch)
+static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, size_t file_size, struct apk_extract_ctx *ectx, apk_blob_t rewrite_arch)
{
static struct field fields[] = {
FIELD("arch", ADBI_PI_ARCH),
@@ -118,9 +119,9 @@ static adb_val_t mkndx_read_v2_pkginfo(struct adb *db, struct apk_istream *is, s
adb_wo_alloca(&deps[2], &schema_dependency_array, db);
while ((r = apk_istream_get_delim(is, token, &line)) == 0) {
- if (sctx) apk_sign_ctx_parse_pkginfo_line(sctx, line);
if (line.len < 1 || line.ptr[0] == '#') continue;
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &k, &v)) continue;
+ apk_extract_v2_control(ectx, k, v);
key.str = k;
f = bsearch(&key, fields, ARRAY_SIZE(fields), sizeof(fields[0]), cmpfield);
@@ -163,33 +164,37 @@ 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(void *pctx, 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 = pctx;
- adb_val_t o;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
- if (r <= 0) return r;
- if (ctx->sctx.control_verified) return -ECANCELED;
- if (!ctx->sctx.control_started || ctx->sctx.data_started) return 0;
-
- if (strcmp(ae->name, ".PKGINFO") == 0) {
- o = adb_wa_append(
- &ctx->pkgs,
- mkndx_read_v2_pkginfo(
- &ctx->db, is, ctx->file_size, &ctx->sctx,
- ctx->rewrite_arch));
- if (ADB_IS_ERROR(o)) return -ADB_VAL_VALUE(o);
- }
+ struct mkndx_ctx *ctx = container_of(ectx, struct mkndx_ctx, ectx);
+ 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 int mkndx_parse_v3meta(struct apk_extract_ctx *ectx, struct adb_obj *pkg)
+{
+ struct mkndx_ctx *ctx = container_of(ectx, struct mkndx_ctx, ectx);
+ struct adb *db = pkg->db;
+
+ adb_val_t o = adb_wa_append(&ctx->pkgs,
+ adb_w_copy(&ctx->db, db, adb_ro_val(pkg, ADBI_PKG_PKGINFO)));
+ 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,
+ .v3meta = mkndx_parse_v3meta,
+};
+
static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
- struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
struct apk_trust *trust = apk_ctx_get_trust(ac);
struct adb odb, tmpdb;
struct adb_obj oroot, opkgs, ndx, tmpl;
@@ -205,6 +210,8 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
return -1;
}
+ apk_extract_init(&ctx->ectx, ac, &extract_ndxinfo_ops);
+
adb_init(&odb);
adb_w_init_tmp(&tmpdb, 200);
adb_wo_alloca(&tmpl, &schema_pkginfo, &tmpdb);
@@ -278,12 +285,8 @@ static int mkndx_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
}
if (!found) {
do_file:
- apk_sign_ctx_init(&ctx->sctx, APK_SIGN_VERIFY, NULL, trust);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg), apk_sign_ctx_mpart_cb, &ctx->sctx),
- mkndx_parse_v2_tar, ctx, idc);
- apk_sign_ctx_free(&ctx->sctx);
- if (r < 0 && r != -ECANCELED) goto err_pkg;
+ r = apk_extract(&ctx->ectx, apk_istream_from_file(AT_FDCWD, *parg));
+ if (r < 0) goto err_pkg;
newpkgs++;
}
}
diff --git a/src/app_mkpkg.c b/src/app_mkpkg.c
index 00f467c..6944599 100644
--- a/src/app_mkpkg.c
+++ b/src/app_mkpkg.c
@@ -20,6 +20,7 @@
#include "apk_applet.h"
#include "apk_database.h"
#include "apk_pathbuilder.h"
+#include "apk_extract.h"
#include "apk_print.h"
#define BLOCK_SIZE 4096
@@ -29,16 +30,21 @@ struct mkpkg_ctx {
const char *files_dir, *output;
struct adb db;
struct adb_obj paths, *files;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
apk_blob_t info[ADBI_PI_MAX];
+ apk_blob_t script[ADBI_SCRPT_MAX];
+ struct apk_string_array *triggers;
uint64_t installed_size;
struct apk_pathbuilder pb;
+ unsigned has_scripts : 1;
};
#define MKPKG_OPTIONS(OPT) \
OPT(OPT_MKPKG_files, APK_OPT_ARG APK_OPT_SH("f") "files") \
OPT(OPT_MKPKG_info, APK_OPT_ARG APK_OPT_SH("i") "info") \
OPT(OPT_MKPKG_output, APK_OPT_ARG APK_OPT_SH("o") "output") \
+ OPT(OPT_MKPKG_script, APK_OPT_ARG APK_OPT_SH("s") "script") \
+ OPT(OPT_MKPKG_trigger, APK_OPT_ARG APK_OPT_SH("t") "trigger") \
APK_OPT_APPLET(option_desc, MKPKG_OPTIONS);
@@ -65,6 +71,23 @@ static int option_parse_applet(void *ctx, struct apk_ctx *ac, int optch, const c
case OPT_MKPKG_output:
ictx->output = optarg;
break;
+ case OPT_MKPKG_script:
+ apk_blob_split(APK_BLOB_STR(optarg), APK_BLOB_STRLIT(":"), &l, &r);
+ i = adb_s_field_by_name_blob(&schema_scripts, l);
+ if (i == APK_SCRIPT_INVALID) {
+ apk_err(out, "invalid script type: " BLOB_FMT, BLOB_PRINTF(l));
+ return -EINVAL;
+ }
+ ictx->script[i] = apk_blob_from_file(AT_FDCWD, r.ptr);
+ if (APK_BLOB_IS_NULL(ictx->script[i])) {
+ apk_err(out, "failed to load script: " BLOB_FMT, BLOB_PRINTF(r));
+ return -ENOENT;
+ }
+ ictx->has_scripts = 1;
+ break;
+ case OPT_MKPKG_trigger:
+ *apk_string_array_add(&ictx->triggers) = (char*) optarg;
+ break;
default:
return -ENOTSUP;
}
@@ -161,8 +184,7 @@ static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry)
return r;
default:
apk_pathbuilder_push(&ctx->pb, entry);
- apk_out(out, "%s: special file ignored",
- apk_pathbuilder_cstr(&ctx->pb), entry);
+ apk_out(out, "%s: special file ignored", apk_pathbuilder_cstr(&ctx->pb));
apk_pathbuilder_pop(&ctx->pb);
return 0;
}
@@ -251,6 +273,20 @@ static int mkpkg_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *a
adb_wo_int(&pkgi, ADBI_PI_INSTALLED_SIZE, ctx->installed_size);
adb_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkgi);
adb_wo_obj(&pkg, ADBI_PKG_PATHS, &ctx->paths);
+ if (ctx->has_scripts) {
+ struct adb_obj scripts;
+ adb_wo_alloca(&scripts, &schema_scripts, &ctx->db);
+ for (i = ADBI_FIRST; i < APK_SCRIPT_MAX; i++)
+ adb_wo_blob(&scripts, i, ctx->script[i]);
+ adb_wo_obj(&pkg, ADBI_PKG_SCRIPTS, &scripts);
+ }
+ if (ctx->triggers) {
+ struct adb_obj triggers;
+ adb_wo_alloca(&triggers, &schema_string_array, &ctx->db);
+ for (i = 0; i < ctx->triggers->num; i++)
+ adb_wa_append_fromstring(&triggers, APK_BLOB_STR(ctx->triggers->item[i]));
+ adb_wo_obj(&pkg, ADBI_PKG_TRIGGERS, &triggers);
+ }
adb_w_rootobj(&pkg);
// re-read since object resets
diff --git a/src/app_verify.c b/src/app_verify.c
index adfe0ec..fd1a148 100644
--- a/src/app_verify.c
+++ b/src/app_verify.c
@@ -12,38 +12,26 @@
#include <unistd.h>
#include "apk_applet.h"
-#include "apk_database.h"
#include "apk_print.h"
+#include "apk_extract.h"
static int verify_main(void *ctx, struct apk_ctx *ac, struct apk_string_array *args)
{
struct apk_out *out = &ac->out;
- struct apk_sign_ctx sctx;
- struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
- struct apk_trust *trust = apk_ctx_get_trust(ac);
+ struct apk_extract_ctx ectx;
char **parg;
- int r, ok, rc = 0;
+ int r, rc = 0;
- trust->allow_untrusted = 1;
+ apk_extract_init(&ectx, ac, 0);
foreach_array_item(parg, args) {
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, trust);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, *parg),
- apk_sign_ctx_mpart_cb, &sctx),
- apk_sign_ctx_verify_tar, &sctx, idc);
- ok = sctx.control_verified && sctx.data_verified;
+ r = apk_extract(&ectx, apk_istream_from_file(AT_FDCWD, *parg));
if (apk_out_verbosity(out) >= 1)
- apk_msg(out, "%s: %d - %s", *parg, r,
- r < 0 ? apk_error_str(r) :
- ok ? "OK" :
- !sctx.control_verified ? "UNTRUSTED" : "FAILED");
- else if (!ok)
+ apk_msg(out, "%s: %s", *parg,
+ r < 0 ? apk_error_str(r) : "OK");
+ else if (r < 0)
apk_out(out, "%s", *parg);
- if (!ok)
- rc++;
-
- apk_sign_ctx_free(&sctx);
+ if (r < 0) rc++;
}
return rc;
diff --git a/src/blob.c b/src/blob.c
index 32cd92e..2052e8e 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -383,27 +383,6 @@ void apk_blob_push_csum(apk_blob_t *to, struct apk_checksum *csum)
}
}
-void apk_blob_push_hexdump(apk_blob_t *to, apk_blob_t binary)
-{
- char *d;
- int i;
-
- if (unlikely(APK_BLOB_IS_NULL(*to)))
- return;
-
- if (unlikely(to->len < binary.len * 2)) {
- *to = APK_BLOB_NULL;
- return;
- }
-
- for (i = 0, d = to->ptr; i < binary.len; i++) {
- *(d++) = xd[(binary.ptr[i] >> 4) & 0xf];
- *(d++) = xd[binary.ptr[i] & 0xf];
- }
- to->ptr = d;
- to->len -= binary.len * 2;
-}
-
static const char b64encode[] =
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
@@ -440,6 +419,47 @@ void apk_blob_push_base64(apk_blob_t *to, apk_blob_t binary)
to->len -= needed;
}
+void apk_blob_push_hexdump(apk_blob_t *to, apk_blob_t binary)
+{
+ char *d;
+ int i;
+
+ if (unlikely(APK_BLOB_IS_NULL(*to)))
+ return;
+
+ if (unlikely(to->len < binary.len * 2)) {
+ *to = APK_BLOB_NULL;
+ return;
+ }
+
+ for (i = 0, d = to->ptr; i < binary.len; i++) {
+ *(d++) = xd[(binary.ptr[i] >> 4) & 0xf];
+ *(d++) = xd[binary.ptr[i] & 0xf];
+ }
+ to->ptr = d;
+ to->len -= binary.len * 2;
+}
+
+void apk_blob_push_fmt(apk_blob_t *to, const char *fmt, ...)
+{
+ va_list va;
+ int n;
+
+ if (unlikely(APK_BLOB_IS_NULL(*to)))
+ return;
+
+ va_start(va, fmt);
+ n = vsnprintf(to->ptr, to->len, fmt, va);
+ va_end(va);
+
+ if (n >= 0 && n <= to->len) {
+ to->ptr += n;
+ to->len -= n;
+ } else {
+ *to = APK_BLOB_NULL;
+ }
+}
+
void apk_blob_pull_char(apk_blob_t *b, int expected)
{
if (unlikely(APK_BLOB_IS_NULL(*b)))
diff --git a/src/commit.c b/src/commit.c
index 640c135..d53ae8a 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -351,7 +351,7 @@ int apk_solver_commit_changeset(struct apk_database *db,
all_done:
apk_dependency_array_copy(&db->world, world);
- apk_db_write_config(db);
+ if (apk_db_write_config(db) != 0) errors++;
run_commit_hooks(db, POST_COMMIT_HOOK);
if (!db->performing_self_upgrade) {
diff --git a/src/common.c b/src/common.c
index 14a56a3..580e6d5 100644
--- a/src/common.c
+++ b/src/common.c
@@ -40,3 +40,18 @@ void *apk_array_resize(void *array, size_t new_size, size_t elem_size)
return tmp;
}
+
+time_t apk_get_build_time(void)
+{
+ static int initialized = 0;
+ static time_t timestamp = 0;
+ char *source_date_epoch;
+
+ if (initialized) return timestamp;
+ source_date_epoch = getenv("SOURCE_DATE_EPOCH");
+ if (source_date_epoch && *source_date_epoch)
+ timestamp = strtoull(source_date_epoch, NULL, 10);
+ else timestamp = time(NULL);
+ initialized = 1;
+ return timestamp;
+}
diff --git a/src/context.c b/src/context.c
index 7020b25..ea3ae0b 100644
--- a/src/context.c
+++ b/src/context.c
@@ -16,7 +16,7 @@ void apk_ctx_init(struct apk_ctx *ac)
{
memset(ac, 0, sizeof *ac);
apk_string_array_init(&ac->repository_list);
- apk_string_array_init(&ac->private_keys);
+ apk_trust_init(&ac->trust);
apk_out_reset(&ac->out);
ac->out.out = stdout;
ac->out.err = stderr;
@@ -28,7 +28,6 @@ void apk_ctx_free(struct apk_ctx *ac)
apk_id_cache_free(&ac->id_cache);
apk_trust_free(&ac->trust);
apk_string_array_free(&ac->repository_list);
- apk_string_array_free(&ac->private_keys);
if (ac->out.log) fclose(ac->out.log);
}
@@ -39,6 +38,7 @@ int apk_ctx_prepare(struct apk_ctx *ac)
ac->open_flags &= ~(APK_OPENF_CREATE | APK_OPENF_WRITE);
ac->open_flags |= APK_OPENF_READ;
}
+ if (ac->flags & APK_ALLOW_UNTRUSTED) ac->trust.allow_untrusted = 1;
if (!ac->cache_dir) ac->cache_dir = "etc/apk/cache";
if (!ac->keys_dir) ac->keys_dir = "etc/apk/keys";
if (!ac->root) ac->root = "/";
@@ -75,12 +75,10 @@ int apk_ctx_prepare(struct apk_ctx *ac)
struct apk_trust *apk_ctx_get_trust(struct apk_ctx *ac)
{
- if (!ac->trust.initialized) {
- int r = apk_trust_init(&ac->trust,
- openat(ac->root_fd, ac->keys_dir, O_RDONLY | O_CLOEXEC),
- ac->private_keys);
- if (r) return ERR_PTR(r);
- ac->trust.allow_untrusted = !!(ac->flags & APK_ALLOW_UNTRUSTED);
+ if (!ac->trust.keys_loaded) {
+ int r = apk_trust_load_keys(&ac->trust,
+ openat(ac->root_fd, ac->keys_dir, O_RDONLY | O_CLOEXEC));
+ if (r != 0) apk_err(&ac->out, "Unable to load trust keys: %s", apk_error_str(r));
}
return &ac->trust;
}
diff --git a/src/database.c b/src/database.c
index 10e9776..f64d706 100644
--- a/src/database.c
+++ b/src/database.c
@@ -32,9 +32,10 @@
#include "apk_package.h"
#include "apk_database.h"
#include "apk_applet.h"
-#include "apk_archive.h"
+#include "apk_extract.h"
#include "apk_print.h"
#include "apk_openssl.h"
+#include "apk_tar.h"
static const apk_spn_match_def apk_spn_repo_separators = {
[1] = (1<<1) /* tab */,
@@ -70,7 +71,7 @@ struct install_ctx {
struct apk_db_dir_instance *diri;
struct apk_checksum data_csum;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
apk_progress_cb cb;
void *cb_ctx;
@@ -621,7 +622,7 @@ int apk_repo_format_item(struct apk_database *db, struct apk_repository *repo, s
}
int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
- struct apk_package *pkg, int verify, int autoupdate,
+ struct apk_package *pkg, int autoupdate,
apk_progress_cb cb, void *cb_ctx)
{
struct apk_out *out = &db->ctx->out;
@@ -629,7 +630,7 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
struct apk_url_print urlp;
struct apk_istream *is;
struct apk_ostream *os;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
char url[PATH_MAX];
char cacheitem[128];
int r;
@@ -658,29 +659,16 @@ int apk_cache_download(struct apk_database *db, struct apk_repository *repo,
if (cb) cb(cb_ctx, 0);
- if (verify != APK_SIGN_NONE) {
- apk_sign_ctx_init(&sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
- is = apk_istream_tee(is, os, autoupdate ? 0 : APK_ISTREAM_TEE_COPY_META, cb, cb_ctx);
- is = apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &sctx);
- r = apk_tar_parse(is, apk_sign_ctx_verify_tar, &sctx, db->id_cache);
- apk_sign_ctx_free(&sctx);
- } else {
- is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
- if (!IS_ERR(is)) {
- apk_stream_copy(is, os, APK_IO_ALL, cb, cb_ctx, 0);
- if (!autoupdate) apk_ostream_copy_meta(os, is);
- apk_istream_close(is);
- } else {
- apk_ostream_cancel(os, PTR_ERR(is));
- }
- r = apk_ostream_close(os);
- }
+ is = apk_istream_from_url(url, apk_db_url_since(db, st.st_mtime));
+ is = apk_istream_tee(is, os, autoupdate ? 0 : APK_ISTREAM_TEE_COPY_META, cb, cb_ctx);
+ apk_extract_init(&ectx, db->ctx, 0);
+ if (pkg) apk_extract_verify_identity(&ectx, &pkg->csum);
+ r = apk_extract(&ectx, is);
if (r == -EALREADY) {
if (autoupdate) utimensat(db->cache_fd, cacheitem, NULL, 0);
return r;
}
- return 0;
+ return r;
}
static struct apk_db_dir_instance *find_diri(struct apk_installed_package *ipkg,
@@ -716,7 +704,7 @@ int apk_db_read_overlay(struct apk_database *db, struct apk_istream *is)
struct apk_installed_package *ipkg;
apk_blob_t token = APK_BLOB_STR("\n"), line, bdir, bfile;
- if (IS_ERR_OR_NULL(is)) return PTR_ERR(is);
+ if (IS_ERR(is)) return PTR_ERR(is);
pkg = apk_pkg_new();
if (!pkg) goto no_mem;
@@ -770,7 +758,7 @@ int apk_db_index_read(struct apk_database *db, struct apk_istream *is, int repo)
gid_t gid;
int field, r, lineno = 0;
- if (IS_ERR_OR_NULL(is)) return PTR_ERR(is);
+ if (IS_ERR(is)) return PTR_ERR(is);
while (apk_istream_get_delim(is, token, &l) == 0) {
lineno++;
@@ -928,16 +916,16 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
struct apk_db_dir_instance *diri;
struct apk_db_file *file;
struct hlist_node *c1, *c2;
- char buf[1024];
+ char buf[1024+PATH_MAX];
apk_blob_t bbuf = APK_BLOB_BUF(buf);
- int r;
+ int r = 0;
+
+ if (IS_ERR(os)) return PTR_ERR(os);
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
pkg = ipkg->pkg;
r = apk_pkg_write_index_entry(pkg, os);
- if (r < 0) {
- return r;
- }
+ if (r < 0) goto err;
if (ipkg->replaces->num) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("r:"));
@@ -972,6 +960,15 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
if (diri->acl != apk_default_acl_dir)
apk_blob_push_db_acl(&bbuf, 'M', diri->acl);
+ bbuf = apk_blob_pushed(APK_BLOB_BUF(buf), bbuf);
+ if (APK_BLOB_IS_NULL(bbuf)) {
+ r = -ENOBUFS;
+ goto err;
+ }
+ r = apk_ostream_write(os, bbuf.ptr, bbuf.len);
+ if (r < 0) goto err;
+ bbuf = APK_BLOB_BUF(buf);
+
hlist_for_each_entry(file, c2, &diri->owned_files, diri_files_list) {
apk_blob_push_blob(&bbuf, APK_BLOB_STR("R:"));
apk_blob_push_blob(&bbuf, APK_BLOB_PTR_LEN(file->name, file->namelen));
@@ -986,19 +983,22 @@ static int apk_db_write_fdb(struct apk_database *db, struct apk_ostream *os)
apk_blob_push_blob(&bbuf, APK_BLOB_STR("\n"));
}
- r = apk_ostream_write(os, buf, bbuf.ptr - buf);
- if (r < 0) return r;
+ bbuf = apk_blob_pushed(APK_BLOB_BUF(buf), bbuf);
+ if (APK_BLOB_IS_NULL(bbuf)) {
+ r = -ENOBUFS;
+ goto err;
+ }
+ r = apk_ostream_write(os, bbuf.ptr, bbuf.len);
+ if (r < 0) goto err;
bbuf = APK_BLOB_BUF(buf);
}
- r = apk_ostream_write(os, buf, bbuf.ptr - buf);
- if (r < 0) return r;
- bbuf = APK_BLOB_BUF(buf);
}
r = apk_ostream_write(os, "\n", 1);
- if (r < 0) return r;
+ if (r < 0) goto err;
}
-
- return 0;
+err:
+ if (r < 0) apk_ostream_cancel(os, r);
+ return apk_ostream_close(os);
}
static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os)
@@ -1009,7 +1009,8 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
char filename[256];
apk_blob_t bfn;
int r, i;
- time_t now = time(NULL);
+
+ if (IS_ERR(os)) return PTR_ERR(os);
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
pkg = ipkg->pkg;
@@ -1022,7 +1023,6 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
.name = filename,
.size = ipkg->script[i].len,
.mode = 0755 | S_IFREG,
- .mtime = now,
};
/* The scripts db expects file names in format:
* pkg-version.<hexdump of package checksum>.action */
@@ -1037,12 +1037,15 @@ static int apk_db_scriptdb_write(struct apk_database *db, struct apk_ostream *os
apk_blob_push_blob(&bfn, APK_BLOB_PTR_LEN("", 1));
r = apk_tar_write_entry(os, &fi, ipkg->script[i].ptr);
- if (r < 0)
- return r;
+ if (r < 0) {
+ apk_ostream_cancel(os, -APKE_V2DB_FORMAT);
+ break;
+ }
}
}
- return apk_tar_write_entry(os, NULL, NULL);
+ apk_tar_write_entry(os, NULL, NULL);
+ return apk_ostream_close(os);
}
static int apk_read_script_archive_entry(void *ctx,
@@ -1096,13 +1099,15 @@ static int parse_triggers(void *ctx, apk_blob_t blob)
return 0;
}
-static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os)
+static int apk_db_triggers_write(struct apk_database *db, struct apk_ostream *os)
{
struct apk_installed_package *ipkg;
char buf[APK_BLOB_CHECKSUM_BUF];
apk_blob_t bfn;
char **trigger;
+ if (IS_ERR(os)) return PTR_ERR(os);
+
list_for_each_entry(ipkg, &db->installed.triggers, trigger_pkgs_list) {
bfn = APK_BLOB_BUF(buf);
apk_blob_push_csum(&bfn, &ipkg->pkg->csum);
@@ -1115,6 +1120,7 @@ static void apk_db_triggers_write(struct apk_database *db, struct apk_ostream *o
}
apk_ostream_write(os, "\n", 1);
}
+ return apk_ostream_close(os);
}
static int apk_db_triggers_read(struct apk_database *db, struct apk_istream *is)
@@ -1217,7 +1223,7 @@ static int apk_db_index_write_nr_cache(struct apk_database *db)
/* Write list of installed non-repository packages to
* cached index file */
os = apk_ostream_to_file(db->cache_fd, "installed", 0644);
- if (IS_ERR_OR_NULL(os)) return PTR_ERR(os);
+ if (IS_ERR(os)) return PTR_ERR(os);
ctx.os = os;
list_for_each_entry(ipkg, &db->installed.packages, installed_pkgs_list) {
@@ -1732,7 +1738,7 @@ int apk_db_write_config(struct apk_database *db)
{
struct apk_out *out = &db->ctx->out;
struct apk_ostream *os;
- int r;
+ int r, rr = 0;
if ((db->ctx->flags & APK_SIMULATE) || db->ctx->root == NULL)
return 0;
@@ -1743,33 +1749,30 @@ int apk_db_write_config(struct apk_database *db)
}
os = apk_ostream_to_file(db->root_fd, apk_world_file, 0644);
- if (IS_ERR_OR_NULL(os)) return PTR_ERR(os);
- apk_deps_write(db, db->world, os, APK_BLOB_PTR_LEN("\n", 1));
- apk_ostream_write(os, "\n", 1);
- r = apk_ostream_close(os);
- if (r < 0) return r;
+ if (!IS_ERR(os)) {
+ apk_deps_write(db, db->world, os, APK_BLOB_PTR_LEN("\n", 1));
+ apk_ostream_write(os, "\n", 1);
+ r = apk_ostream_close(os);
+ if (r && !rr) rr = r;
+ }
- os = apk_ostream_to_file(db->root_fd, apk_installed_file, 0644);
- if (IS_ERR_OR_NULL(os)) return PTR_ERR(os);
- apk_db_write_fdb(db, os);
- r = apk_ostream_close(os);
- if (r < 0) return r;
+ r = apk_db_write_fdb(db, apk_ostream_to_file(db->root_fd, apk_installed_file, 0644));
+ if (r < 0 && !rr) rr = r;
- os = apk_ostream_to_file(db->root_fd, apk_scripts_file, 0644);
- if (IS_ERR_OR_NULL(os)) return PTR_ERR(os);
- apk_db_scriptdb_write(db, os);
- r = apk_ostream_close(os);
- if (r < 0) return r;
+ r = apk_db_scriptdb_write(db, apk_ostream_to_file(db->root_fd, apk_scripts_file, 0644));
+ if (r < 0 && !rr) rr = r;
- apk_db_index_write_nr_cache(db);
+ r = apk_db_index_write_nr_cache(db);
+ if (r < 0 && !rr) rr = r;
- os = apk_ostream_to_file(db->root_fd, apk_triggers_file, 0644);
- if (IS_ERR_OR_NULL(os)) return PTR_ERR(os);
- apk_db_triggers_write(db, os);
- r = apk_ostream_close(os);
- if (r < 0) return r;
+ r = apk_db_triggers_write(db, apk_ostream_to_file(db->root_fd, apk_triggers_file, 0644));
+ if (r < 0 && !rr) rr = r;
- return 0;
+ if (rr) {
+ apk_err(out, "System state may be inconsistent: failed to write database: %s",
+ apk_error_str(rr));
+ }
+ return rr;
}
void apk_db_close(struct apk_database *db)
@@ -2137,9 +2140,9 @@ static int apk_repository_update(struct apk_database *db, struct apk_repository
{
struct apk_out *out = &db->ctx->out;
struct apk_url_print urlp;
- int r, verify = (db->ctx->flags & APK_ALLOW_UNTRUSTED) ? APK_SIGN_NONE : APK_SIGN_VERIFY;
+ int r;
- r = apk_cache_download(db, repo, NULL, verify, 1, NULL, NULL);
+ r = apk_cache_download(db, repo, NULL, 1, NULL, NULL);
if (r == -EALREADY) return 0;
if (r != 0) {
apk_url_parse(&urlp, repo->url);
@@ -2154,67 +2157,38 @@ static int apk_repository_update(struct apk_database *db, struct apk_repository
struct apkindex_ctx {
struct apk_database *db;
- struct apk_sign_ctx sctx;
+ struct apk_extract_ctx ectx;
int repo, found;
};
-static int load_apkindex(void *sctx, 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 = (struct apkindex_ctx *) sctx;
- struct apk_repository *repo;
- int r;
-
- r = apk_sign_ctx_process_file(&ctx->sctx, fi, is);
- if (r <= 0)
- return r;
-
- r = 0;
- 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;
- r = apk_db_index_read(ctx->db, is, ctx->repo);
- }
+ struct apkindex_ctx *ctx = container_of(ectx, struct apkindex_ctx, ectx);
+ struct apk_repository *repo = &ctx->db->repos[ctx->repo];
- return r;
+ repo->description = *desc;
+ *desc = APK_BLOB_NULL;
+ return apk_db_index_read(ctx->db, is, ctx->repo);
}
-static int load_index(struct apk_database *db, struct apk_istream *is,
- int targz, int repo)
-{
- int r = 0;
-
- if (IS_ERR_OR_NULL(is)) return is ? PTR_ERR(is) : -EINVAL;
-
- if (targz) {
- struct apkindex_ctx ctx;
-
- ctx.db = db;
- ctx.repo = repo;
- ctx.found = 0;
- apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY, NULL, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), load_apkindex, &ctx, db->id_cache);
- apk_sign_ctx_free(&ctx.sctx);
+static const struct apk_extract_ops extract_index = {
+ .v2index = load_v2index,
+};
- if (r >= 0 && ctx.found == 0)
- r = -APKE_V2NDX_FORMAT;
- } else {
- apk_db_index_read(db, apk_istream_gunzip(is), repo);
- }
- return r;
+static int load_index(struct apk_database *db, struct apk_istream *is, int repo)
+{
+ struct apkindex_ctx ctx = {
+ .db = db,
+ .repo = repo,
+ };
+ if (IS_ERR(is)) return PTR_ERR(is);
+ 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)
{
- int targz = 1;
-
- if (strstr(file, ".tar.gz") == NULL && strstr(file, ".gz") != NULL)
- targz = 0;
-
- return load_index(db, apk_istream_from_file(AT_FDCWD, file), targz, repo);
+ return load_index(db, apk_istream_from_file(AT_FDCWD, file), repo);
}
int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
@@ -2224,7 +2198,7 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
struct apk_repository *repo;
struct apk_url_print urlp;
apk_blob_t brepo, btag;
- int repo_num, r, targz = 1, tag_id = 0;
+ int repo_num, r, tag_id = 0;
char buf[PATH_MAX], *url;
brepo = _repository;
@@ -2277,14 +2251,13 @@ int apk_db_add_repository(apk_database_t _db, apk_blob_t _repository)
r = apk_repo_format_real_url(db->arch, repo, NULL, buf, sizeof(buf), &urlp);
}
if (r == 0) {
- r = load_index(db, apk_istream_from_fd_url(db->cache_fd, buf, apk_db_url_since(db, 0)), targz, repo_num);
+ r = load_index(db, apk_istream_from_fd_url(db->cache_fd, buf, apk_db_url_since(db, 0)), repo_num);
}
if (r != 0) {
apk_url_parse(&urlp, repo->url);
apk_warn(out, "Ignoring " URL_FMT ": %s", URL_PRINTF(urlp), apk_error_str(r));
db->available_repos &= ~BIT(repo_num);
- r = 0;
} else {
db->repo_tags[tag_id].allowed_repos |= BIT(repo_num);
}
@@ -2302,10 +2275,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->sctx.control_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)
@@ -2334,7 +2306,7 @@ static int read_info_line(void *_ctx, apk_blob_t line)
list_add_tail(&ipkg->trigger_pkgs_list,
&db->installed.triggers);
} else {
- apk_sign_ctx_parse_pkginfo_line(&ctx->sctx, line);
+ apk_extract_v2_control(&ctx->ectx, l, r);
}
return 0;
}
@@ -2393,12 +2365,28 @@ static int contains_control_character(const char *str)
return 0;
}
-static int apk_db_install_archive_entry(void *_ctx,
- 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[] = "/../";
- struct install_ctx *ctx = (struct install_ctx *) _ctx;
struct apk_database *db = ctx->db;
struct apk_out *out = &db->ctx->out;
struct apk_package *pkg = ctx->pkg, *opkg;
@@ -2410,34 +2398,8 @@ static int apk_db_install_archive_entry(void *_ctx,
int ret = 0, r;
char tmpname_file[TMPNAME_MAX], tmpname_link_target[TMPNAME_MAX];
- r = apk_sign_ctx_process_file(&ctx->sctx, ae, is);
- if (r <= 0)
- return r;
-
- /* Package metainfo and script processing */
- if (ctx->sctx.control_started && !ctx->sctx.data_started) {
- 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 (!ctx->sctx.data_started || ae->name[0] == '.')
- return 0;
+ if (ae->name[0] == '.') return 0;
/* Sanity check the file name */
if (ae->name[0] == '/' || contains_control_character(ae->name) ||
@@ -2566,7 +2528,7 @@ static int apk_db_install_archive_entry(void *_ctx,
/* Extract the file with temporary name */
file->acl = apk_db_acl_atomize_digest(db, ae->mode, ae->uid, ae->gid, &ae->xattr_digest);
- r = apk_archive_entry_extract(
+ r = apk_extract_file(
db->root_fd, ae,
format_tmpname(pkg, file, tmpname_file),
format_tmpname(pkg, link_target_file, tmpname_link_target),
@@ -2616,6 +2578,12 @@ static int apk_db_install_archive_entry(void *_ctx,
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)
@@ -2801,7 +2769,7 @@ static int apk_db_unpack_pkg(struct apk_database *db,
need_copy = FALSE;
is = apk_istream_from_fd_url(filefd, file, apk_db_url_since(db, 0));
- if (IS_ERR_OR_NULL(is)) {
+ if (IS_ERR(is)) {
r = PTR_ERR(is);
if (r == -ENOENT && pkg->filename == NULL)
r = -APKE_INDEX_STALE;
@@ -2827,10 +2795,9 @@ static int apk_db_unpack_pkg(struct apk_database *db,
.cb = cb,
.cb_ctx = cb_ctx,
};
- apk_sign_ctx_init(&ctx.sctx, APK_SIGN_VERIFY_IDENTITY, &pkg->csum, apk_ctx_get_trust(db->ctx));
- r = apk_tar_parse(apk_istream_gunzip_mpart(is, apk_sign_ctx_mpart_cb, &ctx.sctx), apk_db_install_archive_entry, &ctx, db->id_cache);
- apk_sign_ctx_free(&ctx.sctx);
-
+ 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);
if (r != 0) goto err_msg;
diff --git a/src/extract.c b/src/extract.c
new file mode 100644
index 0000000..1e092c5
--- /dev/null
+++ b/src/extract.c
@@ -0,0 +1,147 @@
+/* extract.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include <sys/stat.h>
+#include <sys/xattr.h>
+#include <unistd.h>
+
+#include "apk_extract.h"
+
+int apk_extract_file(int atfd, const struct apk_file_info *ae,
+ const char *extract_name, const char *link_target,
+ struct apk_istream *is,
+ apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
+ unsigned int extract_flags, struct apk_out *out)
+{
+ struct apk_xattr *xattr;
+ const char *fn = extract_name ?: ae->name;
+ int fd, r = -1, atflags = 0, ret = 0;
+
+ if (!S_ISDIR(ae->mode) && !(extract_flags & APK_EXTRACTF_NO_OVERWRITE)) {
+ if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
+ }
+
+ switch (ae->mode & S_IFMT) {
+ case S_IFDIR:
+ r = mkdirat(atfd, fn, ae->mode & 07777);
+ if (r < 0 && errno != EEXIST)
+ ret = -errno;
+ break;
+ case S_IFREG:
+ if (ae->link_target == NULL) {
+ int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
+ int fd = openat(atfd, fn, flags, ae->mode & 07777);
+ if (fd < 0) {
+ ret = -errno;
+ break;
+ }
+ struct apk_ostream *os = apk_ostream_to_fd(fd);
+ if (IS_ERR(os)) {
+ ret = PTR_ERR(os);
+ break;
+ }
+ apk_stream_copy(is, os, ae->size, cb, cb_ctx, dctx);
+ r = apk_ostream_close(os);
+ if (r < 0) {
+ unlinkat(atfd, fn, 0);
+ ret = r;
+ }
+ } else {
+ r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
+ if (r < 0) ret = -errno;
+ }
+ break;
+ case S_IFLNK:
+ r = symlinkat(link_target ?: ae->link_target, atfd, fn);
+ if (r < 0) ret = -errno;
+ atflags |= AT_SYMLINK_NOFOLLOW;
+ break;
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ r = mknodat(atfd, fn, ae->mode, ae->device);
+ if (r < 0) ret = -errno;
+ break;
+ }
+ if (ret) {
+ apk_err(out, "Failed to create %s: %s", ae->name, strerror(-ret));
+ return ret;
+ }
+
+ if (!(extract_flags & APK_EXTRACTF_NO_CHOWN)) {
+ r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to set ownership on %s: %s",
+ fn, strerror(errno));
+ if (!ret) ret = -errno;
+ }
+
+ /* chown resets suid bit so we need set it again */
+ if (ae->mode & 07000) {
+ r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to set file permissions on %s: %s",
+ fn, strerror(errno));
+ if (!ret) ret = -errno;
+ }
+ }
+ }
+
+ /* extract xattrs */
+ if (!S_ISLNK(ae->mode) && ae->xattrs && ae->xattrs->num) {
+ r = 0;
+ fd = openat(atfd, fn, O_RDWR);
+ if (fd >= 0) {
+ foreach_array_item(xattr, ae->xattrs) {
+ if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) {
+ r = -errno;
+ if (r != -ENOTSUP) break;
+ }
+ }
+ close(fd);
+ } else {
+ r = -errno;
+ }
+ if (r) {
+ if (r != -ENOTSUP)
+ apk_err(out, "Failed to set xattrs on %s: %s",
+ fn, strerror(-r));
+ if (!ret) ret = r;
+ }
+ }
+
+ if (!S_ISLNK(ae->mode)) {
+ /* preserve modification time */
+ struct timespec times[2];
+
+ times[0].tv_sec = times[1].tv_sec = ae->mtime;
+ times[0].tv_nsec = times[1].tv_nsec = 0;
+ r = utimensat(atfd, fn, times, atflags);
+ if (r < 0) {
+ apk_err(out, "Failed to preserve modification time on %s: %s",
+ fn, strerror(errno));
+ if (!ret || ret == -ENOTSUP) ret = -errno;
+ }
+ }
+
+ return ret;
+}
+
+int apk_extract(struct apk_extract_ctx *ectx, struct apk_istream *is)
+{
+ void *sig;
+
+ if (IS_ERR(is)) return PTR_ERR(is);
+
+ sig = apk_istream_peek(is, 4);
+ if (IS_ERR(sig)) return apk_istream_close_error(is, PTR_ERR(sig));
+
+ if (memcmp(sig, "ADB", 3) == 0) return apk_extract_v3(ectx, is);
+ return apk_extract_v2(ectx, is);
+}
diff --git a/src/extract_v2.c b/src/extract_v2.c
new file mode 100644
index 0000000..e3229de
--- /dev/null
+++ b/src/extract_v2.c
@@ -0,0 +1,395 @@
+/* extract_v2.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include "apk_context.h"
+#include "apk_extract.h"
+#include "apk_package.h"
+#include "apk_tar.h"
+
+#define APK_SIGN_NONE 0
+#define APK_SIGN_VERIFY 1
+#define APK_SIGN_VERIFY_IDENTITY 2
+#define APK_SIGN_GENERATE 4
+#define APK_SIGN_VERIFY_AND_GENERATE 5
+
+struct apk_sign_ctx {
+ struct apk_trust *trust;
+ int action;
+ const EVP_MD *md;
+ int num_signatures;
+ int control_started : 1;
+ int data_started : 1;
+ int has_data_checksum : 1;
+ int control_verified : 1;
+ int data_verified : 1;
+ int allow_untrusted : 1;
+ char data_checksum[EVP_MAX_MD_SIZE];
+ struct apk_checksum identity;
+ EVP_MD_CTX *mdctx;
+
+ struct {
+ apk_blob_t data;
+ EVP_PKEY *pkey;
+ char *identity;
+ } signature;
+};
+
+static void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action, struct apk_checksum *identity, struct apk_trust *trust)
+{
+ memset(ctx, 0, sizeof(struct apk_sign_ctx));
+ ctx->trust = trust;
+ ctx->action = action;
+ ctx->allow_untrusted = trust->allow_untrusted;
+ switch (action) {
+ case APK_SIGN_VERIFY:
+ /* If we're only verifing, we're going to start with a
+ * signature section, which we don't need a hash of */
+ ctx->md = EVP_md_null();
+ break;
+ case APK_SIGN_VERIFY_IDENTITY:
+ /* If we're checking the package against a particular hash,
+ * we need to start with that hash, because there may not
+ * be a signature section to deduce it from */
+ ctx->md = EVP_sha1();
+ memcpy(&ctx->identity, identity, sizeof(ctx->identity));
+ break;
+ case APK_SIGN_GENERATE:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ ctx->md = EVP_sha1();
+ break;
+ default:
+ ctx->action = APK_SIGN_NONE;
+ ctx->md = EVP_md_null();
+ ctx->control_started = 1;
+ ctx->data_started = 1;
+ break;
+ }
+ ctx->mdctx = EVP_MD_CTX_new();
+ EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL);
+ EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+}
+
+static void apk_sign_ctx_free(struct apk_sign_ctx *ctx)
+{
+ if (ctx->signature.data.ptr != NULL)
+ free(ctx->signature.data.ptr);
+ EVP_MD_CTX_free(ctx->mdctx);
+}
+
+static int check_signing_key_trust(struct apk_sign_ctx *sctx)
+{
+ switch (sctx->action) {
+ case APK_SIGN_VERIFY:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ if (sctx->signature.pkey == NULL) {
+ if (sctx->allow_untrusted)
+ break;
+ return -APKE_SIGNATURE_UNTRUSTED;
+ }
+ }
+ return 0;
+}
+
+static int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx, const struct apk_file_info *fi,
+ struct apk_istream *is)
+{
+ static struct {
+ char type[8];
+ unsigned int nid;
+ } signature_type[] = {
+ { "RSA512", NID_sha512 },
+ { "RSA256", NID_sha256 },
+ { "RSA", NID_sha1 },
+ { "DSA", NID_dsa },
+ };
+ const EVP_MD *md = NULL;
+ const char *name = NULL;
+ struct apk_pkey *pkey;
+ int r, i;
+
+ if (ctx->data_started)
+ return 1;
+
+ if (fi->name[0] != '.' || strchr(fi->name, '/') != NULL) {
+ /* APKv1.0 compatibility - first non-hidden file is
+ * considered to start the data section of the file.
+ * This does not make any sense if the file has v2.0
+ * style .PKGINFO */
+ if (ctx->has_data_checksum)
+ return -APKE_V2PKG_FORMAT;
+ /* Error out early if identity part is missing */
+ if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
+ return -APKE_V2PKG_FORMAT;
+ ctx->data_started = 1;
+ ctx->control_started = 1;
+ r = check_signing_key_trust(ctx);
+ if (r < 0)
+ return r;
+ return 1;
+ }
+
+ if (ctx->control_started)
+ return 1;
+
+ if (strncmp(fi->name, ".SIGN.", 6) != 0) {
+ ctx->control_started = 1;
+ return 1;
+ }
+
+ /* By this point, we must be handling a signature file */
+ ctx->num_signatures++;
+
+ /* Already found a signature by a trusted key; no need to keep searching */
+ if ((ctx->action != APK_SIGN_VERIFY &&
+ ctx->action != APK_SIGN_VERIFY_AND_GENERATE) ||
+ ctx->signature.pkey != NULL)
+ return 0;
+
+ for (i = 0; i < ARRAY_SIZE(signature_type); i++) {
+ size_t slen = strlen(signature_type[i].type);
+ if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 &&
+ fi->name[6+slen] == '.') {
+ md = EVP_get_digestbynid(signature_type[i].nid);
+ name = &fi->name[6+slen+1];
+ break;
+ }
+ }
+ if (!md) return 0;
+
+ pkey = apk_trust_key_by_name(ctx->trust, name);
+ if (pkey) {
+ ctx->md = md;
+ ctx->signature.pkey = pkey->key;
+ ctx->signature.data = apk_blob_from_istream(is, fi->size);
+ }
+ return 0;
+}
+
+
+/* apk_sign_ctx_mpart_cb() handles hashing archives and checking signatures, but
+ it can't do it alone. apk_sign_ctx_process_file() must be in the loop to
+ actually select which signature is to be verified and load the corresponding
+ public key into the context object, and apk_sign_ctx_parse_pkginfo_line()
+ needs to be called when handling the .PKGINFO file to find any applicable
+ datahash and load it into the context for this function to check against. */
+static int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
+{
+ struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
+ unsigned char calculated[EVP_MAX_MD_SIZE];
+ int r, end_of_control;
+
+ if ((part == APK_MPART_DATA) ||
+ (part == APK_MPART_BOUNDARY && sctx->data_started))
+ goto update_digest;
+
+ /* Still in signature blocks? */
+ if (!sctx->control_started) {
+ if (part == APK_MPART_END)
+ return -APKE_V2PKG_FORMAT;
+ goto reset_digest;
+ }
+
+ /* Grab state and mark all remaining block as data */
+ end_of_control = (sctx->data_started == 0);
+ sctx->data_started = 1;
+
+ /* End of control-block and control does not have data checksum? */
+ if (sctx->has_data_checksum == 0 && end_of_control &&
+ part != APK_MPART_END)
+ goto update_digest;
+
+ /* Drool in the remainder of the digest block now, we will finish
+ * hashing it in all cases */
+ EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
+
+ if (sctx->has_data_checksum && !end_of_control) {
+ /* End of data-block with a checksum read from the control block */
+ EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
+ if (EVP_MD_CTX_size(sctx->mdctx) == 0 ||
+ memcmp(calculated, sctx->data_checksum, EVP_MD_CTX_size(sctx->mdctx)) != 0)
+ return -APKE_V2PKG_INTEGRITY;
+ sctx->data_verified = 1;
+ if (!sctx->allow_untrusted && !sctx->control_verified)
+ return -APKE_SIGNATURE_UNTRUSTED;
+ return 0;
+ }
+
+ /* Either end of control block with a data checksum or end
+ * of the data block following a control block without a data
+ * checksum. In either case, we're checking a signature. */
+ r = check_signing_key_trust(sctx);
+ if (r < 0)
+ return r;
+
+ switch (sctx->action) {
+ case APK_SIGN_VERIFY:
+ case APK_SIGN_VERIFY_AND_GENERATE:
+ if (sctx->signature.pkey != NULL) {
+ r = EVP_VerifyFinal(sctx->mdctx,
+ (unsigned char *) sctx->signature.data.ptr,
+ sctx->signature.data.len,
+ sctx->signature.pkey);
+ if (r != 1 && !sctx->allow_untrusted)
+ return -APKE_SIGNATURE_INVALID;
+ } else {
+ r = 0;
+ if (!sctx->allow_untrusted)
+ return -APKE_SIGNATURE_UNTRUSTED;
+ }
+ if (r == 1) {
+ sctx->control_verified = 1;
+ if (!sctx->has_data_checksum && part == APK_MPART_END)
+ sctx->data_verified = 1;
+ }
+ if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) goto generate_identity;
+ break;
+ case APK_SIGN_VERIFY_IDENTITY:
+ /* Reset digest for hashing data */
+ EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
+ if (memcmp(calculated, sctx->identity.data,
+ sctx->identity.type) != 0)
+ return -APKE_V2PKG_INTEGRITY;
+ sctx->control_verified = 1;
+ if (!sctx->has_data_checksum && part == APK_MPART_END)
+ sctx->data_verified = 1;
+ break;
+ case APK_SIGN_GENERATE:
+ generate_identity:
+ /* Package identity is the checksum */
+ sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
+ EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
+ if (!sctx->has_data_checksum) return -APKE_V2PKG_FORMAT;
+ break;
+ }
+reset_digest:
+ EVP_DigestInit_ex(sctx->mdctx, sctx->md, NULL);
+ EVP_MD_CTX_set_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+ return 0;
+
+update_digest:
+ EVP_MD_CTX_clear_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
+ EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
+ 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, type;
+
+ r = apk_sign_ctx_process_file(sctx, fi, is);
+ if (r <= 0) return 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;
+ }
+
+ if (!sctx->data_started) 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)
+{
+ struct apk_ctx *ac = ectx->ac;
+ struct apk_trust *trust = apk_ctx_get_trust(ac);
+ struct apk_sign_ctx sctx;
+ int r, action;
+
+ if (ectx->generate_identity)
+ action = trust->allow_untrusted ? APK_SIGN_GENERATE : APK_SIGN_VERIFY_AND_GENERATE;
+ else if (ectx->identity)
+ action = APK_SIGN_VERIFY_IDENTITY;
+ else
+ action = 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 || r == -APKE_SIGNATURE_UNTRUSTED || r == -APKE_EOF) && !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;
+}
+
+void apk_extract_v2_control(struct apk_extract_ctx *ectx, apk_blob_t l, apk_blob_t r)
+{
+ struct apk_sign_ctx *sctx = ectx->pctx;
+
+ if (!sctx || !sctx->control_started || sctx->data_started) return;
+
+ if (apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
+ sctx->has_data_checksum = 1;
+ sctx->md = EVP_sha256();
+ apk_blob_pull_hexdump(
+ &r, APK_BLOB_PTR_LEN(sctx->data_checksum,
+ 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/extract_v3.c b/src/extract_v3.c
new file mode 100644
index 0000000..a5a1459
--- /dev/null
+++ b/src/extract_v3.c
@@ -0,0 +1,262 @@
+/* extract_v3.c - Alpine Package Keeper (APK)
+ *
+ * Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
+ * Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
+ * All rights reserved.
+ *
+ * SPDX-License-Identifier: GPL-2.0-only
+ */
+
+#include <sys/stat.h>
+
+#include "apk_context.h"
+#include "apk_extract.h"
+#include "apk_adb.h"
+#include "apk_pathbuilder.h"
+
+struct apk_extract_v3_ctx {
+ struct apk_extract_ctx *ectx;
+ struct adb db;
+ struct adb_obj pkg, paths, path, files, file;
+ unsigned int cur_path, cur_file;
+ struct apk_pathbuilder pb;
+};
+
+static const char *uvol_detect(struct apk_ctx *ac, const char *path)
+{
+ if (!apk_ctx_get_uvol(ac)) return 0;
+ if (strncmp(path, "uvol", 4) != 0) return 0;
+ if (path[4] == 0) return path;
+ if (path[4] == '/') return &path[5];
+ return 0;
+}
+
+static void apk_extract_v3_acl(struct apk_file_info *fi, struct adb_obj *o, struct apk_id_cache *idc)
+{
+ fi->mode = adb_ro_int(o, ADBI_ACL_MODE);
+ fi->uid = apk_id_cache_resolve_uid(idc, adb_ro_blob(o, ADBI_ACL_USER), 65534);
+ fi->gid = apk_id_cache_resolve_gid(idc, adb_ro_blob(o, ADBI_ACL_GROUP), 65534);
+}
+
+static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct apk_istream *is)
+{
+ struct apk_extract_v3_ctx *ctx = ectx->pctx;
+ struct apk_ctx *ac = ectx->ac;
+ const char *path_name = apk_pathbuilder_cstr(&ctx->pb);
+ struct apk_file_info fi = {
+ .name = path_name,
+ .uvol_name = uvol_detect(ac, path_name),
+ .size = adb_ro_int(&ctx->file, ADBI_FI_SIZE),
+ .mtime = adb_ro_int(&ctx->file, ADBI_FI_MTIME),
+ };
+ struct adb_obj acl;
+ struct apk_digest_istream dis;
+ apk_blob_t target;
+ int r;
+
+ apk_extract_v3_acl(&fi, adb_ro_obj(&ctx->file, ADBI_FI_ACL, &acl), apk_ctx_get_id_cache(ectx->ac));
+
+ target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
+ if (!APK_BLOB_IS_NULL(target)) {
+ char *target_path;
+ uint16_t mode;
+
+ if (target.len < 2) return -APKE_ADB_SCHEMA;
+ mode = *(uint16_t*)target.ptr;
+ target.ptr += 2;
+ target.len -= 2;
+ switch (mode) {
+ case S_IFBLK:
+ case S_IFCHR:
+ case S_IFIFO:
+ if (target.len != sizeof(uint64_t)) return -APKE_ADB_SCHEMA;
+ struct unaligned64 {
+ uint64_t value;
+ } __attribute__((packed));
+ fi.device = ((struct unaligned64 *)target.ptr)->value;
+ break;
+ case S_IFLNK:
+ target_path = alloca(target.len + 1);
+ memcpy(target_path, target.ptr, target.len);
+ target_path[target.len] = 0;
+ fi.link_target = target_path;
+ break;
+ default:
+ return -APKE_ADB_SCHEMA;
+ }
+ fi.mode |= mode;
+ return ectx->ops->file(ectx, &fi, is);
+ }
+
+ apk_digest_from_blob(&fi.digest, adb_ro_blob(&ctx->file, ADBI_FI_HASHES));
+ if (fi.digest.alg == APK_DIGEST_NONE) return -APKE_ADB_SCHEMA;
+
+ fi.mode |= S_IFREG;
+ r = ectx->ops->file(ectx, &fi, apk_istream_verify(&dis, is, &fi.digest));
+ return apk_istream_close_error(&dis.is, r);
+}
+
+static int apk_extract_v3_directory(struct apk_extract_ctx *ectx)
+{
+ struct apk_extract_v3_ctx *ctx = ectx->pctx;
+ struct apk_ctx *ac = ectx->ac;
+ struct apk_file_info fi = {
+ .name = apk_pathbuilder_cstr(&ctx->pb),
+ };
+ struct adb_obj acl;
+
+ if (uvol_detect(ac, fi.name)) return 0;
+
+ apk_extract_v3_acl(&fi, adb_ro_obj(&ctx->path, ADBI_DI_ACL, &acl), apk_ctx_get_id_cache(ectx->ac));
+ fi.mode |= S_IFDIR;
+
+ return ectx->ops->file(ectx, &fi, 0);
+}
+
+static int apk_extract_v3_next_file(struct apk_extract_ctx *ectx)
+{
+ struct apk_extract_v3_ctx *ctx = ectx->pctx;
+ apk_blob_t target;
+ int r;
+
+ if (!ctx->cur_path) {
+ // one time init
+ ctx->cur_path = ADBI_FIRST;
+ ctx->cur_file = 0;
+ adb_r_rootobj(&ctx->db, &ctx->pkg, &schema_package);
+
+ r = ectx->ops->v3meta(ectx, &ctx->pkg);
+ if (r < 0) return r;
+
+ adb_ro_obj(&ctx->pkg, ADBI_PKG_PATHS, &ctx->paths);
+ adb_ro_obj(&ctx->paths, ctx->cur_path, &ctx->path);
+ adb_ro_obj(&ctx->path, ADBI_DI_FILES, &ctx->files);
+ if (!ectx->ops->file) return -ECANCELED;
+ }
+
+ do {
+ ctx->cur_file++;
+ while (ctx->cur_file > adb_ra_num(&ctx->files)) {
+ ctx->cur_path++;
+ ctx->cur_file = ADBI_FIRST;
+ if (ctx->cur_path > adb_ra_num(&ctx->paths)) return 1;
+ adb_ro_obj(&ctx->paths, ctx->cur_path, &ctx->path);
+ apk_pathbuilder_setb(&ctx->pb, adb_ro_blob(&ctx->path, ADBI_DI_NAME));
+ adb_ro_obj(&ctx->path, ADBI_DI_FILES, &ctx->files);
+ r = apk_extract_v3_directory(ectx);
+ if (r != 0) return r;
+ }
+ adb_ro_obj(&ctx->files, ctx->cur_file, &ctx->file);
+ apk_pathbuilder_setb(&ctx->pb, adb_ro_blob(&ctx->path, ADBI_DI_NAME));
+ apk_pathbuilder_pushb(&ctx->pb, adb_ro_blob(&ctx->file, ADBI_FI_NAME));
+ target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
+ if (adb_ro_int(&ctx->file, ADBI_FI_SIZE) != 0 &&
+ APK_BLOB_IS_NULL(target)) {
+ return 0;
+ }
+ r = apk_extract_v3_file(ectx, 0, 0);
+ if (r != 0) return r;
+ } while (1);
+}
+
+static int apk_extract_v3_data_block(struct adb *db, struct adb_block *b, struct apk_istream *is)
+{
+ struct apk_extract_v3_ctx *ctx = container_of(db, struct apk_extract_v3_ctx, db);
+ struct apk_extract_ctx *ectx = ctx->ectx;
+ struct adb_data_package *hdr;
+ size_t sz = adb_block_length(b);
+ int r;
+
+ if (adb_block_type(b) != ADB_BLOCK_DATA) return 0;
+ if (db->schema != ADB_SCHEMA_PACKAGE) return -APKE_ADB_SCHEMA;
+ if (!ectx->ops->v3meta) return -APKE_FORMAT_NOT_SUPPORTED;
+
+ r = apk_extract_v3_next_file(ectx);
+ if (r != 0) {
+ if (r > 0) r = -APKE_ADB_BLOCK;
+ return r;
+ }
+
+ hdr = apk_istream_get(is, sizeof *hdr);
+ sz -= sizeof *hdr;
+ if (IS_ERR(hdr)) return PTR_ERR(hdr);
+
+ if (hdr->path_idx != ctx->cur_path ||
+ hdr->file_idx != ctx->cur_file ||
+ sz != adb_ro_int(&ctx->file, ADBI_FI_SIZE)) {
+ // got data for some unexpected file
+ return -APKE_ADB_BLOCK;
+ }
+
+ return apk_extract_v3_file(ectx, sz, is);
+}
+
+static int apk_extract_v3_verify_index(struct apk_extract_ctx *ectx, struct adb_obj *obj)
+{
+ return 0;
+}
+
+static int apk_extract_v3_verify_meta(struct apk_extract_ctx *ectx, struct adb_obj *obj)
+{
+ return 0;
+}
+
+static int apk_extract_v3_verify_file(struct apk_extract_ctx *ectx, const struct apk_file_info *fi, struct apk_istream *is)
+{
+ if (is) {
+ apk_istream_read(is, 0, fi->size);
+ return apk_istream_close(is);
+ }
+ return 0;
+}
+
+static const struct apk_extract_ops extract_v3verify_ops = {
+ .v3index = apk_extract_v3_verify_index,
+ .v3meta = apk_extract_v3_verify_meta,
+ .file = apk_extract_v3_verify_file,
+};
+
+int apk_extract_v3(struct apk_extract_ctx *ectx, struct apk_istream *is)
+{
+ struct apk_ctx *ac = ectx->ac;
+ struct apk_trust *trust = apk_ctx_get_trust(ac);
+ struct apk_extract_v3_ctx ctx = {
+ .ectx = ectx,
+ };
+ struct adb_obj obj;
+ int r;
+
+ if (IS_ERR(is)) return PTR_ERR(is);
+ if (!ectx->ops) ectx->ops = &extract_v3verify_ops;
+ if (!ectx->ops->v3meta && !ectx->ops->v3index)
+ return apk_istream_close_error(is, -APKE_FORMAT_NOT_SUPPORTED);
+
+ ectx->pctx = &ctx;
+ r = adb_m_process(&ctx.db, adb_decompress(is, 0),
+ ADB_SCHEMA_ANY, trust, apk_extract_v3_data_block);
+ if (r == 0) {
+ switch (ctx.db.schema) {
+ case ADB_SCHEMA_PACKAGE:
+ r = apk_extract_v3_next_file(ectx);
+ if (r == 0) r = -APKE_ADB_BLOCK;
+ if (r == 1) r = 0;
+ break;
+ case ADB_SCHEMA_INDEX:
+ if (!ectx->ops->v3index) {
+ r = -APKE_FORMAT_NOT_SUPPORTED;
+ break;
+ }
+ adb_r_rootobj(&ctx.db, &obj, &schema_index);
+ r = ectx->ops->v3index(ectx, &obj);
+ break;
+ default:
+ r = -APKE_ADB_SCHEMA;
+ break;
+ }
+ }
+ if (r == -ECANCELED) r = 0;
+ adb_free(&ctx.db);
+ apk_extract_reset(ectx);
+
+ return r;
+}
diff --git a/src/io.c b/src/io.c
index 9acf1e6..a8821e4 100644
--- a/src/io.c
+++ b/src/io.c
@@ -154,7 +154,7 @@ void *apk_istream_peek(struct apk_istream *is, size_t len)
void *apk_istream_get(struct apk_istream *is, size_t len)
{
void *p = apk_istream_peek(is, len);
- if (!IS_ERR_OR_NULL(p)) is->ptr += len;
+ if (!IS_ERR(p)) is->ptr += len;
else apk_istream_error(is, PTR_ERR(p));
return p;
}
@@ -174,7 +174,7 @@ int apk_istream_get_max(struct apk_istream *is, size_t max, apk_blob_t *data)
int apk_istream_get_delim(struct apk_istream *is, apk_blob_t token, apk_blob_t *data)
{
apk_blob_t ret = APK_BLOB_NULL, left = APK_BLOB_NULL;
- int r;
+ int r = 0;
do {
if (apk_blob_split(APK_BLOB_PTR_LEN((char*)is->ptr, is->end - is->ptr), token, &ret, &left))
@@ -302,6 +302,61 @@ struct apk_istream *apk_istream_segment(struct apk_segment_istream *sis, struct
return &sis->is;
}
+static void digest_get_meta(struct apk_istream *is, struct apk_file_meta *meta)
+{
+ struct apk_digest_istream *dis = container_of(is, struct apk_digest_istream, is);
+ return apk_istream_get_meta(dis->pis, meta);
+}
+
+static ssize_t digest_read(struct apk_istream *is, void *ptr, size_t size)
+{
+ struct apk_digest_istream *dis = container_of(is, struct apk_digest_istream, is);
+ ssize_t r;
+
+ r = dis->pis->ops->read(dis->pis, ptr, size);
+ if (r > 0) apk_digest_ctx_update(&dis->dctx, ptr, r);
+ return r;
+}
+
+static int digest_close(struct apk_istream *is)
+{
+ struct apk_digest_istream *dis = container_of(is, struct apk_digest_istream, is);
+
+ if (dis->digest) {
+ struct apk_digest res;
+ apk_digest_ctx_final(&dis->dctx, &res);
+ if (apk_digest_cmp(&res, dis->digest) != 0)
+ apk_istream_error(is, -APKE_FILE_INTEGRITY);
+ dis->digest = 0;
+ }
+ apk_digest_ctx_free(&dis->dctx);
+
+ return is->err < 0 ? is->err : 0;
+}
+
+static const struct apk_istream_ops digest_istream_ops = {
+ .get_meta = digest_get_meta,
+ .read = digest_read,
+ .close = digest_close,
+};
+
+struct apk_istream *apk_istream_verify(struct apk_digest_istream *dis, struct apk_istream *is, struct apk_digest *d)
+{
+ *dis = (struct apk_digest_istream) {
+ .is.ops = &digest_istream_ops,
+ .is.buf = is->buf,
+ .is.buf_size = is->buf_size,
+ .is.ptr = is->ptr,
+ .is.end = is->end,
+ .pis = is,
+ .digest = d,
+ };
+ apk_digest_ctx_init(&dis->dctx, d->alg);
+ if (dis->is.ptr != dis->is.end)
+ apk_digest_ctx_update(&dis->dctx, dis->is.ptr, dis->is.end - dis->is.ptr);
+ return &dis->is;
+}
+
struct apk_tee_istream {
struct apk_istream is;
struct apk_istream *inner_is;
@@ -540,7 +595,7 @@ struct apk_istream *__apk_istream_from_file(int atfd, const char *file, int try_
if (try_mmap) {
struct apk_istream *is = apk_mmap_istream_from_fd(fd);
- if (!IS_ERR_OR_NULL(is)) return is;
+ if (!IS_ERR(is)) return is;
}
return apk_istream_from_fd(fd);
}
@@ -761,7 +816,7 @@ int apk_fileinfo_get(int atfd, const char *filename, unsigned int flags,
apk_digest_calc(&fi->digest, hash_alg, target, st.st_size);
} else {
struct apk_istream *is = apk_istream_from_file(atfd, filename);
- if (!IS_ERR_OR_NULL(is)) {
+ if (!IS_ERR(is)) {
struct apk_digest_ctx dctx;
apk_blob_t blob;
@@ -940,7 +995,7 @@ struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode)
if (fd < 0) return ERR_PTR(-errno);
os = apk_ostream_to_fd(fd);
- if (IS_ERR_OR_NULL(os)) return ERR_CAST(os);
+ if (IS_ERR(os)) return ERR_CAST(os);
struct apk_fd_ostream *fos = container_of(os, struct apk_fd_ostream, os);
fos->file = file;
diff --git a/src/io_gunzip.c b/src/io_gunzip.c
index 4ad0b6c..e3ff178 100644
--- a/src/io_gunzip.c
+++ b/src/io_gunzip.c
@@ -146,7 +146,7 @@ struct apk_istream *apk_istream_zlib(struct apk_istream *is, int raw, apk_multip
{
struct apk_gzip_istream *gis;
- if (IS_ERR_OR_NULL(is)) return ERR_CAST(is);
+ if (IS_ERR(is)) return ERR_CAST(is);
gis = malloc(sizeof(*gis) + apk_io_bufsize);
if (!gis) goto err;
@@ -231,7 +231,7 @@ struct apk_ostream *apk_ostream_zlib(struct apk_ostream *output, int raw)
{
struct apk_gzip_ostream *gos;
- if (IS_ERR_OR_NULL(output)) return ERR_CAST(output);
+ if (IS_ERR(output)) return ERR_CAST(output);
gos = malloc(sizeof(struct apk_gzip_ostream));
if (gos == NULL) goto err;
diff --git a/src/meson.build b/src/meson.build
index 98b2461..3bdb477 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -14,15 +14,18 @@ libapk_src = [
'context.c',
'crypto_openssl.c',
'database.c',
+ 'extract.c',
+ 'extract_v2.c',
+ 'extract_v3.c',
'hash.c',
'io.c',
- 'io_archive.c',
'io_url.c',
'io_gunzip.c',
'package.c',
'pathbuilder.c',
'print.c',
'solver.c',
+ 'tar.c',
'trust.c',
'version.c',
]
@@ -30,11 +33,11 @@ libapk_src = [
libapk_headers = [
'apk_applet.h',
'apk_atom.h',
- 'apk_archive.h',
'apk_blob.h',
'apk_crypto.h',
'apk_database.h',
'apk_defines.h',
+ 'apk_extract.h',
'apk_hash.h',
'apk_io.h',
'apk_openssl.h',
@@ -44,6 +47,7 @@ libapk_headers = [
'apk_provider_data.h',
'apk_solver_data.h',
'apk_solver.h',
+ 'apk_tar.h',
'apk_version.h',
]
diff --git a/src/package.c b/src/package.c
index fd0104a..3b634d6 100644
--- a/src/package.c
+++ b/src/package.c
@@ -23,10 +23,10 @@
#include <openssl/pem.h>
#include "apk_defines.h"
-#include "apk_archive.h"
#include "apk_package.h"
#include "apk_database.h"
#include "apk_print.h"
+#include "apk_extract.h"
const apk_spn_match_def apk_spn_dependency_comparer = {
[7] = (1<<4) /*<*/ | (1<<5) /*=*/ | (1<<6) /*<*/,
@@ -470,301 +470,10 @@ int apk_script_type(const char *name)
return APK_SCRIPT_INVALID;
}
-void apk_sign_ctx_init(struct apk_sign_ctx *ctx, int action,
- struct apk_checksum *identity, struct apk_trust *trust)
-{
- memset(ctx, 0, sizeof(struct apk_sign_ctx));
- ctx->trust = trust;
- ctx->action = action;
- ctx->allow_untrusted = trust->allow_untrusted;
- switch (action) {
- case APK_SIGN_VERIFY:
- /* If we're only verifing, we're going to start with a
- * signature section, which we don't need a hash of */
- ctx->md = EVP_md_null();
- break;
- case APK_SIGN_VERIFY_IDENTITY:
- /* If we're checking the package against a particular hash,
- * we need to start with that hash, because there may not
- * be a signature section to deduce it from */
- ctx->md = EVP_sha1();
- memcpy(&ctx->identity, identity, sizeof(ctx->identity));
- break;
- case APK_SIGN_GENERATE:
- case APK_SIGN_VERIFY_AND_GENERATE:
- ctx->md = EVP_sha1();
- break;
- default:
- ctx->action = APK_SIGN_NONE;
- ctx->md = EVP_md_null();
- ctx->control_started = 1;
- ctx->data_started = 1;
- break;
- }
- ctx->mdctx = EVP_MD_CTX_new();
- EVP_DigestInit_ex(ctx->mdctx, ctx->md, NULL);
- EVP_MD_CTX_set_flags(ctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
-}
-
-void apk_sign_ctx_free(struct apk_sign_ctx *ctx)
-{
- if (ctx->signature.data.ptr != NULL)
- free(ctx->signature.data.ptr);
- EVP_MD_CTX_free(ctx->mdctx);
-}
-
-static int check_signing_key_trust(struct apk_sign_ctx *sctx)
-{
- switch (sctx->action) {
- case APK_SIGN_VERIFY:
- case APK_SIGN_VERIFY_AND_GENERATE:
- if (sctx->signature.pkey == NULL) {
- if (sctx->allow_untrusted)
- break;
- return -APKE_SIGNATURE_UNTRUSTED;
- }
- }
- return 0;
-}
-
-int apk_sign_ctx_process_file(struct apk_sign_ctx *ctx,
- const struct apk_file_info *fi,
- struct apk_istream *is)
-{
- static struct {
- char type[8];
- unsigned int nid;
- } signature_type[] = {
- { "RSA512", NID_sha512 },
- { "RSA256", NID_sha256 },
- { "RSA", NID_sha1 },
- { "DSA", NID_dsa },
- };
- const EVP_MD *md = NULL;
- const char *name = NULL;
- struct apk_pkey *pkey;
- int r, i;
-
- if (ctx->data_started)
- return 1;
-
- if (fi->name[0] != '.' || strchr(fi->name, '/') != NULL) {
- /* APKv1.0 compatibility - first non-hidden file is
- * considered to start the data section of the file.
- * This does not make any sense if the file has v2.0
- * style .PKGINFO */
- if (ctx->has_data_checksum)
- return -APKE_V2PKG_FORMAT;
- /* Error out early if identity part is missing */
- if (ctx->action == APK_SIGN_VERIFY_IDENTITY)
- return -APKE_V2PKG_FORMAT;
- ctx->data_started = 1;
- ctx->control_started = 1;
- r = check_signing_key_trust(ctx);
- if (r < 0)
- return r;
- return 1;
- }
-
- if (ctx->control_started)
- return 1;
-
- if (strncmp(fi->name, ".SIGN.", 6) != 0) {
- ctx->control_started = 1;
- return 1;
- }
-
- /* By this point, we must be handling a signature file */
- ctx->num_signatures++;
-
- /* Already found a signature by a trusted key; no need to keep searching */
- if ((ctx->action != APK_SIGN_VERIFY &&
- ctx->action != APK_SIGN_VERIFY_AND_GENERATE) ||
- ctx->signature.pkey != NULL)
- return 0;
-
- for (i = 0; i < ARRAY_SIZE(signature_type); i++) {
- size_t slen = strlen(signature_type[i].type);
- if (strncmp(&fi->name[6], signature_type[i].type, slen) == 0 &&
- fi->name[6+slen] == '.') {
- md = EVP_get_digestbynid(signature_type[i].nid);
- name = &fi->name[6+slen+1];
- break;
- }
- }
- if (!md) return 0;
-
- pkey = apk_trust_key_by_name(ctx->trust, name);
- if (pkey) {
- ctx->md = md;
- ctx->signature.pkey = pkey->key;
- ctx->signature.data = apk_blob_from_istream(is, fi->size);
- }
- return 0;
-}
-
-int apk_sign_ctx_parse_pkginfo_line(void *ctx, apk_blob_t line)
-{
- struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
- apk_blob_t l, r;
-
- if (!sctx->control_started || sctx->data_started)
- return 0;
-
- if (line.ptr == NULL || line.len < 1 || line.ptr[0] == '#')
- return 0;
-
- if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
- return 0;
-
- if (apk_blob_compare(APK_BLOB_STR("datahash"), l) == 0) {
- sctx->has_data_checksum = 1;
- sctx->md = EVP_sha256();
- apk_blob_pull_hexdump(
- &r, APK_BLOB_PTR_LEN(sctx->data_checksum,
- EVP_MD_size(sctx->md)));
- }
-
- return 0;
-}
-
-int apk_sign_ctx_verify_tar(void *sctx, const struct apk_file_info *fi,
- struct apk_istream *is)
-{
- struct apk_sign_ctx *ctx = (struct apk_sign_ctx *) sctx;
- int r;
-
- r = apk_sign_ctx_process_file(ctx, fi, is);
- if (r <= 0)
- return r;
-
- if (!ctx->control_started || ctx->data_started)
- return 0;
-
- if (strcmp(fi->name, ".PKGINFO") == 0) {
- apk_blob_t l, token = APK_BLOB_STR("\n");
- while (apk_istream_get_delim(is, token, &l) == 0)
- apk_sign_ctx_parse_pkginfo_line(ctx, l);
- }
-
- return 0;
-}
-
-/* apk_sign_ctx_mpart_cb() handles hashing archives and checking signatures, but
- it can't do it alone. apk_sign_ctx_process_file() must be in the loop to
- actually select which signature is to be verified and load the corresponding
- public key into the context object, and apk_sign_ctx_parse_pkginfo_line()
- needs to be called when handling the .PKGINFO file to find any applicable
- datahash and load it into the context for this function to check against. */
-int apk_sign_ctx_mpart_cb(void *ctx, int part, apk_blob_t data)
-{
- struct apk_sign_ctx *sctx = (struct apk_sign_ctx *) ctx;
- unsigned char calculated[EVP_MAX_MD_SIZE];
- int r, end_of_control;
-
- if ((part == APK_MPART_DATA) ||
- (part == APK_MPART_BOUNDARY && sctx->data_started))
- goto update_digest;
-
- /* Still in signature blocks? */
- if (!sctx->control_started) {
- if (part == APK_MPART_END)
- return -APKE_V2PKG_FORMAT;
- goto reset_digest;
- }
-
- /* Grab state and mark all remaining block as data */
- end_of_control = (sctx->data_started == 0);
- sctx->data_started = 1;
-
- /* End of control-block and control does not have data checksum? */
- if (sctx->has_data_checksum == 0 && end_of_control &&
- part != APK_MPART_END)
- goto update_digest;
-
- /* Drool in the remainder of the digest block now, we will finish
- * hashing it in all cases */
- EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
-
- if (sctx->has_data_checksum && !end_of_control) {
- /* End of data-block with a checksum read from the control block */
- EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
- if (EVP_MD_CTX_size(sctx->mdctx) == 0 ||
- memcmp(calculated, sctx->data_checksum,
- EVP_MD_CTX_size(sctx->mdctx)) != 0)
- return -APKE_V2PKG_INTEGRITY;
- sctx->data_verified = 1;
- if (!sctx->allow_untrusted && !sctx->control_verified)
- return -APKE_SIGNATURE_UNTRUSTED;
- return 0;
- }
-
- /* Either end of control block with a data checksum or end
- * of the data block following a control block without a data
- * checksum. In either case, we're checking a signature. */
- r = check_signing_key_trust(sctx);
- if (r < 0)
- return r;
-
- switch (sctx->action) {
- case APK_SIGN_VERIFY:
- case APK_SIGN_VERIFY_AND_GENERATE:
- if (sctx->signature.pkey != NULL) {
- r = EVP_VerifyFinal(sctx->mdctx,
- (unsigned char *) sctx->signature.data.ptr,
- sctx->signature.data.len,
- sctx->signature.pkey);
- if (r != 1 && !sctx->allow_untrusted)
- return -APKE_SIGNATURE_INVALID;
- } else {
- r = 0;
- if (!sctx->allow_untrusted)
- return -APKE_SIGNATURE_UNTRUSTED;
- }
- if (r == 1) {
- sctx->control_verified = 1;
- if (!sctx->has_data_checksum && part == APK_MPART_END)
- sctx->data_verified = 1;
- }
- if (sctx->action == APK_SIGN_VERIFY_AND_GENERATE) {
- sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
- EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
- }
- break;
- case APK_SIGN_VERIFY_IDENTITY:
- /* Reset digest for hashing data */
- EVP_DigestFinal_ex(sctx->mdctx, calculated, NULL);
- if (memcmp(calculated, sctx->identity.data,
- sctx->identity.type) != 0)
- return -APKE_V2PKG_INTEGRITY;
- sctx->control_verified = 1;
- if (!sctx->has_data_checksum && part == APK_MPART_END)
- sctx->data_verified = 1;
- break;
- case APK_SIGN_GENERATE:
- /* Package identity is the checksum */
- sctx->identity.type = EVP_MD_CTX_size(sctx->mdctx);
- EVP_DigestFinal_ex(sctx->mdctx, sctx->identity.data, NULL);
- if (sctx->action == APK_SIGN_GENERATE &&
- sctx->has_data_checksum)
- return -ECANCELED;
- break;
- }
-reset_digest:
- EVP_DigestInit_ex(sctx->mdctx, sctx->md, NULL);
- EVP_MD_CTX_set_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
- return 0;
-
-update_digest:
- EVP_MD_CTX_clear_flags(sctx->mdctx, EVP_MD_CTX_FLAG_ONESHOT);
- EVP_DigestUpdate(sctx->mdctx, data.ptr, data.len);
- return 0;
-}
-
struct read_info_ctx {
struct apk_database *db;
struct apk_package *pkg;
- struct apk_sign_ctx *sctx;
+ struct apk_extract_ctx ectx;
};
int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
@@ -840,7 +549,7 @@ int apk_pkg_add_info(struct apk_database *db, struct apk_package *pkg,
return 0;
}
-static int read_info_line(void *ctx, apk_blob_t line)
+static int read_info_line(struct read_info_ctx *ri, apk_blob_t line)
{
static struct {
const char *str;
@@ -862,7 +571,6 @@ static int read_info_line(void *ctx, apk_blob_t line)
{ "commit", 'c' },
{ "provider_priority", 'k' },
};
- struct read_info_ctx *ri = (struct read_info_ctx *) ctx;
apk_blob_t l, r;
int i;
@@ -872,47 +580,32 @@ static int read_info_line(void *ctx, apk_blob_t line)
if (!apk_blob_split(line, APK_BLOB_STR(" = "), &l, &r))
return 0;
+ apk_extract_v2_control(&ri->ectx, l, r);
+
for (i = 0; i < ARRAY_SIZE(fields); i++) {
if (apk_blob_compare(APK_BLOB_STR(fields[i].str), l) == 0) {
apk_pkg_add_info(ri->db, ri->pkg, fields[i].field, r);
return 0;
}
}
- apk_sign_ctx_parse_pkginfo_line(ri->sctx, line);
return 0;
}
-static int read_info_entry(void *ctx, 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 = (struct read_info_ctx *) ctx;
- struct apk_package *pkg = ri->pkg;
- int r;
-
- r = apk_sign_ctx_process_file(ri->sctx, ae, is);
- if (r <= 0)
- return r;
-
- if (!ri->sctx->control_started || ri->sctx->data_started)
- 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(ctx, l);
- } else if (strcmp(ae->name, ".INSTALL") == 0) {
- apk_warn(&ri->db->ctx->out,
- "Package '%s-%s' contains deprecated .INSTALL",
- pkg->name->name, pkg->version);
- }
-
+ struct read_info_ctx *ri = container_of(ectx, struct read_info_ctx, ectx);
+ 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;
}
-int apk_pkg_read(struct apk_database *db, const char *file,
- struct apk_sign_ctx *sctx, struct apk_package **pkg)
+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;
struct apk_file_info fi;
@@ -924,25 +617,21 @@ int apk_pkg_read(struct apk_database *db, const char *file,
memset(&ctx, 0, sizeof(ctx));
ctx.db = db;
- ctx.sctx = sctx;
ctx.pkg = apk_pkg_new();
r = -ENOMEM;
if (ctx.pkg == NULL)
goto err;
ctx.pkg->size = fi.size;
+ apk_extract_init(&ctx.ectx, db->ctx, &extract_pkgmeta_ops);
+ apk_extract_generate_identity(&ctx.ectx, &ctx.pkg->csum);
- r = apk_tar_parse(
- apk_istream_gunzip_mpart(apk_istream_from_file(AT_FDCWD, file), apk_sign_ctx_mpart_cb, sctx),
- read_info_entry, &ctx, db->id_cache);
- if (r < 0 && r != -ECANCELED)
- goto err;
+ r = apk_extract(&ctx.ectx, apk_istream_from_file(AT_FDCWD, file));
+ if (r < 0) goto err;
if (ctx.pkg->name == NULL || ctx.pkg->uninstallable) {
r = -ENOTSUP;
goto err;
}
- if (sctx->action != APK_SIGN_VERIFY)
- ctx.pkg->csum = sctx->identity;
ctx.pkg->filename = strdup(file);
ctx.pkg = apk_db_pkg_add(db, ctx.pkg);
diff --git a/src/print.c b/src/print.c
index 1248995..ea66b90 100644
--- a/src/print.c
+++ b/src/print.c
@@ -39,6 +39,7 @@ const char *apk_error_str(int error)
case APKE_SIGNATURE_FAIL: return "signing failure";
case APKE_SIGNATURE_UNTRUSTED: return "UNTRUSTED signature";
case APKE_SIGNATURE_INVALID: return "BAD signature";
+ case APKE_FORMAT_NOT_SUPPORTED: return "file format not supported (in this applet)";
case APKE_ADB_COMPRESSION: return "ADB compression not supported";
case APKE_ADB_HEADER: return "ADB header error";
case APKE_ADB_VERSION: return "incompatible ADB version";
diff --git a/src/io_archive.c b/src/tar.c
index ccd512a..e682dda 100644
--- a/src/io_archive.c
+++ b/src/tar.c
@@ -1,4 +1,4 @@
-/* io_archive.c - Alpine Package Keeper (APK)
+/* tar.c - Alpine Package Keeper (APK)
*
* Copyright (C) 2005-2008 Natanael Copa <n@tanael.org>
* Copyright (C) 2008-2011 Timo Teräs <timo.teras@iki.fi>
@@ -7,27 +7,12 @@
* SPDX-License-Identifier: GPL-2.0-only
*/
-#include <stdio.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <utime.h>
-#include <string.h>
-#include <unistd.h>
-#include <sysexits.h>
-#include <sys/wait.h>
#include <sys/stat.h>
-#include <sys/xattr.h>
#include <sys/sysmacros.h>
#include <limits.h>
-#include <stdint.h>
-#include <stdlib.h>
#include "apk_defines.h"
-#include "apk_print.h"
-#include "apk_archive.h"
-#include "apk_openssl.h"
+#include "apk_tar.h"
struct tar_header {
/* ustar header, Posix 1003.1 */
@@ -49,21 +34,24 @@ struct tar_header {
char padding[12]; /* 500-511 */
};
-#define TAR_BLOB(s) APK_BLOB_PTR_LEN(s, strnlen(s, sizeof(s)))
-#define GET_OCTAL(s) get_octal(s, sizeof(s))
-#define PUT_OCTAL(s,v) put_octal(s, sizeof(s), v)
+#define TAR_BLOB(s) APK_BLOB_PTR_LEN(s, strnlen(s, sizeof(s)))
+#define GET_OCTAL(s,r) get_octal(s, sizeof(s), r)
+#define PUT_OCTAL(s,v,hz) put_octal(s, sizeof(s), v, hz)
-static unsigned int get_octal(char *s, size_t l)
+static unsigned int get_octal(char *s, size_t l, int *r)
{
apk_blob_t b = APK_BLOB_PTR_LEN(s, l);
- return apk_blob_pull_uint(&b, 8);
+ unsigned int val = apk_blob_pull_uint(&b, 8);
+ while (b.len >= 1 && b.ptr[0] == 0) b.ptr++, b.len--;
+ if (b.len != 0) *r = -APKE_V2PKG_FORMAT;
+ return val;
}
-static void put_octal(char *s, size_t l, size_t value)
+static void put_octal(char *s, size_t l, size_t value, int has_zero)
{
char *ptr = &s[l - 1];
- *(ptr--) = '\0';
+ if (has_zero) *(ptr--) = '\0';
while (value != 0 && ptr >= s) {
*(ptr--) = '0' + (value % 8);
value /= 8;
@@ -137,7 +125,7 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
apk_blob_t pax = APK_BLOB_NULL, longname = APK_BLOB_NULL;
char filename[sizeof buf.name + sizeof buf.prefix + 2];
- if (IS_ERR_OR_NULL(is)) return PTR_ERR(is) ?: -EINVAL;
+ if (IS_ERR(is)) return PTR_ERR(is);
memset(&entry, 0, sizeof(entry));
entry.name = buf.name;
@@ -147,20 +135,27 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
end++;
continue;
}
+ if (memcmp(buf.magic, "ustar", 5) != 0) {
+ r = -APKE_V2PKG_FORMAT;
+ goto err;
+ }
+ r = 0;
entry = (struct apk_file_info){
- .size = GET_OCTAL(buf.size),
- .uid = apk_id_cache_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
- .gid = apk_id_cache_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
- .mode = GET_OCTAL(buf.mode) & 07777,
- .mtime = GET_OCTAL(buf.mtime),
+ .size = GET_OCTAL(buf.size, &r),
+ .uid = apk_id_cache_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid, &r)),
+ .gid = apk_id_cache_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid, &r)),
+ .mode = GET_OCTAL(buf.mode, &r) & 07777,
+ .mtime = GET_OCTAL(buf.mtime, &r),
.name = entry.name,
.uname = buf.uname,
.gname = buf.gname,
- .device = makedev(GET_OCTAL(buf.devmajor),
- GET_OCTAL(buf.devminor)),
+ .device = makedev(GET_OCTAL(buf.devmajor, &r),
+ GET_OCTAL(buf.devminor, &r)),
.xattrs = entry.xattrs,
};
+ if (r != 0) goto err;
+
if (buf.prefix[0] && buf.typeflag != 'x' && buf.typeflag != 'g') {
snprintf(filename, sizeof filename, "%.*s/%.*s",
(int) sizeof buf.prefix, buf.prefix,
@@ -287,11 +282,11 @@ int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae,
strlcpy(buf.uname, ae->uname ?: "root", sizeof buf.uname);
strlcpy(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 ?: time(NULL));
+ PUT_OCTAL(buf.size, ae->size, 0);
+ PUT_OCTAL(buf.uid, ae->uid, 1);
+ PUT_OCTAL(buf.gid, ae->gid, 1);
+ PUT_OCTAL(buf.mode, ae->mode & 07777, 1);
+ PUT_OCTAL(buf.mtime, ae->mtime ?: apk_get_build_time(), 0);
/* Checksum */
strcpy(buf.magic, "ustar ");
@@ -299,7 +294,7 @@ int apk_tar_write_entry(struct apk_ostream *os, const struct apk_file_info *ae,
src = (const unsigned char *) &buf;
for (i = chksum = 0; i < sizeof(buf); i++)
chksum += src[i];
- put_octal(buf.chksum, sizeof(buf.chksum)-1, chksum);
+ put_octal(buf.chksum, sizeof(buf.chksum)-1, chksum, 1);
}
if (apk_ostream_write(os, &buf, sizeof(buf)) < 0)
@@ -331,111 +326,3 @@ int apk_tar_write_padding(struct apk_ostream *os, const struct apk_file_info *ae
return 0;
}
-
-int apk_archive_entry_extract(int atfd, const struct apk_file_info *ae,
- const char *extract_name, const char *link_target,
- struct apk_istream *is,
- apk_progress_cb cb, void *cb_ctx, struct apk_digest_ctx *dctx,
- unsigned int extract_flags, struct apk_out *out)
-{
- struct apk_xattr *xattr;
- const char *fn = extract_name ?: ae->name;
- int fd, r = -1, atflags = 0, ret = 0;
-
- if (!(extract_flags & APK_EXTRACTF_NO_OVERWRITE)) {
- if (unlinkat(atfd, fn, 0) != 0 && errno != ENOENT) return -errno;
- }
-
- switch (ae->mode & S_IFMT) {
- case S_IFDIR:
- r = mkdirat(atfd, fn, ae->mode & 07777);
- if (r < 0 && errno != EEXIST)
- ret = -errno;
- break;
- case S_IFREG:
- if (ae->link_target == NULL) {
- int flags = O_RDWR | O_CREAT | O_TRUNC | O_CLOEXEC | O_EXCL;
- struct apk_ostream *os = apk_ostream_to_fd(openat(atfd, fn, flags, ae->mode & 07777));
- apk_stream_copy(is, os, ae->size, cb, cb_ctx, dctx);
- r = apk_ostream_close(os);
- if (r < 0) ret = r;
- } else {
- r = linkat(atfd, link_target ?: ae->link_target, atfd, fn, 0);
- if (r < 0) ret = -errno;
- }
- break;
- case S_IFLNK:
- r = symlinkat(link_target ?: ae->link_target, atfd, fn);
- if (r < 0) ret = -errno;
- atflags |= AT_SYMLINK_NOFOLLOW;
- break;
- case S_IFBLK:
- case S_IFCHR:
- case S_IFIFO:
- r = mknodat(atfd, fn, ae->mode, ae->device);
- if (r < 0) ret = -errno;
- break;
- }
- if (ret) {
- apk_err(out, "Failed to create %s: %s", ae->name, strerror(-ret));
- return ret;
- }
-
- if (!(extract_flags & APK_EXTRACTF_NO_CHOWN)) {
- r = fchownat(atfd, fn, ae->uid, ae->gid, atflags);
- if (r < 0) {
- apk_err(out, "Failed to set ownership on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
-
- /* chown resets suid bit so we need set it again */
- if (ae->mode & 07000) {
- r = fchmodat(atfd, fn, ae->mode & 07777, atflags);
- if (r < 0) {
- apk_err(out, "Failed to set file permissions on %s: %s",
- fn, strerror(errno));
- if (!ret) ret = -errno;
- }
- }
- }
-
- /* extract xattrs */
- if (!S_ISLNK(ae->mode) && ae->xattrs && ae->xattrs->num) {
- r = 0;
- fd = openat(atfd, fn, O_RDWR);
- if (fd >= 0) {
- foreach_array_item(xattr, ae->xattrs) {
- if (fsetxattr(fd, xattr->name, xattr->value.ptr, xattr->value.len, 0) < 0) {
- r = -errno;
- if (r != -ENOTSUP) break;
- }
- }
- close(fd);
- } else {
- r = -errno;
- }
- if (r) {
- if (r != -ENOTSUP)
- apk_err(out, "Failed to set xattrs on %s: %s",
- fn, strerror(-r));
- if (!ret) ret = r;
- }
- }
-
- if (!S_ISLNK(ae->mode)) {
- /* preserve modification time */
- struct timespec times[2];
-
- times[0].tv_sec = times[1].tv_sec = ae->mtime;
- times[0].tv_nsec = times[1].tv_nsec = 0;
- r = utimensat(atfd, fn, times, atflags);
- if (r < 0) {
- apk_err(out, "Failed to preserve modification time on %s: %s",
- fn, strerror(errno));
- if (!ret || ret == -ENOTSUP) ret = -errno;
- }
- }
-
- return ret;
-}
diff --git a/src/trust.c b/src/trust.c
index 5e2a956..c65377d 100644
--- a/src/trust.c
+++ b/src/trust.c
@@ -32,21 +32,19 @@ static int __apk_trust_load_pubkey(void *pctx, int dirfd, const char *filename)
return 0;
}
-int apk_trust_init(struct apk_trust *trust, int dirfd, struct apk_string_array *pkey_files)
+void apk_trust_init(struct apk_trust *trust)
{
- char **fn;
-
*trust = (struct apk_trust){};
apk_digest_ctx_init(&trust->dctx, APK_DIGEST_NONE);
list_init(&trust->trusted_key_list);
list_init(&trust->private_key_list);
- trust->initialized = 1;
- apk_dir_foreach_file(dirfd, __apk_trust_load_pubkey, trust);
+}
- foreach_array_item(fn, pkey_files) {
- struct apk_trust_key *key = apk_trust_load_key(AT_FDCWD, *fn);
- if (IS_ERR(key)) return PTR_ERR(key);
- list_add_tail(&key->key_node, &trust->private_key_list);
+int apk_trust_load_keys(struct apk_trust *trust, int dirfd)
+{
+ if (!trust->keys_loaded) {
+ trust->keys_loaded = 1;
+ apk_dir_foreach_file(dirfd, __apk_trust_load_pubkey, trust);
}
return 0;
@@ -66,8 +64,6 @@ static void __apk_trust_free_keys(struct list_head *h)
void apk_trust_free(struct apk_trust *trust)
{
- if (!trust->initialized) return;
- trust->initialized = 0;
__apk_trust_free_keys(&trust->trusted_key_list);
__apk_trust_free_keys(&trust->private_key_list);
apk_digest_ctx_free(&trust->dctx);
@@ -95,9 +91,19 @@ APK_OPT_GROUP(options_signing, "Signing", SIGNING_OPTIONS);
static int option_parse_signing(void *ctx, struct apk_ctx *ac, int optch, const char *optarg)
{
+ struct apk_trust *trust = &ac->trust;
+ struct apk_out *out = &ac->out;
+ struct apk_trust_key *key;
+
switch (optch) {
case OPT_SIGN_sign_key:
- *apk_string_array_add(&ac->private_keys) = (char*) optarg;
+ key = apk_trust_load_key(AT_FDCWD, optarg);
+ if (IS_ERR(key)) {
+ apk_err(out, "Failed to load signing key: %s: %s",
+ optarg, apk_error_str(PTR_ERR(key)));
+ return PTR_ERR(key);
+ }
+ list_add_tail(&key->key_node, &trust->private_key_list);
break;
default:
return -ENOTSUP;
diff --git a/test/Makefile b/test/Makefile
index 9834668..a48387d 100644
--- a/test/Makefile
+++ b/test/Makefile
@@ -50,9 +50,9 @@ repos.stamp: $(repos)
fi; \
if ! APK="$(APK)" ROOT="$(testroot)" SYSREPO="$(SYSREPO)" sh -ex ./$< > $(basename $@).out 2>&1; then\
echo " FAIL";\
- printf "------------- output -------------\n" >&2;\
+ printf '%s\n' "------------- output -------------" >&2;\
cat $(basename $@).out >&2;\
- printf "----------------------------------\n" >&2;\
+ printf '%s\n' "----------------------------------" >&2;\
exit 1;\
fi ;\
echo " OK" ;\
diff --git a/test/basic8.test b/test/basic8.test
index 19d3964..0042371 100644
--- a/test/basic8.test
+++ b/test/basic8.test
@@ -2,5 +2,6 @@
--no-network
add -t .virtual
@EXPECT
+WARNING: creating empty virtual package
(1/1) Installing .virtual (20190603.131426)
OK: 0 MiB in 0 packages
diff --git a/test/solver.sh b/test/solver.sh
index d14d89d..4c9f50d 100755
--- a/test/solver.sh
+++ b/test/solver.sh
@@ -10,9 +10,9 @@ TEST_TO_RUN="$@"
fail=0
pass=0
for test in ${TEST_TO_RUN:-*.test}; do
- get_block ARGS < $test | xargs $APK_TEST &> .$test.got
+ get_block ARGS < $test | xargs $APK_TEST > .$test.got 2>&1
- if ! get_block EXPECT < $test | cmp .$test.got &> /dev/null; then
+ if ! get_block EXPECT < $test | cmp .$test.got > /dev/null 2>&1; then
fail=$((fail+1))
echo "FAIL: $test"
get_block EXPECT < $test | diff -ru - .$test.got
diff --git a/test/version.sh b/test/version.sh
index 18199a6..628a6eb 100755
--- a/test/version.sh
+++ b/test/version.sh
@@ -9,7 +9,7 @@ cat version.data | while read a result b rest ; do
fi
done
-if [ "$fail" == "0" ]; then
+if [ "$fail" = "0" ]; then
echo "OK: version checking works"
fi