]> git.sur5r.net Git - bacula/bacula/blobdiff - bacula/src/stored/record.c
Convert restore object to use STREAM_RESTORE_OBJECT; cleaner code
[bacula/bacula] / bacula / src / stored / record.c
index efe66fa51a4ef9a0c5a9510f69a67afc1550b99b..481eb8ae7d990e76db6ca7c41a605032fb9bd0df 100644 (file)
@@ -1,39 +1,43 @@
 /*
- *
- *   record.c -- tape record handling functions
- *
- *             Kern Sibbald, April MMI
- *               added BB02 format October MMII
- *
- *   Version $Id$
- *
- */
-/*
-   Copyright (C) 2000-2003 Kern Sibbald and John Walker
+   Bacula® - The Network Backup Solution
 
-   This program is free software; you can redistribute it and/or
-   modify it under the terms of the GNU General Public License as
-   published by the Free Software Foundation; either version 2 of
-   the License, or (at your option) any later version.
+   Copyright (C) 2001-2010 Free Software Foundation Europe e.V.
 
-   This program is distributed in the hope that it will be useful,
-   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   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.
+
+   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., 59 Temple Place - Suite 330, Boston,
-   MA 02111-1307, USA.
+   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.
 
+   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.
+*/
+/*
+ *
+ *   record.c -- tape record handling functions
+ *
+ *              Kern Sibbald, April MMI
+ *                added BB02 format October MMII
+ *
  */
 
 
 #include "bacula.h"
 #include "stored.h"
 
-extern int debug_level;
-
 /*
  * Convert a FileIndex into a printable
  *   ASCII string.  Not reentrant.
@@ -41,9 +45,8 @@ extern int debug_level;
  *   record as a Label, otherwise it is simply
  *   the FileIndex of the current file.
  */
-char *FI_to_ascii(int fi)
+const char *FI_to_ascii(char *buf, int fi)
 {
-   static char buf[20];
    if (fi >= 0) {
       sprintf(buf, "%d", fi);
       return buf;
@@ -62,14 +65,20 @@ char *FI_to_ascii(int fi)
    case EOT_LABEL:
       return "EOT_LABEL";
       break;
+   case SOB_LABEL:
+      return "SOB_LABEL";
+      break;
+   case EOB_LABEL:
+      return "EOB_LABEL";
+      break;
    default:
-     sprintf(buf, "unknown: %d", fi);
+     sprintf(buf, _("unknown: %d"), fi);
      return buf;
    }
 }
 
 
-/* 
+/*
  * Convert a Stream ID into a printable
  * ASCII string.  Not reentrant.
 
@@ -80,12 +89,11 @@ char *FI_to_ascii(int fi)
  *   dealing with a Label, hence the
  *   stream is the JobId.
  */
