2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2010 Free Software Foundation Europe e.V.
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 two of the GNU General Public
10 License as published by the Free Software Foundation and included
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.
18 You should have received a copy of the GNU 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
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.
30 * record.c -- tape record handling functions
32 * Kern Sibbald, April MMI
33 * added BB02 format October MMII
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.
48 const char *FI_to_ascii(char *buf, int fi)
51 sprintf(buf, "%d", fi);
75 sprintf(buf, _("unknown: %d"), fi);
82 * Convert a Stream ID into a printable
83 * ASCII string. Not reentrant.
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.
92 const char *stream_to_ascii(char *buf, int stream, int fi)
95 sprintf(buf, "%d", stream);
99 case STREAM_UNIX_ATTRIBUTES:
101 case STREAM_FILE_DATA:
103 case STREAM_WIN32_DATA:
105 case STREAM_WIN32_GZIP_DATA:
107 case STREAM_MD5_DIGEST:
109 case STREAM_SHA1_DIGEST:
111 case STREAM_GZIP_DATA:
113 case STREAM_UNIX_ATTRIBUTES_EX:
114 return "UNIX-ATTR-EX";
115 case STREAM_SPARSE_DATA:
116 return "SPARSE-DATA";
117 case STREAM_SPARSE_GZIP_DATA:
118 return "SPARSE-GZIP";
119 case STREAM_PROGRAM_NAMES:
121 case STREAM_PROGRAM_DATA:
123 case STREAM_PLUGIN_NAME:
124 return "PLUGIN-NAME";
125 case STREAM_MACOS_FORK_DATA:
127 case STREAM_HFSPLUS_ATTRIBUTES:
128 return "HFSPLUS-ATTR";
129 case STREAM_SHA256_DIGEST:
131 case STREAM_SHA512_DIGEST:
133 case STREAM_SIGNED_DIGEST:
134 return "SIGNED-DIGEST";
135 case STREAM_ENCRYPTED_SESSION_DATA:
136 return "ENCRYPTED-SESSION-DATA";
137 case STREAM_ENCRYPTED_FILE_DATA:
138 return "ENCRYPTED-FILE";
139 case STREAM_ENCRYPTED_FILE_GZIP_DATA:
140 return "ENCRYPTED-GZIP";
141 case STREAM_ENCRYPTED_WIN32_DATA:
142 return "ENCRYPTED-WIN32-DATA";
143 case STREAM_ENCRYPTED_WIN32_GZIP_DATA:
144 return "ENCRYPTED-WIN32-GZIP";
145 case STREAM_ENCRYPTED_MACOS_FORK_DATA:
146 return "ENCRYPTED-MACOS-RSRC";
147 case -STREAM_UNIX_ATTRIBUTES:
149 case -STREAM_FILE_DATA:
151 case -STREAM_WIN32_DATA:
152 return "contWIN32-DATA";
153 case -STREAM_WIN32_GZIP_DATA:
154 return "contWIN32-GZIP";
155 case -STREAM_MD5_DIGEST:
157 case -STREAM_SHA1_DIGEST:
159 case -STREAM_GZIP_DATA:
161 case -STREAM_UNIX_ATTRIBUTES_EX:
162 return "contUNIX-ATTR-EX";
163 case -STREAM_SPARSE_DATA:
164 return "contSPARSE-DATA";
165 case -STREAM_SPARSE_GZIP_DATA:
166 return "contSPARSE-GZIP";
167 case -STREAM_PROGRAM_NAMES:
168 return "contPROG-NAMES";
169 case -STREAM_PROGRAM_DATA:
170 return "contPROG-DATA";
171 case -STREAM_MACOS_FORK_DATA:
172 return "contMACOS-RSRC";
173 case -STREAM_HFSPLUS_ATTRIBUTES:
174 return "contHFSPLUS-ATTR";
175 case -STREAM_SHA256_DIGEST:
177 case -STREAM_SHA512_DIGEST:
179 case -STREAM_SIGNED_DIGEST:
180 return "contSIGNED-DIGEST";
181 case -STREAM_ENCRYPTED_SESSION_DATA:
182 return "contENCRYPTED-SESSION-DATA";
183 case -STREAM_ENCRYPTED_FILE_DATA:
184 return "contENCRYPTED-FILE";
185 case -STREAM_ENCRYPTED_FILE_GZIP_DATA:
186 return "contENCRYPTED-GZIP";
187 case -STREAM_ENCRYPTED_WIN32_DATA:
188 return "contENCRYPTED-WIN32-DATA";
189 case -STREAM_ENCRYPTED_WIN32_GZIP_DATA:
190 return "contENCRYPTED-WIN32-GZIP";
191 case -STREAM_ENCRYPTED_MACOS_FORK_DATA:
192 return "contENCRYPTED-MACOS-RSRC";
193 case -STREAM_PLUGIN_NAME:
194 return "contPLUGIN-NAME";
197 sprintf(buf, "%d", stream);
203 * Return a new record entity
205 DEV_RECORD *new_record(void)
209 rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
210 memset(rec, 0, sizeof(DEV_RECORD));
211 rec->data = get_pool_memory(PM_MESSAGE);
215 void empty_record(DEV_RECORD *rec)
217 rec->File = rec->Block = 0;
218 rec->VolSessionId = rec->VolSessionTime = 0;
219 rec->FileIndex = rec->Stream = 0;
220 rec->data_len = rec->remainder = 0;
221 rec->state &= ~(REC_PARTIAL_RECORD|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
225 * Free the record entity
228 void free_record(DEV_RECORD *rec)
230 Dmsg0(950, "Enter free_record.\n");
232 free_pool_memory(rec->data);
234 Dmsg0(950, "Data buf is freed.\n");
235 free_pool_memory((POOLMEM *)rec);
236 Dmsg0(950, "Leave free_record.\n");
241 * Write a Record to the block
243 * Returns: false on failure (none or partially written)
244 * true on success (all bytes written)
246 * and remainder returned in packet.
248 * We require enough room for the header, and we deal with
249 * two special cases. 1. Only part of the record may have
250 * been transferred the last time (when remainder is
251 * non-zero), and 2. The remaining bytes to write may not
252 * all fit into the block.
254 bool write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
258 char buf1[100], buf2[100];
260 remlen = block->buf_len - block->binbuf;
262 ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
263 ASSERT(block->buf_len >= block->binbuf);
265 Dmsg6(890, "write_record_to_block() FI=%s SessId=%d Strm=%s len=%d\n"
266 "rem=%d remainder=%d\n",
267 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
268 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
269 remlen, rec->remainder);
272 * If rec->remainder is non-zero, we have been called a
273 * second (or subsequent) time to finish writing a record
274 * that did not previously fit into the block.
276 if (rec->remainder == 0) {
277 /* Require enough room to write a full header */
278 if (remlen >= WRITE_RECHDR_LENGTH) {
279 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
280 if (BLOCK_VER == 1) {
281 ser_uint32(rec->VolSessionId);
282 ser_uint32(rec->VolSessionTime);
284 block->VolSessionId = rec->VolSessionId;
285 block->VolSessionTime = rec->VolSessionTime;
287 ser_int32(rec->FileIndex);
288 ser_int32(rec->Stream);
289 ser_uint32(rec->data_len);
291 block->bufp += WRITE_RECHDR_LENGTH;
292 block->binbuf += WRITE_RECHDR_LENGTH;
293 remlen -= WRITE_RECHDR_LENGTH;
294 rec->remainder = rec->data_len;
295 if (rec->FileIndex > 0) {
296 /* If data record, update what we have in this block */
297 if (block->FirstIndex == 0) {
298 block->FirstIndex = rec->FileIndex;
300 block->LastIndex = rec->FileIndex;
303 rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
308 * We are here to write unwritten bytes from a previous
309 * time. Presumably we have a new buffer (possibly
310 * containing a volume label), so the new header
311 * should be able to fit in the block -- otherwise we have
312 * an error. Note, we have to continue splitting the
313 * data record if it is longer than the block.
315 * First, write the header, then write as much as
316 * possible of the data record.
318 * Every time we write a header and it is a continuation
319 * of a previous partially written record, we store the
320 * Stream as -Stream in the record header.
322 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
323 if (BLOCK_VER == 1) {
324 ser_uint32(rec->VolSessionId);
325 ser_uint32(rec->VolSessionTime);
327 block->VolSessionId = rec->VolSessionId;
328 block->VolSessionTime = rec->VolSessionTime;
330 ser_int32(rec->FileIndex);
331 if (rec->remainder > rec->data_len) {
332 ser_int32(rec->Stream); /* normal full header */
333 ser_uint32(rec->data_len);
334 rec->remainder = rec->data_len; /* must still do data record */
336 ser_int32(-rec->Stream); /* mark this as a continuation record */
337 ser_uint32(rec->remainder); /* bytes to do */
340 /* Require enough room to write a full header */
341 ASSERT(remlen >= WRITE_RECHDR_LENGTH);
343 block->bufp += WRITE_RECHDR_LENGTH;
344 block->binbuf += WRITE_RECHDR_LENGTH;
345 remlen -= WRITE_RECHDR_LENGTH;
346 if (rec->FileIndex > 0) {
347 /* If data record, update what we have in this block */
348 if (block->FirstIndex == 0) {
349 block->FirstIndex = rec->FileIndex;
351 block->LastIndex = rec->FileIndex;
355 return false; /* partial transfer */
359 * Now deal with data record.
360 * Part of it may have already been transferred, and we
361 * may not have enough room to transfer the whole this time.
363 if (rec->remainder > 0) {
364 /* Write as much of data as possible */
365 if (remlen >= rec->remainder) {
366 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
368 block->bufp += rec->remainder;
369 block->binbuf += rec->remainder;
371 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
374 if (!sm_check_rtn(__FILE__, __LINE__, False)) {
375 /* We damaged a buffer */
376 Dmsg6(0, "Damaged block FI=%s SessId=%d Strm=%s len=%d\n"
377 "rem=%d remainder=%d\n",
378 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
379 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
380 remlen, rec->remainder);
381 Dmsg5(0, "Damaged block: bufp=%x binbuf=%d buf_len=%d rem=%d moved=%d\n",
382 block->bufp, block->binbuf, block->buf_len, block->buf_len-block->binbuf,
384 Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
385 block->buf, block->bufp-block->buf);
387 Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
391 block->bufp += remlen;
392 block->binbuf += remlen;
393 rec->remainder -= remlen;
394 return false; /* did partial transfer */
397 rec->remainder = 0; /* did whole transfer */
403 * Test if we can write whole record to the block
405 * Returns: false on failure
406 * true on success (all bytes can be written)
408 bool can_write_record_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
412 remlen = block->buf_len - block->binbuf;
413 if (rec->remainder == 0) {
414 if (remlen >= WRITE_RECHDR_LENGTH) {
415 remlen -= WRITE_RECHDR_LENGTH;
416 rec->remainder = rec->data_len;
423 if (rec->remainder > 0 && remlen < rec->remainder) {
429 uint64_t get_record_address(DEV_RECORD *rec)
431 return ((uint64_t)rec->File)<<32 | rec->Block;
435 * Read a Record from the block
436 * Returns: false if nothing read or if the continuation record does not match.
437 * In both of these cases, a block read must be done.
438 * true if at least the record header was read, this
439 * routine may have to be called again with a new
440 * block if the entire record was not read.
442 bool read_record_from_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
446 uint32_t VolSessionId;
447 uint32_t VolSessionTime;
452 char buf1[100], buf2[100];
454 remlen = block->binbuf;
456 /* Clear state flags */
458 if (block->dev->is_tape()) {
459 rec->state |= REC_ISTAPE;
461 rec->Block = ((DEVICE *)block->dev)->EndBlock;
462 rec->File = ((DEVICE *)block->dev)->EndFile;
465 * Get the header. There is always a full header,
466 * otherwise we find it in the next block.
468 Dmsg3(450, "Block=%d Ver=%d size=%u\n", block->BlockNumber, block->BlockVer,
470 if (block->BlockVer == 1) {
471 rhl = RECHDR1_LENGTH;
473 rhl = RECHDR2_LENGTH;
476 Dmsg4(450, "Enter read_record_block: remlen=%d data_len=%d rem=%d blkver=%d\n",
477 remlen, rec->data_len, rec->remainder, block->BlockVer);
479 unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
480 if (block->BlockVer == 1) {
481 unser_uint32(VolSessionId);
482 unser_uint32(VolSessionTime);
484 VolSessionId = block->VolSessionId;
485 VolSessionTime = block->VolSessionTime;
487 unser_int32(FileIndex);
489 unser_uint32(data_bytes);
492 block->binbuf -= rhl;
495 /* If we are looking for more (remainder!=0), we reject anything
496 * where the VolSessionId and VolSessionTime don't agree
498 if (rec->remainder && (rec->VolSessionId != VolSessionId ||
499 rec->VolSessionTime != VolSessionTime)) {
500 rec->state |= REC_NO_MATCH;
501 Dmsg0(450, "remainder and VolSession doesn't match\n");
502 return false; /* This is from some other Session */
505 /* if Stream is negative, it means that this is a continuation
506 * of a previous partially written record.
508 if (Stream < 0) { /* continuation record? */
509 Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n",
511 rec->state |= REC_CONTINUATION;
512 if (!rec->remainder) { /* if we didn't read previously */
513 rec->data_len = 0; /* return data as if no continuation */
514 } else if (rec->Stream != -Stream) {
515 rec->state |= REC_NO_MATCH;
516 return false; /* This is from some other Session */
518 rec->Stream = -Stream; /* set correct Stream */
519 } else { /* Regular record */
520 rec->Stream = Stream;
521 rec->data_len = 0; /* transfer to beginning of data */
523 rec->VolSessionId = VolSessionId;
524 rec->VolSessionTime = VolSessionTime;
525 rec->FileIndex = FileIndex;
527 if (block->FirstIndex == 0) {
528 block->FirstIndex = FileIndex;
530 block->LastIndex = FileIndex;
533 Dmsg6(450, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%u\n"
534 "remlen=%d data_len=%d\n",
535 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
536 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), data_bytes, remlen,
540 * No more records in this block because the number
541 * of remaining bytes are less than a record header
542 * length, so return empty handed, but indicate that
543 * he must read again. By returning, we allow the
544 * higher level routine to fetch the next block and
547 Dmsg0(450, "read_record_block: nothing\n");
548 rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
549 empty_block(block); /* mark block empty */
554 if (data_bytes >= MAX_BLOCK_LENGTH) {
556 * Something is wrong, force read of next block, abort
557 * continuing with this block.
559 rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
561 Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
562 MAX_BLOCK_LENGTH, data_bytes);
566 rec->data = check_pool_memory_size(rec->data, rec->data_len+data_bytes);
569 * At this point, we have read the header, now we
570 * must transfer as much of the data record as
571 * possible taking into account: 1. A partial
572 * data record may have previously been transferred,
573 * 2. The current block may not contain the whole data
576 if (remlen >= data_bytes) {
577 /* Got whole record */
578 memcpy(rec->data+rec->data_len, block->bufp, data_bytes);
579 block->bufp += data_bytes;
580 block->binbuf -= data_bytes;
581 rec->data_len += data_bytes;
584 memcpy(rec->data+rec->data_len, block->bufp, remlen);
585 block->bufp += remlen;
586 block->binbuf -= remlen;
587 rec->data_len += remlen;
588 rec->remainder = 1; /* partial record transferred */
589 Dmsg1(450, "read_record_block: partial xfered=%d\n", rec->data_len);
590 rec->state |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
594 Dmsg4(450, "Rtn full rd_rec_blk FI=%s SessId=%d Strm=%s len=%d\n",
595 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
596 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len);
597 return true; /* transferred full record */