1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2000-2011 Free Software Foundation Europe e.V.
5 Copyright (C) 2011-2012 Planets Communications B.V.
6 Copyright (C) 2013-2016 Bareos GmbH & Co. KG
7
8 This program is Free Software; you can redistribute it and/or
9 modify it under the terms of version three of the GNU Affero General Public
10 License as published by the Free Software Foundation and included
11 in the file LICENSE.
12
13 This program is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Affero General Public License for more details.
17
18 You should have received a copy of the GNU Affero General Public License
19 along with this program; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21 02110-1301, USA.
22 */
23 /*
24 * Kern Sibbald, March MM
25 * Extracted from other source files by Marco van Wieringen, June 2011
26 */
27 /**
28 * @file
29 * Functions to handle compression/decompression of data.
30 */
31
32 #include "include/bareos.h"
33 #include "filed/filed.h"
34 #include "filed/filed_globals.h"
35 #include "filed/jcr_private.h"
36
37 #if defined(HAVE_LIBZ)
38 #include <zlib.h>
39 #endif
40
41 #include "fastlz/fastlzlib.h"
42
43 namespace filedaemon {
44
45 /**
46 * For compression we enable all used compressors in the fileset.
47 */
AdjustCompressionBuffers(JobControlRecord * jcr)48 bool AdjustCompressionBuffers(JobControlRecord* jcr)
49 {
50 findFILESET* fileset = jcr->impl->ff->fileset;
51 uint32_t compress_buf_size = 0;
52
53 if (fileset) {
54 int i, j;
55
56 for (i = 0; i < fileset->include_list.size(); i++) {
57 findIncludeExcludeItem* incexe =
58 (findIncludeExcludeItem*)fileset->include_list.get(i);
59 for (j = 0; j < incexe->opts_list.size(); j++) {
60 findFOPTS* fo = (findFOPTS*)incexe->opts_list.get(j);
61
62 if (!SetupCompressionBuffers(jcr, me->compatible, fo->Compress_algo,
63 &compress_buf_size)) {
64 return false;
65 }
66 }
67 }
68
69 if (compress_buf_size > 0) {
70 jcr->compress.deflate_buffer = GetMemory(compress_buf_size);
71 jcr->compress.deflate_buffer_size = compress_buf_size;
72 }
73 }
74
75 return true;
76 }
77
78 /**
79 * For decompression we use the same decompression buffer for each algorithm.
80 */
AdjustDecompressionBuffers(JobControlRecord * jcr)81 bool AdjustDecompressionBuffers(JobControlRecord* jcr)
82 {
83 uint32_t decompress_buf_size;
84
85 SetupDecompressionBuffers(jcr, &decompress_buf_size);
86
87 if (decompress_buf_size > 0) {
88 jcr->compress.inflate_buffer = GetMemory(decompress_buf_size);
89 jcr->compress.inflate_buffer_size = decompress_buf_size;
90 }
91
92 return true;
93 }
94
SetupCompressionContext(b_ctx & bctx)95 bool SetupCompressionContext(b_ctx& bctx)
96 {
97 bool retval = false;
98
99 if (BitIsSet(FO_COMPRESS, bctx.ff_pkt->flags)) {
100 /*
101 * See if we need to be compatible with the old GZIP stream encoding.
102 */
103 if (!me->compatible || bctx.ff_pkt->Compress_algo != COMPRESS_GZIP) {
104 memset(&bctx.ch, 0, sizeof(comp_stream_header));
105
106 /*
107 * Calculate buffer offsets.
108 */
109 if (BitIsSet(FO_SPARSE, bctx.ff_pkt->flags) ||
110 BitIsSet(FO_OFFSETS, bctx.ff_pkt->flags)) {
111 bctx.chead =
112 (uint8_t*)bctx.jcr->compress.deflate_buffer + OFFSET_FADDR_SIZE;
113 bctx.cbuf = (uint8_t*)bctx.jcr->compress.deflate_buffer +
114 OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
115 bctx.max_compress_len =
116 bctx.jcr->compress.deflate_buffer_size -
117 (sizeof(comp_stream_header) + OFFSET_FADDR_SIZE);
118 } else {
119 bctx.chead = (uint8_t*)bctx.jcr->compress.deflate_buffer;
120 bctx.cbuf = (uint8_t*)bctx.jcr->compress.deflate_buffer +
121 sizeof(comp_stream_header);
122 bctx.max_compress_len =
123 bctx.jcr->compress.deflate_buffer_size - sizeof(comp_stream_header);
124 }
125
126 bctx.wbuf =
127 bctx.jcr->compress.deflate_buffer; /* compressed output here */
128 bctx.cipher_input =
129 (uint8_t*)
130 bctx.jcr->compress.deflate_buffer; /* encrypt compressed data */
131 bctx.ch.magic = bctx.ff_pkt->Compress_algo;
132 bctx.ch.version = COMP_HEAD_VERSION;
133 } else {
134 /*
135 * Calculate buffer offsets.
136 */
137 bctx.chead = NULL;
138 if (BitIsSet(FO_SPARSE, bctx.ff_pkt->flags) ||
139 BitIsSet(FO_OFFSETS, bctx.ff_pkt->flags)) {
140 bctx.cbuf =
141 (uint8_t*)bctx.jcr->compress.deflate_buffer + OFFSET_FADDR_SIZE;
142 bctx.max_compress_len =
143 bctx.jcr->compress.deflate_buffer_size - OFFSET_FADDR_SIZE;
144 } else {
145 bctx.cbuf = (uint8_t*)bctx.jcr->compress.deflate_buffer;
146 bctx.max_compress_len = bctx.jcr->compress.deflate_buffer_size;
147 }
148 bctx.wbuf =
149 bctx.jcr->compress.deflate_buffer; /* compressed output here */
150 bctx.cipher_input =
151 (uint8_t*)
152 bctx.jcr->compress.deflate_buffer; /* encrypt compressed data */
153 }
154
155 /*
156 * Do compression specific actions and set the magic, header version and
157 * compression level.
158 */
159 switch (bctx.ff_pkt->Compress_algo) {
160 #if defined(HAVE_LIBZ)
161 case COMPRESS_GZIP: {
162 z_stream* pZlibStream;
163
164 /**
165 * Only change zlib parameters if there is no pending operation.
166 * This should never happen as deflateReset is called after each
167 * deflate.
168 */
169 pZlibStream = (z_stream*)bctx.jcr->compress.workset.pZLIB;
170 if (pZlibStream->total_in == 0) {
171 int zstat;
172
173 /*
174 * Set gzip compression level - must be done per file
175 */
176 if ((zstat = deflateParams(pZlibStream, bctx.ff_pkt->Compress_level,
177 Z_DEFAULT_STRATEGY)) != Z_OK) {
178 Jmsg(bctx.jcr, M_FATAL, 0,
179 _("Compression deflateParams error: %d\n"), zstat);
180 bctx.jcr->setJobStatus(JS_ErrorTerminated);
181 goto bail_out;
182 }
183 }
184 bctx.ch.level = bctx.ff_pkt->Compress_level;
185 break;
186 }
187 #endif
188 #if defined(HAVE_LZO)
189 case COMPRESS_LZO1X:
190 break;
191 #endif
192 case COMPRESS_FZFZ:
193 case COMPRESS_FZ4L:
194 case COMPRESS_FZ4H: {
195 int zstat;
196 zfast_stream* pZfastStream;
197 zfast_stream_compressor compressor = COMPRESSOR_FASTLZ;
198
199 /**
200 * Only change fastlz parameters if there is no pending operation.
201 * This should never happen as fastlzlibCompressReset is called after
202 * each fastlzlibCompress.
203 */
204 pZfastStream = (zfast_stream*)bctx.jcr->compress.workset.pZFAST;
205 if (pZfastStream->total_in == 0) {
206 switch (bctx.ff_pkt->Compress_algo) {
207 case COMPRESS_FZ4L:
208 case COMPRESS_FZ4H:
209 compressor = COMPRESSOR_LZ4;
210 break;
211 }
212
213 if ((zstat = fastlzlibSetCompressor(pZfastStream, compressor)) !=
214 Z_OK) {
215 Jmsg(bctx.jcr, M_FATAL, 0,
216 _("Compression fastlzlibSetCompressor error: %d\n"), zstat);
217 bctx.jcr->setJobStatus(JS_ErrorTerminated);
218 goto bail_out;
219 }
220 }
221 bctx.ch.level = bctx.ff_pkt->Compress_level;
222 break;
223 }
224 default:
225 break;
226 }
227 }
228
229 retval = true;
230
231 bail_out:
232 return retval;
233 }
234
235 } /* namespace filedaemon */
236