-char *stream_to_ascii(int stream, int fi)
+const char *stream_to_ascii(char *buf, int stream, int fi)
 {
-    static char buf[20];
     if (fi < 0) {
        sprintf(buf, "%d", stream);
-       return buf;     
+       return buf;
     }
     switch (stream) {
     case STREAM_UNIX_ATTRIBUTES:
@@ -96,14 +104,16 @@ char *stream_to_ascii(int stream, int fi)
        return "WIN32-DATA";
     case STREAM_WIN32_GZIP_DATA:
        return "WIN32-GZIP";
-    case STREAM_MD5_SIGNATURE:
+    case STREAM_MD5_DIGEST:
        return "MD5";
-    case STREAM_SHA1_SIGNATURE:
+    case STREAM_SHA1_DIGEST:
        return "SHA1";
     case STREAM_GZIP_DATA:
        return "GZIP";
     case STREAM_UNIX_ATTRIBUTES_EX:
        return "UNIX-ATTR-EX";
+    case STREAM_RESTORE_OBJECT:
+       return "RESTORE-OBJECT";
     case STREAM_SPARSE_DATA:
        return "SPARSE-DATA";
     case STREAM_SPARSE_GZIP_DATA:
@@ -112,6 +122,30 @@ char *stream_to_ascii(int stream, int fi)
        return "PROG-NAMES";
     case STREAM_PROGRAM_DATA:
        return "PROG-DATA";
+    case STREAM_PLUGIN_NAME:
+       return "PLUGIN-NAME";
+    case STREAM_MACOS_FORK_DATA:
+       return "MACOS-RSRC";
+    case STREAM_HFSPLUS_ATTRIBUTES:
+       return "HFSPLUS-ATTR";
+    case STREAM_SHA256_DIGEST:
+       return "SHA256";
+    case STREAM_SHA512_DIGEST:
+       return "SHA512";
+    case STREAM_SIGNED_DIGEST:
+       return "SIGNED-DIGEST";
+    case STREAM_ENCRYPTED_SESSION_DATA:
+       return "ENCRYPTED-SESSION-DATA";
+    case STREAM_ENCRYPTED_FILE_DATA:
+       return "ENCRYPTED-FILE";
+    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
+       return "ENCRYPTED-GZIP";
+    case STREAM_ENCRYPTED_WIN32_DATA:
+       return "ENCRYPTED-WIN32-DATA";
+    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
+       return "ENCRYPTED-WIN32-GZIP";
+    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
+       return "ENCRYPTED-MACOS-RSRC";
     case -STREAM_UNIX_ATTRIBUTES:
        return "contUATTR";
     case -STREAM_FILE_DATA:
@@ -120,14 +154,16 @@ char *stream_to_ascii(int stream, int fi)
        return "contWIN32-DATA";
     case -STREAM_WIN32_GZIP_DATA:
        return "contWIN32-GZIP";
-    case -STREAM_MD5_SIGNATURE:
+    case -STREAM_MD5_DIGEST:
        return "contMD5";
-    case -STREAM_SHA1_SIGNATURE:
+    case -STREAM_SHA1_DIGEST:
        return "contSHA1";
     case -STREAM_GZIP_DATA:
        return "contGZIP";
     case -STREAM_UNIX_ATTRIBUTES_EX:
        return "contUNIX-ATTR-EX";
+    case -STREAM_RESTORE_OBJECT:
+       return "contRESTORE-OBJECT";
     case -STREAM_SPARSE_DATA:
        return "contSPARSE-DATA";
     case -STREAM_SPARSE_GZIP_DATA:
@@ -136,46 +172,80 @@ char *stream_to_ascii(int stream, int fi)
        return "contPROG-NAMES";
     case -STREAM_PROGRAM_DATA:
        return "contPROG-DATA";
+    case -STREAM_MACOS_FORK_DATA:
+       return "contMACOS-RSRC";
+    case -STREAM_HFSPLUS_ATTRIBUTES:
+       return "contHFSPLUS-ATTR";
+    case -STREAM_SHA256_DIGEST:
+       return "contSHA256";
+    case -STREAM_SHA512_DIGEST:
+       return "contSHA512";
+    case -STREAM_SIGNED_DIGEST:
+       return "contSIGNED-DIGEST";
+    case -STREAM_ENCRYPTED_SESSION_DATA:
+       return "contENCRYPTED-SESSION-DATA";
+    case -STREAM_ENCRYPTED_FILE_DATA:
+       return "contENCRYPTED-FILE";
+    case -STREAM_ENCRYPTED_FILE_GZIP_DATA:
+       return "contENCRYPTED-GZIP";
+    case -STREAM_ENCRYPTED_WIN32_DATA:
+       return "contENCRYPTED-WIN32-DATA";
+    case -STREAM_ENCRYPTED_WIN32_GZIP_DATA:
+       return "contENCRYPTED-WIN32-GZIP";
+    case -STREAM_ENCRYPTED_MACOS_FORK_DATA:
+       return "contENCRYPTED-MACOS-RSRC";
+    case -STREAM_PLUGIN_NAME:
+       return "contPLUGIN-NAME";
+
     default:
        sprintf(buf, "%d", stream);
-       return buf;     
+       return buf;
     }
 }
 
-/* 
+/*
  * Return a new record entity
  */
 DEV_RECORD *new_record(void)
 {
    DEV_RECORD *rec;
 
-   rec = (DEV_RECORD *) get_memory(sizeof(DEV_RECORD));
+   rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
    memset(rec, 0, sizeof(DEV_RECORD));
    rec->data = get_pool_memory(PM_MESSAGE);
    return rec;
 }
 
