* record.c -- tape record handling functions
*
* Kern Sibbald, April MMI
+ * added BB02 format October MMII
*
* Version $Id$
*
*/
/*
- Copyright (C) 2000, 2001, 2002 Kern Sibbald and John Walker
+ Copyright (C) 2000-2003 Kern Sibbald and John Walker
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public License as
return "SOS_LABEL";
case EOS_LABEL:
return "EOS_LABEL";
+ case EOT_LABEL:
+ return "EOT_LABEL";
+ break;
default:
sprintf(buf, "unknown: %d", fi);
return buf;
/*
* Convert a Stream ID into a printable
* ASCII string. Not reentrant.
+
+ * A negative stream number represents
+ * stream data that is continued from a
+ * record in the previous block.
+ * If the FileIndex is negative, we are
+ * dealing with a Label, hence the
+ * stream is the JobId.
*/
-char *stream_to_ascii(int stream)
+char *stream_to_ascii(int stream, int fi)
{
static char buf[20];
+ if (fi < 0) {
+ sprintf(buf, "%d", stream);
+ return buf;
+ }
switch (stream) {
case STREAM_UNIX_ATTRIBUTES:
return "UATTR";
return "DATA";
case STREAM_MD5_SIGNATURE:
return "MD5";
+ case STREAM_SHA1_SIGNATURE:
+ return "SHA1";
case STREAM_GZIP_DATA:
return "GZIP";
+ case STREAM_WIN32_ATTRIBUTES:
+ return "WIN32-ATTR";
+ case STREAM_SPARSE_DATA:
+ return "SPARSE-DATA";
+ case STREAM_SPARSE_GZIP_DATA:
+ return "SPARSE-GZIP";
+ case STREAM_PROGRAM_NAMES:
+ return "PROG-NAMES";
+ case STREAM_PROGRAM_DATA:
+ return "PROG-DATA";
+ case -STREAM_UNIX_ATTRIBUTES:
+ return "contUATTR";
+ case -STREAM_FILE_DATA:
+ return "contDATA";
+ case -STREAM_MD5_SIGNATURE:
+ return "contMD5";
+ case -STREAM_SHA1_SIGNATURE:
+ return "contSHA1";
+ case -STREAM_GZIP_DATA:
+ return "contGZIP";
+ case -STREAM_WIN32_ATTRIBUTES:
+ return "contWIN32-ATTR";
+ case -STREAM_SPARSE_DATA:
+ return "contSPARSE-DATA";
+ case -STREAM_SPARSE_GZIP_DATA:
+ return "contSPARSE-GZIP";
+ case -STREAM_PROGRAM_NAMES:
+ return "contPROG-NAMES";
+ case -STREAM_PROGRAM_DATA:
+ return "contPROG-DATA";
default:
sprintf(buf, "%d", stream);
return buf;
void free_record(DEV_RECORD *rec)
{
Dmsg0(150, "Enter free_record.\n");
- free_pool_memory(rec->data);
+ if (rec->data) {
+ free_pool_memory(rec->data);
+ }
Dmsg0(150, "Data buf is freed.\n");
free_pool_memory((POOLMEM *)rec);
Dmsg0(150, "Leave free_record.\n");
ser_declare;
uint32_t remlen;
- sm_check(__FILE__, __LINE__, False);
remlen = block->buf_len - block->binbuf;
ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
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->data_len,
+ stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len,
remlen, rec->remainder);
/*
*/
if (rec->remainder == 0) {
/* Require enough room to write a full header */
- if (remlen >= RECHDR_LENGTH) {
- ser_begin(block->bufp, RECHDR_LENGTH);
+ 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);
- ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf += RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += WRITE_RECHDR_LENGTH;
+ block->binbuf += WRITE_RECHDR_LENGTH;
+ remlen -= WRITE_RECHDR_LENGTH;
rec->remainder = rec->data_len;
} else {
- rec->remainder = rec->data_len + RECHDR_LENGTH;
- sm_check(__FILE__, __LINE__, False);
+ rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
return 0;
}
} else {
* 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 may have to continue splitting the
- * data record though.
+ * 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
* possible of the data record.
* of a previous partially written record, we store the
* Stream as -Stream in the record header.
*/
- ser_begin(block->bufp, 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);
if (rec->remainder > rec->data_len) {
ser_int32(rec->Stream); /* normal full header */
ser_int32(-rec->Stream); /* mark this as a continuation record */
ser_uint32(rec->remainder); /* bytes to do */
}
- ASSERT(ser_length(block->bufp) == RECHDR_LENGTH);
/* Require enough room to write a full header */
- ASSERT(remlen >= RECHDR_LENGTH);
+ ASSERT(remlen >= WRITE_RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf += RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += WRITE_RECHDR_LENGTH;
+ block->binbuf += WRITE_RECHDR_LENGTH;
+ remlen -= WRITE_RECHDR_LENGTH;
}
if (remlen == 0) {
- sm_check(__FILE__, __LINE__, False);
return 0; /* partial transfer */
}
} else {
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->data_len,
+ stream_to_ascii(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,
Emsg0(M_ABORT, 0, "Damaged buffer\n");
}
+#endif
block->bufp += remlen;
block->binbuf += remlen;
}
}
rec->remainder = 0; /* did whole transfer */
- sm_check(__FILE__, __LINE__, False);
return 1;
}
remlen = block->buf_len - block->binbuf;
if (rec->remainder == 0) {
- if (remlen >= RECHDR_LENGTH) {
- remlen -= RECHDR_LENGTH;
+ if (remlen >= WRITE_RECHDR_LENGTH) {
+ remlen -= WRITE_RECHDR_LENGTH;
rec->remainder = rec->data_len;
} else {
return 0;
int32_t FileIndex;
int32_t Stream;
uint32_t data_bytes;
+ uint32_t rhl;
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) {
+ rec->state |= REC_ISTAPE;
+ }
+
/*
* Get the header. There is always a full header,
* otherwise we find it in the next block.
*/
- if (remlen >= RECHDR_LENGTH) {
- Dmsg3(90, "read_record_block: remlen=%d data_len=%d rem=%d\n",
- remlen, rec->data_len, rec->remainder);
+ Dmsg3(100, "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);
- unser_begin(block->bufp, RECHDR_LENGTH);
+ unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
+ if (block->BlockVer == 1) {
unser_uint32(VolSessionId);
unser_uint32(VolSessionTime);
+ } else {
+ VolSessionId = block->VolSessionId;
+ VolSessionTime = block->VolSessionTime;
+ }
unser_int32(FileIndex);
unser_int32(Stream);
unser_uint32(data_bytes);
- ASSERT(unser_length(block->bufp) == RECHDR_LENGTH);
- block->bufp += RECHDR_LENGTH;
- block->binbuf -= RECHDR_LENGTH;
- remlen -= RECHDR_LENGTH;
+ block->bufp += rhl;
+ block->binbuf -= rhl;
+ remlen -= rhl;
- /*
- * if Stream is negative, it means that this is a continuation
+ /* 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 Stream is negative, it means that this is a continuation
* of a previous partially written record.
*/
if (Stream < 0) { /* continuation record? */
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->VolSessionId != VolSessionId ||
- rec->VolSessionTime != VolSessionTime ||
- rec->Stream != -Stream) {
+ } else if (rec->Stream != -Stream) {
rec->state |= REC_NO_MATCH;
return 0; /* This is from some other Session */
}
rec->VolSessionTime = VolSessionTime;
rec->FileIndex = FileIndex;
- Dmsg6(90, "rd_rec_blk() got FI=%s SessId=%d Strm=%s len=%d\n\
+ Dmsg6(100, "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), data_bytes, remlen, rec->data_len);
+ stream_to_ascii(rec->Stream, rec->FileIndex), data_bytes, remlen,
+ rec->data_len);
} else {
/*
* No more records in this block because the number
* 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
rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
+ empty_block(block); /* mark block empty */
return 0;
}
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->data_len);
+ stream_to_ascii(rec->Stream, rec->FileIndex), rec->data_len);
return 1; /* transferred full record */
}