static inline uint32_t serialize_acl_stream(POOL_MEM *buf, uint32_t expected_serialize_len, uint32_t offset, const char *acl_name, uint32_t acl_name_length, char *xattr_value, uint32_t xattr_value_length) { ser_declare; uint32_t content_length; char *buffer; /* * Make sure the serialized stream fits in the poolmem buffer. * We allocate some more to be sure the stream is gonna fit. */ buf->check_size(offset + expected_serialize_len + 10); buffer = buf->c_str() + offset; ser_begin(buffer, expected_serialize_len + 10); /* * Encode the ACL name including the \0 */ ser_uint32(acl_name_length + 1); ser_bytes(acl_name, acl_name_length + 1); /* * Encode the actual ACL data as stored as XATTR. */ ser_uint32(xattr_value_length); ser_bytes(xattr_value, xattr_value_length); ser_end(buffer, expected_serialize_len + 10); content_length = ser_length(buffer); return offset + content_length; }
/* * Create session label * The pool memory must be released by the calling program */ void create_session_label(DCR *dcr, DEV_RECORD *rec, int label) { JCR *jcr = dcr->jcr; ser_declare; rec->VolSessionId = jcr->VolSessionId; rec->VolSessionTime = jcr->VolSessionTime; rec->Stream = jcr->JobId; rec->maskedStream = jcr->JobId; rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Session_Label); ser_begin(rec->data, SER_LENGTH_Session_Label); if (me->compatible) { ser_string(OldBaculaId); ser_uint32(OldCompatibleBareosTapeVersion1); } else { ser_string(BareosId); ser_uint32(BareosTapeVersion); } ser_uint32(jcr->JobId); /* Changed in VerNum 11 */ ser_btime(get_current_btime()); ser_float64(0); ser_string(dcr->pool_name); ser_string(dcr->pool_type); ser_string(jcr->job_name); /* base Job name */ ser_string(jcr->client_name); /* Added in VerNum 10 */ ser_string(jcr->Job); /* Unique name of this Job */ ser_string(jcr->fileset_name); ser_uint32(jcr->getJobType()); ser_uint32(jcr->getJobLevel()); /* Added in VerNum 11 */ ser_string(jcr->fileset_md5); if (label == EOS_LABEL) { ser_uint32(jcr->JobFiles); ser_uint64(jcr->JobBytes); ser_uint32(dcr->StartBlock); ser_uint32(dcr->EndBlock); ser_uint32(dcr->StartFile); ser_uint32(dcr->EndFile); ser_uint32(jcr->JobErrors); /* Added in VerNum 11 */ ser_uint32(jcr->JobStatus); } ser_end(rec->data, SER_LENGTH_Session_Label); rec->data_len = ser_length(rec->data); }
/* * create_volume_label_record * Serialize label (from dev->VolHdr structure) into device record. * Assumes that the dev->VolHdr structure is properly * initialized. */ static void create_volume_label_record(DCR *dcr, DEVICE *dev, DEV_RECORD *rec) { ser_declare; struct date_time dt; JCR *jcr = dcr->jcr; char buf[100]; /* Serialize the label into the device record. */ rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label); ser_begin(rec->data, SER_LENGTH_Volume_Label); ser_string(dev->VolHdr.Id); ser_uint32(dev->VolHdr.VerNum); if (dev->VolHdr.VerNum >= 11) { ser_btime(dev->VolHdr.label_btime); dev->VolHdr.write_btime = get_current_btime(); ser_btime(dev->VolHdr.write_btime); dev->VolHdr.write_date = 0; dev->VolHdr.write_time = 0; } else { /* OLD WAY DEPRECATED */ ser_float64(dev->VolHdr.label_date); ser_float64(dev->VolHdr.label_time); get_current_time(&dt); dev->VolHdr.write_date = dt.julian_day_number; dev->VolHdr.write_time = dt.julian_day_fraction; } ser_float64(dev->VolHdr.write_date); /* 0 if VerNum >= 11 */ ser_float64(dev->VolHdr.write_time); /* 0 if VerNum >= 11 */ ser_string(dev->VolHdr.VolumeName); ser_string(dev->VolHdr.PrevVolumeName); ser_string(dev->VolHdr.PoolName); ser_string(dev->VolHdr.PoolType); ser_string(dev->VolHdr.MediaType); ser_string(dev->VolHdr.HostName); ser_string(dev->VolHdr.LabelProg); ser_string(dev->VolHdr.ProgVersion); ser_string(dev->VolHdr.ProgDate); ser_end(rec->data, SER_LENGTH_Volume_Label); bstrncpy(dcr->VolumeName, dev->VolHdr.VolumeName, sizeof(dcr->VolumeName)); rec->data_len = ser_length(rec->data); rec->FileIndex = dev->VolHdr.LabelType; rec->VolSessionId = jcr->VolSessionId; rec->VolSessionTime = jcr->VolSessionTime; rec->Stream = jcr->NumWriteVolumes; rec->maskedStream = jcr->NumWriteVolumes; Dmsg2(150, "Created Vol label rec: FI=%s len=%d\n", FI_to_ascii(buf, rec->FileIndex), rec->data_len); }
/* unser_volume_label * * Unserialize the Bareos Volume label into the device Volume_Label * structure. * * Assumes that the record is already read. * * Returns: false on error * true on success */ bool unser_volume_label(DEVICE *dev, DEV_RECORD *rec) { ser_declare; char buf1[100], buf2[100]; if (rec->FileIndex != VOL_LABEL && rec->FileIndex != PRE_LABEL) { Mmsg3(dev->errmsg, _("Expecting Volume Label, got FI=%s Stream=%s len=%d\n"), FI_to_ascii(buf1, rec->FileIndex), stream_to_ascii(buf2, rec->Stream, rec->FileIndex), rec->data_len); if (!forge_on) { return false; } } dev->VolHdr.LabelType = rec->FileIndex; dev->VolHdr.LabelSize = rec->data_len; /* Unserialize the record into the Volume Header */ rec->data = check_pool_memory_size(rec->data, SER_LENGTH_Volume_Label); ser_begin(rec->data, SER_LENGTH_Volume_Label); unser_string(dev->VolHdr.Id); unser_uint32(dev->VolHdr.VerNum); if (dev->VolHdr.VerNum >= 11) { unser_btime(dev->VolHdr.label_btime); unser_btime(dev->VolHdr.write_btime); } else { /* old way */ unser_float64(dev->VolHdr.label_date); unser_float64(dev->VolHdr.label_time); } unser_float64(dev->VolHdr.write_date); /* Unused with VerNum >= 11 */ unser_float64(dev->VolHdr.write_time); /* Unused with VerNum >= 11 */ unser_string(dev->VolHdr.VolumeName); unser_string(dev->VolHdr.PrevVolumeName); unser_string(dev->VolHdr.PoolName); unser_string(dev->VolHdr.PoolType); unser_string(dev->VolHdr.MediaType); unser_string(dev->VolHdr.HostName); unser_string(dev->VolHdr.LabelProg); unser_string(dev->VolHdr.ProgVersion); unser_string(dev->VolHdr.ProgDate); ser_end(rec->data, SER_LENGTH_Volume_Label); Dmsg0(190, "unser_vol_label\n"); if (debug_level >= 190) { dump_volume_label(dev); } return true; }
/* * 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; }
/* * Called by Append phase */ void write_container(struct container* c) { assert(c->meta.chunk_num == g_hash_table_size(c->meta.map)); if (container_empty(c)) { /* An empty container * It possibly occurs in the end of backup */ container_count--; VERBOSE("Append phase: Deny writing an empty container %lld", c->meta.id); return; } VERBOSE("Append phase: Writing container %lld of %d chunks", c->meta.id, c->meta.chunk_num); if (destor.simulation_level < SIMULATION_APPEND) { unsigned char * cur = &c->data[CONTAINER_SIZE - CONTAINER_META_SIZE]; ser_declare; ser_begin(cur, CONTAINER_META_SIZE); ser_int64(c->meta.id); ser_int32(c->meta.chunk_num); ser_int32(c->meta.data_size); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, c->meta.map); while (g_hash_table_iter_next(&iter, &key, &value)) { struct metaEntry *me = (struct metaEntry *) value; ser_bytes(&me->fp, sizeof(fingerprint)); ser_bytes(&me->len, sizeof(int32_t)); ser_bytes(&me->off, sizeof(int32_t)); } ser_end(cur, CONTAINER_META_SIZE); pthread_mutex_lock(&mutex); if (fseek(fp, c->meta.id * CONTAINER_SIZE + 8, SEEK_SET) != 0) { perror("Fail seek in container store."); exit(1); } if(fwrite(c->data, CONTAINER_SIZE, 1, fp) != 1){ perror("Fail to write a container in container store."); exit(1); } pthread_mutex_unlock(&mutex); } else { char buf[CONTAINER_META_SIZE]; memset(buf, 0, CONTAINER_META_SIZE); ser_declare; ser_begin(buf, CONTAINER_META_SIZE); ser_int64(c->meta.id); ser_int32(c->meta.chunk_num); ser_int32(c->meta.data_size); GHashTableIter iter; gpointer key, value; g_hash_table_iter_init(&iter, c->meta.map); while (g_hash_table_iter_next(&iter, &key, &value)) { struct metaEntry *me = (struct metaEntry *) value; ser_bytes(&me->fp, sizeof(fingerprint)); ser_bytes(&me->len, sizeof(int32_t)); ser_bytes(&me->off, sizeof(int32_t)); } ser_end(buf, CONTAINER_META_SIZE); pthread_mutex_lock(&mutex); if(fseek(fp, c->meta.id * CONTAINER_META_SIZE + 8, SEEK_SET) != 0){ perror("Fail seek in container store."); exit(1); } if(fwrite(buf, CONTAINER_META_SIZE, 1, fp) != 1){ perror("Fail to write a container in container store."); exit(1); } pthread_mutex_unlock(&mutex); } }
/* * 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; }