mkpkg: new applet to create v2 packages with basic functionality
parent
cd9aef8f7c
commit
7c9f001cda
90
src/adb.c
90
src/adb.c
|
@ -13,13 +13,16 @@
|
||||||
#include "apk_blob.h"
|
#include "apk_blob.h"
|
||||||
#include "apk_trust.h"
|
#include "apk_trust.h"
|
||||||
|
|
||||||
|
static char padding_zeroes[ADB_BLOCK_ALIGNMENT] = {0};
|
||||||
|
|
||||||
/* Block enumeration */
|
/* Block enumeration */
|
||||||
static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b)
|
static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b)
|
||||||
{
|
{
|
||||||
size_t pos = (char *)blk - b.ptr;
|
size_t pos = (char *)blk - b.ptr;
|
||||||
if (pos == b.len) return NULL;
|
if (pos == b.len) return NULL;
|
||||||
pos += sizeof(struct adb_block);
|
if (sizeof(struct adb_block) > b.len - pos) return ERR_PTR(-EBADMSG);
|
||||||
if (pos > b.len || ADB_BLOCK_SIZE(blk) > b.len - pos) return ERR_PTR(-EBADMSG);
|
if (adb_block_rawsize(blk) < sizeof(struct adb_block)) return ERR_PTR(-EBADMSG);
|
||||||
|
if (adb_block_size(blk) > b.len - pos) return ERR_PTR(-EBADMSG);
|
||||||
return blk;
|
return blk;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -30,7 +33,7 @@ struct adb_block *adb_block_first(apk_blob_t b)
|
||||||
|
|
||||||
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b)
|
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b)
|
||||||
{
|
{
|
||||||
return adb_block_validate((struct adb_block*)((char*)cur + sizeof(struct adb_block) + ADB_BLOCK_SIZE(cur)), b);
|
return adb_block_validate((struct adb_block*)((char*)cur + adb_block_size(cur)), b);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Init stuff */
|
/* Init stuff */
|
||||||
|
@ -71,8 +74,8 @@ static int __adb_m_parse(struct adb *db, struct apk_trust *t)
|
||||||
int trusted = t ? 0 : 1;
|
int trusted = t ? 0 : 1;
|
||||||
|
|
||||||
adb_foreach_block(blk, db->data) {
|
adb_foreach_block(blk, db->data) {
|
||||||
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
|
apk_blob_t b = adb_block_blob(blk);
|
||||||
switch (ADB_BLOCK_TYPE(blk)) {
|
switch (adb_block_type(blk)) {
|
||||||
case ADB_BLOCK_ADB:
|
case ADB_BLOCK_ADB:
|
||||||
if (!APK_BLOB_IS_NULL(db->adb)) break;
|
if (!APK_BLOB_IS_NULL(db->adb)) break;
|
||||||
db->adb = b;
|
db->adb = b;
|
||||||
|
@ -575,13 +578,12 @@ copy:
|
||||||
adb_val_t adb_w_adb(struct adb *db, struct adb *valdb)
|
adb_val_t adb_w_adb(struct adb *db, struct adb *valdb)
|
||||||
{
|
{
|
||||||
uint32_t bsz;
|
uint32_t bsz;
|
||||||
struct adb_block blk = {
|
struct adb_block blk = adb_block_init(ADB_BLOCK_ADB, valdb->adb.len);
|
||||||
.type_size = htole32((ADB_BLOCK_ADB << 30) + valdb->adb.len)
|
|
||||||
};
|
|
||||||
struct iovec vec[] = {
|
struct iovec vec[] = {
|
||||||
{ .iov_base = &bsz, .iov_len = sizeof bsz },
|
{ .iov_base = &bsz, .iov_len = sizeof bsz },
|
||||||
{ .iov_base = &blk, .iov_len = sizeof blk },
|
{ .iov_base = &blk, .iov_len = sizeof blk },
|
||||||
{ .iov_base = valdb->adb.ptr, .iov_len = valdb->adb.len },
|
{ .iov_base = valdb->adb.ptr, .iov_len = valdb->adb.len },
|
||||||
|
{ .iov_base = padding_zeroes, .iov_len = adb_block_padding(&blk) },
|
||||||
};
|
};
|
||||||
if (valdb->adb.len <= 4) return ADB_NULL;
|
if (valdb->adb.len <= 4) return ADB_NULL;
|
||||||
bsz = htole32(iovec_len(vec, ARRAY_SIZE(vec)) - sizeof bsz);
|
bsz = htole32(iovec_len(vec, ARRAY_SIZE(vec)) - sizeof bsz);
|
||||||
|
@ -817,9 +819,8 @@ int adb_c_header(struct apk_ostream *os, struct adb *db)
|
||||||
|
|
||||||
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
|
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
|
||||||
{
|
{
|
||||||
struct adb_block blk = {
|
struct adb_block blk = adb_block_init(type, val.len);
|
||||||
.type_size = htole32((type << 30) + val.len)
|
size_t padding = adb_block_padding(&blk);
|
||||||
};
|
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
r = apk_ostream_write(os, &blk, sizeof blk);
|
r = apk_ostream_write(os, &blk, sizeof blk);
|
||||||
|
@ -827,6 +828,39 @@ int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t val)
|
||||||
|
|
||||||
r = apk_ostream_write(os, val.ptr, val.len);
|
r = apk_ostream_write(os, val.ptr, val.len);
|
||||||
if (r < 0) return r;
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
if (padding) {
|
||||||
|
r = apk_ostream_write(os, padding_zeroes, padding);
|
||||||
|
if (r < 0) return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is)
|
||||||
|
{
|
||||||
|
struct adb_block blk = adb_block_init(ADB_BLOCK_DATA, size + hdr.len);
|
||||||
|
size_t padding = adb_block_padding(&blk);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
if (IS_ERR(os)) return PTR_ERR(os);
|
||||||
|
if (IS_ERR(is)) return apk_ostream_cancel(os, PTR_ERR(is));
|
||||||
|
|
||||||
|
r = apk_ostream_write(os, &blk, sizeof blk);
|
||||||
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
r = apk_ostream_write(os, hdr.ptr, hdr.len);
|
||||||
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
r = apk_stream_copy(is, os, size, 0, 0, 0);
|
||||||
|
if (r < 0) return r;
|
||||||
|
|
||||||
|
if (padding) {
|
||||||
|
r = apk_ostream_write(os, padding_zeroes, padding);
|
||||||
|
if (r < 0) return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
apk_istream_close(is);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -842,7 +876,7 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist
|
||||||
mdctx = EVP_MD_CTX_new();
|
mdctx = EVP_MD_CTX_new();
|
||||||
EVP_DigestInit_ex(mdctx, EVP_sha512(), 0);
|
EVP_DigestInit_ex(mdctx, EVP_sha512(), 0);
|
||||||
}
|
}
|
||||||
r = apk_stream_copy(is, os, ADB_BLOCK_SIZE(b), 0, 0, mdctx);
|
r = apk_stream_copy(is, os, adb_block_size(b), 0, 0, mdctx);
|
||||||
if (vfy) {
|
if (vfy) {
|
||||||
EVP_DigestFinal_ex(mdctx, vfy->sha512, 0);
|
EVP_DigestFinal_ex(mdctx, vfy->sha512, 0);
|
||||||
EVP_MD_CTX_free(mdctx);
|
EVP_MD_CTX_free(mdctx);
|
||||||
|
@ -851,17 +885,23 @@ int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_ist
|
||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
|
int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
|
||||||
{
|
{
|
||||||
if (IS_ERR(os)) return PTR_ERR(os);
|
if (IS_ERR(os))
|
||||||
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) {
|
return apk_ostream_cancel(os, PTR_ERR(os));
|
||||||
apk_ostream_cancel(os, -EAPKFORMAT);
|
if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC))
|
||||||
goto ret;
|
return apk_ostream_cancel(os, -EAPKFORMAT);
|
||||||
}
|
|
||||||
adb_c_header(os, db);
|
adb_c_header(os, db);
|
||||||
adb_c_block(os, ADB_BLOCK_ADB, db->adb);
|
adb_c_block(os, ADB_BLOCK_ADB, db->adb);
|
||||||
if (t) adb_trust_write_signatures(t, db, NULL, os);
|
if (t) adb_trust_write_signatures(t, db, NULL, os);
|
||||||
ret:
|
|
||||||
|
return apk_ostream_error(os);
|
||||||
|
}
|
||||||
|
|
||||||
|
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t)
|
||||||
|
{
|
||||||
|
adb_c_adb(os, db, t);
|
||||||
return apk_ostream_close(os);
|
return apk_ostream_close(os);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -922,8 +962,7 @@ int adb_trust_write_signatures(struct apk_trust *trust, struct adb *db, struct a
|
||||||
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
|
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
|
||||||
if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
|
if (EVP_DigestSignInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, &sig.v0, sizeof sig.v0) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 ||
|
|
||||||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
|
||||||
EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) {
|
EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) {
|
||||||
ERR_print_errors_fp(stdout);
|
ERR_print_errors_fp(stdout);
|
||||||
|
@ -962,8 +1001,7 @@ int adb_trust_verify_signature(struct apk_trust *trust, struct adb *db, struct a
|
||||||
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
|
EVP_MD_CTX_set_pkey_ctx(trust->mdctx, NULL);
|
||||||
if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
|
if (EVP_DigestVerifyInit(trust->mdctx, NULL, EVP_sha512(), NULL, tkey->key.key) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, &db->hdr, sizeof db->hdr) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &sig->sign_ver, sizeof sig->sign_ver) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, sig0, sizeof *sig0) != 1 ||
|
||||||
EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 ||
|
|
||||||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
|
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
|
||||||
EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) {
|
EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) {
|
||||||
ERR_clear_error();
|
ERR_clear_error();
|
||||||
|
@ -998,16 +1036,16 @@ int adb_c_xfrm(struct adb_xfrm *x, int (*cb)(struct adb_xfrm *, struct adb_block
|
||||||
goto err;
|
goto err;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ((block_no++ == 0) != (ADB_BLOCK_TYPE(&blk) == ADB_BLOCK_ADB)) goto bad_msg;
|
if ((block_no++ == 0) != (adb_block_type(&blk) == ADB_BLOCK_ADB)) goto bad_msg;
|
||||||
|
|
||||||
sz = ADB_BLOCK_SIZE(&blk);
|
sz = adb_block_size(&blk) - sizeof blk;
|
||||||
r = cb(x, &blk, apk_istream_segment(&seg, x->is, sz, 0));
|
r = cb(x, &blk, apk_istream_segment(&seg, x->is, sz, 0));
|
||||||
if (r < 0) goto err;
|
if (r < 0) goto err;
|
||||||
|
|
||||||
if (r == 0 && seg.bytes_left == sz) {
|
if (r == 0 && seg.bytes_left == sz) {
|
||||||
r = apk_ostream_write(x->os, &blk, sizeof blk);
|
r = apk_ostream_write(x->os, &blk, sizeof blk);
|
||||||
if (r < 0) goto err;
|
if (r < 0) goto err;
|
||||||
r = apk_stream_copy(x->is, x->os, seg.bytes_left, 0, 0, 0);
|
r = apk_stream_copy(x->is, x->os, sz, 0, 0, 0);
|
||||||
if (r < 0) goto err;
|
if (r < 0) goto err;
|
||||||
} else if (seg.bytes_left > 0) {
|
} else if (seg.bytes_left > 0) {
|
||||||
r = apk_istream_read(x->is, NULL, sz - seg.bytes_left);
|
r = apk_istream_read(x->is, NULL, sz - seg.bytes_left);
|
||||||
|
|
22
src/adb.h
22
src/adb.h
|
@ -51,17 +51,29 @@ struct adb_header {
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Blocks */
|
/* Blocks */
|
||||||
|
#define ADB_BLOCK_ALIGNMENT 8
|
||||||
#define ADB_BLOCK_END -1
|
#define ADB_BLOCK_END -1
|
||||||
#define ADB_BLOCK_ADB 0
|
#define ADB_BLOCK_ADB 0
|
||||||
#define ADB_BLOCK_SIG 2
|
#define ADB_BLOCK_SIG 2
|
||||||
|
#define ADB_BLOCK_DATA 3
|
||||||
#define ADB_BLOCK_TYPE(b) (le32toh((b)->type_size) >> 30)
|
|
||||||
#define ADB_BLOCK_SIZE(b) (le32toh((b)->type_size) & 0x3fffffff)
|
|
||||||
|
|
||||||
struct adb_block {
|
struct adb_block {
|
||||||
uint32_t type_size;
|
uint32_t type_size;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static inline struct adb_block adb_block_init(uint32_t type, uint32_t length) {
|
||||||
|
return (struct adb_block) { .type_size = htole32((type << 30) + sizeof(struct adb_block) + length)};
|
||||||
|
}
|
||||||
|
static inline uint32_t adb_block_type(struct adb_block *b) { return le32toh((b)->type_size) >> 30; }
|
||||||
|
static inline uint32_t adb_block_rawsize(struct adb_block *b) { return le32toh((b)->type_size) & 0x3fffffff; }
|
||||||
|
static inline uint32_t adb_block_size(struct adb_block *b) { return ROUND_UP(adb_block_rawsize(b), ADB_BLOCK_ALIGNMENT); }
|
||||||
|
static inline uint32_t adb_block_length(struct adb_block *b) { return adb_block_rawsize(b) - sizeof(struct adb_block); }
|
||||||
|
static inline uint32_t adb_block_padding(struct adb_block *b) { return adb_block_size(b) - adb_block_rawsize(b); }
|
||||||
|
static inline void *adb_block_payload(struct adb_block *b) { return b + 1; }
|
||||||
|
static inline apk_blob_t adb_block_blob(struct adb_block *b) {
|
||||||
|
return APK_BLOB_PTR_LEN(adb_block_payload(b), adb_block_length(b));
|
||||||
|
}
|
||||||
|
|
||||||
struct adb_sign_hdr {
|
struct adb_sign_hdr {
|
||||||
uint8_t sign_ver, hash_alg;
|
uint8_t sign_ver, hash_alg;
|
||||||
};
|
};
|
||||||
|
@ -81,7 +93,6 @@ struct adb_sign_v0 {
|
||||||
/* Block enumeration */
|
/* Block enumeration */
|
||||||
struct adb_block *adb_block_first(apk_blob_t b);
|
struct adb_block *adb_block_first(apk_blob_t b);
|
||||||
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b);
|
struct adb_block *adb_block_next(struct adb_block *cur, apk_blob_t b);
|
||||||
|
|
||||||
#define adb_foreach_block(__blk, __adb) \
|
#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); !IS_ERR_OR_NULL(__blk); __blk = adb_block_next(__blk, __adb))
|
||||||
|
|
||||||
|
@ -218,7 +229,9 @@ int adb_s_field_by_name(const struct adb_object_schema *, const char *);
|
||||||
/* Creation */
|
/* Creation */
|
||||||
int adb_c_header(struct apk_ostream *os, struct adb *db);
|
int adb_c_header(struct apk_ostream *os, struct adb *db);
|
||||||
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t);
|
int adb_c_block(struct apk_ostream *os, uint32_t type, apk_blob_t);
|
||||||
|
int adb_c_block_data(struct apk_ostream *os, apk_blob_t hdr, uint32_t size, struct apk_istream *is);
|
||||||
int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *);
|
int adb_c_block_copy(struct apk_ostream *os, struct adb_block *b, struct apk_istream *is, struct adb_verify_ctx *);
|
||||||
|
int adb_c_adb(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
|
||||||
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
|
int adb_c_create(struct apk_ostream *os, struct adb *db, struct apk_trust *t);
|
||||||
|
|
||||||
/* Trust */
|
/* Trust */
|
||||||
|
@ -279,6 +292,7 @@ struct adb_walk_gentext {
|
||||||
struct adb_walk_genadb {
|
struct adb_walk_genadb {
|
||||||
struct adb_walk d;
|
struct adb_walk d;
|
||||||
struct adb db;
|
struct adb db;
|
||||||
|
adb_val_t stored_object;
|
||||||
struct adb idb[ADB_WALK_GENADB_MAX_IDB];
|
struct adb idb[ADB_WALK_GENADB_MAX_IDB];
|
||||||
int nest, nestdb, num_vals;
|
int nest, nestdb, num_vals;
|
||||||
struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING];
|
struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING];
|
||||||
|
|
|
@ -107,11 +107,10 @@ static int dump_object(struct adb_walk_ctx *ctx, const struct adb_object_schema
|
||||||
|
|
||||||
static int dump_adb(struct adb_walk_ctx *ctx)
|
static int dump_adb(struct adb_walk_ctx *ctx)
|
||||||
{
|
{
|
||||||
char tmp[256];
|
char tmp[512];
|
||||||
struct adb_block *blk;
|
struct adb_block *blk;
|
||||||
struct adb_sign_hdr *s;
|
struct adb_sign_hdr *s;
|
||||||
struct adb_verify_ctx vfy = {};
|
struct adb_verify_ctx vfy = {};
|
||||||
unsigned char *id;
|
|
||||||
uint32_t schema_magic = ctx->db->hdr.schema;
|
uint32_t schema_magic = ctx->db->hdr.schema;
|
||||||
const struct adb_db_schema *ds;
|
const struct adb_db_schema *ds;
|
||||||
struct adb_walk *d = ctx->d;
|
struct adb_walk *d = ctx->d;
|
||||||
|
@ -121,10 +120,10 @@ static int dump_adb(struct adb_walk_ctx *ctx)
|
||||||
if (ds->magic == schema_magic) break;
|
if (ds->magic == schema_magic) break;
|
||||||
|
|
||||||
adb_foreach_block(blk, ctx->db->data) {
|
adb_foreach_block(blk, ctx->db->data) {
|
||||||
apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
|
apk_blob_t b = adb_block_blob(blk);
|
||||||
switch (ADB_BLOCK_TYPE(blk)) {
|
switch (adb_block_type(blk)) {
|
||||||
case ADB_BLOCK_ADB:
|
case ADB_BLOCK_ADB:
|
||||||
len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", ADB_BLOCK_SIZE(blk));
|
len = snprintf(tmp, sizeof tmp, "ADB block, size: %u", adb_block_length(blk));
|
||||||
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
if (ds->root) {
|
if (ds->root) {
|
||||||
ctx->db->adb = b;
|
ctx->db->adb = b;
|
||||||
|
@ -134,23 +133,19 @@ static int dump_adb(struct adb_walk_ctx *ctx)
|
||||||
case ADB_BLOCK_SIG:
|
case ADB_BLOCK_SIG:
|
||||||
s = (struct adb_sign_hdr*) b.ptr;
|
s = (struct adb_sign_hdr*) b.ptr;
|
||||||
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
|
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
|
||||||
|
len = snprintf(tmp, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
|
||||||
len = snprintf(tmp, sizeof tmp, "signature: v%d ", s->sign_ver);
|
for (size_t j = sizeof *s; j < b.len; j++)
|
||||||
switch (s->sign_ver) {
|
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)b.ptr[j]);
|
||||||
case 0:
|
|
||||||
id = (unsigned char*)(s + 1);
|
|
||||||
for (size_t j = 0; j < 16; j++)
|
|
||||||
len += snprintf(&tmp[len], sizeof tmp - len, "%02x", id[j]);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK");
|
len += snprintf(&tmp[len], sizeof tmp - len, ": %s", r ? apk_error_str(r) : "OK");
|
||||||
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
break;
|
break;
|
||||||
|
case ADB_BLOCK_DATA:
|
||||||
|
len = snprintf(tmp, sizeof tmp, "data block, size: %d", adb_block_length(blk));
|
||||||
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %d",
|
len = snprintf(tmp, sizeof tmp, "unknown block %d, size: %d",
|
||||||
ADB_BLOCK_TYPE(blk), ADB_BLOCK_SIZE(blk));
|
adb_block_type(blk), adb_block_length(blk));
|
||||||
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
d->ops->comment(d, APK_BLOB_PTR_LEN(tmp, len));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -74,7 +74,7 @@ static int adb_walk_genadb_end(struct adb_walk *d)
|
||||||
dt->num_vals -= dt->objs[dt->nest].schema->num_fields;
|
dt->num_vals -= dt->objs[dt->nest].schema->num_fields;
|
||||||
|
|
||||||
if (dt->nest == 0) {
|
if (dt->nest == 0) {
|
||||||
adb_w_root(&dt->db, val);
|
dt->stored_object = val;
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -422,17 +422,16 @@ const struct adb_object_schema schema_index = {
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t file_get_default_int(unsigned i)
|
const struct adb_object_schema schema_acl = {
|
||||||
{
|
.kind = ADB_KIND_OBJECT,
|
||||||
switch (i) {
|
.num_fields = ADBI_ACL_MAX,
|
||||||
case ADBI_FI_UID:
|
.fields = {
|
||||||
case ADBI_FI_GID:
|
ADB_FIELD(ADBI_ACL_MODE, "mode", scalar_oct),
|
||||||
return 0;
|
ADB_FIELD(ADBI_ACL_USER, "user", scalar_string),
|
||||||
case ADBI_FI_MODE:
|
ADB_FIELD(ADBI_ACL_GROUP, "group", scalar_string),
|
||||||
return 0644;
|
//ADB_FIELD(ADBI_ACL_XATTRS, "xattr", schema_string_array),
|
||||||
}
|
},
|
||||||
return -1;
|
};
|
||||||
}
|
|
||||||
|
|
||||||
static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
|
static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
|
||||||
{
|
{
|
||||||
|
@ -442,15 +441,14 @@ static int file_cmp(const struct adb_obj *o1, const struct adb_obj *o2)
|
||||||
const struct adb_object_schema schema_file = {
|
const struct adb_object_schema schema_file = {
|
||||||
.kind = ADB_KIND_OBJECT,
|
.kind = ADB_KIND_OBJECT,
|
||||||
.num_fields = ADBI_FI_MAX,
|
.num_fields = ADBI_FI_MAX,
|
||||||
.get_default_int = file_get_default_int,
|
|
||||||
.compare = file_cmp,
|
.compare = file_cmp,
|
||||||
.fields = {
|
.fields = {
|
||||||
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
|
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
|
||||||
|
ADB_FIELD(ADBI_FI_ACL, "acl", schema_acl),
|
||||||
|
ADB_FIELD(ADBI_FI_SIZE, "size", scalar_int),
|
||||||
|
ADB_FIELD(ADBI_FI_MTIME, "mtime", scalar_int),
|
||||||
ADB_FIELD(ADBI_FI_HASHES, "hash", scalar_hexblob),
|
ADB_FIELD(ADBI_FI_HASHES, "hash", scalar_hexblob),
|
||||||
ADB_FIELD(ADBI_FI_UID, "uid", scalar_int),
|
ADB_FIELD(ADBI_FI_TARGET, "target", scalar_string),
|
||||||
ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
|
|
||||||
ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
|
|
||||||
ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -461,38 +459,22 @@ const struct adb_object_schema schema_file_array = {
|
||||||
.fields = ADB_ARRAY_ITEM(schema_file),
|
.fields = ADB_ARRAY_ITEM(schema_file),
|
||||||
};
|
};
|
||||||
|
|
||||||
static uint32_t path_get_default_int(unsigned i)
|
const struct adb_object_schema schema_dir = {
|
||||||
{
|
|
||||||
switch (i) {
|
|
||||||
case ADBI_FI_UID:
|
|
||||||
case ADBI_FI_GID:
|
|
||||||
return 0;
|
|
||||||
case ADBI_FI_MODE:
|
|
||||||
return 0755;
|
|
||||||
}
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const struct adb_object_schema schema_path = {
|
|
||||||
.kind = ADB_KIND_OBJECT,
|
.kind = ADB_KIND_OBJECT,
|
||||||
.num_fields = ADBI_FI_MAX,
|
.num_fields = ADBI_DI_MAX,
|
||||||
.get_default_int = path_get_default_int,
|
|
||||||
.compare = file_cmp,
|
.compare = file_cmp,
|
||||||
.fields = {
|
.fields = {
|
||||||
ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
|
ADB_FIELD(ADBI_DI_NAME, "name", scalar_string),
|
||||||
ADB_FIELD(ADBI_FI_FILES, "files", schema_file_array),
|
ADB_FIELD(ADBI_DI_ACL, "acl", schema_acl),
|
||||||
ADB_FIELD(ADBI_FI_UID, "uid", scalar_int),
|
ADB_FIELD(ADBI_DI_FILES, "files", schema_file_array),
|
||||||
ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
|
|
||||||
ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
|
|
||||||
ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
|
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct adb_object_schema schema_path_array = {
|
const struct adb_object_schema schema_dir_array = {
|
||||||
.kind = ADB_KIND_ARRAY,
|
.kind = ADB_KIND_ARRAY,
|
||||||
.pre_commit = adb_wa_sort,
|
.pre_commit = adb_wa_sort,
|
||||||
.num_fields = APK_MAX_MANIFEST_PATHS,
|
.num_fields = APK_MAX_MANIFEST_PATHS,
|
||||||
.fields = ADB_ARRAY_ITEM(schema_path),
|
.fields = ADB_ARRAY_ITEM(schema_dir),
|
||||||
};
|
};
|
||||||
|
|
||||||
const struct adb_object_schema schema_scripts = {
|
const struct adb_object_schema schema_scripts = {
|
||||||
|
@ -520,7 +502,7 @@ const struct adb_object_schema schema_package = {
|
||||||
.compare = package_cmp,
|
.compare = package_cmp,
|
||||||
.fields = {
|
.fields = {
|
||||||
ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo),
|
ADB_FIELD(ADBI_PKG_PKGINFO, "info", schema_pkginfo),
|
||||||
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_path_array),
|
ADB_FIELD(ADBI_PKG_PATHS, "paths", schema_dir_array),
|
||||||
ADB_FIELD(ADBI_PKG_SCRIPTS, "scripts", schema_scripts),
|
ADB_FIELD(ADBI_PKG_SCRIPTS, "scripts", schema_scripts),
|
||||||
ADB_FIELD(ADBI_PKG_TRIGGERS, "triggers", schema_string_array),
|
ADB_FIELD(ADBI_PKG_TRIGGERS, "triggers", schema_string_array),
|
||||||
//ADB_FIELD(ADBI_PKG_PASSWD, "passwd", schema_string_array),
|
//ADB_FIELD(ADBI_PKG_PASSWD, "passwd", schema_string_array),
|
||||||
|
|
|
@ -33,16 +33,28 @@
|
||||||
#define ADBI_PI_RECOMMENDS 0x13
|
#define ADBI_PI_RECOMMENDS 0x13
|
||||||
#define ADBI_PI_MAX 0x14
|
#define ADBI_PI_MAX 0x14
|
||||||
|
|
||||||
|
/* ACL entries */
|
||||||
|
#define ADBI_ACL_MODE 0x01
|
||||||
|
#define ADBI_ACL_USER 0x02
|
||||||
|
#define ADBI_ACL_GROUP 0x03
|
||||||
|
#define ADBI_ACL_XATTRS 0x04
|
||||||
|
#define ADBI_ACL_MAX 0x05
|
||||||
|
|
||||||
/* File Info */
|
/* File Info */
|
||||||
#define ADBI_FI_NAME 0x01
|
#define ADBI_FI_NAME 0x01
|
||||||
#define ADBI_FI_HASHES 0x02
|
#define ADBI_FI_ACL 0x02
|
||||||
#define ADBI_FI_FILES 0x02
|
#define ADBI_FI_SIZE 0x03
|
||||||
#define ADBI_FI_MODE 0x03
|
#define ADBI_FI_MTIME 0x04
|
||||||
#define ADBI_FI_UID 0x04
|
#define ADBI_FI_HASHES 0x05
|
||||||
#define ADBI_FI_GID 0x05
|
#define ADBI_FI_TARGET 0x06
|
||||||
#define ADBI_FI_XATTRS 0x06
|
|
||||||
#define ADBI_FI_MAX 0x07
|
#define ADBI_FI_MAX 0x07
|
||||||
|
|
||||||
|
/* Directory Info */
|
||||||
|
#define ADBI_DI_NAME 0x01
|
||||||
|
#define ADBI_DI_ACL 0x02
|
||||||
|
#define ADBI_DI_FILES 0x03
|
||||||
|
#define ADBI_DI_MAX 0x04
|
||||||
|
|
||||||
/* Scripts */
|
/* Scripts */
|
||||||
#define ADBI_SCRPT_TRIGGER 0x01
|
#define ADBI_SCRPT_TRIGGER 0x01
|
||||||
#define ADBI_SCRPT_PREINST 0x02
|
#define ADBI_SCRPT_PREINST 0x02
|
||||||
|
@ -81,7 +93,7 @@
|
||||||
extern const struct adb_object_schema
|
extern const struct adb_object_schema
|
||||||
schema_dependency, schema_dependency_array,
|
schema_dependency, schema_dependency_array,
|
||||||
schema_pkginfo, schema_pkginfo_array,
|
schema_pkginfo, schema_pkginfo_array,
|
||||||
schema_file, schema_file_array, schema_path, schema_path_array,
|
schema_acl, schema_file, schema_file_array, schema_dir, schema_dir_array,
|
||||||
schema_string_array, schema_scripts, schema_package, schema_package_adb_array,
|
schema_string_array, schema_scripts, schema_package, schema_package_adb_array,
|
||||||
schema_index, schema_idb;
|
schema_index, schema_idb;
|
||||||
|
|
||||||
|
|
|
@ -191,14 +191,14 @@ APK_ARRAY(apk_string_array, char *);
|
||||||
#define LIST_POISON1 (void *) 0xdeadbeef
|
#define LIST_POISON1 (void *) 0xdeadbeef
|
||||||
#define LIST_POISON2 (void *) 0xabbaabba
|
#define LIST_POISON2 (void *) 0xabbaabba
|
||||||
|
|
||||||
struct hlist_head {
|
|
||||||
struct hlist_node *first;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct hlist_node {
|
struct hlist_node {
|
||||||
struct hlist_node *next;
|
struct hlist_node *next;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct hlist_head {
|
||||||
|
struct hlist_node *first;
|
||||||
|
};
|
||||||
|
|
||||||
static inline int hlist_empty(const struct hlist_head *h)
|
static inline int hlist_empty(const struct hlist_head *h)
|
||||||
{
|
{
|
||||||
return !h->first;
|
return !h->first;
|
||||||
|
|
18
src/apk_io.h
18
src/apk_io.h
|
@ -15,14 +15,17 @@
|
||||||
|
|
||||||
#include "apk_defines.h"
|
#include "apk_defines.h"
|
||||||
#include "apk_blob.h"
|
#include "apk_blob.h"
|
||||||
#include "apk_hash.h"
|
|
||||||
#include "apk_atom.h"
|
#include "apk_atom.h"
|
||||||
|
|
||||||
|
struct apk_id_hash {
|
||||||
|
int empty;
|
||||||
|
struct hlist_head by_id[16], by_name[16];
|
||||||
|
};
|
||||||
|
|
||||||
struct apk_id_cache {
|
struct apk_id_cache {
|
||||||
int root_fd;
|
int root_fd;
|
||||||
unsigned int genid;
|
struct apk_id_hash uid_cache;
|
||||||
struct apk_hash uid_cache;
|
struct apk_id_hash gid_cache;
|
||||||
struct apk_hash gid_cache;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct apk_xattr {
|
struct apk_xattr {
|
||||||
|
@ -148,6 +151,7 @@ struct apk_ostream *apk_ostream_to_fd(int fd);
|
||||||
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
|
struct apk_ostream *apk_ostream_to_file(int atfd, const char *file, mode_t mode);
|
||||||
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);
|
struct apk_ostream *apk_ostream_to_file_gz(int atfd, const char *file, const char *tmpfile, mode_t mode);
|
||||||
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
|
size_t apk_ostream_write_string(struct apk_ostream *ostream, const char *string);
|
||||||
|
static inline int apk_ostream_error(struct apk_ostream *os) { return os->rc; }
|
||||||
static inline int apk_ostream_cancel(struct apk_ostream *os, int rc) { if (!os->rc) os->rc = rc; return rc; }
|
static inline int apk_ostream_cancel(struct apk_ostream *os, int rc) { if (!os->rc) os->rc = rc; return rc; }
|
||||||
static inline ssize_t apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size)
|
static inline ssize_t apk_ostream_write(struct apk_ostream *os, const void *buf, size_t size)
|
||||||
{
|
{
|
||||||
|
@ -181,7 +185,9 @@ const char *apk_url_local_file(const char *url);
|
||||||
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd);
|
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd);
|
||||||
void apk_id_cache_free(struct apk_id_cache *idc);
|
void apk_id_cache_free(struct apk_id_cache *idc);
|
||||||
void apk_id_cache_reset(struct apk_id_cache *idc);
|
void apk_id_cache_reset(struct apk_id_cache *idc);
|
||||||
uid_t apk_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid);
|
uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid);
|
||||||
uid_t apk_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, uid_t default_gid);
|
gid_t apk_id_cache_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, gid_t default_gid);
|
||||||
|
apk_blob_t apk_id_cache_resolve_user(struct apk_id_cache *idc, uid_t uid);
|
||||||
|
apk_blob_t apk_id_cache_resolve_group(struct apk_id_cache *idc, gid_t gid);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,44 @@
|
||||||
|
/* apk_pathbuilder.h - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef APK_PATHBUILDER_H
|
||||||
|
#define APK_PATHBUILDER_H
|
||||||
|
|
||||||
|
#include "apk_blob.h"
|
||||||
|
|
||||||
|
struct apk_pathbuilder {
|
||||||
|
uint16_t namelen;
|
||||||
|
char name[PATH_MAX];
|
||||||
|
};
|
||||||
|
|
||||||
|
int apk_pathbuilder_pushb(struct apk_pathbuilder *pb, apk_blob_t b);
|
||||||
|
void apk_pathbuilder_pop(struct apk_pathbuilder *pb);
|
||||||
|
|
||||||
|
|
||||||
|
static inline int apk_pathbuilder_setb(struct apk_pathbuilder *pb, apk_blob_t b)
|
||||||
|
{
|
||||||
|
pb->namelen = 0;
|
||||||
|
return apk_pathbuilder_pushb(pb, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline int apk_pathbuilder_push(struct apk_pathbuilder *pb, const char *name)
|
||||||
|
{
|
||||||
|
return apk_pathbuilder_pushb(pb, APK_BLOB_STR(name));
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline const char *apk_pathbuilder_cstr(const struct apk_pathbuilder *pb)
|
||||||
|
{
|
||||||
|
return pb->name;
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline apk_blob_t apk_pathbuilder_get(const struct apk_pathbuilder *pb)
|
||||||
|
{
|
||||||
|
return APK_BLOB_PTR_LEN((void*)pb->name, pb->namelen);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
|
@ -68,8 +68,10 @@ static int adbgen_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *
|
||||||
adb_w_init_alloca(&genadb.idb[0], 0, 100);
|
adb_w_init_alloca(&genadb.idb[0], 0, 100);
|
||||||
foreach_array_item(arg, args) {
|
foreach_array_item(arg, args) {
|
||||||
adb_reset(&genadb.db);
|
adb_reset(&genadb.db);
|
||||||
|
adb_reset(&genadb.idb[0]);
|
||||||
r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg));
|
r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg));
|
||||||
if (!r) {
|
if (!r) {
|
||||||
|
adb_w_root(&genadb.db, genadb.stored_object);
|
||||||
r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db,
|
r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db,
|
||||||
apk_ctx_get_trust(ac));
|
apk_ctx_get_trust(ac));
|
||||||
}
|
}
|
||||||
|
|
|
@ -44,7 +44,7 @@ static int update_signatures(struct adb_xfrm *xfrm, struct adb_block *blk, struc
|
||||||
struct apk_trust *trust = apk_ctx_get_trust(ctx->ac);
|
struct apk_trust *trust = apk_ctx_get_trust(ctx->ac);
|
||||||
int r;
|
int r;
|
||||||
|
|
||||||
switch (blk ? ADB_BLOCK_TYPE(blk) : -1) {
|
switch (blk ? adb_block_type(blk) : -1) {
|
||||||
case ADB_BLOCK_ADB:
|
case ADB_BLOCK_ADB:
|
||||||
return adb_c_block_copy(xfrm->os, blk, is, &xfrm->vfy);
|
return adb_c_block_copy(xfrm->os, blk, is, &xfrm->vfy);
|
||||||
case ADB_BLOCK_SIG:
|
case ADB_BLOCK_SIG:
|
||||||
|
|
|
@ -18,6 +18,7 @@ struct conv_script {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct conv_ctx {
|
struct conv_ctx {
|
||||||
|
struct apk_ctx *ac;
|
||||||
struct apk_atom_pool atoms;
|
struct apk_atom_pool atoms;
|
||||||
struct adb_obj pkgs;
|
struct adb_obj pkgs;
|
||||||
|
|
||||||
|
@ -100,8 +101,9 @@ static int read_triggers(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
|
|
||||||
static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
|
static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
{
|
{
|
||||||
|
struct apk_id_cache *idc = apk_ctx_get_id_cache(ctx->ac);
|
||||||
struct apk_checksum csum;
|
struct apk_checksum csum;
|
||||||
struct adb_obj pkg, pkginfo, files, file, paths, path, scripts, triggers;
|
struct adb_obj pkg, pkginfo, files, file, paths, path, scripts, triggers, acl;
|
||||||
apk_blob_t l, val, spc = APK_BLOB_STR(" "), nl = APK_BLOB_STR("\n");
|
apk_blob_t l, val, spc = APK_BLOB_STR(" "), nl = APK_BLOB_STR("\n");
|
||||||
struct conv_script *s;
|
struct conv_script *s;
|
||||||
int i;
|
int i;
|
||||||
|
@ -111,14 +113,15 @@ static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
adb_wo_alloca(&pkginfo, &schema_pkginfo, &ctx->dbp);
|
adb_wo_alloca(&pkginfo, &schema_pkginfo, &ctx->dbp);
|
||||||
adb_wo_alloca(&files, &schema_file_array, &ctx->dbp);
|
adb_wo_alloca(&files, &schema_file_array, &ctx->dbp);
|
||||||
adb_wo_alloca(&file, &schema_file, &ctx->dbp);
|
adb_wo_alloca(&file, &schema_file, &ctx->dbp);
|
||||||
adb_wo_alloca(&paths, &schema_path_array, &ctx->dbp);
|
adb_wo_alloca(&paths, &schema_dir_array, &ctx->dbp);
|
||||||
adb_wo_alloca(&path, &schema_path, &ctx->dbp);
|
adb_wo_alloca(&path, &schema_dir, &ctx->dbp);
|
||||||
adb_wo_alloca(&pkg, &schema_package, &ctx->dbp);
|
adb_wo_alloca(&pkg, &schema_package, &ctx->dbp);
|
||||||
|
adb_wo_alloca(&acl, &schema_acl, &ctx->dbp);
|
||||||
|
|
||||||
while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, nl))) {
|
while (!APK_BLOB_IS_NULL(l = apk_istream_get_delim(is, nl))) {
|
||||||
if (l.len < 2) {
|
if (l.len < 2) {
|
||||||
adb_wa_append_obj(&files, &file);
|
adb_wa_append_obj(&files, &file);
|
||||||
adb_wo_obj(&path, ADBI_FI_FILES, &files);
|
adb_wo_obj(&path, ADBI_DI_FILES, &files);
|
||||||
adb_wa_append_obj(&paths, &path);
|
adb_wa_append_obj(&paths, &path);
|
||||||
|
|
||||||
adb_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkginfo);
|
adb_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkginfo);
|
||||||
|
@ -152,28 +155,30 @@ static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
|
||||||
break;
|
break;
|
||||||
case 'F': // directory name
|
case 'F': // directory name
|
||||||
adb_wa_append_obj(&files, &file);
|
adb_wa_append_obj(&files, &file);
|
||||||
adb_wo_obj(&path, ADBI_FI_FILES, &files);
|
adb_wo_obj(&path, ADBI_DI_FILES, &files);
|
||||||
adb_wa_append_obj(&paths, &path);
|
adb_wa_append_obj(&paths, &path);
|
||||||
|
|
||||||
adb_wo_blob(&path, ADBI_FI_NAME, val);
|
adb_wo_blob(&path, ADBI_DI_NAME, val);
|
||||||
break;
|
break;
|
||||||
case 'M': // directory mode: uid:gid:mode:xattrcsum
|
case 'M': // directory mode: uid:gid:mode:xattrcsum
|
||||||
adb_wo_int(&path, ADBI_FI_UID, apk_blob_pull_uint(&val, 10));
|
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, apk_blob_pull_uint(&val, 10)));
|
||||||
apk_blob_pull_char(&val, ':');
|
apk_blob_pull_char(&val, ':');
|
||||||
adb_wo_int(&path, ADBI_FI_GID, apk_blob_pull_uint(&val, 10));
|
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, apk_blob_pull_uint(&val, 10)));
|
||||||
apk_blob_pull_char(&val, ':');
|
apk_blob_pull_char(&val, ':');
|
||||||
adb_wo_int(&path, ADBI_FI_MODE, apk_blob_pull_uint(&val, 8));
|
adb_wo_int(&acl, ADBI_ACL_MODE, apk_blob_pull_uint(&val, 8));
|
||||||
|
adb_wo_obj(&path, ADBI_DI_ACL, &acl);
|
||||||
break;
|
break;
|
||||||
case 'R': // file name
|
case 'R': // file name
|
||||||
adb_wa_append_obj(&files, &file);
|
adb_wa_append_obj(&files, &file);
|
||||||
adb_wo_blob(&file, ADBI_FI_NAME, val);
|
adb_wo_blob(&file, ADBI_FI_NAME, val);
|
||||||
break;
|
break;
|
||||||
case 'a': // file mode: uid:gid:mode:xattrcsum
|
case 'a': // file mode: uid:gid:mode:xattrcsum
|
||||||
adb_wo_int(&file, ADBI_FI_UID, apk_blob_pull_uint(&val, 10));
|
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, apk_blob_pull_uint(&val, 10)));
|
||||||
apk_blob_pull_char(&val, ':');
|
apk_blob_pull_char(&val, ':');
|
||||||
adb_wo_int(&file, ADBI_FI_GID, apk_blob_pull_uint(&val, 10));
|
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, apk_blob_pull_uint(&val, 10)));
|
||||||
apk_blob_pull_char(&val, ':');
|
apk_blob_pull_char(&val, ':');
|
||||||
adb_wo_int(&file, ADBI_FI_MODE, apk_blob_pull_uint(&val, 8));
|
adb_wo_int(&acl, ADBI_ACL_MODE, apk_blob_pull_uint(&val, 8));
|
||||||
|
adb_wo_obj(&file, ADBI_FI_ACL, &acl);
|
||||||
break;
|
break;
|
||||||
case 'Z': // file content hash
|
case 'Z': // file content hash
|
||||||
apk_blob_pull_csum(&val, &csum);
|
apk_blob_pull_csum(&val, &csum);
|
||||||
|
@ -196,6 +201,7 @@ static int conv_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *ar
|
||||||
int r;
|
int r;
|
||||||
int root_fd = apk_ctx_fd_root(ac);
|
int root_fd = apk_ctx_fd_root(ac);
|
||||||
|
|
||||||
|
ctx->ac = ac;
|
||||||
list_init(&ctx->script_head);
|
list_init(&ctx->script_head);
|
||||||
apk_atom_init(&ctx->atoms);
|
apk_atom_init(&ctx->atoms);
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,284 @@
|
||||||
|
/* app_mkpkg.c - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2008-2021 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
|
* under the terms of the GNU General Public License version 2 as published
|
||||||
|
* by the Free Software Foundation. See http://www.gnu.org/ for details.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#include "apk_defines.h"
|
||||||
|
#include "apk_adb.h"
|
||||||
|
#include "apk_applet.h"
|
||||||
|
#include "apk_database.h"
|
||||||
|
#include "apk_pathbuilder.h"
|
||||||
|
#include "apk_print.h"
|
||||||
|
|
||||||
|
#define BLOCK_SIZE 4096
|
||||||
|
|
||||||
|
struct mkpkg_ctx {
|
||||||
|
struct apk_ctx *ac;
|
||||||
|
const char *files_dir, *output;
|
||||||
|
struct adb db;
|
||||||
|
struct adb_obj paths, *files;
|
||||||
|
struct apk_sign_ctx sctx;
|
||||||
|
apk_blob_t info[ADBI_PI_MAX];
|
||||||
|
uint64_t installed_size;
|
||||||
|
struct apk_pathbuilder pb;
|
||||||
|
};
|
||||||
|
|
||||||
|
#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") \
|
||||||
|
|
||||||
|
APK_OPT_APPLET(option_desc, MKPKG_OPTIONS);
|
||||||
|
|
||||||
|
static int option_parse_applet(void *ctx, struct apk_ctx *ac, int optch, const char *optarg)
|
||||||
|
{
|
||||||
|
struct apk_out *out = &ac->out;
|
||||||
|
struct mkpkg_ctx *ictx = ctx;
|
||||||
|
apk_blob_t l, r;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
switch (optch) {
|
||||||
|
case OPT_MKPKG_info:
|
||||||
|
apk_blob_split(APK_BLOB_STR(optarg), APK_BLOB_STRLIT(":"), &l, &r);
|
||||||
|
i = adb_s_field_by_name_blob(&schema_pkginfo, l);
|
||||||
|
if (!i || i == ADBI_PI_FILE_SIZE || i == ADBI_PI_INSTALLED_SIZE) {
|
||||||
|
apk_err(out, "invalid pkginfo field: " BLOB_FMT, BLOB_PRINTF(l));
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
ictx->info[i] = r;
|
||||||
|
break;
|
||||||
|
case OPT_MKPKG_files:
|
||||||
|
ictx->files_dir = optarg;
|
||||||
|
break;
|
||||||
|
case OPT_MKPKG_output:
|
||||||
|
ictx->output = optarg;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
return -ENOTSUP;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static const struct apk_option_group optgroup_applet = {
|
||||||
|
.desc = option_desc,
|
||||||
|
.parse = option_parse_applet,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry);
|
||||||
|
|
||||||
|
static int mkpkg_process_directory(struct mkpkg_ctx *ctx, int dirfd, struct apk_file_info *fi)
|
||||||
|
{
|
||||||
|
struct apk_ctx *ac = ctx->ac;
|
||||||
|
struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
|
||||||
|
struct apk_out *out = &ac->out;
|
||||||
|
struct adb_obj acl, fio, files, *prev_files;
|
||||||
|
apk_blob_t dirname = apk_pathbuilder_get(&ctx->pb);
|
||||||
|
int r;
|
||||||
|
|
||||||
|
adb_wo_alloca(&fio, &schema_dir, &ctx->db);
|
||||||
|
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
|
||||||
|
adb_wo_blob(&fio, ADBI_DI_NAME, dirname);
|
||||||
|
adb_wo_int(&acl, ADBI_ACL_MODE, fi->mode & ~S_IFMT);
|
||||||
|
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi->uid));
|
||||||
|
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi->gid));
|
||||||
|
adb_wo_obj(&fio, ADBI_DI_ACL, &acl);
|
||||||
|
|
||||||
|
adb_wo_alloca(&files, &schema_file_array, &ctx->db);
|
||||||
|
prev_files = ctx->files;
|
||||||
|
ctx->files = &files;
|
||||||
|
r = apk_dir_foreach_file(dirfd, mkpkg_process_dirent, ctx);
|
||||||
|
ctx->files = prev_files;
|
||||||
|
if (r) {
|
||||||
|
apk_err(out, "failed to process directory '%s': %d",
|
||||||
|
apk_pathbuilder_cstr(&ctx->pb), r);
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
adb_wo_obj(&fio, ADBI_DI_FILES, &files);
|
||||||
|
adb_wa_append_obj(&ctx->paths, &fio);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry)
|
||||||
|
{
|
||||||
|
struct mkpkg_ctx *ctx = pctx;
|
||||||
|
struct apk_ctx *ac = ctx->ac;
|
||||||
|
struct apk_out *out = &ac->out;
|
||||||
|
struct apk_id_cache *idc = apk_ctx_get_id_cache(ac);
|
||||||
|
struct apk_file_info fi;
|
||||||
|
struct adb_obj fio, acl;
|
||||||
|
int r;
|
||||||
|
|
||||||
|
r = apk_fileinfo_get(dirfd, entry, APK_FI_NOFOLLOW | APK_FI_CSUM(APK_CHECKSUM_SHA1), &fi, NULL);
|
||||||
|
if (r) return r;
|
||||||
|
|
||||||
|
switch (fi.mode & S_IFMT) {
|
||||||
|
case S_IFDIR:
|
||||||
|
apk_pathbuilder_push(&ctx->pb, entry);
|
||||||
|
r = mkpkg_process_directory(ctx, openat(dirfd, entry, O_RDONLY), &fi);
|
||||||
|
apk_pathbuilder_pop(&ctx->pb);
|
||||||
|
break;
|
||||||
|
case S_IFREG:
|
||||||
|
adb_wo_alloca(&fio, &schema_file, &ctx->db);
|
||||||
|
adb_wo_alloca(&acl, &schema_acl, &ctx->db);
|
||||||
|
adb_wo_blob(&fio, ADBI_FI_NAME, APK_BLOB_STR(entry));
|
||||||
|
adb_wo_blob(&fio, ADBI_FI_HASHES, APK_BLOB_PTR_LEN((char*) fi.csum.data, fi.csum.type));
|
||||||
|
adb_wo_int(&fio, ADBI_FI_MTIME, fi.mtime);
|
||||||
|
adb_wo_int(&fio, ADBI_FI_SIZE, fi.size);
|
||||||
|
ctx->installed_size += (fi.size + BLOCK_SIZE - 1) & ~(BLOCK_SIZE-1);
|
||||||
|
|
||||||
|
adb_wo_int(&acl, ADBI_ACL_MODE, fi.mode & 07777);
|
||||||
|
adb_wo_blob(&acl, ADBI_ACL_USER, apk_id_cache_resolve_user(idc, fi.uid));
|
||||||
|
adb_wo_blob(&acl, ADBI_ACL_GROUP, apk_id_cache_resolve_group(idc, fi.gid));
|
||||||
|
adb_wo_obj(&fio, ADBI_FI_ACL, &acl);
|
||||||
|
|
||||||
|
adb_wa_append_obj(ctx->files, &fio);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
apk_pathbuilder_push(&ctx->pb, entry);
|
||||||
|
apk_err(out, "special file '%s' not supported",
|
||||||
|
apk_pathbuilder_cstr(&ctx->pb), entry);
|
||||||
|
apk_pathbuilder_pop(&ctx->pb);
|
||||||
|
r = -EINVAL;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char *pkgi_filename(struct adb_obj *pkgi, char *buf, size_t n)
|
||||||
|
{
|
||||||
|
apk_blob_t to = APK_BLOB_PTR_LEN(buf, n);
|
||||||
|
apk_blob_push_blob(&to, adb_ro_blob(pkgi, ADBI_PI_NAME));
|
||||||
|
apk_blob_push_blob(&to, APK_BLOB_STR("-"));
|
||||||
|
apk_blob_push_blob(&to, adb_ro_blob(pkgi, ADBI_PI_VERSION));
|
||||||
|
apk_blob_push_blob(&to, APK_BLOB_STR(".apk"));
|
||||||
|
apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("", 1));
|
||||||
|
if (APK_BLOB_IS_NULL(to)) return 0;
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int mkpkg_main(void *pctx, struct apk_ctx *ac, struct apk_string_array *args)
|
||||||
|
{
|
||||||
|
struct apk_out *out = &ac->out;
|
||||||
|
struct apk_trust *trust = apk_ctx_get_trust(ac);
|
||||||
|
struct adb_obj pkg, pkgi;
|
||||||
|
int i, j, r;
|
||||||
|
struct mkpkg_ctx *ctx = pctx;
|
||||||
|
struct apk_ostream *os;
|
||||||
|
char outbuf[PATH_MAX];
|
||||||
|
|
||||||
|
ctx->ac = ac;
|
||||||
|
adb_w_init_alloca(&ctx->db, ADB_SCHEMA_PACKAGE, 40);
|
||||||
|
adb_wo_alloca(&pkg, &schema_package, &ctx->db);
|
||||||
|
adb_wo_alloca(&pkgi, &schema_pkginfo, &ctx->db);
|
||||||
|
adb_wo_alloca(&ctx->paths, &schema_dir_array, &ctx->db);
|
||||||
|
|
||||||
|
// prepare package info
|
||||||
|
for (i = 0; i < ARRAY_SIZE(ctx->info); i++) {
|
||||||
|
apk_blob_t val = ctx->info[i];
|
||||||
|
if (APK_BLOB_IS_NULL(val)) {
|
||||||
|
switch (i) {
|
||||||
|
case ADBI_PI_NAME:
|
||||||
|
case ADBI_PI_VERSION:
|
||||||
|
r = -EINVAL;
|
||||||
|
apk_err(out, "required pkginfo field '%s' not provided",
|
||||||
|
schema_pkginfo.fields[i-1].name);
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
adb_wo_val_fromstring(&pkgi, i, val);
|
||||||
|
}
|
||||||
|
if (adb_ro_val(&pkgi, ADBI_PI_ARCH) == ADB_VAL_NULL)
|
||||||
|
adb_wo_blob(&pkgi, ADBI_PI_ARCH, APK_BLOB_STRLIT(APK_DEFAULT_ARCH));
|
||||||
|
|
||||||
|
// scan and add all files
|
||||||
|
if (ctx->files_dir) {
|
||||||
|
struct apk_file_info fi;
|
||||||
|
r = apk_fileinfo_get(AT_FDCWD, ctx->files_dir, APK_FI_NOFOLLOW, &fi, 0);
|
||||||
|
if (r) {
|
||||||
|
apk_err(out, "file directory '%s': %s",
|
||||||
|
ctx->files_dir, apk_error_str(r));
|
||||||
|
goto err;
|
||||||
|
}
|
||||||
|
r = mkpkg_process_directory(ctx, openat(AT_FDCWD, ctx->files_dir, O_RDONLY), &fi);
|
||||||
|
if (r) goto err;
|
||||||
|
if (!ctx->installed_size) ctx->installed_size = BLOCK_SIZE;
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
adb_w_rootobj(&pkg);
|
||||||
|
|
||||||
|
// re-read since object resets
|
||||||
|
adb_r_rootobj(&ctx->db, &pkg, &schema_package);
|
||||||
|
adb_ro_obj(&pkg, ADBI_PKG_PKGINFO, &pkgi);
|
||||||
|
adb_ro_obj(&pkg, ADBI_PKG_PATHS, &ctx->paths);
|
||||||
|
|
||||||
|
if (!ctx->output) {
|
||||||
|
ctx->output = pkgi_filename(&pkgi, outbuf, sizeof outbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
// construct package with ADB as header, and the file data in
|
||||||
|
// concatenated data blocks
|
||||||
|
os = apk_ostream_gzip(apk_ostream_to_file(AT_FDCWD, ctx->output, 0644));
|
||||||
|
adb_c_adb(os, &ctx->db, trust);
|
||||||
|
int files_fd = openat(AT_FDCWD, ctx->files_dir, O_RDONLY);
|
||||||
|
for (i = ADBI_FIRST; i <= adb_ra_num(&ctx->paths); i++) {
|
||||||
|
struct adb_obj path, files, file;
|
||||||
|
adb_ro_obj(&ctx->paths, i, &path);
|
||||||
|
adb_ro_obj(&path, ADBI_DI_FILES, &files);
|
||||||
|
apk_blob_t dirname = adb_ro_blob(&path, ADBI_DI_NAME);
|
||||||
|
|
||||||
|
apk_pathbuilder_setb(&ctx->pb, dirname);
|
||||||
|
for (j = ADBI_FIRST; j <= adb_ra_num(&files); j++) {
|
||||||
|
adb_ro_obj(&files, j, &file);
|
||||||
|
apk_blob_t filename = adb_ro_blob(&file, ADBI_FI_NAME);
|
||||||
|
apk_blob_t target = adb_ro_blob(&file, ADBI_FI_TARGET);
|
||||||
|
size_t sz = adb_ro_int(&file, ADBI_FI_SIZE);
|
||||||
|
if (!APK_BLOB_IS_NULL(target)) continue;
|
||||||
|
if (!sz) continue;
|
||||||
|
struct {
|
||||||
|
uint32_t path_idx;
|
||||||
|
uint32_t file_idx;
|
||||||
|
} hdr = { i, j };
|
||||||
|
|
||||||
|
apk_pathbuilder_pushb(&ctx->pb, filename);
|
||||||
|
adb_c_block_data(
|
||||||
|
os, APK_BLOB_STRUCT(hdr), sz,
|
||||||
|
apk_istream_from_fd(openat(files_fd,
|
||||||
|
apk_pathbuilder_cstr(&ctx->pb),
|
||||||
|
O_RDONLY)));
|
||||||
|
apk_pathbuilder_pop(&ctx->pb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(files_fd);
|
||||||
|
r = apk_ostream_close(os);
|
||||||
|
|
||||||
|
err:
|
||||||
|
adb_free(&ctx->db);
|
||||||
|
if (r) apk_err(out, "failed to create package: %s", apk_error_str(r));
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct apk_applet apk_mkpkg = {
|
||||||
|
.name = "mkpkg",
|
||||||
|
.context_size = sizeof(struct mkpkg_ctx),
|
||||||
|
.optgroups = { &optgroup_global, &optgroup_signing, &optgroup_applet },
|
||||||
|
.main = mkpkg_main,
|
||||||
|
};
|
||||||
|
|
||||||
|
APK_DEFINE_APPLET(apk_mkpkg);
|
210
src/io.c
210
src/io.c
|
@ -1033,72 +1033,86 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
|
||||||
}
|
}
|
||||||
|
|
||||||
struct cache_item {
|
struct cache_item {
|
||||||
apk_hash_node hash_node;
|
struct hlist_node by_id, by_name;
|
||||||
unsigned int genid;
|
unsigned long id;
|
||||||
union {
|
|
||||||
uid_t uid;
|
|
||||||
gid_t gid;
|
|
||||||
};
|
|
||||||
unsigned short len;
|
unsigned short len;
|
||||||
char name[];
|
char name[];
|
||||||
};
|
};
|
||||||
|
|
||||||
static apk_blob_t cache_item_get_key(apk_hash_item item)
|
static void idhash_init(struct apk_id_hash *idh)
|
||||||
{
|
{
|
||||||
struct cache_item *ci = (struct cache_item *) item;
|
memset(idh, 0, sizeof *idh);
|
||||||
return APK_BLOB_PTR_LEN(ci->name, ci->len);
|
idh->empty = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const struct apk_hash_ops id_hash_ops = {
|
static void idhash_reset(struct apk_id_hash *idh)
|
||||||
.node_offset = offsetof(struct cache_item, hash_node),
|
{
|
||||||
.get_key = cache_item_get_key,
|
struct hlist_node *iter, *next;
|
||||||
.hash_key = apk_blob_hash,
|
struct cache_item *ci;
|
||||||
.compare = apk_blob_compare,
|
int i;
|
||||||
.delete_item = (apk_hash_delete_f) free,
|
|
||||||
};
|
|
||||||
|
|
||||||
static struct cache_item *resolve_cache_item(struct apk_hash *hash, apk_blob_t name)
|
for (i = 0; i < ARRAY_SIZE(idh->by_id); i++)
|
||||||
|
hlist_for_each_entry_safe(ci, iter, next, &idh->by_id[i], by_id)
|
||||||
|
free(ci);
|
||||||
|
idhash_init(idh);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void idcache_add(struct apk_id_hash *hash, apk_blob_t name, unsigned long id)
|
||||||
{
|
{
|
||||||
struct cache_item *ci;
|
struct cache_item *ci;
|
||||||
unsigned long h;
|
unsigned long h;
|
||||||
|
|
||||||
h = id_hash_ops.hash_key(name);
|
|
||||||
ci = (struct cache_item *) apk_hash_get_hashed(hash, name, h);
|
|
||||||
if (ci != NULL)
|
|
||||||
return ci;
|
|
||||||
|
|
||||||
ci = calloc(1, sizeof(struct cache_item) + name.len);
|
ci = calloc(1, sizeof(struct cache_item) + name.len);
|
||||||
if (ci == NULL)
|
if (!ci) return;
|
||||||
return NULL;
|
|
||||||
|
|
||||||
|
ci->id = id;
|
||||||
ci->len = name.len;
|
ci->len = name.len;
|
||||||
memcpy(ci->name, name.ptr, name.len);
|
memcpy(ci->name, name.ptr, name.len);
|
||||||
apk_hash_insert_hashed(hash, ci, h);
|
|
||||||
|
|
||||||
return ci;
|
h = apk_blob_hash(name);
|
||||||
|
hlist_add_head(&ci->by_id, &hash->by_id[id % ARRAY_SIZE(hash->by_id)]);
|
||||||
|
hlist_add_head(&ci->by_name, &hash->by_name[h % ARRAY_SIZE(hash->by_name)]);
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cache_item *idcache_by_name(struct apk_id_hash *hash, apk_blob_t name)
|
||||||
|
{
|
||||||
|
struct cache_item *ci;
|
||||||
|
struct hlist_node *pos;
|
||||||
|
unsigned long h = apk_blob_hash(name);
|
||||||
|
|
||||||
|
hlist_for_each_entry(ci, pos, &hash->by_name[h % ARRAY_SIZE(hash->by_name)], by_name)
|
||||||
|
if (apk_blob_compare(name, APK_BLOB_PTR_LEN(ci->name, ci->len)) == 0)
|
||||||
|
return ci;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static struct cache_item *idcache_by_id(struct apk_id_hash *hash, unsigned long id)
|
||||||
|
{
|
||||||
|
struct cache_item *ci;
|
||||||
|
struct hlist_node *pos;
|
||||||
|
|
||||||
|
hlist_for_each_entry(ci, pos, &hash->by_id[id % ARRAY_SIZE(hash->by_name)], by_id)
|
||||||
|
if (ci->id == id) return ci;
|
||||||
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd)
|
void apk_id_cache_init(struct apk_id_cache *idc, int root_fd)
|
||||||
{
|
{
|
||||||
idc->root_fd = root_fd;
|
idc->root_fd = root_fd;
|
||||||
idc->genid = 1;
|
idhash_init(&idc->uid_cache);
|
||||||
apk_hash_init(&idc->uid_cache, &id_hash_ops, 256);
|
idhash_init(&idc->gid_cache);
|
||||||
apk_hash_init(&idc->gid_cache, &id_hash_ops, 256);
|
|
||||||
}
|
|
||||||
|
|
||||||
void apk_id_cache_free(struct apk_id_cache *idc)
|
|
||||||
{
|
|
||||||
if (!idc->root_fd) return;
|
|
||||||
apk_hash_free(&idc->uid_cache);
|
|
||||||
apk_hash_free(&idc->gid_cache);
|
|
||||||
idc->root_fd = 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void apk_id_cache_reset(struct apk_id_cache *idc)
|
void apk_id_cache_reset(struct apk_id_cache *idc)
|
||||||
{
|
{
|
||||||
idc->genid++;
|
idhash_reset(&idc->uid_cache);
|
||||||
if (idc->genid == 0)
|
idhash_reset(&idc->gid_cache);
|
||||||
idc->genid = 1;
|
}
|
||||||
|
|
||||||
|
void apk_id_cache_free(struct apk_id_cache *idc)
|
||||||
|
{
|
||||||
|
apk_id_cache_reset(idc);
|
||||||
|
idc->root_fd = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static FILE *fopenat(int dirfd, const char *pathname)
|
static FILE *fopenat(int dirfd, const char *pathname)
|
||||||
|
@ -1114,86 +1128,94 @@ static FILE *fopenat(int dirfd, const char *pathname)
|
||||||
return f;
|
return f;
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t apk_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid)
|
static void idcache_load_users(int root_fd, struct apk_id_hash *idh)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_FGETPWENT_R
|
#ifdef HAVE_FGETPWENT_R
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct passwd pwent;
|
struct passwd pwent;
|
||||||
#endif
|
#endif
|
||||||
struct cache_item *ci;
|
|
||||||
struct passwd *pwd;
|
struct passwd *pwd;
|
||||||
FILE *in;
|
FILE *in;
|
||||||
|
|
||||||
ci = resolve_cache_item(&idc->uid_cache, username);
|
if (!idh->empty) return;
|
||||||
if (ci == NULL) return default_uid;
|
idh->empty = 0;
|
||||||
|
|
||||||
if (ci->genid != idc->genid) {
|
in = fopenat(root_fd, "etc/passwd");
|
||||||
ci->genid = idc->genid;
|
if (!in) return;
|
||||||
ci->uid = -1;
|
|
||||||
|
|
||||||
in = fopenat(idc->root_fd, "etc/passwd");
|
do {
|
||||||
if (in) {
|
|
||||||
do {
|
|
||||||
#ifdef HAVE_FGETPWENT_R
|
#ifdef HAVE_FGETPWENT_R
|
||||||
fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
|
fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
|
||||||
#else
|
#else
|
||||||
pwd = fgetpwent(in);
|
pwd = fgetpwent(in);
|
||||||
|
#endif
|
||||||
|
if (!pwd) break;
|
||||||
|
idcache_add(idh, APK_BLOB_STR(pwd->pw_name), pwd->pw_uid);
|
||||||
|
} while (1);
|
||||||
|
fclose(in);
|
||||||
|
#ifndef HAVE_FGETPWENT_R
|
||||||
|
endpwent();
|
||||||
#endif
|
#endif
|
||||||
if (pwd == NULL)
|
|
||||||
break;
|
|
||||||
if (apk_blob_compare(APK_BLOB_STR(pwd->pw_name), username) == 0) {
|
|
||||||
ci->uid = pwd->pw_uid;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
} while (1);
|
|
||||||
fclose(in);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ci->uid != -1)
|
|
||||||
return ci->uid;
|
|
||||||
|
|
||||||
return default_uid;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
uid_t apk_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, uid_t default_gid)
|
static void idcache_load_groups(int root_fd, struct apk_id_hash *idh)
|
||||||
{
|
{
|
||||||
#ifdef HAVE_FGETGRENT_R
|
#ifdef HAVE_FGETGRENT_R
|
||||||
char buf[1024];
|
char buf[1024];
|
||||||
struct group grent;
|
struct group grent;
|
||||||
#endif
|
#endif
|
||||||
struct cache_item *ci;
|
|
||||||
struct group *grp;
|
struct group *grp;
|
||||||
FILE *in;
|
FILE *in;
|
||||||
|
|
||||||
ci = resolve_cache_item(&idc->gid_cache, groupname);
|
if (!idh->empty) return;
|
||||||
if (ci == NULL) return default_gid;
|
idh->empty = 0;
|
||||||
|
|
||||||
if (ci->genid != idc->genid) {
|
in = fopenat(root_fd, "etc/group");
|
||||||
ci->genid = idc->genid;
|
if (!in) return;
|
||||||
ci->gid = -1;
|
|
||||||
|
|
||||||
in = fopenat(idc->root_fd, "etc/group");
|
do {
|
||||||
if (in) {
|
|
||||||
do {
|
|
||||||
#ifdef HAVE_FGETGRENT_R
|
#ifdef HAVE_FGETGRENT_R
|
||||||
fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
|
fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
|
||||||
#else
|
#else
|
||||||
grp = fgetgrent(in);
|
grp = fgetgrent(in);
|
||||||
|
#endif
|
||||||
|
if (!grp) break;
|
||||||
|
idcache_add(idh, APK_BLOB_STR(grp->gr_name), grp->gr_gid);
|
||||||
|
} while (1);
|
||||||
|
fclose(in);
|
||||||
|
#ifndef HAVE_FGETGRENT_R
|
||||||
|
endgrent();
|
||||||
#endif
|
#endif
|
||||||
if (grp == NULL)
|
}
|
||||||
break;
|
|
||||||
if (apk_blob_compare(APK_BLOB_STR(grp->gr_name), groupname) == 0) {
|
uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid)
|
||||||
ci->gid = grp->gr_gid;
|
{
|
||||||
break;
|
struct cache_item *ci;
|
||||||
}
|
idcache_load_users(idc->root_fd, &idc->uid_cache);
|
||||||
} while (1);
|
ci = idcache_by_name(&idc->uid_cache, username);
|
||||||
fclose(in);
|
return ci ? ci->id : default_uid;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
gid_t apk_id_cache_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, gid_t default_gid)
|
||||||
if (ci->gid != -1)
|
{
|
||||||
return ci->gid;
|
struct cache_item *ci;
|
||||||
|
idcache_load_groups(idc->root_fd, &idc->gid_cache);
|
||||||
return default_gid;
|
ci = idcache_by_name(&idc->gid_cache, groupname);
|
||||||
|
return ci ? ci->id : default_gid;
|
||||||
|
}
|
||||||
|
|
||||||
|
apk_blob_t apk_id_cache_resolve_user(struct apk_id_cache *idc, uid_t uid)
|
||||||
|
{
|
||||||
|
struct cache_item *ci;
|
||||||
|
idcache_load_users(idc->root_fd, &idc->uid_cache);
|
||||||
|
ci = idcache_by_id(&idc->uid_cache, uid);
|
||||||
|
return ci ? APK_BLOB_PTR_LEN(ci->name, ci->len) : APK_BLOB_STRLIT("nobody");
|
||||||
|
}
|
||||||
|
|
||||||
|
apk_blob_t apk_id_cache_resolve_group(struct apk_id_cache *idc, gid_t gid)
|
||||||
|
{
|
||||||
|
struct cache_item *ci;
|
||||||
|
idcache_load_groups(idc->root_fd, &idc->gid_cache);
|
||||||
|
ci = idcache_by_id(&idc->gid_cache, gid);
|
||||||
|
return ci ? APK_BLOB_PTR_LEN(ci->name, ci->len) : APK_BLOB_STRLIT("nobody");
|
||||||
}
|
}
|
||||||
|
|
|
@ -150,8 +150,8 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
|
||||||
|
|
||||||
entry = (struct apk_file_info){
|
entry = (struct apk_file_info){
|
||||||
.size = GET_OCTAL(buf.size),
|
.size = GET_OCTAL(buf.size),
|
||||||
.uid = apk_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
|
.uid = apk_id_cache_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
|
||||||
.gid = apk_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
|
.gid = apk_id_cache_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
|
||||||
.mode = GET_OCTAL(buf.mode) & 07777,
|
.mode = GET_OCTAL(buf.mode) & 07777,
|
||||||
.mtime = GET_OCTAL(buf.mtime),
|
.mtime = GET_OCTAL(buf.mtime),
|
||||||
.name = entry.name,
|
.name = entry.name,
|
||||||
|
|
|
@ -18,6 +18,7 @@ libapk_src = [
|
||||||
'io_url.c',
|
'io_url.c',
|
||||||
'io_gunzip.c',
|
'io_gunzip.c',
|
||||||
'package.c',
|
'package.c',
|
||||||
|
'pathbuilder.c',
|
||||||
'print.c',
|
'print.c',
|
||||||
'solver.c',
|
'solver.c',
|
||||||
'trust.c',
|
'trust.c',
|
||||||
|
@ -35,6 +36,7 @@ libapk_headers = [
|
||||||
'apk_io.h',
|
'apk_io.h',
|
||||||
'apk_openssl.h',
|
'apk_openssl.h',
|
||||||
'apk_package.h',
|
'apk_package.h',
|
||||||
|
'apk_pathbuilder.h',
|
||||||
'apk_print.h',
|
'apk_print.h',
|
||||||
'apk_provider_data.h',
|
'apk_provider_data.h',
|
||||||
'apk_solver_data.h',
|
'apk_solver_data.h',
|
||||||
|
@ -60,6 +62,7 @@ apk_src = [
|
||||||
'app_list.c',
|
'app_list.c',
|
||||||
'app_manifest.c',
|
'app_manifest.c',
|
||||||
'app_mkndx.c',
|
'app_mkndx.c',
|
||||||
|
'app_mkpkg.c',
|
||||||
'app_policy.c',
|
'app_policy.c',
|
||||||
'app_update.c',
|
'app_update.c',
|
||||||
'app_upgrade.c',
|
'app_upgrade.c',
|
||||||
|
|
|
@ -0,0 +1,29 @@
|
||||||
|
/* apk_pathbuilder.h - Alpine Package Keeper (APK)
|
||||||
|
*
|
||||||
|
* Copyright (C) 2021 Timo Teräs <timo.teras@iki.fi>
|
||||||
|
* All rights reserved.
|
||||||
|
*
|
||||||
|
* SPDX-License-Identifier: GPL-2.0-only
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <errno.h>
|
||||||
|
#include "apk_pathbuilder.h"
|
||||||
|
|
||||||
|
int apk_pathbuilder_pushb(struct apk_pathbuilder *pb, apk_blob_t b)
|
||||||
|
{
|
||||||
|
size_t i = pb->namelen;
|
||||||
|
if (i + b.len + 2 >= ARRAY_SIZE(pb->name)) return -ENAMETOOLONG;
|
||||||
|
if (i) pb->name[i++] = '/';
|
||||||
|
memcpy(&pb->name[i], b.ptr, b.len);
|
||||||
|
pb->namelen = i + b.len;
|
||||||
|
pb->name[pb->namelen] = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void apk_pathbuilder_pop(struct apk_pathbuilder *pb)
|
||||||
|
{
|
||||||
|
char *slash = memrchr(pb->name, '/', pb->namelen);
|
||||||
|
if (slash) pb->namelen = slash - pb->name;
|
||||||
|
else pb->namelen = 0;
|
||||||
|
pb->name[pb->namelen] = 0;
|
||||||
|
}
|
Loading…
Reference in New Issue