1 /*
2 BAREOS® - Backup Archiving REcovery Open Sourced
3
4 Copyright (C) 2013-2014 Planets Communications B.V.
5 Copyright (C) 2013-2020 Bareos GmbH & Co. KG
6
7 This program is Free Software; you can redistribute it and/or
8 modify it under the terms of version three of the GNU Affero General Public
9 License as published by the Free Software Foundation, which is
10 listed in the file LICENSE.
11
12 This program is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Affero General Public License for more details.
16
17 You should have received a copy of the GNU Affero General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20 02110-1301, USA.
21 */
22 /*
23 * Marco van Wieringen, June 2013
24 */
25 /**
26 * @file
27 * Storage Daemon plugin that handles automatic deflation/inflation of data.
28 */
29 #include "include/bareos.h"
30 #include "stored/stored.h"
31 #include "stored/device_control_record.h"
32
33 #if defined(HAVE_LIBZ)
34 # include <zlib.h>
35 #endif
36
37 #include "fastlz/fastlzlib.h"
38
39 using namespace storagedaemon;
40
41 #define PLUGIN_LICENSE "Bareos AGPLv3"
42 #define PLUGIN_AUTHOR "Marco van Wieringen"
43 #define PLUGIN_DATE "June 2013"
44 #define PLUGIN_VERSION "1"
45 #define PLUGIN_DESCRIPTION "Auto Xflation Storage Daemon Plugin"
46 #define PLUGIN_USAGE "(No usage yet)"
47
48 #define Dmsg(context, level, ...) \
49 bareos_core_functions->DebugMessage(context, __FILE__, __LINE__, level, \
50 __VA_ARGS__)
51 #define Jmsg(context, type, ...) \
52 bareos_core_functions->JobMessage(context, __FILE__, __LINE__, type, 0, \
53 __VA_ARGS__)
54
55 #define SETTING_YES (char*)"yes"
56 #define SETTING_NO (char*)"no"
57 #define SETTING_UNSET (char*)"unknown"
58
59 #define COMPRESSOR_NAME_GZIP (char*)"GZIP"
60 #define COMPRESSOR_NAME_LZO (char*)"LZO"
61 #define COMPRESSOR_NAME_FZLZ (char*)"FASTLZ"
62 #define COMPRESSOR_NAME_FZ4L (char*)"LZ4"
63 #define COMPRESSOR_NAME_FZ4H (char*)"LZ4HC"
64 #define COMPRESSOR_NAME_UNSET (char*)"unknown"
65
66 /**
67 * Forward referenced functions
68 */
69 static bRC newPlugin(PluginContext* ctx);
70 static bRC freePlugin(PluginContext* ctx);
71 static bRC getPluginValue(PluginContext* ctx, pVariable var, void* value);
72 static bRC setPluginValue(PluginContext* ctx, pVariable var, void* value);
73 static bRC handlePluginEvent(PluginContext* ctx, bSdEvent* event, void* value);
74 static bRC handleJobEnd(PluginContext* ctx);
75 static bRC setup_record_translation(PluginContext* ctx, void* value);
76 static bRC handle_read_translation(PluginContext* ctx, void* value);
77 static bRC handle_write_translation(PluginContext* ctx, void* value);
78
79 static bool SetupAutoDeflation(PluginContext* ctx, DeviceControlRecord* dcr);
80 static bool SetupAutoInflation(PluginContext* ctx, DeviceControlRecord* dcr);
81 static bool AutoDeflateRecord(PluginContext* ctx, DeviceControlRecord* dcr);
82 static bool AutoInflateRecord(PluginContext* ctx, DeviceControlRecord* dcr);
83
84 /**
85 * Is the SD in compatible mode or not.
86 */
87 static bool sd_enabled_compatible = false;
88
89 /**
90 * Pointers to Bareos functions
91 */
92 static CoreFunctions* bareos_core_functions = NULL;
93 static PluginApiDefinition* bareos_plugin_interface_version = NULL;
94
95 static PluginInformation pluginInfo
96 = {sizeof(pluginInfo), SD_PLUGIN_INTERFACE_VERSION,
97 SD_PLUGIN_MAGIC, PLUGIN_LICENSE,
98 PLUGIN_AUTHOR, PLUGIN_DATE,
99 PLUGIN_VERSION, PLUGIN_DESCRIPTION,
100 PLUGIN_USAGE};
101
102 static PluginFunctions pluginFuncs
103 = {sizeof(pluginFuncs), SD_PLUGIN_INTERFACE_VERSION,
104
105 /*
106 * Entry points into plugin
107 */
108 newPlugin, /* new plugin instance */
109 freePlugin, /* free plugin instance */
110 getPluginValue, setPluginValue, handlePluginEvent};
111
112 /**
113 * Plugin private context
114 */
115 struct plugin_ctx {
116 /*
117 * Counters for compression/decompression ratio
118 */
119 uint64_t deflate_bytes_in;
120 uint64_t deflate_bytes_out;
121 uint64_t inflate_bytes_in;
122 uint64_t inflate_bytes_out;
123 };
124
125 static int const debuglevel = 200;
126
127 #ifdef __cplusplus
128 extern "C" {
129 #endif
130
131 /**
132 * loadPlugin() and unloadPlugin() are entry points that are
133 * exported, so Bareos can directly call these two entry points
134 * they are common to all Bareos plugins.
135 *
136 * External entry point called by Bareos to "load the plugin
137 */
loadPlugin(PluginApiDefinition * lbareos_plugin_interface_version,CoreFunctions * lbareos_core_functions,PluginInformation ** plugin_information,PluginFunctions ** plugin_functions)138 bRC loadPlugin(PluginApiDefinition* lbareos_plugin_interface_version,
139 CoreFunctions* lbareos_core_functions,
140 PluginInformation** plugin_information,
141 PluginFunctions** plugin_functions)
142 {
143 bareos_core_functions
144 = lbareos_core_functions; /* set Bareos funct pointers */
145 bareos_plugin_interface_version = lbareos_plugin_interface_version;
146 *plugin_information = &pluginInfo; /* return pointer to our info */
147 *plugin_functions = &pluginFuncs; /* return pointer to our functions */
148
149 /*
150 * Get the current setting of the compatible flag.
151 */
152 bareos_core_functions->getBareosValue(NULL, bsdVarCompatible,
153 (void*)&sd_enabled_compatible);
154
155 return bRC_OK;
156 }
157
158 /**
159 * External entry point to unload the plugin
160 */
unloadPlugin()161 bRC unloadPlugin() { return bRC_OK; }
162
163 #ifdef __cplusplus
164 }
165 #endif
166
167 /**
168 * The following entry points are accessed through the function
169 * pointers we supplied to Bareos. Each plugin type (dir, fd, sd)
170 * has its own set of entry points that the plugin must define.
171 *
172 * Create a new instance of the plugin i.e. allocate our private storage
173 */
newPlugin(PluginContext * ctx)174 static bRC newPlugin(PluginContext* ctx)
175 {
176 int JobId = 0;
177 struct plugin_ctx* p_ctx;
178
179 bareos_core_functions->getBareosValue(ctx, bsdVarJobId, (void*)&JobId);
180 Dmsg(ctx, debuglevel, "autoxflate-sd: newPlugin JobId=%d\n", JobId);
181
182 p_ctx = (struct plugin_ctx*)malloc(sizeof(struct plugin_ctx));
183 if (!p_ctx) { return bRC_Error; }
184
185 memset(p_ctx, 0, sizeof(struct plugin_ctx));
186 ctx->plugin_private_context = (void*)p_ctx; /* set our context pointer */
187
188 /*
189 * Only register plugin events we are interested in.
190 *
191 * bSdEventJobEnd - SD Job finished.
192 * bSdEventSetupRecordTranslation - Setup the buffers for doing record
193 * translation. bSdEventReadRecordTranslation - Perform read-side record
194 * translation. bSdEventWriteRecordTranslation - Perform write-side record
195 * translantion.
196 */
197 bareos_core_functions->registerBareosEvents(
198 ctx, 4, bSdEventJobEnd, bSdEventSetupRecordTranslation,
199 bSdEventReadRecordTranslation, bSdEventWriteRecordTranslation);
200
201 return bRC_OK;
202 }
203
204 /**
205 * Free a plugin instance, i.e. release our private storage
206 */
freePlugin(PluginContext * ctx)207 static bRC freePlugin(PluginContext* ctx)
208 {
209 int JobId = 0;
210 struct plugin_ctx* p_ctx = (struct plugin_ctx*)ctx->plugin_private_context;
211
212 bareos_core_functions->getBareosValue(ctx, bsdVarJobId, (void*)&JobId);
213 Dmsg(ctx, debuglevel, "autoxflate-sd: freePlugin JobId=%d\n", JobId);
214
215 if (!p_ctx) {
216 Dmsg(ctx, debuglevel, "autoxflate-sd: freePlugin JobId=%d\n", JobId);
217 return bRC_Error;
218 }
219
220 if (p_ctx) { free(p_ctx); }
221 ctx->plugin_private_context = NULL;
222
223 return bRC_OK;
224 }
225
226 /**
227 * Return some plugin value (none defined)
228 */
getPluginValue(PluginContext * ctx,pVariable var,void * value)229 static bRC getPluginValue(PluginContext* ctx, pVariable var, void* value)
230 {
231 Dmsg(ctx, debuglevel, "autoxflate-sd: getPluginValue var=%d\n", var);
232
233 return bRC_OK;
234 }
235
236 /**
237 * Set a plugin value (none defined)
238 */
setPluginValue(PluginContext * ctx,pVariable var,void * value)239 static bRC setPluginValue(PluginContext* ctx, pVariable var, void* value)
240 {
241 Dmsg(ctx, debuglevel, "autoxflate-sd: setPluginValue var=%d\n", var);
242
243 return bRC_OK;
244 }
245
246 /**
247 * Handle an event that was generated in Bareos
248 */
handlePluginEvent(PluginContext * ctx,bSdEvent * event,void * value)249 static bRC handlePluginEvent(PluginContext* ctx, bSdEvent* event, void* value)
250 {
251 switch (event->eventType) {
252 case bSdEventSetupRecordTranslation:
253 return setup_record_translation(ctx, value);
254 case bSdEventReadRecordTranslation:
255 return handle_read_translation(ctx, value);
256 case bSdEventWriteRecordTranslation:
257 return handle_write_translation(ctx, value);
258 case bSdEventJobEnd:
259 return handleJobEnd(ctx);
260 default:
261 Dmsg(ctx, debuglevel, "autoxflate-sd: Unknown event %d\n",
262 event->eventType);
263 return bRC_Error;
264 }
265
266 return bRC_OK;
267 }
268
269 /**
270 * At end of job report how inflate/deflate ratio was.
271 */
handleJobEnd(PluginContext * ctx)272 static bRC handleJobEnd(PluginContext* ctx)
273 {
274 struct plugin_ctx* p_ctx = (struct plugin_ctx*)ctx->plugin_private_context;
275
276 if (!p_ctx) { goto bail_out; }
277
278 if (p_ctx->inflate_bytes_in) {
279 Dmsg(ctx, debuglevel, "autoxflate-sd: inflate ratio: %lld/%lld = %0.2f%%\n",
280 p_ctx->inflate_bytes_out, p_ctx->inflate_bytes_in,
281 (p_ctx->inflate_bytes_out * 100.0 / p_ctx->inflate_bytes_in));
282 Jmsg(ctx, M_INFO, _("autoxflate-sd: inflate ratio: %0.2f%%\n"),
283 (p_ctx->inflate_bytes_out * 100.0 / p_ctx->inflate_bytes_in));
284 }
285
286 if (p_ctx->deflate_bytes_in) {
287 Dmsg(ctx, debuglevel,
288 "autoxflate-sd: deflate ratio: %lld/%lld = %0.2f%%\n",
289 p_ctx->deflate_bytes_out, p_ctx->deflate_bytes_in,
290 (p_ctx->deflate_bytes_out * 100.0 / p_ctx->deflate_bytes_in));
291 Jmsg(ctx, M_INFO, _("autoxflate-sd: deflate ratio: %0.2f%%\n"),
292 (p_ctx->deflate_bytes_out * 100.0 / p_ctx->deflate_bytes_in));
293 }
294
295 bail_out:
296 return bRC_OK;
297 }
298
setup_record_translation(PluginContext * ctx,void * value)299 static bRC setup_record_translation(PluginContext* ctx, void* value)
300 {
301 DeviceControlRecord* dcr;
302 bool did_setup = false;
303 const char* inflate_in = SETTING_UNSET;
304 const char* inflate_out = SETTING_UNSET;
305 const char* deflate_in = SETTING_UNSET;
306 const char* deflate_out = SETTING_UNSET;
307
308 /*
309 * Unpack the arguments passed in.
310 */
311 dcr = (DeviceControlRecord*)value;
312 if (!dcr) { return bRC_Error; }
313
314 /*
315 * Give jobmessage info what is configured
316 */
317 switch (dcr->autodeflate) {
318 case AutoXflateMode::IO_DIRECTION_NONE:
319 deflate_in = SETTING_NO;
320 deflate_out = SETTING_NO;
321 break;
322 case AutoXflateMode::IO_DIRECTION_IN:
323 deflate_in = SETTING_YES;
324 deflate_out = SETTING_NO;
325 break;
326 case AutoXflateMode::IO_DIRECTION_OUT:
327 deflate_in = SETTING_NO;
328 deflate_out = SETTING_YES;
329 break;
330 case AutoXflateMode::IO_DIRECTION_INOUT:
331 deflate_in = SETTING_YES;
332 deflate_out = SETTING_YES;
333 break;
334 default:
335 Jmsg(ctx, M_ERROR,
336 _("autoxflate-sd: Unexpected autodeflate setting on %s"),
337 dcr->dev_name);
338 break;
339 }
340
341 switch (dcr->autoinflate) {
342 case AutoXflateMode::IO_DIRECTION_NONE:
343 inflate_in = SETTING_NO;
344 inflate_out = SETTING_NO;
345 break;
346 case AutoXflateMode::IO_DIRECTION_IN:
347 inflate_in = SETTING_YES;
348 inflate_out = SETTING_NO;
349 break;
350 case AutoXflateMode::IO_DIRECTION_OUT:
351 inflate_in = SETTING_NO;
352 inflate_out = SETTING_YES;
353 break;
354 case AutoXflateMode::IO_DIRECTION_INOUT:
355 inflate_in = SETTING_YES;
356 inflate_out = SETTING_YES;
357 break;
358 default:
359 Jmsg(ctx, M_ERROR,
360 _("autoxflate-sd: Unexpected autoinflate setting on %s"),
361 dcr->dev_name);
362 break;
363 }
364
365 /*
366 * Setup auto deflation/inflation of streams when enabled for this device.
367 */
368 switch (dcr->autodeflate) {
369 case AutoXflateMode::IO_DIRECTION_NONE:
370 break;
371 case AutoXflateMode::IO_DIRECTION_OUT:
372 case AutoXflateMode::IO_DIRECTION_INOUT:
373 if (!SetupAutoDeflation(ctx, dcr)) { return bRC_Error; }
374 did_setup = true;
375 break;
376 default:
377 break;
378 }
379
380 switch (dcr->autoinflate) {
381 case AutoXflateMode::IO_DIRECTION_NONE:
382 break;
383 case AutoXflateMode::IO_DIRECTION_OUT:
384 case AutoXflateMode::IO_DIRECTION_INOUT:
385 if (!SetupAutoInflation(ctx, dcr)) { return bRC_Error; }
386 did_setup = true;
387 break;
388 default:
389 break;
390 }
391
392 if (did_setup) {
393 Jmsg(ctx, M_INFO,
394 _("autoxflate-sd: %s OUT:[SD->inflate=%s->deflate=%s->DEV] "
395 "IN:[DEV->inflate=%s->deflate=%s->SD]\n"),
396 dcr->dev_name, inflate_out, deflate_out, inflate_in, deflate_in);
397 }
398
399 return bRC_OK;
400 }
401
handle_read_translation(PluginContext * ctx,void * value)402 static bRC handle_read_translation(PluginContext* ctx, void* value)
403 {
404 DeviceControlRecord* dcr;
405 bool swap_record = false;
406
407 /*
408 * Unpack the arguments passed in.
409 */
410 dcr = (DeviceControlRecord*)value;
411 if (!dcr) { return bRC_Error; }
412
413 /*
414 * See if we need to perform auto deflation/inflation of streams.
415 */
416 switch (dcr->autoinflate) {
417 case AutoXflateMode::IO_DIRECTION_IN:
418 case AutoXflateMode::IO_DIRECTION_INOUT:
419 swap_record = AutoInflateRecord(ctx, dcr);
420 break;
421 default:
422 break;
423 }
424
425 if (!swap_record) {
426 switch (dcr->autodeflate) {
427 case AutoXflateMode::IO_DIRECTION_IN:
428 case AutoXflateMode::IO_DIRECTION_INOUT:
429 swap_record = AutoDeflateRecord(ctx, dcr);
430 break;
431 default:
432 break;
433 }
434 }
435
436 return bRC_OK;
437 }
438
handle_write_translation(PluginContext * ctx,void * value)439 static bRC handle_write_translation(PluginContext* ctx, void* value)
440 {
441 DeviceControlRecord* dcr;
442 bool swap_record = false;
443
444 /*
445 * Unpack the arguments passed in.
446 */
447 dcr = (DeviceControlRecord*)value;
448 if (!dcr) { return bRC_Error; }
449
450 /*
451 * See if we need to perform auto deflation/inflation of streams.
452 */
453 switch (dcr->autoinflate) {
454 case AutoXflateMode::IO_DIRECTION_OUT:
455 case AutoXflateMode::IO_DIRECTION_INOUT:
456 swap_record = AutoInflateRecord(ctx, dcr);
457 break;
458 default:
459 break;
460 }
461
462 if (!swap_record) {
463 switch (dcr->autodeflate) {
464 case AutoXflateMode::IO_DIRECTION_OUT:
465 case AutoXflateMode::IO_DIRECTION_INOUT:
466 swap_record = AutoDeflateRecord(ctx, dcr);
467 break;
468 default:
469 break;
470 }
471 }
472
473 return bRC_OK;
474 }
475
476 /**
477 * Setup deflate for auto deflate of data streams.
478 */
SetupAutoDeflation(PluginContext * ctx,DeviceControlRecord * dcr)479 static bool SetupAutoDeflation(PluginContext* ctx, DeviceControlRecord* dcr)
480 {
481 JobControlRecord* jcr = dcr->jcr;
482 bool retval = false;
483 uint32_t compress_buf_size = 0;
484 const char* compressorname = COMPRESSOR_NAME_UNSET;
485
486 if (jcr->buf_size == 0) { jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE; }
487
488 if (!SetupCompressionBuffers(jcr, sd_enabled_compatible,
489 dcr->device_resource->autodeflate_algorithm,
490 &compress_buf_size)) {
491 goto bail_out;
492 }
493
494 /*
495 * See if we need to create a new compression buffer or make sure the existing
496 * is big enough.
497 */
498 if (!jcr->compress.deflate_buffer) {
499 jcr->compress.deflate_buffer = GetMemory(compress_buf_size);
500 jcr->compress.deflate_buffer_size = compress_buf_size;
501 } else {
502 if (compress_buf_size > jcr->compress.deflate_buffer_size) {
503 jcr->compress.deflate_buffer
504 = ReallocPoolMemory(jcr->compress.deflate_buffer, compress_buf_size);
505 jcr->compress.deflate_buffer_size = compress_buf_size;
506 }
507 }
508
509 switch (dcr->device_resource->autodeflate_algorithm) {
510 #if defined(HAVE_LIBZ)
511 case COMPRESS_GZIP: {
512 compressorname = COMPRESSOR_NAME_GZIP;
513 int zstat;
514 z_stream* pZlibStream;
515
516 pZlibStream = (z_stream*)jcr->compress.workset.pZLIB;
517 if ((zstat
518 = deflateParams(pZlibStream, dcr->device_resource->autodeflate_level,
519 Z_DEFAULT_STRATEGY))
520 != Z_OK) {
521 Jmsg(ctx, M_FATAL,
522 _("autoxflate-sd: Compression deflateParams error: %d\n"), zstat);
523 jcr->setJobStatus(JS_ErrorTerminated);
524 goto bail_out;
525 }
526 break;
527 }
528 #endif
529 #if defined(HAVE_LZO)
530 case COMPRESS_LZO1X:
531 compressorname = COMPRESSOR_NAME_LZO;
532 break;
533 #endif
534 case COMPRESS_FZFZ:
535 compressorname = COMPRESSOR_NAME_FZLZ;
536 case COMPRESS_FZ4L:
537 compressorname = COMPRESSOR_NAME_FZ4L;
538 case COMPRESS_FZ4H: {
539 compressorname = COMPRESSOR_NAME_FZ4H;
540 int zstat;
541 zfast_stream* pZfastStream;
542 zfast_stream_compressor compressor = COMPRESSOR_FASTLZ;
543
544 switch (dcr->device_resource->autodeflate_algorithm) {
545 case COMPRESS_FZ4L:
546 case COMPRESS_FZ4H:
547 compressor = COMPRESSOR_LZ4;
548 break;
549 }
550
551 pZfastStream = (zfast_stream*)jcr->compress.workset.pZFAST;
552 if ((zstat = fastlzlibSetCompressor(pZfastStream, compressor)) != Z_OK) {
553 Jmsg(ctx, M_FATAL,
554 _("autoxflate-sd: Compression fastlzlibSetCompressor error: %d\n"),
555 zstat);
556 jcr->setJobStatus(JS_ErrorTerminated);
557 goto bail_out;
558 }
559 break;
560 }
561 default:
562 break;
563 }
564
565 Jmsg(ctx, M_INFO, _("autoxflate-sd: Compressor on device %s is %s\n"),
566 dcr->dev_name, compressorname);
567 retval = true;
568
569 bail_out:
570 return retval;
571 }
572
573 /**
574 * Setup inflation for auto inflation of data streams.
575 */
SetupAutoInflation(PluginContext * ctx,DeviceControlRecord * dcr)576 static bool SetupAutoInflation(PluginContext* ctx, DeviceControlRecord* dcr)
577 {
578 JobControlRecord* jcr = dcr->jcr;
579 uint32_t decompress_buf_size;
580
581 if (jcr->buf_size == 0) { jcr->buf_size = DEFAULT_NETWORK_BUFFER_SIZE; }
582
583 SetupDecompressionBuffers(jcr, &decompress_buf_size);
584 if (decompress_buf_size > 0) {
585 /*
586 * See if we need to create a new compression buffer or make sure the
587 * existing is big enough.
588 */
589 if (!jcr->compress.inflate_buffer) {
590 jcr->compress.inflate_buffer = GetMemory(decompress_buf_size);
591 jcr->compress.inflate_buffer_size = decompress_buf_size;
592 } else {
593 if (decompress_buf_size > jcr->compress.inflate_buffer_size) {
594 jcr->compress.inflate_buffer = ReallocPoolMemory(
595 jcr->compress.inflate_buffer, decompress_buf_size);
596 jcr->compress.inflate_buffer_size = decompress_buf_size;
597 }
598 }
599 } else {
600 return false;
601 }
602
603 return true;
604 }
605
606 /**
607 * Perform automatic compression of certain stream types when enabled in the
608 * config.
609 */
AutoDeflateRecord(PluginContext * ctx,DeviceControlRecord * dcr)610 static bool AutoDeflateRecord(PluginContext* ctx, DeviceControlRecord* dcr)
611 {
612 ser_declare;
613 bool retval = false;
614 comp_stream_header ch;
615 DeviceRecord *rec, *nrec;
616 struct plugin_ctx* p_ctx;
617 unsigned char* data = NULL;
618 bool intermediate_value = false;
619 unsigned int max_compression_length = 0;
620
621 p_ctx = (struct plugin_ctx*)ctx->plugin_private_context;
622 if (!p_ctx) { goto bail_out; }
623
624 /*
625 * See what our starting point is. When dcr->after_rec is set we already have
626 * a translated record by another SD plugin. Then we use that translated
627 * record as the starting point otherwise we start at dcr->before_rec. When an
628 * earlier translation already happened we can free that record when we have a
629 * success full translation here as that record is of no use anymore.
630 */
631 if (dcr->after_rec) {
632 rec = dcr->after_rec;
633 intermediate_value = true;
634 } else {
635 rec = dcr->before_rec;
636 }
637
638 /*
639 * We only do autocompression for the following stream types:
640 *
641 * - STREAM_FILE_DATA
642 * - STREAM_WIN32_DATA
643 * - STREAM_SPARSE_DATA
644 */
645 switch (rec->maskedStream) {
646 case STREAM_FILE_DATA:
647 case STREAM_WIN32_DATA:
648 case STREAM_SPARSE_DATA:
649 break;
650 default:
651 goto bail_out;
652 }
653
654 /*
655 * Clone the data from the original DeviceRecord to the converted one.
656 * As we use the compression buffers for the data we need a new
657 * DeviceRecord without a new memory buffer so we call new_record here
658 * with the with_data boolean set explicitly to false.
659 */
660 nrec = bareos_core_functions->new_record(false);
661 bareos_core_functions->CopyRecordState(nrec, rec);
662
663 /*
664 * Setup the converted DeviceRecord to point with its data buffer to the
665 * compression buffer.
666 */
667 nrec->data = dcr->jcr->compress.deflate_buffer;
668 switch (rec->maskedStream) {
669 case STREAM_FILE_DATA:
670 case STREAM_WIN32_DATA:
671 data = (unsigned char*)nrec->data + sizeof(comp_stream_header);
672 max_compression_length
673 = dcr->jcr->compress.deflate_buffer_size - sizeof(comp_stream_header);
674 break;
675 case STREAM_SPARSE_DATA:
676 data = (unsigned char*)nrec->data + OFFSET_FADDR_SIZE
677 + sizeof(comp_stream_header);
678 max_compression_length = dcr->jcr->compress.deflate_buffer_size
679 - OFFSET_FADDR_SIZE - sizeof(comp_stream_header);
680 break;
681 }
682
683 /*
684 * Compress the data using the configured compression algorithm.
685 */
686 if (!CompressData(dcr->jcr, dcr->device_resource->autodeflate_algorithm,
687 rec->data, rec->data_len, data, max_compression_length,
688 &nrec->data_len)) {
689 bareos_core_functions->FreeRecord(nrec);
690 goto bail_out;
691 }
692
693 /*
694 * Map the streams.
695 */
696 switch (rec->maskedStream) {
697 case STREAM_FILE_DATA:
698 nrec->Stream = STREAM_COMPRESSED_DATA;
699 nrec->maskedStream = STREAM_COMPRESSED_DATA;
700 break;
701 case STREAM_WIN32_DATA:
702 nrec->Stream = STREAM_WIN32_COMPRESSED_DATA;
703 nrec->maskedStream = STREAM_WIN32_COMPRESSED_DATA;
704 break;
705 case STREAM_SPARSE_DATA:
706 nrec->Stream = STREAM_SPARSE_COMPRESSED_DATA;
707 nrec->maskedStream = STREAM_SPARSE_COMPRESSED_DATA;
708 break;
709 default:
710 break;
711 }
712
713 /*
714 * Generate a compression header.
715 */
716 ch.magic = dcr->device_resource->autodeflate_algorithm;
717 ch.level = dcr->device_resource->autodeflate_level;
718 ch.version = COMP_HEAD_VERSION;
719 ch.size = nrec->data_len;
720
721 switch (nrec->maskedStream) {
722 case STREAM_COMPRESSED_DATA:
723 case STREAM_WIN32_COMPRESSED_DATA:
724 SerBegin(nrec->data, sizeof(comp_stream_header));
725 ser_uint32(ch.magic);
726 ser_uint32(ch.size);
727 ser_uint16(ch.level);
728 ser_uint16(ch.version);
729 SerEnd(nrec->data, sizeof(comp_stream_header));
730 nrec->data_len += sizeof(comp_stream_header);
731 break;
732 case STREAM_SPARSE_COMPRESSED_DATA:
733 /*
734 * Copy the sparse offset from the original.
735 */
736 memcpy(nrec->data, rec->data, OFFSET_FADDR_SIZE);
737 SerBegin(nrec->data + OFFSET_FADDR_SIZE, sizeof(comp_stream_header));
738 ser_uint32(ch.magic);
739 ser_uint32(ch.size);
740 ser_uint16(ch.level);
741 ser_uint16(ch.version);
742 SerEnd(nrec->data + OFFSET_FADDR_SIZE, sizeof(comp_stream_header));
743 nrec->data_len += OFFSET_FADDR_SIZE + sizeof(comp_stream_header);
744 break;
745 }
746
747 Dmsg(ctx, 400,
748 "AutoDeflateRecord: From datastream %d to %d from original size %ld to "
749 "%ld\n",
750 rec->maskedStream, nrec->maskedStream, rec->data_len, nrec->data_len);
751
752 p_ctx->deflate_bytes_in += rec->data_len;
753 p_ctx->deflate_bytes_out += nrec->data_len;
754
755 /*
756 * If the input is just an intermediate value free it now.
757 */
758 if (intermediate_value) { bareos_core_functions->FreeRecord(dcr->after_rec); }
759 dcr->after_rec = nrec;
760 retval = true;
761
762 bail_out:
763 return retval;
764 }
765
766 /**
767 * Inflate (uncompress) the content of a read record and return the data as an
768 * alternative datastream.
769 */
AutoInflateRecord(PluginContext * ctx,DeviceControlRecord * dcr)770 static bool AutoInflateRecord(PluginContext* ctx, DeviceControlRecord* dcr)
771 {
772 DeviceRecord *rec, *nrec;
773 bool retval = false;
774 struct plugin_ctx* p_ctx;
775 bool intermediate_value = false;
776
777 p_ctx = (struct plugin_ctx*)ctx->plugin_private_context;
778 if (!p_ctx) { goto bail_out; }
779
780 /*
781 * See what our starting point is. When dcr->after_rec is set we already have
782 * a translated record by another SD plugin. Then we use that translated
783 * record as the starting point otherwise we start at dcr->before_rec. When an
784 * earlier translation already happened we can free that record when we have a
785 * success full translation here as that record is of no use anymore.
786 */
787 if (dcr->after_rec) {
788 rec = dcr->after_rec;
789 intermediate_value = true;
790 } else {
791 rec = dcr->before_rec;
792 }
793
794 /*
795 * We only do auto inflation for the following stream types:
796 *
797 * - STREAM_COMPRESSED_DATA
798 * - STREAM_WIN32_COMPRESSED_DATA
799 * - STREAM_SPARSE_COMPRESSED_DATA
800 */
801 switch (rec->maskedStream) {
802 case STREAM_COMPRESSED_DATA:
803 case STREAM_WIN32_COMPRESSED_DATA:
804 case STREAM_SPARSE_COMPRESSED_DATA:
805 break;
806 default:
807 goto bail_out;
808 }
809
810 /*
811 * Clone the data from the original DeviceRecord to the converted one.
812 * As we use the compression buffers for the data we need a new
813 * DeviceRecord without a new memory buffer so we call new_record here
814 * with the with_data boolean set explicitly to false.
815 */
816 nrec = bareos_core_functions->new_record(false);
817 bareos_core_functions->CopyRecordState(nrec, rec);
818
819 /*
820 * Setup the converted record to point to the original data.
821 * The DecompressData function will decompress that data and
822 * then update the pointers with the data in the compression buffer
823 * and with the length of the decompressed data.
824 */
825 nrec->data = rec->data;
826 nrec->data_len = rec->data_len;
827
828 if (!DecompressData(dcr->jcr, "Unknown", rec->maskedStream, &nrec->data,
829 &nrec->data_len, true)) {
830 bareos_core_functions->FreeRecord(nrec);
831 goto bail_out;
832 }
833
834 /*
835 * If we succeeded in decompressing the data update the stream type.
836 */
837 switch (rec->maskedStream) {
838 case STREAM_COMPRESSED_DATA:
839 nrec->Stream = STREAM_FILE_DATA;
840 nrec->maskedStream = STREAM_FILE_DATA;
841 break;
842 case STREAM_WIN32_COMPRESSED_DATA:
843 nrec->Stream = STREAM_WIN32_DATA;
844 nrec->maskedStream = STREAM_WIN32_DATA;
845 break;
846 case STREAM_SPARSE_COMPRESSED_DATA:
847 nrec->Stream = STREAM_SPARSE_DATA;
848 nrec->maskedStream = STREAM_SPARSE_DATA;
849 break;
850 default:
851 break;
852 }
853
854 Dmsg(ctx, 400,
855 "AutoInflateRecord: From datastream %d to %d from original size %ld to "
856 "%ld\n",
857 rec->maskedStream, nrec->maskedStream, rec->data_len, nrec->data_len);
858
859 p_ctx->inflate_bytes_in += rec->data_len;
860 p_ctx->inflate_bytes_out += nrec->data_len;
861
862 /*
863 * If the input is just an intermediate value free it now.
864 */
865 if (intermediate_value) { bareos_core_functions->FreeRecord(dcr->after_rec); }
866 dcr->after_rec = nrec;
867 retval = true;
868
869 bail_out:
870 return retval;
871 }
872