2 Bacula(R) - The Network Backup Solution
4 Copyright (C) 2000-2015 Kern Sibbald
5 Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
7 The original author of Bacula is Kern Sibbald, with contributions
8 from many others, a complete list can be found in the file AUTHORS.
10 You may use this file and others of this release according to the
11 license defined in the LICENSE file, which includes the Affero General
12 Public License, v3.0 ("AGPLv3") and some additional permissions and
13 terms pursuant to its AGPLv3 Section 7.
15 This notice must be preserved when any source code is
16 conveyed and/or propagated.
18 Bacula(R) is a registered trademark of Kern Sibbald.
22 * record_write.c -- Volume (tape/disk) record write functions
24 * Kern Sibbald, April MMI
25 * added BB02 format October MMII
33 /* Imported functions */
35 static const int dbgep = 250; /* debug execution path */
36 static const int dbgel = 250; /* debug Enter/Leave code */
49 bool flush_block(DCR *dcr)
53 if (!is_block_empty(dcr->block)) {
54 Dmsg0(dbgep, "=== wpath 53 flush_block\n");
55 Dmsg3(190, "Call flush_block BlockAddr=%lld nbytes=%d block=%x\n",
56 dcr->block->BlockAddr, dcr->block->binbuf, dcr->block);
57 dump_block(dcr->block, "Flush_block");
58 if (dcr->jcr->is_canceled() || !dcr->write_block_to_device()) {
59 Dmsg0(dbgep, "=== wpath 54 flush_block\n");
60 Dmsg0(190, "Failed to write block to device, return false.\n");
63 empty_block(dcr->block);
72 * Write a header record to the block.
74 static bool write_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
78 Dmsg0(dbgep, "=== wpath 11 write_header_to_block\n");
79 rec->remlen = block->buf_len - block->binbuf;
80 /* Require enough room to write a full header */
81 if (rec->remlen < WRITE_RECHDR_LENGTH) {
82 Dmsg0(dbgep, "=== wpath 12 write_header_to_block\n");
83 Dmsg4(190, "Fail remlen=%d<%d reclen buf_len=%d binbuf=%d\n",
84 rec->remlen, WRITE_RECHDR_LENGTH, block->buf_len, block->binbuf);
85 rec->remainder = rec->data_len + WRITE_RECHDR_LENGTH;
88 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
90 Dmsg0(dbgep, "=== wpath 13 write_header_to_block\n");
91 ser_uint32(rec->VolSessionId);
92 ser_uint32(rec->VolSessionTime);
94 Dmsg0(dbgep, "=== wpath 14 write_header_to_block\n");
95 block->VolSessionId = rec->VolSessionId;
96 block->VolSessionTime = rec->VolSessionTime;
98 ser_int32(rec->FileIndex);
99 ser_int32(rec->Stream);
100 ser_uint32(rec->data_len);
102 block->bufp += WRITE_RECHDR_LENGTH;
103 block->binbuf += WRITE_RECHDR_LENGTH;
104 rec->remlen -= WRITE_RECHDR_LENGTH;
105 rec->remainder = rec->data_len;
106 if (rec->FileIndex > 0) {
107 Dmsg0(dbgep, "=== wpath 15 write_header_to_block\n");
108 /* If data record, update what we have in this block */
109 if (block->FirstIndex == 0) {
110 Dmsg0(dbgep, "=== wpath 16 write_header_to_block\n");
111 block->FirstIndex = rec->FileIndex;
113 block->LastIndex = rec->FileIndex;
116 //dump_block(block, "Add header");
121 * If the prior block was not big enough to hold the
122 * whole record, write a continuation header record.
124 static void write_continue_header_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
128 Dmsg0(dbgep, "=== wpath 17 write_cont_hdr_to_block\n");
129 rec->remlen = block->buf_len - block->binbuf;
131 * We have unwritten bytes from a previous
132 * time. Presumably we have a new buffer (possibly
133 * containing a volume label), so the new header
134 * should be able to fit in the block -- otherwise we have
135 * an error. Note, we have to continue splitting the
136 * data record if it is longer than the block.
138 * First, write the header.
140 * Every time we write a header and it is a continuation
141 * of a previous partially written record, we store the
142 * Stream as -Stream in the record header.
144 ser_begin(block->bufp, WRITE_RECHDR_LENGTH);
145 if (BLOCK_VER == 1) {
146 Dmsg0(dbgep, "=== wpath 18 write_cont_hdr_to_block\n");
147 ser_uint32(rec->VolSessionId);
148 ser_uint32(rec->VolSessionTime);
150 Dmsg0(dbgep, "=== wpath 19 write_cont_hdr_to_block\n");
151 block->VolSessionId = rec->VolSessionId;
152 block->VolSessionTime = rec->VolSessionTime;
154 ser_int32(rec->FileIndex);
155 if (rec->remainder > rec->data_len) {
156 Dmsg0(dbgep, "=== wpath 20 write_cont_hdr_to_block\n");
157 ser_int32(rec->Stream); /* normal full header */
158 ser_uint32(rec->data_len);
159 rec->remainder = rec->data_len; /* must still do data record */
161 Dmsg0(dbgep, "=== wpath 21 write_cont_hdr_to_block\n");
162 ser_int32(-rec->Stream); /* mark this as a continuation record */
163 ser_uint32(rec->remainder); /* bytes to do */
166 /* Require enough room to write a full header */
167 ASSERT(rec->remlen >= WRITE_RECHDR_LENGTH);
169 block->bufp += WRITE_RECHDR_LENGTH;
170 block->binbuf += WRITE_RECHDR_LENGTH;
171 rec->remlen -= WRITE_RECHDR_LENGTH;
172 if (rec->FileIndex > 0) {
173 Dmsg0(dbgep, "=== wpath 22 write_cont_hdr_to_block\n");
174 /* If data record, update what we have in this block */
175 if (block->FirstIndex == 0) {
176 Dmsg0(dbgep, "=== wpath 23 write_cont_hdr_to_block\n");
177 block->FirstIndex = rec->FileIndex;
179 block->LastIndex = rec->FileIndex;
181 //dump_block(block, "Add cont header");
186 static bool write_data_to_block(DCR *dcr, DEV_BLOCK *block, DEV_RECORD *rec)
188 Dmsg0(dbgep, "=== wpath 24 write_data_to_block\n");
189 rec->remlen = block->buf_len - block->binbuf;
190 /* Write as much of data as possible */
191 if (rec->remlen >= rec->remainder) {
192 Dmsg0(dbgep, "=== wpath 25 write_data_to_block\n");
193 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
195 block->bufp += rec->remainder;
196 block->binbuf += rec->remainder;
199 Dmsg0(dbgep, "=== wpath 26 write_data_to_block\n");
200 memcpy(block->bufp, rec->data+rec->data_len-rec->remainder,
202 block->bufp += rec->remlen;
203 block->binbuf += rec->remlen;
204 rec->remainder -= rec->remlen;
205 return false; /* did partial transfer */
211 * Write a record to the block -- handles writing out full
212 * blocks by writing them to the device.
214 * Returns: false means the block could not be written to tape/disk.
215 * true on success (all bytes written to the block).
217 bool DCR::write_record(DEV_RECORD *rec)
220 Dmsg0(dbgep, "=== wpath 33 write_record\n");
221 while (!write_record_to_block(this, rec)) {
222 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
224 if (jcr->is_canceled()) {
228 if (!write_block_to_device()) {
229 Dmsg0(dbgep, "=== wpath 34 write_record\n");
230 Pmsg2(000, "Got write_block_to_dev error on device %s. %s\n",
231 dev->print_name(), dev->bstrerror());
235 Dmsg2(850, "!write_record_to_block data_len=%d rem=%d\n", rec->data_len,
243 * Write a record to the block
245 * Returns: false on failure (none or partially written)
246 * true on success (all bytes written)
248 * and remainder returned in packet.
250 * We require enough room for the header, and we deal with
251 * two special cases. 1. Only part of the record may have
252 * been transferred the last time (when remainder is
253 * non-zero), and 2. The remaining bytes to write may not
254 * all fit into the block.
257 bool write_record_to_block(DCR *dcr, DEV_RECORD *rec)
259 char buf1[100], buf2[100];
263 Dmsg0(dbgep, "=== wpath 35 enter write_record_to_block\n");
264 Dmsg7(200, "write_record_to_block() state=%d FI=%s SessId=%d"
265 " Strm=%s len=%d rem=%d remainder=%d\n", rec->wstate,
266 FI_to_ascii(buf1, rec->FileIndex), rec->VolSessionId,
267 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
268 rec->remlen, rec->remainder);
269 Dmsg4(160, "write_rec Strm=%s len=%d rem=%d remainder=%d\n",
270 stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len,
271 rec->remlen, rec->remainder);
274 Dmsg0(dbgep, "=== wpath 37 top of for loop\n");
275 ASSERT(dcr->block->binbuf == (uint32_t) (dcr->block->bufp - dcr->block->buf));
276 ASSERT(dcr->block->buf_len >= dcr->block->binbuf);
278 switch (rec->wstate) {
280 Dmsg0(dbgep, "=== wpath 38 st_none\n");
281 /* Figure out what to do */
282 rec->wstate = st_header;
283 if (rec->FileIndex < 0) {
285 rec->wstate = st_header;
288 continue; /* go to next state */
294 * If rec->remainder is non-zero, we have been called a
295 * second (or subsequent) time to finish writing a record
296 * that did not previously fit into the block.
298 Dmsg0(dbgep, "=== wpath 42 st_header\n");
299 if (!write_header_to_block(dcr, dcr->block, rec)) {
300 Dmsg0(dbgep, "=== wpath 43 st_header\n");
301 rec->wstate = st_cont_header;
304 Dmsg0(dbgep, "=== wpath 44 st_header\n");
305 rec->wstate = st_data;
309 Dmsg0(dbgep, "=== wpath 45 st_cont_header\n");
310 write_continue_header_to_block(dcr, dcr->block, rec);
311 rec->wstate = st_data;
312 if (rec->remlen == 0) {
313 Dmsg0(dbgep, "=== wpath 46 st_cont_header\n");
319 * We come here only once for each record
325 * Part of it may have already been transferred, and we
326 * may not have enough room to transfer the whole this time.
328 Dmsg0(dbgep, "=== wpath 47 st_data\n");
329 if (rec->remainder > 0) {
330 Dmsg0(dbgep, "=== wpath 48 st_data\n");
331 if (!write_data_to_block(dcr, dcr->block, rec)) {
332 Dmsg0(dbgep, "=== wpath 49 st_data\n");
333 rec->wstate = st_cont_header;
337 rec->remainder = 0; /* did whole transfer */
338 rec->wstate = st_none;
342 Dmsg0(dbgep, "=== wpath 67!!!! default\n");
343 Dmsg0(50, "Something went wrong. Default state.\n");
344 rec->wstate = st_none;