diff options
author | Timo Teräs <timo.teras@iki.fi> | 2023-09-11 17:26:33 +0300 |
---|---|---|
committer | Timo Teräs <timo.teras@iki.fi> | 2023-09-22 08:53:03 +0000 |
commit | 718c44d02e71746c614918141e967b8e45df8eb4 (patch) | |
tree | 65f828b72a854a81614b643283d5749fa58ddceb | |
parent | 99a264f936d752a45ee83442736163163ca458e2 (diff) | |
download | apk-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.c | 57 | ||||
-rw-r--r-- | src/adb.h | 1 | ||||
-rw-r--r-- | src/apk_adb.c | 55 | ||||
-rw-r--r-- | src/apk_adb.h | 1 | ||||
-rw-r--r-- | src/app_mkpkg.c | 39 | ||||
-rw-r--r-- | src/extract_v3.c | 47 |
6 files changed, 170 insertions, 30 deletions
@@ -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); @@ -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) |