summaryrefslogtreecommitdiffhomepage
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/arbits/slbt_archive_merge.c698
1 files changed, 698 insertions, 0 deletions
diff --git a/src/arbits/slbt_archive_merge.c b/src/arbits/slbt_archive_merge.c
new file mode 100644
index 0000000..acbb318
--- /dev/null
+++ b/src/arbits/slbt_archive_merge.c
@@ -0,0 +1,698 @@
+/*******************************************************************/
+/* slibtool: a skinny libtool implementation, written in C */
+/* Copyright (C) 2016--2024 SysDeer Technologies, LLC */
+/* Released under the Standard MIT License; see COPYING.SLIBTOOL. */
+/*******************************************************************/
+
+#include <time.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <stddef.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+#include <sys/mman.h>
+#include <sys/types.h>
+
+#include <slibtool/slibtool.h>
+#include <slibtool/slibtool_arbits.h>
+#include "slibtool_ar_impl.h"
+#include "slibtool_driver_impl.h"
+#include "slibtool_errinfo_impl.h"
+
+/* anonymous fun */
+#ifndef MAP_ANONYMOUS
+#define MAP_ANONYMOUS MAP_ANON
+#endif
+
+/* time stamp format specifier */
+#define PPRII64 "%"PRIi64
+
+/* file size format specifier */
+#define PPRIU64 "%"PRIu64
+
+struct armap_buffer_32 {
+ uint32_t moffset;
+ const char * symname;
+ uint32_t baseidx;
+};
+
+struct armap_buffer_64 {
+ uint64_t moffset;
+ const char * symname;
+ uint64_t baseidx;
+};
+
+static const char ar_signature[] = AR_SIGNATURE;
+
+static int slbt_create_anonymous_archive_ctx(
+ const struct slbt_driver_ctx * dctx,
+ size_t size,
+ struct slbt_archive_ctx ** pctx)
+{
+ struct slbt_archive_ctx_impl * ctx;
+
+ if (!(ctx = calloc(1,sizeof(*ctx))))
+ return SLBT_BUFFER_ERROR(dctx);
+
+ ctx->map.map_size = size;
+ ctx->map.map_addr = mmap(
+ 0,size,
+ PROT_READ|PROT_WRITE,
+ MAP_PRIVATE|MAP_ANONYMOUS,
+ -1,0);
+
+ if (ctx->map.map_addr == MAP_FAILED) {
+ free(ctx);
+ return SLBT_SYSTEM_ERROR(dctx,0);
+ }
+
+ ctx->dctx = dctx;
+ ctx->actx.map = &ctx->map;
+
+ *pctx = &ctx->actx;
+
+ return 0;
+}
+
+static off_t slbt_armap_write_be_32(unsigned char * mark, uint32_t val)
+{
+ mark[0] = val >> 24;
+ mark[1] = val >> 16;
+ mark[2] = val >> 8;
+ mark[3] = val;
+
+ return sizeof(uint32_t);
+}
+
+static off_t slbt_armap_write_le_32(unsigned char * mark, uint32_t val)
+{
+ mark[0] = val;
+ mark[1] = val >> 8;
+ mark[2] = val >> 16;
+ mark[3] = val >> 24;
+
+ return sizeof(uint32_t);
+}
+
+static off_t slbt_armap_write_be_64(unsigned char * mark, uint64_t val)
+{
+ slbt_armap_write_be_32(&mark[0],val >> 32);
+ slbt_armap_write_be_32(&mark[4],val);
+
+ return sizeof(uint64_t);
+}
+
+static off_t slbt_armap_write_le_64(unsigned char * mark, uint64_t val)
+{
+ slbt_armap_write_be_32(&mark[0],val);
+ slbt_armap_write_be_32(&mark[4],val >> 32);
+
+ return sizeof(uint64_t);
+}
+
+
+static int slbt_merge_archives_fail(
+ struct slbt_archive_ctx * arctx,
+ struct armap_buffer_32 * bsdmap32,
+ struct armap_buffer_64 * bsdmap64,
+ int ret)
+{
+ if (bsdmap32)
+ free(bsdmap32);
+
+ if (bsdmap64)
+ free(bsdmap64);
+
+ if (arctx)
+ slbt_free_archive_ctx(arctx);
+
+ return ret;
+}
+
+
+int slbt_merge_archives(
+ struct slbt_archive_ctx * const arctxv[],
+ struct slbt_archive_ctx ** arctxm)
+{
+ struct slbt_archive_ctx * const * arctxp;
+ struct slbt_archive_ctx * arctx;
+
+ const struct slbt_driver_ctx * dctx;
+ const struct slbt_archive_meta * meta;
+
+ struct ar_raw_file_header * arhdr;
+ struct ar_meta_member_info ** memberp;
+ struct ar_meta_member_info * meminfo;
+
+ struct ar_meta_member_info * armap;
+ struct ar_meta_member_info * arnames;
+
+ const struct ar_meta_armap_common_32 * armap32;
+ const struct ar_meta_armap_common_64 * armap64;
+ const struct ar_meta_armap_ref_32 * symref32;
+ const struct ar_meta_armap_ref_64 * symref64;
+
+ struct armap_buffer_32 * bsdmap32;
+ struct armap_buffer_64 * bsdmap64;
+ struct armap_buffer_32 * bsdsort32;
+ struct armap_buffer_64 * bsdsort64;
+
+ size_t nbytes;
+ ssize_t nwritten;
+
+ uint32_t mapattr;
+ uint64_t nmembers;
+ uint64_t nsymrefs;
+
+ uint64_t sarmap;
+ uint64_t sarname;
+ uint64_t sarchive;
+ uint64_t smembers;
+ uint64_t ssymrefs;
+ uint64_t ssymstrs;
+ uint64_t snamestrs;
+
+ int64_t omembers;
+ int64_t osymrefs;
+ int64_t onamestrs;
+ int64_t omemfixup;
+
+ char * base;
+ unsigned char * ubase;
+
+ char * ch;
+ unsigned char * uch;
+
+ char * namebase;
+ char * namestr;
+ char * strtbl;
+
+ uint64_t idx;
+ uint64_t mapidx;
+ uint64_t cmpidx;
+
+ off_t (*armap_write_uint32)(
+ unsigned char *,
+ uint32_t);
+
+ off_t (*armap_write_uint64)(
+ unsigned char *,
+ uint64_t);
+
+ /* init */
+ nmembers = nsymrefs = ssymstrs = mapattr = 0;
+ sarchive = smembers = ssymrefs = snamestrs = 0;
+ omembers = osymrefs = onamestrs = 0;
+
+ if (!arctxv || !arctxv[0])
+ return -1;
+
+ if (!(dctx = slbt_get_archive_ictx(arctxv[0])->dctx))
+ return -1;
+
+ /* determine armap type and size of archive elements */
+ for (armap=0,arnames=0,arctxp=arctxv; *arctxp; arctxp++) {
+ if (slbt_get_archive_ictx(*arctxp)->dctx != dctx)
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_DRIVER_MISMATCH);
+
+ meta = (*arctxp)->meta;
+ armap32 = meta->a_armap_primary.ar_armap_common_32;
+ armap64 = meta->a_armap_primary.ar_armap_common_64;
+
+ for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ if (armap32) {
+ if (mapattr == 0) {
+ armap = meminfo;
+ mapattr = armap32->ar_armap_attr;
+ } else if (mapattr != armap32->ar_armap_attr) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ARMAP_MISMATCH);
+ }
+
+ nsymrefs += armap32->ar_num_of_symbols;
+ ssymstrs += armap32->ar_size_of_strs;
+
+ } else if (armap64) {
+ if (mapattr == 0) {
+ armap = meminfo;
+ mapattr = armap64->ar_armap_attr;
+ } else if (mapattr != armap64->ar_armap_attr) {
+ return SLBT_CUSTOM_ERROR(
+ dctx,
+ SLBT_ERR_AR_ARMAP_MISMATCH);
+ }
+
+ nsymrefs += armap64->ar_num_of_symbols;
+ }
+
+ break;
+
+ case AR_MEMBER_ATTR_LINKINFO:
+ break;
+
+ case AR_MEMBER_ATTR_NAMESTRS:
+ snamestrs += meminfo->ar_object_size;
+
+ if (!arnames)
+ arnames = meminfo;
+
+ break;
+
+ default:
+ smembers += sizeof(struct ar_raw_file_header);
+ smembers += meminfo->ar_file_header.ar_file_size;
+ smembers += 1;
+ smembers |= 1;
+ smembers ^= 1;
+ nmembers++;
+
+ break;
+ }
+ }
+ }
+
+ /* armap size */
+ if (sarmap = 0, sarname = 0, (mapattr == 0)) {
+ (void)0;
+
+ } else if (mapattr & AR_ARMAP_ATTR_SYSV) {
+ if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
+ sarmap += sizeof(uint32_t);
+ sarmap += sizeof(uint32_t) * nsymrefs;
+ } else {
+ sarmap += sizeof(uint64_t);
+ sarmap += sizeof(uint64_t) * nsymrefs;
+ }
+
+ } else if (mapattr & AR_ARMAP_ATTR_BSD) {
+ if (mapattr & (AR_ARMAP_ATTR_LE_32|AR_ARMAP_ATTR_BE_32)) {
+ sarmap += 2 * sizeof(uint32_t);
+ sarmap += 2 * sizeof(uint32_t) * nsymrefs;
+ } else {
+ sarmap += 2 * sizeof(uint64_t);
+ sarmap += 2 * sizeof(uint64_t) * nsymrefs;
+ }
+
+ sarname += armap->ar_file_header.ar_file_size;
+ sarname -= armap->ar_object_size;
+ } else {
+ return SLBT_CUSTOM_ERROR(dctx,SLBT_ERR_FLOW_ERROR);
+ }
+
+ /* long-names member alignment */
+ snamestrs += 1;
+ snamestrs |= 1;
+ snamestrs ^= 1;
+
+ /* archive size */
+ sarchive = sizeof(struct ar_raw_signature);
+ sarchive += armap ? sizeof(struct ar_raw_file_header) : 0;
+ sarchive += arnames ? sizeof(struct ar_raw_file_header) : 0;
+ sarchive += sarname;
+ sarchive += sarmap;
+ sarchive += ssymstrs;
+ sarchive += snamestrs;
+ sarchive += smembers;
+
+ /* offset from archive base to first public member */
+ omembers = sarchive;
+ omembers -= smembers;
+
+
+ /* create in-memory archive */
+ if (slbt_create_anonymous_archive_ctx(dctx,sarchive,&arctx) < 0)
+ return SLBT_NESTED_ERROR(dctx);
+
+
+ /* get ready for writing */
+ base = arctx->map->map_addr;
+ ubase = arctx->map->map_addr;
+
+
+ /* archive header */
+ ch = base;
+ memcpy(ch,ar_signature,sizeof(struct ar_raw_signature));
+ ch += sizeof(struct ar_raw_signature);
+
+
+ /* signature only? */
+ if (!armap && !arnames && !nmembers) {
+ slbt_free_archive_ctx(arctx);
+ *arctxm = 0;
+ return 0;
+ }
+
+
+ /* armap header */
+ if (armap) {
+ arhdr = (struct ar_raw_file_header *)ch;
+ memcpy(arhdr,armap->ar_member_data,sizeof(*arhdr)+sarname);
+
+ nwritten = armap->ar_file_header.ar_time_date_stamp
+ ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
+ : 0;
+
+ if (nwritten < 0)
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
+ arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
+
+ nwritten = sprintf(
+ arhdr->ar_file_size,PPRIU64,
+ sarname + sarmap + ssymstrs);
+
+ if (nwritten < 0)
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
+ arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
+ }
+
+
+ /* arnames header (sysv only) */
+ if (arnames) {
+ ch = base;
+ ch += omembers;
+ ch -= snamestrs;
+ ch -= sizeof(struct ar_raw_file_header);
+
+ namebase = ch;
+ namebase += sizeof(struct ar_raw_file_header);
+
+ memset(namebase,0,snamestrs);
+ namestr = namebase;
+
+ arhdr = (struct ar_raw_file_header *)ch;
+ memcpy(arhdr,arnames->ar_member_data,sizeof(*arhdr));
+
+ nwritten = arnames->ar_file_header.ar_time_date_stamp
+ ? sprintf(arhdr->ar_time_date_stamp,PPRII64,time(0))
+ : 0;
+
+ if (nwritten < 0)
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_time_date_stamp); nbytes++)
+ arhdr->ar_time_date_stamp[nbytes] = AR_DEC_PADDING;
+
+ nwritten = sprintf(
+ arhdr->ar_file_size,PPRIU64,
+ snamestrs);
+
+ if (nwritten < 0)
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_size); nbytes++)
+ arhdr->ar_file_size[nbytes] = AR_DEC_PADDING;
+ }
+
+
+ /* armap data (preparation) */
+ armap_write_uint32 = 0;
+ armap_write_uint64 = 0;
+
+ bsdmap32 = 0;
+ bsdmap64 = 0;
+
+ if (mapattr & AR_ARMAP_ATTR_BE_32)
+ armap_write_uint32 = slbt_armap_write_be_32;
+
+ else if (mapattr & AR_ARMAP_ATTR_LE_32)
+ armap_write_uint32 = slbt_armap_write_le_32;
+
+ else if (mapattr & AR_ARMAP_ATTR_BE_64)
+ armap_write_uint64 = slbt_armap_write_be_64;
+
+ else if (mapattr & AR_ARMAP_ATTR_LE_64)
+ armap_write_uint64 = slbt_armap_write_le_64;
+
+ uch = ubase;
+ uch += sizeof(struct ar_raw_signature);
+ uch += sizeof(struct ar_raw_file_header);
+ uch += sarname;
+
+ if (mapattr & AR_ARMAP_ATTR_SYSV) {
+ if (armap_write_uint32) {
+ uch += armap_write_uint32(uch,nsymrefs);
+
+ ch = base;
+ ch += uch - ubase;
+ ch += sizeof(uint32_t) * nsymrefs;
+ } else {
+ uch += armap_write_uint64(uch,nsymrefs);
+
+ ch = base;
+ ch += uch - ubase;
+ ch += sizeof(uint64_t) * nsymrefs;
+ }
+
+ } else if (mapattr & AR_ARMAP_ATTR_BSD) {
+ strtbl = base;
+ strtbl += omembers;
+ strtbl -= ssymstrs;
+
+ memset(strtbl,0,ssymstrs);
+
+ if (armap_write_uint32) {
+ if (!(bsdmap32 = calloc(2*nsymrefs,sizeof(struct armap_buffer_32))))
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ bsdsort32 = &bsdmap32[nsymrefs];
+
+ } else {
+ if (!(bsdmap64 = calloc(2*nsymrefs,sizeof(struct armap_buffer_64))))
+ return slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_SYSTEM_ERROR(dctx,0));
+
+ bsdsort64 = &bsdmap64[nsymrefs];
+ }
+ }
+
+ /* main iteration (armap data, long-names, public members) */
+ for (mapidx=0,arctxp=arctxv; *arctxp; arctxp++) {
+ meta = (*arctxp)->meta;
+ armap32 = meta->a_armap_primary.ar_armap_common_32;
+ armap64 = meta->a_armap_primary.ar_armap_common_64;
+
+ if ((memberp = meta->a_memberv)) {
+ for (omemfixup=0; *memberp && !omemfixup; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ case AR_MEMBER_ATTR_LINKINFO:
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ omemfixup = (int64_t)meminfo->ar_member_data;
+ omemfixup -= (int64_t)meta->r_archive.map_addr;
+ break;
+ }
+ }
+ }
+
+ for (memberp=meta->a_memberv; memberp && *memberp; memberp++) {
+ meminfo = *memberp;
+
+ switch (meminfo->ar_member_attr) {
+ case AR_MEMBER_ATTR_ARMAP:
+ if (armap32 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
+ symref32 = armap32->ar_symrefs;
+
+ for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
+ uch += armap_write_uint32(
+ uch,
+ symref32[idx].ar_member_offset + omembers - omemfixup);
+
+ strcpy(ch,&armap32->ar_string_table[symref32[idx].ar_name_offset]);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ } else if (armap64 && (mapattr & AR_ARMAP_ATTR_SYSV)) {
+ symref64 = armap64->ar_symrefs;
+
+ for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
+ uch += armap_write_uint64(
+ uch,
+ symref64[idx].ar_member_offset + omembers - omemfixup);
+
+ strcpy(ch,&armap64->ar_string_table[symref64[idx].ar_name_offset]);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ } else if (armap32 && (mapattr & AR_ARMAP_ATTR_BSD)) {
+ symref32 = armap32->ar_symrefs;
+
+ for (idx=0; idx<armap32->ar_num_of_symbols; idx++) {
+ bsdmap32[mapidx].moffset = symref32[idx].ar_member_offset;
+ bsdmap32[mapidx].moffset += omembers - omemfixup;
+
+ bsdmap32[mapidx].symname = armap32->ar_string_table;
+ bsdmap32[mapidx].symname += symref32[idx].ar_name_offset;
+
+ mapidx++;
+ }
+
+ } else if (armap64 && (mapattr & AR_ARMAP_ATTR_BSD)) {
+ symref64 = armap64->ar_symrefs;
+
+ for (idx=0; idx<armap64->ar_num_of_symbols; idx++) {
+ bsdmap64[mapidx].moffset = symref64[idx].ar_member_offset;
+ bsdmap64[mapidx].moffset += omembers - omemfixup;
+
+ bsdmap64[mapidx].symname = armap64->ar_string_table;
+ bsdmap64[mapidx].symname += symref64[idx].ar_name_offset;
+
+ mapidx++;
+ }
+ }
+
+ break;
+
+ case AR_MEMBER_ATTR_LINKINFO:
+ break;
+
+ case AR_MEMBER_ATTR_NAMESTRS:
+ break;
+
+ default:
+ arhdr = meminfo->ar_member_data;
+
+ memcpy(
+ &base[omembers],arhdr,
+ sizeof(*arhdr) + meminfo->ar_file_header.ar_file_size);
+
+ if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_SYSV) {
+ if (meminfo->ar_file_header.ar_header_attr & AR_HEADER_ATTR_NAME_REF) {
+ nwritten = sprintf(
+ &base[omembers],"/"PPRII64,
+ namestr - namebase);
+
+ if (nwritten < 0)
+ SLBT_SYSTEM_ERROR(dctx,0);
+
+ for (nbytes=nwritten; nbytes < sizeof(arhdr->ar_file_id); nbytes++)
+ base[omembers + nbytes] = AR_DEC_PADDING;
+
+ strcpy(namestr,meminfo->ar_file_header.ar_member_name);
+ namestr += strlen(namestr);
+ *namestr++ = '/';
+ *namestr++ = AR_OBJ_PADDING;
+ }
+ }
+
+ omembers += sizeof(*arhdr);
+ omembers += meminfo->ar_file_header.ar_file_size;
+ omembers += 1;
+ omembers |= 1;
+ omembers ^= 1;
+ break;
+ }
+ }
+ }
+
+ /* bsd variant: also sort the string table (because we can:=)) */
+ if (bsdmap32) {
+ for (mapidx=0; mapidx<nsymrefs; mapidx++)
+ for (cmpidx=0; cmpidx<nsymrefs; cmpidx++)
+ if (strcmp(bsdmap32[cmpidx].symname,bsdmap32[mapidx].symname) < 0)
+ bsdmap32[mapidx].baseidx++;
+
+ /* a symbol might be present in more than one member; */
+ /* see whether ar_member_offset has already been set) */
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ idx = bsdmap32[mapidx].baseidx;
+
+ for (; bsdsort32[idx].moffset; )
+ idx++;
+
+ bsdsort32[idx].moffset = bsdmap32[mapidx].moffset;
+ bsdsort32[idx].symname = bsdmap32[mapidx].symname;
+ }
+
+ uch += armap_write_uint32(uch,2*sizeof(uint32_t)*nsymrefs);
+
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ uch += armap_write_uint32(uch,ch-strtbl);
+ uch += armap_write_uint32(uch,bsdsort32[mapidx].moffset);
+
+ strcpy(ch,bsdsort32[mapidx].symname);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ uch +=armap_write_uint32(uch,ssymstrs);
+
+ free(bsdmap32);
+
+ } else if (bsdmap64) {
+ for (mapidx=0; mapidx<nsymrefs; mapidx++)
+ for (cmpidx=0; cmpidx<nsymrefs; cmpidx++)
+ if (strcmp(bsdmap64[cmpidx].symname,bsdmap64[mapidx].symname) < 0)
+ bsdmap64[mapidx].baseidx++;
+
+ /* a symbol might be present in more than one member; */
+ /* see whether ar_member_offset has already been set) */
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ idx = bsdmap64[mapidx].baseidx;
+
+ for (; bsdsort64[idx].moffset; )
+ idx++;
+
+ bsdsort64[idx].moffset = bsdmap64[mapidx].moffset;
+ bsdsort64[idx].symname = bsdmap64[mapidx].symname;
+ }
+
+ uch += armap_write_uint64(uch,2*sizeof(uint64_t)*nsymrefs);
+
+ for (mapidx=0,ch=strtbl; mapidx<nsymrefs; mapidx++) {
+ uch += armap_write_uint64(uch,ch-strtbl);
+ uch += armap_write_uint64(uch,bsdsort64[mapidx].moffset);
+
+ strcpy(ch,bsdsort64[mapidx].symname);
+ ch += strlen(ch);
+ ch++;
+ }
+
+ uch +=armap_write_uint64(uch,ssymstrs);
+
+ free(bsdmap64);
+ }
+
+ struct slbt_archive_ctx_impl * ictx;
+ ictx = slbt_get_archive_ictx(arctx);
+
+ if (slbt_get_archive_meta(dctx,arctx->map,&ictx->meta) < 0)
+ slbt_merge_archives_fail(
+ arctx,0,0,
+ SLBT_NESTED_ERROR(dctx));
+
+ ictx->actx.meta = ictx->meta;
+
+ *arctxm = arctx;
+
+ return 0;
+}