]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/bextract.c
Backport from BEE
[bacula/bacula] / bacula / src / stored / bextract.c
index c3a86d15805686eb5b2f83a68173531664981c1a..5e2664a672207200c79af37db9704920ea131525 100644 (file)
@@ -1,29 +1,17 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2000-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
 
-   The main author of Bacula is Kern Sibbald, with contributions from
-   many others, a complete list can be found in the file AUTHORS.
-   This program is Free Software; you can redistribute it and/or
-   modify it under the terms of version two of the GNU General Public
-   License as published by the Free Software Foundation and included
-   in the file LICENSE.
+   The main author of Bacula is Kern Sibbald, with contributions from many
+   others, a complete list can be found in the file AUTHORS.
 
-   This program is distributed in the hope that it will be useful, but
-   WITHOUT ANY WARRANTY; without even the implied warranty of
-   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
-   General Public License for more details.
-
-   You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
-   02110-1301, USA.
+   You may use this file and others of this release according to the
+   license defined in the LICENSE file, which includes the Affero General
+   Public License, v3.0 ("AGPLv3") and some additional permissions and
+   terms pursuant to its AGPLv3 Section 7.
 
    Bacula® is a registered trademark of Kern Sibbald.
-   The licensor of Bacula is the Free Software Foundation Europe
-   (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
-   Switzerland, email:ftf@fsfeurope.org.
 */
 /*
  *
  *
  *   Kern E. Sibbald, MM
  *
- *   Version $Id$
- *
  */
 
 #include "bacula.h"
 #include "stored.h"
+#include "ch.h"
 #include "findlib/find.h"
 
+#ifdef HAVE_LZO
+#include <lzo/lzoconf.h>
+#include <lzo/lzo1x.h>
+#endif
+
 extern bool parse_sd_config(CONFIG *config, const char *configfile, int exit_code);
 
 static void do_extract(char *fname);
@@ -68,6 +60,8 @@ static uint64_t fileAddr = 0;         /* file write address */
 
 static CONFIG *config;
 #define CONFIG_FILE "bacula-sd.conf"
+
+void *start_heap;
 char *configfile = NULL;
 STORES *me = NULL;                    /* our Global resource */
 bool forge_on = false;
@@ -105,6 +99,7 @@ int main (int argc, char *argv[])
    bindtextdomain("bacula", LOCALEDIR);
    textdomain("bacula");
    init_stack_dump();
+   lmgr_init_thread();
 
    working_directory = "/tmp";
    my_name_is(argc, argv, "bextract");
@@ -203,6 +198,8 @@ int main (int argc, char *argv[])
 
    config = new_config_parser();
    parse_sd_config(config, configfile, M_ERROR_TERM);
+   setup_me();
+   load_sd_plugins(me->plugin_directory);
 
    if (!got_inc) {                            /* If no include file, */
       add_fname_to_include_list(ff, 0, "/");  /*   include everything */
@@ -233,7 +230,7 @@ static void do_extract(char *devname)
 
    enable_backup_privileges(NULL, 1);
 
-   jcr = setup_jcr("bextract", devname, bsr, VolumeName, 1); /* acquire for read */
+   jcr = setup_jcr("bextract", devname, bsr, VolumeName, SD_READ);
    if (!jcr) {
       exit(1);
    }
@@ -309,7 +306,7 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 
    /* File Attributes stream */
 
-   switch (rec->Stream) {
+   switch (rec->maskedStream) {
    case STREAM_UNIX_ATTRIBUTES:
    case STREAM_UNIX_ATTRIBUTES_EX:
 
@@ -324,18 +321,12 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
          extract = false;
       }
 
-      if (!unpack_attributes_record(jcr, rec->Stream, rec->data, attr)) {
+      if (!unpack_attributes_record(jcr, rec->Stream, rec->data, rec->data_len, attr)) {
          Emsg0(M_ERROR_TERM, 0, _("Cannot continue.\n"));
       }
 
-      if (attr->file_index != rec->FileIndex) {
-         Emsg2(M_ERROR_TERM, 0, _("Record header file index %ld not equal record index %ld\n"),
-            rec->FileIndex, attr->file_index);
-      }
-
       if (file_is_included(ff, attr->fname) && !file_is_excluded(ff, attr->fname)) {
-
-         attr->data_stream = decode_stat(attr->attr, &attr->statp, &attr->LinkFI);
+         attr->data_stream = decode_stat(attr->attr, &attr->statp, sizeof(attr->statp), &attr->LinkFI);
          if (!is_restore_stream_supported(attr->data_stream)) {
             if (!non_support_data++) {
                Jmsg(jcr, M_ERROR, 0, _("%s stream not supported on this Client.\n"),
@@ -375,18 +366,22 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
       }
       break;
 
+   case STREAM_RESTORE_OBJECT:
+      /* nothing to do */
+      break;
+
    /* Data stream and extracting */
    case STREAM_FILE_DATA:
    case STREAM_SPARSE_DATA:
    case STREAM_WIN32_DATA:
 
       if (extract) {
-         if (rec->Stream == STREAM_SPARSE_DATA) {
+         if (rec->maskedStream == STREAM_SPARSE_DATA) {
             ser_declare;
             uint64_t faddr;
-            wbuf = rec->data + SPARSE_FADDR_SIZE;
-            wsize = rec->data_len - SPARSE_FADDR_SIZE;
-            ser_begin(rec->data, SPARSE_FADDR_SIZE);
+            wbuf = rec->data + OFFSET_FADDR_SIZE;
+            wsize = rec->data_len - OFFSET_FADDR_SIZE;
+            ser_begin(rec->data, OFFSET_FADDR_SIZE);
             unser_uint64(faddr);
             if (fileAddr != faddr) {
                fileAddr = faddr;
@@ -413,16 +408,16 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
    case STREAM_WIN32_GZIP_DATA:
 #ifdef HAVE_LIBZ
       if (extract) {
-         uLong compress_len;
-         int stat;
+         uLong compress_len = compress_buf_size;
+         int stat = Z_BUF_ERROR;
 
-         if (rec->Stream == STREAM_SPARSE_GZIP_DATA) {
+         if (rec->maskedStream == STREAM_SPARSE_GZIP_DATA) {
             ser_declare;
             uint64_t faddr;
             char ec1[50];
-            wbuf = rec->data + SPARSE_FADDR_SIZE;
-            wsize = rec->data_len - SPARSE_FADDR_SIZE;
-            ser_begin(rec->data, SPARSE_FADDR_SIZE);
+            wbuf = rec->data + OFFSET_FADDR_SIZE;
+            wsize = rec->data_len - OFFSET_FADDR_SIZE;
+            ser_begin(rec->data, OFFSET_FADDR_SIZE);
             unser_uint64(faddr);
             if (fileAddr != faddr) {
                fileAddr = faddr;
@@ -438,9 +433,15 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
             wbuf = rec->data;
             wsize = rec->data_len;
          }
-         compress_len = compress_buf_size;
-         if ((stat=uncompress((Bytef *)compress_buf, &compress_len,
-               (const Bytef *)wbuf, (uLong)wsize) != Z_OK)) {
+
+         while (compress_len < 10000000 && (stat=uncompress((Byte *)compress_buf, &compress_len,
+                                 (const Byte *)wbuf, (uLong)wsize)) == Z_BUF_ERROR) {
+            /* The buffer size is too small, try with a bigger one */
+            compress_len = 2 * compress_len;
+            compress_buf = check_pool_memory_size(compress_buf,
+                                                  compress_len);
+         }
+         if (stat != Z_OK) {
             Emsg1(M_ERROR, 0, _("Uncompression error. ERR=%d\n"), stat);
             extract = false;
             return true;
@@ -462,6 +463,101 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 #endif
       break;
 
+   /* Compressed data stream */
+   case STREAM_COMPRESSED_DATA:
+   case STREAM_SPARSE_COMPRESSED_DATA:
+   case STREAM_WIN32_COMPRESSED_DATA:
+      if (extract) {
+         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
+
+         if (rec->maskedStream == STREAM_SPARSE_COMPRESSED_DATA) {
+            ser_declare;
+            uint64_t faddr;
+            char ec1[50];
+            wbuf = rec->data + OFFSET_FADDR_SIZE;
+            wsize = rec->data_len - OFFSET_FADDR_SIZE;
+            ser_begin(rec->data, OFFSET_FADDR_SIZE);
+            unser_uint64(faddr);
+            if (fileAddr != faddr) {
+               fileAddr = faddr;
+               if (blseek(&bfd, (boffset_t)fileAddr, SEEK_SET) < 0) {
+                  berrno be;
+                  Emsg3(M_ERROR, 0, _("Seek to %s error on %s: ERR=%s\n"),
+                     edit_uint64(fileAddr, ec1), attr->ofname, be.bstrerror());
+                  extract = false;
+                  return true;
+               }
+            }
+         } else {
+            wbuf = rec->data;
+            wsize = rec->data_len;
+         }
+
+         /* read compress header */
+         unser_declare;
+         unser_begin(wbuf, 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) {
+            Emsg1(M_ERROR, 0, _("Compressed header version error. version=0x%x\n"), comp_version);
+            return false;
+         }
+         /* size check */
+         if (comp_len + sizeof(comp_stream_header) != wsize) {
+            Emsg2(M_ERROR, 0, _("Compressed header size error. comp_len=%d, msglen=%d\n"),
+                 comp_len, wsize);
+            return false;
+         }
+
+          switch(comp_magic) {
+#ifdef HAVE_LZO
+            case COMPRESS_LZO1X:
+               compress_len = compress_buf_size;
+               cbuf = (const unsigned char*) wbuf + sizeof(comp_stream_header);
+               real_compress_len = wsize - sizeof(comp_stream_header);
+               Dmsg2(200, "Comp_len=%d msglen=%d\n", compress_len, wsize);
+               while ((r=lzo1x_decompress_safe(cbuf, real_compress_len,
+                                               (unsigned char *)compress_buf, &compress_len, NULL)) == LZO_E_OUTPUT_OVERRUN)
+               {
+
+                  /* The buffer size is too small, try with a bigger one */
+                  compress_len = 2 * compress_len;
+                  compress_buf = check_pool_memory_size(compress_buf,
+                                                  compress_len);
+               }
+               if (r != LZO_E_OK) {
+                  Emsg1(M_ERROR, 0, _("LZO uncompression error. ERR=%d\n"), r);
+                  extract = false;
+                  return true;
+               }
+               Dmsg2(100, "Write uncompressed %d bytes, total before write=%d\n", compress_len, total);
+               store_data(&bfd, compress_buf, compress_len);
+               total += compress_len;
+               fileAddr += compress_len;
+               Dmsg2(100, "Compress len=%d uncompressed=%d\n", rec->data_len, compress_len);
+               break;
+#endif
+            default:
+               Emsg1(M_ERROR, 0, _("Compression algorithm 0x%x found, but not supported!\n"), comp_magic);
+               extract = false;
+               return true;
+         }
+
+      }
+      break;
+
    case STREAM_MD5_DIGEST:
    case STREAM_SHA1_DIGEST:
    case STREAM_SHA256_DIGEST:
@@ -501,13 +597,13 @@ static bool record_cb(DCR *dcr, DEV_RECORD *rec)
 /* Dummies to replace askdir.c */
 bool    dir_find_next_appendable_volume(DCR *dcr) { return 1;}
 bool    dir_update_volume_info(DCR *dcr, bool relabel, bool update_LastWritten) { return 1; }
-bool    dir_create_jobmedia_record(DCR *dcr) { return 1; }
+bool    dir_create_jobmedia_record(DCR *dcr, bool zero) { return 1; }
 bool    dir_ask_sysop_to_create_appendable_volume(DCR *dcr) { return 1; }
 bool    dir_update_file_attributes(DCR *dcr, DEV_RECORD *rec) { return 1;}
 bool    dir_send_job_status(JCR *jcr) {return 1;}
 
 
-bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
+bool dir_ask_sysop_to_mount_volume(DCR *dcr, bool /*writing*/)
 {
    DEVICE *dev = dcr->dev;
    fprintf(stderr, _("Mount Volume \"%s\" on device %s and press return when ready: "),
@@ -520,8 +616,10 @@ bool dir_ask_sysop_to_mount_volume(DCR *dcr, int /*mode*/)
 bool dir_get_volume_info(DCR *dcr, enum get_vol_info_rw  writing)
 {
    Dmsg0(100, "Fake dir_get_volume_info\n");
-   bstrncpy(dcr->VolCatInfo.VolCatName, dcr->VolumeName, sizeof(dcr->VolCatInfo.VolCatName));
+   dcr->setVolCatName(dcr->VolumeName);
+#ifdef BUILD_DVD
    dcr->VolCatInfo.VolCatParts = find_num_dvd_parts(dcr);
-   Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->VolCatInfo.VolCatName, dcr->VolCatInfo.VolCatParts);
+#endif
+   Dmsg2(500, "Vol=%s num_parts=%d\n", dcr->getVolCatName(), dcr->VolCatInfo.VolCatParts);
    return 1;
 }