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