#include "bacula.h"
#include "filed.h"
+#include "ch.h"
#include "restore.h"
#ifdef HAVE_DARWIN_OS
#else
const bool have_libz = false;
#endif
+#ifdef HAVE_LZO
+const bool have_lzo = true;
+#else
+const bool have_lzo = false;
+#endif
+
static void deallocate_cipher(r_ctx &rctx);
static void deallocate_fork_cipher(r_ctx &rctx);
static bool verify_signature(JCR *jcr, r_ctx &rctx);
int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
- uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx);
-bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags,
+ uint64_t *addr, int flags, int32_t stream, RESTORE_CIPHER_CTX *cipher_ctx);
+bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, int32_t stream,
RESTORE_CIPHER_CTX *cipher_ctx);
/*
char ec1[50]; /* Buffer printing huge values */
uint32_t buf_size; /* client buffer size */
int stat;
- intmax_t rsrc_len = 0; /* Original length of resource fork */
+ int64_t rsrc_len = 0; /* Original length of resource fork */
r_ctx rctx;
ATTR *attr;
/* ***FIXME*** make configurable */
* St Bernard code goes here if implemented -- see end of file
*/
- if (have_libz) {
+ /* use the same buffer size to decompress both gzip and lzo */
+ if (have_libz || have_lzo) {
uint32_t compress_buf_size = jcr->buf_size + 12 + ((jcr->buf_size+999) / 1000) + 100;
jcr->compress_buf = get_memory(compress_buf_size);
jcr->compress_buf_size = compress_buf_size;
}
+#ifdef HAVE_LZO
+ if (lzo_init() != LZO_E_OK) {
+ Jmsg(jcr, M_FATAL, 0, _("LZO init failed\n"));
+ goto bail_out;
+ }
+#endif
+
if (have_crypto) {
rctx.cipher_ctx.buf = get_memory(CRYPTO_CIPHER_MAX_BLOCK_SIZE);
if (have_darwin_os) {
case STREAM_GZIP_DATA:
case STREAM_SPARSE_GZIP_DATA:
case STREAM_WIN32_GZIP_DATA:
+ case STREAM_COMPRESSED_DATA:
+ case STREAM_SPARSE_COMPRESSED_DATA:
+ case STREAM_WIN32_COMPRESSED_DATA:
case STREAM_ENCRYPTED_FILE_DATA:
case STREAM_ENCRYPTED_WIN32_DATA:
case STREAM_ENCRYPTED_FILE_GZIP_DATA:
case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
+ case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
+ case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
/*
* Force an expected, consistent stream type here
*/
|| rctx.prev_stream == STREAM_ENCRYPTED_SESSION_DATA)) {
rctx.flags = 0;
- if (rctx.stream == STREAM_SPARSE_DATA ||
- rctx.stream == STREAM_SPARSE_GZIP_DATA) {
+ if (rctx.stream == STREAM_SPARSE_DATA
+ || rctx.stream == STREAM_SPARSE_COMPRESSED_DATA
+ || rctx.stream == STREAM_SPARSE_GZIP_DATA) {
rctx.flags |= FO_SPARSE;
}
|| rctx.stream == STREAM_SPARSE_GZIP_DATA
|| rctx.stream == STREAM_WIN32_GZIP_DATA
|| rctx.stream == STREAM_ENCRYPTED_FILE_GZIP_DATA
+ || rctx.stream == STREAM_COMPRESSED_DATA
+ || rctx.stream == STREAM_SPARSE_COMPRESSED_DATA
+ || rctx.stream == STREAM_WIN32_COMPRESSED_DATA
+ || rctx.stream == STREAM_ENCRYPTED_FILE_COMPRESSED_DATA
+ || rctx.stream == STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA
|| rctx.stream == STREAM_ENCRYPTED_WIN32_GZIP_DATA) {
- rctx.flags |= FO_GZIP;
+ rctx.flags |= FO_COMPRESS;
+ rctx.comp_stream = rctx.stream;
}
if (rctx.stream == STREAM_ENCRYPTED_FILE_DATA
|| rctx.stream == STREAM_ENCRYPTED_FILE_GZIP_DATA
|| rctx.stream == STREAM_ENCRYPTED_WIN32_DATA
+ || rctx.stream == STREAM_ENCRYPTED_FILE_COMPRESSED_DATA
+ || rctx.stream == STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA
|| rctx.stream == STREAM_ENCRYPTED_WIN32_GZIP_DATA) {
/*
* Set up a decryption context
}
if (extract_data(jcr, &rctx.bfd, sd->msg, sd->msglen, &rctx.fileAddr,
- rctx.flags, &rctx.cipher_ctx) < 0) {
+ rctx.flags, rctx.stream, &rctx.cipher_ctx) < 0) {
rctx.extract = false;
bclose(&rctx.bfd);
continue;
}
if (extract_data(jcr, &rctx.forkbfd, sd->msg, sd->msglen, &rctx.fork_addr, rctx.fork_flags,
- &rctx.fork_cipher_ctx) < 0) {
+ rctx.stream, &rctx.fork_cipher_ctx) < 0) {
rctx.extract = false;
bclose(&rctx.forkbfd);
continue;
return true;
}
-bool decompress_data(JCR *jcr, char **data, uint32_t *length)
+bool decompress_data(JCR *jcr, int32_t stream, char **data, uint32_t *length)
{
-#ifdef HAVE_LIBZ
- uLong compress_len;
- int stat;
char ec1[50]; /* Buffer printing huge values */
- /*
- * NOTE! We only use uLong and Byte because they are
- * needed by the zlib routines, they should not otherwise
- * be used in Bacula.
- */
- compress_len = jcr->compress_buf_size;
- Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
- while ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
- (const Byte *)*data, (uLong)*length)) == Z_BUF_ERROR)
+ Dmsg1(200, "Stream found in decompress_data(): %d\n", stream);
+ if(stream == STREAM_COMPRESSED_DATA || stream == STREAM_SPARSE_COMPRESSED_DATA || stream == STREAM_WIN32_COMPRESSED_DATA
+ || stream == STREAM_ENCRYPTED_FILE_COMPRESSED_DATA || stream == STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA)
{
- /*
- * The buffer size is too small, try with a bigger one
+ uint32_t comp_magic, comp_len;
+ uint16_t comp_level, comp_version;
+#ifdef HAVE_LZO
+ lzo_uint compress_len;
+ const unsigned char *cbuf;
+ int r, real_compress_len;
+#endif
+
+ /* read compress header */
+ unser_declare;
+ unser_begin(*data, sizeof(comp_stream_header));
+ unser_uint32(comp_magic);
+ unser_uint32(comp_len);
+ unser_uint16(comp_level);
+ unser_uint16(comp_version);
+ Dmsg4(200, "Compressed data stream found: magic=0x%x, len=%d, level=%d, ver=0x%x\n", comp_magic, comp_len,
+ comp_level, comp_version);
+
+ /* version check */
+ if (comp_version != COMP_HEAD_VERSION) {
+ Qmsg(jcr, M_ERROR, 0, _("Compressed header version error. version=0x%x\n"), comp_version);
+ return false;
+ }
+ /* size check */
+ if (comp_len + sizeof(comp_stream_header) != *length) {
+ Qmsg(jcr, M_ERROR, 0, _("Compressed header size error. comp_len=%d, msglen=%d\n"),
+ comp_len, *length);
+ return false;
+ }
+ switch(comp_magic) {
+#ifdef HAVE_LZO
+ case COMPRESS_LZO1X:
+ compress_len = jcr->compress_buf_size;
+ cbuf = (const unsigned char*)*data + sizeof(comp_stream_header);
+ real_compress_len = *length - sizeof(comp_stream_header);
+ Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
+ while ((r=lzo1x_decompress_safe(cbuf, real_compress_len,
+ (unsigned char *)jcr->compress_buf, &compress_len, NULL)) == LZO_E_OUTPUT_OVERRUN)
+ {
+ /*
+ * The buffer size is too small, try with a bigger one
+ */
+ compress_len = jcr->compress_buf_size = jcr->compress_buf_size + (jcr->compress_buf_size >> 1);
+ Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
+ jcr->compress_buf = check_pool_memory_size(jcr->compress_buf,
+ compress_len);
+ }
+ if (r != LZO_E_OK) {
+ Qmsg(jcr, M_ERROR, 0, _("LZO uncompression error on file %s. ERR=%d\n"),
+ jcr->last_fname, r);
+ return false;
+ }
+ *data = jcr->compress_buf;
+ *length = compress_len;
+ Dmsg2(200, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
+ return true;
+#endif
+ default:
+ Qmsg(jcr, M_ERROR, 0, _("Compression algorithm 0x%x found, but not supported!\n"), comp_magic);
+ return false;
+ }
+ } else {
+#ifdef HAVE_LIBZ
+ uLong compress_len;
+ int stat;
+
+ /*
+ * NOTE! We only use uLong and Byte because they are
+ * needed by the zlib routines, they should not otherwise
+ * be used in Bacula.
*/
- compress_len = jcr->compress_buf_size = jcr->compress_buf_size + (jcr->compress_buf_size >> 1);
+ compress_len = jcr->compress_buf_size;
Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
- jcr->compress_buf = check_pool_memory_size(jcr->compress_buf,
- compress_len);
- }
- if (stat != Z_OK) {
- Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
- jcr->last_fname, zlib_strerror(stat));
- return false;
- }
- *data = jcr->compress_buf;
- *length = compress_len;
- Dmsg2(200, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
- return true;
+ while ((stat=uncompress((Byte *)jcr->compress_buf, &compress_len,
+ (const Byte *)*data, (uLong)*length)) == Z_BUF_ERROR)
+ {
+ /*
+ * The buffer size is too small, try with a bigger one
+ */
+ compress_len = jcr->compress_buf_size = jcr->compress_buf_size + (jcr->compress_buf_size >> 1);
+ Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, *length);
+ jcr->compress_buf = check_pool_memory_size(jcr->compress_buf,
+ compress_len);
+ }
+ if (stat != Z_OK) {
+ Qmsg(jcr, M_ERROR, 0, _("Uncompression error on file %s. ERR=%s\n"),
+ jcr->last_fname, zlib_strerror(stat));
+ return false;
+ }
+ *data = jcr->compress_buf;
+ *length = compress_len;
+ Dmsg2(200, "Write uncompressed %d bytes, total before write=%s\n", compress_len, edit_uint64(jcr->JobBytes, ec1));
+ return true;
#else
- Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
- return false;
+ Qmsg(jcr, M_ERROR, 0, _("GZIP data stream found, but GZIP not configured!\n"));
+ return false;
#endif
+ }
}
static void unser_crypto_packet_len(RESTORE_CIPHER_CTX *ctx)
* Return value is the number of bytes written, or -1 on errors.
*/
int32_t extract_data(JCR *jcr, BFILE *bfd, POOLMEM *buf, int32_t buflen,
- uint64_t *addr, int flags, RESTORE_CIPHER_CTX *cipher_ctx)
+ uint64_t *addr, int flags, int32_t stream, RESTORE_CIPHER_CTX *cipher_ctx)
{
char *wbuf; /* write buffer */
uint32_t wsize; /* write size */
}
}
- if (flags & FO_GZIP) {
- if (!decompress_data(jcr, &wbuf, &wsize)) {
+ if (flags & FO_COMPRESS) {
+ if (!decompress_data(jcr, stream, &wbuf, &wsize)) {
goto bail_out;
}
}
* writing it to bfd.
* Return value is true on success, false on failure.
*/
-bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags,
+bool flush_cipher(JCR *jcr, BFILE *bfd, uint64_t *addr, int flags, int32_t stream,
RESTORE_CIPHER_CTX *cipher_ctx)
{
uint32_t decrypted_len = 0;
}
}
- if (flags & FO_GZIP) {
- if (!decompress_data(jcr, &wbuf, &wsize)) {
+ if (flags & FO_COMPRESS) {
+ if (!decompress_data(jcr, stream, &wbuf, &wsize)) {
return false;
}
}
* Flush and deallocate previous stream's cipher context
*/
if (rctx.cipher_ctx.cipher) {
- flush_cipher(rctx.jcr, &rctx.bfd, &rctx.fileAddr, rctx.flags, &rctx.cipher_ctx);
+ flush_cipher(rctx.jcr, &rctx.bfd, &rctx.fileAddr, rctx.flags, rctx.comp_stream, &rctx.cipher_ctx);
crypto_cipher_free(rctx.cipher_ctx.cipher);
rctx.cipher_ctx.cipher = NULL;
}
* Flush and deallocate previous stream's fork cipher context
*/
if (rctx.fork_cipher_ctx.cipher) {
- flush_cipher(rctx.jcr, &rctx.forkbfd, &rctx.fork_addr, rctx.fork_flags, &rctx.fork_cipher_ctx);
+ flush_cipher(rctx.jcr, &rctx.forkbfd, &rctx.fork_addr, rctx.fork_flags, rctx.comp_stream, &rctx.fork_cipher_ctx);
crypto_cipher_free(rctx.fork_cipher_ctx.cipher);
rctx.fork_cipher_ctx.cipher = NULL;
}