import/export: add support for zstd
This commit is contained in:
@@ -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);
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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 += [
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user