]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/block.c
Allow plugin to skip restore if problem
[bacula/bacula] / bacula / src / stored / block.c
index 7ac0491eab15fbdab24b85577068b0cabd60bb96..8bde1b609d5ee9f161cffffb217fb155b8d5a059 100644 (file)
@@ -1,12 +1,12 @@
 /*
    Bacula® - The Network Backup Solution
 
-   Copyright (C) 2001-2008 Free Software Foundation Europe e.V.
+   Copyright (C) 2001-2010 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
+   modify it under the terms of version three of the GNU Affero General Public
    License as published by the Free Software Foundation and included
    in the file LICENSE.
 
    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
+   You should have received a copy of the GNU Affero 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.
 
-   Bacula® is a registered trademark of John Walker.
+   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.
@@ -32,8 +32,6 @@
  *              Kern Sibbald, March MMI
  *                 added BB02 format October MMII
  *
- *   Version $Id$
- *
  */
 
 
@@ -189,7 +187,7 @@ void empty_block(DEV_BLOCK *block)
  * in the buffer should have already been reserved by
  * init_block.
  */
-void ser_block_header(DEV_BLOCK *block)
+static void ser_block_header(DEV_BLOCK *block, bool do_checksum)
 {
    ser_declare;
    uint32_t CheckSum = 0;
@@ -207,8 +205,10 @@ void ser_block_header(DEV_BLOCK *block)
    }
 
    /* Checksum whole block except for the checksum */
-   CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
-                 block_len-BLKHDR_CS_LENGTH);
+   if (do_checksum) {
+      CheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
+                    block_len-BLKHDR_CS_LENGTH);
+   }
    Dmsg1(1390, "ser_bloc_header: checksum=%x\n", CheckSum);
    ser_begin(block->buf, BLKHDR2_LENGTH);
    ser_uint32(CheckSum);              /* now add checksum to block header */
@@ -307,7 +307,7 @@ static bool unser_block_header(JCR *jcr, DEVICE *dev, DEV_BLOCK *block)
    block->BlockNumber = BlockNumber;
    Dmsg3(390, "Read binbuf = %d %d block_len=%d\n", block->binbuf,
       bhl, block_len);
