2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2016 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_write.c -- Volume (tape/disk) record write functions
23 * Kern Sibbald, April MMI
24 * added BB02 format October MMII
32 /* Imported functions */
34 static const int dbgep = 250; /* debug execution path */
35 static const int dbgel = 250; /* debug Enter/Leave code */
48 bool flush_block(DCR *dcr)
52 if (!is_block_empty(dcr->block)) {
53 Dmsg0(dbgep, "=== wpath 53 flush_block\n");
54 Dmsg3(190, "Call flush_block BlockAddr=%lld nbytes=%d block=%x\n",
55 dcr->block->BlockAddr, dcr->block->binbuf, dcr->block);
56 dump_block(dcr->block, "Flush_block");
57 if (dcr->jcr->is_canceled() || !dcr->write_block_to_device()) {
58 Dmsg0(dbgep, "=== wpath 54 flush_block\n");
59 Dmsg0(190, "Failed to write block to device, return false.\n");
62 empty_block(dcr->block);
71 * Write a header record to the block.
73 static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
77 Dmsg0(dbgep, "=== wpath 11 write_header_to_block\n");
78 rec->remlen = block->buf_len - block->binbuf;
79 /* Require enough room to write a full header */
80 if (rec->remlen < WRITE_RECHDR_LENGTH) {
81 Dmsg0(dbgep, "=== wpath 12 write_header_to_block\n");
82 Dmsg4(190, "Fail remlen=%d<%d reclen buf_len=%d binbuf=%d\n",
83 rec->remlen, WRITE_RECHDR_LENGTH, block->buf_len, block->binbuf);
84 rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
87 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
89 Dmsg0(dbgep, "=== wpath 13 write_header_to_block\n");
90 ser_uint32(rec->VolSessionId);
91 ser_uint32(rec->VolSessionTime);
93 Dmsg0(dbgep, "=== wpath 14 write_header_to_block\n");
94 block->VolSessionId = rec->VolSessionId;
95 block->VolSessionTime = rec->VolSessionTime;
97 ser_int32(rec->FileIndex);
98 ser_int32(rec->Stream);
99 ser_uint32(rec->data_len);
101 block->bufp += WRITE_RECHDR_LENGTH;
102 block->binbuf += WRITE_RECHDR_LENGTH;
103 rec->remlen -= WRITE_RECHDR_LENGTH;
104 rec->remainder = rec->data_len;
105 if (rec->FileIndex > 0) {
106 Dmsg0(dbgep, "=== wpath 15 write_header_to_block\n");
107 /* If data record, update what we have in this block */
108 if (block->FirstIndex == 0) {
109 Dmsg0(dbgep, "=== wpath 16 write_header_to_block\n");
110 block->FirstIndex = rec->FileIndex;
112 block->LastIndex = rec->FileIndex;
115 //dump_block(block, "Add header");
120 * If the prior block was not big enough to hold the
121 * whole record, write a continuation header record.
123 static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
127 Dmsg0(dbgep, "=== wpath 17 write_cont_hdr_to_block\n");
128 rec->remlen = block->buf_len - block->binbuf;
130 * We have unwritten bytes from a previous
131 * time. Presumably we have a new buffer (possibly
132 * containing a volume label), so the new header
133 * should be able to fit in the block -- otherwise we have
134 * an error. Note, we have to continue splitting the
135 * data record if it is longer than the block.
137 * First, write the header.
139 * Every time we write a header and it is a continuation
140 * of a previous partially written record, we store the
141 * Stream as -Stream in the record header.
143 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
144 if (BLOCK_VER == 1) {
145 Dmsg0(dbgep, "=== wpath 18 write_cont_hdr_to_block\n");
146 ser_uint32(rec->VolSessionId);
147 ser_uint32(rec->VolSessionTime);
149 Dmsg0(dbgep, "=== wpath 19 write_cont_hdr_to_block\n");
150 block->VolSessionId = rec->VolSessionId;
151 block->VolSessionTime = rec->VolSessionTime;
153 ser_int32(rec->FileIndex);
154 if (rec->remainder > rec->data_len) {
155 Dmsg0(dbgep, "=== wpath 20 write_cont_hdr_to_block\n");
156 ser_int32(rec->Stream); /* normal full header */
157 ser_uint32(rec->data_len);
158 rec->remainder = rec->data_len; /* must still do data record */
160 Dmsg0(dbgep, "=== wpath 21 write_cont_hdr_to_block\n");
161 ser_int32(-rec->Stream); /* mark this as a continuation record */
162 ser_uint32(rec->remainder); /* bytes to do */
165 /* Require enough room to write a full header */
166 ASSERT(rec->remlen >= WRITE_RECHDR_LENGTH);
168 block->bufp += WRITE_RECHDR_LENGTH;
169 block->binbuf += WRITE_RECHDR_LENGTH;
170 rec->remlen -= WRITE_RECHDR_LENGTH;
171 if (rec->FileIndex > 0) {
172 Dmsg0(dbgep, "=== wpath 22 write_cont_hdr_to_block\n");
173 /* If data record, update what we have in this block */
174 if (block->FirstIndex == 0) {
175 Dmsg0(dbgep, "=== wpath 23 write_cont_hdr_to_block\n");
176 block->FirstIndex = rec->FileIndex;
178 block->LastIndex = rec->FileIndex;
180 //dump_block(block, "Add cont header");
185 static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
187 Dmsg0(dbgep, "=== wpath 24 write_data_to_block\n");
188 rec->remlen = block->buf_len - block->binbuf;
189 /* Write as much of data as possible */
190 if (rec->remlen >= rec->remainder) {
191 Dmsg0(dbgep, "=== wpath 25 write_data_to_block\n");
192 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
194 block->bufp += rec->remainder;
195 block->binbuf += rec->remainder;
198 Dmsg0(dbgep, "=== wpath 26 write_data_to_block\n");
199 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
201 block->bufp += rec->remlen;
202 block->binbuf += rec->remlen;
203 rec->remainder -= rec->remlen;
204 return false; /* did partial transfer */
210 * Write a record to the block -- handles writing out full
211 * blocks by writing them to the device.
213 * Returns: false means the block could not be written to tape/disk.
214 * true on success (all bytes written to the block).
216 bool DCR::write_record(DEV_RECORD *rec)
219 Dmsg0(dbgep, "=== wpath 33 write_record\n");
220 while (!write_record_to_block(this, rec)) {
221 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
223 if (jcr->is_canceled()) {
227 if (!write_block_to_device()) {
228 Dmsg0(dbgep, "=== wpath 34 write_record\n");
229 Pmsg2(000, "Got write_block_to_dev error on device %s. %s\n",
230 dev->print_name(), dev->bstrerror());
234 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
242 * Write a record to the block
244 * Returns: false on failure (none or partially written)
245 * true on success (all bytes written)
247 * and remainder returned in packet.
249 * We require enough room for the header, and we deal with
250 * two special cases. 1. Only part of the record may have
251 * been transferred the last time (when remainder is
252 * non-zero), and 2. The remaining bytes to write may not
253 * all fit into the block.
256 bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
258 char buf1[100], buf2[100];
262 Dmsg0(dbgep, "=== wpath 35 enter write_record_to_block\n");
263 Dmsg7(200, "write_record_to_block() state=%d FI=%s SessId=%d"
264 " Strm=%s len=%d rem=%d remainder=%d\n", rec->wstate,
265 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
266 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
267 rec->remlen, rec->remainder);
268 Dmsg4(160, "write_rec Strm=%s len=%d rem=%d remainder=%d\n",
269 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
270 rec->remlen, rec->remainder);
273 Dmsg0(dbgep, "=== wpath 37 top of for loop\n");
274 ASSERT(dcr->block->binbuf == (uint32_t) (dcr->block->bufp - dcr->block->buf));
275 ASSERT(dcr->block->buf_len >= dcr->block->binbuf);
277 switch (rec->wstate) {
279 Dmsg0(dbgep, "=== wpath 38 st_none\n");
280 /* Figure out what to do */
281 rec->wstate = st_header;
282 if (rec->FileIndex < 0) {
284 rec->wstate = st_header;
287 continue; /* go to next state */
293 * If rec->remainder is non-zero, we have been called a
294 * second (or subsequent) time to finish writing a record
295 * that did not previously fit into the block.
297 Dmsg0(dbgep, "=== wpath 42 st_header\n");
298 if (!write_header_to_block(dcr, dcr->block, rec)) {
299 Dmsg0(dbgep, "=== wpath 43 st_header\n");
300 rec->wstate = st_cont_header;
303 Dmsg0(dbgep, "=== wpath 44 st_header\n");
304 rec->wstate = st_data;
308 Dmsg0(dbgep, "=== wpath 45 st_cont_header\n");
309 write_continue_header_to_block(dcr, dcr->block, rec);
310 rec->wstate = st_data;
311 if (rec->remlen == 0) {
312 Dmsg0(dbgep, "=== wpath 46 st_cont_header\n");
318 * We come here only once for each record
324 * Part of it may have already been transferred, and we
325 * may not have enough room to transfer the whole this time.
327 Dmsg0(dbgep, "=== wpath 47 st_data\n");
328 if (rec->remainder > 0) {
329 Dmsg0(dbgep, "=== wpath 48 st_data\n");
330 if (!write_data_to_block(dcr, dcr->block, rec)) {
331 Dmsg0(dbgep, "=== wpath 49 st_data\n");
332 rec->wstate = st_cont_header;
336 rec->remainder = 0; /* did whole transfer */
337 rec->wstate = st_none;
341 Dmsg0(dbgep, "=== wpath 67!!!! default\n");
342 Dmsg0(50, "Something went wrong. Default state.\n");
343 rec->wstate = st_none;