include, libctf, ld: delete compression from the API

CTF archive member-by-member compression doesn't work with the new CTF
archive format, and is not supported by BTF readers at all.  ld has
already been modified to never compress written-out CTF; now modify the
API to delete compression entirely.  (We will reinstate compression by
simply writing to compressed .ctf ELF sections, which doesn't need any
specific libctf support: instead, its callers deal with all of it.)

This lets us drop really quite a lot of code, including dropping several
tests relating purely to bugs specific to compression.

include/
	* ctf-api.h (ctf_compress_write): Delete.
	(ctf_write_mem): Delete threshold arg.
	(ctf_arc_write_fd): Likewise.
	(ctf_link_output_is_btf): Drop mention of it.
	(ctf_link_write): Likewise.

ld/
	* ldlang.c (lang_write_ctf): Drop threshold arg from
	ctf_link_write call.

libctf/
	* ctf-archive.c (arc_write_one_ctf): Drop threshold arg and all
	uses.
	(ctf_arc_preserialize): Likewise.
	(ctf_arc_write_fd): Likewise.
	(ctf_arc_write): Likewise.
	* ctf-impl.h (ctf_preserialize): Likewise.
	* ctf-link.c (ctf_link_write): Likewise.
	* ctf-serialize.c (ctf_preserialize): Drop force_ctf arg.
	(ctf_serialize): Likewise.
	(ctf_write_mem): Drop threshold arg, compression, and related
	allocation machinery.  Do forced write-time flipping (if
	requested) directly on the ctf_serialized buffer.
	(ctf_write_thresholded): Fold into...
	(ctf_write): ... this.
	(ctf_compress_write): Delete.
	* libctf.ver: Likewise.
	* testsuite/libctf-writable/ctf-nonroot-linking.c: Adjust
	ctf_link_write call.
	* testsuite/libctf-regression/zrewrite*: Removed.
	* testsuite/libctf-writable/ctf-compressed.*: Removed.
This commit is contained in:
Nick Alcock 2026-05-21 16:20:15 +01:00
parent 5532fbca2e
commit 40324c4034
13 changed files with 50 additions and 473 deletions

View file

