/* * Handle the data just read and send it to the SD after doing any postprocessing needed. */ static inline bool send_data_to_sd(b_ctx *bctx) { BSOCK *sd = bctx->jcr->store_bsock; bool need_more_data; /* * Check for sparse blocks */ if (bit_is_set(FO_SPARSE, bctx->ff_pkt->flags)) { bool allZeros; ser_declare; allZeros = false; if ((sd->msglen == bctx->rsize && (bctx->fileAddr + sd->msglen < (uint64_t)bctx->ff_pkt->statp.st_size)) || ((bctx->ff_pkt->type == FT_RAW || bctx->ff_pkt->type == FT_FIFO) && ((uint64_t)bctx->ff_pkt->statp.st_size == 0))) { allZeros = is_buf_zero(bctx->rbuf, bctx->rsize); } if (!allZeros) { /* * Put file address as first data in buffer */ ser_begin(bctx->wbuf, OFFSET_FADDR_SIZE); ser_uint64(bctx->fileAddr); /* store fileAddr in begin of buffer */ } bctx->fileAddr += sd->msglen; /* update file address */ /* * Skip block of all zeros */ if (allZeros) { return true; } } else if (bit_is_set(FO_OFFSETS, bctx->ff_pkt->flags)) { ser_declare; ser_begin(bctx->wbuf, OFFSET_FADDR_SIZE); ser_uint64(bctx->ff_pkt->bfd.offset); /* store offset in begin of buffer */ } bctx->jcr->ReadBytes += sd->msglen; /* count bytes read */ /* * Uncompressed cipher input length */ bctx->cipher_input_len = sd->msglen; /* * Update checksum if requested */ if (bctx->digest) { crypto_digest_update(bctx->digest, (uint8_t *)bctx->rbuf, sd->msglen); } /* * Update signing digest if requested */ if (bctx->signing_digest) { crypto_digest_update(bctx->signing_digest, (uint8_t *)bctx->rbuf, sd->msglen); } /* * Compress the data. */ if (bit_is_set(FO_COMPRESS, bctx->ff_pkt->flags)) { if (!compress_data(bctx->jcr, bctx->ff_pkt->Compress_algo, bctx->rbuf, bctx->jcr->store_bsock->msglen, bctx->cbuf, bctx->max_compress_len, &bctx->compress_len)) { return false; } /* * See if we need to generate a compression header. */ if (bctx->chead) { ser_declare; /* * Complete header */ ser_begin(bctx->chead, sizeof(comp_stream_header)); ser_uint32(bctx->ch.magic); ser_uint32(bctx->compress_len); ser_uint16(bctx->ch.level); ser_uint16(bctx->ch.version); ser_end(bctx->chead, sizeof(comp_stream_header)); bctx->compress_len += sizeof(comp_stream_header); /* add size of header */ } bctx->jcr->store_bsock->msglen = bctx->compress_len; /* set compressed length */ bctx->cipher_input_len = bctx->compress_len; } /* * Encrypt the data. */ need_more_data = false; if (bit_is_set(FO_ENCRYPT, bctx->ff_pkt->flags) && !encrypt_data(bctx, &need_more_data)) { if (need_more_data) { return true; } return false; } /* * Send the buffer to the Storage daemon */ if (bit_is_set(FO_SPARSE, bctx->ff_pkt->flags) || bit_is_set(FO_OFFSETS, bctx->ff_pkt->flags)) { sd->msglen += OFFSET_FADDR_SIZE; /* include fileAddr in size */ } sd->msg = bctx->wbuf; /* set correct write buffer */ if (!sd->send()) { if (!bctx->jcr->is_job_canceled()) { Jmsg1(bctx->jcr, M_FATAL, 0, _("Network send error to SD. ERR=%s\n"), sd->bstrerror()); } return false; } Dmsg1(130, "Send data to SD len=%d\n", sd->msglen); bctx->jcr->JobBytes += sd->msglen; /* count bytes saved possibly compressed/encrypted */ sd->msg = bctx->msgsave; /* restore read buffer */ return true; }
/* * Perform automatic compression of certain stream types when enabled in the config. */ static bool auto_deflate_record(DCR *dcr) { ser_declare; comp_stream_header ch; DEV_RECORD *rec, *nrec; bool retval = false; bool intermediate_value = false; unsigned int max_compression_length = 0; unsigned char *data = NULL; /* * See what our starting point is. When dcr->after_rec is set we already have * a translated record by an other SD plugin. Then we use that translated record * as the starting point otherwise we start at dcr->before_rec. When an earlier * translation already happened we can free that record when we have a success * full translation here as that record is of no use anymore. */ if (dcr->after_rec) { rec = dcr->after_rec; intermediate_value = true; } else { rec = dcr->before_rec; } /* * We only do autocompression for the following stream types: * * - STREAM_FILE_DATA * - STREAM_WIN32_DATA * - STREAM_SPARSE_DATA */ switch (rec->maskedStream) { case STREAM_FILE_DATA: case STREAM_WIN32_DATA: case STREAM_SPARSE_DATA: break; default: goto bail_out; } /* * Clone the data from the original DEV_RECORD to the converted one. * As we use the compression buffers for the data we need a new * DEV_RECORD without a new memory buffer so we call new_record here * with the with_data boolean set explicitly to false. */ nrec = bfuncs->new_record(false); bfuncs->copy_record_state(nrec, rec); /* * Setup the converted DEV_RECORD to point with its data buffer to the compression buffer. */ nrec->data = dcr->jcr->compress.deflate_buffer; switch (rec->maskedStream) { case STREAM_FILE_DATA: case STREAM_WIN32_DATA: data = (unsigned char *)nrec->data + sizeof(comp_stream_header); max_compression_length = dcr->jcr->compress.deflate_buffer_size - sizeof(comp_stream_header); break; case STREAM_SPARSE_DATA: data = (unsigned char *)nrec->data + OFFSET_FADDR_SIZE + sizeof(comp_stream_header); max_compression_length = dcr->jcr->compress.deflate_buffer_size - OFFSET_FADDR_SIZE - sizeof(comp_stream_header); break; } /* * Compress the data using the configured compression algorithm. */ if (!compress_data(dcr->jcr, dcr->device->autodeflate_algorithm, rec->data, rec->data_len, data, max_compression_length, &nrec->data_len)) { bfuncs->free_record(nrec); goto bail_out; } /* * Map the streams. */ switch (rec->maskedStream) { case STREAM_FILE_DATA: nrec->Stream = STREAM_COMPRESSED_DATA; nrec->maskedStream = STREAM_COMPRESSED_DATA; break; case STREAM_WIN32_DATA: nrec->Stream = STREAM_WIN32_COMPRESSED_DATA; nrec->maskedStream = STREAM_WIN32_COMPRESSED_DATA; break; case STREAM_SPARSE_DATA: nrec->Stream = STREAM_SPARSE_COMPRESSED_DATA; nrec->maskedStream = STREAM_SPARSE_COMPRESSED_DATA; break; default: break; } /* * Generate a compression header. */ ch.magic = dcr->device->autodeflate_algorithm; ch.level = dcr->device->autodeflate_level; ch.version = COMP_HEAD_VERSION; ch.size = nrec->data_len; switch (nrec->maskedStream) { case STREAM_COMPRESSED_DATA: case STREAM_WIN32_COMPRESSED_DATA: ser_begin(nrec->data, sizeof(comp_stream_header)); ser_uint32(ch.magic); ser_uint32(ch.size); ser_uint16(ch.level); ser_uint16(ch.version); ser_end(nrec->data, sizeof(comp_stream_header)); nrec->data_len += sizeof(comp_stream_header); break; case STREAM_SPARSE_COMPRESSED_DATA: /* * Copy the sparse offset from the original. */ memcpy(nrec->data, rec->data, OFFSET_FADDR_SIZE); ser_begin(nrec->data + OFFSET_FADDR_SIZE, sizeof(comp_stream_header)); ser_uint32(ch.magic); ser_uint32(ch.size); ser_uint16(ch.level); ser_uint16(ch.version); ser_end(nrec->data + OFFSET_FADDR_SIZE, sizeof(comp_stream_header)); nrec->data_len += OFFSET_FADDR_SIZE + sizeof(comp_stream_header); break; } Dmsg4(400, "auto_deflate_record: From datastream %d to %d from original size %ld to %ld\n", rec->maskedStream, nrec->maskedStream, rec->data_len, nrec->data_len); /* * If the input is just an intermediate value free it now. */ if (intermediate_value) { bfuncs->free_record(dcr->after_rec); } dcr->after_rec = nrec; retval = true; bail_out: return retval; }