/* SPDX-License-Identifier: BSD-2-Clause */ /* Minimal zstd decompressor for EROFS FreeBSD */ #include #include #include #include #include "internal.h" #ifdef ZSTDIO #define ZSTD_STATIC_LINKING_ONLY #include #endif bool erofs_zstd_available(void) { #ifdef ZSTDIO return (true); #else return (false); #endif } int z_erofs_load_zstd_config(struct erofs_mount *em, const void *data, size_t size) { const struct z_erofs_zstd_cfgs *zstd; if (!erofs_zstd_available()) { vfs_mount_error(em->mnt, "erofs: ZSTD compression requires ZSTDIO support"); return (EOPNOTSUPP); } if (size < sizeof(*zstd)) return (EINVAL); zstd = data; if (zstd->format != 0 || zstd->windowlog > 10) return (EOPNOTSUPP); em->zstd_windowlog = zstd->windowlog; return (0); } #ifdef ZSTDIO static void * zstd_alloc(void *opaque, size_t size) { return (malloc(size, opaque, M_WAITOK)); } static void zstd_free(void *opaque, void *address) { free(address, opaque); } static const ZSTD_customMem zstd_erofs_alloc = { .customAlloc = zstd_alloc, .customFree = zstd_free, .opaque = M_EROFS, }; int zstd_decompress(void *src, size_t srclen, void *dst, size_t dstlen, int n, bool partial) { ZSTD_DCtx *dctx; ZSTD_inBuffer input; ZSTD_outBuffer output; size_t in_before, out_before, ret; int error; if (n < 10 || n > 20 || dstlen == 0) return (-1); dctx = ZSTD_createDCtx_advanced(zstd_erofs_alloc); if (dctx == NULL) return (-1); ret = ZSTD_DCtx_setParameter(dctx, ZSTD_d_windowLogMax, n); if (ZSTD_isError(ret)) { ZSTD_freeDCtx(dctx); return (-1); } input = (ZSTD_inBuffer) { .src = src, .size = srclen, }; output = (ZSTD_outBuffer) { .dst = dst, .size = dstlen, }; ret = 1; while (output.pos != output.size) { in_before = input.pos; out_before = output.pos; ret = ZSTD_decompressStream(dctx, &output, &input); if (ZSTD_isError(ret) || (input.pos == in_before && output.pos == out_before)) break; if (ret == 0) break; } error = 0; if (ZSTD_isError(ret) || output.pos != output.size) error = -1; else if (!partial && (ret != 0 || input.pos != input.size)) error = -1; ret = ZSTD_freeDCtx(dctx); if (ZSTD_isError(ret)) error = -1; return (error); } #else int zstd_decompress(void *src, size_t srclen, void *dst, size_t dstlen, int n, bool partial) { (void)src; (void)srclen; (void)dst; (void)dstlen; (void)n; (void)partial; return (-1); } #endif