| // SPDX-License-Identifier: GPL-2.0+ |
| /* |
| * Copyright 2021 Google LLC |
| */ |
| |
| #define LOG_CATEGORY LOGC_BOOT |
| |
| #include <common.h> |
| #include <abuf.h> |
| #include <log.h> |
| #include <malloc.h> |
| #include <linux/zstd.h> |
| |
| int zstd_decompress(struct abuf *in, struct abuf *out) |
| { |
| ZSTD_DStream *dstream; |
| ZSTD_inBuffer in_buf; |
| ZSTD_outBuffer out_buf; |
| void *workspace; |
| size_t wsize; |
| int ret; |
| |
| wsize = ZSTD_DStreamWorkspaceBound(abuf_size(in)); |
| workspace = malloc(wsize); |
| if (!workspace) { |
| debug("%s: cannot allocate workspace of size %zu\n", __func__, |
| wsize); |
| return -ENOMEM; |
| } |
| |
| dstream = ZSTD_initDStream(abuf_size(in), workspace, wsize); |
| if (!dstream) { |
| log_err("%s: ZSTD_initDStream failed\n", __func__); |
| ret = -EPERM; |
| goto do_free; |
| } |
| |
| in_buf.src = abuf_data(in); |
| in_buf.pos = 0; |
| in_buf.size = abuf_size(in); |
| |
| out_buf.dst = abuf_data(out); |
| out_buf.pos = 0; |
| out_buf.size = abuf_size(out); |
| |
| while (1) { |
| size_t res; |
| |
| res = ZSTD_decompressStream(dstream, &out_buf, &in_buf); |
| if (ZSTD_isError(res)) { |
| ret = ZSTD_getErrorCode(res); |
| log_err("ZSTD_decompressStream error %d\n", ret); |
| goto do_free; |
| } |
| |
| if (in_buf.pos >= abuf_size(in) || !res) |
| break; |
| } |
| |
| ret = out_buf.pos; |
| do_free: |
| free(workspace); |
| return ret; |
| } |