+void empty_record(DEV_RECORD *rec)
+{
+   rec->File = rec->Block = 0;
+   rec->VolSessionId = rec->VolSessionTime = 0;
+   rec->FileIndex = rec->Stream = 0;
+   rec->data_len = rec->remainder = 0;
+   rec->state &= ~(REC_PARTIAL_RECORD|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
+}
+
 /*
- * Free the record entity 
+ * Free the record entity
  *
  */
-void free_record(DEV_RECORD *rec) 
+void free_record(DEV_RECORD *rec)
 {
-   Dmsg0(150, "Enter free_record.\n");
+   Dmsg0(950, "Enter free_record.\n");
    if (rec->data) {
       free_pool_memory(rec->data);
    }
-   Dmsg0(150, "Data buf is freed.\n");
+   Dmsg0(950, "Data buf is freed.\n");
    free_pool_memory((POOLMEM *)rec);
-   Dmsg0(150, "Leave free_record.\n");
-} 
+   Dmsg0(950, "Leave free_record.\n");
+}
 
 
 /*
  * Write a Record to the block
  *
- *  Returns: 0 on failure (none or partially written)
- *          1 on success (all bytes written)
+ *  Returns: false on failure (none or partially written)
+ *           true  on success (all bytes written)
  *
  *  and remainder returned in packet.
  *
@@ -185,20 +255,21 @@ void free_record(DEV_RECORD *rec)
  *  non-zero), and 2. The remaining bytes to write may not
  *  all fit into the block.
  */
-int write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
+bool write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
 {
    ser_declare;
    uint32_t remlen;
+   char buf1[100], buf2[100];
 
    remlen = block->buf_len - block->binbuf;
 
    ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
-   ASSERT(remlen >= 0);
+   ASSERT(block->buf_len >= block->binbuf);
 
-   Dmsg6(190, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n\
-rem=%d remainder=%d\n",
-      FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
-      stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
+   Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
+      "rem=%d remainder=%d\n",
+      FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+      stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
       remlen, rec->remainder);
 
    /*
@@ -209,43 +280,43 @@ rem=%d remainder=%d\n",
    if (rec->remainder == 0) {
       /* Require enough room to write a full header */
       if (remlen >= WRITE_RECHDR_LENGTH) {
-        ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
-        if (BLOCK_VER == 1) {
-           ser_uint32(rec->VolSessionId);
-           ser_uint32(rec->VolSessionTime);
-        } else {
-           block->VolSessionId = rec->VolSessionId;
-           block->VolSessionTime = rec->VolSessionTime;
-        }
-        ser_int32(rec->FileIndex);
-        ser_int32(rec->Stream);
-        ser_uint32(rec->data_len);
-
-        block->bufp += WRITE_RECHDR_LENGTH;
-        block->binbuf += WRITE_RECHDR_LENGTH;
-        remlen -= WRITE_RECHDR_LENGTH;
-        rec->remainder = rec->data_len;
-        if (rec->FileIndex > 0) {
-           /* If data record, update what we have in this block */
-           if (block->FirstIndex == 0) {
-              block->FirstIndex = rec->FileIndex;
-           }
-           block->LastIndex = rec->FileIndex;
-        }
+         ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
+         if (BLOCK_VER == 1) {
+            ser_uint32(rec->VolSessionId);
+            ser_uint32(rec->VolSessionTime);
+         } else {
+            block->VolSessionId = rec->VolSessionId;
+            block->VolSessionTime = rec->VolSessionTime;
+         }
+         ser_int32(rec->FileIndex);
+         ser_int32(rec->Stream);
+         ser_uint32(rec->data_len);
+
+         block->bufp += WRITE_RECHDR_LENGTH;
+         block->binbuf += WRITE_RECHDR_LENGTH;
+         remlen -= WRITE_RECHDR_LENGTH;
+         rec->remainder = rec->data_len;
+         if (rec->FileIndex > 0) {
+            /* If data record, update what we have in this block */
+            if (block->FirstIndex == 0) {
+               block->FirstIndex = rec->FileIndex;
+            }
+            block->LastIndex = rec->FileIndex;
+         }
       } else {
-        rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
-        return 0;
+         rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
+         return false;
       }
    } else {
-      /* 
+      /*
        * We are here to write unwritten bytes from a previous
-       * time. Presumably we have a new buffer (possibly 
-       * containing a volume label), so the new header 
+       * time. Presumably we have a new buffer (possibly
+       * containing a volume label), so the new header
        * should be able to fit in the block -- otherwise we have
        * an error.  Note, we have to continue splitting the
        * data record if it is longer than the block.
-       * 
-       * First, write the header, then write as much as 
+       *
+       * First, write the header, then write as much as
        * possible of the data record.
        *
        * Every time we write a header and it is a continuation
@@ -254,20 +325,20 @@ rem=%d remainder=%d\n",
        */
       ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
       if (BLOCK_VER == 1) {
-        ser_uint32(rec->VolSessionId);
-        ser_uint32(rec->VolSessionTime);
+         ser_uint32(rec->VolSessionId);
+         ser_uint32(rec->VolSessionTime);
       } else {
-        block->VolSessionId = rec->VolSessionId;
-        block->VolSessionTime = rec->VolSessionTime;
+         block->VolSessionId = rec->VolSessionId;
+         block->VolSessionTime = rec->VolSessionTime;
       }
       ser_int32(rec->FileIndex);
       if (rec->remainder > rec->data_len) {
-        ser_int32(rec->Stream);      /* normal full header */
-        ser_uint32(rec->data_len);
-        rec->remainder = rec->data_len; /* must still do data record */
+         ser_int32(rec->Stream);      /* normal full header */
+         ser_uint32(rec->data_len);
+         rec->remainder = rec->data_len; /* must still do data record */
       } else {
-        ser_int32(-rec->Stream);     /* mark this as a continuation record */
-        ser_uint32(rec->remainder);  /* bytes to do */
+         ser_int32(-rec->Stream);     /* mark this as a continuation record */
+         ser_uint32(rec->remainder);  /* bytes to do */
       }
 
       /* Require enough room to write a full header */
@@ -277,98 +348,102 @@ rem=%d remainder=%d\n",
       block->binbuf += WRITE_RECHDR_LENGTH;
       remlen -= WRITE_RECHDR_LENGTH;
       if (rec->FileIndex > 0) {
-        /* If data record, update what we have in this block */
-        if (block->FirstIndex == 0) {
-           block->FirstIndex = rec->FileIndex;
-        }
-        block->LastIndex = rec->FileIndex;
+         /* If data record, update what we have in this block */
+         if (block->FirstIndex == 0) {
+            block->FirstIndex = rec->FileIndex;
+         }
+         block->LastIndex = rec->FileIndex;
       }
    }
    if (remlen == 0) {
-      return 0;                      /* partial transfer */
+      return false;                   /* partial transfer */
    }
 
    /*
     * Now deal with data record.
-    * Part of it may have already been transferred, and we 
+    * Part of it may have already been transferred, and we
     * may not have enough room to transfer the whole this time.
     */
    if (rec->remainder > 0) {
       /* Write as much of data as possible */
       if (remlen >= rec->remainder) {
-        memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
-               rec->remainder);
-        block->bufp += rec->remainder;
-        block->binbuf += rec->remainder;
+         memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
+                rec->remainder);
+         block->bufp += rec->remainder;
+         block->binbuf += rec->remainder;
       } else {
-        memcpy(block->bufp, rec->data+rec->data_len-rec->remainder, 
-               remlen);
+         memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
+                remlen);
 #ifdef xxxxxSMCHECK
