summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTimo Teräs <timo.teras@iki.fi>2023-09-11 17:26:33 +0300
committerTimo Teräs <timo.teras@iki.fi>2023-09-22 08:53:03 +0000
commit718c44d02e71746c614918141e967b8e45df8eb4 (patch)
tree65f828b72a854a81614b643283d5749fa58ddceb
parent99a264f936d752a45ee83442736163163ca458e2 (diff)
downloadapk-tools-718c44d02e71746c614918141e967b8e45df8eb4.tar.gz
apk-tools-718c44d02e71746c614918141e967b8e45df8eb4.tar.bz2
apk-tools-718c44d02e71746c614918141e967b8e45df8eb4.tar.xz
apk-tools-718c44d02e71746c614918141e967b8e45df8eb4.zip
adb, mkpkg, extract_v3: add support for xattrs
fixes #10859
-rw-r--r--src/adb.c57
-rw-r--r--src/adb.h1
-rw-r--r--src/apk_adb.c55
-rw-r--r--src/apk_adb.h1
-rw-r--r--src/app_mkpkg.c39
-rw-r--r--src/extract_v3.c47
6 files changed, 170 insertions, 30 deletions
diff --git a/src/adb.c b/src/adb.c
index 16b2c8b..3f22187 100644
--- a/src/adb.c
+++ b/src/adb.c
@@ -649,37 +649,47 @@ void adb_w_rootobj(struct adb_obj *obj)
adb_w_root(obj->db, adb_w_obj(obj));
}
-adb_val_t adb_w_blob(struct adb *db, apk_blob_t b)
+adb_val_t adb_w_blob_vec(struct adb *db, uint32_t n, apk_blob_t *b)
{
union {
uint32_t u32;
uint16_t u16;
uint8_t u8;
} val;
- uint32_t n = b.len;
- struct iovec vec[2] = {
- { .iov_base = &val, .iov_len = sizeof val },
- { .iov_base = (void *) b.ptr, .iov_len = n },
- };
+ const int max_vec_size = 4;
+ struct iovec vec[1+max_vec_size];
adb_val_t o;
+ uint32_t i, align = 1;
+
+ assert(n <= max_vec_size);
+
+ vec[0] = (struct iovec) { .iov_base = &val, .iov_len = sizeof val };
+ for (i = 0; i < n; i++)
+ vec[i+1] = (struct iovec) { .iov_base = b[i].ptr, .iov_len = b[i].len };
- if (n > 0xffff) {
- val.u32 = htole32(n);
- vec[0].iov_len = sizeof val.u32;
+ size_t sz = iovec_len(&vec[1], n);
+ if (sz > 0xffff) {
+ val.u32 = htole32(sz);
+ vec[0].iov_len = align = sizeof val.u32;
o = ADB_TYPE_BLOB_32;
- } else if (n > 0xff) {
- val.u16 = htole16(n);
- vec[0].iov_len = sizeof val.u16;
+ } else if (sz > 0xff) {
+ val.u16 = htole16(sz);
+ vec[0].iov_len = align = sizeof val.u16;
o = ADB_TYPE_BLOB_16;
- } else if (n > 0) {
- val.u8 = n;
- vec[0].iov_len = sizeof val.u8;
+ } else if (sz > 0) {
+ val.u8 = sz;
+ vec[0].iov_len = align = sizeof val.u8;
o = ADB_TYPE_BLOB_8;
} else {
return ADB_VAL_NULL;
}
- return ADB_VAL(o, adb_w_data(db, vec, ARRAY_SIZE(vec), vec[0].iov_len));
+ return ADB_VAL(o, adb_w_data(db, vec, n+1, align));
+}
+
+adb_val_t adb_w_blob(struct adb *db, apk_blob_t b)
+{
+ return adb_w_blob_vec(db, 1, &b);
}
static adb_val_t adb_w_blob_raw(struct adb *db, apk_blob_t b)
@@ -968,10 +978,19 @@ adb_val_t adb_wa_append_fromstring(struct adb_obj *o, apk_blob_t b)
struct wacmp_param {
struct adb *db1, *db2;
- const struct adb_object_schema *schema;
+ union {
+ const struct adb_object_schema *schema;
+ int (*compare)(struct adb *db1, adb_val_t v1, struct adb *db2, adb_val_t v2);
+ };
int mode;
};
+static int wacmpscalar(const void *p1, const void *p2, void *arg)
+{
+ struct wacmp_param *wp = arg;
+ return wp->compare(wp->db1, *(adb_val_t *)p1, wp->db2, *(adb_val_t *)p2);
+}
+
static int wacmp(const void *p1, const void *p2, void *arg)
{
struct wacmp_param *wp = arg;
@@ -1005,6 +1024,10 @@ void adb_wa_sort(struct adb_obj *arr)
assert(schema->kind == ADB_KIND_ARRAY);
switch (*arr->schema->fields[0].kind) {
+ case ADB_KIND_BLOB:
+ arg.compare = container_of(arr->schema->fields[0].kind, struct adb_scalar_schema, kind)->compare;
+ qsort_r(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmpscalar, &arg);
+ break;
case ADB_KIND_OBJECT:
arg.schema = container_of(arr->schema->fields[0].kind, struct adb_object_schema, kind);
qsort_r(&arr->obj[ADBI_FIRST], adb_ra_num(arr), sizeof(arr->obj[0]), wacmp, &arg);
diff --git a/src/adb.h b/src/adb.h
index 7c1869c..8649989 100644
--- a/src/adb.h
+++ b/src/adb.h
@@ -204,6 +204,7 @@ int adb_ra_find(struct adb_obj *arr, int cur, struct adb_obj *tmpl);
/* Primitive write */
void adb_w_root(struct adb *, adb_val_t);
void adb_w_rootobj(struct adb_obj *);
+adb_val_t adb_w_blob_vec(struct adb *, uint32_t, apk_blob_t *);
adb_val_t adb_w_blob(struct adb *, apk_blob_t);
adb_val_t adb_w_int(struct adb *, uint32_t);
adb_val_t adb_w_copy(struct adb *, struct adb *, adb_val_t);
diff --git a/src/apk_adb.c b/src/apk_adb.c
index 7d8b1fb..6dfb301 100644
--- a/src/apk_adb.c
+++ b/src/apk_adb.c
@@ -114,6 +114,53 @@ const struct adb_object_schema schema_string_array = {
.fields = ADB_ARRAY_ITEM(scalar_string),
};
+static apk_blob_t xattr_tostring(struct adb *db, adb_val_t val, char *buf, size_t bufsz)
+{
+ apk_blob_t b = adb_r_blob(db, val), to = APK_BLOB_PTR_LEN(buf, bufsz), k, v;
+
+ if (APK_BLOB_IS_NULL(b)) return b;
+ if (!apk_blob_rsplit(b, 0, &k, &v)) return APK_BLOB_NULL;
+
+ apk_blob_push_blob(&to, k);
+ apk_blob_push_blob(&to, APK_BLOB_PTR_LEN("=", 1));
+ apk_blob_push_hexdump(&to, v);
+ if (!APK_BLOB_IS_NULL(to))
+ return APK_BLOB_PTR_PTR(buf, to.ptr-1);
+ return APK_BLOB_PTR_LEN(buf, snprintf(buf, bufsz, BLOB_FMT "=(%d bytes)",
+ BLOB_PRINTF(k), (int)v.len));
+}
+
+static adb_val_t xattr_fromstring(struct adb *db, apk_blob_t val)
+{
+ char buf[256];
+ apk_blob_t b[2], hex;
+
+ if (!apk_blob_rsplit(val, '=', &b[0], &hex)) return ADB_ERROR(APKE_ADB_SCHEMA);
+ b[0].len++;
+
+ if (hex.len & 1) return ADB_ERROR(EINVAL);
+ if (hex.len/2 > sizeof buf) return ADB_ERROR(E2BIG);
+ b[1] = APK_BLOB_PTR_LEN(buf, hex.len / 2);
+ apk_blob_pull_hexdump(&hex, b[1]);
+ if (APK_BLOB_IS_NULL(hex)) return ADB_ERROR(EINVAL);
+
+ return adb_w_blob_vec(db, ARRAY_SIZE(b), b);
+}
+
+static const struct adb_scalar_schema schema_xattr = {
+ .kind = ADB_KIND_BLOB,
+ .tostring = xattr_tostring,
+ .fromstring = xattr_fromstring,
+ .compare = string_compare,
+};
+
+const struct adb_object_schema schema_xattr_array = {
+ .kind = ADB_KIND_ARRAY,
+ .num_fields = 8,
+ .pre_commit = adb_wa_sort,
+ .fields = ADB_ARRAY_ITEM(schema_xattr),
+};
+
static adb_val_t version_fromstring(struct adb *db, apk_blob_t val)
{
if (!apk_version_validate(val)) return ADB_ERROR(APKE_PKGVERSION_FORMAT);
@@ -154,10 +201,8 @@ static adb_val_t hexblob_fromstring(struct adb *db, apk_blob_t val)
{
char buf[256];
- if (val.len & 1)
- return ADB_ERROR(EINVAL);
- if (val.len > sizeof buf)
- return ADB_ERROR(E2BIG);
+ if (val.len & 1) return ADB_ERROR(EINVAL);
+ if (val.len/2 > sizeof buf) return ADB_ERROR(E2BIG);
apk_blob_t b = APK_BLOB_PTR_LEN(buf, val.len / 2);
apk_blob_pull_hexdump(&val, b);
@@ -429,7 +474,7 @@ const struct adb_object_schema schema_acl = {
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),
+ ADB_FIELD(ADBI_ACL_XATTRS, "xattrs", schema_xattr_array),
},
};
diff --git a/src/apk_adb.h b/src/apk_adb.h
index 0bc46e9..74b0577 100644
--- a/src/apk_adb.h
+++ b/src/apk_adb.h
@@ -92,6 +92,7 @@ struct adb_data_package {
extern const struct adb_object_schema
schema_dependency, schema_dependency_array,
schema_pkginfo, schema_pkginfo_array,
+ schema_xattr_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/app_mkpkg.c b/src/app_mkpkg.c
index 552ef57..8984700 100644
--- a/src/app_mkpkg.c
+++ b/src/app_mkpkg.c
@@ -22,6 +22,7 @@
#include "apk_pathbuilder.h"
#include "apk_extract.h"
#include "apk_print.h"
+#include "apk_xattr.h"
#define BLOCK_SIZE 4096
@@ -128,6 +129,42 @@ static const struct apk_option_group optgroup_applet = {
.parse = option_parse_applet,
};
+static adb_val_t create_xattrs(struct adb *db, int fd)
+{
+ struct adb_obj xa;
+ char names[1024], buf[1024];
+ ssize_t len, vlen;
+ adb_val_t val;
+ int i;
+
+ len = apk_flistxattr(fd, names, sizeof names);
+ if (len <= 0) return ADB_NULL;
+
+ adb_wo_alloca(&xa, &schema_xattr_array, db);
+ for (i = 0; i < len; i += strlen(&names[i]) + 1) {
+ vlen = apk_fgetxattr(fd, &names[i], buf, sizeof buf);
+ if (vlen < 0) continue;
+
+ apk_blob_t vec[] = {
+ APK_BLOB_PTR_LEN(&names[i], strlen(&names[i])+1),
+ APK_BLOB_PTR_LEN(buf, vlen),
+ };
+ adb_wa_append(&xa, adb_w_blob_vec(db, ARRAY_SIZE(vec), vec));
+ }
+ close(fd);
+ val = adb_w_arr(&xa);
+ adb_wo_free(&xa);
+
+ return val;
+}
+
+static adb_val_t create_xattrs_closefd(struct adb *db, int fd)
+{
+ adb_val_t val = create_xattrs(db, fd);
+ close(fd);
+ return val;
+}
+
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)
@@ -145,6 +182,7 @@ static int mkpkg_process_directory(struct mkpkg_ctx *ctx, int dirfd, struct apk_
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_val(&acl, ADBI_ACL_XATTRS, create_xattrs(&ctx->db, dirfd));
adb_wo_obj(&fio, ADBI_DI_ACL, &acl);
adb_wo_alloca(&files, &schema_file_array, &ctx->db);
@@ -233,6 +271,7 @@ static int mkpkg_process_dirent(void *pctx, int dirfd, const char *entry)
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_val(&acl, ADBI_ACL_XATTRS, create_xattrs_closefd(&ctx->db, openat(dirfd, entry, O_RDONLY)));
adb_wo_obj(&fio, ADBI_FI_ACL, &acl);
adb_wa_append_obj(ctx->files, &fio);
diff --git a/src/extract_v3.c b/src/extract_v3.c
index a28eae1..d98fe99 100644
--- a/src/extract_v3.c
+++ b/src/extract_v3.c
@@ -24,9 +24,26 @@ struct apk_extract_v3_ctx {
static void apk_extract_v3_acl(struct apk_file_info *fi, struct adb_obj *o, struct apk_id_cache *idc)
{
+ struct adb_obj xa;
+ apk_blob_t x, key, value;
+ int i;
+
fi->mode = adb_ro_int(o, ADBI_ACL_MODE);
fi->uid = apk_id_cache_resolve_uid(idc, adb_ro_blob(o, ADBI_ACL_USER), 65534);
fi->gid = apk_id_cache_resolve_gid(idc, adb_ro_blob(o, ADBI_ACL_GROUP), 65534);
+
+ adb_ro_obj(o, ADBI_ACL_XATTRS, &xa);
+
+ apk_xattr_array_resize(&fi->xattrs, adb_ra_num(&xa));
+ for (i = ADBI_FIRST; i <= adb_ra_num(&xa); i++) {
+ x = adb_ro_blob(&xa, i);
+ apk_blob_rsplit(x, 0, &key, &value);
+
+ fi->xattrs->item[i-1] = (struct apk_xattr) {
+ .name = key.ptr,
+ .value = value,
+ };
+ }
}
static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct apk_istream *is)
@@ -43,6 +60,7 @@ static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct ap
apk_blob_t target;
int r;
+ apk_xattr_array_init(&fi.xattrs);
apk_extract_v3_acl(&fi, adb_ro_obj(&ctx->file, ADBI_FI_ACL, &acl), apk_ctx_get_id_cache(ectx->ac));
target = adb_ro_blob(&ctx->file, ADBI_FI_TARGET);
@@ -50,7 +68,7 @@ static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct ap
char *target_path;
uint16_t mode;
- if (target.len < 2) return -APKE_ADB_SCHEMA;
+ if (target.len < 2) goto err_schema;
mode = le16toh(*(uint16_t*)target.ptr);
target.ptr += 2;
target.len -= 2;
@@ -58,7 +76,7 @@ static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct ap
case S_IFBLK:
case S_IFCHR:
case S_IFIFO:
- if (target.len != sizeof(uint64_t)) return -APKE_ADB_SCHEMA;
+ if (target.len != sizeof(uint64_t)) goto err_schema;
struct unaligned64 {
uint64_t value;
} __attribute__((packed));
@@ -71,19 +89,28 @@ static int apk_extract_v3_file(struct apk_extract_ctx *ectx, off_t sz, struct ap
fi.link_target = target_path;
break;
default:
- return -APKE_ADB_SCHEMA;
+ err_schema:
+ r = -APKE_ADB_SCHEMA;
+ goto done;
}
fi.mode |= mode;
- return ectx->ops->file(ectx, &fi, is);
+ r = ectx->ops->file(ectx, &fi, is);
+ goto done;
}
apk_digest_from_blob(&fi.digest, adb_ro_blob(&ctx->file, ADBI_FI_HASHES));
- if (fi.digest.alg == APK_DIGEST_NONE) return -APKE_ADB_SCHEMA;
+ if (fi.digest.alg == APK_DIGEST_NONE) goto err_schema;
fi.mode |= S_IFREG;
- if (!is) return ectx->ops->file(ectx, &fi, 0);
+ if (!is) {
+ r = ectx->ops->file(ectx, &fi, 0);
+ goto done;
+ }
r = ectx->ops->file(ectx, &fi, apk_istream_verify(&dis, is, fi.size, &fi.digest));
- return apk_istream_close_error(&dis.is, r);
+ r = apk_istream_close_error(&dis.is, r);
+done:
+ apk_fileinfo_free(&fi);
+ return r;
}
static int apk_extract_v3_directory(struct apk_extract_ctx *ectx)
@@ -93,11 +120,15 @@ static int apk_extract_v3_directory(struct apk_extract_ctx *ectx)
.name = apk_pathbuilder_cstr(&ctx->pb),
};
struct adb_obj acl;
+ int r;
+ apk_xattr_array_init(&fi.xattrs);
apk_extract_v3_acl(&fi, adb_ro_obj(&ctx->path, ADBI_DI_ACL, &acl), apk_ctx_get_id_cache(ectx->ac));
fi.mode |= S_IFDIR;
+ r = ectx->ops->file(ectx, &fi, 0);
+ apk_fileinfo_free(&fi);
- return ectx->ops->file(ectx, &fi, 0);
+ return r;
}
static int apk_extract_v3_next_file(struct apk_extract_ctx *ectx)