import/export: add support for zstd

This commit is contained in:
Luca Boccassi
2025-04-15 12:21:30 +01:00
parent b01f00e9c5
commit bd9c55ebe2
13 changed files with 169 additions and 15 deletions
+4
View File
@@ -43,6 +43,8 @@ static void determine_compression_from_filename(const char *p) {
arg_compress = IMPORT_COMPRESS_GZIP;
else if (endswith(p, ".bz2"))
arg_compress = IMPORT_COMPRESS_BZIP2;
else if (endswith(p, ".zst"))
arg_compress = IMPORT_COMPRESS_ZSTD;
else
arg_compress = IMPORT_COMPRESS_UNCOMPRESSED;
}
@@ -254,6 +256,8 @@ static int parse_argv(int argc, char *argv[]) {
arg_compress = IMPORT_COMPRESS_GZIP;
else if (streq(optarg, "bzip2"))
arg_compress = IMPORT_COMPRESS_BZIP2;
else if (streq(optarg, "zstd"))
arg_compress = IMPORT_COMPRESS_ZSTD;
else
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown format: %s", optarg);
+124 -1
View File
@@ -19,6 +19,16 @@ void import_compress_free(ImportCompress *c) {
BZ2_bzCompressEnd(&c->bzip2);
else
BZ2_bzDecompressEnd(&c->bzip2);
#endif
#if HAVE_ZSTD
} else if (c->type == IMPORT_COMPRESS_ZSTD) {
if (c->encoding) {
ZSTD_freeCCtx(c->c_zstd);
c->c_zstd = NULL;
} else {
ZSTD_freeDCtx(c->d_zstd);
c->d_zstd = NULL;
}
#endif
}
@@ -35,6 +45,9 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
static const uint8_t bzip2_signature[] = {
'B', 'Z', 'h'
};
static const uint8_t zstd_signature[] = {
0x28, 0xb5, 0x2f, 0xfd
};
int r;
@@ -43,8 +56,9 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
if (c->type != IMPORT_COMPRESS_UNKNOWN)
return 1;
if (size < MAX3(sizeof(xz_signature),
if (size < MAX4(sizeof(xz_signature),
sizeof(gzip_signature),
sizeof(zstd_signature),
sizeof(bzip2_signature)))
return 0;
@@ -73,6 +87,14 @@ int import_uncompress_detect(ImportCompress *c, const void *data, size_t size) {
return -EIO;
c->type = IMPORT_COMPRESS_BZIP2;
#endif
#if HAVE_ZSTD
} else if (memcmp(data, zstd_signature, sizeof(zstd_signature)) == 0) {
c->d_zstd = ZSTD_createDCtx();
if (!c->d_zstd)
return -ENOMEM;
c->type = IMPORT_COMPRESS_ZSTD;
#endif
} else
c->type = IMPORT_COMPRESS_UNCOMPRESSED;
@@ -187,6 +209,35 @@ int import_uncompress(ImportCompress *c, const void *data, size_t size, ImportCo
break;
#endif
#if HAVE_ZSTD
case IMPORT_COMPRESS_ZSTD: {
ZSTD_inBuffer input = {
.src = (void*) data,
.size = size,
};
while (input.pos < input.size) {
uint8_t buffer[16 * 1024];
ZSTD_outBuffer output = {
.dst = buffer,
.size = sizeof(buffer),
};
size_t res;
res = ZSTD_decompressStream(c->d_zstd, &output, &input);
if (ZSTD_isError(res))
return -EIO;
if (output.pos > 0) {
r = callback(output.dst, output.pos, userdata);
if (r < 0)
return r;
}
}
break;
}
#endif
default:
assert_not_reached();
@@ -231,6 +282,20 @@ int import_compress_init(ImportCompress *c, ImportCompressType t) {
break;
#endif
#if HAVE_ZSTD
case IMPORT_COMPRESS_ZSTD:
c->c_zstd = ZSTD_createCCtx();
if (!c->c_zstd)
return -ENOMEM;
r = ZSTD_CCtx_setParameter(c->c_zstd, ZSTD_c_compressionLevel, ZSTD_CLEVEL_DEFAULT);
if (ZSTD_isError(r))
return -EIO;
c->type = IMPORT_COMPRESS_ZSTD;
break;
#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
c->type = IMPORT_COMPRESS_UNCOMPRESSED;
break;
@@ -351,6 +416,35 @@ int import_compress(ImportCompress *c, const void *data, size_t size, void **buf
break;
#endif
#if HAVE_ZSTD
case IMPORT_COMPRESS_ZSTD: {
ZSTD_inBuffer input = {
.src = data,
.size = size,
};
while (input.pos < input.size) {
r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
if (r < 0)
return r;
ZSTD_outBuffer output = {
.dst = ((uint8_t *) *buffer + *buffer_size),
.size = *buffer_allocated - *buffer_size,
};
size_t res;
res = ZSTD_compressStream2(c->c_zstd, &output, &input, ZSTD_e_continue);
if (ZSTD_isError(res))
return -EIO;
*buffer_size += output.pos;
}
break;
}
#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
if (*buffer_allocated < size) {
@@ -455,6 +549,32 @@ int import_compress_finish(ImportCompress *c, void **buffer, size_t *buffer_size
break;
#endif
#if HAVE_ZSTD
case IMPORT_COMPRESS_ZSTD: {
ZSTD_inBuffer input = {};
size_t res;
do {
r = enlarge_buffer(buffer, buffer_size, buffer_allocated);
if (r < 0)
return r;
ZSTD_outBuffer output = {
.dst = ((uint8_t *) *buffer + *buffer_size),
.size = *buffer_allocated - *buffer_size,
};
res = ZSTD_compressStream2(c->c_zstd, &output, &input, ZSTD_e_end);
if (ZSTD_isError(res))
return -EIO;
*buffer_size += output.pos;
} while (res != 0);
break;
}
#endif
case IMPORT_COMPRESS_UNCOMPRESSED:
break;
@@ -473,6 +593,9 @@ static const char* const import_compress_type_table[_IMPORT_COMPRESS_TYPE_MAX] =
#if HAVE_BZIP2
[IMPORT_COMPRESS_BZIP2] = "bzip2",
#endif
#if HAVE_ZSTD
[IMPORT_COMPRESS_ZSTD] = "zstd",
#endif
};
DEFINE_STRING_TABLE_LOOKUP(import_compress_type, ImportCompressType);
+9
View File
@@ -7,6 +7,10 @@
#include <lzma.h>
#include <sys/types.h>
#include <zlib.h>
#if HAVE_ZSTD
#include <zstd.h>
#include <zstd_errors.h>
#endif
#include "macro.h"
@@ -16,6 +20,7 @@ typedef enum ImportCompressType {
IMPORT_COMPRESS_XZ,
IMPORT_COMPRESS_GZIP,
IMPORT_COMPRESS_BZIP2,
IMPORT_COMPRESS_ZSTD,
_IMPORT_COMPRESS_TYPE_MAX,
_IMPORT_COMPRESS_TYPE_INVALID = -EINVAL,
} ImportCompressType;
@@ -28,6 +33,10 @@ typedef struct ImportCompress {
z_stream gzip;
#if HAVE_BZIP2
bz_stream bzip2;
#endif
#if HAVE_ZSTD
ZSTD_CCtx *c_zstd;
ZSTD_DCtx *d_zstd;
#endif
};
} ImportCompress;
+5 -2
View File
@@ -491,6 +491,8 @@ static void determine_compression_from_filename(const char *p) {
arg_format = "gzip";
else if (endswith(p, ".bz2"))
arg_format = "bzip2";
else if (endswith(p, ".zst"))
arg_format = "zstd";
}
static int export_tar(int argc, char *argv[], void *userdata) {
@@ -1018,7 +1020,8 @@ static int help(int argc, char *argv[], void *userdata) {
" otherwise\n"
" --verify=MODE Verification mode for downloaded images (no,\n"
" checksum, signature)\n"
" --format=xz|gzip|bzip2 Desired output format for export\n"
" --format=xz|gzip|bzip2|zstd\n"
" Desired output format for export\n"
" --force Install image even if already exists\n"
" -m --class=machine Install as machine image\n"
" -P --class=portable Install as portable service image\n"
@@ -1139,7 +1142,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_FORMAT:
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2"))
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2", "zstd"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown format: %s", optarg);
+2
View File
@@ -47,6 +47,7 @@ lib_import_common = static_library(
libbzip2,
libxz,
libz,
libzstd,
userspace,
],
build_by_default : false)
@@ -61,6 +62,7 @@ common_deps = [
libcurl,
libxz,
libz,
libzstd,
]
executables += [
+1 -1
View File
@@ -2334,7 +2334,7 @@ static int parse_argv(int argc, char *argv[]) {
break;
case ARG_FORMAT:
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2"))
if (!STR_IN_SET(optarg, "uncompressed", "xz", "gzip", "bzip2", "zstd"))
return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
"Unknown format: %s", optarg);
+3
View File
@@ -152,6 +152,8 @@ int tar_strip_suffixes(const char *name, char **ret) {
e = endswith(name, ".tar.gz");
if (!e)
e = endswith(name, ".tar.bz2");
if (!e)
e = endswith(name, ".tar.zst");
if (!e)
e = endswith(name, ".tgz");
if (!e)
@@ -174,6 +176,7 @@ int raw_strip_suffixes(const char *p, char **ret) {
".xz\0"
".gz\0"
".bz2\0"
".zst\0"
".sysext.raw\0"
".confext.raw\0"
".raw\0"