-        if (!sm_check_rtn(__FILE__, __LINE__, False)) {
-           /* We damaged a buffer */
-            Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n\
-rem=%d remainder=%d\n",
-              FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
-              stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
-              remlen, rec->remainder);
+         if (!sm_check_rtn(__FILE__, __LINE__, False)) {
+            /* We damaged a buffer */
+            Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
+               "rem=%d remainder=%d\n",
+               FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+               stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
+               remlen, rec->remainder);
             Dmsg5(0, "Damaged block: bufp=%x binbuf=%d buf_len=%d rem=%d moved=%d\n",
-              block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
-              remlen);
+               block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
+               remlen);
             Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
-              block->buf, block->bufp-block->buf);
+               block->buf, block->bufp-block->buf);
 
-               Emsg0(M_ABORT, 0, "Damaged buffer\n");
-        }
+               Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
+         }
 #endif
 
-        block->bufp += remlen;
-        block->binbuf += remlen;
-        rec->remainder -= remlen;
-        return 0;                    /* did partial transfer */
+         block->bufp += remlen;
+         block->binbuf += remlen;
+         rec->remainder -= remlen;
+         return false;                /* did partial transfer */
       }
    }
-   rec->remainder = 0;               /* did whole transfer */
-   return 1;
+   rec->remainder = 0;                /* did whole transfer */
+   return true;
 }
 
 
 /*
  * Test if we can write whole record to the block
  *
- *  Returns: 0 on failure 
- *          1 on success (all bytes can be written)
+ *  Returns: false on failure
+ *           true  on success (all bytes can be written)
  */
