zupt/sdk/include/zuptsdk.h
Cristian Cezar Moisés e5f5d32aab v2.2.2
2026-05-01 09:58:47 -03:00

605 lines
30 KiB
C

/*
* libzuptsdk — Public C ABI for the Zupt backup compression library
*
* Copyright (c) 2026 Cristian Cezar Moisés
* SPDX-License-Identifier: AGPL-3.0-or-later
*
* Repository: https://git.securityops.co/cristiancmoises/zupt
* Website: https://zupt.securityops.co
* Contact: zupt@riseup.net
*
* --------------------------------------------------------------------------
* STABILITY GUARANTEE
* --------------------------------------------------------------------------
* Every symbol declared in this header is part of the stable v1.0 ABI and
* is gated behind the linker version tag ZUPTSDK_1.0. New symbols may be
* added in minor versions (1.1, 1.2, ...) under new tags (ZUPTSDK_1.1, ...).
* Existing symbols will never change signature within v1.x. Breaking
* changes require a major version bump (libzuptsdk.so.2).
*
* No symbol prefixed with anything other than `zuptsdk_` or `ZUPTSDK_` is
* part of this ABI. Do not link against internal `zupt_*` symbols even if
* they appear in the static archive — they will disappear without notice.
*
* --------------------------------------------------------------------------
* THREAD SAFETY
* --------------------------------------------------------------------------
* Every function that takes a `zuptsdk_ctx_t *` operates only on that
* context's state and on caller-provided buffers. Concurrent calls on
* DISTINCT contexts are safe (MT-Safe). Concurrent calls on the SAME
* context are NOT safe (MT-Unsafe-Same-Context) unless explicitly
* documented otherwise.
*
* --------------------------------------------------------------------------
* MEMORY OWNERSHIP
* --------------------------------------------------------------------------
* Every function documents ownership using these conventions in the param
* comments:
* [in] caller owns, library reads only
* [out] caller owns, library writes
* [in,out] caller owns, library reads and writes
* [transfers] ownership moves caller -> library (or library -> caller)
* [borrowed] pointer valid only for the duration of the call
*
* Any function that returns a heap-allocated value via an output pointer
* documents the corresponding zuptsdk_*_destroy() or zuptsdk_free() call
* the caller must invoke. Calling free() on libc-allocated memory from a
* different allocator is undefined; always use the documented destroyer.
*
* --------------------------------------------------------------------------
* ERROR HANDLING
* --------------------------------------------------------------------------
* Functions return `int` where 0 == ZUPTSDK_OK and negative values are
* `zuptsdk_error_t` codes. Use zuptsdk_strerror() for a static description
* and zuptsdk_last_error_detail(ctx) for a thread-local detailed message
* including filename, line number, and underlying errno where applicable.
*
* The library never calls abort(), exit(), or _exit(). It never writes to
* stdout or stderr unless the caller explicitly enables logging via
* zuptsdk_ctx_set_log_callback().
*
* --------------------------------------------------------------------------
* SECURE MEMORY
* --------------------------------------------------------------------------
* Inputs and outputs containing secret material (passwords, raw keys,
* decrypted plaintext keys) MUST be passed via `zuptsdk_secure_buffer_t`
* to ensure mlock()-backed storage and explicit_bzero() on destroy.
* Passing such material via plain `const uint8_t *` is allowed for
* convenience but the library cannot guarantee zeroization of caller
* memory in that case.
*/
#ifndef ZUPTSDK_H
#define ZUPTSDK_H
#include <stddef.h>
#include <stdint.h>
#ifdef __cplusplus
extern "C" {
#endif
/* ════════════════════════════════════════════════════════════════════════
* VERSION
* ════════════════════════════════════════════════════════════════════════ */
#define ZUPTSDK_VERSION_MAJOR 1
#define ZUPTSDK_VERSION_MINOR 0
#define ZUPTSDK_VERSION_PATCH 0
#define ZUPTSDK_VERSION_STRING "1.0.0"
/* Compile-time version check helper (negative if header older than required) */
#define ZUPTSDK_VERSION_AT_LEAST(maj, min, pat) \
((ZUPTSDK_VERSION_MAJOR > (maj)) || \
(ZUPTSDK_VERSION_MAJOR == (maj) && ZUPTSDK_VERSION_MINOR > (min)) || \
(ZUPTSDK_VERSION_MAJOR == (maj) && ZUPTSDK_VERSION_MINOR == (min) && \
ZUPTSDK_VERSION_PATCH >= (pat)))
/**
* Return the runtime version string of the linked library, e.g. "1.0.0".
* The returned pointer is to static storage and must NOT be freed.
*
* Use this with the compile-time ZUPTSDK_VERSION_STRING to detect mismatch
* between header and library at runtime.
*/
const char *zuptsdk_version_string(void);
/**
* Verify that the linked library is at least the requested version.
* Returns 0 if compatible, ZUPTSDK_ERR_VERSION_MISMATCH otherwise.
* Call this once at startup before any other zuptsdk_* function.
*/
int zuptsdk_version_check(int major, int minor, int patch);
/* ════════════════════════════════════════════════════════════════════════
* ERRORS
* ════════════════════════════════════════════════════════════════════════ */
typedef enum {
ZUPTSDK_OK = 0,
ZUPTSDK_ERR_INVALID_ARG = -1, /* NULL pointer, bad size, bad enum value */
ZUPTSDK_ERR_NO_MEMORY = -2, /* malloc/calloc/realloc returned NULL */
ZUPTSDK_ERR_IO = -3, /* read/write error; see errno detail */
ZUPTSDK_ERR_BAD_ARCHIVE = -4, /* Magic mismatch or truncated header */
ZUPTSDK_ERR_BAD_PASSWORD = -5, /* MAC verification failed */
ZUPTSDK_ERR_BAD_KEY = -6, /* PQ key file malformed or wrong type */
ZUPTSDK_ERR_BAD_MAC = -7, /* HMAC mismatch — archive corrupted or tampered */
ZUPTSDK_ERR_BAD_VERSION = -8, /* Archive format version not supported */
ZUPTSDK_ERR_BAD_CHECKSUM = -9, /* Block checksum mismatch */
ZUPTSDK_ERR_BUFFER_TOO_SMALL = -10, /* Output buffer insufficient */
ZUPTSDK_ERR_NOT_ENCRYPTED = -11, /* Tried to decrypt unencrypted archive */
ZUPTSDK_ERR_PASSWORD_REQUIRED = -12, /* Archive needs password but none supplied */
ZUPTSDK_ERR_PQ_KEY_REQUIRED = -13, /* Archive needs PQ key but none supplied */
ZUPTSDK_ERR_UNSUPPORTED = -14, /* Feature not supported on this platform */
ZUPTSDK_ERR_VERSION_MISMATCH = -15, /* Library older than requested */
ZUPTSDK_ERR_PATH_TRAVERSAL = -16, /* "../" or absolute path in archive */
ZUPTSDK_ERR_TOO_LARGE = -17, /* Decompressed size exceeds limit */
ZUPTSDK_ERR_CRYPTO_FAIL = -18, /* Underlying crypto primitive failed */
ZUPTSDK_ERR_CANCELLED = -19, /* Caller cancelled via progress callback */
ZUPTSDK_ERR_INTERNAL = -99 /* Bug in library — please report */
} zuptsdk_error_t;
/**
* Static error description for a zuptsdk_error_t value.
* Returned pointer is static and must not be freed. Always non-NULL.
*/
const char *zuptsdk_strerror(int err);
/**
* Thread-local detailed error message from the most recent failed call.
* The string includes file:line of the failure point and underlying errno
* description where applicable. Returned pointer is to thread-local
* storage, valid until the next failed zuptsdk_* call on this thread.
* Returns "" if no error has been recorded on this thread.
*/
const char *zuptsdk_last_error_detail(void);
/* ════════════════════════════════════════════════════════════════════════
* OPAQUE TYPES (forward declarations only — no struct layout exposed)
* ════════════════════════════════════════════════════════════════════════ */
typedef struct zuptsdk_ctx zuptsdk_ctx_t;
typedef struct zuptsdk_options zuptsdk_options_t;
typedef struct zuptsdk_archive_info zuptsdk_archive_info_t;
typedef struct zuptsdk_secure_buf zuptsdk_secure_buf_t;
typedef struct zuptsdk_keypair zuptsdk_keypair_t;
typedef struct zuptsdk_pubkey zuptsdk_pubkey_t;
typedef struct zuptsdk_privkey zuptsdk_privkey_t;
/* ════════════════════════════════════════════════════════════════════════
* ENUMS
* ════════════════════════════════════════════════════════════════════════ */
typedef enum {
ZUPTSDK_CODEC_AUTO = 0, /* Hardware-adaptive (VaptVupt on AVX2, LZHP otherwise) */
ZUPTSDK_CODEC_VAPTVUPT = 1, /* VaptVupt LZ + ANS entropy */
ZUPTSDK_CODEC_LZHP = 2, /* LZ77 + Huffman + Byte Prediction */
ZUPTSDK_CODEC_LZH = 3, /* LZ77 + Huffman */
ZUPTSDK_CODEC_LZ = 4, /* LZ77 only */
ZUPTSDK_CODEC_STORE = 5 /* No compression */
} zuptsdk_codec_t;
typedef enum {
ZUPTSDK_ENC_NONE = 0, /* No encryption */
ZUPTSDK_ENC_PASSWORD = 1, /* PBKDF2 → AES-256-CTR + HMAC-SHA256 */
ZUPTSDK_ENC_PQ_HYBRID = 2 /* ML-KEM-768 + X25519 hybrid KEM */
} zuptsdk_encryption_t;
typedef enum {
ZUPTSDK_LOG_ERROR = 0,
ZUPTSDK_LOG_WARN = 1,
ZUPTSDK_LOG_INFO = 2,
ZUPTSDK_LOG_DEBUG = 3
} zuptsdk_log_level_t;
/* ════════════════════════════════════════════════════════════════════════
* CALLBACKS
* ════════════════════════════════════════════════════════════════════════ */
/**
* Streaming read callback. Library calls this to obtain input bytes.
* @param userdata [in] opaque pointer supplied at stream init
* @param buf [out] destination buffer
* @param max_bytes max bytes to read into buf
* @return Number of bytes actually read (0 == EOF, < 0 == error).
*/
typedef int64_t (*zuptsdk_read_fn)(void *userdata, uint8_t *buf, size_t max_bytes);
/**
* Streaming write callback. Library calls this to deliver output bytes.
* @param userdata [in] opaque pointer supplied at stream init
* @param buf [in] data to write
* @param bytes number of bytes in buf
* @return Number of bytes actually written (must equal `bytes` on success).
*/
typedef int64_t (*zuptsdk_write_fn)(void *userdata, const uint8_t *buf, size_t bytes);
/**
* Progress callback. Library invokes periodically during long operations.
* Return non-zero to cancel the operation; the in-flight call will then
* return ZUPTSDK_ERR_CANCELLED.
* @param userdata [in] opaque pointer set via zuptsdk_ctx_set_progress_callback
* @param processed bytes processed so far
* @param total total bytes (0 if unknown)
* @return 0 to continue, non-zero to cancel.
*/
typedef int (*zuptsdk_progress_fn)(void *userdata, uint64_t processed, uint64_t total);
/**
* Log callback. Receives diagnostic messages from the library.
* Set via zuptsdk_ctx_set_log_callback(). NULL means no logging (default).
* The string is null-terminated and valid only for the duration of the call.
*/
typedef void (*zuptsdk_log_fn)(void *userdata, zuptsdk_log_level_t level, const char *msg);
/**
* Custom allocator hooks. Set globally via zuptsdk_set_allocator().
* If any function is NULL, libc malloc/free/realloc is used.
* realloc_fn must accept (NULL, n) as malloc(n) and (p, 0) as free(p).
*/
typedef struct {
void *(*malloc_fn)(void *userdata, size_t size);
void (*free_fn)(void *userdata, void *ptr);
void *(*realloc_fn)(void *userdata, void *ptr, size_t size);
void *userdata;
} zuptsdk_allocator_t;
/* ════════════════════════════════════════════════════════════════════════
* GLOBAL CONFIG
* ════════════════════════════════════════════════════════════════════════ */
/**
* Install a custom allocator. Must be called before any other zuptsdk_*
* function. Calling after contexts have been created is undefined.
* Pass NULL to revert to libc allocator (only valid before first use).
*
* @param alloc [in,borrowed] allocator hooks; copied internally
* @return ZUPTSDK_OK or ZUPTSDK_ERR_INVALID_ARG
*/
int zuptsdk_set_allocator(const zuptsdk_allocator_t *alloc);
/* ════════════════════════════════════════════════════════════════════════
* CONTEXT
* ════════════════════════════════════════════════════════════════════════ */
/**
* Create a new SDK context. Each context holds its own thread pool,
* progress callback, log callback, and error state. Contexts are
* cheap to create — a few KB plus the configured thread count.
*
* @param ctx_out [out,transfers] pointer to receive new context
* @return ZUPTSDK_OK on success, ZUPTSDK_ERR_NO_MEMORY on alloc failure.
* On error, *ctx_out is set to NULL.
*/
int zuptsdk_ctx_create(zuptsdk_ctx_t **ctx_out);
/**
* Destroy a context. Frees all owned resources including thread pool.
* Safe to call with NULL. After this call, the pointer is invalid.
*/
void zuptsdk_ctx_destroy(zuptsdk_ctx_t *ctx);
/**
* Set worker thread count. 0 == auto (one per CPU). Default is auto.
* Returns ZUPTSDK_ERR_INVALID_ARG if ctx is NULL or threads > 256.
*/
int zuptsdk_ctx_set_threads(zuptsdk_ctx_t *ctx, int threads);
/**
* Set progress callback for long-running operations on this context.
* Pass NULL fn to clear. userdata is opaque to the library.
*/
int zuptsdk_ctx_set_progress_callback(zuptsdk_ctx_t *ctx,
zuptsdk_progress_fn fn,
void *userdata);
/**
* Set log callback for diagnostic messages on this context.
* Pass NULL fn to disable logging (default).
*/
int zuptsdk_ctx_set_log_callback(zuptsdk_ctx_t *ctx,
zuptsdk_log_fn fn,
zuptsdk_log_level_t min_level,
void *userdata);
/* ════════════════════════════════════════════════════════════════════════
* OPTIONS
* ════════════════════════════════════════════════════════════════════════ */
/**
* Create a default-initialized options bag for compress/encrypt operations.
* Defaults: codec=AUTO, level=7, no encryption, no dedup, no solid mode.
*/
int zuptsdk_options_create(zuptsdk_options_t **opts_out);
void zuptsdk_options_destroy(zuptsdk_options_t *opts);
int zuptsdk_options_set_codec(zuptsdk_options_t *opts, zuptsdk_codec_t codec);
int zuptsdk_options_set_level(zuptsdk_options_t *opts, int level /* 1..9 */);
int zuptsdk_options_set_dedup(zuptsdk_options_t *opts, int enabled);
int zuptsdk_options_set_solid(zuptsdk_options_t *opts, int enabled);
int zuptsdk_options_set_block_size(zuptsdk_options_t *opts, size_t bytes);
/**
* Maximum decompressed output size. Decompression aborts with
* ZUPTSDK_ERR_TOO_LARGE if exceeded. 0 == unlimited (NOT recommended
* for untrusted input — zip-bomb attack vector). Default: 16 GiB.
*/
int zuptsdk_options_set_max_decompressed(zuptsdk_options_t *opts,
uint64_t max_bytes);
/* ════════════════════════════════════════════════════════════════════════
* SECURE BUFFERS (for passwords and key material)
* ════════════════════════════════════════════════════════════════════════ */
/**
* Allocate a secure buffer: backing memory is mlock()ed (locked into RAM,
* never swapped to disk) and explicit_bzero()ed on destroy.
*
* @param size requested size in bytes (1..65536)
* @param buf_out [out,transfers] receives buffer handle
* @return ZUPTSDK_OK on success.
*/
int zuptsdk_secure_buf_create(size_t size, zuptsdk_secure_buf_t **buf_out);
/**
* Destroy a secure buffer. Memory is zeroed and unlocked before free.
* Safe to call with NULL.
*/
void zuptsdk_secure_buf_destroy(zuptsdk_secure_buf_t *buf);
/**
* Get raw pointer to the secure buffer's storage. Pointer is valid until
* zuptsdk_secure_buf_destroy() is called. Caller may read or write up to
* the buffer's size.
*
* @param buf [in]
* @param data_out [out,borrowed] receives pointer to storage
* @param size_out [out] receives buffer size
*/
int zuptsdk_secure_buf_get(zuptsdk_secure_buf_t *buf,
uint8_t **data_out, size_t *size_out);
/**
* Convenience: copy data into a new secure buffer.
* Useful when migrating an existing plain buffer to secure storage.
*/
int zuptsdk_secure_buf_from_data(const uint8_t *data, size_t size,
zuptsdk_secure_buf_t **buf_out);
/* ════════════════════════════════════════════════════════════════════════
* KEYS (PQ hybrid: ML-KEM-768 + X25519)
* ════════════════════════════════════════════════════════════════════════ */
/**
* Generate a fresh hybrid keypair. Uses the system CSPRNG.
*
* @param ctx [in]
* @param kp_out [out,transfers] receives new keypair
* @return ZUPTSDK_OK on success, ZUPTSDK_ERR_CRYPTO_FAIL on RNG failure.
*/
int zuptsdk_keypair_generate(zuptsdk_ctx_t *ctx, zuptsdk_keypair_t **kp_out);
void zuptsdk_keypair_destroy(zuptsdk_keypair_t *kp);
/**
* Save private key to a file. The file is written with mode 0600 on POSIX.
* Recommended extension: ".key".
*/
int zuptsdk_keypair_save_private(const zuptsdk_keypair_t *kp, const char *path);
/**
* Save public key to a file. World-readable.
* Recommended extension: ".pub" or "_public.key".
*/
int zuptsdk_keypair_save_public(const zuptsdk_keypair_t *kp, const char *path);
/**
* Load a private key from a file.
* @param path [in]
* @param key_out [out,transfers]
*/
int zuptsdk_privkey_load(const char *path, zuptsdk_privkey_t **key_out);
void zuptsdk_privkey_destroy(zuptsdk_privkey_t *key);
/**
* Load a public key from a file.
*/
int zuptsdk_pubkey_load(const char *path, zuptsdk_pubkey_t **key_out);
void zuptsdk_pubkey_destroy(zuptsdk_pubkey_t *key);
/**
* Derive public key from private key (no I/O).
*/
int zuptsdk_privkey_get_public(const zuptsdk_privkey_t *priv,
zuptsdk_pubkey_t **pub_out);
/* ════════════════════════════════════════════════════════════════════════
* COMPRESS / DECOMPRESS — buffer mode (for small archives)
* ════════════════════════════════════════════════════════════════════════ */
/**
* Compress an in-memory file list into a single archive buffer.
*
* @param ctx [in]
* @param opts [in,borrowed] compression and encryption options
* @param file_paths [in] array of filesystem paths to add
* @param file_count number of paths in file_paths
* @param password [in,nullable] password as a secure buffer; NULL for no pw
* @param recipient_pk [in,nullable] PQ public key for encryption; NULL for no PQ
* @param archive_out [out,transfers] receives malloc'd archive bytes;
* caller must free with zuptsdk_free()
* @param archive_sz [out] size of returned archive
* @return ZUPTSDK_OK on success.
*/
int zuptsdk_compress_files(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *const *file_paths,
size_t file_count,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk,
uint8_t **archive_out,
size_t *archive_sz);
/**
* Compress a single in-memory data buffer. Useful for SDK consumers that
* have data in memory and want a self-contained archive.
*
* @param logical_name [in] name to record inside the archive (e.g. "data.bin")
*/
int zuptsdk_compress_buffer(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *logical_name,
const uint8_t *data, size_t data_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk,
uint8_t **archive_out,
size_t *archive_sz);
/**
* Extract an archive into a directory.
*
* @param dest_dir [in] target directory; created if missing
* @param password [in,nullable]
* @param recipient_sk [in,nullable] PQ private key
*/
int zuptsdk_extract_to_dir(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
const char *dest_dir,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/**
* Extract a single-file archive (one created with zuptsdk_compress_buffer)
* back into a memory buffer.
*
* @param data_out [out,transfers] caller frees with zuptsdk_free()
* @param data_sz [out]
*/
int zuptsdk_extract_buffer(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk,
uint8_t **data_out, size_t *data_sz);
/* ════════════════════════════════════════════════════════════════════════
* COMPRESS / DECOMPRESS — streaming mode (for large archives)
* ════════════════════════════════════════════════════════════════════════ */
/**
* Compress from a read callback to a write callback. Streaming version
* with no archive size limit — suitable for piping to network sockets,
* encrypted volumes, or any backend with a write_fn.
*
* @param input [in] read callback supplying source bytes
* @param input_ud [in] userdata passed to read callback
* @param input_name [in] logical filename to record in archive
* @param input_total total bytes to read; 0 if unknown
* @param output [in] write callback receiving archive bytes
* @param output_ud [in] userdata passed to write callback
*/
int zuptsdk_compress_stream(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
zuptsdk_read_fn input, void *input_ud,
const char *input_name, uint64_t input_total,
zuptsdk_write_fn output, void *output_ud,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk);
/**
* Decompress an archive read from a callback, writing extracted single-file
* content to a write callback.
*/
int zuptsdk_decompress_stream(zuptsdk_ctx_t *ctx,
zuptsdk_read_fn input, void *input_ud,
zuptsdk_write_fn output, void *output_ud,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/* ════════════════════════════════════════════════════════════════════════
* VERIFY / INFO
* ════════════════════════════════════════════════════════════════════════ */
/**
* Verify all block checksums and (if encrypted) HMAC of an archive.
* No data is written to disk. Returns ZUPTSDK_OK if every block validates.
*/
int zuptsdk_verify(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/**
* Read archive metadata without password or key. Returns header info only;
* does not decrypt block contents.
*
* @param info_out [out,transfers] receives info object;
* caller must zuptsdk_archive_info_destroy()
*/
int zuptsdk_archive_info_read(zuptsdk_ctx_t *ctx,
const uint8_t *archive, size_t archive_sz,
zuptsdk_archive_info_t **info_out);
void zuptsdk_archive_info_destroy(zuptsdk_archive_info_t *info);
/* Getters — opaque struct, all fields accessed via these functions. */
int zuptsdk_archive_info_format_major(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_format_minor(const zuptsdk_archive_info_t *info);
const char *zuptsdk_archive_info_uuid(const zuptsdk_archive_info_t *info);
int64_t zuptsdk_archive_info_created_unix(const zuptsdk_archive_info_t *info);
uint64_t zuptsdk_archive_info_size(const zuptsdk_archive_info_t *info);
uint32_t zuptsdk_archive_info_block_count(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_encrypted(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_pq_hybrid(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_solid(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_dedup(const zuptsdk_archive_info_t *info);
int zuptsdk_archive_info_is_disk_image(const zuptsdk_archive_info_t *info);
/* ════════════════════════════════════════════════════════════════════════
* DISK BACKUP / RESTORE
* ════════════════════════════════════════════════════════════════════════ */
/**
* Backup a block device or disk image file to an archive.
* REQUIRES root/admin privileges to read raw block devices on most OSes.
*/
int zuptsdk_disk_backup(zuptsdk_ctx_t *ctx,
const zuptsdk_options_t *opts,
const char *source_device_or_image,
const char *output_archive_path,
zuptsdk_secure_buf_t *password,
const zuptsdk_pubkey_t *recipient_pk);
/**
* Restore a disk backup archive to a block device or image file.
* DESTRUCTIVE: target is overwritten without confirmation.
*/
int zuptsdk_disk_restore(zuptsdk_ctx_t *ctx,
const char *archive_path,
const char *target_device_or_image,
zuptsdk_secure_buf_t *password,
const zuptsdk_privkey_t *recipient_sk);
/* ════════════════════════════════════════════════════════════════════════
* MISC
* ════════════════════════════════════════════════════════════════════════ */
/**
* Free memory returned by the library via [transfers] output pointers.
* Safe to call with NULL.
*
* Always use this — never free() — for SDK-allocated memory, since the
* library may have been built with a custom allocator.
*/
void zuptsdk_free(void *ptr);
/**
* Best-effort secure zero of a buffer. Resistant to dead-store elimination
* by the optimizer. Use for caller-managed sensitive memory.
*/
void zuptsdk_secure_zero(void *buf, size_t bytes);
#ifdef __cplusplus
} /* extern "C" */
#endif
#endif /* ZUPTSDK_H */