// SPDX-License-Identifier: GPL-2.0-only /* * EROFS MicroLZMA wrapper around FreeBSD's bundled XZ Embedded decoder. * The decoder source is compiled with private symbol names because the * stock xz.ko does not enable its optional MicroLZMA entry points. */ #include #include #include #include "internal.h" #define XZ_DEC_MICROLZMA #define xz_dec_lzma2_create erofs_xz_dec_lzma2_create #define xz_dec_lzma2_reset erofs_xz_dec_lzma2_reset #define xz_dec_lzma2_run erofs_xz_dec_lzma2_run #define xz_dec_lzma2_end erofs_xz_dec_lzma2_end #define xz_dec_microlzma_alloc erofs_xz_dec_microlzma_alloc #define xz_dec_microlzma_reset erofs_xz_dec_microlzma_reset #define xz_dec_microlzma_run erofs_xz_dec_microlzma_run #define xz_dec_microlzma_end erofs_xz_dec_microlzma_end #define xz_malloc erofs_xz_malloc #define xz_free erofs_xz_free static void * erofs_xz_malloc(unsigned long size) { return (malloc(size, M_EROFS, M_WAITOK)); } static void erofs_xz_free(void *ptr) { free(ptr, M_EROFS); } #include #undef bool #undef false #undef true #undef min int z_erofs_load_lzma_config(struct erofs_mount *em, const void *data, size_t size) { const struct z_erofs_lzma_cfgs *lzma; uint32_t dict_size; if (size < sizeof(*lzma)) return (EINVAL); lzma = data; if (le16toh(lzma->format) != 0) return (EOPNOTSUPP); dict_size = le32toh(lzma->dict_size); if (dict_size < 4096 || dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE) return (EOPNOTSUPP); em->lzma_dict_size = dict_size; return (0); } int lzma_decompress(const void *src, size_t srclen, void *dst, size_t dstlen, uint32_t dict_size, bool partial) { struct xz_dec_microlzma *state; struct xz_buf buffer; enum xz_ret ret; if (srclen > UINT32_MAX || dstlen > UINT32_MAX) return (-1); state = xz_dec_microlzma_alloc(XZ_SINGLE, dict_size); if (state == NULL) return (-1); bzero(&buffer, sizeof(buffer)); buffer.in = src; buffer.in_size = srclen; buffer.out = dst; buffer.out_size = dstlen; xz_dec_microlzma_reset(state, (uint32_t)srclen, (uint32_t)dstlen, !partial); ret = xz_dec_microlzma_run(state, &buffer); xz_dec_microlzma_end(state); if (buffer.out_pos != dstlen) return (-1); if (partial) return (ret == XZ_OK || ret == XZ_STREAM_END ? 0 : -1); return (ret == XZ_STREAM_END && buffer.in_pos == srclen ? 0 : -1); }