@ -1242,19 +1242,14 @@ extern ctf_ret_t ctf_rollback (ctf_dict_t *, ctf_snapshot_id_t);
/* Dict writeout. See ctf_version().
ctf_write: write out an uncompressed dict to an fd.
ctf_compress_write: write out a compressed dict to an fd (currently always
gzip, but this may change in future).
ctf_write_mem: write out a dict to a buffer and return it and its size,
compressing it if its uncompressed size is over THRESHOLD.
ctf_write: write out a dict to an fd.
ctf_write_mem: write out a dict to a buffer and return it and its size.
If the ctf_btf_mode is not LIBCTF_BTM_ALWAYS and the threshold is -1,
the resulting dict may be pure BTF.
*/
If the ctf_btf_mode is not LIBCTF_BTM_ALWAYS, the resulting dict may be pure
BTF. */
extern int ctf_write (ctf_dict_t *, int);
extern int ctf_compress_write (ctf_dict_t * fp, int fd);
extern unsigned char *ctf_write_mem (ctf_dict_t *, size_t *, size_t threshold);
extern unsigned char *ctf_write_mem (ctf_dict_t *, size_t *);
/* Create a CTF archive named FILE from CTF_DICTS inputs (or write it to the
passed-in fd). The member names are derived from the cunames of the
@ -1266,8 +1261,8 @@ typedef enum ctf_arc_write_flags
} ctf_arc_write_flags_t;
extern ctf_error_t ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t,
size_t, ctf_arc_write_flags_t);
extern ctf_error_t ctf_arc_write_fd (int, ctf_dict_t **, size_t, size_t,
ctf_arc_write_flags_t);
extern ctf_error_t ctf_arc_write_fd (int, ctf_dict_t **, size_t,
ctf_arc_write_flags_t);
/* Prohibit writeout of this type kind: attempts to write it out cause
@ -1348,12 +1343,12 @@ extern ctf_ret_t ctf_link_shuffle_syms (ctf_dict_t *);
/* Determine the file format of the dict that will be written out after the
calls above is compatible with pure BTF or would require CTF. (Other things
may nonetheless require CTF, in particular, compression.) */
may nonetheless require CTF.) */
extern ctf_ret_t ctf_link_output_is_btf (ctf_dict_t *);
/* Return the serialized form of this ctf_linked dict as a new
dynamically-allocated string, compressed if size over THRESHOLD.
dynamically-allocated string.
May be a CTF dict or a CTF archive (this library mostly papers over the
differences so you can open both the same way, treat both as ctf_archive_t
@ -1364,8 +1359,7 @@ extern ctf_ret_t ctf_link_output_is_btf (ctf_dict_t *);
If IS_BTF is set on return, the output is BTF-compatible and can be stored
in a .BTF section. */
extern unsigned char *ctf_link_write (ctf_dict_t *, size_t *size,
size_t threshold, int *is_btf);
extern unsigned char *ctf_link_write (ctf_dict_t *, size_t *size, int *is_btf);
/* Specialist linker functions. These functions are not used by ld, but can be
used by other programs making use of the linker machinery for other purposes

View file

@ -4301,8 +4301,7 @@ lang_write_ctf (int late)
CTF in the end. Errors are handled below, if this section is actually
output. */
if (!err)
contents = ctf_link_write (ctf_output, &output_size,
(size_t) -1, &really_btf);
contents = ctf_link_write (ctf_output, &output_size, &really_btf);
/* Emit CTF or BTF, whichever was used and is needed. We decide which to
emit to based on the decision taken by section removal, above, not

View file

@ -42,7 +42,7 @@
it's just a concatenated stream of dicts followed by a magic number and
strtab: that doesn't fit into C structs in any useful fashion. */
static ctf_ret_t arc_write_one_ctf (ctf_dict_t *fp, int fd, size_t threshold);
static ctf_ret_t arc_write_one_ctf (ctf_dict_t *fp, int fd);
static ctf_ret_t ctf_arc_flip_v1_modents (ctf_archive_v1_modent_t *modent, uint64_t els,
unsigned char *ents, uint64_t base,
size_t arc_len, ctf_error_t *errp);
@ -76,8 +76,7 @@ static ctf_dict_t enosym;
Updates the first dict in the archive with the errno value. */
static ctf_error_t
ctf_arc_preserialize (ctf_dict_t **ctf_dicts, ssize_t ctf_dict_cnt,
size_t threshold)
ctf_arc_preserialize (ctf_dict_t **ctf_dicts, ssize_t ctf_dict_cnt)
{
uint64_t old_parent_strlen, all_strlens = 0;
ssize_t i;
@ -88,7 +87,7 @@ ctf_arc_preserialize (ctf_dict_t **ctf_dicts, ssize_t ctf_dict_cnt,
/* Preserialize everything, doing everything but strtab generation and things
that depend on that. */
for (i = 0; i < ctf_dict_cnt; i++)
if (ctf_preserialize (ctf_dicts[i], threshold != (size_t) -1) < 0)
if (ctf_preserialize (ctf_dicts[i]) < 0)
goto err;
for (i = 0; i < ctf_dict_cnt; i++)
@ -138,7 +137,7 @@ ctf_arc_preserialize (ctf_dict_t **ctf_dicts, ssize_t ctf_dict_cnt,
Returns 0 on success, or an errno, or an ECTF_* value. */
ctf_error_t
ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
size_t threshold, ctf_arc_write_flags_t flags)
ctf_arc_write_flags_t flags)
{
size_t i;
ssize_t j;
@ -160,12 +159,12 @@ ctf_arc_write_fd (int fd, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
lot of space and thus is more likely to fail. Between this point and
arc_write_one_ctf(), immediately below, type and string additions will
corrupt the dict. */
if ((err = ctf_arc_preserialize (ctf_dicts, ctf_dict_cnt, threshold)) != 0)
if ((err = ctf_arc_preserialize (ctf_dicts, ctf_dict_cnt)) != 0)
return err;
for (i = 0; i < ctf_dict_cnt; i++)
{
if (arc_write_one_ctf (ctf_dicts[i], fd, threshold) < 0)
if (arc_write_one_ctf (ctf_dicts[i], fd) < 0)
{
errmsg = N_("cannot write CTF file to archive");
goto err;
@ -238,7 +237,7 @@ err:
Returns 0 on success, or an errno, or an ECTF_* value. */
ctf_error_t
ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
size_t threshold, ctf_arc_write_flags_t flags)
ctf_arc_write_flags_t flags)
{
ctf_error_t err;
int fd;
@ -256,7 +255,7 @@ ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
return errno;
}
err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, threshold, flags);
err = ctf_arc_write_fd (fd, ctf_dicts, ctf_dict_cnt, flags);
if (err)
goto err_close;
@ -279,14 +278,14 @@ ctf_arc_write (const char *file, ctf_dict_t **ctf_dicts, size_t ctf_dict_cnt,
file, but if it is, it will be at an 8-byte aligned offset. Sets errno
on error. */
static ctf_ret_t
arc_write_one_ctf (ctf_dict_t *fp, int fd, size_t threshold)
arc_write_one_ctf (ctf_dict_t *fp, int fd)
{
off_t off, end_off;
if ((off = lseek (fd, 0, SEEK_CUR)) < 0)
return -1;
if (ctf_write_thresholded (fp, fd, threshold) != 0)
if (ctf_write (fp, fd) != 0)
{
errno = fp->ctf_errno;
return -1;

View file

@ -881,7 +881,7 @@ extern const ctf_strs_writable_t *ctf_str_write_strtab (ctf_dict_t *);
extern ctf_ret_t ctf_serialize_output_format (ctf_dict_t *fp, int force_ctf);
extern ctf_ret_t ctf_serialize_output_dict_is_btf (ctf_dict_t *fp);
extern ctf_ret_t ctf_preserialize (ctf_dict_t *fp, int force_ctf);
extern ctf_ret_t ctf_preserialize (ctf_dict_t *fp);
extern void ctf_depreserialize (ctf_dict_t *fp);
extern struct ctf_archive_internal *

View file

@ -1984,12 +1984,11 @@ ctf_accumulate_archives (void *key, void *value, void *arg_)
/* Write out a CTF archive (if there are per-CU CTF files) or a CTF file
(otherwise) into a new dynamically-allocated string, and return it.
Members with sizes above THRESHOLD are compressed.
The optional arg IS_BTF is set to 1 if the written output is valid BTF
(no archives, no CTF-specific types). */
unsigned char *
ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold, int *is_btf)
ctf_link_write (ctf_dict_t *fp, size_t *size, int *is_btf)
{
ctf_name_list_accum_cb_arg_t arg;
char *transformed_name = NULL;
@ -2078,8 +2077,7 @@ ctf_link_write (ctf_dict_t *fp, size_t *size, size_t threshold, int *is_btf)
goto err_no;
}
if ((err = ctf_arc_write_fd (fileno (f), arg.files, arg.i,
threshold, flags)) != 0)
if ((err = ctf_arc_write_fd (fileno (f), arg.files, arg.i, flags)) != 0)
{
errloc = NULL; /* errno is set for us. */
goto err_set;

View file

@ -21,7 +21,6 @@
#include <assert.h>
#include <string.h>
#include <unistd.h>
#include <zlib.h>
#include <elf.h>
#include "elf-bfd.h"
@ -1411,19 +1410,17 @@ ctf_serialize_output_dict_is_btf (ctf_dict_t *fp)
ID assignment. The resulting dict must not be modified in any way before
serialization. (This is not enforced, as this feature is internal-only,
employed by the archive writeout machinery, which does a serialization right
after preserialization and string dedup.)
If FORCE_CTF is enabled, always emit CTF in LIBCTF_BTM_POSSIBLE mode, and
error in LIBCTF_BTM_BTF mode. */
after preserialization and string dedup.) */
ctf_ret_t
ctf_preserialize (ctf_dict_t *fp, int force_ctf)
ctf_preserialize (ctf_dict_t *fp)
{
ctf_header_t hdr;
ctf_dtdef_t *dtd;
int sym_functions = 0;
size_t hdr_len;
int ctf_adjustment = 0;
int force_ctf = 0;
unsigned char *t;
size_t buf_size, type_size, objt_size, func_size;
@ -1675,7 +1672,7 @@ ctf_depreserialize (ctf_dict_t *fp)
on visible operation). */
static unsigned char *
ctf_serialize (ctf_dict_t *fp, size_t *bufsiz, int force_ctf)
ctf_serialize (ctf_dict_t *fp, size_t *bufsiz)
{
const ctf_strs_writable_t *strtab;
unsigned char *buf, *newbuf;
@ -1684,7 +1681,7 @@ ctf_serialize (ctf_dict_t *fp, size_t *bufsiz, int force_ctf)
/* Preserialize, if we need to. */
if (!fp->ctf_serialize.cs_buf)
if (ctf_preserialize (fp, force_ctf) < 0)
if (ctf_preserialize (fp) < 0)
return NULL; /* errno is set for us. */
/* Freshly-created parent and child during linking. Construct the final
@ -1751,28 +1748,21 @@ err:
/* File writing. */
/* Optionally compress the specified CTF data stream and return it as a new
dynamically-allocated string. Possibly write it with reversed
endianness. */
/* Serialize and return the specified CTF dictionary as a new dynamically-
allocated string. Possibly write it with reversed endianness. */
unsigned char *
ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
ctf_write_mem (ctf_dict_t *fp, size_t *size)
{
unsigned char *rawbuf;
unsigned char *buf = NULL;
unsigned char *buf;
unsigned char *bp;
ctf_header_t *rawhp, *hp;
unsigned char *src;
size_t rawbufsiz;
size_t alloc_len = 0;
ctf_header_t *hp;
size_t len = 0;
size_t hdrlen;
int uncompressed = 0;
int flip_endian;
int rc;
flip_endian = getenv ("LIBCTF_WRITE_FOREIGN_ENDIAN") != NULL;
if ((rawbuf = ctf_serialize (fp, &rawbufsiz,
threshold != (size_t) -1)) == NULL)
if ((buf = ctf_serialize (fp, &len)) == NULL)
return NULL; /* errno is set for us. */
if (fp->ctf_serialize.cs_is_btf)
@ -1780,87 +1770,33 @@ ctf_write_mem (ctf_dict_t *fp, size_t *size, size_t threshold)
else
hdrlen = sizeof (ctf_header_t);
if (!ctf_assert (fp, rawbufsiz >= hdrlen))
if (!ctf_assert (fp, len >= hdrlen))
goto err;
if (rawbufsiz >= threshold && !fp->ctf_serialize.cs_is_btf)
alloc_len = compressBound (rawbufsiz - sizeof (ctf_header_t))
+ sizeof (ctf_header_t);
*size = len;
/* Trivial operation if the buffer is too small to bother compressing, and
we're not doing a forced write-time flip. */
/* Trivial operation if we're not doing a forced write-time flip. */
if (rawbufsiz < threshold || fp->ctf_serialize.cs_is_btf)
{
alloc_len = rawbufsiz;
uncompressed = 1;
}
if (!flip_endian)
return buf;
if (!flip_endian && uncompressed)
{
*size = rawbufsiz;
return rawbuf;
}
if ((buf = malloc (alloc_len)) == NULL)
{
ctf_err (err_locus (fp), ENOMEM, _("cannot allocate %li bytes"),
(unsigned long) (alloc_len));
goto err;
}
rawhp = (ctf_header_t *) rawbuf;
hp = (ctf_header_t *) buf;
bp = buf + sizeof (ctf_btf_header_t);
memcpy (hp, rawbuf, hdrlen);
bp = buf + hdrlen;
*size = hdrlen;
if (ctf_flip_header (hp, 1, fp->ctf_serialize.cs_is_btf, 0) < 0)
goto err; /* errno is set for us. */
if (ctf_flip (fp, hp, bp, fp->ctf_serialize.cs_is_btf, 1) < 0)
goto err; /* errno is set for us. */
if (!uncompressed && !fp->ctf_serialize.cs_is_btf)
hp->cth_flags |= CTF_F_COMPRESS;
src = rawbuf + hdrlen;
if (flip_endian)
{
if (ctf_flip_header (hp, 1, fp->ctf_serialize.cs_is_btf, 0) < 0)
goto err; /* errno is set for us. */
if (ctf_flip (fp, rawhp, src, fp->ctf_serialize.cs_is_btf, 1) < 0)
goto err; /* errno is set for us. */
}
/* Must be CTFv4. */
if (!uncompressed)
{
size_t compress_len = alloc_len - sizeof (ctf_header_t);
if ((rc = compress (bp, (uLongf *) &compress_len,
src, rawbufsiz - hdrlen)) != Z_OK)
{
ctf_err (err_locus (fp), ECTF_COMPRESS,
_("zlib deflate err: %s"), zError (rc));
goto err;
}
*size += compress_len;
}
else
{
memcpy (bp, src, rawbufsiz - hdrlen);
*size += rawbufsiz - hdrlen;
}
free (rawbuf);
return buf;
err:
free (buf);
free (rawbuf);
return NULL;
}
/* Write the compressed CTF data stream to the specified file descriptor,
possibly compressed. Internal only (for now). */
/* Write the given CTF data stream to the specified file descriptor. */
ctf_ret_t
ctf_write_thresholded (ctf_dict_t *fp, int fd, size_t threshold)
ctf_write (ctf_dict_t *fp, int fd)
{
unsigned char *buf;
unsigned char *bp;
@ -1869,7 +1805,7 @@ ctf_write_thresholded (ctf_dict_t *fp, int fd, size_t threshold)
ssize_t len;
ctf_ret_t ret = -1;
if ((buf = ctf_write_mem (fp, &tmp, threshold)) == NULL)
if ((buf = ctf_write_mem (fp, &tmp)) == NULL)
return -1; /* errno is set for us. */
buf_len = tmp;
@ -1891,18 +1827,3 @@ ret:
free (buf);
return ret;
}
/* Compress the specified CTF data stream and write it to the specified file
descriptor. */
int
ctf_compress_write (ctf_dict_t *fp, int fd)
{
return ctf_write_thresholded (fp, fd, 0);
}
/* Write the uncompressed CTF data stream to the specified file descriptor. */
int
ctf_write (ctf_dict_t *fp, int fd)
{
return ctf_write_thresholded (fp, fd, (size_t) -1);
}

View file

@ -132,7 +132,6 @@ LIBCTF_2.0 {
ctf_rollback;
ctf_write;
ctf_write_mem;
ctf_compress_write;
ctf_write_suppress_kind;
ctf_sect_size;
ctf_get_elf_sect;

View file

@ -1,19 +0,0 @@
int an_int;
char *a_char_ptr;
typedef int (*a_typedef) (int main);
struct struct_forward;
enum enum_forward;
union union_forward;
typedef int an_array[50];
struct a_struct { int foo; };
union a_union { int bar; };
enum an_enum { FOO };
a_typedef a;
struct struct_forward *x;
union union_forward *y;
enum enum_forward *z;
struct a_struct *xx;
union a_union *yy;
enum an_enum *zz;
an_array ar;

View file

@ -1,153 +0,0 @@
/* Make sure that you can modify then ctf_compress_write() a dict
and it changes after modification. */
#include <ctf-api.h>
#include <errno.h>
#include <fcntl.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
char *read_file(const char *path, size_t *len)
{
char *in = NULL;
char buf[4096];
int foo;
size_t ret;
if ((foo = open (path, O_RDONLY)) < 0)
{
fprintf (stderr, "error opening %s: %s\n", path, strerror(errno));
exit (1);
}
*len = 0;
while ((ret = read (foo, buf, 4096)) > 0)
{
if ((in = realloc (in, *len + ret)) == NULL)
{
fprintf (stderr, "Out of memory\n");
exit (1);
}
memcpy (&in[*len], buf, ret);
*len += ret;
}
if (ret < 0)
{
fprintf (stderr, "error reading %s: %s\n", path, strerror(errno));
exit (1);
}
close (foo);
return in;
}
int
main (int argc, char *argv[])
{
ctf_dict_t *fp, *fp_b;
ctf_archive_t *ctf, *ctf_b;
int foo;
char *a, *b;
size_t a_len, b_len;
ctf_id_t type, ptrtype;
int err;
if (argc != 2)
{
fprintf (stderr, "Syntax: %s PROGRAM\n", argv[0]);
exit(1);
}
if ((ctf = ctf_open (argv[1], NULL, &err)) == NULL)
goto open_err;
if ((fp = ctf_dict_open (ctf, NULL, &err)) == NULL)
goto open_err;
if ((foo = open ("tmpdir/one", O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0)
goto write_stderr;
if (ctf_compress_write (fp, foo) < 0)
goto write_err;
close (foo);
if ((foo = open ("tmpdir/two", O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0)
goto write_stderr;
if (ctf_compress_write (fp, foo) < 0)
goto write_err;
close (foo);
a = read_file ("tmpdir/one", &a_len);
b = read_file ("tmpdir/two", &b_len);
if (a_len != b_len || memcmp (a, b, a_len) != 0)
{
fprintf (stderr, "consecutive compress_writes are different: lengths %zu and %zu\n", a_len, b_len);
return 1;
}
free (b);
/* Add some new types to the dict and write it out, then read it back in and
make sure they're still there, and that at least some of the
originally-present data objects are still there too. */
if ((type = ctf_lookup_by_name (fp, "struct a_struct")) == CTF_ERR)
fprintf (stderr, "Lookup of struct a_struct failed: %s\n", ctf_errmsg (ctf_errno (fp)));
if ((ptrtype = ctf_add_pointer (fp, type)) == CTF_ERR)
fprintf (stderr, "Cannot add pointer to ctf_opened dict: %s\n", ctf_errmsg (ctf_errno (fp)));
unlink ("tmpdir/two");
if ((foo = open ("tmpdir/two", O_CREAT | O_TRUNC | O_WRONLY, 0666)) < 0)
goto write_stderr;
if (ctf_compress_write (fp, foo) < 0)
goto write_err;
close (foo);
b = read_file ("tmpdir/two", &b_len);
if (a_len == b_len && memcmp (a, b, b_len) == 0)
{
fprintf (stderr, "compress_writes after adding types does not change the dict\n");
return 1;
}
free (a);
free (b);
if ((ctf_b = ctf_open ("tmpdir/two", NULL, &err)) == NULL)
goto open_err;
if ((fp_b = ctf_dict_open (ctf_b, NULL, &err)) == NULL)
goto open_err;
if (ctf_type_reference (fp_b, ptrtype) == CTF_ERR)
fprintf (stderr, "Lookup of pointer preserved across writeout failed: %s\n", ctf_errmsg (ctf_errno (fp_b)));
if (ctf_type_reference (fp_b, ptrtype) != type)
fprintf (stderr, "Look up of newly-added type in serialized dict yields ID %lx, expected %lx\n", ctf_type_reference (fp_b, ptrtype), type);
if (ctf_arc_lookup_symbol_name (ctf_dict_arc (fp_b, 0), "an_int", NULL, &err) == NULL)
fprintf (stderr, "Lookup of symbol an_int failed: %s\n", ctf_errmsg (err));
ctf_dict_close (fp);
ctf_close (ctf);
ctf_dict_close (fp_b);
ctf_close (ctf_b);
printf ("All done.\n");
return 0;
open_err:
fprintf (stderr, "%s: cannot open: %s\n", argv[0], ctf_errmsg (err));
return 1;
write_err:
fprintf (stderr, "%s: cannot write: %s\n", argv[0], ctf_errmsg (ctf_errno (fp)));
return 1;
write_stderr:
fprintf (stderr, "%s: cannot open for writing: %s\n", argv[0], strerror (errno));
return 1;
}

View file

@ -1,3 +0,0 @@
# source: zrewrite-ctf.c
# lookup: zrewrite.c
All done.

View file

@ -1,156 +0,0 @@
/* Make sure linking and writing an archive with a low threshold correctly
compresses it. (This tests for two bugs, one where archives weren't
serialized regardless of their threshold, and another where nothing was.) */
#include <ctf-api.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int
main (int argc, char *argv[])
{
ctf_dict_t *in1;
ctf_dict_t *in2;
ctf_dict_t *fp;
ctf_dict_t *dump_fp;
ctf_archive_t *arc1, *arc2;
ctf_archive_t *final_arc;
ctf_sect_t s1, s2;
ctf_encoding_t encoding = { CTF_INT_SIGNED, 0, sizeof (char) };
ctf_encoding_t encoding2 = { CTF_INT_SIGNED, 0, sizeof (long long) };
unsigned char *buf1, *buf2, *buf3;
size_t buf1_sz, buf2_sz, buf3_sz;
ctf_dump_state_t *dump_state = NULL;
ctf_next_t *i = NULL;
int err;
/* Linking does not currently work on mingw because of an unreliable tmpfile
implementation on that platform (see
https://github.com/msys2/MINGW-packages/issues/18878). Simply skip for
now. */
if ((fp = ctf_create (NULL, &err)) == NULL)
goto create_err;
if ((in1 = ctf_create (NULL, &err)) == NULL)
goto create_err;
if ((in2 = ctf_create (NULL, &err)) == NULL)
goto create_err;
/* Force a conflict to get an archive created. */
if ((ctf_add_integer (in1, "foo", &encoding)) == CTF_ERR)
{
fprintf (stderr, "Cannot add: %s\n", ctf_errmsg (ctf_errno (in1)));
return 1;
}
if ((ctf_add_integer (in2, "foo", &encoding2)) == CTF_ERR)
{
fprintf (stderr, "Cannot add: %s\n", ctf_errmsg (ctf_errno (in2)));
return 1;
}
/* Write them out and read them back in, to turn them into archives.
This would be unnecessary if ctf_link_add_internal() were public :( */
if ((buf1 = ctf_write_mem (in1, &buf1_sz, -1)) == NULL)
{
fprintf (stderr, "Cannot serialize: %s\n", ctf_errmsg (ctf_errno (in1)));
return 1;
}
if ((buf2 = ctf_write_mem (in2, &buf2_sz, -1)) == NULL)
{
fprintf (stderr, "Cannot serialize: %s\n", ctf_errmsg (ctf_errno (in2)));
return 1;
}
s1.cts_name = "foo";
s2.cts_name = "bar";
s1.cts_data = (void *) buf1;
s2.cts_data = (void *) buf2;
s1.cts_size = buf1_sz;
s2.cts_size = buf2_sz;
s1.cts_entsize = 64; /* Unimportant. */
s2.cts_entsize = 64; /* Unimportant. */
if ((arc1 = ctf_arc_bufopen (&s1, NULL, NULL, &err)) == NULL ||
(arc2 = ctf_arc_bufopen (&s2, NULL, NULL, &err)) == NULL)
goto open_err;
ctf_dict_close (in1);
ctf_dict_close (in2);
/* Link them together. */
if (ctf_link_add (fp, arc1, "a", NULL) < 0 ||
ctf_link_add (fp, arc2, "b", NULL) < 0)
goto link_err;
if (ctf_link (fp, 0) < 0)
goto link_err;
/* Write them out. We need a new buf here, because the archives are still
using the other two bufs. */
if ((buf3 = ctf_link_write (fp, &buf3_sz, 1)) == NULL)
goto link_err;
/* Read them back in. */
s1.cts_data = (void *) buf3;
s1.cts_size = buf3_sz;
if ((final_arc = ctf_arc_bufopen (&s1, NULL, NULL, &err)) == NULL)
goto open_err;
if (ctf_archive_count (final_arc) != 2)
{
fprintf (stderr, "Archive is the wrong length: %zi.\n", ctf_archive_count (final_arc));
return -1;
}
/* Dump the header of each archive member, and search for CTF_F_COMPRESS in
the resulting dump. */
err = 666;
while ((dump_fp = ctf_archive_next (final_arc, &i, NULL, 0, &err)) != NULL)
{
char *dumpstr;
if (err != 0)
fprintf (stderr, "err not set to success on success\n");
while ((dumpstr = ctf_dump (dump_fp, &dump_state, CTF_SECT_HEADER,
NULL, NULL)) != NULL)
{
if (strstr (dumpstr, "CTF_F_COMPRESS") != NULL)
printf ("Output is compressed.\n");
free (dumpstr);
}
ctf_dict_close (dump_fp);
}
if (err != ECTF_NEXT_END)
{
fprintf (stderr, "Archive iteation error: %s\n", ctf_errmsg (err));
return 1;
}
ctf_arc_close (final_arc);
free (buf1);
free (buf2);
free (buf3);
ctf_dict_close (fp);
return 0;
create_err:
fprintf (stderr, "Cannot create: %s\n", ctf_errmsg (err));
return 1;
open_err:
fprintf (stderr, "Cannot open: %s\n", ctf_errmsg (err));
return 1;
link_err:
fprintf (stderr, "Cannot link: %s\n", ctf_errmsg (ctf_errno (fp)));
return 1;
}

View file

@ -1,2 +0,0 @@
Output is compressed.
Output is compressed.

View file

@ -74,7 +74,7 @@ main (int argc, char *argv[])
/* Write it out. We need a new buf here, because the archive is still
using the other buf. */
if ((buf2 = ctf_link_write (fp, &buf2_sz, 4096)) == NULL)
if ((buf2 = ctf_link_write (fp, &buf2_sz)) == NULL)
goto link_err;
/* Read it back in. */