2 Bacula® - The Network Backup Solution
4 Copyright (C) 2001-2014 Free Software Foundation Europe e.V.
6 The main author of Bacula is Kern Sibbald, with contributions from many
7 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 Bacula® is a registered trademark of Kern Sibbald.
18 * record_read.c -- Volume (tape/disk) record read functions
20 * Kern Sibbald, April MMI
21 * added BB02 format October MMII
28 /* Imported subroutines */
31 static const int read_dbglvl = 200;
32 static const int dbgep = 250; /* debug execution path */
35 * Read the header record
37 static bool read_header(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
40 uint32_t VolSessionId;
41 uint32_t VolSessionTime;
45 char buf1[100], buf2[100];
47 Dmsg0(dbgep, "=== rpath 1 read_header\n");
48 /* Clear state flags */
50 if (block->dev->is_tape()) {
51 rec->state_bits |= REC_ISTAPE;
53 rec->Block = ((DEVICE *)block->dev)->EndBlock;
54 rec->File = ((DEVICE *)block->dev)->EndFile;
57 * Get the header. There is always a full header,
58 * otherwise we find it in the next block.
60 Dmsg3(read_dbglvl, "Block=%d Ver=%d block_len=%u\n",
61 block->BlockNumber, block->BlockVer, block->block_len);
62 if (block->BlockVer == 1) {
67 if (rec->remlen >= rhl) {
68 Dmsg0(dbgep, "=== rpath 2 begin unserial header\n");
69 Dmsg4(read_dbglvl, "read_header: remlen=%d data_len=%d rem=%d blkver=%d\n",
70 rec->remlen, rec->data_len, rec->remainder, block->BlockVer);
72 unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
73 if (block->BlockVer == 1) {
74 unser_uint32(VolSessionId);
75 unser_uint32(VolSessionTime);
77 VolSessionId = block->VolSessionId;
78 VolSessionTime = block->VolSessionTime;
80 unser_int32(FileIndex);
82 unser_uint32(rec->data_bytes);
88 /* If we are looking for more (remainder!=0), we reject anything
89 * where the VolSessionId and VolSessionTime don't agree
91 if (rec->remainder && (rec->VolSessionId != VolSessionId ||
92 rec->VolSessionTime != VolSessionTime)) {
93 rec->state_bits |= REC_NO_MATCH;
94 Dmsg0(read_dbglvl, "remainder and VolSession doesn't match\n");
95 Dmsg0(dbgep, "=== rpath 4 VolSession no match\n");
96 return false; /* This is from some other Session */
99 /* if Stream is negative, it means that this is a continuation
100 * of a previous partially written record.
102 if (Stream < 0) { /* continuation record? */
103 Dmsg0(dbgep, "=== rpath 5 negative stream\n");
104 Dmsg1(read_dbglvl, "Got negative Stream => continuation. remainder=%d\n",
106 rec->state_bits |= REC_CONTINUATION;
107 if (!rec->remainder) { /* if we didn't read previously */
108 Dmsg0(dbgep, "=== rpath 6 no remainder\n");
109 rec->data_len = 0; /* return data as if no continuation */
110 } else if (rec->Stream != -Stream) {
111 Dmsg0(dbgep, "=== rpath 7 wrong cont stream\n");
112 rec->state_bits |= REC_NO_MATCH;
113 return false; /* This is from some other Session */
115 rec->Stream = -Stream; /* set correct Stream */
116 rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
117 } else { /* Regular record */
118 Dmsg0(dbgep, "=== rpath 8 normal stream\n");
119 rec->Stream = Stream;
120 rec->maskedStream = rec->Stream & STREAMMASK_TYPE;
121 rec->data_len = 0; /* transfer to beginning of data */
123 rec->VolSessionId = VolSessionId;
124 rec->VolSessionTime = VolSessionTime;
125 rec->FileIndex = FileIndex;
127 Dmsg0(dbgep, "=== rpath 9 FileIndex>0\n");
128 if (block->FirstIndex == 0) {
129 Dmsg0(dbgep, "=== rpath 10 FirstIndex\n");
130 block->FirstIndex = FileIndex;
132 block->LastIndex = rec->FileIndex;
135 Dmsg6(read_dbglvl, "read_header: FI=%s SessId=%d Strm=%s len=%u rec->remlen=%d data_len=%d\n",
136 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
137 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_bytes, rec->remlen,
140 Dmsg0(dbgep, "=== rpath 11a block out of records\n");
142 * No more records in this block because the number
143 * of remaining bytes are less than a record header
144 * length, so return empty handed, but indicate that
145 * he must read again. By returning, we allow the
146 * higher level routine to fetch the next block and
149 Dmsg0(read_dbglvl, "read_header: End of block\n");
150 rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
151 empty_block(block); /* mark block empty */
156 if (rec->data_bytes >= MAX_BLOCK_LENGTH) {
157 Dmsg0(dbgep, "=== rpath 11b maxlen too big\n");
159 * Something is wrong, force read of next block, abort
160 * continuing with this block.
162 rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
164 Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
165 MAX_BLOCK_LENGTH, rec->data_bytes);
169 rec->data = check_pool_memory_size(rec->data, rec->data_len+rec->data_bytes);
170 rec->rstate = st_data;
175 * We have just read a header, now read the data into the record.
176 * Note, if we do not read the full record, we will return to
177 * read the next header, which will then come back here later
178 * to finish reading the full record.
180 static void read_data(DEV_BLOCK *block, DEV_RECORD *rec)
182 char buf1[100], buf2[100];
184 Dmsg0(dbgep, "=== rpath 22 read_data\n");
186 * At this point, we have read the header, now we
187 * must transfer as much of the data record as
188 * possible taking into account: 1. A partial
189 * data record may have previously been transferred,
190 * 2. The current block may not contain the whole data
193 if (rec->remlen >= rec->data_bytes) {
194 Dmsg0(dbgep, "=== rpath 23 full record\n");
195 /* Got whole record */
196 memcpy(rec->data+rec->data_len, block->bufp, rec->data_bytes);
197 block->bufp += rec->data_bytes;
198 block->binbuf -= rec->data_bytes;
199 rec->data_len += rec->data_bytes;
201 Dmsg5(190, "Rdata full FI=%s SessId=%d Strm=%s len=%d block=%p\n",
202 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
203 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
206 Dmsg0(dbgep, "=== rpath 24 partial record\n");
208 memcpy(rec->data+rec->data_len, block->bufp, rec->remlen);
209 block->bufp += rec->remlen;
210 block->binbuf -= rec->remlen;
211 rec->data_len += rec->remlen;
212 rec->remainder = 1; /* partial record transferred */
213 Dmsg1(read_dbglvl, "read_data: partial xfered=%d\n", rec->data_len);
214 rec->state_bits |= (REC_PARTIAL_RECORD | REC_BLOCK_EMPTY);
220 * Read a Record from the block
221 * Returns: false if nothing read or if the continuation record does not match.
222 * In both of these cases, a block read must be done.
223 * true if at least the record header was read, this
224 * routine may have to be called again with a new
225 * block if the entire record was not read.
227 bool read_record_from_block(DCR *dcr, DEV_RECORD *rec)
231 Dmsg0(dbgep, "=== rpath 1 Enter read_record_from block\n");
233 switch (rec->rstate) {
235 dump_block(dcr->block, "st_none");
237 Dmsg0(dbgep, "=== rpath 33 st_header\n");
238 rec->remlen = dcr->block->binbuf;
239 /* Note read_header sets rec->rstate on return true */
240 if (!read_header(dcr, dcr->block, rec)) { /* sets state */
241 Dmsg0(dbgep, "=== rpath 34 failed read header\n");
242 Dmsg0(read_dbglvl, "read_header returned EOF.\n");
248 Dmsg0(dbgep, "=== rpath 37 st_data\n");
249 read_data(dcr->block, rec);
250 rec->rstate = st_header; /* next pass look for a header */
254 Dmsg0(dbgep, "=== rpath 50 default\n");
255 Dmsg0(0, "======= In default !!!!!\n");
256 Pmsg1(190, "Read: unknown state=%d\n", rec->rstate);
261 char buf1[100], buf2[100];
262 Dmsg5(read_dbglvl, "read_rec return: FI=%s Strm=%s len=%d rem=%d remainder=%d\n",
263 FI_to_ascii(buf1, rec->FileIndex),
264 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
265 rec->remlen, rec->remainder);
269 rec->rstate = st_none;