2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2017 Kern Sibbald
6 The original author of Bacula is Kern Sibbald, with contributions
7 from many others, a complete list can be found in the file AUTHORS.
9 You may use this file and others of this release according to the
10 license defined in the LICENSE file, which includes the Affero General
11 Public License, v3.0 ("AGPLv3") and some additional permissions and
12 terms pursuant to its AGPLv3 Section 7.
14 This notice must be preserved when any source code is
15 conveyed and/or propagated.
17 Bacula(R) is a registered trademark of Kern Sibbald.
21 * record_read.c -- Volume (tape/disk) record read functions
23 * Kern Sibbald, April MMI
24 * added BB02 format October MMII
32 /* Imported subroutines */
33 static const int read_dbglvl = 200|DT_VOLUME;
34 static const int dbgep = 200|DT_VOLUME; /* debug execution path */
37 * Read the header record
39 static bool read_header(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
42 uint32_t VolSessionId;
43 uint32_t VolSessionTime;
47 char buf1[100], buf2[100];
49 Dmsg0(dbgep, "=== rpath 1 read_header\n");
50 ASSERT2(!block->adata, "Block is adata. Wrong!");
51 /* Clear state flags */
53 if (block->dev->is_tape()) {
54 rec->state_bits |= REC_ISTAPE;
56 rec->Addr = ((DEVICE *)block->dev)->EndAddr;
59 * Get the header. There is always a full header,
60 * otherwise we find it in the next block.
62 Dmsg4(read_dbglvl, "adata=%d Block=%d Ver=%d block_len=%u\n",
63 block->adata, block->BlockNumber, block->BlockVer, block->block_len);
64 if (block->BlockVer == 1) {
69 if (rec->remlen >= rhl) {
70 Dmsg0(dbgep, "=== rpath 2 begin unserial header\n");
71 Dmsg4(read_dbglvl, "read_header: remlen=%d data_len=%d rem=%d blkver=%d\n",
72 rec->remlen, rec->data_len, rec->remainder, block->BlockVer);
74 unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
75 if (block->BlockVer == 1) {
76 unser_uint32(VolSessionId);
77 unser_uint32(VolSessionTime);
79 VolSessionId = block->VolSessionId;
80 VolSessionTime = block->VolSessionTime;
82 unser_int32(FileIndex);
84 unser_uint32(rec->data_bytes);
86 if (dcr->dev->have_adata_header(dcr, rec, FileIndex, Stream, VolSessionId)) {
94 /* If we are looking for more (remainder!=0), we reject anything
95 * where the VolSessionId and VolSessionTime don't agree
97 if (rec->remainder && (rec->VolSessionId != VolSessionId ||
98 rec->VolSessionTime != VolSessionTime)) {
99 rec->state_bits |= REC_NO_MATCH;
100 Dmsg0(read_dbglvl, "remainder and VolSession doesn't match\n");
101 Dmsg0(dbgep, "=== rpath 4 VolSession no match\n");
102 return false; /* This is from some other Session */
105 /* if Stream is negative, it means that this is a continuation
106 * of a previous partially written record.
108 if (Stream < 0) { /* continuation record? */
109 Dmsg0(dbgep, "=== rpath 5 negative stream\n");
110 Dmsg1(read_dbglvl, "Got negative Stream => continuation. remainder=%d\n",
112 rec->state_bits |= REC_CONTINUATION;
113 if (!rec->remainder) { /* if we didn't read previously */
114 Dmsg0(dbgep, "=== rpath 6 no remainder\n");
115 rec->data_len = 0; /* return data as if no continuation */
116 } else if (rec->Stream != -Stream) {
117 Dmsg0(dbgep, "=== rpath 7 wrong cont stream\n");
118 rec->state_bits |= REC_NO_MATCH;
119 return false; /* This is from some other Session */
121 rec->Stream = -Stream; /* set correct Stream */
122 rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
123 } else { /* Regular record */
124 Dmsg0(dbgep, "=== rpath 8 normal stream\n");
125 rec->Stream = Stream;
126 rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
127 rec->data_len = 0; /* transfer to beginning of data */
129 rec->VolSessionId = VolSessionId;
130 rec->VolSessionTime = VolSessionTime;
131 rec->FileIndex = FileIndex;
133 Dmsg0(dbgep, "=== rpath 9 FileIndex>0\n");
134 if (block->FirstIndex == 0) {
135 Dmsg0(dbgep, "=== rpath 10 FirstIndex\n");
136 block->FirstIndex = FileIndex;
138 block->LastIndex = rec->FileIndex;
141 Dmsg6(read_dbglvl, "read_header: FI=%s SessId=%d Strm=%s len=%u rec->remlen=%d data_len=%d\n",
142 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
143 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_bytes, rec->remlen,
146 Dmsg0(dbgep, "=== rpath 11a block out of records\n");
148 * No more records in this block because the number
149 * of remaining bytes are less than a record header
150 * length, so return empty handed, but indicate that
151 * he must read again. By returning, we allow the
152 * higher level routine to fetch the next block and
155 Dmsg0(read_dbglvl, "read_header: End of block\n");
156 rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
157 empty_block(block); /* mark block empty */
162 if (rec->data_bytes >= MAX_BLOCK_SIZE) {
163 Dmsg0(dbgep, "=== rpath 11b maxlen too big\n");
165 * Something is wrong, force read of next block, abort
166 * continuing with this block.
168 rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
170 Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
171 MAX_BLOCK_SIZE, rec->data_bytes);
175 rec->data = check_pool_memory_size(rec->data, rec->data_len+rec->data_bytes);
176 rec->rstate = st_data;
181 * We have just read a header, now read the data into the record.
182 * Note, if we do not read the full record, we will return to
183 * read the next header, which will then come back here later
184 * to finish reading the full record.
186 static void read_data(DEV_BLOCK *block, DEV_RECORD *rec)
188 char buf1[100], buf2[100];
190 Dmsg0(dbgep, "=== rpath 22 read_data\n");
191 ASSERT2(!block->adata, "Block is adata. Wrong!");
193 * At this point, we have read the header, now we
194 * must transfer as much of the data record as
195 * possible taking into account: 1. A partial
196 * data record may have previously been transferred,
197 * 2. The current block may not contain the whole data
200 if (rec->remlen >= rec->data_bytes) {
201 Dmsg0(dbgep, "=== rpath 23 full record\n");
202 /* Got whole record */
203 memcpy(rec->data+rec->data_len, block->bufp, rec->data_bytes);
204 block->bufp += rec->data_bytes;
205 block->binbuf -= rec->data_bytes;
206 rec->data_len += rec->data_bytes;
208 Dmsg6(190, "Rdata full adata=%d FI=%s SessId=%d Strm=%s len=%d block=%p\n",
209 block->adata, FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
210 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
213 Dmsg0(dbgep, "=== rpath 24 partial record\n");
215 memcpy(rec->data+rec->data_len, block->bufp, rec->remlen);
216 block->bufp += rec->remlen;
217 block->binbuf -= rec->remlen;
218 rec->data_len += rec->remlen;
219 rec->remainder = 1; /* partial record transferred */
220 Dmsg1(read_dbglvl, "read_data: partial xfered=%d\n", rec->data_len);
221 rec->state_bits |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
227 * Read a Record from the block
228 * Returns: false if nothing read or if the continuation record does not match.
229 * In both of these cases, a block read must be done.
230 * true if at least the record header was read, this
231 * routine may have to be called again with a new
232 * block if the entire record was not read.
234 bool read_record_from_block(DCR *dcr, DEV_RECORD *rec)
236 bool save_adata = dcr->dev->adata;
239 Dmsg0(dbgep, "=== rpath 1 Enter read_record_from block\n");
241 /* Update the Record number only if we have a new record */
242 if (rec->remainder == 0) {
243 rec->RecNum = dcr->block->RecNum;
244 rec->VolumeName = dcr->CurrentVol->VolumeName; /* From JCR::VolList, freed at the end */
245 rec->Addr = rec->StartAddr = dcr->block->BlockAddr;
248 /* We read the next record */
249 dcr->block->RecNum++;
252 switch (rec->rstate) {
254 dump_block(dcr->dev, dcr->ameta_block, "st_none");
256 Dmsg0(dbgep, "=== rpath 33 st_header\n");
258 rec->remlen = dcr->block->binbuf;
259 /* Note read_header sets rec->rstate on return true */
260 if (!read_header(dcr, dcr->block, rec)) { /* sets state */
261 Dmsg0(dbgep, "=== rpath 34 failed read header\n");
262 Dmsg0(read_dbglvl, "read_header returned EOF.\n");
268 Dmsg0(dbgep, "=== rpath 37 st_data\n");
269 read_data(dcr->block, rec);
270 rec->rstate = st_header; /* next pass look for a header */
273 case st_adata_blkhdr:
275 dcr->dev->read_adata_block_header(dcr);
276 rec->rstate = st_header;
279 case st_adata_rechdr:
280 Dmsg0(dbgep, "=== rpath 35 st_adata_rechdr\n");
281 if (!dcr->dev->read_adata_record_header(dcr, dcr->block, rec)) { /* sets state */
282 Dmsg0(dbgep, "=== rpath 36 failed read_adata rechdr\n");
283 Dmsg0(100, "read_link returned EOF.\n");
289 switch (dcr->dev->read_adata(dcr, rec)) {
299 Dmsg0(dbgep, "=== rpath 50 default\n");
300 Dmsg0(0, "======= In default !!!!!\n");
301 Pmsg1(190, "Read: unknown state=%d\n", rec->rstate);
306 char buf1[100], buf2[100];
307 Dmsg6(read_dbglvl, "read_rec return: FI=%s Strm=%s len=%d rem=%d remainder=%d Num=%d\n",
308 FI_to_ascii(buf1, rec->FileIndex),
309 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
310 rec->remlen, rec->remainder, rec->RecNum);
314 rec->rstate = st_none;