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-2019 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 = bctx.jcr->compress.deflate_buffer_size
123                                 - 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))
178               != Z_OK) {
179             Jmsg(bctx.jcr, M_FATAL, 0,
180                  _("Compression deflateParams error: %d\n"), zstat);
181             bctx.jcr->setJobStatus(JS_ErrorTerminated);
182             goto bail_out;
183           }
184         }
185         bctx.ch.level = bctx.ff_pkt->Compress_level;
186         break;
187       }
188 #endif
189 #if defined(HAVE_LZO)
190       case COMPRESS_LZO1X:
191         break;
192 #endif
193       case COMPRESS_FZFZ:
194       case COMPRESS_FZ4L:
195       case COMPRESS_FZ4H: {
196         int zstat;
197         zfast_stream* pZfastStream;
198         zfast_stream_compressor compressor = COMPRESSOR_FASTLZ;
199 
200         /**
201          * Only change fastlz parameters if there is no pending operation.
202          * This should never happen as fastlzlibCompressReset is called after
203          * each fastlzlibCompress.
204          */
205         pZfastStream = (zfast_stream*)bctx.jcr->compress.workset.pZFAST;
206         if (pZfastStream->total_in == 0) {
207           switch (bctx.ff_pkt->Compress_algo) {
208             case COMPRESS_FZ4L:
209             case COMPRESS_FZ4H:
210               compressor = COMPRESSOR_LZ4;
211               break;
212           }
213 
214           if ((zstat = fastlzlibSetCompressor(pZfastStream, compressor))
215               != Z_OK) {
216             Jmsg(bctx.jcr, M_FATAL, 0,
217                  _("Compression fastlzlibSetCompressor error: %d\n"), zstat);
218             bctx.jcr->setJobStatus(JS_ErrorTerminated);
219             goto bail_out;
220           }
221         }
222         bctx.ch.level = bctx.ff_pkt->Compress_level;
223         break;
224       }
225       default:
226         break;
227     }
228   }
229 
230   retval = true;
231 
232 bail_out:
233   return retval;
234 }
235 
236 } /* namespace filedaemon */
237