18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 28c2ecf20Sopenharmony_ci 38c2ecf20Sopenharmony_ci/* 48c2ecf20Sopenharmony_ci * Important notes about in-place decompression 58c2ecf20Sopenharmony_ci * 68c2ecf20Sopenharmony_ci * At least on x86, the kernel is decompressed in place: the compressed data 78c2ecf20Sopenharmony_ci * is placed to the end of the output buffer, and the decompressor overwrites 88c2ecf20Sopenharmony_ci * most of the compressed data. There must be enough safety margin to 98c2ecf20Sopenharmony_ci * guarantee that the write position is always behind the read position. 108c2ecf20Sopenharmony_ci * 118c2ecf20Sopenharmony_ci * The safety margin for ZSTD with a 128 KB block size is calculated below. 128c2ecf20Sopenharmony_ci * Note that the margin with ZSTD is bigger than with GZIP or XZ! 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * The worst case for in-place decompression is that the beginning of 158c2ecf20Sopenharmony_ci * the file is compressed extremely well, and the rest of the file is 168c2ecf20Sopenharmony_ci * uncompressible. Thus, we must look for worst-case expansion when the 178c2ecf20Sopenharmony_ci * compressor is encoding uncompressible data. 188c2ecf20Sopenharmony_ci * 198c2ecf20Sopenharmony_ci * The structure of the .zst file in case of a compresed kernel is as follows. 208c2ecf20Sopenharmony_ci * Maximum sizes (as bytes) of the fields are in parenthesis. 218c2ecf20Sopenharmony_ci * 228c2ecf20Sopenharmony_ci * Frame Header: (18) 238c2ecf20Sopenharmony_ci * Blocks: (N) 248c2ecf20Sopenharmony_ci * Checksum: (4) 258c2ecf20Sopenharmony_ci * 268c2ecf20Sopenharmony_ci * The frame header and checksum overhead is at most 22 bytes. 278c2ecf20Sopenharmony_ci * 288c2ecf20Sopenharmony_ci * ZSTD stores the data in blocks. Each block has a header whose size is 298c2ecf20Sopenharmony_ci * a 3 bytes. After the block header, there is up to 128 KB of payload. 308c2ecf20Sopenharmony_ci * The maximum uncompressed size of the payload is 128 KB. The minimum 318c2ecf20Sopenharmony_ci * uncompressed size of the payload is never less than the payload size 328c2ecf20Sopenharmony_ci * (excluding the block header). 338c2ecf20Sopenharmony_ci * 348c2ecf20Sopenharmony_ci * The assumption, that the uncompressed size of the payload is never 358c2ecf20Sopenharmony_ci * smaller than the payload itself, is valid only when talking about 368c2ecf20Sopenharmony_ci * the payload as a whole. It is possible that the payload has parts where 378c2ecf20Sopenharmony_ci * the decompressor consumes more input than it produces output. Calculating 388c2ecf20Sopenharmony_ci * the worst case for this would be tricky. Instead of trying to do that, 398c2ecf20Sopenharmony_ci * let's simply make sure that the decompressor never overwrites any bytes 408c2ecf20Sopenharmony_ci * of the payload which it is currently reading. 418c2ecf20Sopenharmony_ci * 428c2ecf20Sopenharmony_ci * Now we have enough information to calculate the safety margin. We need 438c2ecf20Sopenharmony_ci * - 22 bytes for the .zst file format headers; 448c2ecf20Sopenharmony_ci * - 3 bytes per every 128 KiB of uncompressed size (one block header per 458c2ecf20Sopenharmony_ci * block); and 468c2ecf20Sopenharmony_ci * - 128 KiB (biggest possible zstd block size) to make sure that the 478c2ecf20Sopenharmony_ci * decompressor never overwrites anything from the block it is currently 488c2ecf20Sopenharmony_ci * reading. 498c2ecf20Sopenharmony_ci * 508c2ecf20Sopenharmony_ci * We get the following formula: 518c2ecf20Sopenharmony_ci * 528c2ecf20Sopenharmony_ci * safety_margin = 22 + uncompressed_size * 3 / 131072 + 131072 538c2ecf20Sopenharmony_ci * <= 22 + (uncompressed_size >> 15) + 131072 548c2ecf20Sopenharmony_ci */ 558c2ecf20Sopenharmony_ci 568c2ecf20Sopenharmony_ci/* 578c2ecf20Sopenharmony_ci * Preboot environments #include "path/to/decompress_unzstd.c". 588c2ecf20Sopenharmony_ci * All of the source files we depend on must be #included. 598c2ecf20Sopenharmony_ci * zstd's only source dependeny is xxhash, which has no source 608c2ecf20Sopenharmony_ci * dependencies. 618c2ecf20Sopenharmony_ci * 628c2ecf20Sopenharmony_ci * When UNZSTD_PREBOOT is defined we declare __decompress(), which is 638c2ecf20Sopenharmony_ci * used for kernel decompression, instead of unzstd(). 648c2ecf20Sopenharmony_ci * 658c2ecf20Sopenharmony_ci * Define __DISABLE_EXPORTS in preboot environments to prevent symbols 668c2ecf20Sopenharmony_ci * from xxhash and zstd from being exported by the EXPORT_SYMBOL macro. 678c2ecf20Sopenharmony_ci */ 688c2ecf20Sopenharmony_ci#ifdef STATIC 698c2ecf20Sopenharmony_ci# define UNZSTD_PREBOOT 708c2ecf20Sopenharmony_ci# include "xxhash.c" 718c2ecf20Sopenharmony_ci# include "zstd/entropy_common.c" 728c2ecf20Sopenharmony_ci# include "zstd/fse_decompress.c" 738c2ecf20Sopenharmony_ci# include "zstd/huf_decompress.c" 748c2ecf20Sopenharmony_ci# include "zstd/zstd_common.c" 758c2ecf20Sopenharmony_ci# include "zstd/decompress.c" 768c2ecf20Sopenharmony_ci#endif 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_ci#include <linux/decompress/mm.h> 798c2ecf20Sopenharmony_ci#include <linux/kernel.h> 808c2ecf20Sopenharmony_ci#include <linux/zstd.h> 818c2ecf20Sopenharmony_ci 828c2ecf20Sopenharmony_ci/* 128MB is the maximum window size supported by zstd. */ 838c2ecf20Sopenharmony_ci#define ZSTD_WINDOWSIZE_MAX (1 << ZSTD_WINDOWLOG_MAX) 848c2ecf20Sopenharmony_ci/* 858c2ecf20Sopenharmony_ci * Size of the input and output buffers in multi-call mode. 868c2ecf20Sopenharmony_ci * Pick a larger size because it isn't used during kernel decompression, 878c2ecf20Sopenharmony_ci * since that is single pass, and we have to allocate a large buffer for 888c2ecf20Sopenharmony_ci * zstd's window anyway. The larger size speeds up initramfs decompression. 898c2ecf20Sopenharmony_ci */ 908c2ecf20Sopenharmony_ci#define ZSTD_IOBUF_SIZE (1 << 17) 918c2ecf20Sopenharmony_ci 928c2ecf20Sopenharmony_cistatic int INIT handle_zstd_error(size_t ret, void (*error)(char *x)) 938c2ecf20Sopenharmony_ci{ 948c2ecf20Sopenharmony_ci const int err = ZSTD_getErrorCode(ret); 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci if (!ZSTD_isError(ret)) 978c2ecf20Sopenharmony_ci return 0; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci switch (err) { 1008c2ecf20Sopenharmony_ci case ZSTD_error_memory_allocation: 1018c2ecf20Sopenharmony_ci error("ZSTD decompressor ran out of memory"); 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case ZSTD_error_prefix_unknown: 1048c2ecf20Sopenharmony_ci error("Input is not in the ZSTD format (wrong magic bytes)"); 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case ZSTD_error_dstSize_tooSmall: 1078c2ecf20Sopenharmony_ci case ZSTD_error_corruption_detected: 1088c2ecf20Sopenharmony_ci case ZSTD_error_checksum_wrong: 1098c2ecf20Sopenharmony_ci error("ZSTD-compressed data is corrupt"); 1108c2ecf20Sopenharmony_ci break; 1118c2ecf20Sopenharmony_ci default: 1128c2ecf20Sopenharmony_ci error("ZSTD-compressed data is probably corrupt"); 1138c2ecf20Sopenharmony_ci break; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci return -1; 1168c2ecf20Sopenharmony_ci} 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_ci/* 1198c2ecf20Sopenharmony_ci * Handle the case where we have the entire input and output in one segment. 1208c2ecf20Sopenharmony_ci * We can allocate less memory (no circular buffer for the sliding window), 1218c2ecf20Sopenharmony_ci * and avoid some memcpy() calls. 1228c2ecf20Sopenharmony_ci */ 1238c2ecf20Sopenharmony_cistatic int INIT decompress_single(const u8 *in_buf, long in_len, u8 *out_buf, 1248c2ecf20Sopenharmony_ci long out_len, long *in_pos, 1258c2ecf20Sopenharmony_ci void (*error)(char *x)) 1268c2ecf20Sopenharmony_ci{ 1278c2ecf20Sopenharmony_ci const size_t wksp_size = ZSTD_DCtxWorkspaceBound(); 1288c2ecf20Sopenharmony_ci void *wksp = large_malloc(wksp_size); 1298c2ecf20Sopenharmony_ci ZSTD_DCtx *dctx = ZSTD_initDCtx(wksp, wksp_size); 1308c2ecf20Sopenharmony_ci int err; 1318c2ecf20Sopenharmony_ci size_t ret; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci if (dctx == NULL) { 1348c2ecf20Sopenharmony_ci error("Out of memory while allocating ZSTD_DCtx"); 1358c2ecf20Sopenharmony_ci err = -1; 1368c2ecf20Sopenharmony_ci goto out; 1378c2ecf20Sopenharmony_ci } 1388c2ecf20Sopenharmony_ci /* 1398c2ecf20Sopenharmony_ci * Find out how large the frame actually is, there may be junk at 1408c2ecf20Sopenharmony_ci * the end of the frame that ZSTD_decompressDCtx() can't handle. 1418c2ecf20Sopenharmony_ci */ 1428c2ecf20Sopenharmony_ci ret = ZSTD_findFrameCompressedSize(in_buf, in_len); 1438c2ecf20Sopenharmony_ci err = handle_zstd_error(ret, error); 1448c2ecf20Sopenharmony_ci if (err) 1458c2ecf20Sopenharmony_ci goto out; 1468c2ecf20Sopenharmony_ci in_len = (long)ret; 1478c2ecf20Sopenharmony_ci 1488c2ecf20Sopenharmony_ci ret = ZSTD_decompressDCtx(dctx, out_buf, out_len, in_buf, in_len); 1498c2ecf20Sopenharmony_ci err = handle_zstd_error(ret, error); 1508c2ecf20Sopenharmony_ci if (err) 1518c2ecf20Sopenharmony_ci goto out; 1528c2ecf20Sopenharmony_ci 1538c2ecf20Sopenharmony_ci if (in_pos != NULL) 1548c2ecf20Sopenharmony_ci *in_pos = in_len; 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_ci err = 0; 1578c2ecf20Sopenharmony_ciout: 1588c2ecf20Sopenharmony_ci if (wksp != NULL) 1598c2ecf20Sopenharmony_ci large_free(wksp); 1608c2ecf20Sopenharmony_ci return err; 1618c2ecf20Sopenharmony_ci} 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_cistatic int INIT __unzstd(unsigned char *in_buf, long in_len, 1648c2ecf20Sopenharmony_ci long (*fill)(void*, unsigned long), 1658c2ecf20Sopenharmony_ci long (*flush)(void*, unsigned long), 1668c2ecf20Sopenharmony_ci unsigned char *out_buf, long out_len, 1678c2ecf20Sopenharmony_ci long *in_pos, 1688c2ecf20Sopenharmony_ci void (*error)(char *x)) 1698c2ecf20Sopenharmony_ci{ 1708c2ecf20Sopenharmony_ci ZSTD_inBuffer in; 1718c2ecf20Sopenharmony_ci ZSTD_outBuffer out; 1728c2ecf20Sopenharmony_ci ZSTD_frameParams params; 1738c2ecf20Sopenharmony_ci void *in_allocated = NULL; 1748c2ecf20Sopenharmony_ci void *out_allocated = NULL; 1758c2ecf20Sopenharmony_ci void *wksp = NULL; 1768c2ecf20Sopenharmony_ci size_t wksp_size; 1778c2ecf20Sopenharmony_ci ZSTD_DStream *dstream; 1788c2ecf20Sopenharmony_ci int err; 1798c2ecf20Sopenharmony_ci size_t ret; 1808c2ecf20Sopenharmony_ci 1818c2ecf20Sopenharmony_ci /* 1828c2ecf20Sopenharmony_ci * ZSTD decompression code won't be happy if the buffer size is so big 1838c2ecf20Sopenharmony_ci * that its end address overflows. When the size is not provided, make 1848c2ecf20Sopenharmony_ci * it as big as possible without having the end address overflow. 1858c2ecf20Sopenharmony_ci */ 1868c2ecf20Sopenharmony_ci if (out_len == 0) 1878c2ecf20Sopenharmony_ci out_len = UINTPTR_MAX - (uintptr_t)out_buf; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci if (fill == NULL && flush == NULL) 1908c2ecf20Sopenharmony_ci /* 1918c2ecf20Sopenharmony_ci * We can decompress faster and with less memory when we have a 1928c2ecf20Sopenharmony_ci * single chunk. 1938c2ecf20Sopenharmony_ci */ 1948c2ecf20Sopenharmony_ci return decompress_single(in_buf, in_len, out_buf, out_len, 1958c2ecf20Sopenharmony_ci in_pos, error); 1968c2ecf20Sopenharmony_ci 1978c2ecf20Sopenharmony_ci /* 1988c2ecf20Sopenharmony_ci * If in_buf is not provided, we must be using fill(), so allocate 1998c2ecf20Sopenharmony_ci * a large enough buffer. If it is provided, it must be at least 2008c2ecf20Sopenharmony_ci * ZSTD_IOBUF_SIZE large. 2018c2ecf20Sopenharmony_ci */ 2028c2ecf20Sopenharmony_ci if (in_buf == NULL) { 2038c2ecf20Sopenharmony_ci in_allocated = large_malloc(ZSTD_IOBUF_SIZE); 2048c2ecf20Sopenharmony_ci if (in_allocated == NULL) { 2058c2ecf20Sopenharmony_ci error("Out of memory while allocating input buffer"); 2068c2ecf20Sopenharmony_ci err = -1; 2078c2ecf20Sopenharmony_ci goto out; 2088c2ecf20Sopenharmony_ci } 2098c2ecf20Sopenharmony_ci in_buf = in_allocated; 2108c2ecf20Sopenharmony_ci in_len = 0; 2118c2ecf20Sopenharmony_ci } 2128c2ecf20Sopenharmony_ci /* Read the first chunk, since we need to decode the frame header. */ 2138c2ecf20Sopenharmony_ci if (fill != NULL) 2148c2ecf20Sopenharmony_ci in_len = fill(in_buf, ZSTD_IOBUF_SIZE); 2158c2ecf20Sopenharmony_ci if (in_len < 0) { 2168c2ecf20Sopenharmony_ci error("ZSTD-compressed data is truncated"); 2178c2ecf20Sopenharmony_ci err = -1; 2188c2ecf20Sopenharmony_ci goto out; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci /* Set the first non-empty input buffer. */ 2218c2ecf20Sopenharmony_ci in.src = in_buf; 2228c2ecf20Sopenharmony_ci in.pos = 0; 2238c2ecf20Sopenharmony_ci in.size = in_len; 2248c2ecf20Sopenharmony_ci /* Allocate the output buffer if we are using flush(). */ 2258c2ecf20Sopenharmony_ci if (flush != NULL) { 2268c2ecf20Sopenharmony_ci out_allocated = large_malloc(ZSTD_IOBUF_SIZE); 2278c2ecf20Sopenharmony_ci if (out_allocated == NULL) { 2288c2ecf20Sopenharmony_ci error("Out of memory while allocating output buffer"); 2298c2ecf20Sopenharmony_ci err = -1; 2308c2ecf20Sopenharmony_ci goto out; 2318c2ecf20Sopenharmony_ci } 2328c2ecf20Sopenharmony_ci out_buf = out_allocated; 2338c2ecf20Sopenharmony_ci out_len = ZSTD_IOBUF_SIZE; 2348c2ecf20Sopenharmony_ci } 2358c2ecf20Sopenharmony_ci /* Set the output buffer. */ 2368c2ecf20Sopenharmony_ci out.dst = out_buf; 2378c2ecf20Sopenharmony_ci out.pos = 0; 2388c2ecf20Sopenharmony_ci out.size = out_len; 2398c2ecf20Sopenharmony_ci 2408c2ecf20Sopenharmony_ci /* 2418c2ecf20Sopenharmony_ci * We need to know the window size to allocate the ZSTD_DStream. 2428c2ecf20Sopenharmony_ci * Since we are streaming, we need to allocate a buffer for the sliding 2438c2ecf20Sopenharmony_ci * window. The window size varies from 1 KB to ZSTD_WINDOWSIZE_MAX 2448c2ecf20Sopenharmony_ci * (8 MB), so it is important to use the actual value so as not to 2458c2ecf20Sopenharmony_ci * waste memory when it is smaller. 2468c2ecf20Sopenharmony_ci */ 2478c2ecf20Sopenharmony_ci ret = ZSTD_getFrameParams(¶ms, in.src, in.size); 2488c2ecf20Sopenharmony_ci err = handle_zstd_error(ret, error); 2498c2ecf20Sopenharmony_ci if (err) 2508c2ecf20Sopenharmony_ci goto out; 2518c2ecf20Sopenharmony_ci if (ret != 0) { 2528c2ecf20Sopenharmony_ci error("ZSTD-compressed data has an incomplete frame header"); 2538c2ecf20Sopenharmony_ci err = -1; 2548c2ecf20Sopenharmony_ci goto out; 2558c2ecf20Sopenharmony_ci } 2568c2ecf20Sopenharmony_ci if (params.windowSize > ZSTD_WINDOWSIZE_MAX) { 2578c2ecf20Sopenharmony_ci error("ZSTD-compressed data has too large a window size"); 2588c2ecf20Sopenharmony_ci err = -1; 2598c2ecf20Sopenharmony_ci goto out; 2608c2ecf20Sopenharmony_ci } 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* 2638c2ecf20Sopenharmony_ci * Allocate the ZSTD_DStream now that we know how much memory is 2648c2ecf20Sopenharmony_ci * required. 2658c2ecf20Sopenharmony_ci */ 2668c2ecf20Sopenharmony_ci wksp_size = ZSTD_DStreamWorkspaceBound(params.windowSize); 2678c2ecf20Sopenharmony_ci wksp = large_malloc(wksp_size); 2688c2ecf20Sopenharmony_ci dstream = ZSTD_initDStream(params.windowSize, wksp, wksp_size); 2698c2ecf20Sopenharmony_ci if (dstream == NULL) { 2708c2ecf20Sopenharmony_ci error("Out of memory while allocating ZSTD_DStream"); 2718c2ecf20Sopenharmony_ci err = -1; 2728c2ecf20Sopenharmony_ci goto out; 2738c2ecf20Sopenharmony_ci } 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci /* 2768c2ecf20Sopenharmony_ci * Decompression loop: 2778c2ecf20Sopenharmony_ci * Read more data if necessary (error if no more data can be read). 2788c2ecf20Sopenharmony_ci * Call the decompression function, which returns 0 when finished. 2798c2ecf20Sopenharmony_ci * Flush any data produced if using flush(). 2808c2ecf20Sopenharmony_ci */ 2818c2ecf20Sopenharmony_ci if (in_pos != NULL) 2828c2ecf20Sopenharmony_ci *in_pos = 0; 2838c2ecf20Sopenharmony_ci do { 2848c2ecf20Sopenharmony_ci /* 2858c2ecf20Sopenharmony_ci * If we need to reload data, either we have fill() and can 2868c2ecf20Sopenharmony_ci * try to get more data, or we don't and the input is truncated. 2878c2ecf20Sopenharmony_ci */ 2888c2ecf20Sopenharmony_ci if (in.pos == in.size) { 2898c2ecf20Sopenharmony_ci if (in_pos != NULL) 2908c2ecf20Sopenharmony_ci *in_pos += in.pos; 2918c2ecf20Sopenharmony_ci in_len = fill ? fill(in_buf, ZSTD_IOBUF_SIZE) : -1; 2928c2ecf20Sopenharmony_ci if (in_len < 0) { 2938c2ecf20Sopenharmony_ci error("ZSTD-compressed data is truncated"); 2948c2ecf20Sopenharmony_ci err = -1; 2958c2ecf20Sopenharmony_ci goto out; 2968c2ecf20Sopenharmony_ci } 2978c2ecf20Sopenharmony_ci in.pos = 0; 2988c2ecf20Sopenharmony_ci in.size = in_len; 2998c2ecf20Sopenharmony_ci } 3008c2ecf20Sopenharmony_ci /* Returns zero when the frame is complete. */ 3018c2ecf20Sopenharmony_ci ret = ZSTD_decompressStream(dstream, &out, &in); 3028c2ecf20Sopenharmony_ci err = handle_zstd_error(ret, error); 3038c2ecf20Sopenharmony_ci if (err) 3048c2ecf20Sopenharmony_ci goto out; 3058c2ecf20Sopenharmony_ci /* Flush all of the data produced if using flush(). */ 3068c2ecf20Sopenharmony_ci if (flush != NULL && out.pos > 0) { 3078c2ecf20Sopenharmony_ci if (out.pos != flush(out.dst, out.pos)) { 3088c2ecf20Sopenharmony_ci error("Failed to flush()"); 3098c2ecf20Sopenharmony_ci err = -1; 3108c2ecf20Sopenharmony_ci goto out; 3118c2ecf20Sopenharmony_ci } 3128c2ecf20Sopenharmony_ci out.pos = 0; 3138c2ecf20Sopenharmony_ci } 3148c2ecf20Sopenharmony_ci } while (ret != 0); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci if (in_pos != NULL) 3178c2ecf20Sopenharmony_ci *in_pos += in.pos; 3188c2ecf20Sopenharmony_ci 3198c2ecf20Sopenharmony_ci err = 0; 3208c2ecf20Sopenharmony_ciout: 3218c2ecf20Sopenharmony_ci if (in_allocated != NULL) 3228c2ecf20Sopenharmony_ci large_free(in_allocated); 3238c2ecf20Sopenharmony_ci if (out_allocated != NULL) 3248c2ecf20Sopenharmony_ci large_free(out_allocated); 3258c2ecf20Sopenharmony_ci if (wksp != NULL) 3268c2ecf20Sopenharmony_ci large_free(wksp); 3278c2ecf20Sopenharmony_ci return err; 3288c2ecf20Sopenharmony_ci} 3298c2ecf20Sopenharmony_ci 3308c2ecf20Sopenharmony_ci#ifndef UNZSTD_PREBOOT 3318c2ecf20Sopenharmony_ciSTATIC int INIT unzstd(unsigned char *buf, long len, 3328c2ecf20Sopenharmony_ci long (*fill)(void*, unsigned long), 3338c2ecf20Sopenharmony_ci long (*flush)(void*, unsigned long), 3348c2ecf20Sopenharmony_ci unsigned char *out_buf, 3358c2ecf20Sopenharmony_ci long *pos, 3368c2ecf20Sopenharmony_ci void (*error)(char *x)) 3378c2ecf20Sopenharmony_ci{ 3388c2ecf20Sopenharmony_ci return __unzstd(buf, len, fill, flush, out_buf, 0, pos, error); 3398c2ecf20Sopenharmony_ci} 3408c2ecf20Sopenharmony_ci#else 3418c2ecf20Sopenharmony_ciSTATIC int INIT __decompress(unsigned char *buf, long len, 3428c2ecf20Sopenharmony_ci long (*fill)(void*, unsigned long), 3438c2ecf20Sopenharmony_ci long (*flush)(void*, unsigned long), 3448c2ecf20Sopenharmony_ci unsigned char *out_buf, long out_len, 3458c2ecf20Sopenharmony_ci long *pos, 3468c2ecf20Sopenharmony_ci void (*error)(char *x)) 3478c2ecf20Sopenharmony_ci{ 3488c2ecf20Sopenharmony_ci return __unzstd(buf, len, fill, flush, out_buf, out_len, pos, error); 3498c2ecf20Sopenharmony_ci} 3508c2ecf20Sopenharmony_ci#endif 351