-   if (block_len <= block->read_len) {
+   if (block_len <= block->read_len && dev->do_checksum()) {
       BlockCheckSum = bcrc32((uint8_t *)block->buf+BLKHDR_CS_LENGTH,
                          block_len-BLKHDR_CS_LENGTH);
       if (BlockCheckSum != CheckSum) {
@@ -365,8 +365,8 @@ bool write_block_to_device(DCR *dcr)
       /* Create a jobmedia record for this job */
       if (!dir_create_jobmedia_record(dcr)) {
          dev->dev_errno = EIO;
-         Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
-            dcr->VolCatInfo.VolCatName, jcr->Job);
+         Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+            dcr->getVolCatName(), jcr->Job);
          set_new_volume_parameters(dcr);
          stat = false;
          goto bail_out;
@@ -380,7 +380,7 @@ bool write_block_to_device(DCR *dcr)
    }
 
    if (!write_block_to_dev(dcr)) {
-       if (job_canceled(jcr) || jcr->JobType == JT_SYSTEM) {
+       if (job_canceled(jcr) || jcr->getJobType() == JT_SYSTEM) {
           stat = false;
        } else {
           stat = fixup_device_block_write_error(dcr);
@@ -415,25 +415,34 @@ bool write_block_to_dev(DCR *dcr)
    empty_block(block);
    return true;
 #endif
+   if (job_canceled(jcr)) {
+      return false;
+   }
+
    ASSERT(block->binbuf == ((uint32_t) (block->bufp - block->buf)));
-   ASSERT(dev->is_open());
+
+   wlen = block->binbuf;
+   if (wlen <= WRITE_BLKHDR_LENGTH) {  /* Does block have data in it? */
+      Dmsg0(100, "return write_block_to_dev no data to write\n");
+      return true;
+   }
 
    /* dump_block(block, "before write"); */
    if (dev->at_weot()) {
       Dmsg0(100, "return write_block_to_dev with ST_WEOT\n");
       dev->dev_errno = ENOSPC;
-      Jmsg(jcr, M_FATAL, 0,  _("Cannot write block. Device at EOM.\n"));
+      Jmsg1(jcr, M_FATAL, 0,  _("Cannot write block. Device at EOM. dev=%s\n"), dev->print_name());
       return false;
    }
    if (!dev->can_append()) {
       dev->dev_errno = EIO;
-      Jmsg(jcr, M_FATAL, 0, _("Attempt to write on read-only Volume.\n"));
+      Jmsg1(jcr, M_FATAL, 0, _("Attempt to write on read-only Volume. dev=%s\n"), dev->print_name());
       return false;
    }
-   wlen = block->binbuf;
-   if (wlen <= WRITE_BLKHDR_LENGTH) {  /* Does block have data in it? */
-      Dmsg0(100, "return write_block_to_dev no data to write\n");
-      return true;
+
+   if (!dev->is_open()) {
+      Jmsg1(jcr, M_FATAL, 0, _("Attempt to write on closed device=%s\n"), dev->print_name());
+      return false;
    }
    /*
     * Clear to the end of the buffer if it is not full,
@@ -463,7 +472,7 @@ bool write_block_to_dev(DCR *dcr)
       }
    }
 
-   ser_block_header(block);
+   ser_block_header(block, dev->do_checksum());
 
    /* Limit maximum Volume size to value specified by user */
    hit_max1 = (dev->max_volume_size > 0) &&
@@ -572,7 +581,7 @@ bool write_block_to_dev(DCR *dcr)
       }
       if (dev->dev_errno == ENOSPC) {
          Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s. Write of %u bytes got %d.\n"),
-            dev->VolCatInfo.VolCatName,
+            dev->getVolCatName(),
             dev->file, dev->block_num, dev->print_name(), wlen, stat);
       }
       if (debug_level >= 100) {
@@ -689,15 +698,17 @@ static void reread_last_block(DCR *dcr)
              * If we wrote block and the block numbers don't agree
              *  we have a possible problem.
              */
-#ifdef xxx
-            if (lblock->VolSessionId == block->VolSessionId &&
-                lblock->VolSessionTime == block->VolSessionTime &&
-                lblock->BlockNumber+1 != block->BlockNumber) {
-#endif
             if (lblock->BlockNumber != dev->LastBlock) {
-               Jmsg(jcr, M_ERROR, 0, _(
+                if (dev->LastBlock > (lblock->BlockNumber + 1)) {
+                   Jmsg(jcr, M_FATAL, 0, _(
+"Re-read of last block: block numbers differ by more than one.\n"
+"Probable tape misconfiguration and data loss. Read block=%u Want block=%u.\n"),
+                       lblock->BlockNumber, dev->LastBlock);
+                 } else {
+                   Jmsg(jcr, M_ERROR, 0, _(
 "Re-read of last block OK, but block numbers differ. Read block=%u Want block=%u.\n"),
-                    lblock->BlockNumber, dev->LastBlock);
+                       lblock->BlockNumber, dev->LastBlock);
+                 }
             } else {
                Jmsg(jcr, M_INFO, 0, _("Re-read of last block succeeded.\n"));
             }
@@ -724,10 +735,9 @@ static bool terminate_writing_volume(DCR *dcr)
    if (!dir_create_jobmedia_record(dcr)) {
       Dmsg0(190, "Error from create JobMedia\n");
       dev->dev_errno = EIO;
-       Jmsg(dcr->jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
-            dcr->VolCatInfo.VolCatName, dcr->jcr->Job);
+       Jmsg2(dcr->jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+            dcr->getVolCatName(), dcr->jcr->Job);
        ok = false;
-       goto bail_out;
    }
    dcr->block->write_failed = true;
    if (!dev->weof(1)) {         /* end the tape */
@@ -780,7 +790,6 @@ static bool terminate_writing_volume(DCR *dcr)
       Jmsg(dcr->jcr, M_ERROR, 0, "%s", dev->errmsg);
    }
 
-bail_out:
    dev->set_ateot();                  /* no more writing this tape */
    Dmsg1(50, "*** Leave terminate_writing_volume -- %s\n", ok?"OK":"ERROR");
    return ok;
@@ -800,8 +809,8 @@ static bool do_new_file_bookkeeping(DCR *dcr)
    if (!dir_create_jobmedia_record(dcr)) {
       Dmsg0(190, "Error from create_job_media.\n");
       dev->dev_errno = EIO;
-      Jmsg(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
-           dcr->VolCatInfo.VolCatName, jcr->Job);
+      Jmsg2(jcr, M_FATAL, 0, _("Could not create JobMedia record for Volume=\"%s\" Job=%s\n"),
+           dcr->getVolCatName(), jcr->Job);
       terminate_writing_volume(dcr);
       dev->dev_errno = EIO;
       return false;
@@ -879,7 +888,7 @@ static bool do_dvd_size_checks(DCR *dcr)
       Dmsg1(100, "Cannot get free space on the device ERR=%s.\n", dev->errmsg);
       Jmsg(jcr, M_FATAL, 0, _("End of Volume \"%s\" at %u:%u on device %s "
          "(part_size=%s, free_space=%s, free_space_errno=%d, errmsg=%s).\n"),
-           dev->VolCatInfo.VolCatName,
+           dev->getVolCatName(),
            dev->file, dev->block_num, dev->print_name(),
            edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2),
            dev->free_space_errno, dev->errmsg);
@@ -892,7 +901,7 @@ static bool do_dvd_size_checks(DCR *dcr)
       Dmsg0(100, "==== Just enough free space on the device to write the current part...\n");
       Jmsg(jcr, M_INFO, 0, _("End of Volume \"%s\" at %u:%u on device %s "
          "(part_size=%s, free_space=%s, free_space_errno=%d).\n"),
-            dev->VolCatInfo.VolCatName,
+            dev->getVolCatName(),
             dev->file, dev->block_num, dev->print_name(),
             edit_uint64_with_commas(dev->part_size, ed1), edit_uint64_with_commas(dev->free_space, ed2),
             dev->free_space_errno);
@@ -935,7 +944,9 @@ bool read_block_from_dev(DCR *dcr, bool check_block_numbers)
    DEVICE *dev = dcr->dev;
    DEV_BLOCK *block = dcr->block;
 
-   ASSERT(dev->is_open());
+   if (job_canceled(jcr)) {
+      return false;
+   }
    
    if (dev->at_eot()) {
       return false;
@@ -943,6 +954,9 @@ bool read_block_from_dev(DCR *dcr, bool check_block_numbers)
    looping = 0;
    Dmsg1(250, "Full read in read_block_from_device() len=%d\n",
          block->buf_len);
+
+// ASSERT(dev->is_open());
+
 reread:
    if (looping > 1) {
       dev->dev_errno = EIO;
@@ -953,22 +967,6 @@ reread:
       return false;
    }
    
-// #define lots_of_debug
-#ifdef lots_of_debug
-   if (dev->at_eof() && dev->is_dvd()) {
-      Dmsg1(100, "file_size=%u\n",(unsigned int)dev->file_size);
-      Dmsg1(100, "file_addr=%u\n",(unsigned int)dev->file_addr);
-      Dmsg1(100, "lseek=%u\n",(unsigned int)lseek(dev->fd(), 0, SEEK_CUR));
-      Dmsg1(100, "part_start=%u\n",(unsigned int)dev->part_start);
-      Dmsg1(100, "part_size=%u\n", (unsigned int)dev->part_size);
-      Dmsg2(100, "part=%u num_dvd_parts=%u\n", dev->part, dev->num_dvd_parts);
-      Dmsg1(100, "VolCatInfo.VolCatParts=%u\n", (unsigned int)dev->VolCatInfo.VolCatParts);
-      Dmsg3(100, "Tests : %d %d %d\n", (dev->VolCatInfo.VolCatParts > 0), 
-         ((dev->file_addr-dev->part_start) == dev->part_size), 
-         (dev->part <= dev->VolCatInfo.VolCatParts));
-  }
-#endif
-
    /* Check for DVD part file end */
    if (dev->at_eof() && dev->is_dvd() && dev->num_dvd_parts > 0 &&
         dev->part <= dev->num_dvd_parts) {
@@ -1118,11 +1116,15 @@ reread:
       dcr->EndBlock = dev->EndBlock;
       dcr->EndFile  = dev->EndFile;
    } else {
-      uint64_t addr = dev->file_addr + block->read_len - 1;
+      /* We need to take care about a short block in EndBlock/File
+       * computation 
+       */
+      uint32_t len = MIN(block->read_len, block->block_len);
+      uint64_t addr = dev->file_addr + len - 1;
       dcr->EndBlock = (uint32_t)addr;
       dcr->EndFile = (uint32_t)(addr >> 32);
-      dev->block_num = dcr->EndBlock;
-      dev->file = dcr->EndFile;
+      dev->block_num = dev->EndBlock = dcr->EndBlock;
+      dev->file = dev->EndFile = dcr->EndFile;
    }
    dcr->VolMediaId = dev->VolCatInfo.VolMediaId;
    dev->file_addr += block->read_len;