]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/record.c
Backport more from master
[bacula/bacula] / bacula / src / stored / record.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2001-2012 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from
7    many others, a complete list can be found in the file AUTHORS.
8    This program is Free Software; you can redistribute it and/or
9    modify it under the terms of version three of the GNU Affero General Public
10    License as published by the Free Software Foundation and included
11    in the file LICENSE.
12
13    This program is distributed in the hope that it will be useful, but
14    WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16    General Public License for more details.
17
18    You should have received a copy of the GNU Affero General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
21    02110-1301, USA.
22
23    Bacula® is a registered trademark of Kern Sibbald.
24    The licensor of Bacula is the Free Software Foundation Europe
25    (FSFE), Fiduciary Program, Sumatrastrasse 25, 8006 Zürich,
26    Switzerland, email:ftf@fsfeurope.org.
27 */
28 /*
29  *
30  *   record.c -- Volume (tape/disk) record handling functions
31  *
32  *              Kern Sibbald, April MMI
33  *                added BB02 format October MMII
34  *
35  */
36
37
38 #include "bacula.h"
39 #include "stored.h"
40
41 /*
42  * Convert a FileIndex into a printable
43  *   ASCII string.  Not reentrant.
44  * If the FileIndex is negative, it flags the
45  *   record as a Label, otherwise it is simply
46  *   the FileIndex of the current file.
47  */
48 const char *FI_to_ascii(char *buf, int fi)
49 {
50    if (fi >= 0) {
51       sprintf(buf, "%d", fi);
52       return buf;
53    }
54    switch (fi) {
55    case PRE_LABEL:
56       return "PRE_LABEL";
57    case VOL_LABEL:
58       return "VOL_LABEL";
59    case EOM_LABEL:
60       return "EOM_LABEL";
61    case SOS_LABEL:
62       return "SOS_LABEL";
63    case EOS_LABEL:
64       return "EOS_LABEL";
65    case EOT_LABEL:
66       return "EOT_LABEL";
67       break;
68    case SOB_LABEL:
69       return "SOB_LABEL";
70       break;
71    case EOB_LABEL:
72       return "EOB_LABEL";
73       break;
74    default:
75      sprintf(buf, _("unknown: %d"), fi);
76      return buf;
77    }
78 }
79
80
81 /*
82  * Convert a Stream ID into a printable
83  * ASCII string.  Not reentrant.
84
85  * A negative stream number represents
86  *   stream data that is continued from a
87  *   record in the previous block.
88  * If the FileIndex is negative, we are
89  *   dealing with a Label, hence the
90  *   stream is the JobId.
91  */
92 const char *stream_to_ascii(char *buf, int stream, int fi)
93 {
94
95    if (fi < 0) {
96       sprintf(buf, "%d", stream);
97       return buf;
98    }
99    if (stream < 0) {
100       stream = -stream;
101       stream &= STREAMMASK_TYPE;
102       /* Stream was negative => all are continuation items */
103       switch (stream) {
104       case STREAM_UNIX_ATTRIBUTES:
105          return "contUATTR";
106       case STREAM_FILE_DATA:
107          return "contDATA";
108       case STREAM_WIN32_DATA:
109          return "contWIN32-DATA";
110       case STREAM_WIN32_GZIP_DATA:
111          return "contWIN32-GZIP";
112       case STREAM_WIN32_COMPRESSED_DATA:
113          return "contWIN32-COMPRESSED";
114       case STREAM_MD5_DIGEST:
115          return "contMD5";
116       case STREAM_SHA1_DIGEST:
117          return "contSHA1";
118       case STREAM_GZIP_DATA:
119          return "contGZIP";
120       case STREAM_COMPRESSED_DATA:
121          return "contCOMPRESSED";
122       case STREAM_UNIX_ATTRIBUTES_EX:
123          return "contUNIX-ATTR-EX";
124       case STREAM_RESTORE_OBJECT:
125          return "contRESTORE-OBJECT";
126       case STREAM_SPARSE_DATA:
127          return "contSPARSE-DATA";
128       case STREAM_SPARSE_GZIP_DATA:
129          return "contSPARSE-GZIP";
130       case STREAM_SPARSE_COMPRESSED_DATA:
131          return "contSPARSE-COMPRESSED";
132       case STREAM_PROGRAM_NAMES:
133          return "contPROG-NAMES";
134       case STREAM_PROGRAM_DATA:
135          return "contPROG-DATA";
136       case STREAM_MACOS_FORK_DATA:
137          return "contMACOS-RSRC";
138       case STREAM_HFSPLUS_ATTRIBUTES:
139          return "contHFSPLUS-ATTR";
140       case STREAM_SHA256_DIGEST:
141          return "contSHA256";
142       case STREAM_SHA512_DIGEST:
143          return "contSHA512";
144       case STREAM_SIGNED_DIGEST:
145          return "contSIGNED-DIGEST";
146       case STREAM_ENCRYPTED_SESSION_DATA:
147          return "contENCRYPTED-SESSION-DATA";
148       case STREAM_ENCRYPTED_FILE_DATA:
149          return "contENCRYPTED-FILE";
150       case STREAM_ENCRYPTED_FILE_GZIP_DATA:
151          return "contENCRYPTED-GZIP";
152       case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
153          return "contENCRYPTED-COMPRESSED";
154       case STREAM_ENCRYPTED_WIN32_DATA:
155          return "contENCRYPTED-WIN32-DATA";
156       case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
157          return "contENCRYPTED-WIN32-GZIP";
158       case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
159          return "contENCRYPTED-WIN32-COMPRESSED";
160       case STREAM_ENCRYPTED_MACOS_FORK_DATA:
161          return "contENCRYPTED-MACOS-RSRC";
162       case STREAM_PLUGIN_NAME:
163          return "contPLUGIN-NAME";
164
165       default:
166          sprintf(buf, "%d", -stream);
167          return buf;
168       }
169    }
170
171    switch (stream & STREAMMASK_TYPE) {
172    case STREAM_UNIX_ATTRIBUTES:
173       return "UATTR";
174    case STREAM_FILE_DATA:
175       return "DATA";
176    case STREAM_WIN32_DATA:
177       return "WIN32-DATA";
178    case STREAM_WIN32_GZIP_DATA:
179       return "WIN32-GZIP";
180    case STREAM_WIN32_COMPRESSED_DATA:
181       return "WIN32-COMPRESSED";
182    case STREAM_MD5_DIGEST:
183       return "MD5";
184    case STREAM_SHA1_DIGEST:
185       return "SHA1";
186    case STREAM_GZIP_DATA:
187       return "GZIP";
188    case STREAM_COMPRESSED_DATA:
189       return "COMPRESSED";
190    case STREAM_UNIX_ATTRIBUTES_EX:
191       return "UNIX-ATTR-EX";
192    case STREAM_RESTORE_OBJECT:
193       return "RESTORE-OBJECT";
194    case STREAM_SPARSE_DATA:
195       return "SPARSE-DATA";
196    case STREAM_SPARSE_GZIP_DATA:
197       return "SPARSE-GZIP";
198    case STREAM_SPARSE_COMPRESSED_DATA:
199       return "SPARSE-COMPRESSED";
200    case STREAM_PROGRAM_NAMES:
201       return "PROG-NAMES";
202    case STREAM_PROGRAM_DATA:
203       return "PROG-DATA";
204    case STREAM_PLUGIN_NAME:
205       return "PLUGIN-NAME";
206    case STREAM_MACOS_FORK_DATA:
207       return "MACOS-RSRC";
208    case STREAM_HFSPLUS_ATTRIBUTES:
209       return "HFSPLUS-ATTR";
210    case STREAM_SHA256_DIGEST:
211       return "SHA256";
212    case STREAM_SHA512_DIGEST:
213       return "SHA512";
214    case STREAM_SIGNED_DIGEST:
215       return "SIGNED-DIGEST";
216    case STREAM_ENCRYPTED_SESSION_DATA:
217       return "ENCRYPTED-SESSION-DATA";
218    case STREAM_ENCRYPTED_FILE_DATA:
219       return "ENCRYPTED-FILE";
220    case STREAM_ENCRYPTED_FILE_GZIP_DATA:
221       return "ENCRYPTED-GZIP";
222    case STREAM_ENCRYPTED_FILE_COMPRESSED_DATA:
223       return "ENCRYPTED-COMPRESSED";
224    case STREAM_ENCRYPTED_WIN32_DATA:
225       return "ENCRYPTED-WIN32-DATA";
226    case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
227       return "ENCRYPTED-WIN32-GZIP";
228    case STREAM_ENCRYPTED_WIN32_COMPRESSED_DATA:
229       return "ENCRYPTED-WIN32-COMPRESSED";
230    case STREAM_ENCRYPTED_MACOS_FORK_DATA:
231       return "ENCRYPTED-MACOS-RSRC";
232
233       default:
234          sprintf(buf, "%d", stream);
235          return buf;
236       }
237 }
238
239 /*
240  * Return a new record entity
241  */
242 DEV_RECORD *new_record(void)
243 {
244    DEV_RECORD *rec;
245
246    rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
247    memset(rec, 0, sizeof(DEV_RECORD));
248    rec->data = get_pool_memory(PM_MESSAGE);
249    rec->state = st_none;
250    return rec;
251 }
252
253 void empty_record(DEV_RECORD *rec)
254 {
255    rec->File = rec->Block = 0;
256    rec->VolSessionId = rec->VolSessionTime = 0;
257    rec->FileIndex = rec->Stream = 0;
258    rec->data_len = rec->remainder = 0;
259    rec->state_bits &= ~(REC_PARTIAL_RECORD|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
260    rec->state = st_none;
261 }
262
263 /*
264  * Free the record entity
265  *
266  */
267 void free_record(DEV_RECORD *rec)
268 {
269    Dmsg0(950, "Enter free_record.\n");
270    if (rec->data) {
271       free_pool_memory(rec->data);
272    }
273    Dmsg0(950, "Data buf is freed.\n");
274    free_pool_memory((POOLMEM *)rec);
275    Dmsg0(950, "Leave free_record.\n");
276 }
277
278 static bool write_header_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
279 {
280    ser_declare;
281
282    rec->remlen = block->buf_len - block->binbuf;
283    /* Require enough room to write a full header */
284    if (rec->remlen >= WRITE_RECHDR_LENGTH) {
285       ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
286       if (BLOCK_VER == 1) {
287          ser_uint32(rec->VolSessionId);
288          ser_uint32(rec->VolSessionTime);
289       } else {
290          block->VolSessionId = rec->VolSessionId;
291          block->VolSessionTime = rec->VolSessionTime;
292       }
293       ser_int32(rec->FileIndex);
294       ser_int32(rec->Stream);
295       ser_uint32(rec->data_len);
296
297       block->bufp += WRITE_RECHDR_LENGTH;
298       block->binbuf += WRITE_RECHDR_LENGTH;
299       rec->remlen -= WRITE_RECHDR_LENGTH;
300       rec->remainder = rec->data_len;
301       if (rec->FileIndex > 0) {
302          /* If data record, update what we have in this block */
303          if (block->FirstIndex == 0) {
304             block->FirstIndex = rec->FileIndex;
305          }
306          block->LastIndex = rec->FileIndex;
307       }
308    } else {
309       rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
310       return false;
311    }
312    return true;
313 }
314
315 static void write_continue_header_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
316 {
317    ser_declare;
318
319    rec->remlen = block->buf_len - block->binbuf;
320    /*
321     * We have unwritten bytes from a previous
322     * time. Presumably we have a new buffer (possibly
323     * containing a volume label), so the new header
324     * should be able to fit in the block -- otherwise we have
325     * an error.  Note, we have to continue splitting the
326     * data record if it is longer than the block.
327     *
328     * First, write the header.
329     *
330     * Every time we write a header and it is a continuation
331     * of a previous partially written record, we store the
332     * Stream as -Stream in the record header.
333     */
334    ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
335    if (BLOCK_VER == 1) {
336       ser_uint32(rec->VolSessionId);
337       ser_uint32(rec->VolSessionTime);
338    } else {
339       block->VolSessionId = rec->VolSessionId;
340       block->VolSessionTime = rec->VolSessionTime;
341    }
342    ser_int32(rec->FileIndex);
343    if (rec->remainder > rec->data_len) {
344       ser_int32(rec->Stream);      /* normal full header */
345       ser_uint32(rec->data_len);
346       rec->remainder = rec->data_len; /* must still do data record */
347    } else {
348       ser_int32(-rec->Stream);     /* mark this as a continuation record */
349       ser_uint32(rec->remainder);  /* bytes to do */
350    }
351
352    /* Require enough room to write a full header */
353    ASSERT(rec->remlen >= WRITE_RECHDR_LENGTH);
354
355    block->bufp += WRITE_RECHDR_LENGTH;
356    block->binbuf += WRITE_RECHDR_LENGTH;
357    rec->remlen -= WRITE_RECHDR_LENGTH;
358    if (rec->FileIndex > 0) {
359       /* If data record, update what we have in this block */
360       if (block->FirstIndex == 0) {
361          block->FirstIndex = rec->FileIndex;
362       }
363       block->LastIndex = rec->FileIndex;
364    }
365 }
366
367 static bool write_data_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
368 {
369    rec->remlen = block->buf_len - block->binbuf;
370    /* Write as much of data as possible */
371    if (rec->remlen >= rec->remainder) {
372       memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
373              rec->remainder);
374       block->bufp += rec->remainder;
375       block->binbuf += rec->remainder;
376    } else {
377       memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
378              rec->remlen);
379 #ifdef xxxxxSMCHECK
380       if (!sm_check_rtn(__FILE__, __LINE__, False)) {
381          /* We damaged a buffer */
382          Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
383             "rem=%d remainder=%d\n",
384             FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
385             stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
386             rec->remlen, rec->remainder);
387          Dmsg5(0, "Damaged block: bufp=%x binbuf=%d buf_len=%d rem=%d moved=%d\n",
388             block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
389             rec->remlen);
390          Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
391             block->buf, block->bufp-block->buf);
392          Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
393       }
394 #endif
395
396       block->bufp += rec->remlen;
397       block->binbuf += rec->remlen;
398       rec->remainder -= rec->remlen;
399       return false;                /* did partial transfer */
400    }
401    return true;
402 }
403
404 /*
405  * Write a Record to the block
406  *
407  *  Returns: false means the block could not be written to tape/disk.
408  *           true  on success (all bytes written to the block).
409  */
410 bool DCR::write_record(DEV_RECORD *rec)
411 {
412    while (!write_record_to_block(this, rec)) {
413       Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
414                  rec->remainder);
415       if (!write_block_to_device()) {
416          Dmsg2(90, "Got write_block_to_dev error on device %s. %s\n",
417             dev->print_name(), dev->bstrerror());
418          return false;
419       }
420    }
421    return true;
422 }
423
424 /*
425  * Write a Record to the block
426  *
427  *  Returns: false on failure (none or partially written)
428  *           true  on success (all bytes written)
429  *
430  *  and remainder returned in packet.
431  *
432  *  We require enough room for the header, and we deal with
433  *  two special cases. 1. Only part of the record may have
434  *  been transferred the last time (when remainder is
435  *  non-zero), and 2. The remaining bytes to write may not
436  *  all fit into the block.
437  */
438 bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
439 {
440    char buf1[100], buf2[100];
441    DEV_BLOCK *block = dcr->block;
442
443    for ( ;; ) {
444       ASSERT(block->binbuf == (uint32_t)(block->bufp - block->buf));
445       ASSERT(block->buf_len >= block->binbuf);
446
447       Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
448          "rem=%d remainder=%d\n",
449          FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
450          stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
451          rec->remlen, rec->remainder);
452
453       switch (rec->state) {
454       case st_none:
455          /* Figure out what to do */
456          rec->state = st_header;
457          continue;              /* go to next state */
458
459       case st_header:
460          /*
461           * Write header
462           *
463           * If rec->remainder is non-zero, we have been called a
464           *  second (or subsequent) time to finish writing a record
465           *  that did not previously fit into the block.
466           */
467           if (!write_header_to_block(block, rec)) {
468              return false;        /* write block then come back here */
469           }
470           rec->state = st_data;  /* after header, now write data */
471           continue;
472
473       /* Write continuation header */
474       case st_header_cont:
475          write_continue_header_to_block(block, rec);
476          rec->state = st_data;
477          if (rec->remlen == 0) {
478             return false;                   /* partial transfer */
479          }
480          continue;
481
482       /* Write normal data */
483       case st_data:
484          /*
485           * Write data
486           *
487           * Part of it may have already been transferred, and we
488           * may not have enough room to transfer the whole this time.
489           */
490          if (rec->remainder > 0) {
491             if (!write_data_to_block(block, rec)) {
492                rec->state = st_header_cont;
493                return false;
494             }
495          }
496          rec->remainder = 0;                /* did whole transfer */
497          rec->state = st_none;
498          return true;
499
500       default:
501          Dmsg0(000, "Something went wrong. Default state.\n");
502          rec->state = st_none;
503          return true;
504       }
505    }
506    return true;
507 }
508
509 /*
510  * Test if we can write whole record to the block
511  *
512  *  Returns: false on failure
513  *           true  on success (all bytes can be written)
514  */
515 bool can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
516 {
517    uint32_t remlen;
518
519    remlen = block->buf_len - block->binbuf;
520    if (rec->remainder == 0) {
521       if (remlen >= WRITE_RECHDR_LENGTH) {
522          remlen -= WRITE_RECHDR_LENGTH;
523          rec->remainder = rec->data_len;
524       } else {
525          return false;
526       }
527    } else {
528       return false;
529    }
530    if (rec->remainder > 0 && remlen < rec->remainder) {
531       return false;
532    }
533    return true;
534 }
535
536 uint64_t get_record_address(DEV_RECORD *rec)
537 {
538    return ((uint64_t)rec->File)<<32 | rec->Block;
539 }
540
541 /*
542  * Read a Record from the block
543  *  Returns: false if nothing read or if the continuation record does not match.
544  *                 In both of these cases, a block read must be done.
545  *           true  if at least the record header was read, this
546  *                 routine may have to be called again with a new
547  *                 block if the entire record was not read.
548  */
549 bool read_record_from_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
550 {
551    ser_declare;
552    uint32_t remlen;
553    uint32_t VolSessionId;
554    uint32_t VolSessionTime;
555    int32_t  FileIndex;
556    int32_t  Stream;
557    uint32_t data_bytes;
558    uint32_t rhl;
559    char buf1[100], buf2[100];
560
561    remlen = block->binbuf;
562
563    /* Clear state flags */
564    rec->state_bits = 0;
565    if (block->dev->is_tape()) {
566       rec->state_bits |= REC_ISTAPE;
567    }
568    rec->Block = ((DEVICE *)block->dev)->EndBlock;
569    rec->File = ((DEVICE *)block->dev)->EndFile;
570
571    /*
572     * Get the header. There is always a full header,
573     * otherwise we find it in the next block.
574     */
575    Dmsg3(450, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
576          block->block_len);
577    if (block->BlockVer == 1) {
578       rhl = RECHDR1_LENGTH;
579    } else {
580       rhl = RECHDR2_LENGTH;
581    }
582    if (remlen >= rhl) {
583       Dmsg4(450, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n",
584             remlen, rec->data_len, rec->remainder, block->BlockVer);
585
586       unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
587       if (block->BlockVer == 1) {
588          unser_uint32(VolSessionId);
589          unser_uint32(VolSessionTime);
590       } else {
591          VolSessionId = block->VolSessionId;
592          VolSessionTime = block->VolSessionTime;
593       }
594       unser_int32(FileIndex);
595       unser_int32(Stream);
596       unser_uint32(data_bytes);
597
598       block->bufp += rhl;
599       block->binbuf -= rhl;
600       remlen -= rhl;
601
602       /* If we are looking for more (remainder!=0), we reject anything
603        *  where the VolSessionId and VolSessionTime don't agree
604        */
605       if (rec->remainder && (rec->VolSessionId != VolSessionId ||
606                              rec->VolSessionTime != VolSessionTime)) {
607          rec->state_bits |= REC_NO_MATCH;
608          Dmsg0(450, "remainder and VolSession doesn't match\n");
609          return false;             /* This is from some other Session */
610       }
611
612       /* if Stream is negative, it means that this is a continuation
613        * of a previous partially written record.
614        */
615       if (Stream < 0) {               /* continuation record? */
616          Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n",
617             rec->remainder);
618          rec->state_bits |= REC_CONTINUATION;
619          if (!rec->remainder) {       /* if we didn't read previously */
620             rec->data_len = 0;        /* return data as if no continuation */
621          } else if (rec->Stream != -Stream) {
622             rec->state_bits |= REC_NO_MATCH;
623             return false;             /* This is from some other Session */
624          }
625          rec->Stream = -Stream;       /* set correct Stream */
626          rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
627       } else {                        /* Regular record */
628          rec->Stream = Stream;
629          rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
630          rec->data_len = 0;           /* transfer to beginning of data */
631       }
632       rec->VolSessionId = VolSessionId;
633       rec->VolSessionTime = VolSessionTime;
634       rec->FileIndex = FileIndex;
635       if (FileIndex > 0) {
636          if (block->FirstIndex == 0) {
637             block->FirstIndex = FileIndex;
638          }
639          block->LastIndex = FileIndex;
640       }
641
642       Dmsg6(450, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n"
643                  "remlen=%d data_len=%d\n",
644          FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
645          stream_to_ascii(buf2, rec->Stream, rec->FileIndex), data_bytes, remlen,
646          rec->data_len);
647    } else {
648       /*
649        * No more records in this block because the number
650        * of remaining bytes are less than a record header
651        * length, so return empty handed, but indicate that
652        * he must read again. By returning, we allow the
653        * higher level routine to fetch the next block and
654        * then reread.
655        */
656       Dmsg0(450, "read_record_block: nothing\n");
657       rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
658       empty_block(block);                      /* mark block empty */
659       return false;
660    }
661
662    /* Sanity check */
663    if (data_bytes >= MAX_BLOCK_LENGTH) {
664       /*
665        * Something is wrong, force read of next block, abort 
666        *   continuing with this block.
667        */
668       rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
669       empty_block(block);
670       Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
671          MAX_BLOCK_LENGTH, data_bytes);
672       return false;
673    }
674
675    rec->data = check_pool_memory_size(rec->data, rec->data_len+data_bytes);
676
677    /*
678     * At this point, we have read the header, now we
679     * must transfer as much of the data record as
680     * possible taking into account: 1. A partial
681     * data record may have previously been transferred,
682     * 2. The current block may not contain the whole data
683     * record.
684     */
685    if (remlen >= data_bytes) {
686       /* Got whole record */
687       memcpy(rec->data+rec->data_len, block->bufp, data_bytes);
688       block->bufp += data_bytes;
689       block->binbuf -= data_bytes;
690       rec->data_len += data_bytes;
691    } else {
692       /* Partial record */
693       memcpy(rec->data+rec->data_len, block->bufp, remlen);
694       block->bufp += remlen;
695       block->binbuf -= remlen;
696       rec->data_len += remlen;
697       rec->remainder = 1;             /* partial record transferred */
698       Dmsg1(450, "read_record_block: partial xfered=%d\n", rec->data_len);
699       rec->state_bits |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
700       return true;
701    }
702    rec->remainder = 0;
703    Dmsg4(450, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
704       FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
705       stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
706    return true;                       /* transferred full record */
707 }