• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // SPDX-License-Identifier: GPL-2.0+ OR Apache-2.0
2 /*
3  * Copyright (C) 2021 Gao Xiang <xiang@kernel.org>
4  */
5 #include <stdlib.h>
6 #include "config.h"
7 #ifdef HAVE_LIBLZMA
8 #include <lzma.h>
9 #include "erofs/config.h"
10 #include "erofs/print.h"
11 #include "erofs/internal.h"
12 #include "compressor.h"
13 
14 struct erofs_liblzma_context {
15 	lzma_options_lzma opt;
16 	lzma_stream strm;
17 };
18 
erofs_liblzma_compress_destsize(const struct erofs_compress * c,const void * src,unsigned int * srcsize,void * dst,unsigned int dstsize)19 static int erofs_liblzma_compress_destsize(const struct erofs_compress *c,
20 					   const void *src, unsigned int *srcsize,
21 					   void *dst, unsigned int dstsize)
22 {
23 	struct erofs_liblzma_context *ctx = c->private_data;
24 	lzma_stream *strm = &ctx->strm;
25 
26 	lzma_ret ret = lzma_microlzma_encoder(strm, &ctx->opt);
27 	if (ret != LZMA_OK)
28 		return -EFAULT;
29 
30 	strm->next_in = src;
31 	strm->avail_in = *srcsize;
32 	strm->next_out = dst;
33 	strm->avail_out = dstsize;
34 
35 	ret = lzma_code(strm, LZMA_FINISH);
36 	if (ret != LZMA_STREAM_END)
37 		return -EBADMSG;
38 
39 	*srcsize = strm->total_in;
40 	return strm->total_out;
41 }
42 
erofs_compressor_liblzma_exit(struct erofs_compress * c)43 static int erofs_compressor_liblzma_exit(struct erofs_compress *c)
44 {
45 	struct erofs_liblzma_context *ctx = c->private_data;
46 
47 	if (!ctx)
48 		return -EINVAL;
49 
50 	lzma_end(&ctx->strm);
51 	free(ctx);
52 	return 0;
53 }
54 
erofs_compressor_liblzma_setlevel(struct erofs_compress * c,int compression_level)55 static int erofs_compressor_liblzma_setlevel(struct erofs_compress *c,
56 					     int compression_level)
57 {
58 	struct erofs_liblzma_context *ctx = c->private_data;
59 	u32 preset;
60 
61 	if (compression_level < 0)
62 		preset = LZMA_PRESET_DEFAULT;
63 	else if (compression_level >= 100)
64 		preset = (compression_level - 100) | LZMA_PRESET_EXTREME;
65 	else
66 		preset = compression_level;
67 
68 	if (lzma_lzma_preset(&ctx->opt, preset))
69 		return -EINVAL;
70 
71 	/* XXX: temporary hack */
72 	if (cfg.c_dict_size) {
73 		if (cfg.c_dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE) {
74 			erofs_err("dict size %u is too large", cfg.c_dict_size);
75 			return -EINVAL;
76 		}
77 		ctx->opt.dict_size = cfg.c_dict_size;
78 	} else {
79 		if (ctx->opt.dict_size > Z_EROFS_LZMA_MAX_DICT_SIZE)
80 			ctx->opt.dict_size = Z_EROFS_LZMA_MAX_DICT_SIZE;
81 		cfg.c_dict_size = ctx->opt.dict_size;
82 	}
83 	c->compression_level = compression_level;
84 	return 0;
85 }
86 
erofs_compressor_liblzma_init(struct erofs_compress * c)87 static int erofs_compressor_liblzma_init(struct erofs_compress *c)
88 {
89 	struct erofs_liblzma_context *ctx;
90 
91 	ctx = malloc(sizeof(*ctx));
92 	if (!ctx)
93 		return -ENOMEM;
94 	ctx->strm = (lzma_stream)LZMA_STREAM_INIT;
95 	c->private_data = ctx;
96 	erofs_warn("EXPERIMENTAL MicroLZMA feature in use. Use at your own risk!");
97 	erofs_warn("Note that it may take more time since the compressor is still single-threaded for now.");
98 	return 0;
99 }
100 
101 const struct erofs_compressor erofs_compressor_lzma = {
102 	.default_level = LZMA_PRESET_DEFAULT,
103 	.best_level = 109,
104 	.init = erofs_compressor_liblzma_init,
105 	.exit = erofs_compressor_liblzma_exit,
106 	.setlevel = erofs_compressor_liblzma_setlevel,
107 	.compress_destsize = erofs_liblzma_compress_destsize,
108 };
109 #endif
110