From: Jonathan Dieter Date: Fri, 8 Jun 2018 07:08:17 +0000 (+0300) Subject: Add ABI compliance test. To run it, run 'ninja test-abi' X-Git-Tag: archive/raspbian/1.1.9+ds1-1+rpi1~1^2~233 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=4012539dd7013ec96bb1e9b07ca88b2a4eda1ad6;p=zchunk.git Add ABI compliance test. To run it, run 'ninja test-abi' Signed-off-by: Jonathan Dieter --- diff --git a/.gitignore b/.gitignore index 378eac2..7e6710b 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,3 @@ build +test/abi/new +test/abi/stable/ABI.dump diff --git a/test/abi.sh b/test/abi.sh new file mode 100755 index 0000000..0a94f39 --- /dev/null +++ b/test/abi.sh @@ -0,0 +1,34 @@ +#!/bin/sh +cd "$(dirname "$0")" + +if [ ! -e ../build/src/lib/libzck.so.*.*.* ]; then + echo "No library exists" + exit 1 +fi + +# Copy latest build to abi/new and remove softlinks +rm abi/new -rf +mkdir -p abi/new +cp -a ../build/src/lib/libzck.so.* abi/new +cp -a ../include/zck.h abi/new +find abi -type l -delete + +# Redump abi/stable +cd abi/stable +abi-dumper libzck.so.* -lver `cat zck.h | grep ZCK_VERSION | head -n 1 | awk '{ print $3 }' | sed s/\"//g` +if [ "$?" -ne 0 ]; then + exit 1 +fi + +# Dump abi/new +cd ../new +abi-dumper libzck.so.* -lver `cat zck.h | grep ZCK_VERSION | head -n 1 | awk '{ print $3 }' | sed s/\"//g` +if [ "$?" -ne 0 ]; then + exit 1 +fi +cd ../../ + +# Remove any old reports and generate new abi compliance report +rm compat_reports -rf +abi-compliance-checker -l zchunk -old abi/stable/ABI.dump -new abi/new/ABI.dump +exit $? diff --git a/test/abi/stable/libzck.so.0.0.1 b/test/abi/stable/libzck.so.0.0.1 new file mode 100755 index 0000000..8d1722a Binary files /dev/null and b/test/abi/stable/libzck.so.0.0.1 differ diff --git a/test/abi/stable/zck.h b/test/abi/stable/zck.h new file mode 100644 index 0000000..2892b62 --- /dev/null +++ b/test/abi/stable/zck.h @@ -0,0 +1,332 @@ +#ifndef ZCK_H +#define ZCK_H + +#define ZCK_VERSION "0.6.2" +#define ZCK_VER_MAJOR 0 +#define ZCK_VER_MINOR 6 +#define ZCK_VER_REVISION 2 +#define ZCK_VER_SUBREVISION 0 + +#define True 1 +#define False 0 + +typedef enum zck_hash { + ZCK_HASH_SHA1, + ZCK_HASH_SHA256, + ZCK_HASH_UNKNOWN +} zck_hash; + +typedef enum zck_comp { + ZCK_COMP_NONE, + ZCK_COMP_GZIP, /* Not implemented yet */ + ZCK_COMP_ZSTD +} zck_comp; + +typedef enum zck_ioption { + ZCK_HASH_FULL_TYPE = 0, /* Set full file hash type, using zck_hash */ + ZCK_HASH_CHUNK_TYPE, /* Set chunk hash type using zck_hash */ + ZCK_VAL_HEADER_HASH_TYPE, /* Set what the header hash type *should* be */ + ZCK_VAL_HEADER_LENGTH, /* Set what the header length *should* be */ + ZCK_COMP_TYPE = 100, /* Set compression type using zck_comp */ + ZCK_ZSTD_COMP_LEVEL = 1000 /* Set zstd compression level */ +} zck_ioption; + +typedef enum zck_soption { + ZCK_VAL_HEADER_DIGEST = 0, /* Set what the header hash *should* be */ + ZCK_COMP_DICT = 100 /* Set compression dictionary */ +} zck_soption; + +typedef enum zck_log_type { + ZCK_LOG_DEBUG, + ZCK_LOG_INFO, + ZCK_LOG_WARNING, + ZCK_LOG_ERROR, + ZCK_LOG_NONE +} zck_log_type; + +typedef struct zckCtx zckCtx; +typedef struct zckHash zckHash; + +/* Contains an index item pointing to a chunk */ +typedef struct zckIndexItem { + char *digest; + int digest_size; + int valid; + size_t start; + size_t comp_length; + size_t length; + struct zckIndexItem *next; +} zckIndexItem; + +/* Contains everything about an index and a pointer to the first index item */ +typedef struct zckIndex { + size_t count; + size_t length; + int hash_type; + size_t digest_size; + zckIndexItem *first; +} zckIndex; + +/* Contains a single range */ +typedef struct zckRangeItem { + size_t start; + size_t end; + struct zckRangeItem *next; + struct zckRangeItem *prev; +} zckRangeItem; + +/* Contains a series of ranges, information about them, a link to the first + * range item, and an index describing what information is in the ranges */ +typedef struct zckRange { + unsigned int count; + zckRangeItem *first; + zckIndex index; +} zckRange; + +/******************************************************************* + * Reading a zchunk file + *******************************************************************/ +/* Initialize zchunk for reading */ +zckCtx *zck_init_read (int src_fd) + __attribute__ ((warn_unused_result)); +/* Decompress dst_size bytes from zchunk file to dst, while verifying hashes */ +ssize_t zck_read(zckCtx *zck, char *dst, size_t dst_size) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Writing a zchunk file + *******************************************************************/ +/* Initialize zchunk for writing */ +zckCtx *zck_init_write (int dst_fd) + __attribute__ ((warn_unused_result)); +/* Compress data src of size src_size, and write to zchunk file + * Due to the nature of zchunk files and how they are built, no data will + * actually appear in the zchunk file until zck_close() is called */ +ssize_t zck_write(zckCtx *zck, const char *src, const size_t src_size) + __attribute__ ((warn_unused_result)); +/* Create a chunk boundary */ +ssize_t zck_end_chunk(zckCtx *zck) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Common functions for finishing a zchunk file + *******************************************************************/ +/* Close a zchunk file so it may no longer be read from or written to. The + * context still contains information about the file */ +int zck_close(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Free a zchunk context. You must pass the address of the context, and the + * context will automatically be set to NULL after it is freed */ +void zck_free(zckCtx **zck); + + +/******************************************************************* + * Options + *******************************************************************/ +/* Set string option */ +int zck_set_soption(zckCtx *zck, zck_soption option, const char *value, + size_t length) + __attribute__ ((warn_unused_result)); +/* Set integer option */ +int zck_set_ioption(zckCtx *zck, zck_ioption option, ssize_t value) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Miscellaneous utilities + *******************************************************************/ +/* Set logging level */ +void zck_set_log_level(zck_log_type ll); +/* Validate the chunk and data checksums for the current file. + * Returns -1 for error, 0 for invalid checksum and 1 for valid checksum */ +int zck_validate_checksums(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Validate just the data checksum for the current file */ +int zck_validate_data_checksum(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Go through file and mark valid chunks as valid */ +int zck_find_valid_chunks(zckCtx *zck) + __attribute__ ((warn_unused_result)); + +/* Get a zckRange of ranges that need to still be downloaded. + * max_ranges is the maximum number of ranges supported in a single request + * by the server. If the server supports unlimited ranges, set to -1 + * Returns NULL if there's an error */ +zckRange *zck_get_dl_range(zckCtx *zck, int max_ranges) + __attribute__ ((warn_unused_result)); +/* Get a string representation of a zckRange */ +char *zck_get_range_char(zckRange *range) + __attribute__ ((warn_unused_result)); +/* Get file descriptor attached to zchunk context */ +int zck_get_fd(zckCtx *zck) + __attribute__ ((warn_unused_result)); + +/* Return number of missing chunks (-1 if error) */ +int zck_missing_chunks(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Return number of failed chunks (-1 if error) */ +int zck_failed_chunks(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Reset failed chunks to become missing */ +void zck_reset_failed_chunks(zckCtx *zck); + +/******************************************************************* + * The functions should be all you need to read and write a zchunk + * file. After this point are advanced functions with an unstable + * API, so use them with care. + *******************************************************************/ + + +/******************************************************************* + * Advanced miscellaneous zchunk functions + *******************************************************************/ +/* Initialize zchunk context */ +zckCtx *zck_create() + __attribute__ ((warn_unused_result)); +/* Get lead length */ +ssize_t zck_get_lead_length(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get header length (lead + preface + index + sigs) */ +ssize_t zck_get_header_length(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get data length */ +ssize_t zck_get_data_length(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get file length */ +ssize_t zck_get_length(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get index digest */ +char *zck_get_header_digest(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get data digest */ +char *zck_get_data_digest(zckCtx *zck) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Advanced compression functions + *******************************************************************/ +/* Get name of compression type */ +const char *zck_comp_name_from_type(int comp_type) + __attribute__ ((warn_unused_result)); +/* Initialize compression. Compression type and parameters *must* be done + * before this is called */ + + +/******************************************************************* + * Advanced zchunk reading functions + *******************************************************************/ +/* Initialize zchunk for reading using advanced options */ +zckCtx *zck_init_adv_read (int src_fd) + __attribute__ ((warn_unused_result)); +/* Read zchunk lead */ +int zck_read_lead(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Read zchunk header */ +int zck_read_header(zckCtx *zck) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Indexes + *******************************************************************/ +/* Get index count */ +ssize_t zck_get_index_count(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get index */ +zckIndex *zck_get_index(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get chunk digest */ +char *zck_get_chunk_digest(zckIndexItem *item) + __attribute__ ((warn_unused_result)); + + +/******************************************************************* + * Advanced hash functions + *******************************************************************/ +/* Get overall hash type */ +int zck_get_full_hash_type(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get digest size of overall hash type */ +ssize_t zck_get_full_digest_size(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get chunk hash type */ +int zck_get_chunk_hash_type(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get digest size of chunk hash type */ +ssize_t zck_get_chunk_digest_size(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Get name of hash type */ +const char *zck_hash_name_from_type(int hash_type) + __attribute__ ((warn_unused_result)); + + + +/******************************************************************* + * Downloading (should this go in a separate header and library?) + *******************************************************************/ + +typedef size_t (*zck_wcb)(void *ptr, size_t l, size_t c, void *dl_v); +typedef struct zckDLPriv zckDLPriv; + +/* Contains a zchunk download context */ +typedef struct zckDL { + size_t dl; + size_t ul; + zck_wcb write_cb; + void *wdata; + zck_wcb header_cb; + void *hdrdata; + zckRange *range; + zckDLPriv *priv; + struct zckCtx *zck; +} zckDL; + +/******************************************************************* + * Ranges + *******************************************************************/ +/* Get any matching chunks from src and put them in the right place in tgt */ +int zck_copy_chunks(zckCtx *src, zckCtx *tgt) + __attribute__ ((warn_unused_result)); +/* Free zckRange */ +void zck_range_free(zckRange **info); +/* Get range string from start and end location */ +char *zck_get_range(size_t start, size_t end) + __attribute__ ((warn_unused_result)); +/* Get the minimum size needed to download in order to know how large the header + * is */ +int zck_get_min_download_size() + __attribute__ ((warn_unused_result)); + +/******************************************************************* + * Downloading + *******************************************************************/ +/* Initialize zchunk download context */ +zckDL *zck_dl_init(zckCtx *zck) + __attribute__ ((warn_unused_result)); +/* Reset zchunk download context for reuse */ +void zck_dl_reset(zckDL *dl); +/* Free zchunk download context */ +void zck_dl_free(zckDL **dl); +/* Write callback. You *must* pass this and your initialized zchunk download + * context to the downloader when downloading a zchunk file. If you have your + * own callback, set dl->write_cb to your callback and dl->wdata to your + * callback data. */ +size_t zck_write_chunk_cb(void *ptr, size_t l, size_t c, void *dl_v); +size_t zck_write_zck_header_cb(void *ptr, size_t l, size_t c, void *dl_v); +size_t zck_header_cb(char *b, size_t l, size_t c, void *dl_v); +/* Clear regex used for extracting download ranges from multipart download */ +void zck_dl_clear_regex(zckDL *dl); +/* Download and process the header from url */ +int zck_dl_get_header(zckCtx *zck, zckDL *dl, char *url) + __attribute__ ((warn_unused_result)); +/* Get number of bytes downloaded using download context */ +size_t zck_dl_get_bytes_downloaded(zckDL *dl) + __attribute__ ((warn_unused_result)); +/* Get number of bytes uploaded using download context */ +size_t zck_dl_get_bytes_uploaded(zckDL *dl) + __attribute__ ((warn_unused_result)); + +#endif diff --git a/test/meson.build b/test/meson.build index c49ad0f..58c8107 100644 --- a/test/meson.build +++ b/test/meson.build @@ -5,3 +5,9 @@ empty = executable('empty', ['empty.c'] + util_sources, include_directories: inc file_path = join_paths(meson.source_root(), 'test/files') test('create and validate empty zchunk file', empty) + +run_target('test-abi', + command: 'abi.sh') + +run_target('new-abi', + command: 'new_abi.sh') diff --git a/test/new_abi.sh b/test/new_abi.sh new file mode 100755 index 0000000..1d848e5 --- /dev/null +++ b/test/new_abi.sh @@ -0,0 +1,14 @@ +#!/bin/sh +cd "$(dirname "$0")" + +if [ ! -e ../build/src/lib/libzck.so.*.*.* ]; then + echo "No library exists" + exit 1 +fi + +# Remove stable build and copy current build abi/stable +rm abi/stable -rf +mkdir -p abi/stable +cp -a ../build/src/lib/libzck.so.* abi/stable +cp -a ../include/zck.h abi/stable +find abi -type l -delete