xref: /illumos-gate/usr/src/uts/common/zmod/zmod.c (revision e8d3efa1c56e5f2b5368600a2baeb7b1d54a07f8)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  *
26  * Copyright 2026 Oxide Computer Company
27  */
28 
29 #include <sys/modctl.h>
30 #include <sys/zmod.h>
31 
32 #include <zlib.h>
33 #include <zutil.h>
34 
35 /*
36  * Uncompress the buffer 'src' into the buffer 'dst'.  The caller must store
37  * the expected decompressed data size externally so it can be passed in.
38  * The resulting decompressed size is then returned through dstlen.  This
39  * function return Z_OK on success, or another error code on failure.
40  */
41 static int
42 z_uncompress_impl(void *dst, size_t *dstlen, const void *src, size_t srclen,
43     alloc_func zalloc)
44 {
45 	z_stream zs;
46 	int err;
47 
48 	bzero(&zs, sizeof (zs));
49 	zs.zalloc = zalloc;
50 	zs.next_in = (uchar_t *)src;
51 	zs.avail_in = srclen;
52 	zs.next_out = dst;
53 	zs.avail_out = *dstlen;
54 
55 	/*
56 	 * Call inflateInit2() specifying a window size of DEF_WBITS
57 	 * with the 6th bit set to indicate that the compression format
58 	 * type (zlib or gzip) should be automatically detected.
59 	 */
60 	if ((err = inflateInit2(&zs, DEF_WBITS | 0x20)) != Z_OK)
61 		return (err);
62 
63 	if ((err = inflate(&zs, Z_FINISH)) != Z_STREAM_END) {
64 		(void) inflateEnd(&zs);
65 		return (err == Z_OK ? Z_BUF_ERROR : err);
66 	}
67 
68 	*dstlen = zs.total_out;
69 	return (inflateEnd(&zs));
70 }
71 
72 int
73 z_uncompress(void *dst, size_t *dstlen, const void *src, size_t srclen)
74 {
75 	return (z_uncompress_impl(dst, dstlen, src, srclen, NULL));
76 }
77 
78 /*
79  * Variant of z_uncompress which uses the KM_SLEEP allocator so callers
80  * will block waiting for memory rather than failing immediately.  This is
81  * intended for callers (such as ZFS read-path) that expect to wait for
82  * memory instead of returning an error.
83  */
84 int
85 z_uncompress_sleep(void *dst, size_t *dstlen, const void *src, size_t srclen)
86 {
87 	return (z_uncompress_impl(dst, dstlen, src, srclen, zcalloc_sleep));
88 }
89 
90 int
91 z_compress_level(void *dst, size_t *dstlen, const void *src, size_t srclen,
92     int level)
93 {
94 
95 	z_stream zs;
96 	int err;
97 
98 	bzero(&zs, sizeof (zs));
99 	zs.next_in = (uchar_t *)src;
100 	zs.avail_in = srclen;
101 	zs.next_out = dst;
102 	zs.avail_out = *dstlen;
103 
104 	if ((err = deflateInit(&zs, level)) != Z_OK)
105 		return (err);
106 
107 	if ((err = deflate(&zs, Z_FINISH)) != Z_STREAM_END) {
108 		(void) deflateEnd(&zs);
109 		return (err == Z_OK ? Z_BUF_ERROR : err);
110 	}
111 
112 	*dstlen = zs.total_out;
113 	return (deflateEnd(&zs));
114 }
115 
116 int
117 z_compress(void *dst, size_t *dstlen, const void *src, size_t srclen)
118 {
119 	return (z_compress_level(dst, dstlen, src, srclen,
120 	    Z_DEFAULT_COMPRESSION));
121 }
122 
123 /*
124  * Convert a zlib error code into a string error message.
125  */
126 const char *
127 z_strerror(int err)
128 {
129 	int i = Z_NEED_DICT - err;
130 
131 	if (i < 0 || i > Z_NEED_DICT - Z_VERSION_ERROR)
132 		return ("unknown error");
133 
134 	return (zError(err));
135 }
136