-int can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
+bool can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
 {
    uint32_t remlen;
 
    remlen = block->buf_len - block->binbuf;
    if (rec->remainder == 0) {
       if (remlen >= WRITE_RECHDR_LENGTH) {
-        remlen -= WRITE_RECHDR_LENGTH;
-        rec->remainder = rec->data_len;
+         remlen -= WRITE_RECHDR_LENGTH;
+         rec->remainder = rec->data_len;
       } else {
-        return 0;
+         return false;
       }
    } else {
-      return 0;
+      return false;
    }
    if (rec->remainder > 0 && remlen < rec->remainder) {
-      return 0;
+      return false;
    }
-   return 1;
+   return true;
 }
 
+uint64_t get_record_address(DEV_RECORD *rec)
+{
+   return ((uint64_t)rec->File)<<32 | rec->Block;
+}
 
 /*
  * Read a Record from the block
- *  Returns: 0 if nothing read or if the continuation record does not match.
- *            In both of these cases, a block read must be done.
- *          1 if at least the record header was read, this 
- *            routine may have to be called again with a new
- *            block if the entire record was not read.
+ *  Returns: false if nothing read or if the continuation record does not match.
+ *                 In both of these cases, a block read must be done.
+ *           true  if at least the record header was read, this
+ *                 routine may have to be called again with a new
+ *                 block if the entire record was not read.
  */
-int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec)
+bool read_record_from_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
 {
    ser_declare;
    uint32_t remlen;
@@ -378,40 +453,40 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec)
    int32_t  Stream;
    uint32_t data_bytes;
    uint32_t rhl;
+   char buf1[100], buf2[100];
 
    remlen = block->binbuf;
-   rec->Block = block->BlockNumber;
-   rec->File = ((DEVICE *)block->dev)->file;
 
-   /* Clear state flags */      
+   /* Clear state flags */
    rec->state = 0;
-   if (((DEVICE *)block->dev)->state & ST_TAPE) {
+   if (block->dev->is_tape()) {
       rec->state |= REC_ISTAPE;
    }
+   rec->Block = ((DEVICE *)block->dev)->EndBlock;
+   rec->File = ((DEVICE *)block->dev)->EndFile;
 
-
-   /* 
+   /*
     * Get the header. There is always a full header,
     * otherwise we find it in the next block.
     */
-   Dmsg3(100, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
-        block->block_len);
+   Dmsg3(450, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
+         block->block_len);
    if (block->BlockVer == 1) {
       rhl = RECHDR1_LENGTH;
    } else {
       rhl = RECHDR2_LENGTH;
    }
    if (remlen >= rhl) {
-      Dmsg4(90, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n", 
-           remlen, rec->data_len, rec->remainder, block->BlockVer);
+      Dmsg4(450, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n",
+            remlen, rec->data_len, rec->remainder, block->BlockVer);
 
       unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
       if (block->BlockVer == 1) {
-        unser_uint32(VolSessionId);
-        unser_uint32(VolSessionTime);
+         unser_uint32(VolSessionId);
+         unser_uint32(VolSessionTime);
       } else {
-        VolSessionId = block->VolSessionId;
-        VolSessionTime = block->VolSessionTime;
+         VolSessionId = block->VolSessionId;
+         VolSessionTime = block->VolSessionTime;
       }
       unser_int32(FileIndex);
       unser_int32(Stream);
@@ -424,73 +499,79 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec)
       /* If we are looking for more (remainder!=0), we reject anything
        *  where the VolSessionId and VolSessionTime don't agree
        */
-      if (rec->remainder && (rec->VolSessionId != VolSessionId || 
-                            rec->VolSessionTime != VolSessionTime)) {
-        rec->state |= REC_NO_MATCH;
-        return 0;                 /* This is from some other Session */
+      if (rec->remainder && (rec->VolSessionId != VolSessionId ||
+                             rec->VolSessionTime != VolSessionTime)) {
+         rec->state |= REC_NO_MATCH;
+         Dmsg0(450, "remainder and VolSession doesn't match\n");
+         return false;             /* This is from some other Session */
       }
 
       /* if Stream is negative, it means that this is a continuation
        * of a previous partially written record.
        */
-      if (Stream < 0) {              /* continuation record? */
-         Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n", 
-           rec->remainder);
-        rec->state |= REC_CONTINUATION;
+      if (Stream < 0) {               /* continuation record? */
+         Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n",
+            rec->remainder);
+         rec->state |= REC_CONTINUATION;
          if (!rec->remainder) {       /* if we didn't read previously */
-           rec->data_len = 0;        /* return data as if no continuation */
-        } else if (rec->Stream != -Stream) {
-           rec->state |= REC_NO_MATCH;
-           return 0;                 /* This is from some other Session */
-        }
-        rec->Stream = -Stream;       /* set correct Stream */
-      } else {                       /* Regular record */
-        rec->Stream = Stream;
-        rec->data_len = 0;           /* transfer to beginning of data */
+            rec->data_len = 0;        /* return data as if no continuation */
+         } else if (rec->Stream != -Stream) {
+            rec->state |= REC_NO_MATCH;
+            return false;             /* This is from some other Session */
+         }
+         rec->Stream = -Stream;       /* set correct Stream */
+      } else {                        /* Regular record */
+         rec->Stream = Stream;
+         rec->data_len = 0;           /* transfer to beginning of data */
       }
       rec->VolSessionId = VolSessionId;
       rec->VolSessionTime = VolSessionTime;
       rec->FileIndex = FileIndex;
       if (FileIndex > 0) {
-        if (block->FirstIndex == 0) {
-           block->FirstIndex = FileIndex;
-        }
-        block->LastIndex = FileIndex;
+         if (block->FirstIndex == 0) {
+            block->FirstIndex = FileIndex;
+         }
+         block->LastIndex = FileIndex;
       }
 
