summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/adb.c90
-rw-r--r--src/adb.h22
-rw-r--r--src/adb_walk_adb.c29
-rw-r--r--src/adb_walk_genadb.c2
-rw-r--r--src/apk_adb.c62
-rw-r--r--src/apk_adb.h26
-rw-r--r--src/apk_defines.h8
-rw-r--r--src/apk_io.h18
-rw-r--r--src/apk_pathbuilder.h44
-rw-r--r--src/app_adbdump.c2
-rw-r--r--src/app_adbsign.c2
-rw-r--r--src/app_convdb.c30
-rw-r--r--src/app_mkpkg.c284
-rw-r--r--src/io.c202
-rw-r--r--src/io_archive.c4
-rw-r--r--src/meson.build3
-rw-r--r--src/pathbuilder.c29
17 files changed, 647 insertions, 210 deletions
diff --git a/src/adb.c b/src/adb.c
index b33799c..03f50f3 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -13,13 +13,16 @@
#include "apk_blob.h"
#include "apk_trust.h"
+static char padding_zeroes[ADB_BLOCK_ALIGNMENT] = {0};
+
/* Block enumeration */
static inline struct adb_block *adb_block_validate(struct adb_block *blk, apk_blob_t b)
{
size_t pos = (char *)blk - b.ptr;
if (pos == b.len) return NULL;
- pos += sizeof(struct adb_block);
- if (pos > b.len || ADB_BLOCK_SIZE(blk) > b.len - pos) return ERR_PTR(-EBADMSG);
+ if (sizeof(struct adb_block) > 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;
}
@@ -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)
{
- 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 */
@@ -71,8 +74,8 @@ static int __adb_m_parse(struct adb *db, struct apk_trust *t)
int trusted = t ? 0 : 1;
adb_foreach_block(blk, db->data) {
- apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
- switch (ADB_BLOCK_TYPE(blk)) {
+ apk_blob_t b = adb_block_blob(blk);
+ switch (adb_block_type(blk)) {
case ADB_BLOCK_ADB:
if (!APK_BLOB_IS_NULL(db->adb)) break;
db->adb = b;
@@ -575,13 +578,12 @@ copy:
adb_val_t adb_w_adb(struct adb *db, struct adb *valdb)
{
uint32_t bsz;
- struct adb_block blk = {
- .type_size = htole32((ADB_BLOCK_ADB << 30) + valdb->adb.len)
- };
+ struct adb_block blk = adb_block_init(ADB_BLOCK_ADB, valdb->adb.len);
struct iovec vec[] = {
{ .iov_base = &bsz, .iov_len = sizeof bsz },
{ .iov_base = &blk, .iov_len = sizeof blk },
{ .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;
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)
{
- struct adb_block blk = {
- .type_size = htole32((type << 30) + val.len)
- };
+ struct adb_block blk = adb_block_init(type, val.len);
+ size_t padding = adb_block_padding(&blk);
int r;
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);
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;
}
@@ -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();
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) {
EVP_DigestFinal_ex(mdctx, vfy->sha512, 0);
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;
}
-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 (db->hdr.magic != htole32(ADB_FORMAT_MAGIC)) {
- apk_ostream_cancel(os, -EAPKFORMAT);
- goto ret;
- }
+ if (IS_ERR(os))
+ return apk_ostream_cancel(os, PTR_ERR(os));
+ if (db->hdr.magic != htole32(ADB_FORMAT_MAGIC))
+ return apk_ostream_cancel(os, -EAPKFORMAT);
+
adb_c_header(os, db);
adb_c_block(os, ADB_BLOCK_ADB, db->adb);
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);
}
@@ -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);
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, &sig.hdr.sign_ver, sizeof sig.hdr.sign_ver) != 1 ||
- EVP_DigestUpdate(trust->mdctx, &sig.hdr.hash_alg, sizeof sig.hdr.hash_alg) != 1 ||
+ EVP_DigestUpdate(trust->mdctx, &sig.v0, sizeof sig.v0) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestSignFinal(trust->mdctx, sig.v0.sig, &siglen) != 1) {
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);
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, &sig->sign_ver, sizeof sig->sign_ver) != 1 ||
- EVP_DigestUpdate(trust->mdctx, &sig->hash_alg, sizeof sig->hash_alg) != 1 ||
+ EVP_DigestUpdate(trust->mdctx, sig0, sizeof *sig0) != 1 ||
EVP_DigestUpdate(trust->mdctx, md.ptr, md.len) != 1 ||
EVP_DigestVerifyFinal(trust->mdctx, sig0->sig, sigb.len - sizeof(*sig0)) != 1) {
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;
}
- 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));
if (r < 0) goto err;
if (r == 0 && seg.bytes_left == sz) {
r = apk_ostream_write(x->os, &blk, sizeof blk);
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;
} else if (seg.bytes_left > 0) {
r = apk_istream_read(x->is, NULL, sz - seg.bytes_left);
diff --git a/src/adb.h b/src/adb.h
index a6bd121..5f0d7bd 100644
--- a/src/adb.h
+++ b/src/adb.h
@@ -51,17 +51,29 @@ struct adb_header {
};
/* Blocks */
+#define ADB_BLOCK_ALIGNMENT 8
#define ADB_BLOCK_END -1
#define ADB_BLOCK_ADB 0
#define ADB_BLOCK_SIG 2
-
-#define ADB_BLOCK_TYPE(b) (le32toh((b)->type_size) >> 30)
-#define ADB_BLOCK_SIZE(b) (le32toh((b)->type_size) & 0x3fffffff)
+#define ADB_BLOCK_DATA 3
struct adb_block {
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 {
uint8_t sign_ver, hash_alg;
};
@@ -81,7 +93,6 @@ struct adb_sign_v0 {
/* Block enumeration */
struct adb_block *adb_block_first(apk_blob_t b);
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))
@@ -218,7 +229,9 @@ int adb_s_field_by_name(const struct adb_object_schema *, const char *);
/* Creation */
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_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_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);
/* Trust */
@@ -279,6 +292,7 @@ struct adb_walk_gentext {
struct adb_walk_genadb {
struct adb_walk d;
struct adb db;
+ adb_val_t stored_object;
struct adb idb[ADB_WALK_GENADB_MAX_IDB];
int nest, nestdb, num_vals;
struct adb_obj objs[ADB_WALK_GENADB_MAX_NESTING];
diff --git a/src/adb_walk_adb.c b/src/adb_walk_adb.c
index 4f99d85..b9f051c 100644
--- a/src/adb_walk_adb.c
+++ b/src/adb_walk_adb.c
@@ -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)
{
- char tmp[256];
+ char tmp[512];
struct adb_block *blk;
struct adb_sign_hdr *s;
struct adb_verify_ctx vfy = {};
- unsigned char *id;
uint32_t schema_magic = ctx->db->hdr.schema;
const struct adb_db_schema *ds;
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;
adb_foreach_block(blk, ctx->db->data) {
- apk_blob_t b = APK_BLOB_PTR_LEN((char*)(blk+1), ADB_BLOCK_SIZE(blk));
- switch (ADB_BLOCK_TYPE(blk)) {
+ apk_blob_t b = adb_block_blob(blk);
+ switch (adb_block_type(blk)) {
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));
if (ds->root) {
ctx->db->adb = b;
@@ -134,23 +133,19 @@ static int dump_adb(struct adb_walk_ctx *ctx)
case ADB_BLOCK_SIG:
s = (struct adb_sign_hdr*) b.ptr;
r = adb_trust_verify_signature(ctx->trust, ctx->db, &vfy, b);
-
- len = snprintf(tmp, sizeof tmp, "signature: v%d ", s->sign_ver);
- switch (s->sign_ver) {
- 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, sizeof tmp, "sig v%02x h%02x ", s->sign_ver, s->hash_alg);
+ for (size_t j = sizeof *s; j < b.len; j++)
+ len += snprintf(&tmp[len], sizeof tmp - len, "%02x", (uint8_t)b.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));
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:
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));
}
}
diff --git a/src/adb_walk_genadb.c b/src/adb_walk_genadb.c
index 06a3f94..4852eb6 100644
--- a/src/adb_walk_genadb.c
+++ b/src/adb_walk_genadb.c
@@ -74,7 +74,7 @@ static int adb_walk_genadb_end(struct adb_walk *d)
dt->num_vals -= dt->objs[dt->nest].schema->num_fields;
if (dt->nest == 0) {
- adb_w_root(&dt->db, val);
+ dt->stored_object = val;
return 0;
}
diff --git a/src/apk_adb.c b/src/apk_adb.c
index 0785455..9be0e57 100644
--- a/src/apk_adb.c
+++ b/src/apk_adb.c
@@ -422,17 +422,16 @@ const struct adb_object_schema schema_index = {
},
};
-static uint32_t file_get_default_int(unsigned i)
-{
- switch (i) {
- case ADBI_FI_UID:
- case ADBI_FI_GID:
- return 0;
- case ADBI_FI_MODE:
- return 0644;
- }
- return -1;
-}
+const struct adb_object_schema schema_acl = {
+ .kind = ADB_KIND_OBJECT,
+ .num_fields = ADBI_ACL_MAX,
+ .fields = {
+ ADB_FIELD(ADBI_ACL_MODE, "mode", scalar_oct),
+ ADB_FIELD(ADBI_ACL_USER, "user", scalar_string),
+ ADB_FIELD(ADBI_ACL_GROUP, "group", scalar_string),
+ //ADB_FIELD(ADBI_ACL_XATTRS, "xattr", schema_string_array),
+ },
+};
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 = {
.kind = ADB_KIND_OBJECT,
.num_fields = ADBI_FI_MAX,
- .get_default_int = file_get_default_int,
.compare = file_cmp,
.fields = {
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_UID, "uid", scalar_int),
- ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
- ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
- ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
+ ADB_FIELD(ADBI_FI_TARGET, "target", scalar_string),
},
};
@@ -461,38 +459,22 @@ const struct adb_object_schema schema_file_array = {
.fields = ADB_ARRAY_ITEM(schema_file),
};
-static uint32_t path_get_default_int(unsigned i)
-{
- 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 = {
+const struct adb_object_schema schema_dir = {
.kind = ADB_KIND_OBJECT,
- .num_fields = ADBI_FI_MAX,
- .get_default_int = path_get_default_int,
+ .num_fields = ADBI_DI_MAX,
.compare = file_cmp,
.fields = {
- ADB_FIELD(ADBI_FI_NAME, "name", scalar_string),
- ADB_FIELD(ADBI_FI_FILES, "files", schema_file_array),
- ADB_FIELD(ADBI_FI_UID, "uid", scalar_int),
- ADB_FIELD(ADBI_FI_GID, "gid", scalar_int),
- ADB_FIELD(ADBI_FI_MODE, "mode", scalar_oct),
- ADB_FIELD(ADBI_FI_XATTRS, "xattr", scalar_hexblob),
+ ADB_FIELD(ADBI_DI_NAME, "name", scalar_string),
+ ADB_FIELD(ADBI_DI_ACL, "acl", schema_acl),
+ ADB_FIELD(ADBI_DI_FILES, "files", schema_file_array),
},
};
-const struct adb_object_schema schema_path_array = {
+const struct adb_object_schema schema_dir_array = {
.kind = ADB_KIND_ARRAY,
.pre_commit = adb_wa_sort,
.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 = {
@@ -520,7 +502,7 @@ const struct adb_object_schema schema_package = {
.compare = package_cmp,
.fields = {
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_TRIGGERS, "triggers", schema_string_array),
//ADB_FIELD(ADBI_PKG_PASSWD, "passwd", schema_string_array),
diff --git a/src/apk_adb.h b/src/apk_adb.h
index 557bc6e..1908cba 100644
--- a/src/apk_adb.h
+++ b/src/apk_adb.h
@@ -33,16 +33,28 @@
#define ADBI_PI_RECOMMENDS 0x13
#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 */
#define ADBI_FI_NAME 0x01
-#define ADBI_FI_HASHES 0x02
-#define ADBI_FI_FILES 0x02
-#define ADBI_FI_MODE 0x03
-#define ADBI_FI_UID 0x04
-#define ADBI_FI_GID 0x05
-#define ADBI_FI_XATTRS 0x06
+#define ADBI_FI_ACL 0x02
+#define ADBI_FI_SIZE 0x03
+#define ADBI_FI_MTIME 0x04
+#define ADBI_FI_HASHES 0x05
+#define ADBI_FI_TARGET 0x06
#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 */
#define ADBI_SCRPT_TRIGGER 0x01
#define ADBI_SCRPT_PREINST 0x02
@@ -81,7 +93,7 @@
extern const struct adb_object_schema
schema_dependency, schema_dependency_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_index, schema_idb;
diff --git a/src/apk_defines.h b/src/apk_defines.h
index 92e97d8..3218277 100644
--- a/src/apk_defines.h
+++ b/src/apk_defines.h
@@ -191,14 +191,14 @@ APK_ARRAY(apk_string_array, char *);
#define LIST_POISON1 (void *) 0xdeadbeef
#define LIST_POISON2 (void *) 0xabbaabba
-struct hlist_head {
- struct hlist_node *first;
-};
-
struct hlist_node {
struct hlist_node *next;
};
+struct hlist_head {
+ struct hlist_node *first;
+};
+
static inline int hlist_empty(const struct hlist_head *h)
{
return !h->first;
diff --git a/src/apk_io.h b/src/apk_io.h
index 8a243ac..030255e 100644
--- a/src/apk_io.h
+++ b/src/apk_io.h
@@ -15,14 +15,17 @@
#include "apk_defines.h"
#include "apk_blob.h"
-#include "apk_hash.h"
#include "apk_atom.h"
+struct apk_id_hash {
+ int empty;
+ struct hlist_head by_id[16], by_name[16];
+};
+
struct apk_id_cache {
int root_fd;
- unsigned int genid;
- struct apk_hash uid_cache;
- struct apk_hash gid_cache;
+ struct apk_id_hash uid_cache;
+ struct apk_id_hash gid_cache;
};
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_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);
+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 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_free(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_resolve_gid(struct apk_id_cache *idc, apk_blob_t groupname, uid_t default_gid);
+uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid);
+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
diff --git a/src/apk_pathbuilder.h b/src/apk_pathbuilder.h
new file mode 100644
index 0000000..34181db
--- /dev/null
+++ b/src/apk_pathbuilder.h
@@ -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
diff --git a/src/app_adbdump.c b/src/app_adbdump.c
index 958c90f..5c1b69c 100644
--- a/src/app_adbdump.c
+++ b/src/app_adbdump.c
@@ -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);
foreach_array_item(arg, args) {
adb_reset(&genadb.db);
+ adb_reset(&genadb.idb[0]);
r = adb_walk_istream(&genadb.d, apk_istream_from_file(AT_FDCWD, *arg));
if (!r) {
+ adb_w_root(&genadb.db, genadb.stored_object);
r = adb_c_create(apk_ostream_to_fd(STDOUT_FILENO), &genadb.db,
apk_ctx_get_trust(ac));
}
diff --git a/src/app_adbsign.c b/src/app_adbsign.c
index cdfd6e9..bb489c0 100644
--- a/src/app_adbsign.c
+++ b/src/app_adbsign.c
@@ -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);
int r;
- switch (blk ? ADB_BLOCK_TYPE(blk) : -1) {
+ switch (blk ? adb_block_type(blk) : -1) {
case ADB_BLOCK_ADB:
return adb_c_block_copy(xfrm->os, blk, is, &xfrm->vfy);
case ADB_BLOCK_SIG:
diff --git a/src/app_convdb.c b/src/app_convdb.c
index 4871f67..dfb426b 100644
--- a/src/app_convdb.c
+++ b/src/app_convdb.c
@@ -18,6 +18,7 @@ struct conv_script {
};
struct conv_ctx {
+ struct apk_ctx *ac;
struct apk_atom_pool atoms;
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)
{
+ struct apk_id_cache *idc = apk_ctx_get_id_cache(ctx->ac);
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");
struct conv_script *s;
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(&files, &schema_file_array, &ctx->dbp);
adb_wo_alloca(&file, &schema_file, &ctx->dbp);
- adb_wo_alloca(&paths, &schema_path_array, &ctx->dbp);
- adb_wo_alloca(&path, &schema_path, &ctx->dbp);
+ adb_wo_alloca(&paths, &schema_dir_array, &ctx->dbp);
+ adb_wo_alloca(&path, &schema_dir, &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))) {
if (l.len < 2) {
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_wo_obj(&pkg, ADBI_PKG_PKGINFO, &pkginfo);
@@ -152,28 +155,30 @@ static void convert_idb(struct conv_ctx *ctx, struct apk_istream *is)
break;
case 'F': // directory name
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_wo_blob(&path, ADBI_FI_NAME, val);
+ adb_wo_blob(&path, ADBI_DI_NAME, val);
break;
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, ':');
- 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, ':');
- 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;
case 'R': // file name
adb_wa_append_obj(&files, &file);
adb_wo_blob(&file, ADBI_FI_NAME, val);
break;
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, ':');
- 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, ':');
- 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;
case 'Z': // file content hash
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 root_fd = apk_ctx_fd_root(ac);
+ ctx->ac = ac;
list_init(&ctx->script_head);
apk_atom_init(&ctx->atoms);
diff --git a/src/app_mkpkg.c b/src/app_mkpkg.c
new file mode 100644
index 0000000..872b4da
--- /dev/null
+++ b/src/app_mkpkg.c
@@ -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);
diff --git a/src/io.c b/src/io.c
index a2c23ae..93ca9d6 100644
--- a/src/io.c
+++ b/src/io.c
@@ -1033,72 +1033,86 @@ size_t apk_ostream_write_string(struct apk_ostream *os, const char *string)
}
struct cache_item {
- apk_hash_node hash_node;
- unsigned int genid;
- union {
- uid_t uid;
- gid_t gid;
- };
+ struct hlist_node by_id, by_name;
+ unsigned long id;
unsigned short len;
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;
- return APK_BLOB_PTR_LEN(ci->name, ci->len);
+ memset(idh, 0, sizeof *idh);
+ idh->empty = 1;
}
-static const struct apk_hash_ops id_hash_ops = {
- .node_offset = offsetof(struct cache_item, hash_node),
- .get_key = cache_item_get_key,
- .hash_key = apk_blob_hash,
- .compare = apk_blob_compare,
- .delete_item = (apk_hash_delete_f) free,
-};
+static void idhash_reset(struct apk_id_hash *idh)
+{
+ struct hlist_node *iter, *next;
+ struct cache_item *ci;
+ int i;
-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;
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);
- if (ci == NULL)
- return NULL;
+ if (!ci) return;
+ ci->id = id;
ci->len = 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)
{
idc->root_fd = root_fd;
- idc->genid = 1;
- apk_hash_init(&idc->uid_cache, &id_hash_ops, 256);
- apk_hash_init(&idc->gid_cache, &id_hash_ops, 256);
+ idhash_init(&idc->uid_cache);
+ idhash_init(&idc->gid_cache);
}
-void apk_id_cache_free(struct apk_id_cache *idc)
+void apk_id_cache_reset(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;
+ idhash_reset(&idc->uid_cache);
+ idhash_reset(&idc->gid_cache);
}
-void apk_id_cache_reset(struct apk_id_cache *idc)
+void apk_id_cache_free(struct apk_id_cache *idc)
{
- idc->genid++;
- if (idc->genid == 0)
- idc->genid = 1;
+ apk_id_cache_reset(idc);
+ idc->root_fd = 0;
}
static FILE *fopenat(int dirfd, const char *pathname)
@@ -1114,86 +1128,94 @@ static FILE *fopenat(int dirfd, const char *pathname)
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
char buf[1024];
struct passwd pwent;
#endif
- struct cache_item *ci;
struct passwd *pwd;
FILE *in;
- ci = resolve_cache_item(&idc->uid_cache, username);
- if (ci == NULL) return default_uid;
+ if (!idh->empty) return;
+ idh->empty = 0;
- if (ci->genid != idc->genid) {
- ci->genid = idc->genid;
- ci->uid = -1;
+ in = fopenat(root_fd, "etc/passwd");
+ if (!in) return;
- in = fopenat(idc->root_fd, "etc/passwd");
- if (in) {
- do {
+ do {
#ifdef HAVE_FGETPWENT_R
- fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
+ fgetpwent_r(in, &pwent, buf, sizeof(buf), &pwd);
#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
- 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
char buf[1024];
struct group grent;
#endif
- struct cache_item *ci;
struct group *grp;
FILE *in;
- ci = resolve_cache_item(&idc->gid_cache, groupname);
- if (ci == NULL) return default_gid;
+ if (!idh->empty) return;
+ idh->empty = 0;
- if (ci->genid != idc->genid) {
- ci->genid = idc->genid;
- ci->gid = -1;
+ in = fopenat(root_fd, "etc/group");
+ if (!in) return;
- in = fopenat(idc->root_fd, "etc/group");
- if (in) {
- do {
+ do {
#ifdef HAVE_FGETGRENT_R
- fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
+ fgetgrent_r(in, &grent, buf, sizeof(buf), &grp);
#else
- grp = fgetgrent(in);
+ grp = fgetgrent(in);
#endif
- if (grp == NULL)
- break;
- if (apk_blob_compare(APK_BLOB_STR(grp->gr_name), groupname) == 0) {
- ci->gid = grp->gr_gid;
- break;
- }
- } while (1);
- fclose(in);
- }
- }
+ 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
+}
- if (ci->gid != -1)
- return ci->gid;
+uid_t apk_id_cache_resolve_uid(struct apk_id_cache *idc, apk_blob_t username, uid_t default_uid)
+{
+ struct cache_item *ci;
+ idcache_load_users(idc->root_fd, &idc->uid_cache);
+ ci = idcache_by_name(&idc->uid_cache, username);
+ 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)
+{
+ struct cache_item *ci;
+ idcache_load_groups(idc->root_fd, &idc->gid_cache);
+ ci = idcache_by_name(&idc->gid_cache, groupname);
+ return ci ? ci->id : default_gid;
+}
- return 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");
}
diff --git a/src/io_archive.c b/src/io_archive.c
index 303fb93..ad4f621 100644
--- a/src/io_archive.c
+++ b/src/io_archive.c
@@ -150,8 +150,8 @@ int apk_tar_parse(struct apk_istream *is, apk_archive_entry_parser parser,
entry = (struct apk_file_info){
.size = GET_OCTAL(buf.size),
- .uid = apk_resolve_uid(idc, TAR_BLOB(buf.uname), GET_OCTAL(buf.uid)),
- .gid = apk_resolve_gid(idc, TAR_BLOB(buf.gname), GET_OCTAL(buf.gid)),
+ .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),
.name = entry.name,
diff --git a/src/meson.build b/src/meson.build
index 6c5f6ca..4a76d4c 100644
--- a/src/meson.build
+++ b/src/meson.build
@@ -18,6 +18,7 @@ libapk_src = [
'io_url.c',
'io_gunzip.c',
'package.c',
+ 'pathbuilder.c',
'print.c',
'solver.c',
'trust.c',
@@ -35,6 +36,7 @@ libapk_headers = [
'apk_io.h',
'apk_openssl.h',
'apk_package.h',
+ 'apk_pathbuilder.h',
'apk_print.h',
'apk_provider_data.h',
'apk_solver_data.h',
@@ -60,6 +62,7 @@ apk_src = [
'app_list.c',
'app_manifest.c',
'app_mkndx.c',
+ 'app_mkpkg.c',
'app_policy.c',
'app_update.c',
'app_upgrade.c',
diff --git a/src/pathbuilder.c b/src/pathbuilder.c
new file mode 100644
index 0000000..166aa22
--- /dev/null
+++ b/src/pathbuilder.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;
+}