static BSR *position_to_first_file(JCR *jcr, DCR *dcr);
static bool try_repositioning(JCR *jcr, DEV_RECORD *rec, DCR *dcr);
#ifdef DEBUG
-static char *rec_state_to_str(DEV_RECORD *rec);
+static char *rec_state_bits_to_str(DEV_RECORD *rec);
#endif
static const int dbglvl = 500;
rec = new_record();
recs->prepend(rec);
Dmsg3(dbglvl, "New record for state=%s SI=%d ST=%d\n",
- rec_state_to_str(rec),
+ rec_state_bits_to_str(rec),
block->VolSessionId, block->VolSessionTime);
}
- Dmsg3(dbglvl, "Before read rec loop. stat=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ Dmsg3(dbglvl, "Before read rec loop. stat=%s blk=%d rem=%d\n", rec_state_bits_to_str(rec),
block->BlockNumber, rec->remainder);
record = 0;
- rec->state = 0;
+ rec->state_bits = 0;
lastFileIndex = no_FileIndex;
Dmsg1(dbglvl, "Block %s empty\n", is_block_empty(rec)?"is":"NOT");
- for (rec->state=0; ok && !is_block_empty(rec); ) {
+ for (rec->state_bits=0; ok && !is_block_empty(rec); ) {
if (!read_record_from_block(dcr, block, rec)) {
- Dmsg3(400, "!read-break. state=%s blk=%d rem=%d\n", rec_state_to_str(rec),
+ Dmsg3(400, "!read-break. state_bits=%s blk=%d rem=%d\n", rec_state_bits_to_str(rec),
block->BlockNumber, rec->remainder);
break;
}
- Dmsg5(dbglvl, "read-OK. state=%s blk=%d rem=%d file:block=%u:%u\n",
- rec_state_to_str(rec), block->BlockNumber, rec->remainder,
+ Dmsg5(dbglvl, "read-OK. state_bits=%s blk=%d rem=%d file:block=%u:%u\n",
+ rec_state_bits_to_str(rec), block->BlockNumber, rec->remainder,
dev->file, dev->block_num);
/*
* At this point, we have at least a record header.
* get all the data.
*/
record++;
- Dmsg6(dbglvl, "recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
- rec_state_to_str(rec), block->BlockNumber,
+ Dmsg6(dbglvl, "recno=%d state_bits=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+ rec_state_bits_to_str(rec), block->BlockNumber,
rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
if (rec->FileIndex == EOM_LABEL) { /* end of tape? */
Dmsg4(dbglvl, "BSR no match: clear rem=%d FI=%d before set_eof pos %u:%u\n",
rec->remainder, rec->FileIndex, dev->file, dev->block_num);
rec->remainder = 0;
- rec->state &= ~REC_PARTIAL_RECORD;
+ rec->state_bits &= ~REC_PARTIAL_RECORD;
if (try_repositioning(jcr, rec, dcr)) {
break;
}
}
dcr->VolLastIndex = rec->FileIndex; /* let caller know where we are */
if (is_partial_record(rec)) {
- Dmsg6(dbglvl, "Partial, break. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
- rec_state_to_str(rec), block->BlockNumber,
+ Dmsg6(dbglvl, "Partial, break. recno=%d state_bits=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+ rec_state_bits_to_str(rec), block->BlockNumber,
rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
break; /* read second part of record */
}
- Dmsg6(dbglvl, "OK callback. recno=%d state=%s blk=%d SI=%d ST=%d FI=%d\n", record,
- rec_state_to_str(rec), block->BlockNumber,
+ Dmsg6(dbglvl, "OK callback. recno=%d state_bits=%s blk=%d SI=%d ST=%d FI=%d\n", record,
+ rec_state_bits_to_str(rec), block->BlockNumber,
rec->VolSessionId, rec->VolSessionTime, rec->FileIndex);
if (lastFileIndex != no_FileIndex && lastFileIndex != rec->FileIndex) {
if (is_this_bsr_done(jcr->bsr, rec) && try_repositioning(jcr, rec, dcr)) {
if (dev_addr > bsr_addr) {
return false;
}
- Dmsg4(10, "Try_Reposition from (file:block) %u:%u to %u:%u\n",
+ Dmsg4(dbglvl, "Try_Reposition from (file:block) %u:%u to %u:%u\n",
dev->file, dev->block_num, file, block);
dev->reposition(dcr, file, block);
rec->Block = 0;
}
#ifdef DEBUG
-static char *rec_state_to_str(DEV_RECORD *rec)
+static char *rec_state_bits_to_str(DEV_RECORD *rec)
{
static char buf[200];
buf[0] = 0;
- if (rec->state & REC_NO_HEADER) {
+ if (rec->state_bits & REC_NO_HEADER) {
bstrncat(buf, "Nohdr,", sizeof(buf));
}
if (is_partial_record(rec)) {
bstrncat(buf, "partial,", sizeof(buf));
}
- if (rec->state & REC_BLOCK_EMPTY) {
+ if (rec->state_bits & REC_BLOCK_EMPTY) {
bstrncat(buf, "empty,", sizeof(buf));
}
- if (rec->state & REC_NO_MATCH) {
+ if (rec->state_bits & REC_NO_MATCH) {
bstrncat(buf, "Nomatch,", sizeof(buf));
}
- if (rec->state & REC_CONTINUATION) {
+ if (rec->state_bits & REC_CONTINUATION) {
bstrncat(buf, "cont,", sizeof(buf));
}
if (buf[0]) {
*/
/*
*
- * record.c -- tape record handling functions
+ * record.c -- Volume (tape/disk) record handling functions
*
* Kern Sibbald, April MMI
* added BB02 format October MMII
rec = (DEV_RECORD *)get_memory(sizeof(DEV_RECORD));
memset(rec, 0, sizeof(DEV_RECORD));
rec->data = get_pool_memory(PM_MESSAGE);
+ rec->state = st_none;
return rec;
}
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);
+ rec->state_bits &= ~(REC_PARTIAL_RECORD|REC_BLOCK_EMPTY|REC_NO_MATCH|REC_CONTINUATION);
+ rec->state = st_none;
}
/*
Dmsg0(950, "Leave free_record.\n");
}
-
-/*
- * Write a Record to the block
- *
- * Returns: false on failure (none or partially written)
- * true on success (all bytes written)
- *
- * and remainder returned in packet.
- *
- * We require enough room for the header, and we deal with
- * two special cases. 1. Only part of the record may have
- * been transferred the last time (when remainder is
- * non-zero), and 2. The remaining bytes to write may not
- * all fit into the block.
- */
-bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
+static bool write_header_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
{
ser_declare;
- uint32_t remlen;
- char buf1[100], buf2[100];
- DEV_BLOCK *block;
-
- block = dcr->block;
-
- remlen = block->buf_len - block->binbuf;
-
- ASSERT(block->binbuf == (uint32_t) (block->bufp - block->buf));
- ASSERT(block->buf_len >= block->binbuf);
-
- 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);
- /*
- * If rec->remainder is non-zero, we have been called a
- * second (or subsequent) time to finish writing a record
- * that did not previously fit into the block.
- */
- 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;
- }
- } else {
- 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
- * 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
- * possible of the data record.
- *
- * Every time we write a header and it is a continuation
- * of a previous partially written record, we store the
- * Stream as -Stream in the record header.
- */
+ rec->remlen = block->buf_len - block->binbuf;
+ /* Require enough room to write a full header */
+ if (rec->remlen >= WRITE_RECHDR_LENGTH) {
ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
if (BLOCK_VER == 1) {
ser_uint32(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 */
- } else {
- 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 */
- ASSERT(remlen >= WRITE_RECHDR_LENGTH);
+ ser_int32(rec->Stream);
+ ser_uint32(rec->data_len);
block->bufp += WRITE_RECHDR_LENGTH;
block->binbuf += WRITE_RECHDR_LENGTH;
- remlen -= WRITE_RECHDR_LENGTH;
+ rec->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->LastIndex = rec->FileIndex;
}
+ } else {
+ rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
+ return false;
}
- if (remlen == 0) {
- return false; /* partial transfer */
- }
+ return true;
+}
+static void write_continue_header_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
+{
+ ser_declare;
+
+ rec->remlen = block->buf_len - block->binbuf;
/*
- * Now deal with data record.
- * Part of it may have already been transferred, and we
- * may not have enough room to transfer the whole this time.
+ * We have unwritten bytes from a previous
+ * 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.
+ *
+ * Every time we write a header and it is a continuation
+ * of a previous partially written record, we store the
+ * Stream as -Stream in the record header.
*/
- 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;
- } else {
- memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
- remlen);
+ 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_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 */
+ }
+
+ /* Require enough room to write a full header */
+ ASSERT(rec->remlen >= WRITE_RECHDR_LENGTH);
+
+ block->bufp += WRITE_RECHDR_LENGTH;
+ block->binbuf += WRITE_RECHDR_LENGTH;
+ rec->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;
+ }
+}
+
+static bool write_data_to_block(DEV_BLOCK *block, DEV_RECORD *rec)
+{
+ rec->remlen = block->buf_len - block->binbuf;
+ /* Write as much of data as possible */
+ if (rec->remlen >= 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,
+ rec->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(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);
- Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
- block->buf, block->bufp-block->buf);
-
- Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
- }
+ 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,
+ rec->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,
+ rec->remlen);
+ Dmsg2(0, "Damaged block: buf=%x binbuffrombuf=%d \n",
+ block->buf, block->bufp-block->buf);
+ Emsg0(M_ABORT, 0, _("Damaged buffer\n"));
+ }
#endif
- block->bufp += remlen;
- block->binbuf += remlen;
- rec->remainder -= remlen;
- return false; /* did partial transfer */
- }
+ block->bufp += rec->remlen;
+ block->binbuf += rec->remlen;
+ rec->remainder -= rec->remlen;
+ return false; /* did partial transfer */
}
- rec->remainder = 0; /* did whole transfer */
return true;
}
+/*
+ * Write a Record to the block
+ *
+ * Returns: false on failure (none or partially written)
+ * true on success (all bytes written)
+ *
+ * and remainder returned in packet.
+ *
+ * We require enough room for the header, and we deal with
+ * two special cases. 1. Only part of the record may have
+ * been transferred the last time (when remainder is
+ * non-zero), and 2. The remaining bytes to write may not
+ * all fit into the block.
+ */
+bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
+{
+ char buf1[100], buf2[100];
+ DEV_BLOCK *block = dcr->block;
+ for ( ;; ) {
+ ASSERT(block->binbuf == (uint32_t)(block->bufp - block->buf));
+ ASSERT(block->buf_len >= block->binbuf);
+
+ 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,
+ rec->remlen, rec->remainder);
+
+ switch (rec->state) {
+ case st_none:
+ /* Figure out what to do */
+ rec->state = st_header;
+ continue; /* go to next state */
+
+ case st_header:
+ /*
+ * Write header
+ *
+ * If rec->remainder is non-zero, we have been called a
+ * second (or subsequent) time to finish writing a record
+ * that did not previously fit into the block.
+ */
+ if (!write_header_to_block(block, rec)) {
+ rec->state = st_header_cont;
+ return false;
+ }
+ rec->state = st_data;
+ continue;
+
+ /* Write continuation header */
+ case st_header_cont:
+ write_continue_header_to_block(block, rec);
+ rec->state = st_data;
+ if (rec->remlen == 0) {
+ return false; /* partial transfer */
+ }
+ continue;
+
+ /* Write normal data */
+ case st_data:
+ /*
+ * Write data
+ *
+ * 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) {
+ if (!write_data_to_block(block, rec)) {
+ rec->state = st_header_cont;
+ return false;
+ }
+ }
+ rec->remainder = 0; /* did whole transfer */
+ rec->state = st_none;
+ return true;
+
+ default:
+ Dmsg0(000, "Something went wrong. Default state.\n");
+ rec->state = st_none;
+ return true;
+ }
+ }
+ return true;
+}
/*
* Test if we can write whole record to the block
remlen = block->binbuf;
/* Clear state flags */
- rec->state = 0;
+ rec->state_bits = 0;
if (block->dev->is_tape()) {
- rec->state |= REC_ISTAPE;
+ rec->state_bits |= REC_ISTAPE;
}
rec->Block = ((DEVICE *)block->dev)->EndBlock;
rec->File = ((DEVICE *)block->dev)->EndFile;
*/
if (rec->remainder && (rec->VolSessionId != VolSessionId ||
rec->VolSessionTime != VolSessionTime)) {
- rec->state |= REC_NO_MATCH;
+ rec->state_bits |= REC_NO_MATCH;
Dmsg0(450, "remainder and VolSession doesn't match\n");
return false; /* This is from some other Session */
}
if (Stream < 0) { /* continuation record? */
Dmsg1(500, "Got negative Stream => continuation. remainder=%d\n",
rec->remainder);
- rec->state |= REC_CONTINUATION;
+ rec->state_bits |= 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;
+ rec->state_bits |= REC_NO_MATCH;
return false; /* This is from some other Session */
}
rec->Stream = -Stream; /* set correct Stream */
* then reread.
*/
Dmsg0(450, "read_record_block: nothing\n");
- rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
+ rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
empty_block(block); /* mark block empty */
return false;
}
* Something is wrong, force read of next block, abort
* continuing with this block.
*/
- rec->state |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
+ rec->state_bits |= (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);
rec->data_len += remlen;
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);
+ rec->state_bits |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
return true;
}
rec->remainder = 0;