138514Sdfr// SPDX-License-Identifier: GPL-2.0
238514Sdfr/*
338514Sdfr * uncompress.c
438514Sdfr *
538514Sdfr * (C) Copyright 1999 Linus Torvalds
638514Sdfr *
738514Sdfr * cramfs interfaces to the uncompression library. There's really just
838514Sdfr * three entrypoints:
938514Sdfr *
1038514Sdfr *  - cramfs_uncompress_init() - called to initialize the thing.
1138514Sdfr *  - cramfs_uncompress_exit() - tell me when you're done
1238514Sdfr *  - cramfs_uncompress_block() - uncompress a block.
1338514Sdfr *
1438514Sdfr * NOTE NOTE NOTE! The uncompression is entirely single-threaded. We
1538514Sdfr * only have one stream, and we'll initialize it only once even if it
1638514Sdfr * then is used by multiple filesystems.
1738514Sdfr */
1838514Sdfr
1938514Sdfr#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
2038514Sdfr
2138514Sdfr#include <linux/kernel.h>
2238514Sdfr#include <linux/errno.h>
2338514Sdfr#include <linux/vmalloc.h>
2438514Sdfr#include <linux/zlib.h>
2538514Sdfr#include "internal.h"
2650477Speter
2738514Sdfrstatic z_stream stream;
2838514Sdfrstatic int initialized;
2938514Sdfr
3038514Sdfr/* Returns length of decompressed data. */
3138514Sdfrint cramfs_uncompress_block(void *dst, int dstlen, void *src, int srclen)
3238514Sdfr{
3338514Sdfr	int err;
3438514Sdfr
3538514Sdfr	stream.next_in = src;
3638514Sdfr	stream.avail_in = srclen;
3738514Sdfr
3838514Sdfr	stream.next_out = dst;
3938514Sdfr	stream.avail_out = dstlen;
4039071Sdfr
4152128Speter	err = zlib_inflateReset(&stream);
4252128Speter	if (err != Z_OK) {
4339071Sdfr		pr_err("zlib_inflateReset error %d\n", err);
4439071Sdfr		zlib_inflateEnd(&stream);
4552128Speter		zlib_inflateInit(&stream);
4639071Sdfr	}
4739071Sdfr
4839071Sdfr	err = zlib_inflate(&stream, Z_FINISH);
4952128Speter	if (err != Z_STREAM_END)
5039071Sdfr		goto err;
5139071Sdfr	return stream.total_out;
5239071Sdfr
5340156Spetererr:
5438514Sdfr	pr_err("Error %d while decompressing!\n", err);
5538514Sdfr	pr_err("%p(%d)->%p(%d)\n", src, srclen, dst, dstlen);
5643301Sdillon	return -EIO;
5743309Sdillon}
5838514Sdfr
5943301Sdillonint cramfs_uncompress_init(void)
6038514Sdfr{
6140156Speter	if (!initialized++) {
6240156Speter		stream.workspace = vmalloc(zlib_inflate_workspacesize());
6338514Sdfr		if (!stream.workspace) {
6438514Sdfr			initialized = 0;
6540156Speter			return -ENOMEM;
6638514Sdfr		}
6738514Sdfr		stream.next_in = NULL;
6838514Sdfr		stream.avail_in = 0;
6938514Sdfr		zlib_inflateInit(&stream);
7038514Sdfr	}
7138514Sdfr	return 0;
7240156Speter}
7338514Sdfr
7438514Sdfrvoid cramfs_uncompress_exit(void)
7540156Speter{
7640156Speter	if (!--initialized) {
7740156Speter		zlib_inflateEnd(&stream);
7840156Speter		vfree(stream.workspace);
7940156Speter	}
8040156Speter}
8138514Sdfr