]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/stored/record_read.c
Use one MAX_BLOCK_SIZE and set to 20M
[bacula/bacula] / bacula / src / stored / record_read.c
1 /*
2    Bacula(R) - The Network Backup Solution
3
4    Copyright (C) 2000-2017 Kern Sibbald
5
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.
8
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.
13
14    This notice must be preserved when any source code is
15    conveyed and/or propagated.
16
17    Bacula(R) is a registered trademark of Kern Sibbald.
18 */
19 /*
20  *
21  *   record_read.c -- Volume (tape/disk) record read functions
22  *
23  *            Kern Sibbald, April MMI
24  *              added BB02 format October MMII
25  *
26  */
27
28
29 #include "bacula.h"
30 #include "stored.h"
31
32 /* Imported subroutines */
33 static const int read_dbglvl = 200|DT_VOLUME;
34 static const int dbgep = 200|DT_VOLUME;         /* debug execution path */
35
36 /*
37  * Read the header record
38  */
39 static bool read_header(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
40 {
41    ser_declare;
42    uint32_t VolSessionId;
43    uint32_t VolSessionTime;
44    int32_t  FileIndex;
45    int32_t  Stream;
46    uint32_t rhl;
47    char buf1[100], buf2[100];
48
49    Dmsg0(dbgep, "=== rpath 1 read_header\n");
50    ASSERT2(!block->adata, "Block is adata. Wrong!");
51    /* Clear state flags */
52    rec->state_bits = 0;
53    if (block->dev->is_tape()) {
54       rec->state_bits |= REC_ISTAPE;
55    }
56    rec->Addr = ((DEVICE *)block->dev)->EndAddr;
57
58    /*
59     * Get the header. There is always a full header,
60     * otherwise we find it in the next block.
61     */
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) {
65       rhl = RECHDR1_LENGTH;
66    } else {
67       rhl = RECHDR2_LENGTH;
68    }
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);
73
74       unser_begin(block->bufp, WRITE_RECHDR_LENGTH);
75       if (block->BlockVer == 1) {
76          unser_uint32(VolSessionId);
77          unser_uint32(VolSessionTime);
78       } else {
79          VolSessionId = block->VolSessionId;
80          VolSessionTime = block->VolSessionTime;
81       }
82       unser_int32(FileIndex);
83       unser_int32(Stream);
84       unser_uint32(rec->data_bytes);
85
86       if (dcr->dev->have_adata_header(dcr, rec, FileIndex, Stream, VolSessionId)) {
87          return true;
88       }
89
90       block->bufp += rhl;
91       block->binbuf -= rhl;
92       rec->remlen -= rhl;
93
94       /* If we are looking for more (remainder!=0), we reject anything
95        *  where the VolSessionId and VolSessionTime don't agree
96        */
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 */
103       }
104
105       /* if Stream is negative, it means that this is a continuation
106        * of a previous partially written record.
107        */
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",
111             rec->remainder);
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 */
120          }
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 */
128       }
129       rec->VolSessionId = VolSessionId;
130       rec->VolSessionTime = VolSessionTime;
131       rec->FileIndex = FileIndex;
132       if (FileIndex > 0) {
133          Dmsg0(dbgep, "=== rpath 9 FileIndex>0\n");
134          if (block->FirstIndex == 0) {
135             Dmsg0(dbgep, "=== rpath 10 FirstIndex\n");
136             block->FirstIndex = FileIndex;
137          }
138          block->LastIndex = rec->FileIndex;
139       }
140
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,
144          rec->data_len);
145    } else {
146       Dmsg0(dbgep, "=== rpath 11a block out of records\n");
147       /*
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
153        * then reread.
154        */
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 */
158       return false;
159    }
160
161    /* Sanity check */
162    if (rec->data_bytes >= MAX_BLOCK_SIZE) {
163       Dmsg0(dbgep, "=== rpath 11b maxlen too big\n");
164       /*
165        * Something is wrong, force read of next block, abort
166        *   continuing with this block.
167        */
168       rec->state_bits |= (REC_NO_HEADER | REC_BLOCK_EMPTY);
169       empty_block(block);
170       Jmsg2(dcr->jcr, M_WARNING, 0, _("Sanity check failed. maxlen=%d datalen=%d. Block discarded.\n"),
171          MAX_BLOCK_SIZE, rec->data_bytes);
172       return false;
173    }
174
175    rec->data = check_pool_memory_size(rec->data, rec->data_len+rec->data_bytes);
176    rec->rstate = st_data;
177    return true;
178 }
179
180 /*
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.
185  */
186 static void read_data(DEV_BLOCK *block, DEV_RECORD *rec)
187 {
188    char buf1[100], buf2[100];
189
190    Dmsg0(dbgep, "=== rpath 22 read_data\n");
191    ASSERT2(!block->adata, "Block is adata. Wrong!");
192    /*
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
198     * record.
199     */
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;
207       rec->remainder = 0;
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,
211          block);
212    } else {
213       Dmsg0(dbgep, "=== rpath 24 partial record\n");
214       /* Partial record */
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);
222    }
223 }
224
225
226 /*
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.
233  */
234 bool read_record_from_block(DCR *dcr,  DEV_RECORD *rec)
235 {
236    bool save_adata = dcr->dev->adata;
237    bool rtn;
238
239    Dmsg0(dbgep, "=== rpath 1 Enter read_record_from block\n");
240
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;
246    }
247
248    /* We read the next record */
249    dcr->block->RecNum++;
250
251    for ( ;; ) {
252       switch (rec->rstate) {
253       case st_none:
254          dump_block(dcr->dev, dcr->ameta_block, "st_none");
255       case st_header:
256          Dmsg0(dbgep, "=== rpath 33 st_header\n");
257          dcr->set_ameta();
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");
263             goto fail_out;
264          }
265          continue;
266
267       case st_data:
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 */
271          goto get_out;
272
273       case st_adata_blkhdr:
274          dcr->set_adata();
275          dcr->dev->read_adata_block_header(dcr);
276          rec->rstate = st_header;
277          continue;
278
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");
284             goto fail_out;
285          }
286          continue;
287
288       case st_adata:
289          switch (dcr->dev->read_adata(dcr, rec)) {
290          case -1:
291             goto fail_out;
292          case 0:
293             continue;
294          case 1:
295             goto get_out;
296          }
297
298       default:
299          Dmsg0(dbgep, "=== rpath 50 default\n");
300          Dmsg0(0, "======= In default !!!!!\n");
301          Pmsg1(190, "Read: unknown state=%d\n", rec->rstate);
302          goto fail_out;
303       }
304    }
305 get_out:
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);
311    rtn = true;
312    goto out;
313 fail_out:
314    rec->rstate = st_none;
315    rtn = false;
316 out:
317    if (save_adata) {
318       dcr->set_adata();
319    } else {
320       dcr->set_ameta();
321    }
322    return rtn;
323 }