1// SPDX-License-Identifier: GPL-2.0+
2/*
3 * Copyright 2021 Google LLC
4 */
5
6#define LOG_CATEGORY	LOGC_BOOT
7
8#include <abuf.h>
9#include <log.h>
10#include <malloc.h>
11#include <linux/errno.h>
12#include <linux/zstd.h>
13
14int zstd_decompress(struct abuf *in, struct abuf *out)
15{
16	zstd_dctx *ctx;
17	size_t wsize, len;
18	void *workspace;
19	int ret;
20
21	wsize = zstd_dctx_workspace_bound();
22	workspace = malloc(wsize);
23	if (!workspace) {
24		debug("%s: cannot allocate workspace of size %zu\n", __func__,
25			wsize);
26		return -ENOMEM;
27	}
28
29	ctx = zstd_init_dctx(workspace, wsize);
30	if (!ctx) {
31		log_err("%s: zstd_init_dctx() failed\n", __func__);
32		ret = -EPERM;
33		goto do_free;
34	}
35
36	/*
37	 * Find out how large the frame actually is, there may be junk at
38	 * the end of the frame that zstd_decompress_dctx() can't handle.
39	 */
40	len = zstd_find_frame_compressed_size(abuf_data(in), abuf_size(in));
41	if (zstd_is_error(len)) {
42		log_err("%s: failed to detect compressed size: %d\n", __func__,
43			zstd_get_error_code(len));
44		ret = -EINVAL;
45		goto do_free;
46	}
47
48	len = zstd_decompress_dctx(ctx, abuf_data(out), abuf_size(out),
49				   abuf_data(in), len);
50	if (zstd_is_error(len)) {
51		log_err("%s: failed to decompress: %d\n", __func__,
52			zstd_get_error_code(len));
53		ret = -EINVAL;
54		goto do_free;
55	}
56
57	ret = len;
58do_free:
59	free(workspace);
60	return ret;
61}
62