-      Dmsg6(100, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n"
+      Dmsg6(450, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n"
                  "remlen=%d data_len=%d\n",
-        FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
-        stream_to_ascii(rec->Stream, rec->FileIndex), data_bytes, remlen, 
-        rec->data_len);
+         FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+         stream_to_ascii(buf2, rec->Stream, rec->FileIndex), data_bytes, remlen,
+         rec->data_len);
    } else {
-      /*    
-       * No more records in this block because the number   
-       * of remaining bytes are less than a record header 
+      /*
+       * No more records in this block because the number
+       * of remaining bytes are less than a record header
        * length, so return empty handed, but indicate that
        * he must read again. By returning, we allow the
        * higher level routine to fetch the next block and
        * then reread.
        */
-      Dmsg0(90, "read_record_block: nothing\n");
-#ifdef xxx
-      if (!rec->remainder) {
-        rec->remainder = 1;          /* set to expect continuation */
-        rec->data_len = 0;           /* no data transferred */
-      }
-#endif
+      Dmsg0(450, "read_record_block: nothing\n");
       rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
-      empty_block(block);                     /* mark block empty */
-      return 0;
+      empty_block(block);                      /* mark block empty */
+      return false;
    }
 
-   ASSERT(data_bytes < MAX_BLOCK_LENGTH);      /* temp sanity check */
+   /* Sanity check */
+   if (data_bytes >= MAX_BLOCK_LENGTH) {
+      /*
+       * Something is wrong, force read of next block, abort 
+       *   continuing with this block.
+       */
+      rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
+      empty_block(block);
+      Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
+         MAX_BLOCK_LENGTH, data_bytes);
+      return false;
+   }
 
    rec->data = check_pool_memory_size(rec->data, rec->data_len+data_bytes);
-   
+
    /*
     * At this point, we have read the header, now we
-    * must transfer as much of the data record as 
+    * must transfer as much of the data record as
     * possible taking into account: 1. A partial
     * data record may have previously been transferred,
     * 2. The current block may not contain the whole data
@@ -508,14 +589,14 @@ int read_record_from_block(DEV_BLOCK *block, DEV_RECORD *rec)
       block->bufp += remlen;
       block->binbuf -= remlen;
       rec->data_len += remlen;
-      rec->remainder = 1;            /* partial record transferred */
-      Dmsg1(90, "read_record_block: partial xfered=%d\n", rec->data_len);
+      rec->remainder = 1;             /* partial record transferred */
+      Dmsg1(450, "read_record_block: partial xfered=%d\n", rec->data_len);
       rec->state |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
-      return 1;
+      return true;
    }
    rec->remainder = 0;
-   Dmsg4(90, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
-      FI_to_ascii(rec->FileIndex), rec->VolSessionId, 
-      stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len);
-   return 1;                         /* transferred full record */
+   Dmsg4(450, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
+      FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
+      stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
+   return true;                       /* transferred full record */
 }